Skip to content

Commit 2917ac6

Browse files
Rollup merge of rust-lang#46827 - petrochenkov:assocrecov2, r=estebank
syntax: Follow-up to the incorrect qpath recovery PR cc rust-lang#46788 Add tests checking that "priority" of qpath recovery is higher than priority of unary and binary operators Fix regressed parsing of paths with fn-like generic arguments r? @estebank
2 parents ab7abfc + d333752 commit 2917ac6

File tree

8 files changed

+165
-70
lines changed

8 files changed

+165
-70
lines changed

src/libsyntax/ast.rs

Lines changed: 25 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use syntax_pos::{Span, DUMMY_SP};
2020
use codemap::{respan, Spanned};
2121
use abi::Abi;
2222
use ext::hygiene::{Mark, SyntaxContext};
23-
use parse::parser::{RecoverQPath, PathStyle};
2423
use print::pprust;
2524
use ptr::P;
2625
use rustc_data_structures::indexed_vec;
@@ -485,6 +484,30 @@ impl fmt::Debug for Pat {
485484
}
486485

487486
impl Pat {
487+
pub(super) fn to_ty(&self) -> Option<P<Ty>> {
488+
let node = match &self.node {
489+
PatKind::Wild => TyKind::Infer,
490+
PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None) =>
491+
TyKind::Path(None, Path::from_ident(ident.span, ident.node)),
492+
PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
493+
PatKind::Mac(mac) => TyKind::Mac(mac.clone()),
494+
PatKind::Ref(pat, mutbl) =>
495+
pat.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?,
496+
PatKind::Slice(pats, None, _) if pats.len() == 1 =>
497+
pats[0].to_ty().map(TyKind::Slice)?,
498+
PatKind::Tuple(pats, None) => {
499+
let mut tys = Vec::new();
500+
for pat in pats {
501+
tys.push(pat.to_ty()?);
502+
}
503+
TyKind::Tup(tys)
504+
}
505+
_ => return None,
506+
};
507+
508+
Some(P(Ty { node, id: self.id, span: self.span }))
509+
}
510+
488511
pub fn walk<F>(&self, it: &mut F) -> bool
489512
where F: FnMut(&Pat) -> bool
490513
{
@@ -520,38 +543,6 @@ impl Pat {
520543
}
521544
}
522545

523-
impl RecoverQPath for Pat {
524-
fn to_ty(&self) -> Option<P<Ty>> {
525-
let node = match &self.node {
526-
PatKind::Wild => TyKind::Infer,
527-
PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None) =>
528-
TyKind::Path(None, Path::from_ident(ident.span, ident.node)),
529-
PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
530-
PatKind::Mac(mac) => TyKind::Mac(mac.clone()),
531-
PatKind::Ref(pat, mutbl) =>
532-
pat.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?,
533-
PatKind::Slice(pats, None, _) if pats.len() == 1 =>
534-
pats[0].to_ty().map(TyKind::Slice)?,
535-
PatKind::Tuple(pats, None) => {
536-
let mut tys = Vec::new();
537-
for pat in pats {
538-
tys.push(pat.to_ty()?);
539-
}
540-
TyKind::Tup(tys)
541-
}
542-
_ => return None,
543-
};
544-
545-
Some(P(Ty { node, id: self.id, span: self.span }))
546-
}
547-
fn to_recovered(&self, qself: Option<QSelf>, path: Path) -> Self {
548-
Self { span: path.span, node: PatKind::Path(qself, path), id: self.id }
549-
}
550-
fn to_string(&self) -> String {
551-
pprust::pat_to_string(self)
552-
}
553-
}
554-
555546
/// A single field in a struct pattern
556547
///
557548
/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
@@ -919,10 +910,8 @@ impl Expr {
919910
_ => None,
920911
}
921912
}
922-
}
923913

