Better diagnostics when mismatched types due to implict static lifetime
This commit is contained in:
parent
77d155973c
commit
3cd5ad5cd7
11 changed files with 168 additions and 24 deletions
|
@ -1590,17 +1590,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
if let Some((expected, found)) = expected_found {
|
||||
let expected_label = match exp_found {
|
||||
Mismatch::Variable(ef) => ef.expected.prefix_string(self.tcx),
|
||||
Mismatch::Fixed(s) => s.into(),
|
||||
};
|
||||
let found_label = match exp_found {
|
||||
Mismatch::Variable(ef) => ef.found.prefix_string(self.tcx),
|
||||
Mismatch::Fixed(s) => s.into(),
|
||||
};
|
||||
let exp_found = match exp_found {
|
||||
Mismatch::Variable(exp_found) => Some(exp_found),
|
||||
Mismatch::Fixed(_) => None,
|
||||
let (expected_label, found_label, exp_found) = match exp_found {
|
||||
Mismatch::Variable(ef) => (
|
||||
ef.expected.prefix_string(self.tcx),
|
||||
ef.found.prefix_string(self.tcx),
|
||||
Some(ef),
|
||||
),
|
||||
Mismatch::Fixed(s) => (s.into(), s.into(), None),
|
||||
};
|
||||
match (&terr, expected == found) {
|
||||
(TypeError::Sorts(values), extra) => {
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
//! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
|
||||
//! to hold.
|
||||
|
||||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use crate::infer::error_reporting::note_and_explain_region;
|
||||
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
||||
use crate::infer::{SubregionOrigin, TypeTrace};
|
||||
use crate::traits::ObligationCauseCode;
|
||||
use rustc_errors::{Applicability, ErrorReported};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_middle::ty::{self, TypeVisitor};
|
||||
use rustc_span::MultiSpan;
|
||||
|
||||
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorReported> {
|
||||
let error = self.error.as_ref()?;
|
||||
debug!("try_report_mismatched_static_lifetime {:?}", error);
|
||||
|
||||
let (origin, sub, sup) = match error.clone() {
|
||||
RegionResolutionError::ConcreteFailure(origin, sub, sup) => (origin, sub, sup),
|
||||
_ => return None,
|
||||
};
|
||||
if *sub != ty::RegionKind::ReStatic {
|
||||
return None;
|
||||
}
|
||||
let cause = match origin {
|
||||
SubregionOrigin::Subtype(box TypeTrace { ref cause, .. }) => cause,
|
||||
_ => return None,
|
||||
};
|
||||
let (parent, impl_def_id) = match &cause.code {
|
||||
ObligationCauseCode::MatchImpl(parent, impl_def_id) => (parent, impl_def_id),
|
||||
_ => return None,
|
||||
};
|
||||
let binding_span = match **parent {
|
||||
ObligationCauseCode::BindingObligation(_def_id, binding_span) => binding_span,
|
||||
_ => return None,
|
||||
};
|
||||
let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");
|
||||
// FIXME: we should point at the lifetime
|
||||
let mut multi_span: MultiSpan = vec![binding_span].into();
|
||||
multi_span
|
||||
.push_span_label(binding_span, "introduces a `'static` lifetime requirement".into());
|
||||
err.span_note(multi_span, "because this has an unmet lifetime requirement");
|
||||
note_and_explain_region(self.tcx(), &mut err, "...", sup, "...");
|
||||
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
|
||||
let ty = self.tcx().type_of(*impl_def_id);
|
||||
let mut v = super::static_impl_trait::TraitObjectVisitor(vec![]);
|
||||
v.visit_ty(ty);
|
||||
let matching_def_ids = v.0;
|
||||
|
||||
let impl_self_ty = match impl_node {
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }),
|
||||
..
|
||||
}) => self_ty,
|
||||
_ => bug!("Node not an impl."),
|
||||
};
|
||||
|
||||
for matching_def_id in matching_def_ids {
|
||||
let mut hir_v =
|
||||
super::static_impl_trait::HirTraitObjectVisitor(vec![], matching_def_id);
|
||||
hir_v.visit_ty(&impl_self_ty);
|
||||
|
||||
let mut multi_span: MultiSpan = hir_v.0.clone().into();
|
||||
for span in &hir_v.0 {
|
||||
multi_span.push_span_label(
|
||||
*span,
|
||||
"this has an implicit `'static` lifetime requirement".to_string(),
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"consider relaxing the implicit `'static` requirement",
|
||||
" + '_".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
err.span_note(multi_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
Some(ErrorReported)
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ use rustc_span::source_map::Span;
|
|||
|
||||
mod different_lifetimes;
|
||||
pub mod find_anon_type;
|
||||
mod mismatched_static_lifetime;
|
||||
mod named_anon_conflict;
|
||||
mod placeholder_error;
|
||||
mod static_impl_trait;
|
||||
|
@ -58,6 +59,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
|
|||
.or_else(|| self.try_report_impl_not_conforming_to_trait())
|
||||
.or_else(|| self.try_report_anon_anon_conflict())
|
||||
.or_else(|| self.try_report_static_impl_trait())
|
||||
.or_else(|| self.try_report_mismatched_static_lifetime())
|
||||
}
|
||||
|
||||
pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
|
||||
|
|
|
@ -185,7 +185,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin {
|
||||
if let ObligationCauseCode::ItemObligation(item_def_id) = cause.code {
|
||||
let code = match &cause.code {
|
||||
ObligationCauseCode::MatchImpl(parent, ..) => &**parent,
|
||||
_ => &cause.code,
|
||||
};
|
||||
if let ObligationCauseCode::ItemObligation(item_def_id) = *code {
|
||||
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
|
||||
// lifetime as above, but called using a fully-qualified path to the method:
|
||||
// `Foo::qux(bar)`.
|
||||
|
@ -468,7 +472,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
|
||||
struct TraitObjectVisitor(Vec<DefId>);
|
||||
pub(super) struct TraitObjectVisitor(pub(super) Vec<DefId>);
|
||||
|
||||
impl TypeVisitor<'_> for TraitObjectVisitor {
|
||||
fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
|
||||
|
@ -485,7 +489,7 @@ impl TypeVisitor<'_> for TraitObjectVisitor {
|
|||
}
|
||||
|
||||
/// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime.
|
||||
struct HirTraitObjectVisitor(Vec<Span>, DefId);
|
||||
pub(super) struct HirTraitObjectVisitor(pub(super) Vec<Span>, pub(super) DefId);
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor {
|
||||
type Map = ErasedMap<'tcx>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue