Skip to content

Commit b265a78

Browse files
committed
Introduce const Trait (always-const trait bounds)
1 parent 9746938 commit b265a78

39 files changed

+424
-199
lines changed

compiler/rustc_ast/src/ast.rs

+36-3
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,22 @@ pub enum TraitBoundModifier {
300300
/// `?Trait`
301301
Maybe,
302302

303+
/// `const Trait`
304+
Const(Span),
305+
303306
/// `~const Trait`
304307
MaybeConst(Span),
305308

309+
/// `const !Trait`
310+
//
311+
// This parses but will be rejected during AST validation.
312+
ConstNegative,
313+
314+
/// `const ?Trait`
315+
//
316+
// This parses but will be rejected during AST validation.
317+
ConstMaybe,
318+
306319
/// `~const !Trait`
307320
//
308321
// This parses but will be rejected during AST validation.
@@ -315,10 +328,11 @@ pub enum TraitBoundModifier {
315328
}
316329

317330
impl TraitBoundModifier {
318-
pub fn to_constness(self) -> Const {
331+
pub fn to_constness(self) -> BoundConstness {
319332
match self {
320-
Self::MaybeConst(span) => Const::Yes(span),
321-
_ => Const::No,
333+
Self::Const(span) => BoundConstness::Always(span),
334+
Self::MaybeConst(span) => BoundConstness::Maybe(span),
335+
_ => BoundConstness::Never,
322336
}
323337
}
324338
}
@@ -2526,6 +2540,25 @@ pub enum BoundPolarity {
25262540
Maybe(Span),
25272541
}
25282542

2543+
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
2544+
pub enum BoundConstness {
2545+
/// `Type: Trait`
2546+
Never,
2547+
/// `Type: const Trait`
2548+
Always(Span),
2549+
/// `Type: ~const Trait`
2550+
Maybe(Span),
2551+
}
2552+
2553+
impl From<Const> for BoundConstness {
2554+
fn from(constness: Const) -> Self {
2555+
match constness {
2556+
Const::Yes(span) => Self::Maybe(span),
2557+
Const::No => Self::Never,
2558+
}
2559+
}
2560+
}
2561+
25292562
#[derive(Clone, Encodable, Decodable, Debug)]
25302563
pub enum FnRetTy {
25312564
/// Returns type is not specified.

compiler/rustc_ast_lowering/src/item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
341341
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
342342
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
343343
this.lower_trait_ref(
344-
*constness,
344+
(*constness).into(),
345345
trait_ref,
346346
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
347347
)

compiler/rustc_ast_lowering/src/lib.rs

+54-32
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13181318
span: t.span,
13191319
},
13201320
itctx,
1321-
ast::Const::No,
1321+
ast::BoundConstness::Never,
13221322
);
13231323
let bounds = this.arena.alloc_from_iter([bound]);
13241324
let lifetime_bound = this.elided_dyn_bound(t.span);
@@ -1426,18 +1426,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14261426
GenericBound::Trait(
14271427
ty,
14281428
modifier @ (TraitBoundModifier::None
1429+
| TraitBoundModifier::Const(_)
14291430
| TraitBoundModifier::MaybeConst(_)
14301431
| TraitBoundModifier::Negative),
14311432
) => {
14321433
Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness()))
14331434
}
1434-
// `~const ?Bound` will cause an error during AST validation
1435+
// `{,~}const ?Bound` will cause an error during AST validation
14351436
// anyways, so treat it like `?Bound` as compilation proceeds.
14361437
GenericBound::Trait(
14371438
_,
14381439
TraitBoundModifier::Maybe
14391440
| TraitBoundModifier::MaybeConstMaybe
1440-
| TraitBoundModifier::MaybeConstNegative,
1441+
| TraitBoundModifier::MaybeConstNegative
1442+
| TraitBoundModifier::ConstMaybe
1443+
| TraitBoundModifier::ConstNegative,
14411444
) => None,
14421445
GenericBound::Outlives(lifetime) => {
14431446
if lifetime_bound.is_none() {
@@ -2176,7 +2179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21762179

21772180
fn lower_trait_ref(
21782181
&mut self,
2179-
constness: ast::Const,
2182+
constness: ast::BoundConstness,
21802183
p: &TraitRef,
21812184
itctx: &ImplTraitContext,
21822185
) -> hir::TraitRef<'hir> {
@@ -2199,7 +2202,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21992202
&mut self,
22002203
p: &PolyTraitRef,
22012204
itctx: &ImplTraitContext,
2202-
constness: ast::Const,
2205+
constness: ast::BoundConstness,
22032206
) -> hir::PolyTraitRef<'hir> {
22042207
let bound_generic_params =
22052208
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
@@ -2323,6 +2326,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23232326
fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier {
23242327
match f {
23252328
TraitBoundModifier::None => hir::TraitBoundModifier::None,
2329+
TraitBoundModifier::Const(_) => hir::TraitBoundModifier::Const,
23262330
TraitBoundModifier::MaybeConst(_) => hir::TraitBoundModifier::MaybeConst,
23272331

23282332
TraitBoundModifier::Negative => {
@@ -2333,12 +2337,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23332337
}
23342338
}
23352339

2336-
// `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a
2340+
// `{,Maybe}ConstMaybe` will cause an error during AST validation, but we need to pick a
23372341
// placeholder for compilation to proceed.
2338-
TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
2339-
hir::TraitBoundModifier::Maybe
2340-
}
2342+
TraitBoundModifier::ConstMaybe
2343+
| TraitBoundModifier::MaybeConstMaybe
2344+
| TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
23412345
TraitBoundModifier::MaybeConstNegative => hir::TraitBoundModifier::MaybeConst,
2346+
TraitBoundModifier::ConstNegative => hir::TraitBoundModifier::Const,
23422347
}
23432348
}
23442349

