Skip to content

support anon consts in binders #79313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 35 additions & 25 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{AnonymousLifetimeMode, LoweringContext, ParamMode};
use super::{ImplTraitContext, ImplTraitPosition};
use super::{ImplTraitContext, ImplTraitPosition, LifetimeOrigin};
use crate::Arena;

use rustc_ast::node_id::NodeMap;
Expand Down Expand Up @@ -420,12 +420,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
},
);

let new_impl_items =
self.with_in_scope_lifetime_defs(&ast_generics.params, |this| {
let new_impl_items = self.with_in_scope_lifetime_defs(
LifetimeOrigin::Other,
&ast_generics.params,
|this| {
this.arena.alloc_from_iter(
impl_items.iter().map(|item| this.lower_impl_item_ref(item)),
)
});
},
);

// `defaultness.has_value()` is never called for an `impl`, always `true` in order
// to not cause an assertion failure inside the `lower_defaultness` function.
Expand Down Expand Up @@ -1430,27 +1433,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
ref bounds,
span,
}) => {
self.with_in_scope_lifetime_defs(&bound_generic_params, |this| {
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
bound_generic_params: this.lower_generic_params(
bound_generic_params,
&NodeMap::default(),
ImplTraitContext::disallowed(),
),
bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()),
bounds: this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| {
match *bound {
// Ignore `?Trait` bounds.
// They were copied into type parameters already.
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
_ => Some(
this.lower_param_bound(bound, ImplTraitContext::disallowed()),
),
}
})),
span,
})
})
self.with_in_scope_lifetime_defs(
LifetimeOrigin::Hrtb,
&bound_generic_params,
|this| {
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
bound_generic_params: this.lower_generic_params(
bound_generic_params,
&NodeMap::default(),
ImplTraitContext::disallowed(),
),
bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()),
bounds: this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| {
match *bound {
// Ignore `?Trait` bounds.
// They were copied into type parameters already.
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
_ => {
Some(this.lower_param_bound(
bound,
ImplTraitContext::disallowed(),
))
}
}
})),
span,
})
},
)
}
WherePredicate::RegionPredicate(WhereRegionPredicate {
ref lifetime,
Expand Down
179 changes: 135 additions & 44 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ struct LoweringContext<'a, 'hir: 'a> {
/// We always store a `normalize_to_macros_2_0()` version of the param-name in this
/// vector.
in_scope_lifetimes: Vec<ParamName>,
/// The index of the first lifetime introduced using `for<'lt>`.
///
/// Used to only add lifetimes from binders as generics to anon consts.
hrtb_start: Option<usize>,

current_module: hir::HirId,

Expand All @@ -168,6 +172,12 @@ struct LoweringContext<'a, 'hir: 'a> {
allow_gen_future: Option<Lrc<[Symbol]>>,
}

#[derive(Copy, Clone)]
enum LifetimeOrigin {
Hrtb,
Other,
}

pub trait ResolverAstLowering {
fn def_key(&mut self, id: DefId) -> DefKey;

Expand Down Expand Up @@ -322,6 +332,7 @@ pub fn lower_crate<'a, 'hir>(
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(),
hrtb_start: None,
allow_try_trait: Some([sym::try_trait][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()),
}
Expand Down Expand Up @@ -846,6 +857,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// for them.
fn with_in_scope_lifetime_defs<T>(
&mut self,
origin: LifetimeOrigin,
params: &[GenericParam],
f: impl FnOnce(&mut Self) -> T,
) -> T {
Expand All @@ -858,8 +870,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
});
self.in_scope_lifetimes.extend(lt_def_names);

let hrtb_start = self.hrtb_start;
match (hrtb_start, origin) {
(None, LifetimeOrigin::Hrtb) => self.hrtb_start = Some(old_len),
(Some(idx), LifetimeOrigin::Hrtb) => debug_assert!(idx <= old_len),
(None, LifetimeOrigin::Other) => (),
(Some(idx), LifetimeOrigin::Other) => panic!(
"unexpected lifetime origin inside of hrtb: {:?}, hrtb={:?}, new={:?}",
self.in_scope_lifetimes, idx, old_len
),
}

let res = f(self);

self.hrtb_start = hrtb_start;
self.in_scope_lifetimes.truncate(old_len);
res
}
Expand All @@ -878,7 +902,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
) -> (hir::Generics<'hir>, T) {
let (in_band_defs, (mut lowered_generics, res)) =
self.with_in_scope_lifetime_defs(&generics.params, |this| {
self.with_in_scope_lifetime_defs(LifetimeOrigin::Other, &generics.params, |this| {
this.collect_in_band_defs(parent_def_id, anonymous_lifetime_mode, |this| {
let mut params = Vec::new();
// Note: it is necessary to lower generics *before* calling `f`.
Expand Down Expand Up @@ -1158,9 +1182,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
tokens: None,
};

let ct = self.with_new_scopes(|this| hir::AnonConst {
hir_id: this.lower_node_id(node_id),
body: this.lower_const_body(path_expr.span, Some(&path_expr)),
let ct = self.lower_anon_const(&AnonConst {
id: node_id,
value: ast::ptr::P(path_expr),
});
return GenericArg::Const(ConstArg { value: ct, span: ty.span });
}
Expand All @@ -1169,7 +1193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
GenericArg::Type(self.lower_ty_direct(&ty, itctx))
}
ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg {
value: self.lower_anon_const(&ct),
value: self.lower_anon_const(ct),
span: ct.value.span,
}),
}
Expand Down Expand Up @@ -1218,21 +1242,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
}
TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(&f.generic_params, |this| {
this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
generic_params: this.lower_generic_params(
&f.generic_params,
&NodeMap::default(),
ImplTraitContext::disallowed(),
),
unsafety: this.lower_unsafety(f.unsafety),
abi: this.lower_extern(f.ext),
decl: this.lower_fn_decl(&f.decl, None, false, None),
param_names: this.lower_fn_params_to_names(&f.decl),
}))
TyKind::BareFn(ref f) => {
self.with_in_scope_lifetime_defs(LifetimeOrigin::Hrtb, &f.generic_params, |this| {
this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
generic_params: this.lower_generic_params(
&f.generic_params,
&NodeMap::default(),
ImplTraitContext::disallowed(),
),
unsafety: this.lower_unsafety(f.unsafety),
abi: this.lower_extern(f.ext),
decl: this.lower_fn_decl(&f.decl, None, false, None),
param_names: this.lower_fn_params_to_names(&f.decl),
}))
})
})
}),
}
TyKind::Never => hir::TyKind::Never,
TyKind::Tup(ref tys) => {
hir::TyKind::Tup(self.arena.alloc_from_iter(
Expand Down Expand Up @@ -1948,8 +1974,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);

let generic_params =
this.arena.alloc_from_iter(lifetime_params.iter().map(|(span, hir_name)| {
this.lifetime_to_generic_param(*span, *hir_name, opaque_ty_def_id)
this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name)| {
this.lifetime_to_generic_param(span, hir_name, opaque_ty_def_id)
}));

let opaque_ty_item = hir::OpaqueTy {
Expand Down Expand Up @@ -2236,28 +2262,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx.reborrow(),
);

let trait_ref = self.with_in_scope_lifetime_defs(&p.bound_generic_params, |this| {
// Any impl Trait types defined within this scope can capture
// lifetimes bound on this predicate.
let lt_def_names = p.bound_generic_params.iter().filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(hir::LifetimeName::Param(
ParamName::Plain(param.ident.normalize_to_macros_2_0()),
)),
_ => None,
});
if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx {
capturable_lifetimes.extend(lt_def_names.clone());
}
let trait_ref = self.with_in_scope_lifetime_defs(
LifetimeOrigin::Hrtb,
&p.bound_generic_params,
|this| {
// Any impl Trait types defined within this scope can capture
// lifetimes bound on this predicate.
let lt_def_names =
p.bound_generic_params.iter().filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(hir::LifetimeName::Param(
ParamName::Plain(param.ident.normalize_to_macros_2_0()),
)),
_ => None,
});
if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx
{
capturable_lifetimes.extend(lt_def_names.clone());
}

let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow());
let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow());

if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx {
for param in lt_def_names {
capturable_lifetimes.remove(&param);
if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx
{
for param in lt_def_names {
capturable_lifetimes.remove(&param);
}
}
}
res
});
res
},
);

hir::PolyTraitRef { bound_generic_params, trait_ref, span: p.span }
}
Expand Down Expand Up @@ -2320,10 +2353,68 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.expr_block(block, AttrVec::new())
}

fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
self.with_new_scopes(|this| hir::AnonConst {
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst<'hir> {
self.with_new_scopes(|this| {
this.allocate_hir_id_counter(c.id);
this.with_hir_id_owner(c.id, |this| {
let def_id = this.resolver.local_def_id(c.id);

let hir_id = this.lower_node_id(c.id);
// Calculate all the lifetimes that should be captured
// by the anonymous constant. This is needed for binders,
// for example `for<'a> dyn Trait<{ inner_fn::<'a>() }> where
// we somehow have to deal with `'a` in the anonymous constant.
//
// We therefore add these lifetimes as additional generic parameters.

// We only need `in_scope_lifetimes` because all in-band lifetimes are
// added to the generics of the parent.
let lifetime_params: Vec<(Span, ParamName)> =
if let Some(hrtb_start) = this.hrtb_start {
this.in_scope_lifetimes
.iter()
.skip(hrtb_start)
.cloned()
.map(|name| (name.ident().span, name))
.collect()
} else {
vec![]
};
let generic_params =
this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name)| {
this.lifetime_to_generic_param(span, hir_name, def_id)
}));

let generic_args =
this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name)| {
GenericArg::Lifetime(hir::Lifetime {
hir_id: this.next_id(),
span,
name: hir::LifetimeName::Param(hir_name),
})
}));

// The generics of an anonymous constants refer to the
// generics of their parent anon const, so we only have to
// deal with each higher ranked lifetime at the outermost const.
let hrtb_start = mem::replace(&mut this.hrtb_start, None);
let ct = hir::AnonConst {
hir_id,
generics: hir::Generics {
params: generic_params,
where_clause: hir::WhereClause { predicates: &[], span: c.value.span },
span: c.value.span,
},
generic_args: hir::GenericArgs {
args: generic_args,
bindings: &[],
parenthesized: false,
},
body: this.lower_const_body(c.value.span, Some(&c.value)),
};
this.hrtb_start = hrtb_start;
ct
})
})
}

Expand Down
Loading