diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 461cb0480d2..1d399f159c8 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -20,7 +20,6 @@
use codemap::{respan, Spanned};
use abi::Abi;
use ext::hygiene::{Mark, SyntaxContext};
-use parse::parser::{RecoverQPath, PathStyle};
use print::pprust;
use ptr::P;
use rustc_data_structures::indexed_vec;
@@ -485,6 +484,30 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
impl Pat {
+ pub(super) fn to_ty(&self) -> Option
> {
+ let node = match &self.node {
+ PatKind::Wild => TyKind::Infer,
+ PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None) =>
+ TyKind::Path(None, Path::from_ident(ident.span, ident.node)),
+ PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
+ PatKind::Mac(mac) => TyKind::Mac(mac.clone()),
+ PatKind::Ref(pat, mutbl) =>
+ pat.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?,
+ PatKind::Slice(pats, None, _) if pats.len() == 1 =>
+ pats[0].to_ty().map(TyKind::Slice)?,
+ PatKind::Tuple(pats, None) => {
+ let mut tys = Vec::new();
+ for pat in pats {
+ tys.push(pat.to_ty()?);
+ }
+ TyKind::Tup(tys)
+ }
+ _ => return None,
+ };
+
+ Some(P(Ty { node, id: self.id, span: self.span }))
+ }
+
pub fn walk(&self, it: &mut F) -> bool
where F: FnMut(&Pat) -> bool
{
@@ -520,38 +543,6 @@ pub fn walk(&self, it: &mut F) -> bool
}
}
-impl RecoverQPath for Pat {
- fn to_ty(&self) -> Option> {
- let node = match &self.node {
- PatKind::Wild => TyKind::Infer,
- PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None) =>
- TyKind::Path(None, Path::from_ident(ident.span, ident.node)),
- PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
- PatKind::Mac(mac) => TyKind::Mac(mac.clone()),
- PatKind::Ref(pat, mutbl) =>
- pat.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?,
- PatKind::Slice(pats, None, _) if pats.len() == 1 =>
- pats[0].to_ty().map(TyKind::Slice)?,
- PatKind::Tuple(pats, None) => {
- let mut tys = Vec::new();
- for pat in pats {
- tys.push(pat.to_ty()?);
- }
- TyKind::Tup(tys)
- }
- _ => return None,
- };
-
- Some(P(Ty { node, id: self.id, span: self.span }))
- }
- fn to_recovered(&self, qself: Option, path: Path) -> Self {
- Self { span: path.span, node: PatKind::Path(qself, path), id: self.id }
- }
- fn to_string(&self) -> String {
- pprust::pat_to_string(self)
- }
-}
-
/// A single field in a struct pattern
///
/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
@@ -919,10 +910,8 @@ fn to_bound(&self) -> Option {
_ => None,
}
}
-}
-impl RecoverQPath for Expr {
- fn to_ty(&self) -> Option> {
+ pub(super) fn to_ty(&self) -> Option
> {
let node = match &self.node {
ExprKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
ExprKind::Mac(mac) => TyKind::Mac(mac.clone()),
@@ -951,13 +940,6 @@ fn to_ty(&self) -> Option
> {
Some(P(Ty { node, id: self.id, span: self.span }))
}
- fn to_recovered(&self, qself: Option, path: Path) -> Self {
- Self { span: path.span, node: ExprKind::Path(qself, path),
- id: self.id, attrs: self.attrs.clone() }
- }
- fn to_string(&self) -> String {
- pprust::expr_to_string(self)
- }
}
impl fmt::Debug for Expr {
@@ -1469,19 +1451,6 @@ pub struct Ty {
pub span: Span,
}
-impl RecoverQPath for Ty {
- fn to_ty(&self) -> Option> {
- Some(P(self.clone()))
- }
- fn to_recovered(&self, qself: Option, path: Path) -> Self {
- Self { span: path.span, node: TyKind::Path(qself, path), id: self.id }
- }
- fn to_string(&self) -> String {
- pprust::ty_to_string(self)
- }
- const PATH_STYLE: PathStyle = PathStyle::Type;
-}
-
impl fmt::Debug for Ty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "type({})", pprust::ty_to_string(self))
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 2aac7ef39f2..d9434539246 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -169,11 +169,49 @@ enum PrevTokenKind {
Other,
}
-pub(crate) trait RecoverQPath: Sized {
+trait RecoverQPath: Sized {
+ const PATH_STYLE: PathStyle = PathStyle::Expr;
fn to_ty(&self) -> Option>;
fn to_recovered(&self, qself: Option, path: ast::Path) -> Self;
fn to_string(&self) -> String;
- const PATH_STYLE: PathStyle = PathStyle::Expr;
+}
+
+impl RecoverQPath for Ty {
+ const PATH_STYLE: PathStyle = PathStyle::Type;
+ fn to_ty(&self) -> Option> {
+ Some(P(self.clone()))
+ }
+ fn to_recovered(&self, qself: Option, path: ast::Path) -> Self {
+ Self { span: path.span, node: TyKind::Path(qself, path), id: self.id }
+ }
+ fn to_string(&self) -> String {
+ pprust::ty_to_string(self)
+ }
+}
+
+impl RecoverQPath for Pat {
+ fn to_ty(&self) -> Option> {
+ self.to_ty()
+ }
+ fn to_recovered(&self, qself: Option, path: ast::Path) -> Self {
+ Self { span: path.span, node: PatKind::Path(qself, path), id: self.id }
+ }
+ fn to_string(&self) -> String {
+ pprust::pat_to_string(self)
+ }
+}
+
+impl RecoverQPath for Expr {
+ fn to_ty(&self) -> Option> {
+ self.to_ty()
+ }
+ fn to_recovered(&self, qself: Option, path: ast::Path) -> Self {
+ Self { span: path.span, node: ExprKind::Path(qself, path),
+ id: self.id, attrs: self.attrs.clone() }
+ }
+ fn to_string(&self) -> String {
+ pprust::expr_to_string(self)
+ }
}
/* ident is handled by common.rs */
@@ -1432,7 +1470,7 @@ pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> {
// Parse a type
pub fn parse_ty(&mut self) -> PResult<'a, P> {
- self.parse_ty_common(true)
+ self.parse_ty_common(true, true)
}
/// Parse a type in restricted contexts where `+` is not permitted.
@@ -1441,10 +1479,11 @@ pub fn parse_ty(&mut self) -> PResult<'a, P> {
/// Example 2: `value1 as TYPE + value2`
/// `+` is prohibited to avoid interactions with expression grammar.
fn parse_ty_no_plus(&mut self) -> PResult<'a, P> {
- self.parse_ty_common(false)
+ self.parse_ty_common(false, true)
}
- fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P> {
+ fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool)
+ -> PResult<'a, P> {
maybe_whole!(self, NtTy, |x| x);
let lo = self.span;
@@ -1577,7 +1616,7 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P> {
// Try to recover from use of `+` with incorrect priority.
self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
- let ty = self.maybe_recover_from_bad_qpath(ty)?;
+ let ty = self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)?;
Ok(P(ty))
}
@@ -1633,9 +1672,10 @@ fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PRe
}
// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
- fn maybe_recover_from_bad_qpath(&mut self, base: T) -> PResult<'a, T> {
+ fn maybe_recover_from_bad_qpath(&mut self, base: T, allow_recovery: bool)
+ -> PResult<'a, T> {
// Do not add `::` to expected tokens.
- if self.token != token::ModSep {
+ if !allow_recovery || self.token != token::ModSep {
return Ok(base);
}
let ty = match base.to_ty() {
@@ -1969,7 +2009,7 @@ fn parse_path_segment(&mut self, style: PathStyle, enable_warning: bool)
|p| p.parse_ty())?;
self.bump(); // `)`
let output = if self.eat(&token::RArrow) {
- Some(self.parse_ty_no_plus()?)
+ Some(self.parse_ty_common(false, false)?)
} else {
None
};
@@ -2376,7 +2416,7 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P> {
}
let expr = Expr { node: ex, span: lo.to(hi), id: ast::DUMMY_NODE_ID, attrs };
- let expr = self.maybe_recover_from_bad_qpath(expr)?;
+ let expr = self.maybe_recover_from_bad_qpath(expr, true)?;
return Ok(P(expr));
}
@@ -3743,7 +3783,7 @@ pub fn parse_pat(&mut self) -> PResult<'a, P> {
}
let pat = Pat { node: pat, span: lo.to(self.prev_span), id: ast::DUMMY_NODE_ID };
- let pat = self.maybe_recover_from_bad_qpath(pat)?;
+ let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
Ok(P(pat))
}
diff --git a/src/test/ui/did_you_mean/bad-assoc-expr.rs b/src/test/ui/did_you_mean/bad-assoc-expr.rs
index 72b616ddd69..779aa952c81 100644
--- a/src/test/ui/did_you_mean/bad-assoc-expr.rs
+++ b/src/test/ui/did_you_mean/bad-assoc-expr.rs
@@ -21,4 +21,10 @@ fn main() {
(u8, u8)::clone(&(0, 0));
//~^ ERROR missing angle brackets in associated item path
+
+ &(u8)::clone(&0);
+ //~^ ERROR missing angle brackets in associated item path
+
+ 10 + (u8)::clone(&0);
+ //~^ ERROR missing angle brackets in associated item path
}
diff --git a/src/test/ui/did_you_mean/bad-assoc-expr.stderr b/src/test/ui/did_you_mean/bad-assoc-expr.stderr
index 1f8fc118f78..1affdc5fda2 100644
--- a/src/test/ui/did_you_mean/bad-assoc-expr.stderr
+++ b/src/test/ui/did_you_mean/bad-assoc-expr.stderr
@@ -22,5 +22,17 @@ error: missing angle brackets in associated item path
22 | (u8, u8)::clone(&(0, 0));
| ^^^^^^^^^^^^^^^ help: try: `<(u8, u8)>::clone`
-error: aborting due to 4 previous errors
+error: missing angle brackets in associated item path
+ --> $DIR/bad-assoc-expr.rs:25:6
+ |
+25 | &(u8)::clone(&0);
+ | ^^^^^^^^^^^ help: try: `<(u8)>::clone`
+
+error: missing angle brackets in associated item path
+ --> $DIR/bad-assoc-expr.rs:28:10
+ |
+28 | 10 + (u8)::clone(&0);
+ | ^^^^^^^^^^^ help: try: `<(u8)>::clone`
+
+error: aborting due to 6 previous errors
diff --git a/src/test/ui/did_you_mean/bad-assoc-pat.rs b/src/test/ui/did_you_mean/bad-assoc-pat.rs
index e6b7127f100..bf6be0ee985 100644
--- a/src/test/ui/did_you_mean/bad-assoc-pat.rs
+++ b/src/test/ui/did_you_mean/bad-assoc-pat.rs
@@ -20,4 +20,9 @@ fn main() {
//~^ ERROR missing angle brackets in associated item path
//~| ERROR no associated item named `AssocItem` found for type `_` in the current scope
}
+ match &0u8 {
+ &(u8,)::AssocItem => {}
+ //~^ ERROR missing angle brackets in associated item path
+ //~| ERROR no associated item named `AssocItem` found for type `(u8,)` in the current scope
+ }
}
diff --git a/src/test/ui/did_you_mean/bad-assoc-pat.stderr b/src/test/ui/did_you_mean/bad-assoc-pat.stderr
index 20f9b96dbaa..1ca4576d88f 100644
--- a/src/test/ui/did_you_mean/bad-assoc-pat.stderr
+++ b/src/test/ui/did_you_mean/bad-assoc-pat.stderr
@@ -16,6 +16,12 @@ error: missing angle brackets in associated item path
19 | _::AssocItem => {}
| ^^^^^^^^^^^^ help: try: `<_>::AssocItem`
+error: missing angle brackets in associated item path
+ --> $DIR/bad-assoc-pat.rs:24:10
+ |
+24 | &(u8,)::AssocItem => {}
+ | ^^^^^^^^^^^^^^^^ help: try: `<(u8,)>::AssocItem`
+
error[E0599]: no associated item named `AssocItem` found for type `[u8]` in the current scope
--> $DIR/bad-assoc-pat.rs:13:9
|
@@ -34,5 +40,11 @@ error[E0599]: no associated item named `AssocItem` found for type `_` in the cur
19 | _::AssocItem => {}
| ^^^^^^^^^^^^ associated item not found in `_`
-error: aborting due to 6 previous errors
+error[E0599]: no associated item named `AssocItem` found for type `(u8,)` in the current scope
+ --> $DIR/bad-assoc-pat.rs:24:10
+ |
+24 | &(u8,)::AssocItem => {}
+ | ^^^^^^^^^^^^^^^^ associated item not found in `(u8,)`
+
+error: aborting due to 8 previous errors
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs
index 45a52936738..b4a59904ee4 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.rs
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs
@@ -28,4 +28,19 @@
//~^ ERROR missing angle brackets in associated item path
//~| ERROR the type placeholder `_` is not allowed within types on item signatures
+type F = &'static (u8)::AssocTy;
+//~^ ERROR missing angle brackets in associated item path
+//~| ERROR ambiguous associated type
+
+// Qualified paths cannot appear in bounds, so the recovery
+// should apply to the whole sum and not `(Send)`.
+type G = 'static + (Send)::AssocTy;
+//~^ ERROR missing angle brackets in associated item path
+//~| ERROR ambiguous associated type
+
+// This is actually a legal path with fn-like generic arguments in the middle!
+// Recovery should not apply in this context.
+type H = Fn(u8) -> (u8)::Output;
+//~^ ERROR ambiguous associated type
+
fn main() {}
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
index 617339a7d92..c44dc5a0468 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
@@ -28,6 +28,18 @@ error: missing angle brackets in associated item path
27 | type E = _::AssocTy;
| ^^^^^^^^^^ help: try: `<_>::AssocTy`
+error: missing angle brackets in associated item path
+ --> $DIR/bad-assoc-ty.rs:31:19
+ |
+31 | type F = &'static (u8)::AssocTy;
+ | ^^^^^^^^^^^^^ help: try: `<(u8)>::AssocTy`
+
+error: missing angle brackets in associated item path
+ --> $DIR/bad-assoc-ty.rs:37:10
+ |
+37 | type G = 'static + (Send)::AssocTy;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `<'static + Send>::AssocTy`
+
error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:11:10
|
@@ -66,5 +78,29 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
27 | type E = _::AssocTy;
| ^ not allowed in type signatures
-error: aborting due to 10 previous errors
+error[E0223]: ambiguous associated type
+ --> $DIR/bad-assoc-ty.rs:31:19
+ |
+31 | type F = &'static (u8)::AssocTy;
+ | ^^^^^^^^^^^^^ ambiguous associated type
+ |
+ = note: specify the type using the syntax `::AssocTy`
+
+error[E0223]: ambiguous associated type
+ --> $DIR/bad-assoc-ty.rs:37:10
+ |
+37 | type G = 'static + (Send)::AssocTy;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
+ |
+ = note: specify the type using the syntax `::AssocTy`
+
+error[E0223]: ambiguous associated type
+ --> $DIR/bad-assoc-ty.rs:43:10
+ |
+43 | type H = Fn(u8) -> (u8)::Output;
+ | ^^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
+ |
+ = note: specify the type using the syntax ` u8 + 'static as Trait>::Output`
+
+error: aborting due to 15 previous errors