@@ -2556,45 +2561,62 @@ struct GenericArgsCtor<'hir> {
25562561
}
25572562

25582563
impl<'hir> GenericArgsCtor<'hir> {
2559-
fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
2564+
fn push_constness(
2565+
&mut self,
2566+
lcx: &mut LoweringContext<'_, 'hir>,
2567+
constness: ast::BoundConstness,
2568+
) {
25602569
if !lcx.tcx.features().effects {
25612570
return;
25622571
}
25632572

2564-
// if bound is non-const, don't add host effect param
2565-
let ast::Const::Yes(span) = constness else { return };
2573+
let (span, body) = match constness {
2574+
BoundConstness::Never => return,
2575+
BoundConstness::Always(span) => {
2576+
let span = lcx.lower_span(span);
25662577

2567-
let span = lcx.lower_span(span);
2578+
let body = hir::ExprKind::Lit(
2579+
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }),
2580+
);
25682581

2569-
let id = lcx.next_node_id();
2570-
let hir_id = lcx.next_id();
2582+
(span, body)
2583+
}
2584+
BoundConstness::Maybe(span) => {
2585+
let span = lcx.lower_span(span);
25712586

2572-
let Some(host_param_id) = lcx.host_param_id else {
2573-
lcx.tcx.sess.span_delayed_bug(
2574-
span,
2575-
"no host param id for call in const yet no errors reported",
2576-
);
2577-
return;
2578-
};
2587+
let Some(host_param_id) = lcx.host_param_id else {
2588+
lcx.tcx.sess.span_delayed_bug(
2589+
span,
2590+
"no host param id for call in const yet no errors reported",
2591+
);
2592+
return;
2593+
};
25792594

2580-
let body = lcx.lower_body(|lcx| {
2581-
(&[], {
25822595
let hir_id = lcx.next_id();
25832596
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
2584-
let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
2597+
let body = hir::ExprKind::Path(hir::QPath::Resolved(
25852598
None,
25862599
lcx.arena.alloc(hir::Path {
25872600
span,
25882601
res,
2589-
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
2590-
name: sym::host,
2591-
span,
2592-
}, hir_id, res)],
2602+
segments: arena_vec![
2603+
lcx;
2604+
hir::PathSegment::new(
2605+
Ident { name: sym::host, span },
2606+
hir_id,
2607+
res
2608+
)
2609+
],
25932610
}),
25942611
));
2595-
lcx.expr(span, expr_kind)
2596-
})
2597-
});
2612+
2613+
(span, body)
2614+
}
2615+
};
2616+
let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body)));
2617+
2618+
let id = lcx.next_node_id();
2619+
let hir_id = lcx.next_id();
25982620