924-
impl RecoverQPath for Expr {
925-
fn to_ty(&self) -> Option<P<Ty>> {
914+
pub(super) fn to_ty(&self) -> Option<P<Ty>> {
926915
let node = match &self.node {
927916
ExprKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
928917
ExprKind::Mac(mac) => TyKind::Mac(mac.clone()),
@@ -951,13 +940,6 @@ impl RecoverQPath for Expr {
951940

952941
Some(P(Ty { node, id: self.id, span: self.span }))
953942
}
954-
fn to_recovered(&self, qself: Option<QSelf>, path: Path) -> Self {
955-
Self { span: path.span, node: ExprKind::Path(qself, path),
956-
id: self.id, attrs: self.attrs.clone() }
957-
}
958-
fn to_string(&self) -> String {
959-
pprust::expr_to_string(self)
960-
}
961943
}
962944

963945
impl fmt::Debug for Expr {
@@ -1469,19 +1451,6 @@ pub struct Ty {
14691451
pub span: Span,
14701452
}
14711453

1472-
impl RecoverQPath for Ty {
1473-
fn to_ty(&self) -> Option<P<Ty>> {
1474-
Some(P(self.clone()))
1475-
}
1476-
fn to_recovered(&self, qself: Option<QSelf>, path: Path) -> Self {
1477-
Self { span: path.span, node: TyKind::Path(qself, path), id: self.id }
1478-
}
1479-
fn to_string(&self) -> String {
1480-
pprust::ty_to_string(self)
1481-
}
1482-
const PATH_STYLE: PathStyle = PathStyle::Type;
1483-
}
1484-
14851454
impl fmt::Debug for Ty {
14861455
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
14871456
write!(f, "type({})", pprust::ty_to_string(self))

src/libsyntax/parse/parser.rs

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,49 @@ enum PrevTokenKind {
169169
Other,
170170
}
171171

172-
pub(crate) trait RecoverQPath: Sized {
172+
trait RecoverQPath: Sized {
173+
const PATH_STYLE: PathStyle = PathStyle::Expr;
173174
fn to_ty(&self) -> Option<P<Ty>>;
174175
fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self;
175176
fn to_string(&self) -> String;
176-
const PATH_STYLE: PathStyle = PathStyle::Expr;
177+
}
178+
179+
impl RecoverQPath for Ty {
180+
const PATH_STYLE: PathStyle = PathStyle::Type;
181+
fn to_ty(&self) -> Option<P<Ty>> {
182+
Some(P(self.clone()))
183+
}
184+
fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self {
185+
Self { span: path.span, node: TyKind::Path(qself, path), id: self.id }
186+
}
187+
fn to_string(&self) -> String {
188+
pprust::ty_to_string(self)
189+
}
190+
}
191+
192+
impl RecoverQPath for Pat {
193+
fn to_ty(&self) -> Option<P<Ty>> {
194+
self.to_ty()
195+
}
196+
fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self {
197+
Self { span: path.span, node: PatKind::Path(qself, path), id: self.id }
198+
}
199+
fn to_string(&self) -> String {
200+
pprust::pat_to_string(self)
201+
}
202+
}
203+
204+
impl RecoverQPath for Expr {
205+
fn to_ty(&self) -> Option<P<Ty>> {
206+
self.to_ty()
207+
}
208+
fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self {
209+
Self { span: path.span, node: ExprKind::Path(qself, path),
210+
id: self.id, attrs: self.attrs.clone() }
211+
}
212+
fn to_string(&self) -> String {
213+
pprust::expr_to_string(self)
214+
}
177215
}
178216

179217
/* ident is handled by common.rs */
@@ -1432,7 +1470,7 @@ impl<'a> Parser<'a> {
14321470

14331471
// Parse a type
14341472
pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
1435-
self.parse_ty_common(true)
1473+
self.parse_ty_common(true, true)
14361474
}
14371475

14381476
/// Parse a type in restricted contexts where `+` is not permitted.
@@ -1441,10 +1479,11 @@ impl<'a> Parser<'a> {
14411479
/// Example 2: `value1 as TYPE + value2`
14421480
/// `+` is prohibited to avoid interactions with expression grammar.
14431481
fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
1444-
self.parse_ty_common(false)
1482+
self.parse_ty_common(false, true)
14451483
}
14461484

1447-
fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
1485+
fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool)
1486+
-> PResult<'a, P<Ty>> {
14481487
maybe_whole!(self, NtTy, |x| x);
14491488

14501489
let lo = self.span;
@@ -1577,7 +1616,7 @@ impl<'a> Parser<'a> {
15771616

15781617
// Try to recover from use of `+` with incorrect priority.
15791618
self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
1580-
let ty = self.maybe_recover_from_bad_qpath(ty)?;
1619+
let ty = self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)?;
15811620

15821621
Ok(P(ty))
15831622
}
@@ -1633,9 +1672,10 @@ impl<'a> Parser<'a> {
16331672
}
16341673

16351674
// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
1636-
fn maybe_recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: T) -> PResult<'a, T> {
1675+
fn maybe_recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: T, allow_recovery: bool)
1676+
-> PResult<'a, T> {
16371677
// Do not add `::` to expected tokens.
1638-
if self.token != token::ModSep {
1678+
if !allow_recovery || self.token != token::ModSep {
16391679
return Ok(base);
16401680
}
16411681
let ty = match base.to_ty() {
@@ -1969,7 +2009,7 @@ impl<'a> Parser<'a> {
19692009
|p| p.parse_ty())?;
19702010
self.bump(); // `)`
19712011
let output = if self.eat(&token::RArrow) {
1972-
Some(self.parse_ty_no_plus()?)
2012+
Some(self.parse_ty_common(false, false)?)
19732013
} else {
19742014
None
19752015
};
@@ -2376,7 +2416,7 @@ impl<'a> Parser<'a> {
23762416
}
23772417

23782418
let expr = Expr { node: ex, span: lo.to(hi), id: ast::DUMMY_NODE_ID, attrs };
2379-
let expr = self.maybe_recover_from_bad_qpath(expr)?;
2419+
let expr = self.maybe_recover_from_bad_qpath(expr, true)?;
23802420

23812421
return Ok(P(expr));
23822422
}
@@ -3743,7 +3783,7 @@ impl<'a> Parser<'a> {
37433783
}
37443784

37453785
let pat = Pat { node: pat, span: lo.to(self.prev_span), id: ast::DUMMY_NODE_ID };
3746-
let pat = self.maybe_recover_from_bad_qpath(pat)?;
3786+
let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
37473787

37483788
Ok(P(pat))
37493789
}

src/test/ui/did_you_mean/bad-assoc-expr.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,10 @@ fn main() {
2121

2222
(u8, u8)::clone(&(0, 0));
2323
//~^ ERROR missing angle brackets in associated item path
24+
25+
&(u8)::clone(&0);
26+
//~^ ERROR missing angle brackets in associated item path
27+
28+
10 + (u8)::clone(&0);
29+
//~^ ERROR missing angle brackets in associated item path
2430
}

src/test/ui/did_you_mean/bad-assoc-expr.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,17 @@ error: missing angle brackets in associated item path
2222
22 | (u8, u8)::clone(&(0, 0));
2323
| ^^^^^^^^^^^^^^^ help: try: `<(u8, u8)>::clone`
2424

25-
error: aborting due to 4 previous errors
25+
error: missing angle brackets in associated item path
26+
--> $DIR/bad-assoc-expr.rs:25:6
27+
|
28+
25 | &(u8)::clone(&0);
29+
| ^^^^^^^^^^^ help: try: `<(u8)>::clone`
30+
31+
error: missing angle brackets in associated item path
32+
--> $DIR/bad-assoc-expr.rs:28:10
33+
|
34+
28 | 10 + (u8)::clone(&0);
35+
| ^^^^^^^^^^^ help: try: `<(u8)>::clone`
36+
37+
error: aborting due to 6 previous errors
2638

src/test/ui/did_you_mean/bad-assoc-pat.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,9 @@ fn main() {
2020
//~^ ERROR missing angle brackets in associated item path
2121
//~| ERROR no associated item named `AssocItem` found for type `_` in the current scope
2222
}
23+
match &0u8 {
24+
&(u8,)::AssocItem => {}
25+
//~^ ERROR missing angle brackets in associated item path
26+
//~| ERROR no associated item named `AssocItem` found for type `(u8,)` in the current scope
27+
}
2328
}

src/test/ui/did_you_mean/bad-assoc-pat.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ error: missing angle brackets in associated item path
1616
19 | _::AssocItem => {}
1717
| ^^^^^^^^^^^^ help: try: `<_>::AssocItem`
1818

19+
error: missing angle brackets in associated item path
20+
--> $DIR/bad-assoc-pat.rs:24:10
21+
|
22+
24 | &(u8,)::AssocItem => {}
23+
| ^^^^^^^^^^^^^^^^ help: try: `<(u8,)>::AssocItem`
24+
1925
error[E0599]: no associated item named `AssocItem` found for type `[u8]` in the current scope
2026
--> $DIR/bad-assoc-pat.rs:13:9
2127
|
@@ -34,5 +40,11 @@ error[E0599]: no associated item named `AssocItem` found for type `_` in the cur
3440
19 | _::AssocItem => {}
3541
| ^^^^^^^^^^^^ associated item not found in `_`
3642

37-
error: aborting due to 6 previous errors
43+
error[E0599]: no associated item named `AssocItem` found for type `(u8,)` in the current scope
44+
--> $DIR/bad-assoc-pat.rs:24:10
45+
|
46+
24 | &(u8,)::AssocItem => {}
47+
| ^^^^^^^^^^^^^^^^ associated item not found in `(u8,)`
48+
49+
error: aborting due to 8 previous errors
3850

src/test/ui/did_you_mean/bad-assoc-ty.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,19 @@ type E = _::AssocTy;
2828
//~^ ERROR missing angle brackets in associated item path
2929
//~| ERROR the type placeholder `_` is not allowed within types on item signatures
3030

31+
type F = &'static (u8)::AssocTy;
32+
//~^ ERROR missing angle brackets in associated item path
33+
//~| ERROR ambiguous associated type
34+
35+
// Qualified paths cannot appear in bounds, so the recovery
36+
// should apply to the whole sum and not `(Send)`.
37+
type G = 'static + (Send)::AssocTy;
38+
//~^ ERROR missing angle brackets in associated item path
39+
//~| ERROR ambiguous associated type
40+
41+
// This is actually a legal path with fn-like generic arguments in the middle!
42+
// Recovery should not apply in this context.
43+
type H = Fn(u8) -> (u8)::Output;
44+
//~^ ERROR ambiguous associated type
45+
3146
fn main() {}

src/test/ui/did_you_mean/bad-assoc-ty.stderr

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ error: missing angle brackets in associated item path
2828
27 | type E = _::AssocTy;
2929
| ^^^^^^^^^^ help: try: `<_>::AssocTy`
3030

31+
error: missing angle brackets in associated item path
32+
--> $DIR/bad-assoc-ty.rs:31:19
33+
|
34+
31 | type F = &'static (u8)::AssocTy;
35+
| ^^^^^^^^^^^^^ help: try: `<(u8)>::AssocTy`
36+
37+
error: missing angle brackets in associated item path
38+
--> $DIR/bad-assoc-ty.rs:37:10
39+
|
40+
37 | type G = 'static + (Send)::AssocTy;
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `<'static + Send>::AssocTy`
42+
3143
error[E0223]: ambiguous associated type
3244
--> $DIR/bad-assoc-ty.rs:11:10
3345
|
@@ -66,5 +78,29 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
6678
27 | type E = _::AssocTy;
6779
| ^ not allowed in type signatures
6880

69-
error: aborting due to 10 previous errors
81+
error[E0223]: ambiguous associated type
82+
--> $DIR/bad-assoc-ty.rs:31:19
83+
|
84+
31 | type F = &'static (u8)::AssocTy;
85+
| ^^^^^^^^^^^^^ ambiguous associated type
86+
|
87+
= note: specify the type using the syntax `<u8 as Trait>::AssocTy`
88+
89+
error[E0223]: ambiguous associated type
90+
--> $DIR/bad-assoc-ty.rs:37:10
91+
|
92+
37 | type G = 'static + (Send)::AssocTy;
93+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
94+
|
95+
= note: specify the type using the syntax `<std::marker::Send + 'static as Trait>::AssocTy`
96+
97+
error[E0223]: ambiguous associated type
98+
--> $DIR/bad-assoc-ty.rs:43:10
99+
|
100+
43 | type H = Fn(u8) -> (u8)::Output;
101+
| ^^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
102+
|
103+
= note: specify the type using the syntax `<std::ops::Fn(u8) -> u8 + 'static as Trait>::Output`
104+
105+
error: aborting due to 15 previous errors
70106

0 commit comments

Comments
 (0)