Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
provide generic_param_scope for region errors
  • Loading branch information
lcnr committed Jul 15, 2022
commit 5bd8c960f5f7b07128ebdb12e7f788b1ba0a1902
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx);
let origin = RelateParamBound(type_test_span, generic_ty, None);
self.buffer_error(self.infcx.construct_generic_bound_failure(
self.body.source.def_id().expect_local(),
type_test_span,
Some(origin),
type_test.generic_kind,
lower_bound_region,
self.body.source.def_id().as_local(),
));
} else {
// FIXME. We should handle this case better. It
Expand Down
84 changes: 28 additions & 56 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, Mul
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Item, ItemKind, Node};
use rustc_hir::Node;
use rustc_middle::dep_graph::DepContext;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{
Expand Down Expand Up @@ -348,7 +348,11 @@ pub fn same_type_modulo_infer<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
}

impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn report_region_errors(&self, errors: &[RegionResolutionError<'tcx>]) {
pub fn report_region_errors(
&self,
generic_param_scope: LocalDefId,
errors: &[RegionResolutionError<'tcx>],
) {
debug!("report_region_errors(): {} errors to start", errors.len());

// try to pre-process the errors, which will group some of them
Expand Down Expand Up @@ -379,6 +383,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {

RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => {
self.report_generic_bound_failure(
generic_param_scope,
origin.span(),
Some(origin),
param_ty,
Expand Down Expand Up @@ -2269,56 +2274,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {

pub fn report_generic_bound_failure(
&self,
generic_param_scope: LocalDefId,
span: Span,
origin: Option<SubregionOrigin<'tcx>>,
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>,
) {
let owner =
self.in_progress_typeck_results.map(|typeck_results| typeck_results.borrow().hir_owner);
self.construct_generic_bound_failure(span, origin, bound_kind, sub, owner).emit();
self.construct_generic_bound_failure(generic_param_scope, span, origin, bound_kind, sub)
.emit();
}

pub fn construct_generic_bound_failure(
&self,
generic_param_scope: LocalDefId,
span: Span,
origin: Option<SubregionOrigin<'tcx>>,
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>,
owner: Option<LocalDefId>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let hir = self.tcx.hir();
// Attempt to obtain the span of the parameter so we can
// suggest adding an explicit lifetime bound to it.
let generics = owner.map(|owner| {
let hir_id = hir.local_def_id_to_hir_id(owner);
let parent_id = hir.get_parent_item(hir_id);
(
// Parent item could be a `mod`, so we check the HIR before calling:
if let Some(Node::Item(Item {
kind: ItemKind::Trait(..) | ItemKind::Impl { .. },
..
})) = hir.find_by_def_id(parent_id)
{
Some(self.tcx.generics_of(parent_id))
} else {
None
},
self.tcx.generics_of(owner.to_def_id()),
hir.span(hir_id),
)
});

let span = match generics {
// This is to get around the trait identity obligation, that has a `DUMMY_SP` as signal
// for other diagnostics, so we need to recover it here.
Some((_, _, node)) if span.is_dummy() => node,
_ => span,
};

let generics = self.tcx.generics_of(generic_param_scope);
// type_param_span is (span, has_bounds)
let type_param_span = match (generics, bound_kind) {
(Some((_, ref generics, _)), GenericKind::Param(ref param)) => {
let type_param_span = match bound_kind {
GenericKind::Param(ref param) => {
// Account for the case where `param` corresponds to `Self`,
// which doesn't have the expected type argument.
if !(generics.has_self && param.index == 0) {
Expand Down Expand Up @@ -2346,30 +2325,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
_ => None,
};
let new_lt = generics
.as_ref()
.and_then(|(parent_g, g, _)| {
let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char));
let mut lts_names = g
.params
.iter()

let new_lt = {
let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char));
let lts_names =
iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
.flat_map(|g| &g.params)
.filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
.map(|p| p.name.as_str())
.collect::<Vec<_>>();
if let Some(g) = parent_g {
lts_names.extend(
g.params
.iter()
.filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
.map(|p| p.name.as_str()),
);
}
possible.find(|candidate| !lts_names.contains(&&candidate[..]))
})
.unwrap_or("'lt".to_string());
possible
.find(|candidate| !lts_names.contains(&&candidate[..]))
.unwrap_or("'lt".to_string())
};

let add_lt_sugg = generics
.as_ref()
.and_then(|(_, g, _)| g.params.first())
.params
.first()
.and_then(|param| param.def_id.as_local())
.map(|def_id| (self.tcx.def_span(def_id).shrink_to_lo(), format!("{}, ", new_lt)));

Expand Down Expand Up @@ -2571,7 +2543,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
);
if let Some(infer::RelateParamBound(_, t, _)) = origin {
let return_impl_trait =
owner.and_then(|owner| self.tcx.return_type_impl_trait(owner)).is_some();
self.tcx.return_type_impl_trait(generic_param_scope).is_some();
let t = self.resolve_vars_if_possible(t);
match t.kind() {
// We've got:
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1301,7 +1301,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
pub fn resolve_regions_and_report_errors(&self, outlives_env: &OutlivesEnvironment<'tcx>) {
pub fn resolve_regions_and_report_errors(
&self,
generic_param_scope: LocalDefId,
outlives_env: &OutlivesEnvironment<'tcx>,
) {
let errors = self.resolve_regions(outlives_env);

if !self.is_tainted_by_errors() {
Expand All @@ -1310,7 +1314,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// this infcx was in use. This is totally hokey but
// otherwise we have a hard time separating legit region
// errors from silly ones.
self.report_region_errors(&errors);
self.report_region_errors(generic_param_scope, &errors);
}
}

Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_infer/src/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ use crate::infer::{
};
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::undo_log::UndoLogs;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
use smallvec::smallvec;
Expand Down Expand Up @@ -163,14 +164,15 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {

pub fn check_region_obligations_and_report_errors(
&self,
generic_param_scope: LocalDefId,
outlives_env: &OutlivesEnvironment<'tcx>,
) {
self.process_registered_region_obligations(
outlives_env.region_bound_pairs(),
outlives_env.param_env,
);

self.resolve_regions_and_report_errors(outlives_env)
self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
}
}

Expand Down
38 changes: 23 additions & 15 deletions compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,29 +237,37 @@ fn do_normalize_predicates<'tcx>(
// cares about declarations like `'a: 'b`.
let outlives_env = OutlivesEnvironment::new(elaborated_env);

infcx.resolve_regions_and_report_errors(&outlives_env);
// FIXME: It's very weird that we ignore region obligations but apparently
// still need to use `resolve_regions` as we need the resolved regions in
// the normalized predicates.
let errors = infcx.resolve_regions(&outlives_env);
if !errors.is_empty() {
tcx.sess.delay_span_bug(
span,
format!(
"failed region resolution while normalizing {elaborated_env:?}: {errors:?}"
),
);
}

let predicates = match infcx.fully_resolve(predicates) {
Ok(predicates) => predicates,
match infcx.fully_resolve(predicates) {
Ok(predicates) => Ok(predicates),
Err(fixup_err) => {
// If we encounter a fixup error, it means that some type
// variable wound up unconstrained. I actually don't know
// if this can happen, and I certainly don't expect it to
// happen often, but if it did happen it probably
// represents a legitimate failure due to some kind of
// unconstrained variable, and it seems better not to ICE,
// all things considered.
let reported = tcx.sess.span_err(span, &fixup_err.to_string());
return Err(reported);
// unconstrained variable.
//
// @lcnr: Let's still ICE here for now. I want a test case
// for that.
span_bug!(
span,
"inference variables in normalized parameter environment: {}",
fixup_err
);
}
};
if predicates.needs_infer() {
let reported = tcx
.sess
.delay_span_bug(span, "encountered inference variables after `fully_resolve`");
Err(reported)
} else {
Ok(predicates)
}
})
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,10 @@ fn check_opaque_meets_bounds<'tcx>(
// Can have different predicates to their defining use
hir::OpaqueTyOrigin::TyAlias => {
let outlives_environment = OutlivesEnvironment::new(param_env);
infcx.check_region_obligations_and_report_errors(&outlives_environment);
infcx.check_region_obligations_and_report_errors(
defining_use_anchor,
&outlives_environment,
);
}
}

Expand Down
18 changes: 14 additions & 4 deletions compiler/rustc_typeck/src/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,10 @@ fn compare_predicate_entailment<'tcx>(
// lifetime parameters.
let mut outlives_environment = OutlivesEnvironment::new(param_env);
outlives_environment.add_implied_bounds(infcx, wf_tys, impl_m_hir_id);
infcx.check_region_obligations_and_report_errors(&outlives_environment);
infcx.check_region_obligations_and_report_errors(
impl_m.def_id.expect_local(),
&outlives_environment,
);

Ok(())
})
Expand Down Expand Up @@ -1145,7 +1148,8 @@ pub(crate) fn compare_const_impl<'tcx>(
}

let outlives_environment = OutlivesEnvironment::new(param_env);
infcx.resolve_regions_and_report_errors(&outlives_environment);
infcx
.resolve_regions_and_report_errors(impl_c.def_id.expect_local(), &outlives_environment);
});
}

Expand Down Expand Up @@ -1262,7 +1266,10 @@ fn compare_type_predicate_entailment<'tcx>(
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
let outlives_environment = OutlivesEnvironment::new(param_env);
infcx.check_region_obligations_and_report_errors(&outlives_environment);
infcx.check_region_obligations_and_report_errors(
impl_ty.def_id.expect_local(),
&outlives_environment,
);

Ok(())
})
Expand Down Expand Up @@ -1493,7 +1500,10 @@ pub fn check_type_bounds<'tcx>(
};
let mut outlives_environment = OutlivesEnvironment::new(param_env);
outlives_environment.add_implied_bounds(&infcx, implied_bounds, impl_ty_hir_id);
infcx.check_region_obligations_and_report_errors(&outlives_environment);
infcx.check_region_obligations_and_report_errors(
impl_ty.def_id.expect_local(),
&outlives_environment,
);

