summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs273
1 files changed, 156 insertions, 117 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 6dd0c840d..eb4466449 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -158,13 +158,14 @@ enum Scope<'a> {
s: ScopeRef<'a>,
},
- /// Disallows capturing non-lifetime binders from parent scopes.
+ /// Disallows capturing late-bound vars 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 {
+ LateBoundary {
s: ScopeRef<'a>,
+ what: &'static str,
},
Root {
@@ -216,7 +217,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
.field("s", &"..")
.finish(),
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
- Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(),
+ Scope::LateBoundary { s: _, what } => {
+ f.debug_struct("LateBoundary").field("what", what).finish()
+ }
Scope::Root { opt_parent_item } => {
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
}
@@ -318,7 +321,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
break (vec![], BinderScopeType::Normal);
}
- Scope::ObjectLifetimeDefault { s, .. } | Scope::AnonConstBoundary { s } => {
+ Scope::ObjectLifetimeDefault { s, .. } | Scope::LateBoundary { s, .. } => {
scope = s;
}
@@ -697,9 +700,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}) => {
intravisit::walk_ty(self, ty);
- // Elided lifetimes are not allowed in non-return
- // position impl Trait
- let scope = Scope::TraitRefBoundary { s: self.scope };
+ // Elided lifetimes and late-bound lifetimes (from the parent)
+ // are not allowed in non-return position impl Trait
+ let scope = Scope::LateBoundary {
+ s: &Scope::TraitRefBoundary { s: self.scope },
+ what: "type alias impl trait",
+ };
self.with(scope, |this| intravisit::walk_item(this, opaque_ty));
return;
@@ -849,106 +855,87 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| {
- for param in generics.params {
- match param.kind {
- GenericParamKind::Lifetime { .. } => {}
- GenericParamKind::Type { default, .. } => {
- if let Some(ty) = default {
- this.visit_ty(ty);
- }
- }
- GenericParamKind::Const { ty, default } => {
- this.visit_ty(ty);
- if let Some(default) = default {
- this.visit_body(this.tcx.hir().body(default.body));
- }
- }
- }
+ walk_list!(this, visit_generic_param, generics.params);
+ walk_list!(this, visit_where_predicate, generics.predicates);
+ })
+ }
+
+ fn visit_where_predicate(&mut self, predicate: &'tcx hir::WherePredicate<'tcx>) {
+ match predicate {
+ &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+ hir_id,
+ bounded_ty,
+ bounds,
+ bound_generic_params,
+ origin,
+ ..
+ }) => {
+ let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
+ bound_generic_params
+ .iter()
+ .enumerate()
+ .map(|(late_bound_idx, param)| {
+ 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();
+ self.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
+ // will be `Concatenating` anyways, so we don't have to worry about the depth
+ // being wrong.
+ let scope = Scope::Binder {
+ hir_id,
+ bound_vars,
+ s: self.scope,
+ scope_type: BinderScopeType::Normal,
+ where_bound_origin: Some(origin),
+ };
+ self.with(scope, |this| {
+ walk_list!(this, visit_generic_param, bound_generic_params);
+ this.visit_ty(&bounded_ty);
+ walk_list!(this, visit_param_bound, bounds);
+ })
}
- for predicate in generics.predicates {
- match predicate {
- &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
- hir_id,
- bounded_ty,
- bounds,
- bound_generic_params,
- origin,
- ..
- }) => {
- let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
- bound_generic_params
- .iter()
- .enumerate()
- .map(|(late_bound_idx, param)| {
- let pair = ResolvedArg::late(late_bound_idx as u32, param);
- let r = late_arg_as_bound_arg(this.tcx, &pair.1, param);
- (pair, r)
- })
- .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
- // will be `Concatenating` anyways, so we don't have to worry about the depth
- // being wrong.
- let scope = Scope::Binder {
- hir_id,
- bound_vars,
- s: this.scope,
- scope_type: BinderScopeType::Normal,
- where_bound_origin: Some(origin),
+ &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
+ lifetime,
+ bounds,
+ ..
+ }) => {
+ self.visit_lifetime(lifetime);
+ walk_list!(self, visit_param_bound, bounds);
+
+ if lifetime.res != hir::LifetimeName::Static {
+ for bound in bounds {
+ let hir::GenericBound::Outlives(lt) = bound else {
+ continue;
};
- this.with(scope, |this| {
- this.visit_ty(&bounded_ty);
- walk_list!(this, visit_param_bound, bounds);
- })
- }
- &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
- lifetime,
- bounds,
- ..
- }) => {
- this.visit_lifetime(lifetime);
- walk_list!(this, visit_param_bound, bounds);
-
- if lifetime.res != hir::LifetimeName::Static {
- for bound in bounds {
- let hir::GenericBound::Outlives(lt) = bound else {
- continue;
- };
- if lt.res != hir::LifetimeName::Static {
- continue;
- }
- 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,
- );
- lint.help(help)
- },
- );
- }
+ if lt.res != hir::LifetimeName::Static {
+ continue;
}
- }
- &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
- lhs_ty,
- rhs_ty,
- ..
- }) => {
- this.visit_ty(lhs_ty);
- this.visit_ty(rhs_ty);
+ self.insert_lifetime(lt, ResolvedArg::StaticLifetime);
+ self.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,
+ );
+ lint.help(help)
+ },
+ );
}
}
}
- })
+ &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
+ self.visit_ty(lhs_ty);
+ self.visit_ty(rhs_ty);
+ }
+ }
}
fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) {
@@ -982,10 +969,37 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
- self.with(Scope::AnonConstBoundary { s: self.scope }, |this| {
+ self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| {
intravisit::walk_anon_const(this, c);
});
}
+
+ fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
+ match p.kind {
+ GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
+ self.resolve_type_ref(p.def_id, p.hir_id);
+ }
+ GenericParamKind::Lifetime { .. } => {
+ // No need to resolve lifetime params, we don't use them for things
+ // like implicit `?Sized` or const-param-has-ty predicates.
+ }
+ }
+
+ match p.kind {
+ GenericParamKind::Lifetime { .. } => {}
+ GenericParamKind::Type { default, .. } => {
+ if let Some(ty) = default {
+ self.visit_ty(ty);
+ }
+ }
+ GenericParamKind::Const { ty, default } => {
+ self.visit_ty(ty);
+ if let Some(default) = default {
+ self.visit_body(self.tcx.hir().body(default.body));
+ }
+ }
+ }
+ }
}
fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault {
@@ -1165,6 +1179,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let mut late_depth = 0;
let mut scope = self.scope;
let mut outermost_body = None;
+ let mut crossed_late_boundary = None;
let result = loop {
match *scope {
Scope::Body { id, s } => {
@@ -1197,7 +1212,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
&& 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.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
{
let mut diag = rustc_session::parse::feature_err(
@@ -1249,8 +1264,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
- | Scope::TraitRefBoundary { s, .. }
- | Scope::AnonConstBoundary { s } => {
+ | Scope::TraitRefBoundary { s, .. } => {
+ scope = s;
+ }
+
+ Scope::LateBoundary { s, what } => {
+ crossed_late_boundary = Some(what);
scope = s;
}
}
@@ -1259,6 +1278,22 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
if let Some(mut def) = result {
if let ResolvedArg::EarlyBound(..) = def {
// Do not free early-bound regions, only late-bound ones.
+ } else if let ResolvedArg::LateBound(_, _, param_def_id) = def
+ && let Some(what) = crossed_late_boundary
+ {
+ let use_span = lifetime_ref.ident.span;
+ let def_span = self.tcx.def_span(param_def_id);
+ let guar = match self.tcx.def_kind(param_def_id) {
+ DefKind::LifetimeParam => {
+ self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Lifetime {
+ use_span,
+ def_span,
+ what,
+ })
+ }
+ _ => unreachable!(),
+ };
+ def = ResolvedArg::Error(guar);
} 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) {
@@ -1313,7 +1348,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
- | Scope::AnonConstBoundary { s } => {
+ | Scope::LateBoundary { s, .. } => {
scope = s;
}
}
@@ -1332,7 +1367,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
// search.
let mut late_depth = 0;
let mut scope = self.scope;
- let mut crossed_anon_const = false;
+ let mut crossed_late_boundary = None;
let result = loop {
match *scope {
@@ -1367,28 +1402,32 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
scope = s;
}
- Scope::AnonConstBoundary { s } => {
- crossed_anon_const = true;
+ Scope::LateBoundary { s, what } => {
+ crossed_late_boundary = Some(what);
scope = s;
}
}
};
if let Some(def) = result {
- if let ResolvedArg::LateBound(..) = def && crossed_anon_const {
+ if let ResolvedArg::LateBound(..) = def
+ && let Some(what) = crossed_late_boundary
+ {
let use_span = self.tcx.hir().span(hir_id);
let def_span = self.tcx.def_span(param_def_id);
let guar = match self.tcx.def_kind(param_def_id) {
DefKind::ConstParam => {
- self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const {
+ self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Const {
use_span,
def_span,
+ what,
})
}
DefKind::TyParam => {
- self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type {
+ self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Type {
use_span,
def_span,
+ what,
})
}
_ => unreachable!(),
@@ -1437,7 +1476,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
- | Scope::AnonConstBoundary { s } => {
+ | Scope::LateBoundary { s, .. } => {
scope = s;
}
}
@@ -1480,7 +1519,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
DefKind::Struct
| DefKind::Union
| DefKind::Enum
- | DefKind::TyAlias { .. }
+ | DefKind::TyAlias
| DefKind::Trait,
def_id,
) if depth == 0 => Some(def_id),
@@ -1517,7 +1556,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
- | Scope::AnonConstBoundary { s } => {
+ | Scope::LateBoundary { s, .. } => {
scope = s;
}
}
@@ -1822,7 +1861,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
- | Scope::AnonConstBoundary { s } => {
+ | Scope::LateBoundary { s, .. } => {
scope = s;
}
}
@@ -1990,7 +2029,7 @@ fn is_late_bound_map(
hir::TyKind::Path(hir::QPath::Resolved(
None,
- hir::Path { res: Res::Def(DefKind::TyAlias { .. }, alias_def), segments, span },
+ hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
)) => {
// See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider
// args to be unconstrained.