Skip to content

Commit ac50a53

Browse files
committed
Auto merge of #88328 - fee1-dead:not-quite-const, r=oli-obk
Introduce `~const` - [x] Removed `?const` and change uses of `?const` - [x] Added `~const` to the AST. It is gated behind const_trait_impl. - [x] Validate `~const` in ast_validation. - [x] Update UI Tests - [x] Add enum `BoundConstness` (With variants `NotConst` and `ConstIfConst` allowing future extensions) - [x] Adjust trait selection and pre-existing code to use `BoundConstness`. - [ ] Optional steps for this PR - [x] Fix #88155 - [x] ~~Do something with constness bounds in chalk~~ Must be done to rust-lang/chalk (just tried to refactor, there are a lot of errors to resolve :( ) - [ ] Adjust Error messages for `~const` bounds that can't be satisfied. r? `@oli-obk`
2 parents dfd8472 + 2d7dbf2 commit ac50a53

File tree

79 files changed

+501
-545
lines changed

Some content is hidden

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

79 files changed

+501
-545
lines changed

compiler/rustc_ast/src/ast.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ impl ParenthesizedArgs {
284284

285285
pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
286286

287-
/// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
287+
/// A modifier on a bound, e.g., `?Sized` or `~const Trait`.
288288
///
289289
/// Negative bounds should also be handled here.
290290
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
@@ -295,10 +295,10 @@ pub enum TraitBoundModifier {
295295
/// `?Trait`
296296
Maybe,
297297

298-
/// `?const Trait`
298+
/// `~const Trait`
299299
MaybeConst,
300300

301-
/// `?const ?Trait`
301+
/// `~const ?Trait`
302302
//
303303
// This parses but will be rejected during AST validation.
304304
MaybeConstMaybe,

compiler/rustc_ast_lowering/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1414,7 +1414,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14141414
ref ty,
14151415
TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
14161416
) => Some(this.lower_poly_trait_ref(ty, itctx.reborrow())),
1417-
// `?const ?Bound` will cause an error during AST validation
1417+
// `~const ?Bound` will cause an error during AST validation
14181418
// anyways, so treat it like `?Bound` as compilation proceeds.
14191419
GenericBound::Trait(
14201420
_,

compiler/rustc_ast_passes/src/ast_validation.rs

+90-51
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,6 @@ enum SelfSemantic {
3333
No,
3434
}
3535

36-
/// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
37-
#[derive(Clone, Copy)]
38-
enum BoundContext {
39-
ImplTrait,
40-
TraitBounds,
41-
TraitObject,
42-
}
43-
44-
impl BoundContext {
45-
fn description(&self) -> &'static str {
46-
match self {
47-
Self::ImplTrait => "`impl Trait`",
48-
Self::TraitBounds => "supertraits",
49-
Self::TraitObject => "trait objects",
50-
}
51-
}
52-
}
53-
5436
struct AstValidator<'a> {
5537
session: &'a Session,
5638

@@ -60,18 +42,16 @@ struct AstValidator<'a> {
6042
/// Are we inside a trait impl?
6143
in_trait_impl: bool,
6244

45+
in_const_trait_impl: bool,
46+
6347
has_proc_macro_decls: bool,
6448

6549
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
6650
/// Nested `impl Trait` _is_ allowed in associated type position,
6751
/// e.g., `impl Iterator<Item = impl Debug>`.
6852
outer_impl_trait: Option<Span>,
6953

70-
/// Keeps track of the `BoundContext` as we recurse.
71-
///
72-
/// This is used to forbid `?const Trait` bounds in, e.g.,
73-
/// `impl Iterator<Item = Box<dyn ?const Trait>`.
74-
bound_context: Option<BoundContext>,
54+
is_tilde_const_allowed: bool,
7555

7656
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
7757
/// or `Foo::Bar<impl Trait>`
@@ -88,10 +68,18 @@ struct AstValidator<'a> {
8868
}
8969

9070
impl<'a> AstValidator<'a> {
91-
fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
71+
fn with_in_trait_impl(
72+
&mut self,
73+
is_in: bool,
74+
constness: Option<Const>,
75+
f: impl FnOnce(&mut Self),
76+
) {
9277
let old = mem::replace(&mut self.in_trait_impl, is_in);
78+
let old_const =
79+
mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
9380
f(self);
9481
self.in_trait_impl = old;
82+
self.in_const_trait_impl = old_const;
9583
}
9684

9785
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
@@ -100,6 +88,18 @@ impl<'a> AstValidator<'a> {
10088
self.is_impl_trait_banned = old;
10189
}
10290

91+
fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
92+
let old = mem::replace(&mut self.is_tilde_const_allowed, true);
93+
f(self);
94+
self.is_tilde_const_allowed = old;
95+
}
96+
97+
fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
98+
let old = mem::replace(&mut self.is_tilde_const_allowed, false);
99+
f(self);
100+
self.is_tilde_const_allowed = old;
101+
}
102+
103103
fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
104104
let old = mem::replace(&mut self.is_let_allowed, allowed);
105105
f(self, old);
@@ -130,19 +130,13 @@ impl<'a> AstValidator<'a> {
130130
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
131131
let old = mem::replace(&mut self.outer_impl_trait, outer);
132132
if outer.is_some() {
133-
self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
133+
self.with_banned_tilde_const(f);
134134
} else {
135-
f(self)
135+
f(self);
136136
}
137137
self.outer_impl_trait = old;
138138
}
139139

