Skip to content

Commit 47dbdfc

Browse files
committed
Auto merge of rust-lang#119099 - fmease:always-const-trait-bounds, r=fee1-dead
Introduce `const Trait` (always-const trait bounds) Feature `const_trait_impl` currently lacks a way to express “always const” trait bounds. This makes it impossible to define generic items like fns or structs which contain types that depend on const method calls (\*). While the final design and esp. the syntax of effects / keyword generics isn't set in stone, some version of “always const” trait bounds will very likely form a part of it. Further, their implementation is trivial thanks to the `effects` backbone. Not sure if this needs t-lang sign-off though. (\*): ```rs #![feature(const_trait_impl, effects, generic_const_exprs)] fn compute<T: const Trait>() -> Type<{ T::generate() }> { /*…*/ } struct Store<T: const Trait> where Type<{ T::generate() }>:, { field: Type<{ T::generate() }>, } ``` Lastly, “always const” trait bounds are a perfect fit for `generic_const_items`. ```rs #![feature(const_trait_impl, effects, generic_const_items)] const DEFAULT<T: const Default>: T = T::default(); ``` Previously, we (oli, fee1-dead and I) wanted to reinterpret `~const Trait` as `const Trait` in generic const items which would've been quite surprising and not very generalizable. Supersedes rust-lang#117530. --- cc `@oli-obk` As discussed r? fee1-dead (or compiler)
2 parents ca9ff83 + 3eb48a3 commit 47dbdfc

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
@@ -1349,7 +1349,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13491349
span: t.span,
13501350
},
13511351
itctx,
1352-
ast::Const::No,
1352+
ast::BoundConstness::Never,
13531353
);
13541354
let bounds = this.arena.alloc_from_iter([bound]);
13551355
let lifetime_bound = this.elided_dyn_bound(t.span);
@@ -1460,7 +1460,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14601460
polarity: BoundPolarity::Positive | BoundPolarity::Negative(_),
14611461
constness,
14621462
},
1463-
) => Some(this.lower_poly_trait_ref(ty, itctx, (*constness).into())),
1463+
) => Some(this.lower_poly_trait_ref(ty, itctx, *constness)),
14641464
// We can safely ignore constness here, since AST validation
14651465
// will take care of invalid modifier combinations.
14661466
GenericBound::Trait(
@@ -2199,7 +2199,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21992199

22002200
fn lower_trait_ref(
22012201
&mut self,
2202-
constness: ast::Const,
2202+
constness: ast::BoundConstness,
22032203
p: &TraitRef,
22042204
itctx: &ImplTraitContext,
22052205
) -> hir::TraitRef<'hir> {
@@ -2222,7 +2222,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
22222222
&mut self,
22232223
p: &PolyTraitRef,
22242224
itctx: &ImplTraitContext,
2225-
constness: ast::Const,
2225+
constness: ast::BoundConstness,
22262226
) -> hir::PolyTraitRef<'hir> {
22272227
let bound_generic_params =
22282228
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
@@ -2347,25 +2347,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23472347
&mut self,
23482348
modifiers: TraitBoundModifiers,
23492349
) -> hir::TraitBoundModifier {
2350+
// Invalid modifier combinations will cause an error during AST validation.
2351+
// Arbitrarily pick a placeholder for them to make compilation proceed.
23502352
match (modifiers.constness, modifiers.polarity) {
23512353
(BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
2352-
(BoundConstness::Never, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
2354+
(_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
23532355
(BoundConstness::Never, BoundPolarity::Negative(_)) => {
23542356
if self.tcx.features().negative_bounds {
23552357
hir::TraitBoundModifier::Negative
23562358
} else {
23572359
hir::TraitBoundModifier::None
23582360
}
23592361
}
2360-
(BoundConstness::Maybe(_), BoundPolarity::Positive) => {
2361-
hir::TraitBoundModifier::MaybeConst
2362-
}
2363-
// Invalid modifier combinations will cause an error during AST validation.
2364-
// Arbitrarily pick a placeholder for compilation to proceed.
2365-
(BoundConstness::Maybe(_), BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
2366-
(BoundConstness::Maybe(_), BoundPolarity::Negative(_)) => {
2367-
hir::TraitBoundModifier::MaybeConst
2368-
}
2362+
(BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
2363+
(BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
23692364
}
23702365
}
23712366

@@ -2583,45 +2578,62 @@ struct GenericArgsCtor<'hir> {
25832578
}
25842579

25852580
impl<'hir> GenericArgsCtor<'hir> {
2586-
fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
2581+
fn push_constness(
2582+
&mut self,
2583+
lcx: &mut LoweringContext<'_, 'hir>,
2584+
constness: ast::BoundConstness,
2585+
) {
25872586
if !lcx.tcx.features().effects {
25882587
return;
25892588
}
25902589

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

2594-
let span = lcx.lower_span(span);
2595+
let body = hir::ExprKind::Lit(
2596+
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }),
2597+
);
25952598

2596-
let id = lcx.next_node_id();
2597-
let hir_id = lcx.next_id();
2599+
(span, body)
2600+
}
2601+
BoundConstness::Maybe(span) => {
2602+
let span = lcx.lower_span(span);
25982603

2599-
let Some(host_param_id) = lcx.host_param_id else {
2600-
lcx.dcx().span_delayed_bug(
2601-
span,
2602-
"no host param id for call in const yet no errors reported",
2603-
);
2604-
return;
2605-
};
2604+
let Some(host_param_id) = lcx.host_param_id else {
2605+
lcx.dcx().span_delayed_bug(
2606+
span,
2607+
"no host param id for call in const yet no errors reported",
2608+
);
2609+
return;
2610+
};
26062611

2607-
let body = lcx.lower_body(|lcx| {
2608-
(&[], {
26092612
let hir_id = lcx.next_id();
26102613
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
2611-
let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
2614+
let body = hir::ExprKind::Path(hir::QPath::Resolved(
26122615
None,
26132616
lcx.arena.alloc(hir::Path {
26142617
span,
26152618
res,
2616-
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
2617-
name: sym::host,
2618-
span,
2619-
}, hir_id, res)],
2619+
segments: arena_vec![
2620+
lcx;
2621+
hir::PathSegment::new(
2622+
Ident { name: sym::host, span },
2623+
hir_id,
2624+
res
2625+
)
2626+
],
26202627
}),
26212628
));
2622-
lcx.expr(span, expr_kind)
2623-
})
2624-
});
2629+
2630+
(span, body)
2631+
}
2632+
};
2633+
let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body)));
2634+
2635+
let id = lcx.next_node_id();
2636+
let hir_id = lcx.next_id();
26252637

26262638
let def_id = lcx.create_def(
26272639
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)