Skip to content

Commit 3eb48a3

Browse files
committed
Introduce const Trait (always-const trait bounds)
1 parent 2fe50cd commit 3eb48a3

File tree

69 files changed

+505
-223
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+505
-223
lines changed

compiler/rustc_ast/src/ast.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -2481,15 +2481,6 @@ pub enum Const {
24812481
No,
24822482
}
24832483

2484-
impl From<BoundConstness> for Const {
2485-
fn from(constness: BoundConstness) -> Self {
2486-
match constness {
2487-
BoundConstness::Maybe(span) => Self::Yes(span),
2488-
BoundConstness::Never => Self::No,
2489-
}
2490-
}
2491-
}
2492-
24932484
/// Item defaultness.
24942485
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
24952486
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
@@ -2543,6 +2534,8 @@ impl BoundPolarity {
25432534
pub enum BoundConstness {
25442535
/// `Type: Trait`
25452536
Never,
2537+
/// `Type: const Trait`
2538+
Always(Span),
25462539
/// `Type: ~const Trait`
25472540
Maybe(Span),
25482541
}
@@ -2551,6 +2544,7 @@ impl BoundConstness {
25512544
pub fn as_str(self) -> &'static str {
25522545
match self {
25532546
Self::Never => "",
2547+
Self::Always(_) => "const",
25542548
Self::Maybe(_) => "~const",
25552549
}
25562550
}

compiler/rustc_ast/src/token.rs

-9
Original file line numberDiff line numberDiff line change
@@ -528,15 +528,6 @@ impl Token {
528528
}
529529
}
530530