Ok(())
})
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(

let mut outlives_environment = OutlivesEnvironment::new(param_env);
outlives_environment.add_implied_bounds(infcx, wf_tys, body_id);
infcx.check_region_obligations_and_report_errors(&outlives_environment);
infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
})
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_typeck/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:

// Finally, resolve all regions.
let outlives_env = OutlivesEnvironment::new(param_env);
infcx.resolve_regions_and_report_errors(&outlives_env);
infcx.resolve_regions_and_report_errors(impl_did, &outlives_env);
}
}
_ => {
Expand Down Expand Up @@ -606,7 +606,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn

// Finally, resolve all regions.
let outlives_env = OutlivesEnvironment::new(param_env);
infcx.resolve_regions_and_report_errors(&outlives_env);
infcx.resolve_regions_and_report_errors(impl_did, &outlives_env);

CoerceUnsizedInfo { custom_kind: kind }
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ fn get_impl_substs<'tcx>(

// Conservatively use an empty `ParamEnv`.
let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
infcx.resolve_regions_and_report_errors(&outlives_env);
infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
let span = tcx.def_span(impl1_def_id);
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ error[E0310]: the parameter type `T` may not live long enough
--> $DIR/builtin-superkinds-self-type.rs:10:16
|
LL | impl <T: Sync> Foo for T { }
| ^^^
| ^^^ ...so that the type `T` will meet its required lifetime bounds...
|
= help: consider adding an explicit lifetime bound `T: 'static`...
= note: ...so that the type `T` will meet its required lifetime bounds...
note: ...that is required by this bound
--> $DIR/builtin-superkinds-self-type.rs:6:24
|
LL | trait Foo : Sized+Sync+'static {
| ^^^^^^^
help: consider adding an explicit lifetime bound...
|
LL | impl <T: Sync + 'static> Foo for T { }
| +++++++++

error: aborting due to previous error

Expand Down
8 changes: 5 additions & 3 deletions src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
--> $DIR/implied-bounds-unnorm-associated-type-3.rs:19:5
|
LL | fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `[T]` will meet its required lifetime bounds
|
= help: consider adding an explicit lifetime bound `T: 'static`...
= note: ...so that the type `[T]` will meet its required lifetime bounds
help: consider adding an explicit lifetime bound...
|
LL | impl<T: 'static> ZeroCopyFrom<[T]> for &'static [T] {
| +++++++++

error: aborting due to previous error

Expand Down
Loading