Skip to content

Commit 3bc3247

Browse files
Move binder and polarity parsing into parse_generic_ty_bound
1 parent 036b38c commit 3bc3247

File tree

7 files changed

+204
-40
lines changed

7 files changed

+204
-40
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

+60-38
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())
@@ -916,7 +927,7 @@ impl<'a> Parser<'a> {
916927
/// If no modifiers are present, this does not consume any tokens.
917928
///
918929
/// ```ebnf
919-
/// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["?" | "!"]
930+
/// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["async"] ["?" | "!"]
920931
/// ```
921932
fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
922933
let constness = if self.eat(&token::Tilde) {
@@ -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 modifiers = self.parse_trait_bound_modifiers()?;
992+
let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?;
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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn foo<T>() where T: for<'a> 'a {}
2+
//~^ ERROR `for<...>` may only modify trait bounds, not lifetime bounds
3+
//~| ERROR use of undeclared lifetime name `'a` [E0261]
4+
5+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error: `for<...>` may only modify trait bounds, not lifetime bounds
2+
--> $DIR/erroneous-lifetime-bound.rs:1:25
3+
|
4+
LL | fn foo<T>() where T: for<'a> 'a {}
5+
| ^^^^
6+
7+
error[E0261]: use of undeclared lifetime name `'a`
8+
--> $DIR/erroneous-lifetime-bound.rs:1:30
9+
|
10+
LL | fn foo<T>() where T: for<'a> 'a {}
11+
| ^^ undeclared lifetime
12+
|
13+
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
14+
help: consider making the bound lifetime-generic with a new `'a` lifetime
15+
|
16+
LL | fn foo<T>() where for<'a> T: for<'a> 'a {}
17+
| +++++++
18+
help: consider introducing lifetime `'a` here
19+
|
20+
LL | fn foo<'a, T>() where T: for<'a> 'a {}
21+
| +++
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0261`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ edition: 2021
2+
3+
#![feature(precise_capturing)]
4+
5+
fn polarity() -> impl Sized + ?use<> {}
6+
//~^ ERROR expected identifier, found keyword `use`
7+
//~| ERROR cannot find trait `r#use` in this scope
8+
//~| WARN relaxing a default bound only does something for `?Sized`
9+
//~| WARN relaxing a default bound only does something for `?Sized`
10+
11+
fn asyncness() -> impl Sized + async use<> {}
12+
//~^ ERROR expected identifier, found keyword `use`
13+
//~| ERROR cannot find trait `r#use` in this scope
14+
//~| ERROR async closures are unstable
15+
16+
fn constness() -> impl Sized + const use<> {}
17+
//~^ ERROR expected identifier, found keyword `use`
18+
//~| ERROR cannot find trait `r#use` in this scope
19+
//~| ERROR const trait impls are experimental
20+
21+
fn binder() -> impl Sized + for<'a> use<> {}
22+
//~^ ERROR expected identifier, found keyword `use`
23+
//~| ERROR cannot find trait `r#use` in this scope
24+
25+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
error: expected identifier, found keyword `use`
2+
--> $DIR/bound-modifiers.rs:5:32
3+
|
4+
LL | fn polarity() -> impl Sized + ?use<> {}
5+
| ^^^ expected identifier, found keyword
6+
7+
error: expected identifier, found keyword `use`
8+
--> $DIR/bound-modifiers.rs:11:38
9+
|
10+
LL | fn asyncness() -> impl Sized + async use<> {}
11+
| ^^^ expected identifier, found keyword
12+
13+
error: expected identifier, found keyword `use`
14+
--> $DIR/bound-modifiers.rs:16:38
15+
|
16+
LL | fn constness() -> impl Sized + const use<> {}
17+
| ^^^ expected identifier, found keyword
18+
19+
error: expected identifier, found keyword `use`
20+
--> $DIR/bound-modifiers.rs:21:37
21+
|
22+
LL | fn binder() -> impl Sized + for<'a> use<> {}
23+
| ^^^ expected identifier, found keyword
24+
25+
error[E0405]: cannot find trait `r#use` in this scope
26+
--> $DIR/bound-modifiers.rs:5:32
27+
|
28+
LL | fn polarity() -> impl Sized + ?use<> {}
29+
| ^^^ not found in this scope
30+
31+
error[E0405]: cannot find trait `r#use` in this scope
32+
--> $DIR/bound-modifiers.rs:11:38
33+
|
34+
LL | fn asyncness() -> impl Sized + async use<> {}
35+
| ^^^ not found in this scope
36+
37+
error[E0405]: cannot find trait `r#use` in this scope
38+
--> $DIR/bound-modifiers.rs:16:38
39+
|
40+
LL | fn constness() -> impl Sized + const use<> {}
41+
| ^^^ not found in this scope
42+
43+
error[E0405]: cannot find trait `r#use` in this scope
44+
--> $DIR/bound-modifiers.rs:21:37
45+
|
46+
LL | fn binder() -> impl Sized + for<'a> use<> {}
47+
| ^^^ not found in this scope
48+
49+
error[E0658]: async closures are unstable
50+
--> $DIR/bound-modifiers.rs:11:32
51+
|
52+
LL | fn asyncness() -> impl Sized + async use<> {}
53+
| ^^^^^
54+
|
55+
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
56+
= help: add `#![feature(async_closure)]` to the crate attributes to enable
57+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
58+
= help: to use an async block, remove the `||`: `async {`
59+
60+
error[E0658]: const trait impls are experimental
61+
--> $DIR/bound-modifiers.rs:16:32
62+
|
63+
LL | fn constness() -> impl Sized + const use<> {}
64+
| ^^^^^
65+
|
66+
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
67+
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
68+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
69+
70+
warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
71+
--> $DIR/bound-modifiers.rs:5:31
72+
|
73+
LL | fn polarity() -> impl Sized + ?use<> {}
74+
| ^^^^^^
75+
76+
warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
77+
--> $DIR/bound-modifiers.rs:5:31
78+
|
79+
LL | fn polarity() -> impl Sized + ?use<> {}
80+
| ^^^^^^
81+
|
82+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
83+
84+
error: aborting due to 10 previous errors; 2 warnings emitted
85+
86+
Some errors have detailed explanations: E0405, E0658.
87+
For more information about an error, try `rustc --explain E0405`.

0 commit comments

Comments
 (0)