531-
/// Returns `true` if the token can appear at the start of a generic bound.
532-
pub fn can_begin_bound(&self) -> bool {
533-
self.is_path_start()
534-
|| self.is_lifetime()
535-
|| self.is_keyword(kw::For)
536-
|| self == &Question
537-
|| self == &OpenDelim(Delimiter::Parenthesis)
538-
}
539-
540531
/// Returns `true` if the token can appear at the start of an item.
541532
pub fn can_begin_item(&self) -> bool {
542533
match self.kind {

compiler/rustc_ast_lowering/src/item.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
339339
let itctx = ImplTraitContext::Universal;
340340
let (generics, (trait_ref, lowered_ty)) =
341341
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
342+
let constness = match *constness {
343+
Const::Yes(span) => BoundConstness::Maybe(span),
344+
Const::No => BoundConstness::Never,
345+
};
346+
342347
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
343348
this.lower_trait_ref(
344-
*constness,
349+
constness,
345350
trait_ref,
346351
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
347352
)

compiler/rustc_ast_lowering/src/lib.rs

+49-37
Original file line numberDiff line numberDiff line change
@@ -1324,7 +1324,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13241324
span: t.span,
13251325
},
13261326
itctx,
1327-
ast::Const::No,
1327+
ast::BoundConstness::Never,
13281328
);
13291329
let bounds = this.arena.alloc_from_iter([bound]);
13301330
let lifetime_bound = this.elided_dyn_bound(t.span);
@@ -1435,7 +1435,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14351435
polarity: BoundPolarity::Positive | BoundPolarity::Negative(_),
14361436
constness,
14371437
},
1438-
) => Some(this.lower_poly_trait_ref(ty, itctx, (*constness).into())),
1438+
) => Some(this.lower_poly_trait_ref(ty, itctx, *constness)),
14391439
// We can safely ignore constness here, since AST validation
14401440
// will take care of invalid modifier combinations.
14411441
GenericBound::Trait(
@@ -2174,7 +2174,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21742174

21752175
fn lower_trait_ref(
21762176
&mut self,
2177-
constness: ast::Const,
2177+
constness: ast::BoundConstness,
21782178
p: &TraitRef,
21792179
itctx: &ImplTraitContext,
21802180
) -> hir::TraitRef<'hir> {
@@ -2197,7 +2197,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21972197
&mut self,
21982198
p: &PolyTraitRef,
21992199
itctx: &ImplTraitContext,
2200-
constness: ast::Const,
2200+
constness: ast::BoundConstness,
22012201
) -> hir::PolyTraitRef<'hir> {
22022202
let bound_generic_params =
22032203
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
@@ -2322,25 +2322,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23222322
&mut self,
23232323
modifiers: TraitBoundModifiers,
23242324
) -> hir::TraitBoundModifier {
2325+
// Invalid modifier combinations will cause an error during AST validation.
2326+
// Arbitrarily pick a placeholder for them to make compilation proceed.
23252327
match (modifiers.constness, modifiers.polarity) {
23262328
(BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
2327-
(BoundConstness::Never, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
2329+
(_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
23282330
(BoundConstness::Never, BoundPolarity::Negative(_)) => {
23292331
if self.tcx.features().negative_bounds {
23302332
hir::TraitBoundModifier::Negative
23312333
} else {
23322334
hir::TraitBoundModifier::None
23332335
}
23342336
}
2335-
(BoundConstness::Maybe(_), BoundPolarity::Positive) => {
2336-
hir::TraitBoundModifier::MaybeConst
2337-
}
2338-
// Invalid modifier combinations will cause an error during AST validation.
2339-
// Arbitrarily pick a placeholder for compilation to proceed.
2340-
(BoundConstness::Maybe(_), BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
2341-
(BoundConstness::Maybe(_), BoundPolarity::Negative(_)) => {
2342-
hir::TraitBoundModifier::MaybeConst
2343-
}
2337+
(BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
2338+
(BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
23442339
}
23452340
}
23462341

@@ -2558,45 +2553,62 @@ struct GenericArgsCtor<'hir> {
25582553
}
25592554

25602555
impl<'hir> GenericArgsCtor<'hir> {
2561-
fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
2556+
fn push_constness(
2557+
&mut self,
2558+
lcx: &mut LoweringContext<'_, 'hir>,
2559+
constness: ast::BoundConstness,
2560+
) {
25622561
if !lcx.tcx.features().effects {
25632562
return;
25642563
}
25652564

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

2569-
let span = lcx.lower_span(span);
2570+
let body = hir::ExprKind::Lit(
2571+
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }),
2572+
);
25702573

2571-
let id = lcx.next_node_id();
2572-
let hir_id = lcx.next_id();
2574+
(span, body)
2575+
}
2576+
BoundConstness::Maybe(span) => {
2577+
let span = lcx.lower_span(span);
25732578

2574-
let Some(host_param_id) = lcx.host_param_id else {
2575-
lcx.dcx().span_delayed_bug(
2576-
span,
2577-
"no host param id for call in const yet no errors reported",
2578-
);
2579-
return;
2580-
};
2579+
let Some(host_param_id) = lcx.host_param_id else {
2580+
lcx.dcx().span_delayed_bug(
2581+
span,
2582+
"no host param id for call in const yet no errors reported",
2583+
);
2584+
return;
2585+
};
25812586

2582-
let body = lcx.lower_body(|lcx| {
2583-
(&[], {
25842587
let hir_id = lcx.next_id();
25852588
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
2586-
let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
2589+
let body = hir::ExprKind::Path(hir::QPath::Resolved(
25872590
None,
25882591
lcx.arena.alloc(hir::Path {
25892592
span,
25902593
res,
2591-
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
2592-
name: sym::host,
2593-
span,
2594-
}, hir_id, res)],
2594+
segments: arena_vec![
2595+
lcx;
2596+
hir::PathSegment::new(
2597+
Ident { name: sym::host, span },
2598+
hir_id,
2599+
res
2600+
)
2601+
],
25952602
}),
25962603
));
2597-
lcx.expr(span, expr_kind)
2598-
})
2599-
});
2604+
2605+
(span, body)
2606+
}
2607+
};
2608+
let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body)));
2609+
2610+
let id = lcx.next_node_id();
2611+
let hir_id = lcx.next_id();
26002612

