From 19ecfcd0e2ae01c79159888a45042a5d6f4ed487 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Sat, 27 Feb 2021 21:31:56 -0500 Subject: [PATCH 1/4] resolve late lifetimes by item This reverts commit 22ae20733515d710c1134600bc1e29cdd76f6b9b. --- .../src/middle/resolve_lifetime.rs | 5 - compiler/rustc_middle/src/query/mod.rs | 11 +- compiler/rustc_middle/src/ty/context.rs | 4 +- compiler/rustc_resolve/src/late/lifetimes.rs | 424 +++++++++++------- compiler/rustc_typeck/src/astconv/mod.rs | 14 +- src/test/ui/error-codes/E0106.stderr | 22 +- .../feature-gate-in_band_lifetimes.stderr | 168 +++---- .../generic-associated-types/shadowing.stderr | 16 +- ...rrect-explicit-lifetime-name-needed.stderr | 22 +- .../ui/generics/wrong-number-of-args.stderr | 66 +-- .../no_introducing_in_band_in_locals.rs | 2 +- .../no_introducing_in_band_in_locals.stderr | 18 +- ...ime-used-in-debug-macro-issue-70152.stderr | 20 +- .../method-call-lifetime-args-unresolved.rs | 2 + ...ethod-call-lifetime-args-unresolved.stderr | 17 +- .../issue-74918-missing-lifetime.rs | 2 +- .../issue-74918-missing-lifetime.stderr | 18 +- .../ui/regions/regions-name-undeclared.stderr | 40 +- .../missing-lifetimes-in-signature.rs | 7 +- .../missing-lifetimes-in-signature.stderr | 107 +---- .../missing-lifetime-specifier.stderr | 48 +- 21 files changed, 513 insertions(+), 520 deletions(-) diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 1b7d0e620a4..32615f6c410 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -78,9 +78,4 @@ pub struct ResolveLifetimes { /// be late-bound if (a) it does NOT appear in a where-clause and /// (b) it DOES appear in the arguments. pub late_bound: FxHashMap>, - - /// For each type and trait definition, maps type parameters - /// to the trait object lifetime defaults computed from them. - pub object_lifetime_defaults: - FxHashMap>>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 36162cfe924..93e4c97efd8 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1253,7 +1253,12 @@ rustc_queries! { } /// Lifetime resolution. See `middle::resolve_lifetimes`. - query resolve_lifetimes(_: CrateNum) -> ResolveLifetimes { + query resolve_lifetimes_definition(_: LocalDefId) -> ResolveLifetimes { + storage(ArenaCacheSelector<'tcx>) + desc { "resolving lifetimes in a definition" } + } + /// Lifetime resolution. See `middle::resolve_lifetimes`. + query resolve_lifetimes(_: LocalDefId) -> ResolveLifetimes { storage(ArenaCacheSelector<'tcx>) desc { "resolving lifetimes" } } @@ -1266,8 +1271,8 @@ rustc_queries! { desc { "testing if a region is late bound" } } query object_lifetime_defaults_map(_: LocalDefId) - -> Option<&'tcx FxHashMap>> { - desc { "looking up lifetime defaults for a region" } + -> Option> { + desc { "looking up lifetime defaults for a region on an item" } } query visibility(def_id: DefId) -> ty::Visibility { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 56c38baa2df..57225b7abf7 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2641,6 +2641,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn named_region(self, id: HirId) -> Option { + debug!(?id, "named_region"); self.named_region_map(id.owner).and_then(|map| map.get(&id.local_id).cloned()) } @@ -2649,9 +2650,8 @@ impl<'tcx> TyCtxt<'tcx> { .map_or(false, |(owner, set)| owner == id.owner && set.contains(&id.local_id)) } - pub fn object_lifetime_defaults(self, id: HirId) -> Option<&'tcx [ObjectLifetimeDefault]> { + pub fn object_lifetime_defaults(self, id: HirId) -> Option> { self.object_lifetime_defaults_map(id.owner) - .and_then(|map| map.get(&id.local_id).map(|v| &**v)) } } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 744945c5b0f..02b732e75ef 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength //! Name resolution for lifetimes. //! //! Name resolution for lifetimes follows *much* simpler rules than the @@ -11,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefIdMap, LOCAL_CRATE}; +use rustc_hir::def_id::DefIdMap; use rustc_hir::hir_id::ItemLocalId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath}; @@ -26,6 +27,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use std::borrow::Cow; use std::cell::Cell; +use std::fmt; use std::mem::take; use tracing::debug; @@ -135,7 +137,7 @@ impl RegionExt for Region { /// FIXME. This struct gets converted to a `ResolveLifetimes` for /// actual use. It has the same data, but indexed by `LocalDefId`. This /// is silly. -#[derive(Default)] +#[derive(Debug, Default)] struct NamedRegionMap { // maps from every use of a named (not anonymous) lifetime to a // `Region` describing how that region is bound @@ -145,10 +147,6 @@ struct NamedRegionMap { // be late-bound if (a) it does NOT appear in a where-clause and // (b) it DOES appear in the arguments. late_bound: HirIdSet, - - // For each type and trait definition, maps type parameters - // to the trait object lifetime defaults computed from them. - object_lifetime_defaults: HirIdMap>, } crate struct LifetimeContext<'a, 'tcx> { @@ -176,6 +174,8 @@ crate struct LifetimeContext<'a, 'tcx> { is_in_const_generic: bool, + definition_only: bool, + /// List of labels in the function/method currently under analysis. labels_in_fn: Vec, @@ -252,6 +252,42 @@ enum Scope<'a> { Root, } +// A helper struct for debugging scopes without printing parent scopes +struct TruncatedScopeDebug<'a>(&'a Scope<'a>); + +impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.0 { + Scope::Binder { + lifetimes, + next_early_index, + track_lifetime_uses, + opaque_type_parent, + s: _, + } => f + .debug_struct("Binder") + .field("lifetimes", lifetimes) + .field("next_early_index", next_early_index) + .field("track_lifetime_uses", track_lifetime_uses) + .field("opaque_type_parent", opaque_type_parent) + .field("s", &"..") + .finish(), + Scope::Body { id, s: _ } => { + f.debug_struct("Body").field("id", id).field("s", &"..").finish() + } + Scope::Elision { elide, s: _ } => { + f.debug_struct("Elision").field("elide", elide).field("s", &"..").finish() + } + Scope::ObjectLifetimeDefault { lifetime, s: _ } => f + .debug_struct("ObjectLifetimeDefault") + .field("lifetime", lifetime) + .field("s", &"..") + .finish(), + Scope::Root => f.debug_struct("Root").finish(), + } + } +} + #[derive(Clone, Debug)] enum Elide { /// Use a fresh anonymous late-bound lifetime each time, by @@ -283,26 +319,61 @@ const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { + resolve_lifetimes_definition, resolve_lifetimes, - named_region_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id), + named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id), is_late_bound_map, object_lifetime_defaults_map: |tcx, id| { - tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id) + let hir_id = tcx.hir().local_def_id_to_hir_id(id); + match tcx.hir().find(hir_id) { + Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item), + _ => None, + } }, ..*providers }; } +/// Like `resolve_lifetimes`, but does not resolve lifetimes for trait items. +/// Also does not generate any diagnostics. +#[tracing::instrument(level = "debug", skip(tcx))] +fn resolve_lifetimes_definition(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { + do_resolve(tcx, local_def_id, true) +} + /// Computes the `ResolveLifetimes` map that contains data for the /// entire crate. You should not read the result of this query /// directly, but rather use `named_region_map`, `is_late_bound_map`, /// etc. -fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> ResolveLifetimes { - assert_eq!(for_krate, LOCAL_CRATE); +#[tracing::instrument(level = "debug", skip(tcx))] +fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { + do_resolve(tcx, local_def_id, false) +} - let named_region_map = krate(tcx); +fn do_resolve( + tcx: TyCtxt<'_>, + local_def_id: LocalDefId, + definition_only: bool, +) -> ResolveLifetimes { + let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(local_def_id)); + let mut named_region_map = + NamedRegionMap { defs: Default::default(), late_bound: Default::default() }; + let mut visitor = LifetimeContext { + tcx, + map: &mut named_region_map, + scope: ROOT_SCOPE, + trait_ref_hack: false, + is_in_fn_syntax: false, + is_in_const_generic: false, + definition_only, + labels_in_fn: vec![], + xcrate_object_lifetime_defaults: Default::default(), + lifetime_uses: &mut Default::default(), + missing_named_lifetime_spots: vec![], + }; + visitor.visit_item(item); let mut rl = ResolveLifetimes::default(); @@ -314,14 +385,47 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> ResolveLifetimes { let map = rl.late_bound.entry(hir_id.owner).or_default(); map.insert(hir_id.local_id); } - for (hir_id, v) in named_region_map.object_lifetime_defaults { - let map = rl.object_lifetime_defaults.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, v); - } + debug!(?rl.defs); rl } +fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ResolveLifetimes { + let item_id = item_for(tcx, def_id); + if item_id == def_id { + let item = tcx.hir().item(hir::ItemId { def_id: item_id }); + match item.kind { + hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_definition(item_id), + _ => tcx.resolve_lifetimes(item_id), + } + } else { + tcx.resolve_lifetimes(item_id) + } +} + +fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId { + let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id); + match tcx.hir().find(hir_id) { + Some(Node::Item(item)) => { + return item.def_id; + } + _ => {} + } + let item = { + let hir = tcx.hir(); + let mut parent_iter = hir.parent_iter(hir_id); + loop { + let node = parent_iter.next().map(|n| n.1); + match node { + Some(hir::Node::Item(item)) => break item.def_id, + Some(hir::Node::Crate(_)) | None => bug!("Called `item_for` on an Item."), + _ => {} + } + } + }; + item +} + fn is_late_bound_map<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, @@ -344,37 +448,10 @@ fn is_late_bound_map<'tcx>( tcx.is_late_bound_map(def_id.expect_local()) } - _ => tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&def_id).map(|lt| (def_id, lt)), + _ => resolve_lifetimes_for(tcx, def_id).late_bound.get(&def_id).map(|lt| (def_id, lt)), } } -fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap { - let krate = tcx.hir().krate(); - let mut map = NamedRegionMap { - defs: Default::default(), - late_bound: Default::default(), - object_lifetime_defaults: compute_object_lifetime_defaults(tcx), - }; - { - let mut visitor = LifetimeContext { - tcx, - map: &mut map, - scope: ROOT_SCOPE, - trait_ref_hack: false, - is_in_fn_syntax: false, - is_in_const_generic: false, - labels_in_fn: vec![], - xcrate_object_lifetime_defaults: Default::default(), - lifetime_uses: &mut Default::default(), - missing_named_lifetime_spots: vec![], - }; - for item in krate.items.values() { - visitor.visit_item(item); - } - } - map -} - /// In traits, there is an implicit `Self` type parameter which comes before the generics. /// We have to account for this when computing the index of the other generic parameters. /// This function returns whether there is such an implicit parameter defined on the given item. @@ -392,6 +469,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // We want to nest trait/impl items in their parent, but nothing else. fn visit_nested_item(&mut self, _: hir::ItemId) {} + fn visit_trait_item_ref(&mut self, ii: &'tcx hir::TraitItemRef) { + if !self.definition_only { + intravisit::walk_trait_item_ref(self, ii) + } + } + fn visit_nested_body(&mut self, body: hir::BodyId) { // Each body has their own set of labels, save labels. let saved = take(&mut self.labels_in_fn); @@ -430,6 +513,32 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // Opaque types are visited when we visit the // `TyKind::OpaqueDef`, so that they have the lifetimes from // their parent opaque_ty in scope. + for (_hir_id, node) in + self.tcx.hir().parent_iter(self.tcx.hir().local_def_id_to_hir_id(item.def_id)) + { + match node { + hir::Node::Item(parent_item) => { + let resolved_lifetimes: &ResolveLifetimes = + self.tcx.resolve_lifetimes(item_for(self.tcx, parent_item.def_id)); + // We need to add *all* deps, since opaque tys may want them from *us* + for (&owner, defs) in resolved_lifetimes.defs.iter() { + defs.iter().for_each(|(&local_id, region)| { + self.map + .defs + .insert(hir::HirId { owner, local_id }, region.clone()); + }); + } + for (&owner, late_bound) in resolved_lifetimes.late_bound.iter() { + late_bound.iter().for_each(|&local_id| { + self.map.late_bound.insert(hir::HirId { owner, local_id }); + }); + } + break; + } + hir::Node::Crate(_) => bug!("No Item about an OpaqueTy"), + _ => {} + } + } } hir::ItemKind::TyAlias(_, ref generics) | hir::ItemKind::Enum(_, ref generics) @@ -495,9 +604,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + #[tracing::instrument(level = "debug", skip(self))] fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - debug!("visit_ty: id={:?} ty={:?}", ty.hir_id, ty); - debug!("visit_ty: ty.kind={:?}", ty.kind); match ty.kind { hir::TyKind::BareFn(ref c) => { let next_early_index = self.next_early_index(); @@ -541,7 +649,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.is_in_fn_syntax = was_in_fn_syntax; } hir::TyKind::TraitObject(bounds, ref lifetime, _) => { - debug!("visit_ty: TraitObject(bounds={:?}, lifetime={:?})", bounds, lifetime); + debug!(?bounds, ?lifetime, "TraitObject"); for bound in bounds { self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); } @@ -652,14 +760,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; if !parent_is_item { - struct_span_err!( - self.tcx.sess, - lifetime.span, - E0657, - "`impl Trait` can only capture lifetimes \ - bound at the fn or impl level" - ) - .emit(); + if !self.definition_only { + struct_span_err!( + self.tcx.sess, + lifetime.span, + E0657, + "`impl Trait` can only capture lifetimes \ + bound at the fn or impl level" + ) + .emit(); + } self.uninsert_lifetime_on_error(lifetime, def.unwrap()); } } @@ -670,7 +780,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // We want to start our early-bound indices at the end of the parent scope, // not including any parent `impl Trait`s. let mut index = self.next_early_index_for_opaque_type(); - debug!("visit_ty: index = {}", index); + debug!(?index); let mut elision = None; let mut lifetimes = FxHashMap::default(); @@ -862,8 +972,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + #[tracing::instrument(level = "debug", skip(self))] fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - debug!("visit_lifetime(lifetime_ref={:?})", lifetime_ref); if lifetime_ref.is_elided() { self.resolve_elided_lifetimes(vec![lifetime_ref]); return; @@ -897,7 +1007,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { - check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); + if !self.definition_only { + check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); + } for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => {} @@ -1224,56 +1336,53 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) { } } -fn compute_object_lifetime_defaults(tcx: TyCtxt<'_>) -> HirIdMap> { - let mut map = HirIdMap::default(); - for item in tcx.hir().krate().items.values() { - match item.kind { - hir::ItemKind::Struct(_, ref generics) - | hir::ItemKind::Union(_, ref generics) - | hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - ref generics, impl_trait_fn: None, .. - }) - | hir::ItemKind::TyAlias(_, ref generics) - | hir::ItemKind::Trait(_, _, ref generics, ..) => { - let result = object_lifetime_defaults_for_item(tcx, generics); +fn compute_object_lifetime_defaults( + tcx: TyCtxt<'_>, + item: &hir::Item<'_>, +) -> Option> { + match item.kind { + hir::ItemKind::Struct(_, ref generics) + | hir::ItemKind::Union(_, ref generics) + | hir::ItemKind::Enum(_, ref generics) + | hir::ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, impl_trait_fn: None, .. }) + | hir::ItemKind::TyAlias(_, ref generics) + | hir::ItemKind::Trait(_, _, ref generics, ..) => { + let result = object_lifetime_defaults_for_item(tcx, generics); - // Debugging aid. - let attrs = tcx.hir().attrs(item.hir_id()); - if tcx.sess.contains_name(attrs, sym::rustc_object_lifetime_default) { - let object_lifetime_default_reprs: String = result - .iter() - .map(|set| match *set { - Set1::Empty => "BaseDefault".into(), - Set1::One(Region::Static) => "'static".into(), - Set1::One(Region::EarlyBound(mut i, _, _)) => generics - .params - .iter() - .find_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if i == 0 { - return Some(param.name.ident().to_string().into()); - } - i -= 1; - None + // Debugging aid. + let attrs = tcx.hir().attrs(item.hir_id()); + if tcx.sess.contains_name(attrs, sym::rustc_object_lifetime_default) { + let object_lifetime_default_reprs: String = result + .iter() + .map(|set| match *set { + Set1::Empty => "BaseDefault".into(), + Set1::One(Region::Static) => "'static".into(), + Set1::One(Region::EarlyBound(mut i, _, _)) => generics + .params + .iter() + .find_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + if i == 0 { + return Some(param.name.ident().to_string().into()); } - _ => None, - }) - .unwrap(), - Set1::One(_) => bug!(), - Set1::Many => "Ambiguous".into(), - }) - .collect::>>() - .join(","); - tcx.sess.span_err(item.span, &object_lifetime_default_reprs); - } - - map.insert(item.hir_id(), result); + i -= 1; + None + } + _ => None, + }) + .unwrap(), + Set1::One(_) => bug!(), + Set1::Many => "Ambiguous".into(), + }) + .collect::>>() + .join(","); + tcx.sess.span_err(item.span, &object_lifetime_default_reprs); } - _ => {} + + Some(result) } + _ => None, } - map } /// Scan the bounds and where-clauses on parameters to extract bounds @@ -1392,15 +1501,20 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { trait_ref_hack: self.trait_ref_hack, is_in_fn_syntax: self.is_in_fn_syntax, is_in_const_generic: self.is_in_const_generic, + definition_only: self.definition_only, labels_in_fn, xcrate_object_lifetime_defaults, lifetime_uses, missing_named_lifetime_spots, }; - debug!("entering scope {:?}", this.scope); - f(self.scope, &mut this); - this.check_uses_for_lifetimes_defined_by_scope(); - debug!("exiting scope {:?}", this.scope); + let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); + { + let _enter = span.enter(); + f(self.scope, &mut this); + if !self.definition_only { + this.check_uses_for_lifetimes_defined_by_scope(); + } + } self.labels_in_fn = this.labels_in_fn; self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; @@ -1859,7 +1973,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } // Check for fn-syntax conflicts with in-band lifetime definitions - if self.is_in_fn_syntax { + if !self.definition_only && self.is_in_fn_syntax { match def { Region::EarlyBound(_, _, LifetimeDefOrigin::InBand) | Region::LateBound(_, _, LifetimeDefOrigin::InBand) => { @@ -1991,47 +2105,47 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }; let map = &self.map; - let unsubst = if let Some(def_id) = def_id.as_local() { + let set_to_region = |set: &ObjectLifetimeDefault| match *set { + Set1::Empty => { + if in_body { + None + } else { + Some(Region::Static) + } + } + Set1::One(r) => { + let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { + GenericArg::Lifetime(lt) => Some(lt), + _ => None, + }); + r.subst(lifetimes, map) + } + Set1::Many => None, + }; + if let Some(def_id) = def_id.as_local() { let id = self.tcx.hir().local_def_id_to_hir_id(def_id); - &map.object_lifetime_defaults[&id] + self.tcx.object_lifetime_defaults(id).unwrap().iter().map(set_to_region).collect() } else { let tcx = self.tcx; - self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| { - tcx.generics_of(def_id) - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamDefKind::Type { object_lifetime_default, .. } => { - Some(object_lifetime_default) - } - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => { - None - } - }) - .collect() - }) - }; - debug!("visit_segment_args: unsubst={:?}", unsubst); - unsubst - .iter() - .map(|set| match *set { - Set1::Empty => { - if in_body { - None - } else { - Some(Region::Static) - } - } - Set1::One(r) => { - let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(lt) => Some(lt), - _ => None, - }); - r.subst(lifetimes, map) - } - Set1::Many => None, - }) - .collect() + self.xcrate_object_lifetime_defaults + .entry(def_id) + .or_insert_with(|| { + tcx.generics_of(def_id) + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamDefKind::Type { object_lifetime_default, .. } => { + Some(object_lifetime_default) + } + GenericParamDefKind::Lifetime + | GenericParamDefKind::Const { .. } => None, + }) + .collect() + }) + .iter() + .map(set_to_region) + .collect() + } }); debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); @@ -2092,12 +2206,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } + #[tracing::instrument(level = "debug", skip(self))] fn visit_fn_like_elision( &mut self, inputs: &'tcx [hir::Ty<'tcx>], output: Option<&'tcx hir::Ty<'tcx>>, ) { - debug!("visit_fn_like_elision: enter"); let arg_scope = Scope::Elision { elide: Elide::FreshLateAnon(Cell::new(0)), s: self.scope }; self.with(arg_scope, |_, this| { for input in inputs { @@ -2110,7 +2224,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { None => return, }; - debug!("visit_fn_like_elision: determine output"); + debug!("determine output"); // Figure out if there's a body we can get argument names from, // and whether there's a `self` argument (treated specially). @@ -2276,11 +2390,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Elide::Error(arg_lifetimes) }; - debug!("visit_fn_like_elision: elide={:?}", elide); + debug!(?elide); let scope = Scope::Elision { elide, s: self.scope }; self.with(scope, |_, this| this.visit_ty(output)); - debug!("visit_fn_like_elision: exit"); struct GatherLifetimes<'a> { map: &'a NamedRegionMap, @@ -2743,12 +2856,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } + #[tracing::instrument(level = "debug", skip(self))] fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { debug!( - "insert_lifetime: {} resolved to {:?} span={:?}", - self.tcx.hir().node_to_string(lifetime_ref.hir_id), - def, - self.tcx.sess.source_map().span_to_string(lifetime_ref.span) + node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id), + span = ?self.tcx.sess.source_map().span_to_string(lifetime_ref.span) ); self.map.defs.insert(lifetime_ref.hir_id, def); @@ -2762,12 +2874,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | Region::EarlyBound(_, def_id, _) => { // A lifetime declared by the user. let track_lifetime_uses = self.track_lifetime_uses(); - debug!("insert_lifetime: track_lifetime_uses={}", track_lifetime_uses); + debug!(?track_lifetime_uses); if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) { - debug!("insert_lifetime: first use of {:?}", def_id); + debug!("first use of {:?}", def_id); self.lifetime_uses.insert(def_id, LifetimeUseSet::One(lifetime_ref)); } else { - debug!("insert_lifetime: many uses of {:?}", def_id); + debug!("many uses of {:?}", def_id); self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 8076aa7102c..dbc518da8c8 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -198,6 +198,7 @@ pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> { } impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { + #[tracing::instrument(level = "debug", skip(self))] pub fn ast_region_to_region( &self, lifetime: &hir::Lifetime, @@ -237,6 +238,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { None => { self.re_infer(def, lifetime.span).unwrap_or_else(|| { + debug!(?lifetime, "unelided lifetime in signature"); + // This indicates an illegal lifetime // elision. `resolve_lifetime` should have // reported an error in this case -- but if @@ -2173,9 +2176,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors. + #[tracing::instrument(level = "debug", skip(self))] fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool) -> Ty<'tcx> { - debug!("ast_ty_to_ty(id={:?}, ast_ty={:?} ty_ty={:?})", ast_ty.hir_id, ast_ty, ast_ty.kind); - let tcx = self.tcx(); let result_ty = match ast_ty.kind { @@ -2185,7 +2187,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } hir::TyKind::Rptr(ref region, ref mt) => { let r = self.ast_region_to_region(region, None); - debug!("ast_ty_to_ty: r={:?}", r); + debug!(?r); let t = self.ast_ty_to_ty_inner(&mt.ty, true); tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) } @@ -2209,7 +2211,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed) } hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { - debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); + debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself)); self.res_to_ty(opt_self_ty, path, false) } @@ -2225,7 +2227,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { - debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); + debug!(?qself, ?segment); let ty = self.ast_ty_to_ty(qself); let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind { @@ -2270,7 +2272,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::TyKind::Err => tcx.ty_error(), }; - debug!("ast_ty_to_ty: result_ty={:?}", result_ty); + debug!(?result_ty); self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); result_ty diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index ac70e887626..b961fc8aeeb 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -23,17 +23,6 @@ LL | A(u8), LL | B(&'a bool), | -error[E0106]: missing lifetime specifier - --> $DIR/E0106.rs:10:14 - | -LL | type MyStr = &str; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type MyStr<'a> = &'a str; - | ^^^^ ^^^ - error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:17:10 | @@ -61,6 +50,17 @@ LL | LL | buzz: Buzz<'a, 'a>, | +error[E0106]: missing lifetime specifier + --> $DIR/E0106.rs:10:14 + | +LL | type MyStr = &str; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type MyStr<'a> = &'a str; + | ^^^^ ^^^ + error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr index 0f0406b8e17..497b8a429e0 100644 --- a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr +++ b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr @@ -1,3 +1,87 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/feature-gate-in_band_lifetimes.rs:50:14 + | +LL | impl MyTrait<'a> for Y<&'a u8> { + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/feature-gate-in_band_lifetimes.rs:50:25 + | +LL | impl MyTrait<'a> for Y<&'a u8> { + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/feature-gate-in_band_lifetimes.rs:53:31 + | +LL | fn my_lifetime(&self) -> &'a u8 { self.0 } + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes +help: consider introducing lifetime `'a` here + | +LL | impl<'a> MyTrait<'a> for Y<&'a u8> { + | ^^^^ +help: consider introducing lifetime `'a` here + | +LL | fn my_lifetime<'a>(&self) -> &'a u8 { self.0 } + | ^^^^ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/feature-gate-in_band_lifetimes.rs:55:27 + | +LL | fn any_lifetime() -> &'b u8 { &0 } + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes +help: consider introducing lifetime `'b` here + | +LL | impl<'b> MyTrait<'a> for Y<&'a u8> { + | ^^^^ +help: consider introducing lifetime `'b` here + | +LL | fn any_lifetime<'b>() -> &'b u8 { &0 } + | ^^^^ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/feature-gate-in_band_lifetimes.rs:57:27 + | +LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes +help: consider introducing lifetime `'b` here + | +LL | impl<'b> MyTrait<'a> for Y<&'a u8> { + | ^^^^ +help: consider introducing lifetime `'b` here + | +LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 } + | ^^^^ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/feature-gate-in_band_lifetimes.rs:57:40 + | +LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes +help: consider introducing lifetime `'b` here + | +LL | impl<'b> MyTrait<'a> for Y<&'a u8> { + | ^^^^ +help: consider introducing lifetime `'b` here + | +LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 } + | ^^^^ + error[E0261]: use of undeclared lifetime name `'x` --> $DIR/feature-gate-in_band_lifetimes.rs:3:12 | @@ -142,90 +226,6 @@ help: consider introducing lifetime `'b` here LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8; | ^^^^ -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:50:14 - | -LL | impl MyTrait<'a> for Y<&'a u8> { - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:50:25 - | -LL | impl MyTrait<'a> for Y<&'a u8> { - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:53:31 - | -LL | fn my_lifetime(&self) -> &'a u8 { self.0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'a` here - | -LL | impl<'a> MyTrait<'a> for Y<&'a u8> { - | ^^^^ -help: consider introducing lifetime `'a` here - | -LL | fn my_lifetime<'a>(&self) -> &'a u8 { self.0 } - | ^^^^ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:55:27 - | -LL | fn any_lifetime() -> &'b u8 { &0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b> MyTrait<'a> for Y<&'a u8> { - | ^^^^ -help: consider introducing lifetime `'b` here - | -LL | fn any_lifetime<'b>() -> &'b u8 { &0 } - | ^^^^ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:57:27 - | -LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b> MyTrait<'a> for Y<&'a u8> { - | ^^^^ -help: consider introducing lifetime `'b` here - | -LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 } - | ^^^^ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:57:40 - | -LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b> MyTrait<'a> for Y<&'a u8> { - | ^^^^ -help: consider introducing lifetime `'b` here - | -LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 } - | ^^^^ - error: aborting due to 17 previous errors For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index 95cebbb8681..d45ef83873a 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -14,14 +14,6 @@ LL | impl NoShadowT for Option { LL | type Bar = i32; | ^ already used -error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope - --> $DIR/shadowing.rs:5:14 - | -LL | trait Shadow<'a> { - | -- first declared here -LL | type Bar<'a>; - | ^^ lifetime `'a` already in scope - error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope --> $DIR/shadowing.rs:14:14 | @@ -30,6 +22,14 @@ LL | impl<'a> NoShadow<'a> for &'a u32 { LL | type Bar<'a> = i32; | ^^ lifetime `'a` already in scope +error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope + --> $DIR/shadowing.rs:5:14 + | +LL | trait Shadow<'a> { + | -- first declared here +LL | type Bar<'a>; + | ^^ lifetime `'a` already in scope + error: aborting due to 4 previous errors Some errors have detailed explanations: E0403, E0496. diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr index 1106a067822..ce853d4d36d 100644 --- a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr +++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr @@ -4,6 +4,17 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here LL | fn should_error() where T : Into<&u32> {} | ^ explicit lifetime name needed here +error[E0106]: missing lifetime specifier + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:17 + | +LL | fn bar<'b, L: X<&'b Nested>>(){} + | ^ expected named lifetime parameter + | +help: consider using the `'b` lifetime + | +LL | fn bar<'b, L: X<'b, &'b Nested>>(){} + | ^^^ + error[E0106]: missing lifetime specifier --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:21 | @@ -22,17 +33,6 @@ help: consider using one of the available lifetimes here LL | fn foo<'b, L: X<'lifetime, &'b Nested>>(); | ^^^^^^^^^^ -error[E0106]: missing lifetime specifier - --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:17 - | -LL | fn bar<'b, L: X<&'b Nested>>(){} - | ^ expected named lifetime parameter - | -help: consider using the `'b` lifetime - | -LL | fn bar<'b, L: X<'b, &'b Nested>>(){} - | ^^^ - error: aborting due to 3 previous errors Some errors have detailed explanations: E0106, E0637. diff --git a/src/test/ui/generics/wrong-number-of-args.stderr b/src/test/ui/generics/wrong-number-of-args.stderr index 73bd76aa5fa..94fdd355d48 100644 --- a/src/test/ui/generics/wrong-number-of-args.stderr +++ b/src/test/ui/generics/wrong-number-of-args.stderr @@ -1,36 +1,3 @@ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:44:14 - | -LL | type A = Ty; - | ^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Ty<'a>; - | ^^^^ ^^^^^^ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:54:17 - | -LL | type C = Ty; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type C<'a> = Ty<'a, usize>; - | ^^^^ ^^^ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:100:22 - | -LL | type B = Box; - | ^^^^^^^^^^^^^^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type B<'a> = Box>; - | ^^^^ ^^^^^^^^^^^^^^^^^^^ - error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied --> $DIR/wrong-number-of-args.rs:6:14 | @@ -165,6 +132,17 @@ help: use angle brackets to add missing type argument LL | type A = Ty; | ^^^ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:44:14 + | +LL | type A = Ty; + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Ty<'a>; + | ^^^^ ^^^^^^ + error[E0107]: this struct takes 1 type argument but 0 type arguments were supplied --> $DIR/wrong-number-of-args.rs:50:14 | @@ -181,6 +159,17 @@ help: add missing type argument LL | type B = Ty<'static, T>; | ^^^ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:54:17 + | +LL | type C = Ty; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type C<'a> = Ty<'a, usize>; + | ^^^^ ^^^ + error[E0107]: missing generics for struct `type_and_type_and_type::Ty` --> $DIR/wrong-number-of-args.rs:64:14 | @@ -243,6 +232,17 @@ note: trait defined here, with 0 type parameters LL | trait NonGeneric { | ^^^^^^^^^^ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:100:22 + | +LL | type B = Box; + | ^^^^^^^^^^^^^^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type B<'a> = Box>; + | ^^^^ ^^^^^^^^^^^^^^^^^^^ + error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied --> $DIR/wrong-number-of-args.rs:104:22 | diff --git a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.rs b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.rs index c1c40afdbab..3b407871e37 100644 --- a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.rs +++ b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.rs @@ -7,7 +7,7 @@ fn foo(x: &u32) { fn foo2(x: &u32) {} fn bar() { - let y: fn(&'test u32) = foo2; //~ ERROR use of undeclared lifetime + let y: fn(&'test u32) = foo2; } fn main() {} diff --git a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr index a43b49041ec..7ecb6ff0c9d 100644 --- a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr +++ b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr @@ -6,22 +6,6 @@ LL | fn foo(x: &u32) { LL | let y: &'test u32 = x; | ^^^^^ undeclared lifetime -error[E0261]: use of undeclared lifetime name `'test` - --> $DIR/no_introducing_in_band_in_locals.rs:10:16 - | -LL | let y: fn(&'test u32) = foo2; - | ^^^^^ undeclared lifetime - | - = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html -help: consider introducing lifetime `'test` here - | -LL | fn bar<'test>() { - | ^^^^^^^ -help: consider making the type lifetime-generic with a new `'test` lifetime - | -LL | let y: for<'test> fn(&'test u32) = foo2; - | ^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr index 30142e24cd5..16333a7ca38 100644 --- a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr +++ b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr @@ -1,3 +1,13 @@ +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9 + | +LL | struct Test { + | - help: consider introducing lifetime `'b` here: `<'b>` +LL | a: &'b str, + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + error[E0261]: use of undeclared lifetime name `'b` --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:13:13 | @@ -14,16 +24,6 @@ help: consider introducing lifetime `'b` here LL | fn foo<'b>(&'b self) {} | ^^^^ -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9 - | -LL | struct Test { - | - help: consider introducing lifetime `'b` here: `<'b>` -LL | a: &'b str, - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - error[E0261]: use of undeclared lifetime name `'b` --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9 | diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.rs b/src/test/ui/methods/method-call-lifetime-args-unresolved.rs index d16ba3df47b..d7760985ec6 100644 --- a/src/test/ui/methods/method-call-lifetime-args-unresolved.rs +++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.rs @@ -1,3 +1,5 @@ fn main() { 0.clone::<'a>(); //~ ERROR use of undeclared lifetime name `'a` + //~^ WARNING cannot specify lifetime arguments + //~| WARNING this was previously accepted } diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr index 93c0384fcc2..5a958bc4b9c 100644 --- a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr +++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr @@ -1,3 +1,18 @@ +warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-unresolved.rs:2:15 + | +LL | 0.clone::<'a>(); + | ^^ + | + ::: $SRC_DIR/core/src/clone.rs:LL:COL + | +LL | fn clone(&self) -> Self; + | - the late bound lifetime parameter is introduced here + | + = note: `#[warn(late_bound_lifetime_arguments)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 + error[E0261]: use of undeclared lifetime name `'a` --> $DIR/method-call-lifetime-args-unresolved.rs:2:15 | @@ -8,6 +23,6 @@ LL | 0.clone::<'a>(); | = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs index 0e3ea4bc8c9..6aa34354a7a 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs @@ -8,7 +8,7 @@ struct ChunkingIterator> { impl> Iterator for ChunkingIterator { type Item = IteratorChunk; //~ ERROR missing lifetime - fn next(&mut self) -> Option> { //~ ERROR `impl` + fn next(&mut self) -> Option> { todo!() } } diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr index 5df35fa571c..1e035ff99d0 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr @@ -9,22 +9,6 @@ help: consider introducing a named lifetime parameter LL | type Item<'a> = IteratorChunk<'a, T, S>; | ^^^^ ^^^ -error: `impl` item signature doesn't match `trait` item signature - --> $DIR/issue-74918-missing-lifetime.rs:11:5 - | -LL | fn next(&mut self) -> Option> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&mut ChunkingIterator) -> Option>` - | - ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - | -LL | fn next(&mut self) -> Option; - | ----------------------------------------- expected `fn(&mut ChunkingIterator) -> Option>` - | - = note: expected `fn(&mut ChunkingIterator) -> Option>` - found `fn(&mut ChunkingIterator) -> Option>` - = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` - = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index ad0e7bd5afb..5f6ff280e65 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -1,3 +1,23 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-name-undeclared.rs:28:13 + | +LL | enum E { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | E1(&'a isize) + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-name-undeclared.rs:31:13 + | +LL | struct S { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | f: &'a isize + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:16:24 | @@ -56,26 +76,6 @@ LL | type X = Option<&'a isize>; | = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/regions-name-undeclared.rs:28:13 - | -LL | enum E { - | - help: consider introducing lifetime `'a` here: `<'a>` -LL | E1(&'a isize) - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/regions-name-undeclared.rs:31:13 - | -LL | struct S { - | - help: consider introducing lifetime `'a` here: `<'a>` -LL | f: &'a isize - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:33:14 | diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs index 94dd826a15c..dd434ea5318 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -16,14 +16,13 @@ fn foo(g: G, dest: &mut T) -> impl FnOnce() where G: Get { - move || { //~ ERROR `dest` + move || { *dest = g.get(); } } // After applying suggestion for `foo`: fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ -//~^ ERROR the parameter type `G` may not live long enough where G: Get { @@ -45,7 +44,6 @@ where // After applying suggestion for `baz`: fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ -//~^ ERROR the parameter type `G` may not live long enough where G: Get { @@ -57,7 +55,6 @@ where // Same as above, but show that we pay attention to lifetime names from parent item impl<'a> Foo { fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - //~^ ERROR the parameter type `G` may not live long enough move || { *dest = g.get(); } @@ -66,7 +63,6 @@ impl<'a> Foo { // After applying suggestion for `qux`: fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a -//~^ ERROR explicit lifetime required in the type of `dest` where G: Get { @@ -77,7 +73,6 @@ where // Potential incorrect attempt: fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a -//~^ ERROR the parameter type `G` may not live long enough where G: Get { diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 789fff7acc2..916a6c2bf12 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -1,112 +1,11 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/missing-lifetimes-in-signature.rs:37:11 + --> $DIR/missing-lifetimes-in-signature.rs:36:11 | LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `'a,` -error[E0759]: `dest` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/missing-lifetimes-in-signature.rs:19:5 - | -LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() - | ------ this data with an anonymous lifetime `'_`... -... -LL | / move || { -LL | | *dest = g.get(); -LL | | } - | |_____^ ...is captured here... - | -note: ...and is required to live as long as `'static` here - --> $DIR/missing-lifetimes-in-signature.rs:15:37 - | -LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() - | ^^^^^^^^^^^^^ -help: to declare that the `impl Trait` captures data from argument `dest`, you can add an explicit `'_` lifetime bound - | -LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^ +error: aborting due to previous error -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:25:37 - | -LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the function body at 25:26... - --> $DIR/missing-lifetimes-in-signature.rs:25:26 - | -LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: 32:6]` will meet its required lifetime bounds - --> $DIR/missing-lifetimes-in-signature.rs:25:37 - | -LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ -help: consider introducing an explicit lifetime bound - | -LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ^^^^^ ^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:47:45 - | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the function body at 47:34... - --> $DIR/missing-lifetimes-in-signature.rs:47:34 - | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: 54:6]` will meet its required lifetime bounds - --> $DIR/missing-lifetimes-in-signature.rs:47:45 - | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ -help: consider introducing an explicit lifetime bound - | -LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b - | ^^^ ^^^^^^^ ^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:59:58 - | -LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the method body at 59:47... - --> $DIR/missing-lifetimes-in-signature.rs:59:47 - | -LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ^^^^^^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10]` will meet its required lifetime bounds - --> $DIR/missing-lifetimes-in-signature.rs:59:58 - | -LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ^^^^^^^^^^^^^^^^^^ -help: consider introducing an explicit lifetime bound - | -LL | fn qux<'c, 'b, G: 'c + Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c { - | ^^^ ^^^^^^^ ^^^^ - -error[E0621]: explicit lifetime required in the type of `dest` - --> $DIR/missing-lifetimes-in-signature.rs:68:45 - | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ------ ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required - | | - | help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` - -error[E0309]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:79:44 - | -LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:84:5: 86:6]` will meet its required lifetime bounds - | | - | help: consider adding an explicit lifetime bound...: `G: 'a` - -error: aborting due to 7 previous errors - -Some errors have detailed explanations: E0261, E0309, E0621, E0759. -For more information about an error, try `rustc --explain E0261`. +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.stderr b/src/test/ui/suggestions/missing-lifetime-specifier.stderr index e6cec5cbd45..489926ea78a 100644 --- a/src/test/ui/suggestions/missing-lifetime-specifier.stderr +++ b/src/test/ui/suggestions/missing-lifetime-specifier.stderr @@ -142,30 +142,6 @@ help: consider using the `'static` lifetime LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^^^^^^^^^^^^^^^ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:50:44 - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^^^^^^ - -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:50:44 - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^^^^^^ - error[E0107]: this union takes 2 lifetime arguments but only 1 lifetime argument was supplied --> $DIR/missing-lifetime-specifier.rs:43:44 | @@ -256,6 +232,18 @@ help: add missing lifetime argument LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^^ +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:50:44 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + error[E0107]: this trait takes 2 lifetime arguments but only 1 lifetime argument was supplied --> $DIR/missing-lifetime-specifier.rs:50:45 | @@ -274,6 +262,18 @@ help: add missing lifetime argument LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^^ +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:50:44 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + error[E0107]: this trait takes 2 lifetime arguments but only 1 lifetime argument was supplied --> $DIR/missing-lifetime-specifier.rs:50:45 | From cfbd0eed98c93fed6dbcec4eb2e63966ff0ffc1b Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Fri, 12 Mar 2021 12:38:42 -0500 Subject: [PATCH 2/4] Review comments --- compiler/rustc_middle/src/query/mod.rs | 18 +++++-- compiler/rustc_resolve/src/late/lifetimes.rs | 53 ++++++++++++++------ 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 93e4c97efd8..9014d798a64 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1252,12 +1252,18 @@ rustc_queries! { desc { "looking up link arguments for a crate" } } - /// Lifetime resolution. See `middle::resolve_lifetimes`. - query resolve_lifetimes_definition(_: LocalDefId) -> ResolveLifetimes { + /// Does lifetime resolution, but does not descend into trait items. This + /// should only be used for resolving lifetimes of on trait definitions, + /// and is used to avoid cycles. Importantly, `resolve_lifetimes` still visits + /// the same lifetimes and is responsible for diagnostics. + /// See `rustc_resolve::late::lifetimes for details. + query resolve_lifetimes_trait_definition(_: LocalDefId) -> ResolveLifetimes { storage(ArenaCacheSelector<'tcx>) - desc { "resolving lifetimes in a definition" } + desc { "resolving lifetimes for a trait definition" } } - /// Lifetime resolution. See `middle::resolve_lifetimes`. + /// Does lifetime resolution on items. Importantly, we can't resolve + /// lifetimes directly on things like trait methods, because of trait params. + /// See `rustc_resolve::late::lifetimes for details. query resolve_lifetimes(_: LocalDefId) -> ResolveLifetimes { storage(ArenaCacheSelector<'tcx>) desc { "resolving lifetimes" } @@ -1270,6 +1276,10 @@ rustc_queries! { Option<(LocalDefId, &'tcx FxHashSet)> { desc { "testing if a region is late bound" } } + /// For a given item (like a struct), gets the default lifetimes to be used + /// for each paramter if a trait object were to be passed for that parameter. + /// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`. + /// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`. query object_lifetime_defaults_map(_: LocalDefId) -> Option> { desc { "looking up lifetime defaults for a region on an item" } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 02b732e75ef..a47a574218f 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -174,7 +174,10 @@ crate struct LifetimeContext<'a, 'tcx> { is_in_const_generic: bool, - definition_only: bool, + /// Indicates that we only care about the definition of a trait. This should + /// be false if the `Item` we are resolving lifetimes for is not a trait or + /// we eventually need lifetimes resolve for trait items. + trait_definition_only: bool, /// List of labels in the function/method currently under analysis. labels_in_fn: Vec, @@ -319,7 +322,7 @@ const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { - resolve_lifetimes_definition, + resolve_lifetimes_trait_definition, resolve_lifetimes, named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id), @@ -339,14 +342,16 @@ pub fn provide(providers: &mut ty::query::Providers) { /// Like `resolve_lifetimes`, but does not resolve lifetimes for trait items. /// Also does not generate any diagnostics. #[tracing::instrument(level = "debug", skip(tcx))] -fn resolve_lifetimes_definition(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { +fn resolve_lifetimes_trait_definition( + tcx: TyCtxt<'_>, + local_def_id: LocalDefId, +) -> ResolveLifetimes { do_resolve(tcx, local_def_id, true) } -/// Computes the `ResolveLifetimes` map that contains data for the -/// entire crate. You should not read the result of this query -/// directly, but rather use `named_region_map`, `is_late_bound_map`, -/// etc. +/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`. +/// You should not read the result of this query directly, but rather use +/// `named_region_map`, `is_late_bound_map`, etc. #[tracing::instrument(level = "debug", skip(tcx))] fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { do_resolve(tcx, local_def_id, false) @@ -355,7 +360,7 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifeti fn do_resolve( tcx: TyCtxt<'_>, local_def_id: LocalDefId, - definition_only: bool, + trait_definition_only: bool, ) -> ResolveLifetimes { let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(local_def_id)); let mut named_region_map = @@ -367,7 +372,7 @@ fn do_resolve( trait_ref_hack: false, is_in_fn_syntax: false, is_in_const_generic: false, - definition_only, + trait_definition_only, labels_in_fn: vec![], xcrate_object_lifetime_defaults: Default::default(), lifetime_uses: &mut Default::default(), @@ -390,12 +395,22 @@ fn do_resolve( rl } +/// Given `any` owner (structs, traits, trait methods, etc.), does lifetime resolution. +/// There are two important things this does. +/// First, we have to resolve lifetimes for +/// the entire *`Item`* that contains this owner, because that's the largest "scope" +/// where we can have relevant lifetimes. +/// Second, if we are asking for lifetimes in a trait *definition*, we use `resolve_lifetimes_trait_definition` +/// instead of `resolve_lifetimes`, which does not descend into the trait items and does not emit diagnostics. +/// This allows us to avoid cycles. Importantly, if we ask for lifetimes for lifetimes that have an owner +/// other than the trait itself (like the trait methods or associated types), then we just use the regular +/// `resolve_lifetimes`. fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ResolveLifetimes { let item_id = item_for(tcx, def_id); if item_id == def_id { let item = tcx.hir().item(hir::ItemId { def_id: item_id }); match item.kind { - hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_definition(item_id), + hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(item_id), _ => tcx.resolve_lifetimes(item_id), } } else { @@ -403,6 +418,7 @@ fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx R } } +/// Finds the `Item` that contains the given `LocalDefId` fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId { let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id); match tcx.hir().find(hir_id) { @@ -470,7 +486,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_nested_item(&mut self, _: hir::ItemId) {} fn visit_trait_item_ref(&mut self, ii: &'tcx hir::TraitItemRef) { - if !self.definition_only { + if !self.trait_definition_only { intravisit::walk_trait_item_ref(self, ii) } } @@ -513,6 +529,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // Opaque types are visited when we visit the // `TyKind::OpaqueDef`, so that they have the lifetimes from // their parent opaque_ty in scope. + // + // The core idea here is that since OpaqueTys are generated with the impl Trait as + // their owner, we can keep going until we find the Item that owns that. We then + // conservatively add all resolved lifetimes. Otherwise we run into problems in + // cases like `type Foo<'a> = impl Bar`. for (_hir_id, node) in self.tcx.hir().parent_iter(self.tcx.hir().local_def_id_to_hir_id(item.def_id)) { @@ -760,7 +781,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; if !parent_is_item { - if !self.definition_only { + if !self.trait_definition_only { struct_span_err!( self.tcx.sess, lifetime.span, @@ -1007,7 +1028,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { - if !self.definition_only { + if !self.trait_definition_only { check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); } for param in generics.params { @@ -1501,7 +1522,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { trait_ref_hack: self.trait_ref_hack, is_in_fn_syntax: self.is_in_fn_syntax, is_in_const_generic: self.is_in_const_generic, - definition_only: self.definition_only, + trait_definition_only: self.trait_definition_only, labels_in_fn, xcrate_object_lifetime_defaults, lifetime_uses, @@ -1511,7 +1532,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { { let _enter = span.enter(); f(self.scope, &mut this); - if !self.definition_only { + if !self.trait_definition_only { this.check_uses_for_lifetimes_defined_by_scope(); } } @@ -1973,7 +1994,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } // Check for fn-syntax conflicts with in-band lifetime definitions - if !self.definition_only && self.is_in_fn_syntax { + if !self.trait_definition_only && self.is_in_fn_syntax { match def { Region::EarlyBound(_, _, LifetimeDefOrigin::InBand) | Region::LateBound(_, _, LifetimeDefOrigin::InBand) => { From 7cb8f513c6fbea904703bfd0f28f70f439d6f671 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 25 Mar 2021 09:22:15 -0400 Subject: [PATCH 3/4] write-up what is happening --- compiler/rustc_resolve/src/late/lifetimes.rs | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index a47a574218f..698e5048f7b 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -341,6 +341,34 @@ pub fn provide(providers: &mut ty::query::Providers) { /// Like `resolve_lifetimes`, but does not resolve lifetimes for trait items. /// Also does not generate any diagnostics. +/// +/// This is ultimately a subset of the `resolve_lifetimes` work. It effectively +/// resolves lifetimes only within the trait "header" -- that is, the trait +/// and supertrait list. In contrast, `resolve_lifetimes` resolves all the +/// lifetimes within the trait and its items. There is room to refactor this, +/// for example to resolve lifetimes for each trait item in separate queries, +/// but it's convenient to do the entire trait at once because the lifetimes +/// from the trait definition are in scope within the trait items as well. +/// +/// The reason for this separate call is to resolve what would otherwise +/// be a cycle. Consider this example: +/// +/// ```rust +/// trait Base<'a> { +/// type BaseItem; +/// } +/// trait Sub<'b>: for<'a> Base<'a> { +/// type SubItem: Sub; +/// } +/// ``` +/// +/// When we resolve `Sub` and all its items, we also have to resolve `Sub`. +/// To figure out the index of `'b`, we have to know about the supertraits +/// of `Sub` so that we can determine that the `for<'a>` will be in scope. +/// (This is because we -- currently at least -- flatten all the late-bound +/// lifetimes into a single binder.) This requires us to resolve the +/// *trait definition* of `Sub`; basically just enough lifetime information +/// to look at the supertraits. #[tracing::instrument(level = "debug", skip(tcx))] fn resolve_lifetimes_trait_definition( tcx: TyCtxt<'_>, From 44e9d201c1a5bb7db4fd9e312ea1ad690fc42476 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Thu, 25 Mar 2021 14:11:03 -0400 Subject: [PATCH 4/4] Bless nll test --- .../missing-lifetimes-in-signature.nll.stderr | 87 +------------------ 1 file changed, 3 insertions(+), 84 deletions(-) diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr index b509610b89e..916a6c2bf12 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr @@ -1,92 +1,11 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/missing-lifetimes-in-signature.rs:37:11 + --> $DIR/missing-lifetimes-in-signature.rs:36:11 | LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `'a,` -error: lifetime may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:15:37 - | -LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() - | - ^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static` - | | - | let's call the lifetime of this reference `'1` - | -help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound - | -LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ +error: aborting due to previous error -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:25:37 - | -LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the function body at 25:26... - --> $DIR/missing-lifetimes-in-signature.rs:25:26 - | -LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:47:45 - | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the function body at 47:34... - --> $DIR/missing-lifetimes-in-signature.rs:47:34 - | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:59:58 - | -LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the method body at 59:47... - --> $DIR/missing-lifetimes-in-signature.rs:59:47 - | -LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ^^^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:68:45 - | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the function body at 68:34... - --> $DIR/missing-lifetimes-in-signature.rs:68:34 - | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ^^^^^^ - -error[E0621]: explicit lifetime required in the type of `dest` - --> $DIR/missing-lifetimes-in-signature.rs:73:5 - | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` -... -LL | / move || { -LL | | *dest = g.get(); -LL | | } - | |_____^ lifetime `'a` required - -error[E0309]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:79:44 - | -LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | ^^^^^^^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `G: 'a`... - -error: aborting due to 8 previous errors - -Some errors have detailed explanations: E0261, E0309, E0621. -For more information about an error, try `rustc --explain E0261`. +For more information about this error, try `rustc --explain E0261`.