From 59ea28e652dd56fd6546d653472e5d82b853feb2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 23 May 2022 17:20:48 +0200 Subject: [PATCH 01/13] Make object_lifetime_defaults a cross-crate query. --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_resolve/src/late/lifetimes.rs | 59 +++++++------------- 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 899d6c7e490a6..f29d1f25e2829 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1591,7 +1591,7 @@ rustc_queries! { /// for each parameter 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(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> { + query object_lifetime_defaults(_: DefId) -> Option<&'tcx [ObjectLifetimeDefault]> { desc { "looking up lifetime defaults for a region on an item" } } query late_bound_vars_map(_: LocalDefId) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 11f80b314d770..c862312fe4e51 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefIdMap, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::hir_id::ItemLocalId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node}; @@ -156,9 +156,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> { /// we eventually need lifetimes resolve for trait items. trait_definition_only: bool, - /// Cache for cross-crate per-definition object lifetime defaults. - xcrate_object_lifetime_defaults: DefIdMap>, - /// When encountering an undefined named lifetime, we will suggest introducing it in these /// places. pub(crate) missing_named_lifetime_spots: Vec>, @@ -348,9 +345,23 @@ pub fn provide(providers: &mut ty::query::Providers) { named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id), is_late_bound_map, - object_lifetime_defaults: |tcx, id| match tcx.hir().find_by_def_id(id) { - Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item), - _ => None, + object_lifetime_defaults: |tcx, def_id| { + if let Some(def_id) = def_id.as_local() { + match tcx.hir().get_by_def_id(def_id) { + Node::Item(item) => compute_object_lifetime_defaults(tcx, item), + _ => None, + } + } else { + Some(tcx.arena.alloc_from_iter(tcx.generics_of(def_id).params.iter().filter_map( + |param| match param.kind { + GenericParamDefKind::Type { object_lifetime_default, .. } => { + Some(object_lifetime_default) + } + GenericParamDefKind::Const { .. } => Some(Set1::Empty), + GenericParamDefKind::Lifetime => None, + }, + ))) + } }, late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id), lifetime_scope_map: |tcx, id| { @@ -425,7 +436,6 @@ fn do_resolve( map: &mut named_region_map, scope: ROOT_SCOPE, trait_definition_only, - xcrate_object_lifetime_defaults: Default::default(), missing_named_lifetime_spots: vec![], }; visitor.visit_item(item); @@ -1573,14 +1583,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), { let LifetimeContext { tcx, map, .. } = self; - let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots); let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope, trait_definition_only: self.trait_definition_only, - xcrate_object_lifetime_defaults, missing_named_lifetime_spots, }; let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); @@ -1588,7 +1596,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let _enter = span.enter(); f(&mut this); } - self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; } @@ -1904,35 +1911,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } 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); - self.tcx - .object_lifetime_defaults(id.owner) - .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::Const { .. } => Some(Set1::Empty), - GenericParamDefKind::Lifetime => None, - }) - .collect() - }) - .iter() - .map(set_to_region) - .collect() - } + self.tcx.object_lifetime_defaults(def_id).unwrap().iter().map(set_to_region).collect() }); debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); From ca16d287ba7628e283683d9118b5da21e70d0823 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 24 May 2022 08:30:27 +0200 Subject: [PATCH 02/13] Separate computation of object lifetime default. --- compiler/rustc_middle/src/query/mod.rs | 5 + compiler/rustc_resolve/src/late/lifetimes.rs | 359 +--------- compiler/rustc_typeck/src/astconv/mod.rs | 71 +- compiler/rustc_typeck/src/collect.rs | 12 +- .../src/collect/object_lifetime_defaults.rs | 654 ++++++++++++++++++ src/test/ui/issues/issue-41139.rs | 2 +- src/test/ui/issues/issue-41139.stderr | 4 +- 7 files changed, 731 insertions(+), 376 deletions(-) create mode 100644 compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f29d1f25e2829..5c5d99f76ed29 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1594,6 +1594,11 @@ rustc_queries! { query object_lifetime_defaults(_: DefId) -> Option<&'tcx [ObjectLifetimeDefault]> { desc { "looking up lifetime defaults for a region on an item" } } + /// Fetch the lifetimes for all the trait objects in an item-like. + query object_lifetime_map(_: LocalDefId) -> FxHashMap { + storage(ArenaCacheSelector<'tcx>) + desc { "looking up lifetime defaults for a region on an item" } + } query late_bound_vars_map(_: LocalDefId) -> Option<&'tcx FxHashMap>> { desc { "looking up late bound vars" } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index c862312fe4e51..728a6e4ba01c9 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -20,12 +20,11 @@ use rustc_hir::{GenericParamKind, HirIdMap}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::*; -use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; -use std::borrow::Cow; use std::cell::Cell; use std::fmt; use std::mem::take; @@ -44,10 +43,6 @@ trait RegionExt { fn shifted(self, amount: u32) -> Region; fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region; - - fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option - where - L: Iterator; } impl RegionExt for Region { @@ -109,17 +104,6 @@ impl RegionExt for Region { _ => self, } } - - fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option - where - L: Iterator, - { - if let Region::EarlyBound(index, _) = self { - params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned()) - } else { - Some(self) - } - } } /// Maps the id of each lifetime reference to the lifetime decl @@ -222,14 +206,6 @@ enum Scope<'a> { s: ScopeRef<'a>, }, - /// Use a specific lifetime (if `Some`) or leave it unset (to be - /// inferred in a function body or potentially error outside one), - /// for the default choice of lifetime in a trait object type. - ObjectLifetimeDefault { - lifetime: Option, - s: ScopeRef<'a>, - }, - /// When we have nested trait refs, we concatenate late bound vars for inner /// trait refs from outer ones. But we also need to include any HRTB /// lifetimes encountered when identifying the trait that an associated type @@ -292,11 +268,6 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { 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::Supertrait { lifetimes, s: _ } => f .debug_struct("Supertrait") .field("lifetimes", lifetimes) @@ -345,24 +316,6 @@ pub fn provide(providers: &mut ty::query::Providers) { named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id), is_late_bound_map, - object_lifetime_defaults: |tcx, def_id| { - if let Some(def_id) = def_id.as_local() { - match tcx.hir().get_by_def_id(def_id) { - Node::Item(item) => compute_object_lifetime_defaults(tcx, item), - _ => None, - } - } else { - Some(tcx.arena.alloc_from_iter(tcx.generics_of(def_id).params.iter().filter_map( - |param| match param.kind { - GenericParamDefKind::Type { object_lifetime_default, .. } => { - Some(object_lifetime_default) - } - GenericParamDefKind::Const { .. } => Some(Set1::Empty), - GenericParamDefKind::Lifetime => None, - }, - ))) - } - }, late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id), lifetime_scope_map: |tcx, id| { let item_id = item_for(tcx, id); @@ -544,9 +497,6 @@ fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath { scope = s; } } - Scope::ObjectLifetimeDefault { s, .. } => { - scope = s; - } Scope::Root => { return LifetimeScopeForPath::NonElided(available_lifetimes); } @@ -568,7 +518,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break (vec![], BinderScopeType::Normal); } - Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { + Scope::Elision { s, .. } => { scope = s; } @@ -855,7 +805,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // use the object lifetime defaulting // rules. So e.g., `Box` becomes // `Box`. - self.resolve_object_lifetime_default(lifetime) } LifetimeName::Underscore => { // If the user writes `'_`, we use the *ordinary* elision @@ -874,11 +823,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } hir::TyKind::Rptr(ref lifetime_ref, ref mt) => { self.visit_lifetime(lifetime_ref); - let scope = Scope::ObjectLifetimeDefault { - lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), - s: self.scope, - }; - self.with(scope, |this| this.visit_ty(&mt.ty)); + self.visit_ty(&mt.ty); } hir::TyKind::OpaqueDef(item_id, lifetimes) => { // Resolve the lifetimes in the bounds to the lifetime defs in the generics. @@ -1442,141 +1387,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } -fn compute_object_lifetime_defaults<'tcx>( - tcx: TyCtxt<'tcx>, - item: &hir::Item<'_>, -) -> Option<&'tcx [ObjectLifetimeDefault]> { - 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, - origin: hir::OpaqueTyOrigin::TyAlias, - .. - }) - | 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 - } - _ => None, - }) - .unwrap(), - Set1::One(_) => bug!(), - Set1::Many => "Ambiguous".into(), - }) - .collect::>>() - .join(","); - tcx.sess.span_err(item.span, &object_lifetime_default_reprs); - } - - Some(result) - } - _ => None, - } -} - -/// Scan the bounds and where-clauses on parameters to extract bounds -/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` -/// for each type parameter. -fn object_lifetime_defaults_for_item<'tcx>( - tcx: TyCtxt<'tcx>, - generics: &hir::Generics<'_>, -) -> &'tcx [ObjectLifetimeDefault] { - fn add_bounds(set: &mut Set1, bounds: &[hir::GenericBound<'_>]) { - for bound in bounds { - if let hir::GenericBound::Outlives(ref lifetime) = *bound { - set.insert(lifetime.name.normalize_to_macros_2_0()); - } - } - } - - let process_param = |param: &hir::GenericParam<'_>| match param.kind { - GenericParamKind::Lifetime { .. } => None, - GenericParamKind::Type { .. } => { - let mut set = Set1::Empty; - - let param_def_id = tcx.hir().local_def_id(param.hir_id); - for predicate in generics.predicates { - // Look for `type: ...` where clauses. - let hir::WherePredicate::BoundPredicate(ref data) = *predicate else { continue }; - - // Ignore `for<'a> type: ...` as they can change what - // lifetimes mean (although we could "just" handle it). - if !data.bound_generic_params.is_empty() { - continue; - } - - let res = match data.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res, - _ => continue, - }; - - if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) { - add_bounds(&mut set, &data.bounds); - } - } - - Some(match set { - Set1::Empty => Set1::Empty, - Set1::One(name) => { - if name == hir::LifetimeName::Static { - Set1::One(Region::Static) - } else { - generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - let param_def_id = tcx.hir().local_def_id(param.hir_id); - Some(( - param_def_id, - hir::LifetimeName::Param(param_def_id, param.name), - )) - } - _ => None, - }) - .enumerate() - .find(|&(_, (_, lt_name))| lt_name == name) - .map_or(Set1::Many, |(i, (def_id, _))| { - Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id())) - }) - } - } - Set1::Many => Set1::Many, - }) - } - GenericParamKind::Const { .. } => { - // Generic consts don't impose any constraints. - // - // We still store a dummy value here to allow generic parameters - // in an arbitrary order. - Some(Set1::Empty) - } - }; - - tcx.arena.alloc_from_iter(generics.params.iter().filter_map(process_param)) -} - impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn with(&mut self, wrap_scope: Scope<'_>, f: F) where @@ -1706,7 +1516,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Binder { s, .. } | Scope::Body { s, .. } | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => scope = s, } @@ -1763,7 +1572,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { scope = s; @@ -1857,138 +1665,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }; debug!("visit_segment_args: type_def_id={:?}", type_def_id); - - // Compute a vector of defaults, one for each type parameter, - // per the rules given in RFCs 599 and 1156. Example: - // - // ```rust - // struct Foo<'a, T: 'a, U> { } - // ``` - // - // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default - // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) - // and `dyn Baz` to `dyn Baz + 'static` (because there is no - // such bound). - // - // Therefore, we would compute `object_lifetime_defaults` to a - // vector like `['x, 'static]`. Note that the vector only - // includes type parameters. - let object_lifetime_defaults = type_def_id.map_or_else(Vec::new, |def_id| { - let in_body = { - let mut scope = self.scope; - loop { - match *scope { - Scope::Root => break false, - - Scope::Body { .. } => break true, - - Scope::Binder { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } - | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { - scope = s; - } - } - } - }; - - let map = &self.map; - 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, - }; - self.tcx.object_lifetime_defaults(def_id).unwrap().iter().map(set_to_region).collect() - }); - - debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); - - let mut i = 0; for arg in generic_args.args { match arg { GenericArg::Lifetime(_) => {} - GenericArg::Type(ty) => { - if let Some(<) = object_lifetime_defaults.get(i) { - let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; - self.with(scope, |this| this.visit_ty(ty)); - } else { - self.visit_ty(ty); - } - i += 1; - } - GenericArg::Const(ct) => { - self.visit_anon_const(&ct.value); - i += 1; - } - GenericArg::Infer(inf) => { - self.visit_id(inf.hir_id); - i += 1; - } + GenericArg::Type(ty) => self.visit_ty(ty), + GenericArg::Const(ct) => self.visit_anon_const(&ct.value), + GenericArg::Infer(inf) => self.visit_id(inf.hir_id), } } - // Hack: when resolving the type `XX` in binding like `dyn - // Foo<'b, Item = XX>`, the current object-lifetime default - // would be to examine the trait `Foo` to check whether it has - // a lifetime bound declared on `Item`. e.g., if `Foo` is - // declared like so, then the default object lifetime bound in - // `XX` should be `'b`: - // - // ```rust - // trait Foo<'a> { - // type Item: 'a; - // } - // ``` - // - // but if we just have `type Item;`, then it would be - // `'static`. However, we don't get all of this logic correct. - // - // Instead, we do something hacky: if there are no lifetime parameters - // to the trait, then we simply use a default object lifetime - // bound of `'static`, because there is no other possibility. On the other hand, - // if there ARE lifetime parameters, then we require the user to give an - // explicit bound for now. - // - // This is intended to leave room for us to implement the - // correct behavior in the future. - let has_lifetime_parameter = - generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); - // Resolve lifetimes found in the bindings, so either in the type `XX` in `Item = XX` or // in the trait ref `YY<...>` in `Item: YY<...>`. for binding in generic_args.bindings { - let scope = Scope::ObjectLifetimeDefault { - lifetime: if has_lifetime_parameter { None } else { Some(Region::Static) }, - s: self.scope, - }; if let Some(type_def_id) = type_def_id { let lifetimes = LifetimeContext::supertrait_hrtb_lifetimes( self.tcx, type_def_id, binding.ident, ); - self.with(scope, |this| { - let scope = Scope::Supertrait { - lifetimes: lifetimes.unwrap_or_default(), - s: this.scope, - }; - this.with(scope, |this| this.visit_assoc_type_binding(binding)); - }); - } else { + let scope = + Scope::Supertrait { lifetimes: lifetimes.unwrap_or_default(), s: self.scope }; self.with(scope, |this| this.visit_assoc_type_binding(binding)); + } else { + self.visit_assoc_type_binding(binding); } } } @@ -2069,8 +1768,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Binder { hir_id, allow_late_bound: true, .. } => { break *hir_id; } - Scope::ObjectLifetimeDefault { ref s, .. } - | Scope::Elision { ref s, .. } + Scope::Elision { ref s, .. } | Scope::Supertrait { ref s, .. } | Scope::TraitRefBoundary { ref s, .. } => { scope = *s; @@ -2449,8 +2147,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { in_scope_lifetimes.extend(lifetimes.keys().copied()); scope = s; } - Scope::ObjectLifetimeDefault { ref s, .. } - | Scope::Elision { ref s, .. } + Scope::Elision { ref s, .. } | Scope::TraitRefBoundary { ref s, .. } => { scope = s; } @@ -2462,9 +2159,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Elision { elide: Elide::Forbid, .. } => break None, - Scope::ObjectLifetimeDefault { s, .. } - | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { + Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { scope = s; } } @@ -2500,34 +2195,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { err.emit(); } - fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); - let mut late_depth = 0; - let mut scope = self.scope; - let lifetime = loop { - match *scope { - Scope::Binder { s, scope_type, .. } => { - match scope_type { - BinderScopeType::Normal => late_depth += 1, - BinderScopeType::Concatenating => {} - } - scope = s; - } - - Scope::Root | Scope::Elision { .. } => break Region::Static, - - Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, - - Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, - - Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { - scope = s; - } - } - }; - self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); - } - #[tracing::instrument(level = "debug", skip(self))] fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { debug!( diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index bcff2ae512909..15501cd765cb1 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -202,12 +202,39 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def: Option<&ty::GenericParamDef>, ) -> ty::Region<'tcx> { let tcx = self.tcx(); + + let r = if let Some(rl) = tcx.named_region(lifetime.hir_id) { + self.ast_region_to_region_inner(rl) + } else { + 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 + // not, let's error out. + tcx.sess.delay_span_bug(lifetime.span, "unelided lifetime in signature"); + + // Supply some dummy value. We don't have an + // `re_error`, annoyingly, so use `'static`. + tcx.lifetimes.re_static + }) + }; + + debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r); + + r + } + + #[tracing::instrument(level = "debug", skip(self))] + fn ast_region_to_region_inner(&self, lifetime: rl::Region) -> ty::Region<'tcx> { + let tcx = self.tcx(); let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)); - let r = match tcx.named_region(lifetime.hir_id) { - Some(rl::Region::Static) => tcx.lifetimes.re_static, + let r = match lifetime { + rl::Region::Static => tcx.lifetimes.re_static, - Some(rl::Region::LateBound(debruijn, index, def_id)) => { + rl::Region::LateBound(debruijn, index, def_id) => { let name = lifetime_name(def_id.expect_local()); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), @@ -216,7 +243,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.mk_region(ty::ReLateBound(debruijn, br)) } - Some(rl::Region::LateBoundAnon(debruijn, index, anon_index)) => { + rl::Region::LateBoundAnon(debruijn, index, anon_index) => { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), kind: ty::BrAnon(anon_index), @@ -224,12 +251,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.mk_region(ty::ReLateBound(debruijn, br)) } - Some(rl::Region::EarlyBound(index, id)) => { + rl::Region::EarlyBound(index, id) => { let name = lifetime_name(id.expect_local()); tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name })) } - Some(rl::Region::Free(scope, id)) => { + rl::Region::Free(scope, id) => { let name = lifetime_name(id.expect_local()); tcx.mk_region(ty::ReFree(ty::FreeRegion { scope, @@ -238,22 +265,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // (*) -- not late-bound, won't change } - - 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 - // not, let's error out. - tcx.sess.delay_span_bug(lifetime.span, "unelided lifetime in signature"); - - // Supply some dummy value. We don't have an - // `re_error`, annoyingly, so use `'static`. - tcx.lifetimes.re_static - }) - } }; debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r); @@ -1537,8 +1548,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ast_region_to_region(lifetime, None) } else { self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { - if tcx.named_region(lifetime.hir_id).is_some() { - self.ast_region_to_region(lifetime, None) + if let Some(rl) = tcx.named_region(lifetime.hir_id) { + self.ast_region_to_region_inner(rl) + } else if let Some(&rl) = + tcx.object_lifetime_map(lifetime.hir_id.owner).get(&lifetime.hir_id.local_id) + { + self.ast_region_to_region_inner(rl) } else { self.re_infer(None, span).unwrap_or_else(|| { let mut err = struct_span_err!( @@ -2840,10 +2855,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); if !infer_replacements.is_empty() { - diag.multipart_suggestion(&format!( + diag.multipart_suggestion( + &format!( "try replacing `_` with the type{} in the corresponding trait method signature", rustc_errors::pluralize!(infer_replacements.len()), - ), infer_replacements, Applicability::MachineApplicable); + ), + infer_replacements, + Applicability::MachineApplicable, + ); } diag.emit(); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 34d107349e7c7..cb0d1715255a8 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -50,6 +50,7 @@ use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamNa use std::iter; mod item_bounds; +mod object_lifetime_defaults; mod type_of; #[derive(Debug)] @@ -68,6 +69,8 @@ pub fn provide(providers: &mut Providers) { type_of: type_of::type_of, item_bounds: item_bounds::item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds, + object_lifetime_defaults: object_lifetime_defaults::object_lifetime_defaults, + object_lifetime_map: object_lifetime_defaults::object_lifetime_map, generics_of, predicates_of, predicates_defined_on, @@ -1304,6 +1307,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { ) } +#[tracing::instrument(level = "debug", skip(tcx))] fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option { struct LateBoundRegionsDetector<'tcx> { tcx: TyCtxt<'tcx>, @@ -1343,8 +1347,13 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option {} Some( rl::Region::LateBound(debruijn, _, _) @@ -1380,6 +1389,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option, + def_id: DefId, +) -> Option<&[ObjectLifetimeDefault]> { + if let Some(def_id) = def_id.as_local() { + match tcx.hir().get_by_def_id(def_id) { + Node::Item(item) => compute_object_lifetime_defaults(tcx, item), + _ => None, + } + } else { + Some(tcx.arena.alloc_from_iter(tcx.generics_of(def_id).params.iter().filter_map(|param| { + match param.kind { + GenericParamDefKind::Type { object_lifetime_default, .. } => { + Some(object_lifetime_default) + } + GenericParamDefKind::Const { .. } => Some(Set1::Empty), + GenericParamDefKind::Lifetime => None, + } + }))) + } +} + +fn compute_object_lifetime_defaults<'tcx>( + tcx: TyCtxt<'tcx>, + item: &hir::Item<'_>, +) -> Option<&'tcx [ObjectLifetimeDefault]> { + 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, + origin: hir::OpaqueTyOrigin::TyAlias, + .. + }) + | hir::ItemKind::TyAlias(_, ref generics) + | hir::ItemKind::Trait(_, _, ref generics, ..) => { + let result = object_lifetime_defaults_for_item(tcx, generics); + debug!(?result); + + // 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 + } + _ => None, + }) + .unwrap(), + Set1::One(_) => bug!(), + Set1::Many => "Ambiguous".into(), + }) + .collect::>>() + .join(","); + tcx.sess.span_err(item.span, &object_lifetime_default_reprs); + } + + Some(result) + } + _ => None, + } +} + +/// Scan the bounds and where-clauses on parameters to extract bounds +/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` +/// for each type parameter. +fn object_lifetime_defaults_for_item<'tcx>( + tcx: TyCtxt<'tcx>, + generics: &hir::Generics<'_>, +) -> &'tcx [ObjectLifetimeDefault] { + fn add_bounds(set: &mut Set1, bounds: &[hir::GenericBound<'_>]) { + for bound in bounds { + if let hir::GenericBound::Outlives(ref lifetime) = *bound { + set.insert(lifetime.name.normalize_to_macros_2_0()); + } + } + } + + let process_param = |param: &hir::GenericParam<'_>| match param.kind { + GenericParamKind::Lifetime { .. } => None, + GenericParamKind::Type { .. } => { + let mut set = Set1::Empty; + + let param_def_id = tcx.hir().local_def_id(param.hir_id); + for predicate in generics.predicates { + // Look for `type: ...` where clauses. + let hir::WherePredicate::BoundPredicate(ref data) = *predicate else { continue }; + + // Ignore `for<'a> type: ...` as they can change what + // lifetimes mean (although we could "just" handle it). + if !data.bound_generic_params.is_empty() { + continue; + } + + let res = match data.bounded_ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res, + _ => continue, + }; + + if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) { + add_bounds(&mut set, &data.bounds); + } + } + + Some(match set { + Set1::Empty => Set1::Empty, + Set1::One(hir::LifetimeName::Static) => Set1::One(Region::Static), + Set1::One(hir::LifetimeName::Param(def_id, _)) => generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + let param_def_id = tcx.hir().local_def_id(param.hir_id); + Some(param_def_id) + } + _ => None, + }) + .enumerate() + .find(|&(_, param_def_id)| param_def_id == def_id) + .map_or(Set1::Many, |(i, _)| { + Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id())) + }), + Set1::One(_) | Set1::Many => Set1::Many, + }) + } + GenericParamKind::Const { .. } => { + // Generic consts don't impose any constraints. + // + // We still store a dummy value here to allow generic parameters + // in an arbitrary order. + Some(Set1::Empty) + } + }; + + tcx.arena.alloc_from_iter(generics.params.iter().filter_map(process_param)) +} + +pub(super) fn object_lifetime_map( + tcx: TyCtxt<'_>, + def_id: LocalDefId, +) -> FxHashMap { + let mut named_region_map = Default::default(); + let mut visitor = LifetimeContext { tcx, defs: &mut named_region_map, scope: ROOT_SCOPE }; + let node = tcx.hir().get_by_def_id(def_id); + match node { + Node::Item(item) => visitor.visit_item(item), + Node::TraitItem(item) => visitor.visit_trait_item(item), + Node::ImplItem(item) => visitor.visit_impl_item(item), + Node::ForeignItem(item) => visitor.visit_foreign_item(item), + _ => bug!(), + } + + named_region_map +} + +trait RegionExt { + fn shifted(self, amount: u32) -> Region; +} + +impl RegionExt for Region { + fn shifted(self, amount: u32) -> Region { + match self { + Region::LateBound(debruijn, idx, id) => { + Region::LateBound(debruijn.shifted_in(amount), idx, id) + } + _ => self, + } + } +} + +struct LifetimeContext<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + defs: &'a mut FxHashMap, + scope: ScopeRef<'a>, +} + +#[derive(Debug)] +enum Scope<'a> { + /// Declares lifetimes, and each can be early-bound or late-bound. + /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and + /// it should be shifted by the number of `Binder`s in between the + /// declaration `Binder` and the location it's referenced from. + Binder { + scope_type: BinderScopeType, + s: ScopeRef<'a>, + }, + + /// Lifetimes introduced by a fn are scoped to the call-site for that fn, + /// if this is a fn body, otherwise the original definitions are used. + /// Unspecified lifetimes are inferred, unless an elision scope is nested, + /// e.g., `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`. + Body, + + /// A scope which either determines unspecified lifetimes to static. + Static { + s: ScopeRef<'a>, + }, + + /// Use a specific lifetime (if `Some`) or leave it unset (to be + /// inferred in a function body or potentially error outside one), + /// for the default choice of lifetime in a trait object type. + ObjectLifetimeDefault { + lifetime: Option, + s: ScopeRef<'a>, + }, + + Root, +} + +#[derive(Copy, Clone, Debug)] +enum BinderScopeType { + /// Any non-concatenating binder scopes. + Normal, + /// Within a syntactic trait ref, there may be multiple poly trait refs that + /// are nested (under the `associated_type_bounds` feature). The binders of + /// the inner poly trait refs are extended from the outer poly trait refs + /// and don't increase the late bound depth. If you had + /// `T: for<'a> Foo Baz<'a, 'b>>`, then the `for<'b>` scope + /// would be `Concatenating`. This also used in trait refs in where clauses + /// where we have two binders `for<> T: for<> Foo` (I've intentionally left + /// out any lifetimes because they aren't needed to show the two scopes). + /// The inner `for<>` has a scope of `Concatenating`. + Concatenating, +} + +type ScopeRef<'a> = &'a Scope<'a>; + +const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; + +impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { + /// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref. + fn poly_trait_ref_binder_info(&mut self) -> BinderScopeType { + let mut scope = self.scope; + loop { + match scope { + // Nested poly trait refs have the binders concatenated + Scope::Binder { .. } => break BinderScopeType::Concatenating, + Scope::Body | Scope::Root => break BinderScopeType::Normal, + Scope::Static { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => scope = s, + } + } + } +} +impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + + fn visit_nested_body(&mut self, body: hir::BodyId) { + let body = self.tcx.hir().body(body); + self.with(Scope::Body, |this| { + this.visit_body(body); + }); + } + + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Closure(..) = e.kind { + let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + self.with(scope, |this| { + // a closure has no bounds, so everything + // contained within is scoped within its binder. + intravisit::walk_expr(this, e) + }); + } else { + intravisit::walk_expr(self, e) + } + } + + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + match item.kind { + hir::ItemKind::ExternCrate(_) + | hir::ItemKind::Use(..) + | hir::ItemKind::Macro(..) + | hir::ItemKind::Mod(..) + | hir::ItemKind::ForeignMod { .. } + | hir::ItemKind::GlobalAsm(..) => { + // These sorts of items have no lifetime parameters at all. + intravisit::walk_item(self, item); + } + hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { + // No lifetime parameters, but implied 'static. + self.with(Scope::Static { s: self.scope }, |this| { + intravisit::walk_item(this, item) + }); + } + hir::ItemKind::OpaqueTy(..) + | hir::ItemKind::TyAlias(..) + | hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..) + | hir::ItemKind::Trait(..) + | hir::ItemKind::TraitAlias(..) + | hir::ItemKind::Fn(..) + | hir::ItemKind::Impl(..) => { + // These kinds of items have only early-bound lifetime parameters. + let scope = Scope::Binder { scope_type: BinderScopeType::Normal, s: ROOT_SCOPE }; + self.with(scope, |this| intravisit::walk_item(this, item)); + } + } + } + + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { + match item.kind { + hir::ForeignItemKind::Fn(..) => { + let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + self.with(scope, |this| intravisit::walk_foreign_item(this, item)) + } + hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => { + intravisit::walk_foreign_item(self, item) + } + } + } + + #[tracing::instrument(level = "debug", skip(self))] + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + match ty.kind { + hir::TyKind::BareFn(..) => { + let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + self.with(scope, |this| { + // a bare fn has no bounds, so everything + // contained within is scoped within its binder. + intravisit::walk_ty(this, ty); + }); + } + hir::TyKind::TraitObject(bounds, ref lifetime, _) => { + debug!(?bounds, ?lifetime, "TraitObject"); + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + if let LifetimeName::ImplicitObjectLifetimeDefault = lifetime.name { + // If the user does not write *anything*, we + // use the object lifetime defaulting + // rules. So e.g., `Box` becomes + // `Box`. + self.resolve_object_lifetime_default(lifetime) + } + } + hir::TyKind::Rptr(ref lifetime_ref, ref mt) => { + let lifetime = self.tcx.named_region(lifetime_ref.hir_id); + let scope = Scope::ObjectLifetimeDefault { lifetime, s: self.scope }; + self.with(scope, |this| this.visit_ty(&mt.ty)); + } + _ => intravisit::walk_ty(self, ty), + } + } + + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + use self::hir::TraitItemKind::*; + match trait_item.kind { + Fn(..) | Type(..) => { + let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + self.with(scope, |this| intravisit::walk_trait_item(this, trait_item)); + } + // Only methods and types support generics. + Const(_, _) => intravisit::walk_trait_item(self, trait_item), + } + } + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + use self::hir::ImplItemKind::*; + match impl_item.kind { + Fn(..) | TyAlias(..) => { + let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + self.with(scope, |this| intravisit::walk_impl_item(this, impl_item)); + } + // Only methods and types support generics. + Const(..) => intravisit::walk_impl_item(self, impl_item), + } + } + + fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { + for (i, segment) in path.segments.iter().enumerate() { + let depth = path.segments.len() - i - 1; + if let Some(ref args) = segment.args { + self.visit_segment_args(path.res, depth, args); + } + } + } + + fn visit_where_predicate(&mut self, predicate: &'tcx hir::WherePredicate<'tcx>) { + match predicate { + &hir::WherePredicate::BoundPredicate(..) => { + // Even if there are no lifetimes defined here, we still wrap it in a binder + // scope. If there happens to be a nested poly trait ref (an error), that + // will be `Concatenating` anyways, so we don't have to worry about the depth + // being wrong. + let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + self.with(scope, |this| intravisit::walk_where_predicate(this, predicate)) + } + &hir::WherePredicate::RegionPredicate(..) | &hir::WherePredicate::EqPredicate(..) => { + intravisit::walk_where_predicate(self, predicate) + } + } + } + + fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { + match bound { + hir::GenericBound::LangItemTrait(..) => { + // FIXME(jackh726): This is pretty weird. `LangItemTrait` doesn't go + // through the regular poly trait ref code, so we don't get another + // chance to introduce a binder. For now, I'm keeping the existing logic + // of "if there isn't a Binder scope above us, add one", but I + // imagine there's a better way to go about this. + let scope_type = self.poly_trait_ref_binder_info(); + + let scope = Scope::Binder { s: self.scope, scope_type }; + self.with(scope, |this| intravisit::walk_param_bound(this, bound)); + } + _ => intravisit::walk_param_bound(self, bound), + } + } + + fn visit_poly_trait_ref( + &mut self, + trait_ref: &'tcx hir::PolyTraitRef<'tcx>, + modifier: hir::TraitBoundModifier, + ) { + debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); + + let scope_type = self.poly_trait_ref_binder_info(); + + // Always introduce a scope here, even if this is in a where clause and + // we introduced the binders around the bounded Ty. In that case, we + // just reuse the concatenation functionality also present in nested trait + // refs. + let scope = Scope::Binder { s: self.scope, scope_type }; + self.with(scope, |this| intravisit::walk_poly_trait_ref(this, trait_ref, modifier)); + } +} + +impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { + fn with(&mut self, wrap_scope: Scope<'_>, f: F) + where + F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), + { + let LifetimeContext { tcx, defs, .. } = self; + let mut this = LifetimeContext { tcx: *tcx, defs, scope: &wrap_scope }; + f(&mut this); + } + + #[tracing::instrument(level = "debug", skip(self))] + fn visit_segment_args( + &mut self, + res: Res, + depth: usize, + generic_args: &'tcx hir::GenericArgs<'tcx>, + ) { + if generic_args.parenthesized { + for input in generic_args.inputs() { + self.visit_ty(input); + } + let output = generic_args.bindings[0].ty(); + self.visit_ty(output); + return; + } + + // Figure out if this is a type/trait segment, + // which requires object lifetime defaults. + let parent_def_id = |this: &mut Self, def_id: DefId| { + let def_key = this.tcx.def_key(def_id); + DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") } + }; + let type_def_id = match res { + Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)), + Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)), + Res::Def( + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::TyAlias + | DefKind::Trait, + def_id, + ) if depth == 0 => Some(def_id), + _ => None, + }; + debug!(?type_def_id); + + // Compute a vector of defaults, one for each type parameter, + // per the rules given in RFCs 599 and 1156. Example: + // + // ```rust + // struct Foo<'a, T: 'a, U> { } + // ``` + // + // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default + // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) + // and `dyn Baz` to `dyn Baz + 'static` (because there is no + // such bound). + // + // Therefore, we would compute `object_lifetime_defaults` to a + // vector like `['x, 'static]`. Note that the vector only + // includes type parameters. + let object_lifetime_defaults = type_def_id.map_or_else(Vec::new, |def_id| { + let in_body = { + let mut scope = self.scope; + loop { + match *scope { + Scope::Root => break false, + + Scope::Body => break true, + + Scope::Binder { s, .. } + | Scope::Static { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + } + } + }; + + let set_to_region = |set: &ObjectLifetimeDefault| match *set { + Set1::Empty => { + if in_body { + None + } else { + Some(Region::Static) + } + } + Set1::One(Region::EarlyBound(index, _)) => { + let mut lifetimes = generic_args.args.iter().filter_map(|arg| match arg { + GenericArg::Lifetime(lt) => Some(lt), + _ => None, + }); + lifetimes + .nth(index as usize) + .and_then(|lifetime| self.tcx.named_region(lifetime.hir_id)) + } + Set1::One(r) => Some(r), + Set1::Many => None, + }; + self.tcx.object_lifetime_defaults(def_id).unwrap().iter().map(set_to_region).collect() + }); + debug!(?object_lifetime_defaults); + + let mut i = 0; + for arg in generic_args.args { + match arg { + GenericArg::Lifetime(_) => {} + GenericArg::Type(ty) => { + if let Some(<) = object_lifetime_defaults.get(i) { + let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; + self.with(scope, |this| this.visit_ty(ty)); + } else { + self.visit_ty(ty); + } + i += 1; + } + GenericArg::Const(ct) => { + self.visit_anon_const(&ct.value); + i += 1; + } + GenericArg::Infer(inf) => { + self.visit_id(inf.hir_id); + i += 1; + } + } + } + + // Hack: when resolving the type `XX` in binding like `dyn + // Foo<'b, Item = XX>`, the current object-lifetime default + // would be to examine the trait `Foo` to check whether it has + // a lifetime bound declared on `Item`. e.g., if `Foo` is + // declared like so, then the default object lifetime bound in + // `XX` should be `'b`: + // + // ```rust + // trait Foo<'a> { + // type Item: 'a; + // } + // ``` + // + // but if we just have `type Item;`, then it would be + // `'static`. However, we don't get all of this logic correct. + // + // Instead, we do something hacky: if there are no lifetime parameters + // to the trait, then we simply use a default object lifetime + // bound of `'static`, because there is no other possibility. On the other hand, + // if there ARE lifetime parameters, then we require the user to give an + // explicit bound for now. + // + // This is intended to leave room for us to implement the + // correct behavior in the future. + let has_lifetime_parameter = + generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); + + // Resolve lifetimes found in the bindings, so either in the type `XX` in `Item = XX` or + // in the trait ref `YY<...>` in `Item: YY<...>`. + for binding in generic_args.bindings { + let scope = Scope::ObjectLifetimeDefault { + lifetime: if has_lifetime_parameter { None } else { Some(Region::Static) }, + s: self.scope, + }; + self.with(scope, |this| this.visit_assoc_type_binding(binding)); + } + } + + fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); + let mut late_depth = 0; + let mut scope = self.scope; + let lifetime = loop { + match *scope { + Scope::Binder { s, scope_type, .. } => { + match scope_type { + BinderScopeType::Normal => late_depth += 1, + BinderScopeType::Concatenating => {} + } + scope = s; + } + + Scope::Root | Scope::Static { .. } => break Region::Static, + + Scope::Body | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, + + Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, + } + }; + let def = lifetime.shifted(late_depth); + debug!(?def); + self.defs.insert(lifetime_ref.hir_id.local_id, def); + } +} diff --git a/src/test/ui/issues/issue-41139.rs b/src/test/ui/issues/issue-41139.rs index 94c53216f50ac..ff67aef3b8d85 100644 --- a/src/test/ui/issues/issue-41139.rs +++ b/src/test/ui/issues/issue-41139.rs @@ -8,5 +8,5 @@ fn main() { // This isn't great. The issue here is that `dyn Trait` is not sized, so // `dyn Fn() -> dyn Trait` is not well-formed. let t: &dyn Trait = &get_function()(); - //~^ ERROR expected function, found `&dyn Fn() -> (dyn Trait + 'static)` + //~^ ERROR expected function, found `&dyn Fn() -> dyn Trait` } diff --git a/src/test/ui/issues/issue-41139.stderr b/src/test/ui/issues/issue-41139.stderr index 48b22bca20f06..6d4aefc6d02c2 100644 --- a/src/test/ui/issues/issue-41139.stderr +++ b/src/test/ui/issues/issue-41139.stderr @@ -1,8 +1,8 @@ -error[E0618]: expected function, found `&dyn Fn() -> (dyn Trait + 'static)` +error[E0618]: expected function, found `&dyn Fn() -> dyn Trait` --> $DIR/issue-41139.rs:10:26 | LL | fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait { - | -------------------------------------------------- `get_function` defined here returns `&dyn Fn() -> (dyn Trait + 'static)` + | -------------------------------------------------- `get_function` defined here returns `&dyn Fn() -> dyn Trait` ... LL | let t: &dyn Trait = &get_function()(); | ^^^^^^^^^^^^^^-- From ca362888990507d616516e752aa86b1742866771 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 24 May 2022 12:51:59 +0200 Subject: [PATCH 03/13] Create a specific `ObjectLifetimeDefault` enum. --- .../src/middle/resolve_lifetime.rs | 8 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_typeck/src/astconv/mod.rs | 2 - compiler/rustc_typeck/src/collect.rs | 9 +- .../src/collect/object_lifetime_defaults.rs | 118 +++++++----------- 5 files changed, 56 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index cdc0d07680193..83193dc1c4902 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -50,7 +50,13 @@ impl Set1 { } } -pub type ObjectLifetimeDefault = Set1; +#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)] +pub enum ObjectLifetimeDefault { + Empty, + Static, + Ambiguous, + Param(DefId), +} /// Maps the id of each lifetime reference to the lifetime decl /// that it corresponds to. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5c5d99f76ed29..217fae1536781 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1591,7 +1591,7 @@ rustc_queries! { /// for each parameter 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(_: DefId) -> Option<&'tcx [ObjectLifetimeDefault]> { + query object_lifetime_defaults(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> { desc { "looking up lifetime defaults for a region on an item" } } /// Fetch the lifetimes for all the trait objects in an item-like. diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 15501cd765cb1..e5dc4adb64f2c 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -266,9 +266,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // (*) -- not late-bound, won't change } }; - debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r); - r } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index cb0d1715255a8..f99a098bcbf6c 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -34,6 +34,7 @@ use rustc_hir::weak_lang_items; use rustc_hir::{GenericParamKind, HirId, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::InternalSubsts; @@ -1636,7 +1637,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, - object_lifetime_default: rl::Set1::Empty, + object_lifetime_default: ObjectLifetimeDefault::Empty, synthetic: false, }, }); @@ -1714,7 +1715,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { has_default: default.is_some(), object_lifetime_default: object_lifetime_defaults .as_ref() - .map_or(rl::Set1::Empty, |o| o[i]), + .map_or(ObjectLifetimeDefault::Empty, |o| o[i]), synthetic, }; @@ -1766,7 +1767,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, - object_lifetime_default: rl::Set1::Empty, + object_lifetime_default: ObjectLifetimeDefault::Empty, synthetic: false, }, })); @@ -1783,7 +1784,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, - object_lifetime_default: rl::Set1::Empty, + object_lifetime_default: ObjectLifetimeDefault::Empty, synthetic: false, }, }); diff --git a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs index 757f2100e677c..97f4fbab38d5b 100644 --- a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs +++ b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs @@ -17,30 +17,9 @@ use tracing::debug; pub(super) fn object_lifetime_defaults( tcx: TyCtxt<'_>, - def_id: DefId, + def_id: LocalDefId, ) -> Option<&[ObjectLifetimeDefault]> { - if let Some(def_id) = def_id.as_local() { - match tcx.hir().get_by_def_id(def_id) { - Node::Item(item) => compute_object_lifetime_defaults(tcx, item), - _ => None, - } - } else { - Some(tcx.arena.alloc_from_iter(tcx.generics_of(def_id).params.iter().filter_map(|param| { - match param.kind { - GenericParamDefKind::Type { object_lifetime_default, .. } => { - Some(object_lifetime_default) - } - GenericParamDefKind::Const { .. } => Some(Set1::Empty), - GenericParamDefKind::Lifetime => None, - } - }))) - } -} - -fn compute_object_lifetime_defaults<'tcx>( - tcx: TyCtxt<'tcx>, - item: &hir::Item<'_>, -) -> Option<&'tcx [ObjectLifetimeDefault]> { + let Node::Item(item) = tcx.hir().get_by_def_id(def_id) else { return None }; match item.kind { hir::ItemKind::Struct(_, ref generics) | hir::ItemKind::Union(_, ref generics) @@ -61,24 +40,18 @@ fn compute_object_lifetime_defaults<'tcx>( 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 - } - _ => None, - }) - .unwrap(), - Set1::One(_) => bug!(), - Set1::Many => "Ambiguous".into(), + ObjectLifetimeDefault::Empty => "BaseDefault".into(), + ObjectLifetimeDefault::Static => "'static".into(), + ObjectLifetimeDefault::Param(def_id) => { + let def_id = def_id.expect_local(); + generics + .params + .iter() + .find(|param| tcx.hir().local_def_id(param.hir_id) == def_id) + .map(|param| param.name.ident().to_string().into()) + .unwrap() + } + ObjectLifetimeDefault::Ambiguous => "Ambiguous".into(), }) .collect::>>() .join(","); @@ -133,24 +106,12 @@ fn object_lifetime_defaults_for_item<'tcx>( } Some(match set { - Set1::Empty => Set1::Empty, - Set1::One(hir::LifetimeName::Static) => Set1::One(Region::Static), - Set1::One(hir::LifetimeName::Param(def_id, _)) => generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - let param_def_id = tcx.hir().local_def_id(param.hir_id); - Some(param_def_id) - } - _ => None, - }) - .enumerate() - .find(|&(_, param_def_id)| param_def_id == def_id) - .map_or(Set1::Many, |(i, _)| { - Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id())) - }), - Set1::One(_) | Set1::Many => Set1::Many, + Set1::Empty => ObjectLifetimeDefault::Empty, + Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, + Set1::One(hir::LifetimeName::Param(def_id, _)) => { + ObjectLifetimeDefault::Param(def_id.to_def_id()) + } + Set1::One(_) | Set1::Many => ObjectLifetimeDefault::Ambiguous, }) } GenericParamKind::Const { .. } => { @@ -158,7 +119,7 @@ fn object_lifetime_defaults_for_item<'tcx>( // // We still store a dummy value here to allow generic parameters // in an arbitrary order. - Some(Set1::Empty) + Some(ObjectLifetimeDefault::Empty) } }; @@ -528,9 +489,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { loop { match *scope { Scope::Root => break false, - Scope::Body => break true, - Scope::Binder { s, .. } | Scope::Static { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { @@ -539,28 +498,37 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } }; - - let set_to_region = |set: &ObjectLifetimeDefault| match *set { - Set1::Empty => { + let generics = self.tcx.generics_of(def_id); + let set_to_region = |set: ObjectLifetimeDefault| match set { + ObjectLifetimeDefault::Empty => { if in_body { None } else { Some(Region::Static) } } - Set1::One(Region::EarlyBound(index, _)) => { - let mut lifetimes = generic_args.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(lt) => Some(lt), + ObjectLifetimeDefault::Static => Some(Region::Static), + ObjectLifetimeDefault::Param(def_id) => { + let index = generics.param_def_id_to_index[&def_id]; + generic_args.args.get(index as usize).and_then(|arg| match arg { + GenericArg::Lifetime(lt) => self.tcx.named_region(lt.hir_id), _ => None, - }); - lifetimes - .nth(index as usize) - .and_then(|lifetime| self.tcx.named_region(lifetime.hir_id)) + }) } - Set1::One(r) => Some(r), - Set1::Many => None, + ObjectLifetimeDefault::Ambiguous => None, }; - self.tcx.object_lifetime_defaults(def_id).unwrap().iter().map(set_to_region).collect() + generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamDefKind::Type { object_lifetime_default, .. } => { + Some(object_lifetime_default) + } + GenericParamDefKind::Const { .. } => Some(ObjectLifetimeDefault::Empty), + GenericParamDefKind::Lifetime => None, + }) + .map(set_to_region) + .collect() }); debug!(?object_lifetime_defaults); From a959cf69eaa48b0314ea72c9a6e65df9be3aa868 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 24 May 2022 08:31:11 +0200 Subject: [PATCH 04/13] Create lifetime parameter like any other parameter. --- compiler/rustc_middle/src/hir/map/mod.rs | 8 ++++++-- compiler/rustc_typeck/src/astconv/mod.rs | 9 ++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index aab84b718d406..32f4817e5cd09 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -546,7 +546,9 @@ impl<'hir> Map<'hir> { let def_kind = self.tcx.def_kind(def_id); match def_kind { DefKind::Trait | DefKind::TraitAlias => def_id, - DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id), + DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam => { + self.tcx.local_parent(def_id) + } _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind), } } @@ -555,7 +557,9 @@ impl<'hir> Map<'hir> { let def_kind = self.tcx.def_kind(def_id); match def_kind { DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper, - DefKind::TyParam | DefKind::ConstParam => self.tcx.item_name(def_id.to_def_id()), + DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam => { + self.tcx.item_name(def_id.to_def_id()) + } _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind), } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index e5dc4adb64f2c..8441c7f5db235 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -251,9 +251,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.mk_region(ty::ReLateBound(debruijn, br)) } - rl::Region::EarlyBound(index, id) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name })) + rl::Region::EarlyBound(_, def_id) => { + let name = tcx.hir().ty_param_name(def_id.expect_local()); + let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name })) } rl::Region::Free(scope, id) => { From bc70bb9291e60bd8feeb8086b45d693734d516b6 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 24 May 2022 13:00:36 +0200 Subject: [PATCH 05/13] Remove index from Region::EarlyBound. --- .../nice_region_error/find_anon_type.rs | 8 +- compiler/rustc_lint/src/builtin.rs | 19 +- .../src/middle/resolve_lifetime.rs | 2 +- compiler/rustc_resolve/src/late/lifetimes.rs | 174 +++--------------- compiler/rustc_typeck/src/astconv/mod.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- 6 files changed, 45 insertions(+), 162 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index e5ae835e81349..b3efc307be902 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -120,7 +120,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // Find the index of the named region that was part of the // error. We will then search the function parameters for a bound // region at the right depth with the same index - (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => { + (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { self.found_type = Some(arg); @@ -150,7 +150,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { Some( rl::Region::Static | rl::Region::Free(_, _) - | rl::Region::EarlyBound(_, _) + | rl::Region::EarlyBound(_) | rl::Region::LateBound(_, _, _) | rl::Region::LateBoundAnon(_, _, _), ) @@ -216,7 +216,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { } } - (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => { + (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { self.found_it = true; @@ -237,7 +237,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { ( Some( rl::Region::Static - | rl::Region::EarlyBound(_, _) + | rl::Region::EarlyBound(_) | rl::Region::LateBound(_, _, _) | rl::Region::LateBoundAnon(_, _, _) | rl::Region::Free(_, _), diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6be78c52f99e3..3e751b3b9a480 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2050,13 +2050,13 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN impl ExplicitOutlivesRequirements { fn lifetimes_outliving_lifetime<'tcx>( inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)], - index: u32, + def_id: DefId, ) -> Vec> { inferred_outlives .iter() .filter_map(|(pred, _)| match pred.kind().skip_binder() { ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { - ty::ReEarlyBound(ebr) if ebr.index == index => Some(b), + ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b), _ => None, }, _ => None, @@ -2097,8 +2097,12 @@ impl ExplicitOutlivesRequirements { Some(Region::Static) if infer_static => { inferred_outlives.iter().any(|r| matches!(**r, ty::ReStatic)) } - Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| { - if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false } + Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| { + if let ty::ReEarlyBound(ebr) = **r { + ebr.def_id == def_id + } else { + false + } }), _ => false, }; @@ -2193,11 +2197,14 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { for (i, where_predicate) in hir_generics.predicates.iter().enumerate() { let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate { hir::WherePredicate::RegionPredicate(predicate) => { - if let Some(Region::EarlyBound(index, ..)) = + if let Some(Region::EarlyBound(region_def_id)) = cx.tcx.named_region(predicate.lifetime.hir_id) { ( - Self::lifetimes_outliving_lifetime(inferred_outlives, index), + Self::lifetimes_outliving_lifetime( + inferred_outlives, + region_def_id, + ), &predicate.bounds, predicate.span, predicate.in_where_clause, diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 83193dc1c4902..5bbaa043d203a 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -10,7 +10,7 @@ use rustc_macros::HashStable; #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum Region { Static, - EarlyBound(/* index */ u32, /* lifetime decl */ DefId), + EarlyBound(/* lifetime decl */ DefId), LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId), LateBoundAnon(ty::DebruijnIndex, /* late-bound index */ u32, /* anon index */ u32), Free(DefId, /* lifetime decl */ DefId), diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 728a6e4ba01c9..f3135bc2feee6 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -32,7 +32,7 @@ use std::mem::take; use tracing::{debug, span, Level}; trait RegionExt { - fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region); + fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region); fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region); @@ -46,12 +46,10 @@ trait RegionExt { } impl RegionExt for Region { - fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) { - let i = *index; - *index += 1; + fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) { let def_id = hir_map.local_def_id(param.hir_id); - debug!("Region::early: index={} def_id={:?}", i, def_id); - (def_id, Region::EarlyBound(i, def_id.to_def_id())) + debug!("Region::early: def_id={:?}", def_id); + (def_id, Region::EarlyBound(def_id.to_def_id())) } fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) { @@ -75,9 +73,7 @@ impl RegionExt for Region { match *self { Region::Static | Region::LateBoundAnon(..) => None, - Region::EarlyBound(_, id) | Region::LateBound(_, _, id) | Region::Free(_, id) => { - Some(id) - } + Region::EarlyBound(id) | Region::LateBound(_, _, id) | Region::Free(_, id) => Some(id), } } @@ -156,10 +152,6 @@ enum Scope<'a> { /// for diagnostics. lifetimes: FxIndexMap, - /// if we extend this scope with another scope, what is the next index - /// we should use for an early-bound region? - next_early_index: u32, - /// Whether or not this binder would serve as the parent /// binder for opaque types introduced within. For example: /// @@ -246,7 +238,6 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { match self.0 { Scope::Binder { lifetimes, - next_early_index, opaque_type_parent, scope_type, hir_id, @@ -255,7 +246,6 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { } => f .debug_struct("Binder") .field("lifetimes", lifetimes) - .field("next_early_index", next_early_index) .field("opaque_type_parent", opaque_type_parent) .field("scope_type", scope_type) .field("hir_id", hir_id) @@ -458,13 +448,6 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId { item } -/// 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. -fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { - matches!(*node, hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..)) -} - fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind { match region { Region::LateBound(_, _, def_id) => { @@ -593,7 +576,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let scope = Scope::Binder { hir_id, lifetimes: FxIndexMap::default(), - next_early_index: self.next_early_index(), s: self.scope, opaque_type_parent: false, scope_type: BinderScopeType::Normal, @@ -616,8 +598,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match item.kind { hir::ItemKind::Fn(_, ref generics, _) => { self.missing_named_lifetime_spots.push(generics.into()); - self.visit_early_late(None, item.hir_id(), generics, |this| { - intravisit::walk_item(this, item); + self.visit_early_late(item.hir_id(), generics, |this| { + intravisit::walk_item(this, item) }); self.missing_named_lifetime_spots.pop(); } @@ -685,30 +667,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.missing_named_lifetime_spots.push(generics.into()); // These kinds of items have only early-bound lifetime parameters. - let mut index = if sub_items_have_self_param(&item.kind) { - 1 // Self comes before lifetimes - } else { - 0 - }; - let mut non_lifetime_count = 0; let lifetimes = generics .params .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { - Some(Region::early(self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None + Some(Region::early(self.tcx.hir(), param)) } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, }) .collect(); self.map.late_bound_vars.insert(item.hir_id(), vec![]); let scope = Scope::Binder { hir_id: item.hir_id(), lifetimes, - next_early_index: index + non_lifetime_count, opaque_type_parent: true, scope_type: BinderScopeType::Normal, s: ROOT_SCOPE, @@ -728,8 +700,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { hir::ForeignItemKind::Fn(_, _, ref generics) => { - self.visit_early_late(None, item.hir_id(), generics, |this| { - intravisit::walk_foreign_item(this, item); + self.visit_early_late(item.hir_id(), generics, |this| { + intravisit::walk_foreign_item(this, item) }) } hir::ForeignItemKind::Static(..) => { @@ -745,7 +717,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { match ty.kind { hir::TyKind::BareFn(ref c) => { - let next_early_index = self.next_early_index(); let lifetime_span: Option = c.generic_params.iter().rev().find_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => Some(param.span), @@ -774,7 +745,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: ty.hir_id, lifetimes, s: self.scope, - next_early_index, opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: true, @@ -919,16 +889,12 @@ 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!(?index); - let mut elision = None; let mut lifetimes = FxIndexMap::default(); - let mut non_lifetime_count = 0; for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => { - let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, ¶m); + let (def_id, reg) = Region::early(self.tcx.hir(), ¶m); if let hir::ParamName::Plain(Ident { name: kw::UnderscoreLifetime, .. @@ -941,12 +907,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { lifetimes.insert(def_id, reg); } } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {} } } - let next_early_index = index + non_lifetime_count; self.map.late_bound_vars.insert(ty.hir_id, vec![]); if let Some(elision_region) = elision { @@ -956,7 +919,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let scope = Scope::Binder { hir_id: ty.hir_id, lifetimes, - next_early_index, s: this.scope, opaque_type_parent: false, scope_type: BinderScopeType::Normal, @@ -976,7 +938,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let scope = Scope::Binder { hir_id: ty.hir_id, lifetimes, - next_early_index, s: self.scope, opaque_type_parent: false, scope_type: BinderScopeType::Normal, @@ -1002,39 +963,28 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match trait_item.kind { Fn(_, _) => { self.missing_named_lifetime_spots.push((&trait_item.generics).into()); - let tcx = self.tcx; - self.visit_early_late( - Some(tcx.hir().get_parent_item(trait_item.hir_id())), - trait_item.hir_id(), - &trait_item.generics, - |this| intravisit::walk_trait_item(this, trait_item), - ); + self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| { + intravisit::walk_trait_item(this, trait_item) + }); self.missing_named_lifetime_spots.pop(); } Type(bounds, ref ty) => { self.missing_named_lifetime_spots.push((&trait_item.generics).into()); let generics = &trait_item.generics; - let mut index = self.next_early_index(); - debug!("visit_ty: index = {}", index); - let mut non_lifetime_count = 0; let lifetimes = generics .params .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { - Some(Region::early(self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None + Some(Region::early(self.tcx.hir(), param)) } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, }) .collect(); self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]); let scope = Scope::Binder { hir_id: trait_item.hir_id(), lifetimes, - next_early_index: index + non_lifetime_count, s: self.scope, opaque_type_parent: true, scope_type: BinderScopeType::Normal, @@ -1069,39 +1019,28 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match impl_item.kind { Fn(..) => { self.missing_named_lifetime_spots.push((&impl_item.generics).into()); - let tcx = self.tcx; - self.visit_early_late( - Some(tcx.hir().get_parent_item(impl_item.hir_id())), - impl_item.hir_id(), - &impl_item.generics, - |this| intravisit::walk_impl_item(this, impl_item), - ); + self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| { + intravisit::walk_impl_item(this, impl_item) + }); self.missing_named_lifetime_spots.pop(); } TyAlias(ref ty) => { let generics = &impl_item.generics; self.missing_named_lifetime_spots.push(generics.into()); - let mut index = self.next_early_index(); - let mut non_lifetime_count = 0; - debug!("visit_ty: index = {}", index); let lifetimes: FxIndexMap = generics .params .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { - Some(Region::early(self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => { - non_lifetime_count += 1; - None + Some(Region::early(self.tcx.hir(), param)) } + GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None, }) .collect(); self.map.late_bound_vars.insert(ty.hir_id, vec![]); let scope = Scope::Binder { hir_id: ty.hir_id, lifetimes, - next_early_index: index + non_lifetime_count, s: self.scope, opaque_type_parent: true, scope_type: BinderScopeType::Normal, @@ -1238,7 +1177,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }) .unzip(); this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone()); - let next_early_index = this.next_early_index(); // Even if there are no lifetimes defined here, we still wrap it in a binder // scope. If there happens to be a nested poly trait ref (an error), that // will be `Concatenating` anyways, so we don't have to worry about the depth @@ -1247,7 +1185,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: bounded_ty.hir_id, lifetimes, s: this.scope, - next_early_index, opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: true, @@ -1319,7 +1256,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: *hir_id, lifetimes: FxIndexMap::default(), s: self.scope, - next_early_index: self.next_early_index(), opaque_type_parent: false, scope_type, allow_late_bound: true, @@ -1341,7 +1277,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); - let next_early_index = self.next_early_index(); let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); let initial_bound_vars = binders.len() as u32; @@ -1371,7 +1306,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: trait_ref.trait_ref.hir_ref_id, lifetimes, s: self.scope, - next_early_index, opaque_type_parent: false, scope_type, allow_late_bound: true, @@ -1429,30 +1363,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// ordering is not important there. fn visit_early_late( &mut self, - parent_id: Option, hir_id: hir::HirId, generics: &'tcx hir::Generics<'tcx>, walk: F, ) where F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), { - // Find the start of nested early scopes, e.g., in methods. - let mut next_early_index = 0; - if let Some(parent_id) = parent_id { - let parent = self.tcx.hir().expect_item(parent_id); - if sub_items_have_self_param(&parent.kind) { - next_early_index += 1; // Self comes before lifetimes - } - match parent.kind { - hir::ItemKind::Trait(_, _, ref generics, ..) - | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { - next_early_index += generics.params.len() as u32; - } - _ => {} - } - } - - let mut non_lifetime_count = 0; let mut named_late_bound_vars = 0; let lifetimes: FxIndexMap = generics .params @@ -1464,16 +1380,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { named_late_bound_vars += 1; Some(Region::late(late_bound_idx, self.tcx.hir(), param)) } else { - Some(Region::early(self.tcx.hir(), &mut next_early_index, param)) + Some(Region::early(self.tcx.hir(), param)) } } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None - } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, }) .collect(); - let next_early_index = next_early_index + non_lifetime_count; let binders: Vec<_> = generics .params @@ -1492,7 +1404,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let scope = Scope::Binder { hir_id, lifetimes, - next_early_index, s: self.scope, opaque_type_parent: true, scope_type: BinderScopeType::Normal, @@ -1501,41 +1412,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.with(scope, walk); } - fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 { - let mut scope = self.scope; - loop { - match *scope { - Scope::Root => return 0, - - Scope::Binder { next_early_index, opaque_type_parent, .. } - if (!only_opaque_type_parent || opaque_type_parent) => - { - return next_early_index; - } - - Scope::Binder { s, .. } - | Scope::Body { s, .. } - | Scope::Elision { s, .. } - | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => scope = s, - } - } - } - - /// Returns the next index one would use for an early-bound-region - /// if extending the current scope. - fn next_early_index(&self) -> u32 { - self.next_early_index_helper(true) - } - - /// Returns the next index one would use for an `impl Trait` that - /// is being converted into an opaque type alias `impl Trait`. This will be the - /// next early index from the enclosing item, for the most - /// part. See the `opaque_type_parent` field for more info. - fn next_early_index_for_opaque_type(&self) -> u32 { - self.next_early_index_helper(false) - } - #[tracing::instrument(level = "debug", skip(self))] fn resolve_lifetime_ref( &mut self, diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 8441c7f5db235..5b0b4d9ae18af 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -251,7 +251,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.mk_region(ty::ReLateBound(debruijn, br)) } - rl::Region::EarlyBound(_, def_id) => { + rl::Region::EarlyBound(def_id) => { let name = tcx.hir().ty_param_name(def_id.expect_local()); let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); let generics = tcx.generics_of(item_def_id); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f3070fb35f1d0..2ace486ad652d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -192,7 +192,7 @@ impl<'tcx> Clean<'tcx, Lifetime> for hir::Lifetime { fn clean(&self, cx: &mut DocContext<'tcx>) -> Lifetime { let def = cx.tcx.named_region(self.hir_id); if let Some( - rl::Region::EarlyBound(_, node_id) + rl::Region::EarlyBound(node_id) | rl::Region::LateBound(_, _, node_id) | rl::Region::Free(_, node_id), ) = def From be9a2a03192a9b7a8ae5d724fab2cf7bc0cd637f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 24 May 2022 13:37:23 +0200 Subject: [PATCH 06/13] Remove opaque_type_parent. --- compiler/rustc_resolve/src/late/lifetimes.rs | 36 +------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index f3135bc2feee6..df83d06cebf48 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -152,21 +152,6 @@ enum Scope<'a> { /// for diagnostics. lifetimes: FxIndexMap, - /// Whether or not this binder would serve as the parent - /// binder for opaque types introduced within. For example: - /// - /// ```text - /// fn foo<'a>() -> impl for<'b> Trait> - /// ``` - /// - /// Here, the opaque types we create for the `impl Trait` - /// and `impl Trait2` references will both have the `foo` item - /// as their parent. When we get to `impl Trait2`, we find - /// that it is nested within the `for<>` binder -- this flag - /// allows us to skip that when looking for the parent binder - /// of the resulting opaque type. - opaque_type_parent: bool, - scope_type: BinderScopeType, /// The late bound vars for a given item are stored by `HirId` to be @@ -236,17 +221,9 @@ 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, - opaque_type_parent, - scope_type, - hir_id, - s: _, - allow_late_bound, - } => f + Scope::Binder { lifetimes, scope_type, hir_id, s: _, allow_late_bound } => f .debug_struct("Binder") .field("lifetimes", lifetimes) - .field("opaque_type_parent", opaque_type_parent) .field("scope_type", scope_type) .field("hir_id", hir_id) .field("s", &"..") @@ -577,7 +554,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id, lifetimes: FxIndexMap::default(), s: self.scope, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: true, }; @@ -681,7 +657,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let scope = Scope::Binder { hir_id: item.hir_id(), lifetimes, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, s: ROOT_SCOPE, allow_late_bound: false, @@ -745,7 +720,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: ty.hir_id, lifetimes, s: self.scope, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: true, }; @@ -920,7 +894,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: ty.hir_id, lifetimes, s: this.scope, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: false, }; @@ -939,7 +912,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: ty.hir_id, lifetimes, s: self.scope, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: false, }; @@ -986,7 +958,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: trait_item.hir_id(), lifetimes, s: self.scope, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, allow_late_bound: false, }; @@ -1042,7 +1013,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: ty.hir_id, lifetimes, s: self.scope, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, allow_late_bound: true, }; @@ -1185,7 +1155,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: bounded_ty.hir_id, lifetimes, s: this.scope, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: true, }; @@ -1256,7 +1225,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: *hir_id, lifetimes: FxIndexMap::default(), s: self.scope, - opaque_type_parent: false, scope_type, allow_late_bound: true, }; @@ -1306,7 +1274,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: trait_ref.trait_ref.hir_ref_id, lifetimes, s: self.scope, - opaque_type_parent: false, scope_type, allow_late_bound: true, }; @@ -1405,7 +1372,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { hir_id, lifetimes, s: self.scope, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, allow_late_bound: true, }; From 7ada5e58a1c27d61a231ac5f6e381cb8cf7e3f71 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 25 May 2022 11:01:00 +0200 Subject: [PATCH 07/13] Avoid recomputing defaults for all arguments. --- .../src/collect/object_lifetime_defaults.rs | 105 ++++++++---------- 1 file changed, 47 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs index 97f4fbab38d5b..075c88ecf247d 100644 --- a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs +++ b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs @@ -8,8 +8,7 @@ use rustc_hir::{GenericArg, GenericParamKind, LifetimeName, Node}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::*; -use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; -use rustc_span::def_id::DefId; +use rustc_middle::ty::{DefIdTree, GenericParamDefKind, TyCtxt}; use rustc_span::symbol::sym; use std::borrow::Cow; @@ -447,15 +446,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { return; } + let tcx = self.tcx; + // Figure out if this is a type/trait segment, // which requires object lifetime defaults. - let parent_def_id = |this: &mut Self, def_id: DefId| { - let def_key = this.tcx.def_key(def_id); - DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") } - }; let type_def_id = match res { - Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)), - Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)), + Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(tcx.parent(def_id)), + Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(tcx.parent(def_id)), Res::Def( DefKind::Struct | DefKind::Union @@ -468,22 +465,24 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }; debug!(?type_def_id); - // Compute a vector of defaults, one for each type parameter, - // per the rules given in RFCs 599 and 1156. Example: - // - // ```rust - // struct Foo<'a, T: 'a, U> { } - // ``` - // - // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default - // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) - // and `dyn Baz` to `dyn Baz + 'static` (because there is no - // such bound). - // - // Therefore, we would compute `object_lifetime_defaults` to a - // vector like `['x, 'static]`. Note that the vector only - // includes type parameters. - let object_lifetime_defaults = type_def_id.map_or_else(Vec::new, |def_id| { + if let Some(type_def_id) = type_def_id { + // Compute a vector of defaults, one for each type parameter, + // per the rules given in RFCs 599 and 1156. Example: + // + // ```rust + // struct Foo<'a, T: 'a, U> { } + // ``` + // + // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default + // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) + // and `dyn Baz` to `dyn Baz + 'static` (because there is no + // such bound). + // + // Therefore, we would compute `object_lifetime_defaults` to a + // vector like `['x, 'static]`. Note that the vector only + // includes type parameters. + let generics = self.tcx.generics_of(type_def_id); + let in_body = { let mut scope = self.scope; loop { @@ -498,7 +497,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } }; - let generics = self.tcx.generics_of(def_id); + let object_lifetime_default = |i: usize| { + let param = generics.params.get(i)?; + match param.kind { + GenericParamDefKind::Type { object_lifetime_default, .. } => { + Some(object_lifetime_default) + } + GenericParamDefKind::Const { .. } => Some(ObjectLifetimeDefault::Empty), + GenericParamDefKind::Lifetime => return None, + } + }; let set_to_region = |set: ObjectLifetimeDefault| match set { ObjectLifetimeDefault::Empty => { if in_body { @@ -509,51 +517,32 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } ObjectLifetimeDefault::Static => Some(Region::Static), ObjectLifetimeDefault::Param(def_id) => { - let index = generics.param_def_id_to_index[&def_id]; + let index = *generics.param_def_id_to_index.get(&def_id)?; generic_args.args.get(index as usize).and_then(|arg| match arg { - GenericArg::Lifetime(lt) => self.tcx.named_region(lt.hir_id), + GenericArg::Lifetime(lt) => tcx.named_region(lt.hir_id), _ => None, }) } ObjectLifetimeDefault::Ambiguous => None, }; - generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamDefKind::Type { object_lifetime_default, .. } => { - Some(object_lifetime_default) - } - GenericParamDefKind::Const { .. } => Some(ObjectLifetimeDefault::Empty), - GenericParamDefKind::Lifetime => None, - }) - .map(set_to_region) - .collect() - }); - debug!(?object_lifetime_defaults); - - let mut i = 0; - for arg in generic_args.args { - match arg { - GenericArg::Lifetime(_) => {} - GenericArg::Type(ty) => { - if let Some(<) = object_lifetime_defaults.get(i) { - let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; + + for (i, arg) in generic_args.args.iter().enumerate() { + if let GenericArg::Type(ty) = arg { + if let Some(default) = object_lifetime_default(i) { + let lifetime = set_to_region(default); + let scope = Scope::ObjectLifetimeDefault { lifetime, s: self.scope }; self.with(scope, |this| this.visit_ty(ty)); } else { self.visit_ty(ty); } - i += 1; - } - GenericArg::Const(ct) => { - self.visit_anon_const(&ct.value); - i += 1; - } - GenericArg::Infer(inf) => { - self.visit_id(inf.hir_id); - i += 1; + } else { + self.visit_generic_arg(arg); } } + } else { + for arg in generic_args.args { + self.visit_generic_arg(arg); + } } // Hack: when resolving the type `XX` in binding like `dyn From 830f2211361b31ee6ea103632c234f14864f184f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 25 May 2022 11:21:19 +0200 Subject: [PATCH 08/13] Remove BinderScopeType. --- .../src/collect/object_lifetime_defaults.rs | 78 +++++++------------ 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs index 075c88ecf247d..75ada9a3fae27 100644 --- a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs +++ b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs @@ -171,7 +171,6 @@ enum Scope<'a> { /// it should be shifted by the number of `Binder`s in between the /// declaration `Binder` and the location it's referenced from. Binder { - scope_type: BinderScopeType, s: ScopeRef<'a>, }, @@ -197,35 +196,19 @@ enum Scope<'a> { Root, } -#[derive(Copy, Clone, Debug)] -enum BinderScopeType { - /// Any non-concatenating binder scopes. - Normal, - /// Within a syntactic trait ref, there may be multiple poly trait refs that - /// are nested (under the `associated_type_bounds` feature). The binders of - /// the inner poly trait refs are extended from the outer poly trait refs - /// and don't increase the late bound depth. If you had - /// `T: for<'a> Foo Baz<'a, 'b>>`, then the `for<'b>` scope - /// would be `Concatenating`. This also used in trait refs in where clauses - /// where we have two binders `for<> T: for<> Foo` (I've intentionally left - /// out any lifetimes because they aren't needed to show the two scopes). - /// The inner `for<>` has a scope of `Concatenating`. - Concatenating, -} - type ScopeRef<'a> = &'a Scope<'a>; const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref. - fn poly_trait_ref_binder_info(&mut self) -> BinderScopeType { + fn poly_trait_ref_needs_binder(&mut self) -> bool { let mut scope = self.scope; loop { match scope { // Nested poly trait refs have the binders concatenated - Scope::Binder { .. } => break BinderScopeType::Concatenating, - Scope::Body | Scope::Root => break BinderScopeType::Normal, + Scope::Binder { .. } => break false, + Scope::Body | Scope::Root => break true, Scope::Static { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => scope = s, } } @@ -247,7 +230,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Closure(..) = e.kind { - let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + let scope = Scope::Binder { s: self.scope }; self.with(scope, |this| { // a closure has no bounds, so everything // contained within is scoped within its binder. @@ -285,7 +268,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | hir::ItemKind::Fn(..) | hir::ItemKind::Impl(..) => { // These kinds of items have only early-bound lifetime parameters. - let scope = Scope::Binder { scope_type: BinderScopeType::Normal, s: ROOT_SCOPE }; + let scope = Scope::Binder { s: ROOT_SCOPE }; self.with(scope, |this| intravisit::walk_item(this, item)); } } @@ -294,7 +277,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { hir::ForeignItemKind::Fn(..) => { - let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + let scope = Scope::Binder { s: self.scope }; self.with(scope, |this| intravisit::walk_foreign_item(this, item)) } hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => { @@ -307,7 +290,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { match ty.kind { hir::TyKind::BareFn(..) => { - let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + let scope = Scope::Binder { s: self.scope }; self.with(scope, |this| { // a bare fn has no bounds, so everything // contained within is scoped within its binder. @@ -340,7 +323,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { use self::hir::TraitItemKind::*; match trait_item.kind { Fn(..) | Type(..) => { - let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + let scope = Scope::Binder { s: self.scope }; self.with(scope, |this| intravisit::walk_trait_item(this, trait_item)); } // Only methods and types support generics. @@ -352,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { use self::hir::ImplItemKind::*; match impl_item.kind { Fn(..) | TyAlias(..) => { - let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + let scope = Scope::Binder { s: self.scope }; self.with(scope, |this| intravisit::walk_impl_item(this, impl_item)); } // Only methods and types support generics. @@ -376,7 +359,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // scope. If there happens to be a nested poly trait ref (an error), that // will be `Concatenating` anyways, so we don't have to worry about the depth // being wrong. - let scope = Scope::Binder { s: self.scope, scope_type: BinderScopeType::Normal }; + let scope = Scope::Binder { s: self.scope }; self.with(scope, |this| intravisit::walk_where_predicate(this, predicate)) } &hir::WherePredicate::RegionPredicate(..) | &hir::WherePredicate::EqPredicate(..) => { @@ -387,15 +370,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { match bound { - hir::GenericBound::LangItemTrait(..) => { - // FIXME(jackh726): This is pretty weird. `LangItemTrait` doesn't go - // through the regular poly trait ref code, so we don't get another - // chance to introduce a binder. For now, I'm keeping the existing logic - // of "if there isn't a Binder scope above us, add one", but I - // imagine there's a better way to go about this. - let scope_type = self.poly_trait_ref_binder_info(); - - let scope = Scope::Binder { s: self.scope, scope_type }; + // FIXME(jackh726): This is pretty weird. `LangItemTrait` doesn't go + // through the regular poly trait ref code, so we don't get another + // chance to introduce a binder. For now, I'm keeping the existing logic + // of "if there isn't a Binder scope above us, add one", but I + // imagine there's a better way to go about this. + hir::GenericBound::LangItemTrait(..) if self.poly_trait_ref_needs_binder() => { + let scope = Scope::Binder { s: self.scope }; self.with(scope, |this| intravisit::walk_param_bound(this, bound)); } _ => intravisit::walk_param_bound(self, bound), @@ -409,14 +390,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ) { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); - let scope_type = self.poly_trait_ref_binder_info(); - - // Always introduce a scope here, even if this is in a where clause and - // we introduced the binders around the bounded Ty. In that case, we - // just reuse the concatenation functionality also present in nested trait - // refs. - let scope = Scope::Binder { s: self.scope, scope_type }; - self.with(scope, |this| intravisit::walk_poly_trait_ref(this, trait_ref, modifier)); + if self.poly_trait_ref_needs_binder() { + // Always introduce a scope here, even if this is in a where clause and + // we introduced the binders around the bounded Ty. In that case, we + // just reuse the concatenation functionality also present in nested trait + // refs. + let scope = Scope::Binder { s: self.scope }; + self.with(scope, |this| intravisit::walk_poly_trait_ref(this, trait_ref, modifier)); + } else { + intravisit::walk_poly_trait_ref(self, trait_ref, modifier); + } } } @@ -589,11 +572,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut scope = self.scope; let lifetime = loop { match *scope { - Scope::Binder { s, scope_type, .. } => { - match scope_type { - BinderScopeType::Normal => late_depth += 1, - BinderScopeType::Concatenating => {} - } + Scope::Binder { s, .. } => { + late_depth += 1; scope = s; } From 64e7067f8261bdd292409b068180654dd5fae61b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 25 May 2022 11:22:28 +0200 Subject: [PATCH 09/13] Add FIXME for using ty::Region. --- compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs index 75ada9a3fae27..57c9613e38b9f 100644 --- a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs +++ b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs @@ -189,6 +189,7 @@ enum Scope<'a> { /// inferred in a function body or potentially error outside one), /// for the default choice of lifetime in a trait object type. ObjectLifetimeDefault { + //FIXME(cjgillot) This should use a `ty::Region`. lifetime: Option, s: ScopeRef<'a>, }, From e80a113b4a02579c4f28e907fc3bd7c07ffe4f0a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 25 May 2022 11:28:57 +0200 Subject: [PATCH 10/13] Return ty::Region in object_lifetime_map. --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_typeck/src/astconv/mod.rs | 55 +++++++++---------- .../src/collect/object_lifetime_defaults.rs | 8 ++- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 217fae1536781..25071104ed345 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1595,7 +1595,7 @@ rustc_queries! { desc { "looking up lifetime defaults for a region on an item" } } /// Fetch the lifetimes for all the trait objects in an item-like. - query object_lifetime_map(_: LocalDefId) -> FxHashMap { + query object_lifetime_map(_: LocalDefId) -> FxHashMap> { storage(ArenaCacheSelector<'tcx>) desc { "looking up lifetime defaults for a region on an item" } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 5b0b4d9ae18af..25e933e7f4e49 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -204,7 +204,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let tcx = self.tcx(); let r = if let Some(rl) = tcx.named_region(lifetime.hir_id) { - self.ast_region_to_region_inner(rl) + Self::ast_region_to_region_inner(tcx, rl) } else { self.re_infer(def, lifetime.span).unwrap_or_else(|| { debug!(?lifetime, "unelided lifetime in signature"); @@ -226,9 +226,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { r } - #[tracing::instrument(level = "debug", skip(self))] - fn ast_region_to_region_inner(&self, lifetime: rl::Region) -> ty::Region<'tcx> { - let tcx = self.tcx(); + #[tracing::instrument(level = "debug", skip(tcx))] + pub fn ast_region_to_region_inner(tcx: TyCtxt<'tcx>, lifetime: rl::Region) -> ty::Region<'tcx> { let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)); let r = match lifetime { @@ -1547,33 +1546,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Use explicitly-specified region bound. let region_bound = if !lifetime.is_elided() { self.ast_region_to_region(lifetime, None) + } else if let Some(region) = + self.compute_object_lifetime_bound(span, existential_predicates) + { + region + } else if let Some(rl) = tcx.named_region(lifetime.hir_id) { + Self::ast_region_to_region_inner(self.tcx(), rl) + } else if let Some(®ion) = + tcx.object_lifetime_map(lifetime.hir_id.owner).get(&lifetime.hir_id.local_id) + { + region } else { - self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { - if let Some(rl) = tcx.named_region(lifetime.hir_id) { - self.ast_region_to_region_inner(rl) - } else if let Some(&rl) = - tcx.object_lifetime_map(lifetime.hir_id.owner).get(&lifetime.hir_id.local_id) - { - self.ast_region_to_region_inner(rl) - } else { - self.re_infer(None, span).unwrap_or_else(|| { - let mut err = struct_span_err!( - tcx.sess, - span, - E0228, - "the lifetime bound for this object type cannot be deduced \ + self.re_infer(None, span).unwrap_or_else(|| { + let mut err = struct_span_err!( + tcx.sess, + span, + E0228, + "the lifetime bound for this object type cannot be deduced \ from context; please supply an explicit bound" - ); - if borrowed { - // We will have already emitted an error E0106 complaining about a - // missing named lifetime in `&dyn Trait`, so we elide this one. - err.delay_as_bug(); - } else { - err.emit(); - } - tcx.lifetimes.re_static - }) + ); + if borrowed { + // We will have already emitted an error E0106 complaining about a + // missing named lifetime in `&dyn Trait`, so we elide this one. + err.delay_as_bug(); + } else { + err.emit(); } + tcx.lifetimes.re_static }) }; debug!("region_bound: {:?}", region_bound); diff --git a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs index 57c9613e38b9f..146a7726608ef 100644 --- a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs +++ b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs @@ -1,3 +1,4 @@ +use crate::AstConv; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -8,7 +9,7 @@ use rustc_hir::{GenericArg, GenericParamKind, LifetimeName, Node}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::*; -use rustc_middle::ty::{DefIdTree, GenericParamDefKind, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; use rustc_span::symbol::sym; use std::borrow::Cow; @@ -128,7 +129,7 @@ fn object_lifetime_defaults_for_item<'tcx>( pub(super) fn object_lifetime_map( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> FxHashMap { +) -> FxHashMap> { let mut named_region_map = Default::default(); let mut visitor = LifetimeContext { tcx, defs: &mut named_region_map, scope: ROOT_SCOPE }; let node = tcx.hir().get_by_def_id(def_id); @@ -160,7 +161,7 @@ impl RegionExt for Region { struct LifetimeContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, - defs: &'a mut FxHashMap, + defs: &'a mut FxHashMap>, scope: ScopeRef<'a>, } @@ -586,6 +587,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } }; let def = lifetime.shifted(late_depth); + let def = >::ast_region_to_region_inner(self.tcx, def); debug!(?def); self.defs.insert(lifetime_ref.hir_id.local_id, def); } From d63dda205fb4c7e467a9b501d6fb386de4e3ac96 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 25 May 2022 14:58:19 +0200 Subject: [PATCH 11/13] Pacify tidy. --- compiler/rustc_resolve/src/late/lifetimes.rs | 1 - compiler/rustc_typeck/src/collect.rs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index df83d06cebf48..37db3471ed953 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1,4 +1,3 @@ -// ignore-tidy-filelength //! Name resolution for lifetimes. //! //! Name resolution for lifetimes follows *much* simpler rules than the diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index f99a098bcbf6c..510058749c53b 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength //! "Collection" is the process of determining the type and other external //! details of each item in Rust. Collection is specifically concerned //! with *inter-procedural* things -- for example, for a function From 7c1a8d8972bb13bac3115f45d9623a1dc2bb8881 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 29 May 2022 20:15:34 +0200 Subject: [PATCH 12/13] Compute `object_lifetime_default` per parameter. --- .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 5 + compiler/rustc_metadata/src/rmeta/mod.rs | 2 + compiler/rustc_middle/src/query/mod.rs | 3 +- compiler/rustc_middle/src/ty/generics.rs | 3 +- compiler/rustc_middle/src/ty/parameterized.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 28 ++++++ compiler/rustc_typeck/src/collect.rs | 26 +----- .../src/collect/object_lifetime_defaults.rs | 93 +++++-------------- 9 files changed, 65 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index e3581a7607fb8..2c46c281f17d6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -199,6 +199,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, codegen_fn_attrs => { table } impl_trait_ref => { table } const_param_default => { table } + object_lifetime_default => { table } thir_abstract_const => { table } optimized_mir => { table } mir_for_ctfe => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1425c5467af87..79a33f448222c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1035,6 +1035,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); } } + if let DefKind::TyParam | DefKind::ConstParam = def_kind { + if let Some(default) = self.tcx.object_lifetime_default(def_id) { + record!(self.tables.object_lifetime_default[def_id] <- default); + } + } if let DefKind::Trait | DefKind::TraitAlias = def_kind { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index fb2ffe1d73d96..e1a6f22ab9e80 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -16,6 +16,7 @@ use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; +use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc_middle::mir; use rustc_middle::thir; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -357,6 +358,7 @@ define_tables! { codegen_fn_attrs: Table>, impl_trait_ref: Table>>, const_param_default: Table>>, + object_lifetime_default: Table>, optimized_mir: Table>>, mir_for_ctfe: Table>>, promoted_mir: Table>>>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 25071104ed345..f435e9dbc06e1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1591,8 +1591,9 @@ rustc_queries! { /// for each parameter 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(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> { + query object_lifetime_default(_: DefId) -> Option { desc { "looking up lifetime defaults for a region on an item" } + separate_provide_extern } /// Fetch the lifetimes for all the trait objects in an item-like. query object_lifetime_map(_: LocalDefId) -> FxHashMap> { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 1feabb2d6b122..dd086ce8d817d 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -1,4 +1,3 @@ -use crate::middle::resolve_lifetime::ObjectLifetimeDefault; use crate::ty; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::EarlyBinder; @@ -13,7 +12,7 @@ use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predi #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub enum GenericParamDefKind { Lifetime, - Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool }, + Type { has_default: bool, synthetic: bool }, Const { has_default: bool }, } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 54ba9e84fdb7b..1ad3b983eba39 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -53,6 +53,7 @@ trivially_parameterized_over_tcx! { crate::metadata::ModChild, crate::middle::codegen_fn_attrs::CodegenFnAttrs, crate::middle::exported_symbols::SymbolExportInfo, + crate::middle::resolve_lifetime::ObjectLifetimeDefault, crate::mir::ConstQualifs, ty::Generics, ty::ImplPolarity, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 0fe6d58b86daa..c6c5d15896484 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -16,6 +16,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID}; use rustc_hir::{MethodKind, Target}; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{ @@ -164,6 +165,9 @@ impl CheckAttrVisitor<'_> { sym::no_implicit_prelude => { self.check_generic_attr(hir_id, attr, target, &[Target::Mod]) } + sym::rustc_object_lifetime_default => { + self.check_object_lifetime_default(hir_id, span) + } _ => {} } @@ -368,6 +372,30 @@ impl CheckAttrVisitor<'_> { } } + /// Debugging aid for `object_lifetime_default` query. + fn check_object_lifetime_default(&self, hir_id: HirId, span: Span) { + let tcx = self.tcx; + if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) { + let object_lifetime_default_reprs: String = generics + .params + .iter() + .filter_map(|p| { + let param_id = tcx.hir().local_def_id(p.hir_id); + let default = tcx.object_lifetime_default(param_id)?; + Some(match default { + ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(), + ObjectLifetimeDefault::Static => "'static".to_owned(), + ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(), + ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(), + }) + }) + .collect::>() + .join(","); + + tcx.sess.span_err(span, &object_lifetime_default_reprs); + } + } + /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid. fn check_track_caller( &self, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 510058749c53b..5d7a4dc1d0156 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -35,7 +35,6 @@ use rustc_hir::weak_lang_items; use rustc_hir::{GenericParamKind, HirId, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; -use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::InternalSubsts; @@ -71,7 +70,7 @@ pub fn provide(providers: &mut Providers) { type_of: type_of::type_of, item_bounds: item_bounds::item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds, - object_lifetime_defaults: object_lifetime_defaults::object_lifetime_defaults, + object_lifetime_default: object_lifetime_defaults::object_lifetime_default, object_lifetime_map: object_lifetime_defaults::object_lifetime_map, generics_of, predicates_of, @@ -1638,7 +1637,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, - object_lifetime_default: ObjectLifetimeDefault::Empty, synthetic: false, }, }); @@ -1686,8 +1684,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { kind: ty::GenericParamDefKind::Lifetime, })); - let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id.owner); - // Now create the real type and const parameters. let type_start = own_start - has_self as u32 + params.len() as u32; let mut i = 0; @@ -1712,13 +1708,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { } } - let kind = ty::GenericParamDefKind::Type { - has_default: default.is_some(), - object_lifetime_default: object_lifetime_defaults - .as_ref() - .map_or(ObjectLifetimeDefault::Empty, |o| o[i]), - synthetic, - }; + let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic }; let param_def = ty::GenericParamDef { index: type_start + i as u32, @@ -1766,11 +1756,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { name: Symbol::intern(arg), def_id, pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { - has_default: false, - object_lifetime_default: ObjectLifetimeDefault::Empty, - synthetic: false, - }, + kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, })); } @@ -1783,11 +1769,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { name: Symbol::intern(""), def_id, pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { - has_default: false, - object_lifetime_default: ObjectLifetimeDefault::Empty, - synthetic: false, - }, + kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, }); } } diff --git a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs index 146a7726608ef..2b03b0e7b36a5 100644 --- a/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs +++ b/compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs @@ -2,7 +2,7 @@ use crate::AstConv; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::ItemLocalId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParamKind, LifetimeName, Node}; @@ -10,76 +10,25 @@ use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::*; use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; -use rustc_span::symbol::sym; -use std::borrow::Cow; use tracing::debug; -pub(super) fn object_lifetime_defaults( +pub(super) fn object_lifetime_default( tcx: TyCtxt<'_>, - def_id: LocalDefId, -) -> Option<&[ObjectLifetimeDefault]> { - let Node::Item(item) = tcx.hir().get_by_def_id(def_id) else { return None }; - 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, - origin: hir::OpaqueTyOrigin::TyAlias, - .. - }) - | hir::ItemKind::TyAlias(_, ref generics) - | hir::ItemKind::Trait(_, _, ref generics, ..) => { - let result = object_lifetime_defaults_for_item(tcx, generics); - debug!(?result); - - // 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 { - ObjectLifetimeDefault::Empty => "BaseDefault".into(), - ObjectLifetimeDefault::Static => "'static".into(), - ObjectLifetimeDefault::Param(def_id) => { - let def_id = def_id.expect_local(); - generics - .params - .iter() - .find(|param| tcx.hir().local_def_id(param.hir_id) == def_id) - .map(|param| param.name.ident().to_string().into()) - .unwrap() - } - ObjectLifetimeDefault::Ambiguous => "Ambiguous".into(), - }) - .collect::>>() - .join(","); - tcx.sess.span_err(item.span, &object_lifetime_default_reprs); - } + param_def_id: DefId, +) -> Option { + let param_def_id = param_def_id.expect_local(); + let parent_item_id = tcx.local_parent(param_def_id); + let generics = tcx.hir().get_generics(parent_item_id)?; - Some(result) - } - _ => None, - } -} + // Scan the bounds and where-clauses on parameters to extract bounds + // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` + // for each type parameter. -/// Scan the bounds and where-clauses on parameters to extract bounds -/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` -/// for each type parameter. -fn object_lifetime_defaults_for_item<'tcx>( - tcx: TyCtxt<'tcx>, - generics: &hir::Generics<'_>, -) -> &'tcx [ObjectLifetimeDefault] { - fn add_bounds(set: &mut Set1, bounds: &[hir::GenericBound<'_>]) { - for bound in bounds { - if let hir::GenericBound::Outlives(ref lifetime) = *bound { - set.insert(lifetime.name.normalize_to_macros_2_0()); - } - } - } + let param_hir_id = tcx.hir().local_def_id_to_hir_id(param_def_id); + let param = generics.params.iter().find(|p| p.hir_id == param_hir_id)?; - let process_param = |param: &hir::GenericParam<'_>| match param.kind { + match param.kind { GenericParamKind::Lifetime { .. } => None, GenericParamKind::Type { .. } => { let mut set = Set1::Empty; @@ -101,7 +50,11 @@ fn object_lifetime_defaults_for_item<'tcx>( }; if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) { - add_bounds(&mut set, &data.bounds); + for bound in data.bounds { + if let hir::GenericBound::Outlives(ref lifetime) = *bound { + set.insert(lifetime.name.normalize_to_macros_2_0()); + } + } } } @@ -121,9 +74,7 @@ fn object_lifetime_defaults_for_item<'tcx>( // in an arbitrary order. Some(ObjectLifetimeDefault::Empty) } - }; - - tcx.arena.alloc_from_iter(generics.params.iter().filter_map(process_param)) + } } pub(super) fn object_lifetime_map( @@ -466,7 +417,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // Therefore, we would compute `object_lifetime_defaults` to a // vector like `['x, 'static]`. Note that the vector only // includes type parameters. - let generics = self.tcx.generics_of(type_def_id); + let generics = tcx.generics_of(type_def_id); let in_body = { let mut scope = self.scope; @@ -485,9 +436,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let object_lifetime_default = |i: usize| { let param = generics.params.get(i)?; match param.kind { - GenericParamDefKind::Type { object_lifetime_default, .. } => { - Some(object_lifetime_default) - } + GenericParamDefKind::Type { .. } => tcx.object_lifetime_default(param.def_id), GenericParamDefKind::Const { .. } => Some(ObjectLifetimeDefault::Empty), GenericParamDefKind::Lifetime => return None, } From 5f6be7fcd8c3e133ecc00d70fa0a292cc44403da Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 29 May 2022 21:20:20 +0200 Subject: [PATCH 13/13] Bless incremental tests. --- src/test/incremental/hashes/enum_defs.rs | 8 ++++---- src/test/incremental/hashes/trait_defs.rs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index b466cfdd59594..0f8898c389b7f 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -504,9 +504,9 @@ enum EnumAddLifetimeBoundToParameter<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeBoundToParameter<'a, T: 'a> { Variant1(T), @@ -559,9 +559,9 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a { Variant1(T), diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 9b79fd8a0a105..be11b807cb6ae 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -1054,9 +1054,9 @@ trait TraitAddTraitBoundToTypeParameterOfTrait { } trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } @@ -1132,9 +1132,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } @@ -1189,9 +1189,9 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } @@ -1242,9 +1242,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { }