Skip to content

Commit 2abf9c0

Browse files
committed
effects: support generic const items
1 parent ffb7ed9 commit 2abf9c0

File tree

4 files changed

+98
-59
lines changed

4 files changed

+98
-59
lines changed

compiler/rustc_ast_lowering/src/item.rs

+56-25
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
22
use super::ResolverAstLoweringExt;
33
use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
4-
use super::{FnDeclKind, LoweringContext, ParamMode};
4+
use super::{EffectContext, FnDeclKind, LoweringContext, ParamMode};
55

66
use hir::definitions::DefPathData;
77
use rustc_ast::ptr::P;
@@ -90,7 +90,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
9090
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
9191
allow_gen_future,
9292
generics_def_id_map: Default::default(),
93-
host_param_id: None,
93+
effect_context: None,
9494
};
9595
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
9696

@@ -150,7 +150,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
150150
lctx.is_in_trait_impl = impl_.of_trait.is_some();
151151
}
152152
hir::ItemKind::Trait(_, _, generics, _, _) if lctx.tcx.features().effects => {
153-
lctx.host_param_id = generics
153+
lctx.effect_context = generics
154154
.params
155155
.iter()
156156
.find(|param| {
@@ -160,7 +160,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
160160
.iter()
161161
.any(|attr| attr.has_name(sym::rustc_host))
162162
})
163-
.map(|param| param.def_id);
163+
.map(|param| EffectContext::Parametrized { host_param_id: param.def_id });
164164
}
165165
_ => {}
166166
}
@@ -256,7 +256,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
256256
ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
257257
let (generics, (ty, body_id)) = self.lower_generics(
258258
generics,
259-
Const::No,
259+
Constness::Always,
260260
id,
261261
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
262262
|this| this.lower_const_item(ty, span, expr.as_deref()),
@@ -286,11 +286,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
286286
);
287287

288288
let itctx = ImplTraitContext::Universal;
289-
let (generics, decl) =
290-
this.lower_generics(generics, header.constness, id, &itctx, |this| {
289+
let (generics, decl) = this.lower_generics(
290+
generics,
291+
header.constness.into(),
292+
id,
293+
&itctx,
294+
|this| {
291295
let ret_id = asyncness.opt_return_id();
292296
this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id)
293-
});
297+
},
298+
);
294299
let sig = hir::FnSig {
295300
decl,
296301
header: this.lower_fn_header(*header),
@@ -325,7 +330,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
325330
add_ty_alias_where_clause(&mut generics, *where_clauses, true);
326331
let (generics, ty) = self.lower_generics(
327332
&generics,
328-
Const::No,
333+
Constness::Never,
329334
id,
330335
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
331336
|this| match ty {
@@ -347,7 +352,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
347352
ItemKind::Enum(enum_definition, generics) => {
348353
let (generics, variants) = self.lower_generics(
349354
generics,
350-
Const::No,
355+
Constness::Never,
351356
id,
352357
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
353358
|this| {
@@ -361,7 +366,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
361366
ItemKind::Struct(struct_def, generics) => {
362367
let (generics, struct_def) = self.lower_generics(
363368
generics,
364-
Const::No,
369+
Constness::Never,
365370
id,
366371
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
367372
|this| this.lower_variant_data(hir_id, struct_def),
@@ -371,7 +376,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
371376
ItemKind::Union(vdata, generics) => {
372377
let (generics, vdata) = self.lower_generics(
373378
generics,
374-
Const::No,
379+
Constness::Never,
375380
id,
376381
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
377382
|this| this.lower_variant_data(hir_id, vdata),
@@ -403,7 +408,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
403408
// parent lifetime.
404409
let itctx = ImplTraitContext::Universal;
405410
let (generics, (trait_ref, lowered_ty)) =
406-
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
411+
self.lower_generics(ast_generics, (*constness).into(), id, &itctx, |this| {
407412
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
408413
this.lower_trait_ref(
409414
*constness,
@@ -449,7 +454,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
449454
.unwrap_or(&[])
450455
.iter()
451456
.find(|x| x.has_name(sym::const_trait))
452-
.map_or(Const::No, |x| Const::Yes(x.span));
457+
.map_or(Constness::Never, |x| Constness::Maybe(x.span));
453458
let (generics, (unsafety, items, bounds)) = self.lower_generics(
454459
generics,
455460
constness,
@@ -472,7 +477,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
472477
ItemKind::TraitAlias(generics, bounds) => {
473478
let (generics, bounds) = self.lower_generics(
474479
generics,
475-
Const::No,
480+
Constness::Never,
476481
id,
477482
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
478483
|this| {
@@ -627,7 +632,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
627632
let fdec = &sig.decl;
628633
let itctx = ImplTraitContext::Universal;
629634
let (generics, (fn_dec, fn_args)) =
630-
self.lower_generics(generics, Const::No, i.id, &itctx, |this| {
635+
self.lower_generics(generics, Constness::Never, i.id, &itctx, |this| {
631636
(
632637
// Disallow `impl Trait` in foreign items.
633638
this.lower_fn_decl(
@@ -746,7 +751,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
746751
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => {
747752
let (generics, kind) = self.lower_generics(
748753
&generics,
749-
Const::No,
754+
Constness::Always,
750755
i.id,
751756
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
752757
|this| {
@@ -791,7 +796,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
791796
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
792797
let (generics, kind) = self.lower_generics(
793798
&generics,
794-
Const::No,
799+
Constness::Never,
795800
i.id,
796801
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
797802
|this| {
@@ -859,7 +864,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
859864
let (generics, kind) = match &i.kind {
860865
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
861866
&generics,
862-
Const::No,
867+
Constness::Always,
863868
i.id,
864869
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
865870
|this| {
@@ -895,7 +900,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
895900
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
896901
self.lower_generics(
897902
&generics,
898-
Const::No,
903+
Constness::Never,
899904
i.id,
900905
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
901906
|this| match ty {
@@ -1255,7 +1260,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
12551260
let header = self.lower_fn_header(sig.header);
12561261
let itctx = ImplTraitContext::Universal;
12571262
let (generics, decl) =
1258-
self.lower_generics(generics, sig.header.constness, id, &itctx, |this| {
1263+
self.lower_generics(generics, sig.header.constness.into(), id, &itctx, |this| {
12591264
this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async)
12601265
});
12611266
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
@@ -1333,7 +1338,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
13331338
fn lower_generics<T>(
13341339
&mut self,
13351340
generics: &Generics,
1336-
constness: Const,
1341+
constness: Constness,
13371342
parent_node_id: NodeId,
13381343
itctx: &ImplTraitContext,
13391344
f: impl FnOnce(&mut Self) -> T,
@@ -1387,7 +1392,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
13871392
// Desugar `~const` bound in generics into an additional `const host: bool` param
13881393
// if the effects feature is enabled. This needs to be done before we lower where
13891394
// clauses since where clauses need to bind to the DefId of the host param
1390-
let host_param_parts = if let Const::Yes(span) = constness
1395+
let host_param_parts = if let Constness::Maybe(span) = constness
13911396
&& self.tcx.features().effects
13921397
{
13931398
if let Some(param) =
@@ -1396,7 +1401,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
13961401
// user has manually specified a `rustc_host` param, in this case, we set
13971402
// the param id so that lowering logic can use that. But we don't create
13981403
// another host param, so this gives `None`.
1399-
self.host_param_id = Some(self.local_def_id(param.id));
1404+
self.effect_context = Some(EffectContext::Parametrized {
1405+
host_param_id: self.local_def_id(param.id),
1406+
});
14001407
None
14011408
} else {
14021409
let param_node_id = self.next_node_id();
@@ -1407,13 +1414,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
14071414
DefPathData::TypeNs(sym::host),
14081415
span,
14091416
);
1410-
self.host_param_id = Some(def_id);
1417+
self.effect_context = Some(EffectContext::Parametrized {
1418+
host_param_id: def_id,
1419+
});
14111420
Some((span, hir_id, def_id))
14121421
}
14131422
} else {
14141423
None
14151424
};
14161425

1426+
// FIXME(generic_const_items, effects): Instead of interpreting `~const` bounds as `const`
1427+
// bounds, we should probably introduce `const` bounds into the surface language.
1428+
if let Constness::Always = constness && self.tcx.features().effects {
1429+
self.effect_context = Some(EffectContext::Invariant { value: false });
1430+
};
1431+
14171432
let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
14181433
predicates.extend(generics.params.iter().filter_map(|param| {
14191434
self.lower_generic_bound_predicate(
@@ -1660,3 +1675,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
16601675
}
16611676
}
16621677
}
1678+
1679+
#[derive(Debug)]
1680+
enum Constness {
1681+
Always,
1682+
Maybe(Span),
1683+
Never,
1684+
}
1685+
1686+
impl From<Const> for Constness {
1687+
fn from(constness: Const) -> Self {
1688+
match constness {
1689+
Const::Yes(span) => Self::Maybe(span),
1690+
Const::No => Self::Never,
1691+
}
1692+
}
1693+
}

compiler/rustc_ast_lowering/src/lib.rs

+29-19
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ struct LoweringContext<'a, 'hir> {
146146
/// field from the original parameter 'a to the new parameter 'a1.
147147
generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
148148

149-
host_param_id: Option<LocalDefId>,
149+
effect_context: Option<EffectContext>,
150150
}
151151

152152
trait ResolverAstLoweringExt {
@@ -227,6 +227,12 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
227227
}
228228
}
229229

230+
#[derive(Clone, Copy)]
231+
enum EffectContext {
232+
Parametrized { host_param_id: LocalDefId },
233+
Invariant { value: bool },
234+
}
235+
230236
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
231237
/// and if so, what meaning it has.
232238
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -2476,34 +2482,38 @@ impl<'hir> GenericArgsCtor<'hir> {
24762482

24772483
// if bound is non-const, don't add host effect param
24782484
let ast::Const::Yes(span) = constness else { return };
2479-
24802485
let span = lcx.lower_span(span);
24812486

24822487
let id = lcx.next_node_id();
24832488
let hir_id = lcx.next_id();
24842489

2485-
let Some(host_param_id) = lcx.host_param_id else {
2486-
lcx.tcx
2487-
.sess
2488-
.delay_span_bug(span, "no host param id for call in const yet no errors reported");
2490+
let Some(context) = lcx.effect_context else {
2491+
lcx.tcx.sess.delay_span_bug(span, "no effect context for maybe-const trait bound");
24892492
return;
24902493
};
24912494

24922495
let body = lcx.lower_body(|lcx| {
24932496
(&[], {
2494-
let hir_id = lcx.next_id();
2495-
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
2496-
let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
2497-
None,
2498-
lcx.arena.alloc(hir::Path {
2499-
span,
2500-
res,
2501-
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
2502-
name: sym::host,
2503-
span,
2504-
}, hir_id, res)],
2505-
}),
2506-
));
2497+
let expr_kind = match context {
2498+
EffectContext::Parametrized { host_param_id } => {
2499+
let hir_id = lcx.next_id();
2500+
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
2501+
hir::ExprKind::Path(hir::QPath::Resolved(
2502+
None,
2503+
lcx.arena.alloc(hir::Path {
2504+
span,
2505+
res,
2506+
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
2507+
name: sym::host,
2508+
span,
2509+
}, hir_id, res)],
2510+
}),
2511+
))
2512+
}
2513+
EffectContext::Invariant { value } => hir::ExprKind::Lit(
2514+
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(value), span }),
2515+
),
2516+
};
25072517
lcx.expr(span, expr_kind)
25082518
})
25092519
});

tests/ui/generic-const-items/const-trait-impl.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
1-
// known-bug: #110395
2-
// FIXME check-pass
1+
// check-pass
32

43
// Test that we can call methods from const trait impls inside of generic const items.
4+
// `~const` bounds are interpreted as `const` bounds.
55

6-
#![feature(generic_const_items, const_trait_impl)]
6+
#![feature(generic_const_items, const_trait_impl, effects)]
77
#![allow(incomplete_features)]
88
#![crate_type = "lib"]
99

10-
// FIXME(generic_const_items): Interpret `~const` as always-const.
1110
const CREATE<T: ~const Create>: T = T::create();
1211

1312
pub const K0: i32 = CREATE::<i32>;
1413
pub const K1: i32 = CREATE; // arg inferred
1514

15+
trait Creator { // doesn't need to be a `#[const_trait]`
16+
const CREATE<T: ~const Create>: T;
17+
}
18+
19+
impl Creator for () {
20+
const CREATE<T: ~const Create>: T = T::create();
21+
}
22+
23+
pub const K2: i32 = <() as Creator>::CREATE::<i32>;
24+
1625
#[const_trait]
1726
trait Create {
1827
fn create() -> Self;

tests/ui/generic-const-items/const-trait-impl.stderr

-11
This file was deleted.

0 commit comments

Comments
 (0)