140-
fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
141-
let old = self.bound_context.replace(ctx);
142-
f(self);
143-
self.bound_context = old;
144-
}
145-
146140
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
147141
match constraint.kind {
148142
AssocTyConstraintKind::Equality { .. } => {}
@@ -164,9 +158,7 @@ impl<'a> AstValidator<'a> {
164158
TyKind::ImplTrait(..) => {
165159
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
166160
}
167-
TyKind::TraitObject(..) => {
168-
self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
169-
}
161+
TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
170162
TyKind::Path(ref qself, ref path) => {
171163
// We allow these:
172164
// - `Option<impl Trait>`
@@ -1083,13 +1075,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10831075
unsafety,
10841076
polarity,
10851077
defaultness: _,
1086-
constness: _,
1087-
generics: _,
1078+
constness,
1079+
ref generics,
10881080
of_trait: Some(ref t),
10891081
ref self_ty,
1090-
items: _,
1082+
ref items,
10911083
}) => {
1092-
self.with_in_trait_impl(true, |this| {
1084+
self.with_in_trait_impl(true, Some(constness), |this| {
10931085
this.invalid_visibility(&item.vis, None);
10941086
if let TyKind::Err = self_ty.kind {
10951087
this.err_handler()
@@ -1112,7 +1104,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11121104
.emit();
11131105
}
11141106

1115-
visit::walk_item(this, item);
1107+
this.visit_vis(&item.vis);
1108+
this.visit_ident(item.ident);
1109+
if let Const::Yes(_) = constness {
1110+
this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1111+
} else {
1112+
this.visit_generics(generics);
1113+
}
1114+
this.visit_trait_ref(t);
1115+
this.visit_ty(self_ty);
1116+
1117+
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
11161118
});
11171119
return; // Avoid visiting again.
11181120
}
@@ -1157,13 +1159,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11571159
.emit();
11581160
}
11591161
}
1160-
ItemKind::Fn(box FnKind(def, _, _, ref body)) => {
1162+
ItemKind::Fn(box FnKind(def, ref sig, ref generics, ref body)) => {
11611163
self.check_defaultness(item.span, def);
11621164

11631165
if body.is_none() {
11641166
let msg = "free function without a body";
11651167
self.error_item_without_body(item.span, "function", msg, " { <body> }");
11661168
}
1169+
self.visit_vis(&item.vis);
1170+
self.visit_ident(item.ident);
1171+
if let Const::Yes(_) = sig.header.constness {
1172+
self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1173+
} else {
1174+
self.visit_generics(generics);
1175+
}
1176+
let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
1177+
self.visit_fn(kind, item.span, item.id);
1178+
walk_list!(self, visit_attribute, &item.attrs);
1179+
return; // Avoid visiting again.
11671180
}
11681181
ItemKind::ForeignMod(ForeignMod { unsafety, .. }) => {
11691182
let old_item = mem::replace(&mut self.extern_mod, Some(item));
@@ -1206,9 +1219,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12061219
self.visit_vis(&item.vis);
12071220
self.visit_ident(item.ident);
12081221
self.visit_generics(generics);
1209-
self.with_bound_context(BoundContext::TraitBounds, |this| {
1210-
walk_list!(this, visit_param_bound, bounds);
1211-
});
1222+
self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
12121223
walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
12131224
walk_list!(self, visit_attribute, &item.attrs);
12141225
return;
@@ -1281,7 +1292,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12811292
_ => {}
12821293
}
12831294

1284-
visit::walk_item(self, item)
1295+
visit::walk_item(self, item);
12851296
}
12861297

12871298
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
@@ -1428,15 +1439,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14281439
fn visit_param_bound(&mut self, bound: &'a GenericBound) {
14291440
match bound {
14301441
GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1431-
if let Some(ctx) = self.bound_context {
1432-
let msg = format!("`?const` is not permitted in {}", ctx.description());
1433-
self.err_handler().span_err(bound.span(), &msg);
1442+
if !self.is_tilde_const_allowed {
1443+
self.err_handler()
1444+
.struct_span_err(bound.span(), "`~const` is not allowed here")
1445+
.note("only allowed on bounds on traits' associated types, const fns, const impls and its associated functions")
1446+
.emit();
14341447
}
14351448
}
14361449

14371450
GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
14381451
self.err_handler()
1439-
.span_err(bound.span(), "`?const` and `?` are mutually exclusive");
1452+
.span_err(bound.span(), "`~const` and `?` are mutually exclusive");
14401453
}
14411454

14421455
_ => {}
@@ -1589,7 +1602,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
15891602
self.check_item_named(item.ident, "const");
15901603
}
15911604

1592-
self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
1605+
match item.kind {
1606+
AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty))
1607+
if ctxt == AssocCtxt::Trait =>
1608+
{
1609+
self.visit_vis(&item.vis);
1610+
self.visit_ident(item.ident);
1611+
walk_list!(self, visit_attribute, &item.attrs);
1612+
self.with_tilde_const_allowed(|this| {
1613+
this.visit_generics(generics);
1614+
walk_list!(this, visit_param_bound, bounds);
1615+
});
1616+
walk_list!(self, visit_ty, ty);
1617+
}
1618+
AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body))
1619+
if self.in_const_trait_impl =>
1620+
{
1621+
self.visit_vis(&item.vis);
1622+
self.visit_ident(item.ident);
1623+
self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1624+
let kind =
1625+
FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
1626+
self.visit_fn(kind, item.span, item.id);
1627+
}
1628+
_ => self
1629+
.with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1630+
}
15931631
}
15941632
}
15951633

