Skip to content

Commit f9e007d

Browse files
Reorder modifiers and polarity to be *after* binder in trait bounds
1 parent 036b38c commit f9e007d

File tree

9 files changed

+78
-82
lines changed

9 files changed

+78
-82
lines changed

compiler/rustc_parse/src/parser/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2327,7 +2327,7 @@ impl<'a> Parser<'a> {
23272327
let before = self.prev_token.clone();
23282328
let binder = if self.check_keyword(kw::For) {
23292329
let lo = self.token.span;
2330-
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
2330+
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
23312331
let span = lo.to(self.prev_token.span);
23322332

23332333
self.psess.gated_spans.gate(sym::closure_lifetime_binder, span);

compiler/rustc_parse/src/parser/generics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ impl<'a> Parser<'a> {
457457
// * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
458458
// * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
459459
// * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
460-
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
460+
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
461461

462462
// Parse type with mandatory colon and (possibly empty) bounds,
463463
// or with mandatory equality sign and the second type.

compiler/rustc_parse/src/parser/ty.rs

+59-37
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_ast::{
1818
};
1919
use rustc_errors::{Applicability, PResult};
2020
use rustc_span::symbol::{kw, sym, Ident};
21-
use rustc_span::{Span, Symbol};
21+
use rustc_span::{ErrorGuaranteed, Span, Symbol};
2222
use thin_vec::{thin_vec, ThinVec};
2323

2424
#[derive(Copy, Clone, PartialEq)]
@@ -280,7 +280,7 @@ impl<'a> Parser<'a> {
280280
// Function pointer type or bound list (trait object type) starting with a poly-trait.
281281
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
282282
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
283-
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
283+
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
284284
if self.check_fn_front_matter(false, Case::Sensitive) {
285285
self.parse_ty_bare_fn(
286286
lo,
@@ -833,12 +833,9 @@ impl<'a> Parser<'a> {
833833
let lo = self.token.span;
834834
let leading_token = self.prev_token.clone();
835835
let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis));
836-
let inner_lo = self.token.span;
837836

838-
let modifiers = self.parse_trait_bound_modifiers()?;
839837
let bound = if self.token.is_lifetime() {
840-
self.error_lt_bound_with_modifiers(modifiers);
841-
self.parse_generic_lt_bound(lo, inner_lo, has_parens)?
838+
self.parse_generic_lt_bound(lo, has_parens)?
842839
} else if self.eat_keyword(kw::Use) {
843840
// parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
844841
// lifetimes and ident params (including SelfUpper). These are validated later
@@ -848,7 +845,7 @@ impl<'a> Parser<'a> {
848845
let (args, args_span) = self.parse_precise_capturing_args()?;
849846
GenericBound::Use(args, use_span.to(args_span))
850847
} else {
851-
self.parse_generic_ty_bound(lo, has_parens, modifiers, &leading_token)?
848+
self.parse_generic_ty_bound(lo, has_parens, &leading_token)?
852849
};
853850

854851
Ok(bound)
@@ -858,50 +855,64 @@ impl<'a> Parser<'a> {
858855
/// ```ebnf
859856
/// LT_BOUND = LIFETIME
860857
/// ```
861-
fn parse_generic_lt_bound(
862-
&mut self,
863-
lo: Span,
864-
inner_lo: Span,
865-
has_parens: bool,
866-
) -> PResult<'a, GenericBound> {
867-
let bound = GenericBound::Outlives(self.expect_lifetime());
858+
fn parse_generic_lt_bound(&mut self, lo: Span, has_parens: bool) -> PResult<'a, GenericBound> {
859+
let lt = self.expect_lifetime();
860+
let bound = GenericBound::Outlives(lt);
868861
if has_parens {
869862
// FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
870863
// possibly introducing `GenericBound::Paren(P<GenericBound>)`?
871-
self.recover_paren_lifetime(lo, inner_lo)?;
864+
self.recover_paren_lifetime(lo, lt.ident.span)?;
872865
}
873866
Ok(bound)
874867
}
875868

876869
/// Emits an error if any trait bound modifiers were present.
877-
fn error_lt_bound_with_modifiers(&self, modifiers: TraitBoundModifiers) {
878-
match modifiers.constness {
870+
fn error_lt_bound_with_modifiers(
871+
&self,
872+
modifiers: TraitBoundModifiers,
873+
binder_span: Option<Span>,
874+
) -> ErrorGuaranteed {
875+
let TraitBoundModifiers { constness, asyncness, polarity } = modifiers;
876+
877+
match constness {
879878
BoundConstness::Never => {}
880879
BoundConstness::Always(span) | BoundConstness::Maybe(span) => {
881-
self.dcx().emit_err(errors::ModifierLifetime {
882-
span,
883-
modifier: modifiers.constness.as_str(),
884-
});
880+
return self
881+
.dcx()
882+
.emit_err(errors::ModifierLifetime { span, modifier: constness.as_str() });
885883
}
886884
}
887885

888-
match modifiers.polarity {
886+
match polarity {
889887
BoundPolarity::Positive => {}
890888
BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => {
891-
self.dcx().emit_err(errors::ModifierLifetime {
892-
span,
893-
modifier: modifiers.polarity.as_str(),
894-
});
889+
return self
890+
.dcx()
891+
.emit_err(errors::ModifierLifetime { span, modifier: polarity.as_str() });
892+
}
893+
}
894+
895+
match asyncness {
896+
BoundAsyncness::Normal => {}
897+
BoundAsyncness::Async(span) => {
898+
return self
899+
.dcx()
900+
.emit_err(errors::ModifierLifetime { span, modifier: asyncness.as_str() });
895901
}
896902
}
903+
904+
if let Some(span) = binder_span {
905+
return self.dcx().emit_err(errors::ModifierLifetime { span, modifier: "for<...>" });
906+
}
907+
908+
unreachable!("lifetime bound intercepted in `parse_generic_ty_bound` but no modifiers?")
897909
}
898910

899911
/// Recover on `('lifetime)` with `(` already eaten.
900-
fn recover_paren_lifetime(&mut self, lo: Span, inner_lo: Span) -> PResult<'a, ()> {
901-
let inner_span = inner_lo.to(self.prev_token.span);
912+
fn recover_paren_lifetime(&mut self, lo: Span, lt_span: Span) -> PResult<'a, ()> {
902913
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
903914
let span = lo.to(self.prev_token.span);
904-
let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(inner_span) {
915+
let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(lt_span) {
905916
(Some(span), snippet)
906917
} else {
907918
(None, String::new())
@@ -970,15 +981,23 @@ impl<'a> Parser<'a> {
970981
/// TY_BOUND_NOPAREN = [TRAIT_BOUND_MODIFIERS] [for<LT_PARAM_DEFS>] SIMPLE_PATH
971982
/// ```
972983
///
973-
/// For example, this grammar accepts `~const ?for<'a: 'b> m::Trait<'a>`.
984+
/// For example, this grammar accepts `for<'a: 'b> ~const ?m::Trait<'a>`.
974985
fn parse_generic_ty_bound(
975986
&mut self,
976987
lo: Span,
977988
has_parens: bool,
978-
modifiers: TraitBoundModifiers,
979989
leading_token: &Token,
980990
) -> PResult<'a, GenericBound> {
981-
let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?;
991+
let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?;
992+
let modifiers = self.parse_trait_bound_modifiers()?;
993+
994+
// Recover erroneous lifetime bound with modifiers or binder.
995+
// e.g. `T: for<'a> 'a` or `T: ~const 'a`.
996+
if self.token.is_lifetime() {
997+
let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span);
998+
return self.parse_generic_lt_bound(lo, has_parens);
999+
}
1000+
9821001
let mut path = if self.token.is_keyword(kw::Fn)
9831002
&& self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
9841003
&& let Some(path) = self.recover_path_from_fn()
@@ -1094,16 +1113,19 @@ impl<'a> Parser<'a> {
10941113
}
10951114

10961115
/// Optionally parses `for<$generic_params>`.
1097-
pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, ThinVec<GenericParam>> {
1116+
pub(super) fn parse_late_bound_lifetime_defs(
1117+
&mut self,
1118+
) -> PResult<'a, (ThinVec<GenericParam>, Option<Span>)> {
10981119
if self.eat_keyword(kw::For) {
1120+
let lo = self.token.span;
10991121
self.expect_lt()?;
11001122
let params = self.parse_generic_params()?;
11011123
self.expect_gt()?;
1102-
// We rely on AST validation to rule out invalid cases: There must not be type
1103-
// parameters, and the lifetime parameters must not have bounds.
1104-
Ok(params)
1124+
// We rely on AST validation to rule out invalid cases: There must not be
1125+
// type or const parameters, and parameters must not have bounds.
1126+
Ok((params, Some(lo.to(self.prev_token.span))))
11051127
} else {
1106-
Ok(ThinVec::new())
1128+
Ok((ThinVec::new(), None))
11071129
}
11081130
}
11091131

tests/ui/async-await/async-fn/higher-ranked-async-fn.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ async fn f(arg: &i32) {}
1515

1616
async fn func<F>(f: F)
1717
where
18-
F: async for<'a> Fn(&'a i32),
18+
F: for<'a> async Fn(&'a i32),
1919
{
2020
let x: i32 = 0;
2121
f(&x).await;
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,8 @@
1-
error: `~const` can only be applied to `#[const_trait]` traits
2-
--> $DIR/normalize-tait-in-const.rs:27:42
1+
error: expected a trait, found type
2+
--> $DIR/normalize-tait-in-const.rs:27:34
33
|
44
LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
5-
| ^^^^^^^^^^^^^^^^^
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
66

7-
error: `~const` can only be applied to `#[const_trait]` traits
8-
--> $DIR/normalize-tait-in-const.rs:27:69
9-
|
10-
LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
11-
| ^^^^^^^^
12-
13-
error[E0015]: cannot call non-const closure in constant functions
14-
--> $DIR/normalize-tait-in-const.rs:28:5
15-
|
16-
LL | fun(filter_positive());
17-
| ^^^^^^^^^^^^^^^^^^^^^^
18-
|
19-
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
20-
help: consider further restricting this bound
21-
|
22-
LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) {
23-
| ++++++++++++++++++++++++++++
24-
help: add `#![feature(effects)]` to the crate attributes to enable
25-
|
26-
LL + #![feature(effects)]
27-
|
28-
29-
error[E0493]: destructor of `F` cannot be evaluated at compile-time
30-
--> $DIR/normalize-tait-in-const.rs:27:79
31-
|
32-
LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
33-
| ^^^ the destructor for this type cannot be evaluated in constant functions
34-
LL | fun(filter_positive());
35-
LL | }
36-
| - value is dropped here
37-
38-
error: aborting due to 4 previous errors
7+
error: aborting due to 1 previous error
398

40-
Some errors have detailed explanations: E0015, E0493.
41-
For more information about an error, try `rustc --explain E0015`.

tests/ui/issues/issue-39089.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//@ check-pass
2-
#![allow(dead_code)]
31
fn f<T: ?for<'a> Sized>() {}
2+
//~^ ERROR expected a trait, found type
43

54
fn main() {}

tests/ui/issues/issue-39089.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected a trait, found type
2+
--> $DIR/issue-39089.rs:1:10
3+
|
4+
LL | fn f<T: ?for<'a> Sized>() {}
5+
| ^^^^^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+

tests/ui/parser/bounds-type.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ struct S<
55
T: Tr + 'a, // OK
66
T: 'a, // OK
77
T:, // OK
8-
T: ?for<'a> Trait, // OK
8+
T: for<'a> ?Trait, // OK
99
T: Tr +, // OK
1010
T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
1111

tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
#![feature(const_trait_impl)]
55

66
struct S<
7-
T: ~const ?for<'a> Tr<'a> + 'static + ~const std::ops::Add,
8-
T: ~const ?for<'a: 'b> m::Trait<'a>,
7+
T: for<'a> ~const ?Tr<'a> + 'static + ~const std::ops::Add,
8+
T: for<'a: 'b> ~const ?m::Trait<'a>,
99
>;

0 commit comments

Comments
 (0)