Skip to content

Commit

Permalink
And additionally enforce ? and async/const aren't mixed
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Jul 11, 2024
1 parent 898ed2f commit de88bc5
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 44 deletions.
2 changes: 0 additions & 2 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,6 @@ ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
.help = remove one of these features
ast_passes_incompatible_trait_bound_modifiers = `{$left}` and `{$right}` are mutually exclusive
ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
.because = {$annotation} because of this
.type = inherent impl for this type
Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1435,17 +1435,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
};
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
}
(
_,
BoundConstness::Always(_) | BoundConstness::Maybe(_),
BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
) => {
self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
span: bound.span(),
left: modifiers.constness.as_str(),
right: modifiers.polarity.as_str(),
});
}
_ => {}
}

Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,15 +657,6 @@ pub enum TildeConstReason {
Item,
}

#[derive(Diagnostic)]
#[diag(ast_passes_incompatible_trait_bound_modifiers)]
pub struct IncompatibleTraitBoundModifiers {
#[primary_span]
pub span: Span,
pub left: &'static str,
pub right: &'static str,
}

#[derive(Diagnostic)]
#[diag(ast_passes_const_and_async)]
pub struct ConstAndAsync {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,9 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl
parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds
.suggestion = remove the `{$modifier}`
parse_modifiers_and_polarity = `{$modifiers_concatenated}` trait not allowed with `{$polarity}` trait polarity modifier
.label = there is not a well-defined meaning for a `{$modifiers_concatenated} {$polarity}` trait
parse_more_than_one_char = character literal may only contain one codepoint
.followed_by = this `{$chr}` is followed by the combining {$len ->
[one] mark
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3060,3 +3060,14 @@ pub struct BinderAndPolarity {
pub binder_span: Span,
pub polarity: &'static str,
}

#[derive(Diagnostic)]
#[diag(parse_modifiers_and_polarity)]
pub struct PolarityAndModifiers {
#[primary_span]
pub polarity_span: Span,
#[label]
pub modifiers_span: Span,
pub polarity: &'static str,
pub modifiers_concatenated: String,
}
29 changes: 29 additions & 0 deletions compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,7 @@ impl<'a> Parser<'a> {
/// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["async"] ["?" | "!"]
/// ```
fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
let modifier_lo = self.token.span;
let constness = if self.eat(&token::Tilde) {
let tilde = self.prev_token.span;
self.expect_keyword(kw::Const)?;
Expand Down Expand Up @@ -962,6 +963,7 @@ impl<'a> Parser<'a> {
} else {
BoundAsyncness::Normal
};
let modifier_hi = self.prev_token.span;

let polarity = if self.eat(&token::Question) {
BoundPolarity::Maybe(self.prev_token.span)
Expand All @@ -972,6 +974,33 @@ impl<'a> Parser<'a> {
BoundPolarity::Positive
};

// Enforce the mutual-exclusivity of `const`/`async` and `?`/`!`.
match polarity {
BoundPolarity::Positive => {
// All trait bound modifiers allowed to combine with positive polarity
}
BoundPolarity::Maybe(polarity_span) | BoundPolarity::Negative(polarity_span) => {
match (asyncness, constness) {
(BoundAsyncness::Normal, BoundConstness::Never) => {
// Ok, no modifiers.
}
(_, _) => {
let constness = constness.as_str();
let asyncness = asyncness.as_str();
let glue =
if !constness.is_empty() && !asyncness.is_empty() { " " } else { "" };
let modifiers_concatenated = format!("{constness}{glue}{asyncness}");
self.dcx().emit_err(errors::PolarityAndModifiers {
polarity_span,
polarity: polarity.as_str(),
modifiers_span: modifier_lo.to(modifier_hi),
modifiers_concatenated,
});
}
}
}
}

Ok(TraitBoundModifiers { constness, asyncness, polarity })
}

Expand Down
13 changes: 12 additions & 1 deletion tests/ui/parser/bounds-type.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//@ compile-flags: -Z parse-only
//@ edition: 2021

struct S<
T: 'a + Tr, // OK
Expand All @@ -10,10 +11,20 @@ struct S<
T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds

T: ~const Tr, // OK
T: ~const ?Tr, // OK
T: ~const ?Tr, //~ ERROR `~const` trait not allowed with `?` trait polarity modifier
T: ~const Tr + 'a, // OK
T: ~const 'a, //~ ERROR `~const` may only modify trait bounds, not lifetime bounds
T: const 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds

T: async Tr, // OK
T: async ?Tr, //~ ERROR `async` trait not allowed with `?` trait polarity modifier
T: async Tr + 'a, // OK
T: async 'a, //~ ERROR `async` may only modify trait bounds, not lifetime bounds

T: const async Tr, // OK
T: const async ?Tr, //~ ERROR `const async` trait not allowed with `?` trait polarity modifier
T: const async Tr + 'a, // OK
T: const async 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds
>;

fn main() {}
46 changes: 41 additions & 5 deletions tests/ui/parser/bounds-type.stderr
Original file line number Diff line number Diff line change
@@ -1,28 +1,64 @@
error: `for<...>` binder not allowed with `?` trait polarity modifier
--> $DIR/bounds-type.rs:8:16
--> $DIR/bounds-type.rs:9:16
|
LL | T: for<'a> ?Trait,
| ---- ^
| |
| there is not a well-defined meaning for a higher-ranked `?` trait

error: `?` may only modify trait bounds, not lifetime bounds
--> $DIR/bounds-type.rs:10:8
--> $DIR/bounds-type.rs:11:8
|
LL | T: ?'a,
| ^

error: `~const` trait not allowed with `?` trait polarity modifier
--> $DIR/bounds-type.rs:14:15
|
LL | T: ~const ?Tr,
| ------ ^
| |
| there is not a well-defined meaning for a `~const ?` trait

error: `~const` may only modify trait bounds, not lifetime bounds
--> $DIR/bounds-type.rs:15:8
--> $DIR/bounds-type.rs:16:8
|
LL | T: ~const 'a,
| ^^^^^^

error: `const` may only modify trait bounds, not lifetime bounds
--> $DIR/bounds-type.rs:16:8
--> $DIR/bounds-type.rs:17:8
|
LL | T: const 'a,
| ^^^^^

error: aborting due to 4 previous errors
error: `async` trait not allowed with `?` trait polarity modifier
--> $DIR/bounds-type.rs:20:14
|
LL | T: async ?Tr,
| ----- ^
| |
| there is not a well-defined meaning for a `async ?` trait

error: `async` may only modify trait bounds, not lifetime bounds
--> $DIR/bounds-type.rs:22:8
|
LL | T: async 'a,
| ^^^^^

error: `const async` trait not allowed with `?` trait polarity modifier
--> $DIR/bounds-type.rs:25:20
|
LL | T: const async ?Tr,
| ----------- ^
| |
| there is not a well-defined meaning for a `const async ?` trait

error: `const` may only modify trait bounds, not lifetime bounds
--> $DIR/bounds-type.rs:27:8
|
LL | T: const async 'a,
| ^^^^^

error: aborting due to 9 previous errors

Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#![feature(const_trait_impl)]

const fn maybe_const_maybe<T: ~const ?Sized>() {}
//~^ ERROR `~const` and `?` are mutually exclusive
//~^ ERROR `~const` trait not allowed with `?` trait polarity modifier

fn const_maybe<T: const ?Sized>() {}
//~^ ERROR `const` and `?` are mutually exclusive
//~^ ERROR `const` trait not allowed with `?` trait polarity modifier

const fn maybe_const_negative<T: ~const !Trait>() {}
//~^ ERROR `~const` and `!` are mutually exclusive
//~^ ERROR `~const` trait not allowed with `!` trait polarity modifier
//~| ERROR negative bounds are not supported

fn const_negative<T: const !Trait>() {}
//~^ ERROR `const` and `!` are mutually exclusive
//~^ ERROR `const` trait not allowed with `!` trait polarity modifier
//~| ERROR negative bounds are not supported

#[const_trait]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
error: `~const` and `?` are mutually exclusive
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31
error: `~const` trait not allowed with `?` trait polarity modifier
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:38
|
LL | const fn maybe_const_maybe<T: ~const ?Sized>() {}
| ^^^^^^^^^^^^^
| ------ ^
| |
| there is not a well-defined meaning for a `~const ?` trait

error: `const` and `?` are mutually exclusive
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:19
error: `const` trait not allowed with `?` trait polarity modifier
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:25
|
LL | fn const_maybe<T: const ?Sized>() {}
| ^^^^^^^^^^^^
| ----- ^
| |
| there is not a well-defined meaning for a `const ?` trait

error: `~const` and `!` are mutually exclusive
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:34
error: `~const` trait not allowed with `!` trait polarity modifier
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41
|
LL | const fn maybe_const_negative<T: ~const !Trait>() {}
| ^^^^^^^^^^^^^
| ------ ^
| |
| there is not a well-defined meaning for a `~const !` trait

error: `const` and `!` are mutually exclusive
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:22
error: `const` trait not allowed with `!` trait polarity modifier
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28
|
LL | fn const_negative<T: const !Trait>() {}
| ^^^^^^^^^^^^
| ----- ^
| |
| there is not a well-defined meaning for a `const !` trait

error: negative bounds are not supported
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41
Expand Down

0 comments on commit de88bc5

Please sign in to comment.