@@ -1683,9 +1721,10 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
16831721
session,
16841722
extern_mod: None,
16851723
in_trait_impl: false,
1724+
in_const_trait_impl: false,
16861725
has_proc_macro_decls: false,
16871726
outer_impl_trait: None,
1688-
bound_context: None,
1727+
is_tilde_const_allowed: false,
16891728
is_impl_trait_banned: false,
16901729
is_assoc_ty_bound_banned: false,
16911730
is_let_allowed: false,

compiler/rustc_ast_passes/src/feature_gate.rs

-1
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
656656
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
657657
gate_all!(generators, "yield syntax is experimental");
658658
gate_all!(raw_ref_op, "raw address of syntax is experimental");
659-
gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
660659
gate_all!(const_trait_impl, "const trait impls are experimental");
661660
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
662661
gate_all!(inline_const, "inline-const is experimental");

compiler/rustc_feature/src/active.rs

-3
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,6 @@ declare_features! (
515515
/// Allows `impl const Trait for T` syntax.
516516
(active, const_trait_impl, "1.42.0", Some(67792), None),
517517

518-
/// Allows `T: ?const Trait` syntax in bounds.
519-
(incomplete, const_trait_bound_opt_out, "1.42.0", Some(67794), None),
520-
521518
/// Allows the use of `no_sanitize` attribute.
522519
(active, no_sanitize, "1.42.0", Some(39699), None),
523520

compiler/rustc_feature/src/removed.rs

+3
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ declare_features! (
123123
/// Allows overlapping impls of marker traits.
124124
(removed, overlapping_marker_traits, "1.42.0", Some(29864), None,
125125
Some("removed in favor of `#![feature(marker_trait_attr)]`")),
126+
/// Allows `T: ?const Trait` syntax in bounds.
127+
(removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None,
128+
Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")),
126129
/// Allows `#[no_debug]`.
127130
(removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
128131
/// Allows comparing raw pointers during const eval.

compiler/rustc_middle/src/traits/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use rustc_data_structures::sync::Lrc;
1717
use rustc_errors::{Applicability, DiagnosticBuilder};
1818
use rustc_hir as hir;
1919
use rustc_hir::def_id::{DefId, LocalDefId};
20-
use rustc_hir::Constness;
2120
use rustc_span::symbol::Symbol;
2221
use rustc_span::{Span, DUMMY_SP};
2322
use smallvec::SmallVec;
@@ -497,7 +496,7 @@ pub enum ImplSource<'tcx, N> {
497496
/// for some type parameter. The `Vec<N>` represents the
498497
/// obligations incurred from normalizing the where-clause (if
499498
/// any).
500-
Param(Vec<N>, Constness),
499+
Param(Vec<N>, ty::BoundConstness),
501500

502501
/// Virtual calls through an object.
503502
Object(ImplSourceObjectData<'tcx, N>),

compiler/rustc_middle/src/ty/error.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl<T> ExpectedFound<T> {
3333
#[derive(Clone, Debug, TypeFoldable)]
3434
pub enum TypeError<'tcx> {
3535
Mismatch,
36-
ConstnessMismatch(ExpectedFound<hir::Constness>),
36+
ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
3737
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
3838
AbiMismatch(ExpectedFound<abi::Abi>),
3939
Mutability,
@@ -102,7 +102,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
102102
CyclicConst(_) => write!(f, "encountered a self-referencing constant"),
103103
Mismatch => write!(f, "types differ"),
104104
ConstnessMismatch(values) => {
105-
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
105+
write!(f, "expected {} bound, found {} bound", values.expected, values.found)
106106
}
107107
UnsafetyMismatch(values) => {
108108
write!(f, "expected {} fn, found {} fn", values.expected, values.found)

0 commit comments

Comments
 (0)