25992621
let def_id = lcx.create_def(
26002622
lcx.current_hir_id_owner.def_id,

compiler/rustc_ast_lowering/src/path.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
2525
param_mode: ParamMode,
2626
itctx: &ImplTraitContext,
2727
// constness of the impl/bound if this is a trait path
28-
constness: Option<ast::Const>,
28+
constness: Option<ast::BoundConstness>,
2929
) -> hir::QPath<'hir> {
3030
let qself_position = qself.as_ref().map(|q| q.position);
3131
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
@@ -179,7 +179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
179179
param_mode: ParamMode,
180180
parenthesized_generic_args: ParenthesizedGenericArgs,
181181
itctx: &ImplTraitContext,
182-
constness: Option<ast::Const>,
182+
constness: Option<ast::BoundConstness>,
183183
) -> hir::PathSegment<'hir> {
184184
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
185185
let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {

compiler/rustc_ast_passes/messages.ftl

+4-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadi
4646
.const = `const` because of this
4747
.variadic = C-variadic because of this
4848
49+
ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types
50+
4951
ast_passes_const_without_body =
5052
free constant item without body
5153
.suggestion = provide a definition for the constant
@@ -181,6 +183,8 @@ ast_passes_match_arm_with_no_body =
181183
ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
182184
.help = consider using the `#[path]` attribute to specify filesystem path
183185
186+
ast_passes_mutually_exclusive_trait_bound_modifiers = `{$left}` and `{$right}` are mutually exclusive
187+
184188
ast_passes_negative_bound_not_supported =
185189
negative bounds are not supported
186190
@@ -195,8 +199,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
195199
ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
196200
.help = use `auto trait Trait {"{}"}` instead
197201
198-
ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive
199-
200202
ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
201203
202204
ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits

compiler/rustc_ast_passes/src/ast_validation.rs

+21-9
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12071207
(BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
12081208
self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
12091209
}
1210+
(BoundKind::TraitObject, TraitBoundModifier::Const(_)) => {
1211+
self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span });
1212+
}
12101213
(_, &TraitBoundModifier::MaybeConst(span))
12111214
if let Some(reason) = &self.disallow_tilde_const =>
12121215
{
@@ -1235,16 +1238,25 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12351238
};
12361239
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
12371240
}
1238-
(_, TraitBoundModifier::MaybeConstMaybe) => {
1239-
self.dcx().emit_err(errors::OptionalConstExclusive {
1240-
span: bound.span(),
1241-
modifier: "?",
1242-
});
1243-
}
1244-
(_, TraitBoundModifier::MaybeConstNegative) => {
1245-
self.dcx().emit_err(errors::OptionalConstExclusive {
1241+
(
1242+
_,
1243+
TraitBoundModifier::ConstMaybe
1244+
| TraitBoundModifier::ConstNegative
1245+
| TraitBoundModifier::MaybeConstMaybe
1246+
| TraitBoundModifier::MaybeConstNegative,
1247+
) => {
1248+
let (left, right) = match modify {
1249+
TraitBoundModifier::ConstMaybe => ("const", "?"),
1250+
TraitBoundModifier::ConstNegative => ("const", "!"),
1251+
TraitBoundModifier::MaybeConstMaybe => ("~const", "?"),
1252+
TraitBoundModifier::MaybeConstNegative => ("~const", "!"),
1253+
_ => unreachable!("unexpected trait bound modifier"),
1254+
};
1255+
1256+
self.dcx().emit_err(errors::MutuallyExclusiveTraitBoundModifiers {
12461257
span: bound.span(),
1247-
modifier: "!",
1258+
left,
1259+
right,
12481260
});
12491261
}
12501262
_ => {}

compiler/rustc_ast_passes/src/errors.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,13 @@ pub struct OptionalTraitObject {
540540
pub span: Span,
541541
}
542542

543+
#[derive(Diagnostic)]
544+
#[diag(ast_passes_const_bound_trait_object)]
545+
pub struct ConstBoundTraitObject {
546+
#[primary_span]
547+
pub span: Span,
548+
}
549+
543550
#[derive(Diagnostic)]
544551
#[diag(ast_passes_tilde_const_disallowed)]
545552
pub struct TildeConstDisallowed {
@@ -580,11 +587,12 @@ pub enum TildeConstReason {
580587
}
581588

582589
#[derive(Diagnostic)]
583-
#[diag(ast_passes_optional_const_exclusive)]
584-
pub struct OptionalConstExclusive {
590+
#[diag(ast_passes_mutually_exclusive_trait_bound_modifiers)]
591+
pub struct MutuallyExclusiveTraitBoundModifiers {
585592
#[primary_span]
586593
pub span: Span,
587-
pub modifier: &'static str,
594+
pub left: &'static str,
595+
pub right: &'static str,
588596
}
589597

590598
#[derive(Diagnostic)]

compiler/rustc_ast_pretty/src/pprust/state.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1567,6 +1567,17 @@ impl<'a> State<'a> {
15671567
TraitBoundModifier::Maybe => {
15681568
self.word("?");
15691569
}
1570+
TraitBoundModifier::Const(_) => {
1571+
self.word_space("const");
1572+
}
1573+
TraitBoundModifier::ConstNegative => {
1574+
self.word_space("const");
1575+
self.word("!");
1576+
}
1577+
TraitBoundModifier::ConstMaybe => {
1578+
self.word_space("const");
1579+
self.word("?");
1580+
}
15701581
TraitBoundModifier::MaybeConst(_) => {
15711582
self.word_space("~const");
15721583
}

compiler/rustc_hir/src/hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ pub enum TraitBoundModifier {
425425
None,
426426
Negative,
427427
Maybe,
428+
Const,
428429
MaybeConst,
429430
}
430431

compiler/rustc_hir_analysis/messages.ftl

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s
7070
hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found
7171
7272
hir_analysis_const_bound_for_non_const_trait =
73-
~const can only be applied to `#[const_trait]` traits
73+
{$modifier} can only be applied to `#[const_trait]` traits
7474
7575
hir_analysis_const_impl_for_non_const_trait =
7676
const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`

0 commit comments

Comments
 (0)