summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/collect
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_hir_analysis/src/collect
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis/src/collect')
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/lifetimes.rs577
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs191
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs18
5 files changed, 415 insertions, 392 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index c7777a946..639f81f20 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -51,7 +51,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.lazy_normalization() {
- if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
+ if let Some(param_id) = tcx.hir().opt_const_param_default_param_def_id(hir_id) {
// If the def_id we are calling generics_of on is an anon ct default i.e:
//
// struct Foo<const N: usize = { .. }>;
@@ -77,8 +77,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// This has some implications for how we get the predicates available to the anon const
// see `explicit_predicates_of` for more information on this
let generics = tcx.generics_of(parent_def_id.to_def_id());
- let param_def = tcx.hir().local_def_id(param_id).to_def_id();
- let param_def_idx = generics.param_def_id_to_index[&param_def];
+ let param_def_idx = generics.param_def_id_to_index[&param_id.to_def_id()];
// In the above example this would be .params[..N#0]
let params = generics.params[..param_def_idx as usize].to_owned();
let param_def_id_to_index =
@@ -241,7 +240,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
name: param.name.ident().name,
index: own_start + i as u32,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ def_id: param.def_id.to_def_id(),
pure_wrt_drop: param.pure_wrt_drop,
kind: ty::GenericParamDefKind::Lifetime,
}));
@@ -286,7 +285,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
Some(ty::GenericParamDef {
index: next_index(),
name: param.name.ident().name,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ def_id: param.def_id.to_def_id(),
pure_wrt_drop: param.pure_wrt_drop,
kind,
})
@@ -303,7 +302,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
Some(ty::GenericParamDef {
index: next_index(),
name: param.name.ident().name,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ def_id: param.def_id.to_def_id(),
pure_wrt_drop: param.pure_wrt_drop,
kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
})
@@ -399,7 +398,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
- self.has_late_bound_regions = Some(lt.span);
+ self.has_late_bound_regions = Some(lt.ident.span);
}
}
}
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 0d34a8bfe..0542e2c8f 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -35,9 +35,11 @@ fn associated_type_bounds<'tcx>(
let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(tr) => tr.self_ty() == item_ty,
- ty::PredicateKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
- ty::PredicateKind::TypeOutlives(outlives) => outlives.0 == item_ty,
+ ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => tr.self_ty() == item_ty,
+ ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => {
+ proj.projection_ty.self_ty() == item_ty
+ }
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => outlives.0 == item_ty,
_ => false,
}
});
diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
index 3f263a6de..e4fe3e90e 100644
--- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
@@ -15,19 +15,18 @@ use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
use rustc_middle::bug;
-use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::*;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_span::def_id::DefId;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use std::fmt;
trait RegionExt {
- fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
+ fn early(param: &GenericParam<'_>) -> (LocalDefId, Region);
- fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
+ fn late(index: u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
fn id(&self) -> Option<DefId>;
@@ -35,20 +34,18 @@ trait RegionExt {
}
impl RegionExt for Region {
- fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
- let def_id = hir_map.local_def_id(param.hir_id);
- debug!("Region::early: def_id={:?}", def_id);
- (def_id, Region::EarlyBound(def_id.to_def_id()))
+ fn early(param: &GenericParam<'_>) -> (LocalDefId, Region) {
+ debug!("Region::early: def_id={:?}", param.def_id);
+ (param.def_id, Region::EarlyBound(param.def_id.to_def_id()))
}
- fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
+ fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
let depth = ty::INNERMOST;
- let def_id = hir_map.local_def_id(param.hir_id);
debug!(
"Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
- idx, param, depth, def_id,
+ idx, param, depth, param.def_id,
);
- (def_id, Region::LateBound(depth, idx, def_id.to_def_id()))
+ (param.def_id, Region::LateBound(depth, idx, param.def_id.to_def_id()))
}
fn id(&self) -> Option<DefId> {
@@ -94,11 +91,6 @@ struct LifetimeContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
map: &'a mut NamedRegionMap,
scope: ScopeRef<'a>,
-
- /// Indicates that we only care about the definition of a trait. This should
- /// be false if the `Item` we are resolving lifetimes for is not a trait or
- /// we eventually need lifetimes resolve for trait items.
- trait_definition_only: bool,
}
#[derive(Debug)]
@@ -166,7 +158,9 @@ enum Scope<'a> {
s: ScopeRef<'a>,
},
- Root,
+ Root {
+ opt_parent_item: Option<LocalDefId>,
+ },
}
#[derive(Copy, Clone, Debug)]
@@ -214,95 +208,58 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
.field("s", &"..")
.finish(),
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
- Scope::Root => f.debug_struct("Root").finish(),
+ Scope::Root { opt_parent_item } => {
+ f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
+ }
}
}
}
type ScopeRef<'a> = &'a Scope<'a>;
-const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
-
pub(crate) fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
- resolve_lifetimes_trait_definition,
resolve_lifetimes,
- named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id),
+ named_region_map: |tcx, id| tcx.resolve_lifetimes(id).defs.get(&id),
is_late_bound_map,
object_lifetime_default,
- late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
+ late_bound_vars_map: |tcx, id| tcx.resolve_lifetimes(id).late_bound_vars.get(&id),
..*providers
};
}
-/// Like `resolve_lifetimes`, but does not resolve lifetimes for trait items.
-/// Also does not generate any diagnostics.
-///
-/// This is ultimately a subset of the `resolve_lifetimes` work. It effectively
-/// resolves lifetimes only within the trait "header" -- that is, the trait
-/// and supertrait list. In contrast, `resolve_lifetimes` resolves all the
-/// lifetimes within the trait and its items. There is room to refactor this,
-/// for example to resolve lifetimes for each trait item in separate queries,
-/// but it's convenient to do the entire trait at once because the lifetimes
-/// from the trait definition are in scope within the trait items as well.
-///
-/// The reason for this separate call is to resolve what would otherwise
-/// be a cycle. Consider this example:
-///
-/// ```ignore UNSOLVED (maybe @jackh726 knows what lifetime parameter to give Sub)
-/// trait Base<'a> {
-/// type BaseItem;
-/// }
-/// trait Sub<'b>: for<'a> Base<'a> {
-/// type SubItem: Sub<BaseItem = &'b u32>;
-/// }
-/// ```
-///
-/// When we resolve `Sub` and all its items, we also have to resolve `Sub<BaseItem = &'b u32>`.
-/// To figure out the index of `'b`, we have to know about the supertraits
-/// of `Sub` so that we can determine that the `for<'a>` will be in scope.
-/// (This is because we -- currently at least -- flatten all the late-bound
-/// lifetimes into a single binder.) This requires us to resolve the
-/// *trait definition* of `Sub`; basically just enough lifetime information
-/// to look at the supertraits.
-#[instrument(level = "debug", skip(tcx))]
-fn resolve_lifetimes_trait_definition(
- tcx: TyCtxt<'_>,
- local_def_id: LocalDefId,
-) -> ResolveLifetimes {
- convert_named_region_map(do_resolve(tcx, local_def_id, true))
-}
-
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
/// You should not read the result of this query directly, but rather use
/// `named_region_map`, `is_late_bound_map`, etc.
#[instrument(level = "debug", skip(tcx))]
-fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
- convert_named_region_map(do_resolve(tcx, local_def_id, false))
-}
-
-fn do_resolve(
- tcx: TyCtxt<'_>,
- local_def_id: LocalDefId,
- trait_definition_only: bool,
-) -> NamedRegionMap {
- let item = tcx.hir().expect_item(local_def_id);
+fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveLifetimes {
let mut named_region_map =
NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() };
let mut visitor = LifetimeContext {
tcx,
map: &mut named_region_map,
- scope: ROOT_SCOPE,
- trait_definition_only,
+ scope: &Scope::Root { opt_parent_item: None },
};
- visitor.visit_item(item);
-
- named_region_map
-}
+ match tcx.hir().owner(local_def_id) {
+ hir::OwnerNode::Item(item) => visitor.visit_item(item),
+ hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
+ hir::OwnerNode::TraitItem(item) => {
+ let scope =
+ Scope::Root { opt_parent_item: Some(tcx.local_parent(item.owner_id.def_id)) };
+ visitor.scope = &scope;
+ visitor.visit_trait_item(item)
+ }
+ hir::OwnerNode::ImplItem(item) => {
+ let scope =
+ Scope::Root { opt_parent_item: Some(tcx.local_parent(item.owner_id.def_id)) };
+ visitor.scope = &scope;
+ visitor.visit_impl_item(item)
+ }
+ hir::OwnerNode::Crate(_) => {}
+ }
-fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes {
let mut rl = ResolveLifetimes::default();
for (hir_id, v) in named_region_map.defs {
@@ -319,53 +276,6 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
rl
}
-/// Given `any` owner (structs, traits, trait methods, etc.), does lifetime resolution.
-/// There are two important things this does.
-/// First, we have to resolve lifetimes for
-/// the entire *`Item`* that contains this owner, because that's the largest "scope"
-/// where we can have relevant lifetimes.
-/// Second, if we are asking for lifetimes in a trait *definition*, we use `resolve_lifetimes_trait_definition`
-/// instead of `resolve_lifetimes`, which does not descend into the trait items and does not emit diagnostics.
-/// This allows us to avoid cycles. Importantly, if we ask for lifetimes for lifetimes that have an owner
-/// other than the trait itself (like the trait methods or associated types), then we just use the regular
-/// `resolve_lifetimes`.
-fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: hir::OwnerId) -> &'tcx ResolveLifetimes {
- let item_id = item_for(tcx, def_id.def_id);
- let local_def_id = item_id.owner_id.def_id;
- if item_id.owner_id == def_id {
- let item = tcx.hir().item(item_id);
- match item.kind {
- hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id),
- _ => tcx.resolve_lifetimes(local_def_id),
- }
- } else {
- tcx.resolve_lifetimes(local_def_id)
- }
-}
-
-/// Finds the `Item` that contains the given `LocalDefId`
-fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> hir::ItemId {
- match tcx.hir().find_by_def_id(local_def_id) {
- Some(Node::Item(item)) => {
- return item.item_id();
- }
- _ => {}
- }
- let item = {
- let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
- let mut parent_iter = tcx.hir().parent_iter(hir_id);
- loop {
- let node = parent_iter.next().map(|n| n.1);
- match node {
- Some(hir::Node::Item(item)) => break item.item_id(),
- Some(hir::Node::Crate(_)) | None => bug!("Called `item_for` on an Item."),
- _ => {}
- }
- }
- };
- item
-}
-
fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind {
match region {
Region::LateBound(_, _, def_id) => {
@@ -383,7 +293,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut supertrait_lifetimes = vec![];
loop {
match scope {
- Scope::Body { .. } | Scope::Root => {
+ Scope::Body { .. } | Scope::Root { .. } => {
break (vec![], BinderScopeType::Normal);
}
@@ -414,21 +324,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
}
impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
- type NestedFilter = nested_filter::All;
+ type NestedFilter = nested_filter::OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
- // We want to nest trait/impl items in their parent, but nothing else.
- fn visit_nested_item(&mut self, _: hir::ItemId) {}
-
- fn visit_trait_item_ref(&mut self, ii: &'tcx hir::TraitItemRef) {
- if !self.trait_definition_only {
- intravisit::walk_trait_item_ref(self, ii)
- }
- }
-
fn visit_nested_body(&mut self, body: hir::BodyId) {
let body = self.tcx.hir().body(body);
self.with(Scope::Body { id: body.id(), s: self.scope }, |this| {
@@ -491,7 +392,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
+ let pair = Region::late(late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
(pair, r)
})
@@ -548,7 +449,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
intravisit::walk_item(this, item)
});
}
- hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin: hir::OpaqueTyOrigin::TyAlias, ..
+ }) => {
// Opaque types are visited when we visit the
// `TyKind::OpaqueDef`, so that they have the lifetimes from
// their parent opaque_ty in scope.
@@ -557,34 +460,53 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// their owner, we can keep going until we find the Item that owns that. We then
// conservatively add all resolved lifetimes. Otherwise we run into problems in
// cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
- for (_hir_id, node) in self.tcx.hir().parent_iter(item.owner_id.into()) {
- match node {
- hir::Node::Item(parent_item) => {
- let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(
- item_for(self.tcx, parent_item.owner_id.def_id).owner_id.def_id,
- );
- // We need to add *all* deps, since opaque tys may want them from *us*
- for (&owner, defs) in resolved_lifetimes.defs.iter() {
- defs.iter().for_each(|(&local_id, region)| {
- self.map.defs.insert(hir::HirId { owner, local_id }, *region);
- });
- }
- for (&owner, late_bound_vars) in
- resolved_lifetimes.late_bound_vars.iter()
- {
- late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
- self.record_late_bound_vars(
- hir::HirId { owner, local_id },
- late_bound_vars.clone(),
- );
- });
- }
- break;
+ let parent_item = self.tcx.hir().get_parent_item(item.hir_id());
+ let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(parent_item);
+ // We need to add *all* deps, since opaque tys may want them from *us*
+ for (&owner, defs) in resolved_lifetimes.defs.iter() {
+ defs.iter().for_each(|(&local_id, region)| {
+ self.map.defs.insert(hir::HirId { owner, local_id }, *region);
+ });
+ }
+ for (&owner, late_bound_vars) in resolved_lifetimes.late_bound_vars.iter() {
+ late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
+ self.record_late_bound_vars(
+ hir::HirId { owner, local_id },
+ late_bound_vars.clone(),
+ );
+ });
+ }
+ }
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin: hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_),
+ generics,
+ ..
+ }) => {
+ // We want to start our early-bound indices at the end of the parent scope,
+ // not including any parent `impl Trait`s.
+ let mut lifetimes = FxIndexMap::default();
+ debug!(?generics.params);
+ for param in generics.params {
+ match param.kind {
+ GenericParamKind::Lifetime { .. } => {
+ let (def_id, reg) = Region::early(&param);
+ lifetimes.insert(def_id, reg);
}
- hir::Node::Crate(_) => bug!("No Item about an OpaqueTy"),
- _ => {}
+ GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
}
}
+
+ let scope = Scope::Binder {
+ hir_id: item.hir_id(),
+ lifetimes,
+ s: self.scope,
+ scope_type: BinderScopeType::Normal,
+ where_bound_origin: None,
+ };
+ self.with(scope, |this| {
+ let scope = Scope::TraitRefBoundary { s: this.scope };
+ this.with(scope, |this| intravisit::walk_item(this, item))
+ });
}
hir::ItemKind::TyAlias(_, ref generics)
| hir::ItemKind::Enum(_, ref generics)
@@ -598,9 +520,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.params
.iter()
.filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => {
- Some(Region::early(self.tcx.hir(), param))
- }
+ GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
})
.collect();
@@ -609,7 +529,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
hir_id: item.hir_id(),
lifetimes,
scope_type: BinderScopeType::Normal,
- s: ROOT_SCOPE,
+ s: self.scope,
where_bound_origin: None,
};
self.with(scope, |this| {
@@ -648,7 +568,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
+ let pair = Region::late(late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
(pair, r)
})
@@ -675,7 +595,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.visit_poly_trait_ref(bound);
}
});
- match lifetime.name {
+ match lifetime.res {
LifetimeName::ImplicitObjectLifetimeDefault => {
// If the user does not write *anything*, we
// use the object lifetime defaulting
@@ -712,7 +632,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// ^ ^ this gets resolved in the scope of
// the opaque_ty generics
let opaque_ty = self.tcx.hir().item(item_id);
- let (generics, bounds) = match opaque_ty.kind {
+ match opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias,
..
@@ -733,10 +653,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
- ref generics,
- bounds,
..
- }) => (generics, bounds),
+ }) => {}
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
};
@@ -766,65 +684,28 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// Ensure that the parent of the def is an item, not HRTB
let parent_id = self.tcx.hir().get_parent_node(hir_id);
if !parent_id.is_owner() {
- if !self.trait_definition_only {
- struct_span_err!(
- self.tcx.sess,
- lifetime.span,
- E0657,
- "`impl Trait` can only capture lifetimes \
- bound at the fn or impl level"
- )
- .emit();
- }
+ struct_span_err!(
+ self.tcx.sess,
+ lifetime.ident.span,
+ E0657,
+ "`impl Trait` can only capture lifetimes bound at the fn or impl level"
+ )
+ .emit();
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
}
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy { .. }, ..
}) = self.tcx.hir().get(parent_id)
{
- if !self.trait_definition_only {
- let mut err = self.tcx.sess.struct_span_err(
- lifetime.span,
- "higher kinded lifetime bounds on nested opaque types are not supported yet",
- );
- err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
- err.emit();
- }
+ let mut err = self.tcx.sess.struct_span_err(
+ lifetime.ident.span,
+ "higher kinded lifetime bounds on nested opaque types are not supported yet",
+ );
+ err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
+ err.emit();
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
}
}
-
- // We want to start our early-bound indices at the end of the parent scope,
- // not including any parent `impl Trait`s.
- let mut lifetimes = FxIndexMap::default();
- debug!(?generics.params);
- for param in generics.params {
- match param.kind {
- GenericParamKind::Lifetime { .. } => {
- let (def_id, reg) = Region::early(self.tcx.hir(), &param);
- lifetimes.insert(def_id, reg);
- }
- GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
- }
- }
- self.record_late_bound_vars(ty.hir_id, vec![]);
-
- let scope = Scope::Binder {
- hir_id: ty.hir_id,
- lifetimes,
- s: self.scope,
- scope_type: BinderScopeType::Normal,
- where_bound_origin: None,
- };
- self.with(scope, |this| {
- let scope = Scope::TraitRefBoundary { s: this.scope };
- this.with(scope, |this| {
- this.visit_generics(generics);
- for bound in bounds {
- this.visit_param_bound(bound);
- }
- })
- });
}
_ => intravisit::walk_ty(self, ty),
}
@@ -845,9 +726,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.params
.iter()
.filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => {
- Some(Region::early(self.tcx.hir(), param))
- }
+ GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
})
.collect();
@@ -893,9 +772,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.params
.iter()
.filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => {
- Some(Region::early(self.tcx.hir(), param))
- }
+ GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None,
})
.collect();
@@ -925,9 +802,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
- match lifetime_ref.name {
+ match lifetime_ref.res {
hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
- hir::LifetimeName::Param(param_def_id, _) => {
+ hir::LifetimeName::Param(param_def_id) => {
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
}
// If we've already reported an error, just ignore `lifetime_ref`.
@@ -937,7 +814,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
}
- fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
+ fn visit_path(&mut self, path: &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 {
@@ -1000,7 +877,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
})
.enumerate()
.map(|(late_bound_idx, param)| {
- Region::late(late_bound_idx as u32, this.tcx.hir(), param)
+ Region::late(late_bound_idx as u32, param)
})
.collect();
let binders: Vec<_> =
@@ -1035,27 +912,27 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.visit_lifetime(lifetime);
walk_list!(this, visit_param_bound, bounds);
- if lifetime.name != hir::LifetimeName::Static {
+ if lifetime.res != hir::LifetimeName::Static {
for bound in bounds {
let hir::GenericBound::Outlives(ref lt) = bound else {
continue;
};
- if lt.name != hir::LifetimeName::Static {
+ if lt.res != hir::LifetimeName::Static {
continue;
}
this.insert_lifetime(lt, Region::Static);
this.tcx
.sess
.struct_span_warn(
- lifetime.span,
+ lifetime.ident.span,
&format!(
"unnecessary lifetime parameter `{}`",
- lifetime.name.ident(),
+ lifetime.ident,
),
)
.help(&format!(
"you can use the `'static` lifetime directly, in place of `{}`",
- lifetime.name.ident(),
+ lifetime.ident,
))
.emit();
}
@@ -1113,8 +990,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair =
- Region::late(initial_bound_vars + late_bound_idx as u32, self.tcx.hir(), param);
+ let pair = Region::late(initial_bound_vars + late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
lifetimes.insert(pair.0, pair.1);
r
@@ -1167,7 +1043,7 @@ fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> Obje
for bound in bound.bounds {
if let hir::GenericBound::Outlives(ref lifetime) = *bound {
- set.insert(lifetime.name.normalize_to_macros_2_0());
+ set.insert(lifetime.res);
}
}
}
@@ -1175,7 +1051,7 @@ fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> Obje
match set {
Set1::Empty => ObjectLifetimeDefault::Empty,
Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
- Set1::One(hir::LifetimeName::Param(param_def_id, _)) => {
+ Set1::One(hir::LifetimeName::Param(param_def_id)) => {
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
}
_ => ObjectLifetimeDefault::Ambiguous,
@@ -1193,12 +1069,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
{
let LifetimeContext { tcx, map, .. } = self;
- let mut this = LifetimeContext {
- tcx: *tcx,
- map,
- scope: &wrap_scope,
- trait_definition_only: self.trait_definition_only,
- };
+ let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope };
let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
{
let _enter = span.enter();
@@ -1250,9 +1121,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
if self.tcx.is_late_bound(param.hir_id) {
let late_bound_idx = named_late_bound_vars;
named_late_bound_vars += 1;
- Some(Region::late(late_bound_idx, self.tcx.hir(), param))
+ Some(Region::late(late_bound_idx, param))
} else {
- Some(Region::early(self.tcx.hir(), param))
+ Some(Region::early(param))
}
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
@@ -1268,7 +1139,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
})
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
+ let pair = Region::late(late_bound_idx as u32, param);
late_region_as_bound_region(self.tcx, &pair.1)
})
.collect();
@@ -1303,7 +1174,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
scope = s;
}
- Scope::Root => {
+ Scope::Root { opt_parent_item } => {
+ if let Some(parent_item) = opt_parent_item
+ && let parent_generics = self.tcx.generics_of(parent_item)
+ && parent_generics.param_def_id_to_index.contains_key(&region_def_id.to_def_id())
+ {
+ break Some(Region::EarlyBound(region_def_id.to_def_id()));
+ }
break None;
}
@@ -1318,42 +1195,52 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
// regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
- && let hir::LifetimeName::Param(_, hir::ParamName::Fresh) = lifetime_ref.name
+ && let hir::LifetimeName::Param(param_id) = lifetime_ref.res
+ && let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
+ && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
+ && param.is_elided_lifetime()
&& let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
{
let mut diag = rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
sym::anonymous_lifetime_in_impl_trait,
- lifetime_ref.span,
+ lifetime_ref.ident.span,
"anonymous lifetimes in `impl Trait` are unstable",
);
- match self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id) {
- Some(generics) => {
-
- let new_param_sugg_tuple;
-
- new_param_sugg_tuple = match generics.span_for_param_suggestion() {
- Some(_) => {
- Some((self.tcx.sess.source_map().span_through_char(generics.span, '<').shrink_to_hi(), "'a, ".to_owned()))
- },
- None => Some((generics.span, "<'a>".to_owned()))
- };
-
- let mut multi_sugg_vec = vec![(lifetime_ref.span.shrink_to_hi(), "'a ".to_owned())];
-
- if let Some(new_tuple) = new_param_sugg_tuple{
- multi_sugg_vec.push(new_tuple);
- }
-
- diag.span_label(lifetime_ref.span, "expected named lifetime parameter");
- diag.multipart_suggestion("consider introducing a named lifetime parameter",
- multi_sugg_vec,
- rustc_errors::Applicability::MaybeIncorrect);
-
- },
- None => { }
+ if let Some(generics) =
+ self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id)
+ {
+ let new_param_sugg = if let Some(span) =
+ generics.span_for_lifetime_suggestion()
+ {
+ (span, "'a, ".to_owned())
+ } else {
+ (generics.span, "<'a>".to_owned())
+ };
+
+ let lifetime_sugg = match lifetime_ref.suggestion_position() {
+ (hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()),
+ (hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()),
+ (hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()),
+ (hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()),
+ (hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()),
+ };
+ let suggestions = vec![
+ lifetime_sugg,
+ new_param_sugg,
+ ];
+
+ diag.span_label(
+ lifetime_ref.ident.span,
+ "expected named lifetime parameter",
+ );
+ diag.multipart_suggestion(
+ "consider introducing a named lifetime parameter",
+ suggestions,
+ rustc_errors::Applicability::MaybeIncorrect,
+ );
}
diag.emit();
@@ -1377,11 +1264,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
} else if let Some(body_id) = outermost_body {
let fn_id = self.tcx.hir().body_owner(body_id);
match self.tcx.hir().get(fn_id) {
- Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. })
- | Node::TraitItem(&hir::TraitItem {
+ Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
+ | Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(..), ..
})
- | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
+ | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. })
+ | Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
let scope = self.tcx.hir().local_def_id(fn_id);
def = Region::Free(scope.to_def_id(), def.id().unwrap());
}
@@ -1409,14 +1297,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
} => {
let mut err = self.tcx.sess.struct_span_err(
- lifetime_ref.span,
+ lifetime_ref.ident.span,
"`impl Trait` can only mention lifetimes bound at the fn or impl level",
);
err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here");
err.emit();
return;
}
- Scope::Root => break,
+ Scope::Root { .. } => break,
Scope::Binder { s, .. }
| Scope::Body { s, .. }
| Scope::Elision { s, .. }
@@ -1429,7 +1317,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
self.tcx.sess.delay_span_bug(
- lifetime_ref.span,
+ lifetime_ref.ident.span,
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
);
}
@@ -1494,7 +1382,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut scope = self.scope;
loop {
match *scope {
- Scope::Root => break false,
+ Scope::Root { .. } => break false,
Scope::Body { .. } => break true,
@@ -1680,7 +1568,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(data) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
// The order here needs to match what we would get from `subst_supertrait`
let pred_bound_vars = bound_predicate.bound_vars();
let mut all_bound_vars = bound_vars.clone();
@@ -1731,7 +1619,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
scope = s;
}
- Scope::Root | Scope::Elision { .. } => break Region::Static,
+ Scope::Root { .. } | Scope::Elision { .. } => break Region::Static,
Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
@@ -1747,10 +1635,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
- debug!(
- node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id),
- span = ?self.tcx.sess.source_map().span_to_diagnostic_string(lifetime_ref.span)
- );
+ debug!(span = ?lifetime_ref.ident.span);
self.map.defs.insert(lifetime_ref.hir_id, def);
}
@@ -1780,7 +1665,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
let mut late_bound = FxIndexSet::default();
- let mut constrained_by_input = ConstrainedCollector::default();
+ let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
for arg_ty in decl.inputs {
constrained_by_input.visit_ty(arg_ty);
}
@@ -1833,12 +1718,65 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
debug!(?late_bound);
return Some(tcx.arena.alloc(late_bound));
- #[derive(Default)]
- struct ConstrainedCollector {
+ /// Visits a `ty::Ty` collecting information about what generic parameters are constrained.
+ ///
+ /// The visitor does not operate on `hir::Ty` so that it can be called on the rhs of a `type Alias<...> = ...;`
+ /// which may live in a separate crate so there would not be any hir available. Instead we use the `type_of`
+ /// query to obtain a `ty::Ty` which will be present even in cross crate scenarios. It also naturally
+ /// handles cycle detection as we go through the query system.
+ ///
+ /// This is necessary in the first place for the following case:
+ /// ```
+ /// type Alias<'a, T> = <T as Trait<'a>>::Assoc;
+ /// fn foo<'a>(_: Alias<'a, ()>) -> Alias<'a, ()> { ... }
+ /// ```
+ ///
+ /// If we conservatively considered `'a` unconstrained then we could break users who had written code before
+ /// we started correctly handling aliases. If we considered `'a` constrained then it would become late bound
+ /// causing an error during astconv as the `'a` is not constrained by the input type `<() as Trait<'a>>::Assoc`
+ /// but appears in the output type `<() as Trait<'a>>::Assoc`.
+ ///
+ /// We must therefore "look into" the `Alias` to see whether we should consider `'a` constrained or not.
+ ///
+ /// See #100508 #85533 #47511 for additional context
+ struct ConstrainedCollectorPostAstConv {
+ arg_is_constrained: Box<[bool]>,
+ }
+
+ use std::ops::ControlFlow;
+ use ty::Ty;
+ impl<'tcx> TypeVisitor<'tcx> for ConstrainedCollectorPostAstConv {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
+ match t.kind() {
+ ty::Param(param_ty) => {
+ self.arg_is_constrained[param_ty.index as usize] = true;
+ }
+ ty::Projection(_) => return ControlFlow::Continue(()),
+ _ => (),
+ }
+ t.super_visit_with(self)
+ }
+
+ fn visit_const(&mut self, _: ty::Const<'tcx>) -> ControlFlow<!> {
+ ControlFlow::Continue(())
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<!> {
+ debug!("r={:?}", r.kind());
+ if let ty::RegionKind::ReEarlyBound(region) = r.kind() {
+ self.arg_is_constrained[region.index as usize] = true;
+ }
+
+ ControlFlow::Continue(())
+ }
+ }
+
+ struct ConstrainedCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
regions: FxHashSet<LocalDefId>,
}
- impl<'v> Visitor<'v> for ConstrainedCollector {
+ impl<'v> Visitor<'v> for ConstrainedCollector<'_> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
match ty.kind {
hir::TyKind::Path(
@@ -1849,6 +1787,47 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
// (defined above)
}
+ hir::TyKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
+ )) => {
+ // See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider
+ // substs to be unconstrained.
+ let generics = self.tcx.generics_of(alias_def);
+ let mut walker = ConstrainedCollectorPostAstConv {
+ arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(),
+ };
+ walker.visit_ty(self.tcx.type_of(alias_def));
+
+ match segments.last() {
+ Some(hir::PathSegment { args: Some(args), .. }) => {
+ let tcx = self.tcx;
+ for constrained_arg in
+ args.args.iter().enumerate().flat_map(|(n, arg)| {
+ match walker.arg_is_constrained.get(n) {
+ Some(true) => Some(arg),
+ Some(false) => None,
+ None => {
+ tcx.sess.delay_span_bug(
+ *span,
+ format!(
+ "Incorrect generic arg count for alias {:?}",
+ alias_def
+ ),
+ );
+ None
+ }
+ }
+ })
+ {
+ self.visit_generic_arg(constrained_arg);
+ }
+ }
+ Some(_) => (),
+ None => bug!("Path with no segments or self type"),
+ }
+ }
+
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
// consider only the lifetimes on the final
// segment; I am not sure it's even currently
@@ -1867,7 +1846,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
}
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
- if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
+ if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
self.regions.insert(def_id);
}
}
@@ -1880,7 +1859,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
impl<'v> Visitor<'v> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
- if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
+ if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
self.regions.insert(def_id);
}
}
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 2e84e1d01..45e241f4e 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -84,60 +84,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
Node::ImplItem(item) => item.generics,
- Node::Item(item) => {
- match item.kind {
- ItemKind::Impl(ref impl_) => {
- if impl_.defaultness.is_default() {
- is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
- }
- &impl_.generics
- }
- ItemKind::Fn(.., ref generics, _)
- | ItemKind::TyAlias(_, ref generics)
- | ItemKind::Enum(_, ref generics)
- | ItemKind::Struct(_, ref generics)
- | ItemKind::Union(_, ref generics) => *generics,
-
- ItemKind::Trait(_, _, ref generics, ..) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
+ Node::Item(item) => match item.kind {
+ ItemKind::Impl(ref impl_) => {
+ if impl_.defaultness.is_default() {
+ is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
}
- ItemKind::TraitAlias(ref generics, _) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
- }
- ItemKind::OpaqueTy(OpaqueTy {
- origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
- ..
- }) => {
- // return-position impl trait
- //
- // We don't inherit predicates from the parent here:
- // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
- // then the return type is `f::<'static, T>::{{opaque}}`.
- //
- // If we inherited the predicates of `f` then we would
- // require that `T: 'static` to show that the return
- // type is well-formed.
- //
- // The only way to have something with this opaque type
- // is from the return type of the containing function,
- // which will ensure that the function's predicates
- // hold.
- return ty::GenericPredicates { parent: None, predicates: &[] };
- }
- ItemKind::OpaqueTy(OpaqueTy {
- ref generics,
- origin: hir::OpaqueTyOrigin::TyAlias,
- ..
- }) => {
- // type-alias impl trait
- generics
- }
-
- _ => NO_GENERICS,
+ &impl_.generics
}
- }
+ ItemKind::Fn(.., ref generics, _)
+ | ItemKind::TyAlias(_, ref generics)
+ | ItemKind::Enum(_, ref generics)
+ | ItemKind::Struct(_, ref generics)
+ | ItemKind::Union(_, ref generics) => *generics,
+
+ ItemKind::Trait(_, _, ref generics, ..) => {
+ is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+ *generics
+ }
+ ItemKind::TraitAlias(ref generics, _) => {
+ is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+ *generics
+ }
+ ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) => generics,
+ _ => NO_GENERICS,
+ },
Node::ForeignItem(item) => match item.kind {
ForeignItemKind::Static(..) => NO_GENERICS,
@@ -181,6 +151,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
trace!(?predicates);
trace!(?ast_generics);
+ trace!(?generics);
// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`).
@@ -199,7 +170,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
&icx,
&mut bounds,
&[],
- Some((param.hir_id, ast_generics.predicates)),
+ Some((param.def_id, ast_generics.predicates)),
param.span,
);
trace!(?bounds);
@@ -258,12 +229,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
predicates.extend(region_pred.bounds.iter().map(|bound| {
let (r2, span) = match bound {
hir::GenericBound::Outlives(lt) => {
- (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
+ (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.ident.span)
}
_ => bug!(),
};
- let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
- ty::OutlivesPredicate(r1, r2),
+ let pred = ty::Binder::dummy(ty::PredicateKind::Clause(
+ ty::Clause::RegionOutlives(ty::OutlivesPredicate(r1, r2)),
))
.to_predicate(icx.tcx);
@@ -299,6 +270,52 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
);
}
+ // Opaque types duplicate some of their generic parameters.
+ // We create bi-directional Outlives predicates between the original
+ // and the duplicated parameter, to ensure that they do not get out of sync.
+ if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
+ let opaque_ty_id = tcx.hir().get_parent_node(hir_id);
+ let opaque_ty_node = tcx.hir().get(opaque_ty_id);
+ let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
+ bug!("unexpected {opaque_ty_node:?}")
+ };
+ debug!(?lifetimes);
+ for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) {
+ let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
+ let orig_region = <dyn AstConv<'_>>::ast_region_to_region(&icx, &arg, None);
+ if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
+ // Only early-bound regions can point to the original generic parameter.
+ continue;
+ }
+
+ let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue };
+ let dup_def = tcx.hir().local_def_id(duplicate.hir_id).to_def_id();
+
+ let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() };
+
+ let dup_region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: dup_def,
+ index: dup_index,
+ name: duplicate.name.ident().name,
+ }));
+ predicates.push((
+ ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
+ ty::OutlivesPredicate(orig_region, dup_region),
+ )))
+ .to_predicate(icx.tcx),
+ duplicate.span,
+ ));
+ predicates.push((
+ ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
+ ty::OutlivesPredicate(dup_region, orig_region),
+ )))
+ .to_predicate(icx.tcx),
+ duplicate.span,
+ ));
+ }
+ debug!(?predicates);
+ }
+
ty::GenericPredicates {
parent: generics.parent,
predicates: tcx.arena.alloc_from_iter(predicates),
@@ -316,10 +333,9 @@ fn const_evaluatable_predicates_of<'tcx>(
impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
- let def_id = self.tcx.hir().local_def_id(c.hir_id);
- let ct = ty::Const::from_anon_const(self.tcx, def_id);
+ let ct = ty::Const::from_anon_const(self.tcx, c.def_id);
if let ty::ConstKind::Unevaluated(_) = ct.kind() {
- let span = self.tcx.hir().span(c.hir_id);
+ let span = self.tcx.def_span(c.def_id);
self.preds.insert((
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
.to_predicate(self.tcx),
@@ -408,11 +424,13 @@ pub(super) fn explicit_predicates_of<'tcx>(
.iter()
.copied()
.filter(|(pred, _)| match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
- ty::PredicateKind::Projection(proj) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => !is_assoc_item_ty(tr.self_ty()),
+ ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => {
!is_assoc_item_ty(proj.projection_ty.self_ty())
}
- ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => {
+ !is_assoc_item_ty(outlives.0)
+ }
_ => true,
})
.collect();
@@ -427,7 +445,9 @@ pub(super) fn explicit_predicates_of<'tcx>(
} else {
if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
+ let parent_def_id = tcx.hir().get_parent_item(hir_id);
+
+ if tcx.hir().opt_const_param_default_param_def_id(hir_id).is_some() {
// In `generics_of` we set the generics' parent to be our parent's parent which means that
// we lose out on the predicates of our actual parent if we dont return those predicates here.
// (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
@@ -439,8 +459,33 @@ pub(super) fn explicit_predicates_of<'tcx>(
// parent of generics returned by `generics_of`
//
// In the above code we want the anon const to have predicates in its param env for `T: Trait`
- let item_def_id = tcx.hir().get_parent_item(hir_id);
- // In the above code example we would be calling `explicit_predicates_of(Foo)` here
+ // and we would be calling `explicit_predicates_of(Foo)` here
+ return tcx.explicit_predicates_of(parent_def_id);
+ }
+
+ let parent_def_kind = tcx.def_kind(parent_def_id);
+ if matches!(parent_def_kind, DefKind::OpaqueTy) {
+ // In `instantiate_identity` we inherit the predicates of our parent.
+ // However, opaque types do not have a parent (see `gather_explicit_predicates_of`), which means
+ // that we lose out on the predicates of our actual parent if we dont return those predicates here.
+ //
+ //
+ // fn foo<T: Trait>() -> impl Iterator<Output = Another<{ <T as Trait>::ASSOC }> > { todo!() }
+ // ^^^^^^^^^^^^^^^^^^^ the def id we are calling
+ // explicit_predicates_of on
+ //
+ // In the above code we want the anon const to have predicates in its param env for `T: Trait`.
+ // However, the anon const cannot inherit predicates from its parent since it's opaque.
+ //
+ // To fix this, we call `explicit_predicates_of` directly on `foo`, the parent's parent.
+
+ // In the above example this is `foo::{opaque#0}` or `impl Iterator`
+ let parent_hir_id = tcx.hir().local_def_id_to_hir_id(parent_def_id.def_id);
+
+ // In the above example this is the function `foo`
+ let item_def_id = tcx.hir().get_parent_item(parent_hir_id);
+
+ // In the above code example we would be calling `explicit_predicates_of(foo)` here
return tcx.explicit_predicates_of(item_def_id);
}
}
@@ -504,7 +549,7 @@ pub(super) fn super_predicates_that_define_assoc_type(
let is_trait_alias = tcx.is_trait_alias(trait_def_id);
let superbounds2 = icx.type_parameter_bounds_in_generics(
generics,
- item.hir_id(),
+ item.owner_id.def_id,
self_param_ty,
OnlySelfBounds(!is_trait_alias),
assoc_name,
@@ -521,7 +566,9 @@ pub(super) fn super_predicates_that_define_assoc_type(
// which will, in turn, reach indirect supertraits.
for &(pred, span) in superbounds {
debug!("superbound: {:?}", pred);
- if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) =
+ pred.kind().skip_binder()
+ {
tcx.at(span).super_predicates_of(bound.def_id());
}
}
@@ -614,14 +661,14 @@ pub(super) fn type_param_predicates(
let extra_predicates = extend.into_iter().chain(
icx.type_parameter_bounds_in_generics(
ast_generics,
- param_id,
+ def_id,
ty,
OnlySelfBounds(true),
Some(assoc_name),
)
.into_iter()
.filter(|(predicate, _)| match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
+ ty::PredicateKind::Clause(ty::Clause::Trait(data)) => data.self_ty().is_param(index),
_ => false,
}),
);
@@ -639,13 +686,11 @@ impl<'tcx> ItemCtxt<'tcx> {
fn type_parameter_bounds_in_generics(
&self,
ast_generics: &'tcx hir::Generics<'tcx>,
- param_id: hir::HirId,
+ param_def_id: LocalDefId,
ty: Ty<'tcx>,
only_self_bounds: OnlySelfBounds,
assoc_name: Option<Ident>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
- let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
- trace!(?param_def_id);
ast_generics
.predicates
.iter()
@@ -654,7 +699,7 @@ impl<'tcx> ItemCtxt<'tcx> {
_ => None,
})
.flat_map(|bp| {
- let bt = if bp.is_param_bound(param_def_id) {
+ let bt = if bp.is_param_bound(param_def_id.to_def_id()) {
Some(ty)
} else if !only_self_bounds.0 {
Some(self.to_ty(bp.bounded_ty))
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index c29a645eb..9bd1715ce 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -514,10 +514,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
Node::GenericParam(&GenericParam {
- hir_id: param_hir_id,
+ def_id: param_def_id,
kind: GenericParamKind::Const { default: Some(ct), .. },
..
- }) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)),
+ }) if ct.hir_id == hir_id => tcx.type_of(param_def_id),
x => tcx.ty_error_with_message(
DUMMY_SP,
@@ -636,9 +636,8 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
self.tcx.hir()
}
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
- if let hir::ExprKind::Closure { .. } = ex.kind {
- let def_id = self.tcx.hir().local_def_id(ex.hir_id);
- self.check(def_id);
+ if let hir::ExprKind::Closure(closure) = ex.kind {
+ self.check(closure.def_id);
}
intravisit::walk_expr(self, ex);
}
@@ -698,7 +697,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
}
let Some(hidden) = locator.found else {
- tcx.sess.emit_err(UnconstrainedOpaqueType {
+ let reported = tcx.sess.emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id),
name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
what: match tcx.hir().get(scope) {
@@ -708,7 +707,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
_ => "item",
},
});
- return tcx.ty_error();
+ return tcx.ty_error_with_guaranteed(reported);
};
// Only check against typeck if we didn't already error
@@ -771,9 +770,8 @@ fn find_opaque_ty_constraints_for_rpit(
self.tcx.hir()
}
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
- if let hir::ExprKind::Closure { .. } = ex.kind {
- let def_id = self.tcx.hir().local_def_id(ex.hir_id);
- self.check(def_id);
+ if let hir::ExprKind::Closure(closure) = ex.kind {
+ self.check(closure.def_id);
}
intravisit::walk_expr(self, ex);
}