infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
infer_tid_consider_borriwing = consider borrowing this type parameter in the trait
infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+
+infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
+infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s 'static` requirement
+infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
+infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
+
+infer_but_calling_introduces = {$has_param_name ->
+ [true] `{$param_name}`
+ *[false] `fn` parameter
+} has {$lifetime_kind ->
+ [named] lifetime `{lifetime}`
+ *[anon] an anonymous lifetime `'_`
+} but calling `{assoc_item}` introduces an implicit `'static` lifetime requirement
+ .label1 = {$has_lifetime ->
+ [named] lifetime `{lifetime}`
+ *[anon] an anonymous lifetime `'_`
+ }
+ .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path ->
+ [named] `impl` of `{$impl_path}`
+ *[anon] inherent `impl`
+ }
+
+infer_but_needs_to_satisfy = {$has_param_name ->
+ [true] `{$param_name}`
+ *[false] `fn` parameter
+} has {$has_lifetime ->
+ [named] lifetime `{lifetime}`
+ *[anon] an anonymous lifetime `'_`
+} but it needs to satisfy a `'static` lifetime requirement
+ .influencer = this data with {$has_lifetime ->
+ [named] lifetime `{lifetime}`
+ *[anon] an anonymous lifetime `'_`
+ }...
+ .require = {$spans_empty ->
+ *[true] ...is used and required to live as long as `'static` here
+ [false] ...and is required to live as long as `'static` here
+ }
+ .used_here = ...is used here...
+ .introduced_by_bound = 'static` lifetime requirement introduced by this bound
+
+infer_more_targeted = {$has_param_name ->
+ [true] `{$param_name}`
+ *[false] `fn` parameter
+} has {$has_lifetime ->
+ [named] lifetime `{lifetime}`
+ *[anon] an anonymous lifetime `'_`
+} but calling `{$ident}` introduces an implicit `'static` lifetime requirement
+
+infer_ril_introduced_here = `'static` requirement introduced here
+infer_ril_introduced_by = requirement introduced by this return type
+infer_ril_because_of = because of this returned expression
+infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::{Region, TyCtxt};
use rustc_span::symbol::kw;
+use rustc_span::Symbol;
use rustc_span::{symbol::Ident, BytePos, Span};
use crate::infer::error_reporting::{
pub expected: String,
pub found: String,
}
+
+pub struct DynTraitConstraintSuggestion {
+ pub span: Span,
+ pub ident: Ident,
+}
+
+impl AddSubdiagnostic for DynTraitConstraintSuggestion {
+ fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+ let mut multi_span: MultiSpan = vec![self.span].into();
+ multi_span.push_span_label(self.span, fluent::infer::dtcs_has_lifetime_req_label);
+ multi_span.push_span_label(self.ident.span, fluent::infer::dtcs_introduces_requirement);
+ diag.span_note(multi_span, fluent::infer::dtcs_has_req_note);
+ diag.span_suggestion_verbose(
+ self.span.shrink_to_hi(),
+ fluent::infer::dtcs_suggestion,
+ " + '_",
+ Applicability::MaybeIncorrect,
+ );
+ }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::but_calling_introduces, code = "E0772")]
+pub struct ButCallingIntroduces {
+ #[label(infer::label1)]
+ pub param_ty_span: Span,
+ #[primary_span]
+ #[label(infer::label2)]
+ pub cause_span: Span,
+
+ pub has_param_name: bool,
+ pub param_name: String,
+ pub has_lifetime: bool,
+ pub lifetime: String,
+ pub assoc_item: Symbol,
+ pub has_impl_path: bool,
+ pub impl_path: String,
+}
+
+pub struct ReqIntroducedLocations {
+ pub span: MultiSpan,
+ pub spans: Vec<Span>,
+ pub fn_decl_span: Span,
+ pub cause_span: Span,
+ pub add_label: bool,
+}
+
+impl AddSubdiagnostic for ReqIntroducedLocations {
+ fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) {
+ for sp in self.spans {
+ self.span.push_span_label(sp, fluent::infer::ril_introduced_here);
+ }
+
+ if self.add_label {
+ self.span.push_span_label(self.fn_decl_span, fluent::infer::ril_introduced_by);
+ }
+ self.span.push_span_label(self.cause_span, fluent::infer::ril_because_of);
+ diag.span_note(self.span, fluent::infer::ril_static_introduced_by);
+ }
+}
+
+pub struct MoreTargeted {
+ pub ident: Symbol,
+}
+
+impl AddSubdiagnostic for MoreTargeted {
+ fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+ diag.code(rustc_errors::error_code!(E0772));
+ diag.set_primary_message(fluent::infer::more_targeted);
+ diag.set_arg("ident", self.ident);
+ }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::but_needs_to_satisfy, code = "E0759")]
+pub struct ButNeedsToSatisfy {
+ #[primary_span]
+ pub sp: Span,
+ #[label(infer::influencer)]
+ pub influencer_point: Span,
+ #[label(infer::used_here)]
+ pub spans: Vec<Span>,
+ #[label(infer::require)]
+ pub require_span_as_label: Option<Span>,
+ #[note(infer::require)]
+ pub require_span_as_note: Option<Span>,
+ #[note(infer::introduced_by_bound)]
+ pub bound: Option<Span>,
+
+ #[subdiagnostic]
+ pub req_introduces_loc: Option<ReqIntroducedLocations>,
+
+ pub spans_empty: bool,
+ pub has_lifetime: bool,
+ pub lifetime: String,
+}
//! Error Reporting for static impl Traits.
+use crate::errors::{
+ ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
+ ReqIntroducedLocations,
+};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{AddSubdiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
}
let param = self.find_param_with_region(*sup_r, *sub_r)?;
- let lifetime = if sup_r.has_name() {
- format!("lifetime `{}`", sup_r)
- } else {
- "an anonymous lifetime `'_`".to_string()
+ let simple_ident = param.param.pat.simple_ident();
+
+ let (has_impl_path, impl_path) = match ctxt.assoc_item.container {
+ AssocItemContainer::TraitContainer => {
+ let id = ctxt.assoc_item.container_id(tcx);
+ (true, tcx.def_path_str(id))
+ }
+ AssocItemContainer::ImplContainer => (false, String::new()),
};
- let mut err = struct_span_err!(
- tcx.sess,
- cause.span,
- E0772,
- "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
- requirement",
- param
- .param
- .pat
- .simple_ident()
- .map(|s| format!("`{}`", s))
- .unwrap_or_else(|| "`fn` parameter".to_string()),
- lifetime,
- ctxt.assoc_item.name,
- );
- err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
- err.span_label(
- cause.span,
- &format!(
- "...is used and required to live as long as `'static` here \
- because of an implicit lifetime bound on the {}",
- match ctxt.assoc_item.container {
- AssocItemContainer::TraitContainer => {
- let id = ctxt.assoc_item.container_id(tcx);
- format!("`impl` of `{}`", tcx.def_path_str(id))
- }
- AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
- },
- ),
- );
+
+ let diag = ButCallingIntroduces {
+ param_ty_span: param.param_ty_span,
+ cause_span: cause.span,
+ has_param_name: simple_ident.is_some(),
+ param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
+ has_lifetime: sup_r.has_name(),
+ lifetime: sup_r.to_string(),
+ assoc_item: ctxt.assoc_item.name,
+ has_impl_path,
+ impl_path,
+ };
+ let mut err = self.tcx().sess.create_err(diag);
if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
let reported = err.emit();
return Some(reported);
} else {
- err.cancel();
+ err.cancel()
}
}
return None;
let sp = var_origin.span();
let return_sp = sub_origin.span();
let param = self.find_param_with_region(*sup_r, *sub_r)?;
- let (lifetime_name, lifetime) = if sup_r.has_name() {
- (sup_r.to_string(), format!("lifetime `{}`", sup_r))
- } else {
- ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
- };
- let param_name = param
- .param
- .pat
- .simple_ident()
- .map(|s| format!("`{}`", s))
- .unwrap_or_else(|| "`fn` parameter".to_string());
- let mut err = struct_span_err!(
- tcx.sess,
- sp,
- E0759,
- "{} has {} but it needs to satisfy a `'static` lifetime requirement",
- param_name,
- lifetime,
- );
+ let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
let (mention_influencer, influencer_point) =
if sup_origin.span().overlaps(param.param_ty_span) {
} else {
(!sup_origin.span().overlaps(return_sp), param.param_ty_span)
};
- err.span_label(influencer_point, &format!("this data with {}...", lifetime));
debug!("try_report_static_impl_trait: param_info={:?}", param);
spans.dedup_by_key(|span| (span.lo(), span.hi()));
// We try to make the output have fewer overlapping spans if possible.
- let require_msg = if spans.is_empty() {
- "...is used and required to live as long as `'static` here"
- } else {
- "...and is required to live as long as `'static` here"
- };
let require_span =
if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };
- for span in &spans {
- err.span_label(*span, "...is used here...");
- }
-
- if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
- // If any of the "captured here" labels appears on the same line or after
- // `require_span`, we put it on a note to ensure the text flows by appearing
- // always at the end.
- err.span_note(require_span, require_msg);
+ let spans_empty = spans.is_empty();
+ let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp);
+ let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
+ Some(*bound)
} else {
- // We don't need a note, it's already at the end, it can be shown as a `span_label`.
- err.span_label(require_span, require_msg);
- }
+ None
+ };
+
+ let mut subdiag = None;
- if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
- err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
- }
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
if let ObligationCauseCode::ReturnValue(hir_id)
| ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
let parent_id = tcx.hir().get_parent_item(*hir_id);
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
let mut span: MultiSpan = fn_decl.output.span().into();
+ let mut spans = Vec::new();
let mut add_label = true;
if let hir::FnRetTy::Return(ty) = fn_decl.output {
let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
v.visit_ty(ty);
if !v.0.is_empty() {
span = v.0.clone().into();
- for sp in v.0 {
- span.push_span_label(sp, "`'static` requirement introduced here");
- }
+ spans = v.0;
add_label = false;
}
}
- if add_label {
- span.push_span_label(
- fn_decl.output.span(),
- "requirement introduced by this return type",
- );
- }
- span.push_span_label(cause.span, "because of this returned expression");
- err.span_note(
+ let fn_decl_span = fn_decl.output.span();
+
+ subdiag = Some(ReqIntroducedLocations {
span,
- "`'static` lifetime requirement introduced by the return type",
- );
+ spans,
+ fn_decl_span,
+ cause_span: cause.span,
+ add_label,
+ });
}
}
}
+ let diag = ButNeedsToSatisfy {
+ sp,
+ influencer_point,
+ spans: spans.clone(),
+ // If any of the "captured here" labels appears on the same line or after
+ // `require_span`, we put it on a note to ensure the text flows by appearing
+ // always at the end.
+ require_span_as_note: require_as_note.then_some(require_span),
+ // We don't need a note, it's already at the end, it can be shown as a `span_label`.
+ require_span_as_label: (!require_as_note).then_some(require_span),
+ req_introduces_loc: subdiag,
+
+ has_lifetime: sup_r.has_name(),
+ lifetime: sup_r.to_string(),
+ spans_empty,
+ bound,
+ };
+
+ let mut err = self.tcx().sess.create_err(diag);
+
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
let mut override_error_code = None;
}
if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
// Provide a more targeted error code and description.
- err.code(rustc_errors::error_code!(E0772));
- err.set_primary_message(&format!(
- "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
- requirement",
- param_name, lifetime, ident,
- ));
+ let retarget_subdiag = MoreTargeted { ident };
+ retarget_subdiag.add_to_diagnostic(&mut err);
}
let arg = match param.param.pat.simple_ident() {
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
hir_v.visit_ty(&self_ty);
- for span in &traits {
- let mut multi_span: MultiSpan = vec![*span].into();
- multi_span
- .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
- multi_span.push_span_label(
- ident.span,
- "calling this method introduces the `impl`'s 'static` requirement",
- );
- err.span_note(multi_span, "the used `impl` has a `'static` requirement");
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- "consider relaxing the implicit `'static` requirement",
- " + '_",
- Applicability::MaybeIncorrect,
- );
+ for &span in &traits {
+ let subdiag = DynTraitConstraintSuggestion { span, ident };
+ subdiag.add_to_diagnostic(err);
suggested = true;
}
}