Auto merge of #57901 - lqd:issue_57362, r=nikomatsakis

Add information to higher-ranked lifetimes conflicts error messages

Make these errors go through the new "placeholder error" code path, to have self tys displayed and make them hopefully less confusing.

Should fix #57362.

r? @nikomatsakis — so we can iterate on the specific wording you wanted.
This commit is contained in:
bors 2019-01-29 16:58:15 +00:00
commit 7425663011
27 changed files with 430 additions and 219 deletions

View File

@ -46,9 +46,9 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
let (span, sub, sup) = self.get_regions();
// Determine whether the sub and sup consist of both anonymous (elided) regions.
let anon_reg_sup = self.tcx.is_suitable_region(sup)?;
let anon_reg_sup = self.tcx().is_suitable_region(sup)?;
let anon_reg_sub = self.tcx.is_suitable_region(sub)?;
let anon_reg_sub = self.tcx().is_suitable_region(sub)?;
let scope_def_id_sup = anon_reg_sup.def_id;
let bregion_sup = anon_reg_sup.boundregion;
let scope_def_id_sub = anon_reg_sub.def_id;
@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
};
struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch")
.span_label(span_1, main_label)
.span_label(span_2, String::new())
.span_label(span, span_label)

View File

@ -26,10 +26,10 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
region: Region<'tcx>,
br: &ty::BoundRegion,
) -> Option<(&hir::Ty, &hir::FnDecl)> {
if let Some(anon_reg) = self.tcx.is_suitable_region(region) {
if let Some(anon_reg) = self.tcx().is_suitable_region(region) {
let def_id = anon_reg.def_id;
if let Some(node_id) = self.tcx.hir().as_local_node_id(def_id) {
let fndecl = match self.tcx.hir().get(node_id) {
if let Some(node_id) = self.tcx().hir().as_local_node_id(def_id) {
let fndecl = match self.tcx().hir().get(node_id) {
Node::Item(&hir::Item {
node: hir::ItemKind::Fn(ref fndecl, ..),
..
@ -64,7 +64,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
br: &ty::BoundRegion,
) -> Option<(&'gcx hir::Ty)> {
let mut nested_visitor = FindNestedTypeVisitor {
tcx: self.tcx,
tcx: self.tcx(),
bound_region: *br,
found_type: None,
current_index: ty::INNERMOST,

View File

@ -22,15 +22,15 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
if let Some(tables) = self.in_progress_tables {
let tables = tables.borrow();
NiceRegionError::new(self.tcx, error.clone(), Some(&tables)).try_report().is_some()
NiceRegionError::new(self, error.clone(), Some(&tables)).try_report().is_some()
} else {
NiceRegionError::new(self.tcx, error.clone(), None).try_report().is_some()
NiceRegionError::new(self, error.clone(), None).try_report().is_some()
}
}
}
pub struct NiceRegionError<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
error: Option<RegionResolutionError<'tcx>>,
regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
tables: Option<&'cx ty::TypeckTables<'tcx>>,
@ -38,21 +38,25 @@ pub struct NiceRegionError<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
pub fn new(
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
error: RegionResolutionError<'tcx>,
tables: Option<&'cx ty::TypeckTables<'tcx>>,
) -> Self {
Self { tcx, error: Some(error), regions: None, tables }
Self { infcx, error: Some(error), regions: None, tables }
}
pub fn new_from_span(
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
span: Span,
sub: ty::Region<'tcx>,
sup: ty::Region<'tcx>,
tables: Option<&'cx ty::TypeckTables<'tcx>>,
) -> Self {
Self { tcx, error: None, regions: Some((span, sub, sup)), tables }
Self { infcx, error: None, regions: Some((span, sub, sup)), tables }
}
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
self.infcx.tcx
}
pub fn try_report_from_nll(&self) -> Option<ErrorReported> {

View File

@ -24,23 +24,23 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
// version new_ty of its type where the anonymous region is replaced
// with the named one.//scope_def_id
let (named, anon, anon_arg_info, region_info) = if self.is_named_region(sub)
&& self.tcx.is_suitable_region(sup).is_some()
&& self.tcx().is_suitable_region(sup).is_some()
&& self.find_arg_with_region(sup, sub).is_some()
{
(
sub,
sup,
self.find_arg_with_region(sup, sub).unwrap(),
self.tcx.is_suitable_region(sup).unwrap(),
self.tcx().is_suitable_region(sup).unwrap(),
)
} else if self.is_named_region(sup) && self.tcx.is_suitable_region(sub).is_some()
} else if self.is_named_region(sup) && self.tcx().is_suitable_region(sub).is_some()
&& self.find_arg_with_region(sub, sup).is_some()
{
(
sup,
sub,
self.find_arg_with_region(sub, sup).unwrap(),
self.tcx.is_suitable_region(sub).unwrap(),
self.tcx().is_suitable_region(sub).unwrap(),
)
} else {
return None; // inapplicable
@ -97,7 +97,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
};
struct_span_err!(
self.tcx.sess,
self.tcx().sess,
span,
E0621,
"explicit lifetime required in {}",

View File

@ -47,7 +47,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
// closure, provide a specific message pointing this out.
if let (&SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span),
&RegionKind::ReFree(ref free_region)) = (&sub_origin, sup_region) {
let hir = &self.tcx.hir();
let hir = &self.tcx().hir();
if let Some(node_id) = hir.as_local_node_id(free_region.scope) {
if let Node::Expr(Expr {
node: Closure(_, _, _, closure_span, None),
@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
}) = hir.get(node_id) {
let sup_sp = sup_origin.span();
let origin_sp = origin.span();
let mut err = self.tcx.sess.struct_span_err(
let mut err = self.tcx().sess.struct_span_err(
sup_sp,
"borrowed data cannot be stored outside of its closure");
err.span_label(sup_sp, "cannot be stored outside of its closure");

View File

@ -1,3 +1,4 @@
use errors::DiagnosticBuilder;
use hir::def_id::DefId;
use infer::error_reporting::nice_region_error::NiceRegionError;
use infer::lexical_region_resolve::RegionResolutionError;
@ -12,7 +13,7 @@ use util::ppaux::RegionHighlightMode;
impl NiceRegionError<'me, 'gcx, 'tcx> {
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
/// an anonymous region, emit an descriptive diagnostic error.
/// an anonymous region, emit a descriptive diagnostic error.
pub(super) fn try_report_placeholder_conflict(&self) -> Option<ErrorReported> {
match &self.error {
///////////////////////////////////////////////////////////////////////////
@ -34,19 +35,15 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
sub_placeholder @ ty::RePlaceholder(_),
_,
sup_placeholder @ ty::RePlaceholder(_),
))
if expected.def_id == found.def_id =>
{
Some(self.try_report_placeholders_trait(
Some(self.tcx.mk_region(ty::ReVar(*vid))),
cause,
Some(sub_placeholder),
Some(sup_placeholder),
expected.def_id,
expected.substs,
found.substs,
))
}
)) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Some(sub_placeholder),
Some(sup_placeholder),
expected.def_id,
expected.substs,
found.substs,
)),
Some(RegionResolutionError::SubSupConflict(
vid,
@ -58,19 +55,15 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
sub_placeholder @ ty::RePlaceholder(_),
_,
_,
))
if expected.def_id == found.def_id =>
{
Some(self.try_report_placeholders_trait(
Some(self.tcx.mk_region(ty::ReVar(*vid))),
cause,
Some(sub_placeholder),
None,
expected.def_id,
expected.substs,
found.substs,
))
}
)) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Some(sub_placeholder),
None,
expected.def_id,
expected.substs,
found.substs,
)),
Some(RegionResolutionError::SubSupConflict(
vid,
@ -82,19 +75,35 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
_,
_,
sup_placeholder @ ty::RePlaceholder(_),
))
if expected.def_id == found.def_id =>
{
Some(self.try_report_placeholders_trait(
Some(self.tcx.mk_region(ty::ReVar(*vid))),
)) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
None,
Some(*sup_placeholder),
expected.def_id,
expected.substs,
found.substs,
)),
Some(RegionResolutionError::SubSupConflict(
vid,
_,
_,
_,
SubregionOrigin::Subtype(TypeTrace {
cause,
None,
Some(*sup_placeholder),
expected.def_id,
expected.substs,
found.substs,
))
}
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
}),
sup_placeholder @ ty::RePlaceholder(_),
)) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
None,
Some(*sup_placeholder),
expected.def_id,
expected.substs,
found.substs,
)),
Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(TypeTrace {
@ -103,19 +112,15 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
}),
sub_region @ ty::RePlaceholder(_),
sup_region @ ty::RePlaceholder(_),
))
if expected.def_id == found.def_id =>
{
Some(self.try_report_placeholders_trait(
None,
cause,
Some(*sub_region),
Some(*sup_region),
expected.def_id,
expected.substs,
found.substs,
))
}
)) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
None,
cause,
Some(*sub_region),
Some(*sup_region),
expected.def_id,
expected.substs,
found.substs,
)),
Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(TypeTrace {
@ -124,19 +129,15 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
}),
sub_region @ ty::RePlaceholder(_),
sup_region,
))
if expected.def_id == found.def_id =>
{
Some(self.try_report_placeholders_trait(
Some(sup_region),
cause,
Some(*sub_region),
None,
expected.def_id,
expected.substs,
found.substs,
))
}
)) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
Some(sup_region),
cause,
Some(*sub_region),
None,
expected.def_id,
expected.substs,
found.substs,
)),
Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(TypeTrace {
@ -145,19 +146,15 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
}),
sub_region,
sup_region @ ty::RePlaceholder(_),
))
if expected.def_id == found.def_id =>
{
Some(self.try_report_placeholders_trait(
Some(sub_region),
cause,
None,
Some(*sup_region),
expected.def_id,
expected.substs,
found.substs,
))
}
)) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
Some(sub_region),
cause,
None,
Some(*sup_region),
expected.def_id,
expected.substs,
found.substs,
)),
_ => None,
}
@ -182,11 +179,22 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
expected_substs: &'tcx Substs<'tcx>,
actual_substs: &'tcx Substs<'tcx>,
) -> ErrorReported {
let mut err = self.tcx.sess.struct_span_err(
cause.span(&self.tcx),
debug!(
"try_report_placeholders_trait(\
vid={:?}, \
sub_placeholder={:?}, \
sup_placeholder={:?}, \
trait_def_id={:?}, \
expected_substs={:?}, \
actual_substs={:?})",
vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs
);
let mut err = self.tcx().sess.struct_span_err(
cause.span(&self.tcx()),
&format!(
"implementation of `{}` is not general enough",
self.tcx.item_path_str(trait_def_id),
self.tcx().item_path_str(trait_def_id),
),
);
@ -194,20 +202,20 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
ObligationCauseCode::ItemObligation(def_id) => {
err.note(&format!(
"Due to a where-clause on `{}`,",
self.tcx.item_path_str(def_id),
self.tcx().item_path_str(def_id),
));
}
_ => (),
}
let expected_trait_ref = ty::TraitRef {
let expected_trait_ref = self.infcx.resolve_type_vars_if_possible(&ty::TraitRef {
def_id: trait_def_id,
substs: expected_substs,
};
let actual_trait_ref = ty::TraitRef {
});
let actual_trait_ref = self.infcx.resolve_type_vars_if_possible(&ty::TraitRef {
def_id: trait_def_id,
substs: actual_substs,
};
});
// Search the expected and actual trait references to see (a)
// whether the sub/sup placeholders appear in them (sometimes
@ -218,9 +226,11 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
let mut counter = 0;
let mut has_sub = None;
let mut has_sup = None;
let mut has_vid = None;
self.tcx.for_each_free_region(&expected_trait_ref, |r| {
let mut actual_has_vid = None;
let mut expected_has_vid = None;
self.tcx().for_each_free_region(&expected_trait_ref, |r| {
if Some(r) == sub_placeholder && has_sub.is_none() {
has_sub = Some(counter);
counter += 1;
@ -228,80 +238,207 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
has_sup = Some(counter);
counter += 1;
}
});
self.tcx.for_each_free_region(&actual_trait_ref, |r| {
if Some(r) == vid && has_vid.is_none() {
has_vid = Some(counter);
if Some(r) == vid && expected_has_vid.is_none() {
expected_has_vid = Some(counter);
counter += 1;
}
});
let self_ty_has_vid = self
.tcx
self.tcx().for_each_free_region(&actual_trait_ref, |r| {
if Some(r) == vid && actual_has_vid.is_none() {
actual_has_vid = Some(counter);
counter += 1;
}
});
let actual_self_ty_has_vid = self
.tcx()
.any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);
let expected_self_ty_has_vid = self
.tcx()
.any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);
let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
debug!(
"try_report_placeholders_trait: actual_has_vid={:?}",
actual_has_vid
);
debug!(
"try_report_placeholders_trait: expected_has_vid={:?}",
expected_has_vid
);
debug!("try_report_placeholders_trait: has_sub={:?}", has_sub);
debug!("try_report_placeholders_trait: has_sup={:?}", has_sup);
debug!(
"try_report_placeholders_trait: actual_self_ty_has_vid={:?}",
actual_self_ty_has_vid
);
debug!(
"try_report_placeholders_trait: expected_self_ty_has_vid={:?}",
expected_self_ty_has_vid
);
self.explain_actual_impl_that_was_found(
&mut err,
sub_placeholder,
sup_placeholder,
has_sub,
has_sup,
expected_trait_ref,
actual_trait_ref,
vid,
expected_has_vid,
actual_has_vid,
any_self_ty_has_vid,
);
err.emit();
ErrorReported
}
/// Add notes with details about the expected and actual trait refs, with attention to cases
/// when placeholder regions are involved: either the trait or the self type containing
/// them needs to be mentioned the closest to the placeholders.
/// This makes the error messages read better, however at the cost of some complexity
/// due to the number of combinations we have to deal with.
fn explain_actual_impl_that_was_found(
&self,
err: &mut DiagnosticBuilder<'_>,
sub_placeholder: Option<ty::Region<'tcx>>,
sup_placeholder: Option<ty::Region<'tcx>>,
has_sub: Option<usize>,
has_sup: Option<usize>,
expected_trait_ref: ty::TraitRef<'_>,
actual_trait_ref: ty::TraitRef<'_>,
vid: Option<ty::Region<'tcx>>,
expected_has_vid: Option<usize>,
actual_has_vid: Option<usize>,
any_self_ty_has_vid: bool,
) {
// The weird thing here with the `maybe_highlighting_region` calls and the
// the match inside is meant to be like this:
//
// - The match checks whether the given things (placeholders, etc) appear
// in the types are about to print
// - Meanwhile, the `maybe_highlighting_region` calls set up
// highlights so that, if they do appear, we will replace
// them `'0` and whatever. (This replacement takes place
// inside the closure given to `maybe_highlighting_region`.)
//
// There is some duplication between the calls -- i.e., the
// `maybe_highlighting_region` checks if (e.g.) `has_sub` is
// None, an then we check again inside the closure, but this
// setup sort of minimized the number of calls and so form.
RegionHighlightMode::maybe_highlighting_region(sub_placeholder, has_sub, || {
RegionHighlightMode::maybe_highlighting_region(sup_placeholder, has_sup, || {
match (has_sub, has_sup) {
(Some(n1), Some(n2)) => {
err.note(&format!(
"`{}` must implement `{}` \
for any two lifetimes `'{}` and `'{}`",
expected_trait_ref.self_ty(),
expected_trait_ref,
std::cmp::min(n1, n2),
std::cmp::max(n1, n2),
));
if any_self_ty_has_vid {
err.note(&format!(
"`{}` would have to be implemented for the type `{}`, \
for any two lifetimes `'{}` and `'{}`",
expected_trait_ref,
expected_trait_ref.self_ty(),
std::cmp::min(n1, n2),
std::cmp::max(n1, n2),
));
} else {
err.note(&format!(
"`{}` must implement `{}`, \
for any two lifetimes `'{}` and `'{}`",
expected_trait_ref.self_ty(),
expected_trait_ref,
std::cmp::min(n1, n2),
std::cmp::max(n1, n2),
));
}
}
(Some(n), _) | (_, Some(n)) => {
err.note(&format!(
"`{}` must implement `{}` \
for any lifetime `'{}`",
expected_trait_ref.self_ty(),
expected_trait_ref,
n,
));
}
(None, None) => {
err.note(&format!(
"`{}` must implement `{}`",
expected_trait_ref.self_ty(),
expected_trait_ref,
));
if any_self_ty_has_vid {
err.note(&format!(
"`{}` would have to be implemented for the type `{}`, \
for any lifetime `'{}`",
expected_trait_ref,
expected_trait_ref.self_ty(),
n,
));
} else {
err.note(&format!(
"`{}` must implement `{}`, for any lifetime `'{}`",
expected_trait_ref.self_ty(),
expected_trait_ref,
n,
));
}
}
(None, None) => RegionHighlightMode::maybe_highlighting_region(
vid,
expected_has_vid,
|| {
if let Some(n) = expected_has_vid {
err.note(&format!(
"`{}` would have to be implemented for the type `{}`, \
for some specific lifetime `'{}`",
expected_trait_ref,
expected_trait_ref.self_ty(),
n,
));
} else {
if any_self_ty_has_vid {
err.note(&format!(
"`{}` would have to be implemented for the type `{}`",
expected_trait_ref,
expected_trait_ref.self_ty(),
));
} else {
err.note(&format!(
"`{}` must implement `{}`",
expected_trait_ref.self_ty(),
expected_trait_ref,
));
}
}
},
),
}
})
});
RegionHighlightMode::maybe_highlighting_region(vid, has_vid, || match has_vid {
Some(n) => {
if self_ty_has_vid {
RegionHighlightMode::maybe_highlighting_region(
vid,
actual_has_vid,
|| match actual_has_vid {
Some(n) => {
if any_self_ty_has_vid {
err.note(&format!(
"but `{}` is actually implemented for the type `{}`, \
for some specific lifetime `'{}`",
actual_trait_ref,
actual_trait_ref.self_ty(),
n
));
} else {
err.note(&format!(
"but `{}` actually implements `{}`, for some specific lifetime `'{}`",
actual_trait_ref.self_ty(),
actual_trait_ref,
n
));
}
}
_ => {
err.note(&format!(
"but `{}` only implements `{}` for the lifetime `'{}`",
actual_trait_ref.self_ty(),
"but `{}` is actually implemented for the type `{}`",
actual_trait_ref,
n
));
} else {
err.note(&format!(
"but `{}` only implements `{}` for some lifetime `'{}`",
actual_trait_ref.self_ty(),
actual_trait_ref,
n
));
}
}
None => {
err.note(&format!(
"but `{}` only implements `{}`",
actual_trait_ref.self_ty(),
actual_trait_ref,
));
}
});
err.emit();
ErrorReported
},
);
}
}

View File

@ -19,13 +19,13 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
sup_r,
) = error.clone()
{
let anon_reg_sup = self.tcx.is_suitable_region(sup_r)?;
let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
if sub_r == &RegionKind::ReStatic &&
self.tcx.return_type_impl_trait(anon_reg_sup.def_id).is_some()
self.tcx().return_type_impl_trait(anon_reg_sup.def_id).is_some()
{
let sp = var_origin.span();
let return_sp = sub_origin.span();
let mut err = self.tcx.sess.struct_span_err(
let mut err = self.tcx().sess.struct_span_err(
sp,
"cannot infer an appropriate lifetime",
);
@ -38,7 +38,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
"...but this borrow...",
);
let (lifetime, lt_sp_opt) = self.tcx.msg_span_from_free_region(sup_r);
let (lifetime, lt_sp_opt) = self.tcx().msg_span_from_free_region(sup_r);
if let Some(lifetime_sp) = lt_sp_opt {
err.span_note(
lifetime_sp,
@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
}) => name.to_string(),
_ => "'_".to_owned(),
};
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(return_sp) {
if let Ok(snippet) = self.tcx().sess.source_map().span_to_snippet(return_sp) {
err.span_suggestion(
return_sp,
&format!(

View File

@ -44,13 +44,13 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
let (id, bound_region) = match *anon_region {
ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
ty::ReEarlyBound(ref ebr) => (
self.tcx.parent_def_id(ebr.def_id).unwrap(),
self.tcx().parent_def_id(ebr.def_id).unwrap(),
ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
),
_ => return None, // not a free region
};
let hir = &self.tcx.hir();
let hir = &self.tcx().hir();
if let Some(node_id) = hir.as_local_node_id(id) {
if let Some(body_id) = hir.maybe_body_owned_by(node_id) {
let body = hir.body(body_id);
@ -66,7 +66,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
let arg_ty_span = hir.span(hir.hir_to_node_id(ty_hir_id));
let ty = tables.node_id_to_type_opt(arg.hir_id)?;
let mut found_anon_region = false;
let new_arg_ty = self.tcx.fold_regions(&ty, &mut false, |r, _| {
let new_arg_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| {
if *r == *anon_region {
found_anon_region = true;
replace_region
@ -108,10 +108,10 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
br: ty::BoundRegion,
decl: &hir::FnDecl,
) -> Option<Span> {
let ret_ty = self.tcx.type_of(scope_def_id);
let ret_ty = self.tcx().type_of(scope_def_id);
if let ty::FnDef(_, _) = ret_ty.sty {
let sig = ret_ty.fn_sig(self.tcx);
let late_bound_regions = self.tcx
let sig = ret_ty.fn_sig(self.tcx());
let late_bound_regions = self.tcx()
.collect_referenced_late_bound_regions(&sig.output());
if late_bound_regions.iter().any(|r| *r == br) {
return Some(decl.output.span());
@ -126,7 +126,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
// enable E0621 for it.
pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool {
is_first
&& self.tcx
&& self.tcx()
.opt_associated_item(scope_def_id)
.map(|i| i.method_has_self_argument) == Some(true)
}

View File

@ -243,7 +243,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Check if we can use one of the "nice region errors".
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
let nice = NiceRegionError::new_from_span(infcx.tcx, span, o, f, Some(tables));
let nice = NiceRegionError::new_from_span(infcx, span, o, f, Some(tables));
if let Some(_error_reported) = nice.try_report_from_nll() {
return;
}

View File

@ -41,8 +41,8 @@ LL | tuple_one::<Tuple>();
| ^^^^^^^^^^^^^^^^^^
|
= note: Due to a where-clause on `tuple_one`,
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
= note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2`
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`
= note: but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:96:5
@ -51,8 +51,8 @@ LL | tuple_two::<Tuple>();
| ^^^^^^^^^^^^^^^^^^
|
= note: Due to a where-clause on `tuple_two`,
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
= note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2`
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`
= note: but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: implementation of `TheTrait` is not general enough
--> $DIR/associated-types-eq-hr.rs:105:5
@ -61,8 +61,8 @@ LL | tuple_four::<Tuple>();
| ^^^^^^^^^^^^^^^^^^^
|
= note: Due to a where-clause on `tuple_four`,
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
= note: but `Tuple` only implements `TheTrait<(&'2 isize, &'2 isize)>` for some lifetime `'2`
= note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`
= note: but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: aborting due to 5 previous errors

View File

@ -1,12 +1,12 @@
error[E0308]: mismatched types
error: implementation of `Mirror` is not general enough
--> $DIR/higher-ranked-projection.rs:25:5
|
LL | foo(());
| ^^^ one type is more general than the other
| ^^^
|
= note: expected type `Mirror`
found type `Mirror`
= note: Due to a where-clause on `foo`,
= note: `Mirror` would have to be implemented for the type `&'0 ()`, for any lifetime `'0`
= note: but `Mirror` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -3,7 +3,7 @@ error: compilation successful
|
LL | / fn main() { //[good]~ ERROR compilation successful
LL | | foo(());
LL | | //[bad]~^ ERROR E0308
LL | | //[bad]~^ ERROR not general enough
LL | | }
| |_^

View File

@ -23,5 +23,5 @@ fn foo<U, T>(_t: T)
#[rustc_error]
fn main() { //[good]~ ERROR compilation successful
foo(());
//[bad]~^ ERROR E0308
//[bad]~^ ERROR not general enough
}

View File

@ -4,8 +4,8 @@ error: implementation of `Foo` is not general enough
LL | assert_foo(gen);
| ^^^^^^^^^^
|
= note: `&'0 OnlyFooIfStaticRef` must implement `Foo` for any lifetime `'0`
= note: but `&'1 OnlyFooIfStaticRef` only implements `Foo` for the lifetime `'1`
= note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`
= note: but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/auto-trait-regions.rs:48:5
@ -13,8 +13,8 @@ error: implementation of `Foo` is not general enough
LL | assert_foo(gen);
| ^^^^^^^^^^
|
= note: `A<'0, '1>` must implement `Foo` for any two lifetimes `'0` and `'1`
= note: but `A<'_, '2>` only implements `Foo` for the lifetime `'2`
= note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`
= note: but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
error: aborting due to 2 previous errors

View File

@ -4,8 +4,8 @@ error: implementation of `Deserialize` is not general enough
LL | assert_deserialize_owned::<&'static str>(); //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `&'static str` must implement `Deserialize<'0>` for any lifetime `'0`
= note: but `&str` only implements `Deserialize<'1>` for some lifetime `'1`
= note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`
= note: but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
error: aborting due to previous error

View File

@ -5,8 +5,8 @@ LL | fn b() { want_foo2::<SomeStruct>(); } //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: Due to a where-clause on `want_foo2`,
= note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>` for any two lifetimes `'0` and `'1`
= note: but `SomeStruct` only implements `Foo<(&'2 isize, &'2 isize)>` for some lifetime `'2`
= note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`
= note: but `SomeStruct` actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
error: aborting due to previous error

View File

@ -6,7 +6,7 @@ LL | foo::<()>(); //~ ERROR not general enough
|
= note: Due to a where-clause on `foo`,
= note: `()` must implement `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>`
= note: but `()` only implements `Trait<fn(std::cell::Cell<&'0 u32>)>` for some lifetime `'0`
= note: but `()` actually implements `Trait<fn(std::cell::Cell<&'0 u32>)>`, for some specific lifetime `'0`
error: aborting due to previous error

View File

@ -5,8 +5,8 @@ LL | want_hrtb::<StaticInt>() //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: Due to a where-clause on `want_hrtb`,
= note: `StaticInt` must implement `Foo<&'0 isize>` for any lifetime `'0`
= note: but `StaticInt` only implements `Foo<&'1 isize>` for some lifetime `'1`
= note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`
= note: but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/hrtb-just-for-static.rs:30:5
@ -15,8 +15,8 @@ LL | want_hrtb::<&'a u32>() //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^
|
= note: Due to a where-clause on `want_hrtb`,
= note: `&'a u32` must implement `Foo<&'0 isize>` for any lifetime `'0`
= note: but `&'1 u32` only implements `Foo<&'1 isize>` for the lifetime `'1`
= note: `Foo<&'0 isize>` would have to be implemented for the type `&'a u32`, for any lifetime `'0`
= note: but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: aborting due to 2 previous errors

View File

@ -43,7 +43,7 @@ fn foo_hrtb_bar_not<'b,T>(mut t: T)
// be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a
// isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where
// clause only specifies `T : Bar<&'b isize>`.
foo_hrtb_bar_not(&mut t); //~ ERROR E0308
foo_hrtb_bar_not(&mut t); //~ ERROR not general enough
}
fn foo_hrtb_bar_hrtb<T>(mut t: T)

View File

@ -1,12 +1,12 @@
error[E0308]: mismatched types
error: implementation of `Foo` is not general enough
--> $DIR/hrtb-perfect-forwarding.rs:46:5
|
LL | foo_hrtb_bar_not(&mut t); //~ ERROR E0308
| ^^^^^^^^^^^^^^^^ one type is more general than the other
LL | foo_hrtb_bar_not(&mut t); //~ ERROR not general enough
| ^^^^^^^^^^^^^^^^
|
= note: expected type `Foo<&'a isize>`
found type `Foo<&isize>`
= note: Due to a where-clause on `foo_hrtb_bar_not`,
= note: `&mut T` must implement `Foo<&'0 isize>`, for any lifetime `'0`
= note: but `&mut T` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -4,8 +4,8 @@ error: implementation of `Foo` is not general enough
LL | <u32 as RefFoo<u32>>::ref_foo(a)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `&'0 u32` must implement `Foo<'static, u32>` for any lifetime `'0`
= note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1`
= note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`
= note: but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:69:5
@ -13,8 +13,8 @@ error: implementation of `Foo` is not general enough
LL | <i32 as RefFoo<i32>>::ref_foo(a)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `&'0 i32` must implement `Foo<'static, i32>` for any lifetime `'0`
= note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1`
= note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`
= note: but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:75:5
@ -22,8 +22,8 @@ error: implementation of `Foo` is not general enough
LL | <u64 as RefFoo<u64>>::ref_foo(a)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `&'0 u64` must implement `Foo<'static, u64>` for any lifetime `'0`
= note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1`
= note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`
= note: but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1`
error: implementation of `Foo` is not general enough
--> $DIR/issue-54302-cases.rs:81:5
@ -31,8 +31,8 @@ error: implementation of `Foo` is not general enough
LL | <i64 as RefFoo<i64>>::ref_foo(a)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `&'0 i64` must implement `Foo<'static, i64>` for any lifetime `'0`
= note: but `&'1 _` only implements `Foo<'_, _>` for the lifetime `'1`
= note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`
= note: but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1`
error: aborting due to 4 previous errors

View File

@ -4,8 +4,8 @@ error: implementation of `Deserialize` is not general enough
LL | assert_deserialize_owned::<&'static str>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `&'static str` must implement `Deserialize<'0>` for any lifetime `'0`
= note: but `&str` only implements `Deserialize<'1>` for some lifetime `'1`
= note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`
= note: but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
error: aborting due to previous error

View File

@ -0,0 +1,23 @@
// Test for issue #57362, ensuring that the self ty is shown in cases of higher-ranked lifetimes
// conflicts: the `expected` and `found` trait refs would otherwise be printed the same, leading
// to confusing notes such as:
// = note: expected type `Trait`
// found type `Trait`
// from issue #57362
trait Trait {
fn f(self);
}
impl<T> Trait for fn(&T) {
fn f(self) {
println!("f");
}
}
fn f() {
let a: fn(_) = |_: &u8| {};
a.f(); //~ ERROR not general enough
}
fn main() {}

View File

@ -0,0 +1,11 @@
error: implementation of `Trait` is not general enough
--> $DIR/issue-57362-1.rs:20:7
|
LL | a.f(); //~ ERROR not general enough
| ^
|
= note: `Trait` would have to be implemented for the type `fn(&'0 u8)`, for some specific lifetime `'0`
= note: but `Trait` is actually implemented for the type `for<'r> fn(&'r u8)`
error: aborting due to previous error

View File

@ -0,0 +1,25 @@
// Test for issue #57362, ensuring that the self ty is shown in cases of higher-ranked lifetimes
// conflicts: the `expected` and `found` trait refs would otherwise be printed the same, leading
// to confusing notes such as:
// = note: expected type `Trait`
// found type `Trait`
// extracted from a similar issue: #57642
trait X {
type G;
fn make_g() -> Self::G;
}
impl<'a> X for fn(&'a ()) {
type G = &'a ();
fn make_g() -> Self::G {
&()
}
}
fn g() {
let x = <fn (&())>::make_g(); //~ ERROR not general enough
}
fn main() {}

View File

@ -0,0 +1,11 @@
error: implementation of `X` is not general enough
--> $DIR/issue-57362-2.rs:22:13
|
LL | let x = <fn (&())>::make_g(); //~ ERROR not general enough
| ^^^^^^^^^^^^^^^^^^
|
= note: `X` would have to be implemented for the type `for<'r> fn(&'r ())`
= note: but `X` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
error: aborting due to previous error

View File

@ -5,8 +5,8 @@ LL | foo(&X); //~ ERROR implementation of `Bar` is not general enough
| ^^^
|
= note: Due to a where-clause on `foo`,
= note: `&'0 _` must implement `Bar` for any lifetime `'0`
= note: but `&'1 u32` only implements `Bar` for the lifetime `'1`
= note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`
= note: but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
error: aborting due to previous error