Skip to content

Commit aaef5fe

Browse files
committed
Auto merge of rust-lang#119163 - fmease:refactor-ast-trait-bound-modifiers, r=compiler-errors
Refactor AST trait bound modifiers Instead of having two types to represent trait bound modifiers in the parser / the AST (`parser::ty::BoundModifiers` & `ast::TraitBoundModifier`), only to map one to the other later, just use `parser::ty::BoundModifiers` (moved & renamed to `ast::TraitBoundModifiers`). The struct type is more extensible and easier to deal with (see [here](https://github.com/rust-lang/rust/pull/119099/files#r1430749981) and [here](https://github.com/rust-lang/rust/pull/119099/files#r1430752116) for context) since it more closely models what it represents: A compound of two kinds of modifiers, constness and polarity. Modeling this as an enum (the now removed `ast::TraitBoundModifier`) meant one had to add a new variant per *combination* of modifier kind, which simply isn't scalable and which lead to a lot of explicit non-DRY matches. NB: `hir::TraitBoundModifier` being an enum is fine since HIR doesn't need to worry representing invalid modifier kind combinations as those get rejected during AST validation thereby immensely cutting down the number of possibilities.
2 parents cee794e + 5e4f12b commit aaef5fe

File tree

16 files changed

+194
-200
lines changed

16 files changed

+194
-200
lines changed

compiler/rustc_ast/src/ast.rs

+51-36
Original file line numberDiff line numberDiff line change
@@ -286,41 +286,16 @@ impl ParenthesizedArgs {
286286

287287
pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
288288

289-
/// A modifier on a bound, e.g., `?Trait` or `~const Trait`.
290-
///
291-
/// Negative bounds should also be handled here.
289+
/// Modifiers on a trait bound like `~const`, `?` and `!`.
292290
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
293-
pub enum TraitBoundModifier {
294-
/// No modifiers
295-
None,
296-
297-
/// `!Trait`
298-
Negative,
299-
300-
/// `?Trait`
301-
Maybe,
302-
303-
/// `~const Trait`
304-
MaybeConst(Span),
305-
306-
/// `~const !Trait`
307-
//
308-
// This parses but will be rejected during AST validation.
309-
MaybeConstNegative,
310-
311-
/// `~const ?Trait`
312-
//
313-
// This parses but will be rejected during AST validation.
314-
MaybeConstMaybe,
291+
pub struct TraitBoundModifiers {
292+
pub constness: BoundConstness,
293+
pub polarity: BoundPolarity,
315294
}
316295

317-
impl TraitBoundModifier {
318-
pub fn to_constness(self) -> Const {
319-
match self {
320-
Self::MaybeConst(span) => Const::Yes(span),
321-
_ => Const::No,
322-
}
323-
}
296+
impl TraitBoundModifiers {
297+
pub const NONE: Self =
298+
Self { constness: BoundConstness::Never, polarity: BoundPolarity::Positive };
324299
}
325300

326301
/// The AST represents all type param bounds as types.
@@ -329,7 +304,7 @@ impl TraitBoundModifier {
329304
/// detects `Copy`, `Send` and `Sync`.
330305
#[derive(Clone, Encodable, Decodable, Debug)]
331306
pub enum GenericBound {
332-
Trait(PolyTraitRef, TraitBoundModifier),
307+
Trait(PolyTraitRef, TraitBoundModifiers),
333308
Outlives(Lifetime),
334309
}
335310

@@ -1193,7 +1168,7 @@ impl Expr {
11931168
match &self.kind {
11941169
ExprKind::Path(None, path) => Some(GenericBound::Trait(
11951170
PolyTraitRef::new(ThinVec::new(), path.clone(), self.span),
1196-
TraitBoundModifier::None,
1171+
TraitBoundModifiers::NONE,
11971172
)),
11981173
_ => None,
11991174
}
@@ -2491,6 +2466,15 @@ pub enum Const {
24912466
No,
24922467
}
24932468

2469+
impl From<BoundConstness> for Const {
2470+
fn from(constness: BoundConstness) -> Self {
2471+
match constness {
2472+
BoundConstness::Maybe(span) => Self::Yes(span),
2473+
BoundConstness::Never => Self::No,
2474+
}
2475+
}
2476+
}
2477+
24942478
/// Item defaultness.
24952479
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
24962480
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
@@ -2516,7 +2500,9 @@ impl fmt::Debug for ImplPolarity {
25162500
}
25172501
}
25182502

2519-
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
2503+
/// The polarity of a trait bound.
2504+
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
2505+
#[derive(HashStable_Generic)]
25202506
pub enum BoundPolarity {
25212507
/// `Type: Trait`
25222508
Positive,
@@ -2526,6 +2512,35 @@ pub enum BoundPolarity {
25262512
Maybe(Span),
25272513
}
25282514

2515+
impl BoundPolarity {
2516+
pub fn as_str(self) -> &'static str {
2517+
match self {
2518+
Self::Positive => "",
2519+
Self::Negative(_) => "!",
2520+
Self::Maybe(_) => "?",
2521+
}
2522+
}
2523+
}
2524+
2525+
/// The constness of a trait bound.
2526+
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
2527+
#[derive(HashStable_Generic)]
2528+
pub enum BoundConstness {
2529+
/// `Type: Trait`
2530+
Never,
2531+
/// `Type: ~const Trait`
2532+
Maybe(Span),
2533+
}
2534+
2535+
impl BoundConstness {
2536+
pub fn as_str(self) -> &'static str {
2537+
match self {
2538+
Self::Never => "",
2539+
Self::Maybe(_) => "~const",
2540+
}
2541+
}
2542+
}
2543+
25292544
#[derive(Clone, Encodable, Decodable, Debug)]
25302545
pub enum FnRetTy {
25312546
/// Returns type is not specified.
@@ -3259,7 +3274,7 @@ mod size_asserts {
32593274
static_assert_size!(ForeignItem, 96);
32603275
static_assert_size!(ForeignItemKind, 24);
32613276
static_assert_size!(GenericArg, 24);
3262-
static_assert_size!(GenericBound, 64);
3277+
static_assert_size!(GenericBound, 72);
32633278
static_assert_size!(Generics, 40);
32643279
static_assert_size!(Impl, 136);
32653280
static_assert_size!(Item, 136);

compiler/rustc_ast_lowering/src/item.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1372,7 +1372,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
13721372
// need to compute this at all unless there is a Maybe bound.
13731373
let mut is_param: Option<bool> = None;
13741374
for bound in &bound_pred.bounds {
1375-
if !matches!(*bound, GenericBound::Trait(_, TraitBoundModifier::Maybe)) {
1375+
if !matches!(
1376+
*bound,
1377+
GenericBound::Trait(
1378+
_,
1379+
TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. }
1380+
)
1381+
) {
13761382
continue;
13771383
}
13781384
let is_param = *is_param.get_or_insert_with(compute_is_param);

compiler/rustc_ast_lowering/src/lib.rs

+27-26
Original file line numberDiff line numberDiff line change
@@ -1425,19 +1425,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14251425
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
14261426
GenericBound::Trait(
14271427
ty,
1428-
modifier @ (TraitBoundModifier::None
1429-
| TraitBoundModifier::MaybeConst(_)
1430-
| TraitBoundModifier::Negative),
1431-
) => {
1432-
Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness()))
1433-
}
1434-
// `~const ?Bound` will cause an error during AST validation
1435-
// anyways, so treat it like `?Bound` as compilation proceeds.
1428+
TraitBoundModifiers {
1429+
polarity: BoundPolarity::Positive | BoundPolarity::Negative(_),
1430+
constness,
1431+
},
1432+
) => Some(this.lower_poly_trait_ref(ty, itctx, (*constness).into())),
1433+
// We can safely ignore constness here, since AST validation
1434+
// will take care of invalid modifier combinations.
14361435
GenericBound::Trait(
14371436
_,
1438-
TraitBoundModifier::Maybe
1439-
| TraitBoundModifier::MaybeConstMaybe
1440-
| TraitBoundModifier::MaybeConstNegative,
1437+
TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. },
14411438
) => None,
14421439
GenericBound::Outlives(lifetime) => {
14431440
if lifetime_bound.is_none() {
@@ -2028,9 +2025,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20282025
itctx: &ImplTraitContext,
20292026
) -> hir::GenericBound<'hir> {
20302027
match tpb {
2031-
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
2032-
self.lower_poly_trait_ref(p, itctx, modifier.to_constness()),
2033-
self.lower_trait_bound_modifier(*modifier),
2028+
GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait(
2029+
self.lower_poly_trait_ref(p, itctx, modifiers.constness.into()),
2030+
self.lower_trait_bound_modifiers(*modifiers),
20342031
),
20352032
GenericBound::Outlives(lifetime) => {
20362033
hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
@@ -2316,25 +2313,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23162313
}
23172314
}
23182315

2319-
fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier {
2320-
match f {
2321-
TraitBoundModifier::None => hir::TraitBoundModifier::None,
2322-
TraitBoundModifier::MaybeConst(_) => hir::TraitBoundModifier::MaybeConst,
2323-
2324-
TraitBoundModifier::Negative => {
2316+
fn lower_trait_bound_modifiers(
2317+
&mut self,
2318+
modifiers: TraitBoundModifiers,
2319+
) -> hir::TraitBoundModifier {
2320+
match (modifiers.constness, modifiers.polarity) {
2321+
(BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
2322+
(BoundConstness::Never, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
2323+
(BoundConstness::Never, BoundPolarity::Negative(_)) => {
23252324
if self.tcx.features().negative_bounds {
23262325
hir::TraitBoundModifier::Negative
23272326
} else {
23282327
hir::TraitBoundModifier::None
23292328
}
23302329
}
2331-
2332-
// `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a
2333-
// placeholder for compilation to proceed.
2334-
TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
2335-
hir::TraitBoundModifier::Maybe
2330+
(BoundConstness::Maybe(_), BoundPolarity::Positive) => {
2331+
hir::TraitBoundModifier::MaybeConst
2332+
}
2333+
// Invalid modifier combinations will cause an error during AST validation.
2334+
// Arbitrarily pick a placeholder for compilation to proceed.
2335+
(BoundConstness::Maybe(_), BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
2336+
(BoundConstness::Maybe(_), BoundPolarity::Negative(_)) => {
2337+
hir::TraitBoundModifier::MaybeConst
23362338
}
2337-
TraitBoundModifier::MaybeConstNegative => hir::TraitBoundModifier::MaybeConst,
23382339
}
23392340
}
23402341

compiler/rustc_ast_passes/messages.ftl

+2-2
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
152152
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
153153
.help = remove one of these features
154154
155+
ast_passes_incompatible_trait_bound_modifiers = `{$left}` and `{$right}` are mutually exclusive
156+
155157
ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
156158
.because = {$annotation} because of this
157159
.type = inherent impl for this type
@@ -195,8 +197,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
195197
ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
196198
.help = use `auto trait Trait {"{}"}` instead
197199
198-
ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive
199-
200200
ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
201201
202202
ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits

compiler/rustc_ast_passes/src/ast_validation.rs

+17-16
Original file line numberDiff line numberDiff line change
@@ -1196,18 +1196,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11961196
}
11971197

11981198
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
1199-
if let GenericBound::Trait(poly, modify) = bound {
1200-
match (ctxt, modify) {
1201-
(BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
1199+
if let GenericBound::Trait(poly, modifiers) = bound {
1200+
match (ctxt, modifiers.constness, modifiers.polarity) {
1201+
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
12021202
self.dcx().emit_err(errors::OptionalTraitSupertrait {
12031203
span: poly.span,
12041204
path_str: pprust::path_to_string(&poly.trait_ref.path),
12051205
});
12061206
}
1207-
(BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
1207+
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
12081208
self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
12091209
}
1210-
(_, &TraitBoundModifier::MaybeConst(span))
1210+
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
12111211
if let Some(reason) = &self.disallow_tilde_const =>
12121212
{
12131213
let reason = match reason {
@@ -1235,24 +1235,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12351235
};
12361236
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
12371237
}
1238-
(_, TraitBoundModifier::MaybeConstMaybe) => {
1239-
self.dcx().emit_err(errors::OptionalConstExclusive {
1238+
(
1239+
_,
1240+
BoundConstness::Maybe(_),
1241+
BoundPolarity::Maybe(_) | BoundPolarity::Negative(_),
1242+
) => {
1243+
self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
12401244
span: bound.span(),
1241-
modifier: "?",
1242-
});
1243-
}
1244-
(_, TraitBoundModifier::MaybeConstNegative) => {
1245-
self.dcx().emit_err(errors::OptionalConstExclusive {
1246-
span: bound.span(),
1247-
modifier: "!",
1245+
left: modifiers.constness.as_str(),
1246+
right: modifiers.polarity.as_str(),
12481247
});
12491248
}
12501249
_ => {}
12511250
}
12521251
}
12531252

12541253
// Negative trait bounds are not allowed to have associated constraints
1255-
if let GenericBound::Trait(trait_ref, TraitBoundModifier::Negative) = bound
1254+
if let GenericBound::Trait(trait_ref, modifiers) = bound
1255+
&& let BoundPolarity::Negative(_) = modifiers.polarity
12561256
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
12571257
&& let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref()
12581258
{
@@ -1494,7 +1494,8 @@ fn deny_equality_constraints(
14941494
for param in &generics.params {
14951495
if param.ident == potential_param.ident {
14961496
for bound in &param.bounds {
1497-
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1497+
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) =
1498+
bound
14981499
{
14991500
if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
15001501
let assoc = pprust::path_to_string(&ast::Path::from_ident(

compiler/rustc_ast_passes/src/errors.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -580,11 +580,12 @@ pub enum TildeConstReason {
580580
}
581581

582582
#[derive(Diagnostic)]
583-
#[diag(ast_passes_optional_const_exclusive)]
584-
pub struct OptionalConstExclusive {
583+
#[diag(ast_passes_incompatible_trait_bound_modifiers)]
584+
pub struct IncompatibleTraitBoundModifiers {
585585
#[primary_span]
586586
pub span: Span,
587-
pub modifier: &'static str,
587+
pub left: &'static str,
588+
pub right: &'static str,
588589
}
589590

590591
#[derive(Diagnostic)]

compiler/rustc_ast_pretty/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#![deny(rustc::untranslatable_diagnostic)]
55
#![deny(rustc::diagnostic_outside_of_impl)]
66
#![feature(box_patterns)]
7+
#![feature(let_chains)]
78
#![recursion_limit = "256"]
89

910
mod helpers;

compiler/rustc_ast_pretty/src/pprust/state.rs

+12-18
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
1717
use rustc_ast::util::parser;
1818
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
1919
use rustc_ast::{attr, BindingAnnotation, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
20-
use rustc_ast::{GenericArg, GenericBound, SelfKind, TraitBoundModifier};
20+
use rustc_ast::{GenericArg, GenericBound, SelfKind};
2121
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
2222
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
2323
use rustc_span::edition::Edition;
@@ -1559,26 +1559,20 @@ impl<'a> State<'a> {
15591559

15601560
match bound {
15611561
GenericBound::Trait(tref, modifier) => {
1562-
match modifier {
1563-
TraitBoundModifier::None => {}
1564-
TraitBoundModifier::Negative => {
1565-
self.word("!");
1562+
match modifier.constness {
1563+
ast::BoundConstness::Never => {}
1564+
ast::BoundConstness::Maybe(_) => {
1565+
self.word_space(modifier.constness.as_str());
15661566
}
1567-
TraitBoundModifier::Maybe => {
1568-
self.word("?");
1569-
}
1570-
TraitBoundModifier::MaybeConst(_) => {
1571-
self.word_space("~const");
1572-
}
1573-
TraitBoundModifier::MaybeConstNegative => {
1574-
self.word_space("~const");
1575-
self.word("!");
1576-
}
1577-
TraitBoundModifier::MaybeConstMaybe => {
1578-
self.word_space("~const");
1579-
self.word("?");
1567+
}
1568+
1569+
match modifier.polarity {
1570+
ast::BoundPolarity::Positive => {}
1571+
ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => {
1572+
self.word(modifier.polarity.as_str());
15801573
}
15811574
}
1575+
15821576
self.print_poly_trait_ref(tref);
15831577
}
15841578
GenericBound::Outlives(lt) => self.print_lifetime(*lt),

0 commit comments

Comments
 (0)