summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/collect
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/collect')
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs65
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs (renamed from compiler/rustc_hir_analysis/src/collect/lifetimes.rs)719
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs115
5 files changed, 562 insertions, 355 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 014ee9fcc..127d4fa90 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -1,4 +1,4 @@
-use crate::middle::resolve_lifetime as rl;
+use crate::middle::resolve_bound_vars as rbv;
use hir::{
intravisit::{self, Visitor},
GenericParamKind, HirId, Node,
@@ -394,10 +394,16 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
return;
}
- match self.tcx.named_region(lt.hir_id) {
- 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 => {
+ match self.tcx.named_bound_var(lt.hir_id) {
+ Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {}
+ Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
+ if debruijn < self.outer_index => {}
+ Some(
+ rbv::ResolvedArg::LateBound(..)
+ | rbv::ResolvedArg::Free(..)
+ | rbv::ResolvedArg::Error(_),
+ )
+ | None => {
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 8d479f1c3..9cf3ff65a 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -103,7 +103,7 @@ pub(super) fn item_bounds(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
- let bounds = tcx.mk_predicates(
+ let bounds = tcx.mk_predicates_from_iter(
util::elaborate_predicates(
tcx,
tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 46b277d98..2badd66e3 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -9,8 +9,8 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{GenericPredicates, ToPredicate};
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, DUMMY_SP};
@@ -151,7 +151,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
trace!(?generics);
// Collect the predicates that were written inline by the user on each
- // type parameter (e.g., `<T: Foo>`).
+ // type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates
+ // for each const parameter.
for param in ast_generics.params {
match param.kind {
// We already dealt with early bound lifetimes above.
@@ -175,7 +176,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
trace!(?predicates);
}
GenericParamKind::Const { .. } => {
- // Bounds on const parameters are currently not possible.
+ let name = param.name.ident().name;
+ let param_const = ty::ParamConst::new(index, name);
+
+ let ct_ty = tcx.type_of(param.def_id.to_def_id()).subst_identity();
+
+ let ct = tcx.mk_const(param_const, ct_ty);
+
+ let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
+ ty::Clause::ConstArgHasType(ct, ct_ty),
+ ))
+ .to_predicate(tcx);
+ predicates.insert((predicate, param.span));
+
index += 1;
}
}
@@ -251,7 +264,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
// in trait checking. See `setup_constraining_predicates`
// for details.
if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
- let self_ty = tcx.type_of(def_id);
+ let self_ty = tcx.type_of(def_id).subst_identity();
let trait_ref = tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::subst_identity);
cgp::setup_constraining_predicates(
tcx,
@@ -280,15 +293,15 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
}
let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue };
- let dup_def = tcx.hir().local_def_id(duplicate.hir_id).to_def_id();
+ let dup_def = duplicate.def_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 {
+ let dup_region = tcx.mk_re_early_bound(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),
@@ -439,7 +452,9 @@ pub(super) fn explicit_predicates_of<'tcx>(
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
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() {
+ if let Some(defaulted_param_def_id) =
+ tcx.hir().opt_const_param_default_param_def_id(hir_id)
+ {
// 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)
@@ -452,7 +467,39 @@ pub(super) fn explicit_predicates_of<'tcx>(
//
// In the above code we want the anon const to have predicates in its param env for `T: Trait`
// and we would be calling `explicit_predicates_of(Foo)` here
- return tcx.explicit_predicates_of(parent_def_id);
+ let parent_preds = tcx.explicit_predicates_of(parent_def_id);
+
+ // If we dont filter out `ConstArgHasType` predicates then every single defaulted const parameter
+ // will ICE because of #106994. FIXME(generic_const_exprs): remove this when a more general solution
+ // to #106994 is implemented.
+ let filtered_predicates = parent_preds
+ .predicates
+ .into_iter()
+ .filter(|(pred, _)| {
+ if let ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, _)) =
+ pred.kind().skip_binder()
+ {
+ match ct.kind() {
+ ty::ConstKind::Param(param_const) => {
+ let defaulted_param_idx = tcx
+ .generics_of(parent_def_id)
+ .param_def_id_to_index[&defaulted_param_def_id.to_def_id()];
+ param_const.index < defaulted_param_idx
+ }
+ _ => bug!(
+ "`ConstArgHasType` in `predicates_of`\
+ that isn't a `Param` const"
+ ),
+ }
+ } else {
+ true
+ }
+ })
+ .cloned();
+ return GenericPredicates {
+ parent: parent_preds.parent,
+ predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
+ };
}
let parent_def_kind = tcx.def_kind(parent_def_id);
diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 359122d4e..65a9052a6 100644
--- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -16,67 +16,72 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
use rustc_middle::bug;
use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::resolve_lifetime::*;
+use rustc_middle::middle::resolve_bound_vars::*;
use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
+use rustc_session::lint;
use rustc_span::def_id::DefId;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use std::fmt;
+use crate::errors;
+
trait RegionExt {
- fn early(param: &GenericParam<'_>) -> (LocalDefId, Region);
+ fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
- fn late(index: u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
+ fn late(index: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
fn id(&self) -> Option<DefId>;
- fn shifted(self, amount: u32) -> Region;
+ fn shifted(self, amount: u32) -> ResolvedArg;
}
-impl RegionExt for Region {
- 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()))
+impl RegionExt for ResolvedArg {
+ fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
+ debug!("ResolvedArg::early: def_id={:?}", param.def_id);
+ (param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id()))
}
- fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
+ fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
let depth = ty::INNERMOST;
debug!(
- "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
+ "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
idx, param, depth, param.def_id,
);
- (param.def_id, Region::LateBound(depth, idx, param.def_id.to_def_id()))
+ (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id.to_def_id()))
}
fn id(&self) -> Option<DefId> {
match *self {
- Region::Static => None,
+ ResolvedArg::StaticLifetime | ResolvedArg::Error(_) => None,
- Region::EarlyBound(id) | Region::LateBound(_, _, id) | Region::Free(_, id) => Some(id),
+ ResolvedArg::EarlyBound(id)
+ | ResolvedArg::LateBound(_, _, id)
+ | ResolvedArg::Free(_, id) => Some(id),
}
}
- fn shifted(self, amount: u32) -> Region {
+ fn shifted(self, amount: u32) -> ResolvedArg {
match self {
- Region::LateBound(debruijn, idx, id) => {
- Region::LateBound(debruijn.shifted_in(amount), idx, id)
+ ResolvedArg::LateBound(debruijn, idx, id) => {
+ ResolvedArg::LateBound(debruijn.shifted_in(amount), idx, id)
}
_ => self,
}
}
}
-/// Maps the id of each lifetime reference to the lifetime decl
+/// Maps the id of each bound variable reference to the variable decl
/// that it corresponds to.
///
-/// FIXME. This struct gets converted to a `ResolveLifetimes` for
+/// FIXME. This struct gets converted to a `ResolveBoundVars` for
/// actual use. It has the same data, but indexed by `LocalDefId`. This
/// is silly.
#[derive(Debug, Default)]
-struct NamedRegionMap {
- // maps from every use of a named (not anonymous) lifetime to a
- // `Region` describing how that region is bound
- defs: HirIdMap<Region>,
+struct NamedVarMap {
+ // maps from every use of a named (not anonymous) bound var to a
+ // `ResolvedArg` describing how that variable is bound
+ defs: HirIdMap<ResolvedArg>,
// Maps relevant hir items to the bound vars on them. These include:
// - function defs
@@ -87,9 +92,9 @@ struct NamedRegionMap {
late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
}
-struct LifetimeContext<'a, 'tcx> {
+struct BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
- map: &'a mut NamedRegionMap,
+ map: &'a mut NamedVarMap,
scope: ScopeRef<'a>,
}
@@ -102,7 +107,7 @@ enum Scope<'a> {
Binder {
/// We use an IndexMap here because we want these lifetimes in order
/// for diagnostics.
- lifetimes: FxIndexMap<LocalDefId, Region>,
+ bound_vars: FxIndexMap<LocalDefId, ResolvedArg>,
scope_type: BinderScopeType,
@@ -141,7 +146,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 {
- lifetime: Option<Region>,
+ lifetime: Option<ResolvedArg>,
s: ScopeRef<'a>,
},
@@ -150,7 +155,7 @@ enum Scope<'a> {
/// lifetimes encountered when identifying the trait that an associated type
/// is declared on.
Supertrait {
- lifetimes: Vec<ty::BoundVariableKind>,
+ bound_vars: Vec<ty::BoundVariableKind>,
s: ScopeRef<'a>,
},
@@ -158,6 +163,15 @@ enum Scope<'a> {
s: ScopeRef<'a>,
},
+ /// Disallows capturing non-lifetime binders from parent scopes.
+ ///
+ /// This is necessary for something like `for<T> [(); { /* references T */ }]:`,
+ /// since we don't do something more correct like replacing any captured
+ /// late-bound vars with early-bound params in the const's own generics.
+ AnonConstBoundary {
+ s: ScopeRef<'a>,
+ },
+
Root {
opt_parent_item: Option<LocalDefId>,
},
@@ -185,9 +199,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, scope_type, hir_id, where_bound_origin, s: _ } => f
+ Scope::Binder { bound_vars, scope_type, hir_id, where_bound_origin, s: _ } => f
.debug_struct("Binder")
- .field("lifetimes", lifetimes)
+ .field("bound_vars", bound_vars)
.field("scope_type", scope_type)
.field("hir_id", hir_id)
.field("where_bound_origin", where_bound_origin)
@@ -202,12 +216,13 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
.field("lifetime", lifetime)
.field("s", &"..")
.finish(),
- Scope::Supertrait { lifetimes, s: _ } => f
+ Scope::Supertrait { bound_vars, s: _ } => f
.debug_struct("Supertrait")
- .field("lifetimes", lifetimes)
+ .field("bound_vars", bound_vars)
.field("s", &"..")
.finish(),
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
+ Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(),
Scope::Root { opt_parent_item } => {
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
}
@@ -219,27 +234,27 @@ type ScopeRef<'a> = &'a Scope<'a>;
pub(crate) fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
- resolve_lifetimes,
+ resolve_bound_vars,
- named_region_map: |tcx, id| tcx.resolve_lifetimes(id).defs.get(&id),
+ named_variable_map: |tcx, id| tcx.resolve_bound_vars(id).defs.get(&id),
is_late_bound_map,
object_lifetime_default,
- late_bound_vars_map: |tcx, id| tcx.resolve_lifetimes(id).late_bound_vars.get(&id),
+ late_bound_vars_map: |tcx, id| tcx.resolve_bound_vars(id).late_bound_vars.get(&id),
..*providers
};
}
-/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
+/// Computes the `ResolveBoundVars` 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.
+/// `named_variable_map`, `is_late_bound_map`, etc.
#[instrument(level = "debug", skip(tcx))]
-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 {
+fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars {
+ let mut named_variable_map =
+ NamedVarMap { defs: Default::default(), late_bound_vars: Default::default() };
+ let mut visitor = BoundVarContext {
tcx,
- map: &mut named_region_map,
+ map: &mut named_variable_map,
scope: &Scope::Root { opt_parent_item: None },
};
match tcx.hir().owner(local_def_id) {
@@ -260,13 +275,13 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveLife
hir::OwnerNode::Crate(_) => {}
}
- let mut rl = ResolveLifetimes::default();
+ let mut rl = ResolveBoundVars::default();
- for (hir_id, v) in named_region_map.defs {
+ for (hir_id, v) in named_variable_map.defs {
let map = rl.defs.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v);
}
- for (hir_id, v) in named_region_map.late_bound_vars {
+ for (hir_id, v) in named_variable_map.late_bound_vars {
let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v);
}
@@ -276,39 +291,53 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveLife
rl
}
-fn late_region_as_bound_region(tcx: TyCtxt<'_>, region: &Region) -> ty::BoundVariableKind {
- match region {
- Region::LateBound(_, _, def_id) => {
+fn late_arg_as_bound_arg<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ arg: &ResolvedArg,
+ param: &GenericParam<'tcx>,
+) -> ty::BoundVariableKind {
+ match arg {
+ ResolvedArg::LateBound(_, _, def_id) => {
let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local()));
- ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name))
+ match param.kind {
+ GenericParamKind::Lifetime { .. } => {
+ ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name))
+ }
+ GenericParamKind::Type { .. } => {
+ ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(*def_id, name))
+ }
+ GenericParamKind::Const { .. } => ty::BoundVariableKind::Const,
+ }
}
- _ => bug!("{:?} is not a late region", region),
+ _ => bug!("{:?} is not a late argument", arg),
}
}
-impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
+impl<'a, 'tcx> BoundVarContext<'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) -> (Vec<ty::BoundVariableKind>, BinderScopeType) {
let mut scope = self.scope;
- let mut supertrait_lifetimes = vec![];
+ let mut supertrait_bound_vars = vec![];
loop {
match scope {
Scope::Body { .. } | Scope::Root { .. } => {
break (vec![], BinderScopeType::Normal);
}
- Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => {
+ Scope::Elision { s, .. }
+ | Scope::ObjectLifetimeDefault { s, .. }
+ | Scope::AnonConstBoundary { s } => {
scope = s;
}
- Scope::Supertrait { s, lifetimes } => {
- supertrait_lifetimes = lifetimes.clone();
+ Scope::Supertrait { s, bound_vars } => {
+ supertrait_bound_vars = bound_vars.clone();
scope = s;
}
Scope::TraitRefBoundary { .. } => {
// We should only see super trait lifetimes if there is a `Binder` above
- assert!(supertrait_lifetimes.is_empty());
+ assert!(supertrait_bound_vars.is_empty());
break (vec![], BinderScopeType::Normal);
}
@@ -316,14 +345,64 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// Nested poly trait refs have the binders concatenated
let mut full_binders =
self.map.late_bound_vars.entry(*hir_id).or_default().clone();
- full_binders.extend(supertrait_lifetimes.into_iter());
+ full_binders.extend(supertrait_bound_vars.into_iter());
break (full_binders, BinderScopeType::Concatenating);
}
}
}
}
+
+ fn visit_poly_trait_ref_inner(
+ &mut self,
+ trait_ref: &'tcx hir::PolyTraitRef<'tcx>,
+ non_lifetime_binder_allowed: NonLifetimeBinderAllowed,
+ ) {
+ debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
+
+ let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
+
+ let initial_bound_vars = binders.len() as u32;
+ let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default();
+ let binders_iter =
+ trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| {
+ let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
+ let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
+ bound_vars.insert(pair.0, pair.1);
+ r
+ });
+ binders.extend(binders_iter);
+
+ if let NonLifetimeBinderAllowed::Deny(where_) = non_lifetime_binder_allowed {
+ deny_non_region_late_bound(self.tcx, &mut bound_vars, where_);
+ }
+
+ debug!(?binders);
+ self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders);
+
+ // 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 {
+ hir_id: trait_ref.trait_ref.hir_ref_id,
+ bound_vars,
+ s: self.scope,
+ scope_type,
+ where_bound_origin: None,
+ };
+ self.with(scope, |this| {
+ walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
+ this.visit_trait_ref(&trait_ref.trait_ref);
+ });
+ }
+}
+
+enum NonLifetimeBinderAllowed {
+ Deny(&'static str),
+ Allow,
}
-impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
+
+impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
type NestedFilter = nested_filter::OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map {
@@ -386,22 +465,23 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
}
- let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
+ let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
bound_generic_params
.iter()
- .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, param);
- let r = late_region_as_bound_region(self.tcx, &pair.1);
+ let pair = ResolvedArg::late(late_bound_idx as u32, param);
+ let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
(pair, r)
})
.unzip();
+ deny_non_region_late_bound(self.tcx, &mut bound_vars, "closures");
+
self.record_late_bound_vars(e.hir_id, binders);
let scope = Scope::Binder {
hir_id: e.hir_id,
- lifetimes,
+ bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
@@ -461,7 +541,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// conservatively add all resolved lifetimes. Otherwise we run into problems in
// cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
let parent_item = self.tcx.hir().get_parent_item(item.hir_id());
- let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(parent_item);
+ let resolved_lifetimes: &ResolveBoundVars =
+ self.tcx.resolve_bound_vars(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)| {
@@ -478,35 +559,33 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
}
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- origin: hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_),
+ origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent),
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();
+ let mut bound_vars = 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);
- }
- GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
- }
+ let (def_id, reg) = ResolvedArg::early(&param);
+ bound_vars.insert(def_id, reg);
}
- let scope = Scope::Binder {
- hir_id: item.hir_id(),
- lifetimes,
- s: self.scope,
- scope_type: BinderScopeType::Normal,
- where_bound_origin: None,
- };
+ let scope = Scope::Root { opt_parent_item: Some(parent) };
self.with(scope, |this| {
- let scope = Scope::TraitRefBoundary { s: this.scope };
- this.with(scope, |this| intravisit::walk_item(this, item))
- });
+ let scope = Scope::Binder {
+ hir_id: item.hir_id(),
+ bound_vars,
+ s: this.scope,
+ scope_type: BinderScopeType::Normal,
+ where_bound_origin: None,
+ };
+ this.with(scope, |this| {
+ let scope = Scope::TraitRefBoundary { s: this.scope };
+ this.with(scope, |this| intravisit::walk_item(this, item))
+ });
+ })
}
hir::ItemKind::TyAlias(_, generics)
| hir::ItemKind::Enum(_, generics)
@@ -516,18 +595,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
| hir::ItemKind::TraitAlias(generics, ..)
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
// These kinds of items have only early-bound lifetime parameters.
- let lifetimes = generics
- .params
- .iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
- GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
- })
- .collect();
+ let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
self.record_late_bound_vars(item.hir_id(), vec![]);
let scope = Scope::Binder {
hir_id: item.hir_id(),
- lifetimes,
+ bound_vars,
scope_type: BinderScopeType::Normal,
s: self.scope,
where_bound_origin: None,
@@ -562,21 +634,23 @@ 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(c) => {
- let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
+ let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c
.generic_params
.iter()
- .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, param);
- let r = late_region_as_bound_region(self.tcx, &pair.1);
+ let pair = ResolvedArg::late(late_bound_idx as u32, param);
+ let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
(pair, r)
})
.unzip();
+
+ deny_non_region_late_bound(self.tcx, &mut bound_vars, "function pointer types");
+
self.record_late_bound_vars(ty.hir_id, binders);
let scope = Scope::Binder {
hir_id: ty.hir_id,
- lifetimes,
+ bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
@@ -592,7 +666,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| {
for bound in bounds {
- this.visit_poly_trait_ref(bound);
+ this.visit_poly_trait_ref_inner(
+ bound,
+ NonLifetimeBinderAllowed::Deny("trait object types"),
+ );
}
});
match lifetime.res {
@@ -674,7 +751,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// well-supported at the moment, so this doesn't work.
// In the future, this should be fixed and this error should be removed.
let def = self.map.defs.get(&lifetime.hir_id).cloned();
- let Some(Region::LateBound(_, _, def_id)) = def else {
+ let Some(ResolvedArg::LateBound(_, _, def_id)) = def else {
continue
};
let Some(def_id) = def_id.as_local() else {
@@ -722,18 +799,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
Type(bounds, ty) => {
let generics = &trait_item.generics;
- let lifetimes = generics
- .params
- .iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
- GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
- })
- .collect();
+ let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
self.record_late_bound_vars(trait_item.hir_id(), vec![]);
let scope = Scope::Binder {
hir_id: trait_item.hir_id(),
- lifetimes,
+ bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
@@ -768,18 +838,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}),
Type(ty) => {
let generics = &impl_item.generics;
- let lifetimes: FxIndexMap<LocalDefId, Region> = generics
- .params
- .iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
- GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None,
- })
- .collect();
+ let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> =
+ generics.params.iter().map(ResolvedArg::early).collect();
self.record_late_bound_vars(impl_item.hir_id(), vec![]);
let scope = Scope::Binder {
hir_id: impl_item.hir_id(),
- lifetimes,
+ bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
@@ -803,7 +867,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.res {
- hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
+ hir::LifetimeName::Static => {
+ self.insert_lifetime(lifetime_ref, ResolvedArg::StaticLifetime)
+ }
hir::LifetimeName::Param(param_def_id) => {
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
}
@@ -814,13 +880,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
}
- fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
+ fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: hir::HirId) {
for (i, segment) in path.segments.iter().enumerate() {
let depth = path.segments.len() - i - 1;
if let Some(args) = segment.args {
self.visit_segment_args(path.res, depth, args);
}
}
+ if let Res::Def(DefKind::TyParam | DefKind::ConstParam, param_def_id) = path.res {
+ self.resolve_type_ref(param_def_id.expect_local(), hir_id);
+ }
}
fn visit_fn(
@@ -829,7 +898,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fd: &'tcx hir::FnDecl<'tcx>,
body_id: hir::BodyId,
_: Span,
- _: hir::HirId,
+ _: LocalDefId,
) {
let output = match fd.output {
hir::FnRetTy::DefaultReturn(_) => None,
@@ -869,24 +938,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
origin,
..
}) => {
- let lifetimes: FxIndexMap<LocalDefId, Region> =
+ let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
bound_generic_params
.iter()
- .filter(|param| {
- matches!(param.kind, GenericParamKind::Lifetime { .. })
- })
.enumerate()
.map(|(late_bound_idx, param)| {
- Region::late(late_bound_idx as u32, param)
- })
- .collect();
- let binders: Vec<_> =
- lifetimes
- .iter()
- .map(|(_, region)| {
- late_region_as_bound_region(this.tcx, region)
+ let pair = ResolvedArg::late(late_bound_idx as u32, param);
+ let r = late_arg_as_bound_arg(this.tcx, &pair.1, param);
+ (pair, r)
})
- .collect();
+ .unzip();
this.record_late_bound_vars(hir_id, binders.clone());
// 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
@@ -894,7 +955,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// being wrong.
let scope = Scope::Binder {
hir_id,
- lifetimes,
+ bound_vars,
s: this.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: Some(origin),
@@ -920,21 +981,23 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
if lt.res != hir::LifetimeName::Static {
continue;
}
- this.insert_lifetime(lt, Region::Static);
- this.tcx
- .sess
- .struct_span_warn(
- lifetime.ident.span,
- &format!(
- "unnecessary lifetime parameter `{}`",
+ this.insert_lifetime(lt, ResolvedArg::StaticLifetime);
+ this.tcx.struct_span_lint_hir(
+ lint::builtin::UNUSED_LIFETIMES,
+ lifetime.hir_id,
+ lifetime.ident.span,
+ format!(
+ "unnecessary lifetime parameter `{}`",
+ lifetime.ident
+ ),
+ |lint| {
+ let help = &format!(
+ "you can use the `'static` lifetime directly, in place of `{}`",
lifetime.ident,
- ),
- )
- .help(&format!(
- "you can use the `'static` lifetime directly, in place of `{}`",
- lifetime.ident,
- ))
- .emit();
+ );
+ lint.help(help)
+ },
+ );
}
}
}
@@ -964,7 +1027,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
self.record_late_bound_vars(*hir_id, binders);
let scope = Scope::Binder {
hir_id: *hir_id,
- lifetimes: FxIndexMap::default(),
+ bound_vars: FxIndexMap::default(),
s: self.scope,
scope_type,
where_bound_origin: None,
@@ -978,42 +1041,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) {
- debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
-
- let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
-
- let initial_bound_vars = binders.len() as u32;
- let mut lifetimes: FxIndexMap<LocalDefId, Region> = FxIndexMap::default();
- let binders_iter = trait_ref
- .bound_generic_params
- .iter()
- .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, param);
- let r = late_region_as_bound_region(self.tcx, &pair.1);
- lifetimes.insert(pair.0, pair.1);
- r
- });
- binders.extend(binders_iter);
-
- debug!(?binders);
- self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders);
+ self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow);
+ }
- // 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 {
- hir_id: trait_ref.trait_ref.hir_ref_id,
- lifetimes,
- s: self.scope,
- scope_type,
- where_bound_origin: None,
- };
- self.with(scope, |this| {
- walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
- this.visit_trait_ref(&trait_ref.trait_ref);
+ fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
+ self.with(Scope::AnonConstBoundary { s: self.scope }, |this| {
+ intravisit::walk_anon_const(this, c);
});
}
}
@@ -1021,55 +1054,63 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault {
debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam);
let param_def_id = param_def_id.expect_local();
- let parent_def_id = tcx.local_parent(param_def_id);
- let generics = tcx.hir().get_generics(parent_def_id).unwrap();
- let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id);
- let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap();
-
- // 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.
- match param.kind {
- GenericParamKind::Type { .. } => {
- let mut set = Set1::Empty;
-
- // Look for `type: ...` where clauses.
- for bound in generics.bounds_for_param(param_def_id) {
- // Ignore `for<'a> type: ...` as they can change what
- // lifetimes mean (although we could "just" handle it).
- if !bound.bound_generic_params.is_empty() {
- continue;
- }
+ let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(param_def_id) else {
+ bug!("expected GenericParam for object_lifetime_default");
+ };
+ match param.source {
+ hir::GenericParamSource::Generics => {
+ let parent_def_id = tcx.local_parent(param_def_id);
+ let generics = tcx.hir().get_generics(parent_def_id).unwrap();
+ let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id);
+ let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap();
+
+ // 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.
+ match param.kind {
+ GenericParamKind::Type { .. } => {
+ let mut set = Set1::Empty;
+
+ // Look for `type: ...` where clauses.
+ for bound in generics.bounds_for_param(param_def_id) {
+ // Ignore `for<'a> type: ...` as they can change what
+ // lifetimes mean (although we could "just" handle it).
+ if !bound.bound_generic_params.is_empty() {
+ continue;
+ }
- for bound in bound.bounds {
- if let hir::GenericBound::Outlives(lifetime) = bound {
- set.insert(lifetime.res);
+ for bound in bound.bounds {
+ if let hir::GenericBound::Outlives(lifetime) = bound {
+ set.insert(lifetime.res);
+ }
+ }
}
- }
- }
- match set {
- Set1::Empty => ObjectLifetimeDefault::Empty,
- Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
- Set1::One(hir::LifetimeName::Param(param_def_id)) => {
- ObjectLifetimeDefault::Param(param_def_id.to_def_id())
+ match set {
+ Set1::Empty => ObjectLifetimeDefault::Empty,
+ Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
+ Set1::One(hir::LifetimeName::Param(param_def_id)) => {
+ ObjectLifetimeDefault::Param(param_def_id.to_def_id())
+ }
+ _ => ObjectLifetimeDefault::Ambiguous,
+ }
+ }
+ _ => {
+ bug!("object_lifetime_default_raw must only be called on a type parameter")
}
- _ => ObjectLifetimeDefault::Ambiguous,
}
}
- _ => {
- bug!("object_lifetime_default_raw must only be called on a type parameter")
- }
+ hir::GenericParamSource::Binder => ObjectLifetimeDefault::Empty,
}
}
-impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
+impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
where
- F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
+ F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>),
{
- let LifetimeContext { tcx, map, .. } = self;
- let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope };
+ let BoundVarContext { tcx, map, .. } = self;
+ let mut this = BoundVarContext { tcx: *tcx, map, scope: &wrap_scope };
let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
{
let _enter = span.enter();
@@ -1110,23 +1151,25 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
generics: &'tcx hir::Generics<'tcx>,
walk: F,
) where
- F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
+ F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>),
{
let mut named_late_bound_vars = 0;
- let lifetimes: FxIndexMap<LocalDefId, Region> = generics
+ let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = generics
.params
.iter()
- .filter_map(|param| match param.kind {
+ .map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
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, param))
+ ResolvedArg::late(late_bound_idx, param)
} else {
- Some(Region::early(param))
+ ResolvedArg::early(param)
}
}
- GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
+ GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
+ ResolvedArg::early(param)
+ }
})
.collect();
@@ -1139,14 +1182,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
})
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, param);
- late_region_as_bound_region(self.tcx, &pair.1)
+ let pair = ResolvedArg::late(late_bound_idx as u32, param);
+ late_arg_as_bound_arg(self.tcx, &pair.1, param)
})
.collect();
self.record_late_bound_vars(hir_id, binders);
let scope = Scope::Binder {
hir_id,
- lifetimes,
+ bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
@@ -1177,15 +1220,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
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())
+ && parent_generics.param_def_id_to_index(self.tcx, region_def_id.to_def_id()).is_some()
{
- break Some(Region::EarlyBound(region_def_id.to_def_id()));
+ break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id()));
}
break None;
}
- Scope::Binder { ref lifetimes, scope_type, s, where_bound_origin, .. } => {
- if let Some(&def) = lifetimes.get(&region_def_id) {
+ Scope::Binder { ref bound_vars, scope_type, s, where_bound_origin, .. } => {
+ if let Some(&def) = bound_vars.get(&region_def_id) {
break Some(def.shifted(late_depth));
}
match scope_type {
@@ -1252,26 +1295,34 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
- | Scope::TraitRefBoundary { s, .. } => {
+ | Scope::TraitRefBoundary { s, .. }
+ | Scope::AnonConstBoundary { s } => {
scope = s;
}
}
};
if let Some(mut def) = result {
- if let Region::EarlyBound(..) = def {
+ if let ResolvedArg::EarlyBound(..) = def {
// Do not free early-bound regions, only late-bound ones.
} 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::Item(hir::Item { owner_id, kind: hir::ItemKind::Fn(..), .. })
| Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(..), ..
+ owner_id,
+ kind: hir::TraitItemKind::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());
+ | Node::ImplItem(hir::ImplItem {
+ owner_id,
+ kind: hir::ImplItemKind::Fn(..),
+ ..
+ }) => {
+ def = ResolvedArg::Free(owner_id.to_def_id(), def.id().unwrap());
+ }
+ Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) => {
+ def = ResolvedArg::Free(closure.def_id.to_def_id(), def.id().unwrap());
}
_ => {}
}
@@ -1310,7 +1361,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
- | Scope::TraitRefBoundary { s, .. } => {
+ | Scope::TraitRefBoundary { s, .. }
+ | Scope::AnonConstBoundary { s } => {
scope = s;
}
}
@@ -1322,6 +1374,87 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
);
}
+ fn resolve_type_ref(&mut self, param_def_id: LocalDefId, hir_id: hir::HirId) {
+ // Walk up the scope chain, tracking the number of fn scopes
+ // that we pass through, until we find a lifetime with the
+ // given name or we run out of scopes.
+ // search.
+ let mut late_depth = 0;
+ let mut scope = self.scope;
+ let mut crossed_anon_const = false;
+ let result = loop {
+ match *scope {
+ Scope::Body { s, .. } => {
+ scope = s;
+ }
+
+ 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(self.tcx, param_def_id.to_def_id()).is_some()
+ {
+ break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id()));
+ }
+ break None;
+ }
+
+ Scope::Binder { ref bound_vars, scope_type, s, .. } => {
+ if let Some(&def) = bound_vars.get(&param_def_id) {
+ break Some(def.shifted(late_depth));
+ }
+ match scope_type {
+ BinderScopeType::Normal => late_depth += 1,
+ BinderScopeType::Concatenating => {}
+ }
+ scope = s;
+ }
+
+ Scope::Elision { s, .. }
+ | Scope::ObjectLifetimeDefault { s, .. }
+ | Scope::Supertrait { s, .. }
+ | Scope::TraitRefBoundary { s, .. } => {
+ scope = s;
+ }
+
+ Scope::AnonConstBoundary { s } => {
+ crossed_anon_const = true;
+ scope = s;
+ }
+ }
+ };
+
+ if let Some(def) = result {
+ if let ResolvedArg::LateBound(..) = def && crossed_anon_const {
+ let use_span = self.tcx.hir().span(hir_id);
+ let def_span = self.tcx.def_span(param_def_id);
+ match self.tcx.def_kind(param_def_id) {
+ DefKind::ConstParam => {
+ self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const {
+ use_span,
+ def_span,
+ });
+ }
+ DefKind::TyParam => {
+ self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type {
+ use_span,
+ def_span,
+ });
+ }
+ _ => unreachable!(),
+ }
+ return;
+ }
+
+ self.map.defs.insert(hir_id, def);
+ return;
+ }
+
+ self.tcx.sess.delay_span_bug(
+ self.tcx.hir().span(hir_id),
+ format!("could not resolve {param_def_id:?}"),
+ );
+ }
+
#[instrument(level = "debug", skip(self))]
fn visit_segment_args(
&mut self,
@@ -1390,7 +1523,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
- | Scope::TraitRefBoundary { s, .. } => {
+ | Scope::TraitRefBoundary { s, .. }
+ | Scope::AnonConstBoundary { s } => {
scope = s;
}
}
@@ -1408,10 +1542,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
if in_body {
None
} else {
- Some(Region::Static)
+ Some(ResolvedArg::StaticLifetime)
}
}
- ObjectLifetimeDefault::Static => Some(Region::Static),
+ ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime),
ObjectLifetimeDefault::Param(param_def_id) => {
// This index can be used with `generic_args` since `parent_count == 0`.
let index = generics.param_def_id_to_index[&param_def_id] as usize;
@@ -1500,18 +1634,19 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// 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) },
+ lifetime: if has_lifetime_parameter {
+ None
+ } else {
+ Some(ResolvedArg::StaticLifetime)
+ },
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,
- );
+ let bound_vars =
+ BoundVarContext::supertrait_hrtb_vars(self.tcx, type_def_id, binding.ident);
self.with(scope, |this| {
let scope = Scope::Supertrait {
- lifetimes: lifetimes.unwrap_or_default(),
+ bound_vars: bound_vars.unwrap_or_default(),
s: this.scope,
};
this.with(scope, |this| this.visit_assoc_type_binding(binding));
@@ -1534,7 +1669,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// ```
/// In this case, if we wanted to the supertrait HRTB lifetimes for `As` on
/// the starting trait `Bar`, we would return `Some(['b, 'a])`.
- fn supertrait_hrtb_lifetimes(
+ fn supertrait_hrtb_vars(
tcx: TyCtxt<'tcx>,
def_id: DefId,
assoc_name: Ident,
@@ -1556,7 +1691,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// See issue #83753. If someone writes an associated type on a non-trait, just treat it as
// there being no supertrait HRTBs.
match tcx.def_kind(def_id) {
- DefKind::Trait | DefKind::TraitAlias | DefKind::Impl => {}
+ DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {}
_ => break None,
}
@@ -1619,13 +1754,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
scope = s;
}
- Scope::Root { .. } | Scope::Elision { .. } => break Region::Static,
+ Scope::Root { .. } | Scope::Elision { .. } => break ResolvedArg::StaticLifetime,
Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l,
- Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => {
+ Scope::Supertrait { s, .. }
+ | Scope::TraitRefBoundary { s, .. }
+ | Scope::AnonConstBoundary { s } => {
scope = s;
}
}
@@ -1634,7 +1771,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
#[instrument(level = "debug", skip(self))]
- fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
+ fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) {
debug!(span = ?lifetime_ref.ident.span);
self.map.defs.insert(lifetime_ref.hir_id, def);
}
@@ -1642,7 +1779,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// Sometimes we resolve a lifetime, but later find that it is an
/// error (esp. around impl trait). In that case, we remove the
/// entry into `map.defs` so as not to confuse later code.
- fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_def: Region) {
+ fn uninsert_lifetime_on_error(
+ &mut self,
+ lifetime_ref: &'tcx hir::Lifetime,
+ bad_def: ResolvedArg,
+ ) {
let old_value = self.map.defs.remove(&lifetime_ref.hir_id);
assert_eq!(old_value, Some(bad_def));
}
@@ -1658,10 +1799,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// "Constrained" basically means that it appears in any type but
/// not amongst the inputs to a projection. In other words, `<&'a
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
-fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<LocalDefId>> {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?;
- let generics = tcx.hir().get_generics(def_id)?;
+fn is_late_bound_map(
+ tcx: TyCtxt<'_>,
+ owner_id: hir::OwnerId,
+) -> Option<&FxIndexSet<hir::ItemLocalId>> {
+ let decl = tcx.hir().fn_decl_by_hir_id(owner_id.into())?;
+ let generics = tcx.hir().get_generics(owner_id.def_id)?;
let mut late_bound = FxIndexSet::default();
@@ -1695,24 +1838,22 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue,
}
- let param_def_id = tcx.hir().local_def_id(param.hir_id);
-
// appears in the where clauses? early-bound.
- if appears_in_where_clause.regions.contains(&param_def_id) {
+ if appears_in_where_clause.regions.contains(&param.def_id) {
continue;
}
// does not appear in the inputs, but appears in the return type? early-bound.
- if !constrained_by_input.regions.contains(&param_def_id)
- && appears_in_output.regions.contains(&param_def_id)
+ if !constrained_by_input.regions.contains(&param.def_id)
+ && appears_in_output.regions.contains(&param.def_id)
{
continue;
}
- debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id);
+ debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.def_id);
- let inserted = late_bound.insert(param_def_id);
- assert!(inserted, "visited lifetime {:?} twice", param.hir_id);
+ let inserted = late_bound.insert(param.hir_id.local_id);
+ assert!(inserted, "visited lifetime {:?} twice", param.def_id);
}
debug!(?late_bound);
@@ -1745,7 +1886,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
use std::ops::ControlFlow;
use ty::Ty;
- impl<'tcx> TypeVisitor<'tcx> for ConstrainedCollectorPostAstConv {
+ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ConstrainedCollectorPostAstConv {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
match t.kind() {
ty::Param(param_ty) => {
@@ -1797,7 +1938,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
let mut walker = ConstrainedCollectorPostAstConv {
arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(),
};
- walker.visit_ty(self.tcx.type_of(alias_def));
+ walker.visit_ty(self.tcx.type_of(alias_def).subst_identity());
match segments.last() {
Some(hir::PathSegment { args: Some(args), .. }) => {
@@ -1865,3 +2006,37 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
}
}
}
+
+pub fn deny_non_region_late_bound(
+ tcx: TyCtxt<'_>,
+ bound_vars: &mut FxIndexMap<LocalDefId, ResolvedArg>,
+ where_: &str,
+) {
+ let mut first = true;
+
+ for (var, arg) in bound_vars {
+ let Node::GenericParam(param) = tcx.hir().get_by_def_id(*var) else {
+ bug!();
+ };
+
+ let what = match param.kind {
+ hir::GenericParamKind::Type { .. } => "type",
+ hir::GenericParamKind::Const { .. } => "const",
+ hir::GenericParamKind::Lifetime { .. } => continue,
+ };
+
+ let mut diag = tcx.sess.struct_span_err(
+ param.span,
+ format!("late-bound {what} parameter not allowed on {where_}"),
+ );
+
+ let guar = if tcx.features().non_lifetime_binders && first {
+ diag.emit()
+ } else {
+ diag.delay_as_bug()
+ };
+
+ first = false;
+ *arg = ResolvedArg::Error(guar);
+ }
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 5e388a2f2..50073d94e 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -8,7 +8,9 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
+use rustc_middle::ty::{
+ self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
@@ -54,15 +56,14 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
// ty which is a fully resolved projection.
// For the code example above, this would mean converting Self::Assoc<3>
// into a ty::Alias(ty::Projection, <Self as Foo>::Assoc<3>)
- let item_hir_id = tcx
+ let item_def_id = tcx
.hir()
- .parent_iter(hir_id)
- .filter(|(_, node)| matches!(node, Node::Item(_)))
- .map(|(id, _)| id)
- .next()
- .unwrap();
- let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
- let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
+ .parent_owner_iter(hir_id)
+ .find(|(_, node)| matches!(node, OwnerNode::Item(_)))
+ .unwrap()
+ .0
+ .to_def_id();
+ let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>;
let ty = item_ctxt.ast_ty_to_ty(hir_ty);
// Iterate through the generics of the projection to find the one that corresponds to
@@ -242,7 +243,7 @@ fn get_path_containing_arg_in_pat<'hir>(
arg_path
}
-pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
+pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> {
let def_id = def_id.expect_local();
use rustc_hir::*;
@@ -250,7 +251,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let icx = ItemCtxt::new(tcx, def_id.to_def_id());
- match tcx.hir().get(hir_id) {
+ let output = match tcx.hir().get(hir_id) {
Node::TraitItem(item) => match item.kind {
TraitItemKind::Fn(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
@@ -258,13 +259,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
TraitItemKind::Const(ty, body_id) => body_id
.and_then(|body_id| {
- if is_suggestable_infer_ty(ty) {
- Some(infer_placeholder_type(
- tcx, def_id, body_id, ty.span, item.ident, "constant",
- ))
- } else {
- None
- }
+ is_suggestable_infer_ty(ty)
+ .then(|| infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant",))
})
.unwrap_or_else(|| icx.to_ty(ty)),
TraitItemKind::Type(_, Some(ty)) => icx.to_ty(ty),
@@ -323,8 +319,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
ItemKind::Impl(hir::Impl { self_ty, .. }) => {
match self_ty.find_self_aliases() {
spans if spans.len() > 0 => {
- tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: (), });
- tcx.ty_error()
+ let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
+ tcx.ty_error(guar)
},
_ => icx.to_ty(*self_ty),
}
@@ -381,7 +377,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def {
VariantData::Unit(..) | VariantData::Struct(..) => {
- tcx.type_of(tcx.hir().get_parent_item(hir_id))
+ tcx.type_of(tcx.hir().get_parent_item(hir_id)).subst_identity()
}
VariantData::Tuple(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
@@ -398,7 +394,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
// We defer to `type_of` of the corresponding parameter
// for generic arguments.
- tcx.type_of(param)
+ tcx.type_of(param).subst_identity()
}
Node::AnonConst(_) => {
@@ -450,7 +446,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
&& e.hir_id == hir_id =>
{
let Some(trait_def_id) = trait_ref.trait_def_id() else {
- return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
+ return ty::EarlyBinder(tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"));
};
let assoc_items = tcx.associated_items(trait_def_id);
let assoc_item = assoc_items.find_by_name_and_kind(
@@ -460,7 +456,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
def_id.to_def_id(),
);
if let Some(assoc_item) = assoc_item {
- tcx.type_of(assoc_item.def_id)
+ tcx.type_of(assoc_item.def_id).subst_identity()
} else {
// FIXME(associated_const_equality): add a useful error message here.
tcx.ty_error_with_message(
@@ -484,7 +480,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}) =>
{
let Some(trait_def_id) = trait_ref.trait_def_id() else {
- return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
+ return ty::EarlyBinder(tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"));
};
let assoc_items = tcx.associated_items(trait_def_id);
let assoc_item = assoc_items.find_by_name_and_kind(
@@ -505,7 +501,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
if let Some(param)
= assoc_item.map(|item| &tcx.generics_of(item.def_id).params[idx]).filter(|param| param.kind.is_ty_or_const())
{
- tcx.type_of(param.def_id)
+ tcx.type_of(param.def_id).subst_identity()
} else {
// FIXME(associated_const_equality): add a useful error message here.
tcx.ty_error_with_message(
@@ -519,7 +515,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
def_id: param_def_id,
kind: GenericParamKind::Const { default: Some(ct), .. },
..
- }) if ct.hir_id == hir_id => tcx.type_of(param_def_id),
+ }) if ct.hir_id == hir_id => tcx.type_of(param_def_id).subst_identity(),
x => tcx.ty_error_with_message(
DUMMY_SP,
@@ -537,7 +533,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
x => {
bug!("unexpected sort of node in type_of(): {:?}", x);
}
- }
+ };
+ ty::EarlyBinder(output)
}
#[instrument(skip(tcx), level = "debug")]
@@ -602,8 +599,9 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
// // constant does not contain interior mutability.
// ```
let tables = self.tcx.typeck(item_def_id);
- if let Some(_) = tables.tainted_by_errors {
- self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
+ if let Some(guar) = tables.tainted_by_errors {
+ self.found =
+ Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) });
return;
}
let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else {
@@ -621,8 +619,8 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
debug!(?concrete_type, "found constraint");
if let Some(prev) = &mut self.found {
if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
- prev.report_mismatch(&concrete_type, self.tcx);
- prev.ty = self.tcx.ty_error();
+ let guar = prev.report_mismatch(&concrete_type, self.tcx);
+ prev.ty = self.tcx.ty_error(guar);
}
} else {
self.found = Some(concrete_type);
@@ -709,7 +707,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
_ => "item",
},
});
- return tcx.ty_error_with_guaranteed(reported);
+ return tcx.ty_error(reported);
};
// Only check against typeck if we didn't already error
@@ -817,11 +815,11 @@ fn find_opaque_ty_constraints_for_rpit(
concrete.map(|concrete| concrete.ty).unwrap_or_else(|| {
let table = tcx.typeck(owner_def_id);
- if let Some(_) = table.tainted_by_errors {
+ if let Some(guar) = table.tainted_by_errors {
// Some error in the
// owner fn prevented us from populating
// the `concrete_opaque_types` table.
- tcx.ty_error()
+ tcx.ty_error(guar)
} else {
table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| {
// We failed to resolve the opaque type or it
@@ -846,35 +844,23 @@ fn infer_placeholder_type<'a>(
) -> Ty<'a> {
// Attempts to make the type nameable by turning FnDefs into FnPtrs.
struct MakeNameable<'tcx> {
- success: bool,
tcx: TyCtxt<'tcx>,
}
- impl<'tcx> MakeNameable<'tcx> {
- fn new(tcx: TyCtxt<'tcx>) -> Self {
- MakeNameable { success: true, tcx }
- }
- }
-
- impl<'tcx> TypeFolder<'tcx> for MakeNameable<'tcx> {
- fn tcx(&self) -> TyCtxt<'tcx> {
+ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MakeNameable<'tcx> {
+ fn interner(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if !self.success {
- return ty;
- }
-
- match ty.kind() {
- ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
- // FIXME: non-capturing closures should also suggest a function pointer
- ty::Closure(..) | ty::Generator(..) => {
- self.success = false;
- ty
+ let ty = match *ty.kind() {
+ ty::FnDef(def_id, substs) => {
+ self.tcx.mk_fn_ptr(self.tcx.fn_sig(def_id).subst(self.tcx, substs))
}
- _ => ty.super_fold_with(self),
- }
+ _ => ty,
+ };
+
+ ty.super_fold_with(self)
}
}
@@ -897,15 +883,11 @@ fn infer_placeholder_type<'a>(
suggestions.clear();
}
- // Suggesting unnameable types won't help.
- let mut mk_nameable = MakeNameable::new(tcx);
- let ty = mk_nameable.fold_ty(ty);
- let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
- if let Some(sugg_ty) = sugg_ty {
+ if let Some(ty) = ty.make_suggestable(tcx, false) {
err.span_suggestion(
span,
&format!("provide a type for the {item}", item = kind),
- format!("{colon} {sugg_ty}"),
+ format!("{colon} {ty}"),
Applicability::MachineApplicable,
);
} else {
@@ -922,15 +904,12 @@ fn infer_placeholder_type<'a>(
let mut diag = bad_placeholder(tcx, vec![span], kind);
if !ty.references_error() {
- let mut mk_nameable = MakeNameable::new(tcx);
- let ty = mk_nameable.fold_ty(ty);
- let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
- if let Some(sugg_ty) = sugg_ty {
+ if let Some(ty) = ty.make_suggestable(tcx, false) {
diag.span_suggestion(
span,
"replace with the correct type",
- sugg_ty,
- Applicability::MaybeIncorrect,
+ ty,
+ Applicability::MachineApplicable,
);
} else {
with_forced_trimmed_paths!(diag.span_note(