/// Print the error message for lifetime errors when the return type is a static impl Trait.
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
debug!("try_report_static_impl_trait(error={:?})", self.error);
- if let Some(ref error) = self.error {
- if let RegionResolutionError::SubSupConflict(
- _,
- var_origin,
- sub_origin,
- sub_r,
- sup_origin,
- sup_r,
- ) = error
- {
- debug!(
- "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
- var_origin, sub_origin, sub_r, sup_origin, sup_r
+ if let Some(RegionResolutionError::SubSupConflict(
+ _,
+ var_origin,
+ ref sub_origin,
+ sub_r,
+ ref sup_origin,
+ sup_r,
+ )) = self.error
+ {
+ debug!(
+ "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
+ var_origin, sub_origin, sub_r, sup_origin, sup_r
+ );
+ let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
+ debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
+ let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
+ if fn_returns.is_empty() {
+ return None;
+ }
+ debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
+ if *sub_r == RegionKind::ReStatic {
+ let sp = var_origin.span();
+ let return_sp = sub_origin.span();
+ let param_info = 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 mut err = struct_span_err!(
+ self.tcx().sess,
+ sp,
+ E0759,
+ "cannot infer an appropriate lifetime"
);
- let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
- debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
- let fn_returns =
- self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id.expect_local());
- if fn_returns.is_empty() {
- return None;
- }
- debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
- if **sub_r == RegionKind::ReStatic {
- let sp = var_origin.span();
- let return_sp = sub_origin.span();
- let param_info = 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))
+ err.span_label(
+ param_info.param_ty_span,
+ &format!("this data with {}...", lifetime),
+ );
+ debug!("try_report_static_impl_trait: param_info={:?}", param_info);
+
+ // We try to make the output have fewer overlapping spans if possible.
+ if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
+ && sup_origin.span() != return_sp
+ {
+ // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
+
+ // Customize the spans and labels depending on their relative order so
+ // that split sentences flow correctly.
+ if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
+ // Avoid the following:
+ //
+ // error: cannot infer an appropriate lifetime
+ // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+ // |
+ // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+ // | ---- ---------^-
+ //
+ // and instead show:
+ //
+ // error: cannot infer an appropriate lifetime
+ // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+ // |
+ // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+ // | ---- ^
+ err.span_label(
+ sup_origin.span(),
+ "...is captured here, requiring it to live as long as `'static`",
+ );
} else {
- ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
- };
- let mut err = struct_span_err!(
- self.tcx().sess,
- sp,
- E0759,
- "cannot infer an appropriate lifetime"
- );
+ err.span_label(sup_origin.span(), "...is captured here...");
+ if return_sp < sup_origin.span() {
+ err.span_note(
+ return_sp,
+ "...and is required to live as long as `'static` here",
+ );
+ } else {
+ err.span_label(
+ return_sp,
+ "...and is required to live as long as `'static` here",
+ );
+ }
+ }
+ } else {
err.span_label(
- param_info.param_ty_span,
- &format!("this data with {}...", lifetime),
+ return_sp,
+ "...is captured and required to live as long as `'static` here",
);
- debug!("try_report_static_impl_trait: param_info={:?}", param_info);
+ }
- // We try to make the output have fewer overlapping spans if possible.
- if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
- && sup_origin.span() != return_sp
- {
- // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
+ // FIXME: account for the need of parens in `&(dyn Trait + '_)`
+ let consider = "consider changing the";
+ let declare = "to declare that the";
+ let arg = match param_info.param.pat.simple_ident() {
+ Some(simple_ident) => format!("argument `{}`", simple_ident),
+ None => "the argument".to_string(),
+ };
+ let explicit =
+ format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+ let explicit_static =
+ format!("explicit `'static` bound to the lifetime of {}", arg);
+ let captures = format!("captures data from {}", arg);
+ let add_static_bound =
+ "alternatively, add an explicit `'static` bound to this reference";
+ let plus_lt = format!(" + {}", lifetime_name);
+ for fn_return in fn_returns {
+ if fn_return.span.desugaring_kind().is_some() {
+ // Skip `async` desugaring `impl Future`.
+ continue;
+ }
+ match fn_return.kind {
+ TyKind::OpaqueDef(item_id, _) => {
+ let item = self.tcx().hir().item(item_id.id);
+ let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
+ opaque
+ } else {
+ err.emit();
+ return Some(ErrorReported);
+ };
- // Customize the spans and labels depending on their relative order so
- // that split sentences flow correctly.
- if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
- // Avoid the following:
- //
- // error: cannot infer an appropriate lifetime
- // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
- // |
- // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
- // | ---- ---------^-
- //
- // and instead show:
- //
- // error: cannot infer an appropriate lifetime
- // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
- // |
- // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
- // | ---- ^
- err.span_label(
- sup_origin.span(),
- "...is captured here, requiring it to live as long as `'static`",
- );
- } else {
- err.span_label(sup_origin.span(), "...is captured here...");
- if return_sp < sup_origin.span() {
- err.span_note(
- return_sp,
- "...and is required to live as long as `'static` here",
+ if let Some(span) = opaque
+ .bounds
+ .iter()
+ .filter_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime {
+ name: LifetimeName::Static,
+ span,
+ ..
+ }) => Some(*span),
+ _ => None,
+ })
+ .next()
+ {
+ err.span_suggestion_verbose(
+ span,
+ &format!("{} `impl Trait`'s {}", consider, explicit_static),
+ lifetime_name.clone(),
+ Applicability::MaybeIncorrect,
);
+ err.span_suggestion_verbose(
+ param_info.param_ty_span,
+ add_static_bound,
+ param_info.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else if let Some(_) = opaque
+ .bounds
+ .iter()
+ .filter_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime { name, span, .. })
+ if name.ident().to_string() == lifetime_name =>
+ {
+ Some(*span)
+ }
+ _ => None,
+ })
+ .next()
+ {
} else {
- err.span_label(
- return_sp,
- "...and is required to live as long as `'static` here",
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "{declare} `impl Trait` {captures}, {explicit}",
+ declare = declare,
+ captures = captures,
+ explicit = explicit,
+ ),
+ plus_lt.clone(),
+ Applicability::MaybeIncorrect,
);
}
}
- } else {
- err.span_label(
- return_sp,
- "...is captured and required to live as long as `'static` here",
- );
- }
-
- // FIXME: account for the need of parens in `&(dyn Trait + '_)`
- let consider = "consider changing the";
- let declare = "to declare that the";
- let arg = match param_info.param.pat.simple_ident() {
- Some(simple_ident) => format!("argument `{}`", simple_ident),
- None => "the argument".to_string(),
- };
- let explicit =
- format!("you can add an explicit `{}` lifetime bound", lifetime_name);
- let explicit_static =
- format!("explicit `'static` bound to the lifetime of {}", arg);
- let captures = format!("captures data from {}", arg);
- let add_static_bound =
- "alternatively, add an explicit `'static` bound to this reference";
- let plus_lt = format!(" + {}", lifetime_name);
- for fn_return in fn_returns {
- if fn_return.span.desugaring_kind().is_some() {
- // Skip `async` desugaring `impl Future`.
- continue;
- }
- match fn_return.kind {
- TyKind::OpaqueDef(item_id, _) => {
- let item = self.tcx().hir().item(item_id.id);
- let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
- opaque
- } else {
- err.emit();
- return Some(ErrorReported);
- };
-
- if let Some(span) = opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime {
- name: LifetimeName::Static,
- span,
- ..
- }) => Some(*span),
- _ => None,
- })
- .next()
- {
- err.span_suggestion_verbose(
- span,
- &format!("{} `impl Trait`'s {}", consider, explicit_static),
- lifetime_name.clone(),
- Applicability::MaybeIncorrect,
- );
- err.span_suggestion_verbose(
- param_info.param_ty_span,
- add_static_bound,
- param_info.param_ty.to_string(),
- Applicability::MaybeIncorrect,
- );
- } else if let Some(_) = opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime { name, span, .. })
- if name.ident().to_string() == lifetime_name =>
- {
- Some(*span)
- }
- _ => None,
- })
- .next()
- {
- } else {
- err.span_suggestion_verbose(
- fn_return.span.shrink_to_hi(),
- &format!(
- "{declare} `impl Trait` {captures}, {explicit}",
- declare = declare,
- captures = captures,
- explicit = explicit,
- ),
- plus_lt.clone(),
- Applicability::MaybeIncorrect,
- );
- }
+ TyKind::TraitObject(_, lt) => match lt.name {
+ LifetimeName::ImplicitObjectLifetimeDefault => {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "{declare} trait object {captures}, {explicit}",
+ declare = declare,
+ captures = captures,
+ explicit = explicit,
+ ),
+ plus_lt.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ name if name.ident().to_string() != lifetime_name => {
+ // With this check we avoid suggesting redundant bounds. This
+ // would happen if there are nested impl/dyn traits and only
+ // one of them has the bound we'd suggest already there, like
+ // in `impl Foo<X = dyn Bar> + '_`.
+ err.span_suggestion_verbose(
+ lt.span,
+ &format!("{} trait object's {}", consider, explicit_static),
+ lifetime_name.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion_verbose(
+ param_info.param_ty_span,
+ add_static_bound,
+ param_info.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
}
- TyKind::TraitObject(_, lt) => match lt.name {
- LifetimeName::ImplicitObjectLifetimeDefault => {
- err.span_suggestion_verbose(
- fn_return.span.shrink_to_hi(),
- &format!(
- "{declare} trait object {captures}, {explicit}",
- declare = declare,
- captures = captures,
- explicit = explicit,
- ),
- plus_lt.clone(),
- Applicability::MaybeIncorrect,
- );
- }
- name if name.ident().to_string() != lifetime_name => {
- // With this check we avoid suggesting redundant bounds. This
- // would happen if there are nested impl/dyn traits and only
- // one of them has the bound we'd suggest already there, like
- // in `impl Foo<X = dyn Bar> + '_`.
- err.span_suggestion_verbose(
- lt.span,
- &format!("{} trait object's {}", consider, explicit_static),
- lifetime_name.clone(),
- Applicability::MaybeIncorrect,
- );
- err.span_suggestion_verbose(
- param_info.param_ty_span,
- add_static_bound,
- param_info.param_ty.to_string(),
- Applicability::MaybeIncorrect,
- );
- }
- _ => {}
- },
_ => {}
- }
+ },
+ _ => {}
}
- err.emit();
- return Some(ErrorReported);
}
+ err.emit();
+ return Some(ErrorReported);
}
}
None
) -> Self {
let tcx = infcx.tcx;
let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id);
- UniversalRegionsBuilder { infcx, mir_def_id: mir_def_id.to_def_id(), mir_hir_id, param_env }
- .build()
+ UniversalRegionsBuilder { infcx, mir_def_id, mir_hir_id, param_env }.build()
}
/// Given a reference to a closure type, extracts all the values
struct UniversalRegionsBuilder<'cx, 'tcx> {
infcx: &'cx InferCtxt<'cx, 'tcx>,
- mir_def_id: DefId,
+ mir_def_id: LocalDefId,
mir_hir_id: HirId,
param_env: ty::ParamEnv<'tcx>,
}
let mut indices = self.compute_indices(fr_static, defining_ty);
debug!("build: indices={:?}", indices);
- let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id);
+ let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id.to_def_id());
// If this is a closure or generator, then the late-bound regions from the enclosing
// function are actually external regions to us. For example, here, 'a is not local
// fn foo<'a>() {
// let c = || { let x: &'a u32 = ...; }
// }
- if self.mir_def_id != closure_base_def_id {
+ if self.mir_def_id.to_def_id() != closure_base_def_id {
self.infcx.replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices)
}
);
// Converse of above, if this is a function then the late-bound regions declared on its
// signature are local to the fn.
- if self.mir_def_id == closure_base_def_id {
+ if self.mir_def_id.to_def_id() == closure_base_def_id {
self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices);
}
/// see `DefiningTy` for details.
fn defining_ty(&self) -> DefiningTy<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
+ let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
match tcx.hir().body_owner_kind(self.mir_hir_id) {
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
- let defining_ty = if self.mir_def_id == closure_base_def_id {
+ let defining_ty = if self.mir_def_id.to_def_id() == closure_base_def_id {
tcx.type_of(closure_base_def_id)
} else {
- let tables = tcx.typeck_tables_of(self.mir_def_id.expect_local());
+ let tables = tcx.typeck_tables_of(self.mir_def_id);
tables.node_type(self.mir_hir_id)
};
}
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
- assert_eq!(closure_base_def_id, self.mir_def_id);
+ assert_eq!(self.mir_def_id.to_def_id(), closure_base_def_id);
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
let substs =
self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs);
- DefiningTy::Const(self.mir_def_id, substs)
+ DefiningTy::Const(self.mir_def_id.to_def_id(), substs)
}
}
}
defining_ty: DefiningTy<'tcx>,
) -> UniversalRegionIndices<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
+ let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
let fr_substs = match defining_ty {
DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
let tcx = self.infcx.tcx;
match defining_ty {
DefiningTy::Closure(def_id, substs) => {
- assert_eq!(self.mir_def_id, def_id);
+ assert_eq!(self.mir_def_id.to_def_id(), def_id);
let closure_sig = substs.as_closure().sig();
let inputs_and_output = closure_sig.inputs_and_output();
let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap();
}
DefiningTy::Generator(def_id, substs, movability) => {
- assert_eq!(self.mir_def_id, def_id);
+ assert_eq!(self.mir_def_id.to_def_id(), def_id);
let resume_ty = substs.as_generator().resume_ty();
let output = substs.as_generator().return_ty();
let generator_ty = tcx.mk_generator(def_id, substs, movability);
DefiningTy::Const(def_id, _) => {
// For a constant body, there are no inputs, and one
// "output" (the type of the constant).
- assert_eq!(self.mir_def_id, def_id);
+ assert_eq!(self.mir_def_id.to_def_id(), def_id);
let ty = tcx.type_of(def_id);
let ty = indices.fold_to_region_vids(tcx, &ty);
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
fn replace_bound_regions_with_nll_infer_vars<T>(
&self,
origin: NLLRegionVariableOrigin,
- all_outlive_scope: DefId,
+ all_outlive_scope: LocalDefId,
value: &ty::Binder<T>,
indices: &mut UniversalRegionIndices<'tcx>,
) -> T
fn replace_late_bound_regions_with_nll_infer_vars(
&self,
- mir_def_id: DefId,
+ mir_def_id: LocalDefId,
indices: &mut UniversalRegionIndices<'tcx>,
);
}
fn replace_bound_regions_with_nll_infer_vars<T>(
&self,
origin: NLLRegionVariableOrigin,
- all_outlive_scope: DefId,
+ all_outlive_scope: LocalDefId,
value: &ty::Binder<T>,
indices: &mut UniversalRegionIndices<'tcx>,
) -> T
let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
- scope: all_outlive_scope,
+ scope: all_outlive_scope.to_def_id(),
bound_region: br,
}));
let region_vid = self.next_nll_region_var(origin);
/// inputs vector.
fn replace_late_bound_regions_with_nll_infer_vars(
&self,
- mir_def_id: DefId,
+ mir_def_id: LocalDefId,
indices: &mut UniversalRegionIndices<'tcx>,
) {
debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
- let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id);
+ let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
if !indices.indices.contains_key(&r) {