26012613
let def_id = lcx.create_def(
26022614
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

+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

compiler/rustc_ast_passes/src/ast_validation.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12071207
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
12081208
self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
12091209
}
1210+
(BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => {
1211+
self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span });
1212+
}
12101213
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
12111214
if let Some(reason) = &self.disallow_tilde_const =>
12121215
{
@@ -1237,8 +1240,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12371240
}
12381241
(
12391242
_,
1240-
BoundConstness::Maybe(_),
1241-
BoundPolarity::Maybe(_) | BoundPolarity::Negative(_),
1243+
BoundConstness::Always(_) | BoundConstness::Maybe(_),
1244+
BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
12421245
) => {
12431246
self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
12441247
span: bound.span(),

compiler/rustc_ast_passes/src/errors.rs

+7
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 {

compiler/rustc_ast_pretty/src/pprust/state.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1561,7 +1561,7 @@ impl<'a> State<'a> {
15611561
GenericBound::Trait(tref, modifier) => {
15621562
match modifier.constness {
15631563
ast::BoundConstness::Never => {}
1564-
ast::BoundConstness::Maybe(_) => {
1564+
ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => {
15651565
self.word_space(modifier.constness.as_str());
15661566
}
15671567
}

compiler/rustc_hir/src/hir.rs

+6
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,15 @@ pub enum GenericArgsParentheses {
420420
/// A modifier on a trait bound.
421421
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
422422
pub enum TraitBoundModifier {
423+
/// `Type: Trait`
423424
None,
425+
/// `Type: !Trait`
424426
Negative,
427+
/// `Type: ?Trait`
425428
Maybe,
429+
/// `Type: const Trait`
430+
Const,
431+
/// `Type: ~const Trait`
426432
MaybeConst,
427433
}
428434

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]`

compiler/rustc_hir_analysis/src/astconv/bounds.rs

+3
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
112112
match ast_bound {
113113
hir::GenericBound::Trait(poly_trait_ref, modifier) => {
114114
let (constness, polarity) = match modifier {
115+
hir::TraitBoundModifier::Const => {
116+
(ty::BoundConstness::Const, ty::ImplPolarity::Positive)
117+
}
115118
hir::TraitBoundModifier::MaybeConst => {
116119
(ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
117120
}

compiler/rustc_hir_analysis/src/astconv/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -560,11 +560,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
560560
inferred_params: vec![],
561561
infer_args,
562562
};
563-
if let ty::BoundConstness::ConstIfConst = constness
563+
if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
564564
&& generics.has_self
565565
&& !tcx.has_attr(def_id, sym::const_trait)
566566
{
567-
let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { span });
567+
let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
568+
span,
569+
modifier: constness.as_str(),
570+
});
568571
arg_count.correct =
569572
Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] });
570573
}

compiler/rustc_hir_analysis/src/errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ pub struct ConstImplForNonConstTrait {
408408
pub struct ConstBoundForNonConstTrait {
409409
#[primary_span]
410410
pub span: Span,
411+
pub modifier: &'static str,
411412
}
412413

413414
#[derive(Diagnostic)]

compiler/rustc_middle/src/ty/mod.rs

+10-11
Original file line numberDiff line numberDiff line change
@@ -309,23 +309,22 @@ impl Visibility {
309309

310310
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
311311
pub enum BoundConstness {
312-
/// `T: Trait`
312+
/// `Type: Trait`
313313
NotConst,
314-
/// `T: ~const Trait`
314+
/// `Type: const Trait`
315+
Const,
316+
/// `Type: ~const Trait`
315317
///
316318
/// Requires resolving to const only when we are in a const context.
317319
ConstIfConst,
318320
}
319321

320322
impl BoundConstness {
321-
/// Reduce `self` and `constness` to two possible combined states instead of four.
322-
pub fn and(&mut self, constness: hir::Constness) -> hir::Constness {
323-
match (constness, self) {
324-
(hir::Constness::Const, BoundConstness::ConstIfConst) => hir::Constness::Const,
325-
(_, this) => {
326-
*this = BoundConstness::NotConst;
327-
hir::Constness::NotConst
328-
}
323+
pub fn as_str(self) -> &'static str {
324+
match self {
325+
Self::NotConst => "",
326+
Self::Const => "const",
327+
Self::ConstIfConst => "~const",
329328
}
330329
}
331330
}
@@ -334,7 +333,7 @@ impl fmt::Display for BoundConstness {
334333
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335334
match self {
336335
Self::NotConst => f.write_str("normal"),
337-
Self::ConstIfConst => f.write_str("`~const`"),
336+
_ => write!(f, "`{self}`"),
338337
}
339338
}
340339
}

0 commit comments

Comments
 (0)