Skip to content

syntax: Follow-up to the incorrect qpath recovery PR #46827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 25 additions & 56 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use syntax_pos::{Span, DUMMY_SP};
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;
Expand Down Expand Up @@ -485,6 +484,30 @@ impl fmt::Debug for Pat {
}

impl Pat {
pub(super) fn to_ty(&self) -> Option<P<Ty>> {
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<F>(&self, it: &mut F) -> bool
where F: FnMut(&Pat) -> bool
{
Expand Down Expand Up @@ -520,38 +543,6 @@ impl Pat {
}
}

impl RecoverQPath for Pat {
fn to_ty(&self) -> Option<P<Ty>> {
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<QSelf>, 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 }`
Expand Down Expand Up @@ -919,10 +910,8 @@ impl Expr {
_ => None,
}
}
}

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

Some(P(Ty { node, id: self.id, span: self.span }))
}
fn to_recovered(&self, qself: Option<QSelf>, 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 {
Expand Down Expand Up @@ -1469,19 +1451,6 @@ pub struct Ty {
pub span: Span,
}

impl RecoverQPath for Ty {
fn to_ty(&self) -> Option<P<Ty>> {
Some(P(self.clone()))
}
fn to_recovered(&self, qself: Option<QSelf>, 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))
Expand Down
62 changes: 51 additions & 11 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<P<Ty>>;
fn to_recovered(&self, qself: Option<QSelf>, 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<P<Ty>> {
Some(P(self.clone()))
}
fn to_recovered(&self, qself: Option<QSelf>, 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<P<Ty>> {
self.to_ty()
}
fn to_recovered(&self, qself: Option<QSelf>, 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<P<Ty>> {
self.to_ty()
}
fn to_recovered(&self, qself: Option<QSelf>, 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 */
Expand Down Expand Up @@ -1429,7 +1467,7 @@ impl<'a> Parser<'a> {

// Parse a type
pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
self.parse_ty_common(true)
self.parse_ty_common(true, true)
}

/// Parse a type in restricted contexts where `+` is not permitted.
Expand All @@ -1438,10 +1476,11 @@ impl<'a> Parser<'a> {
/// Example 2: `value1 as TYPE + value2`
/// `+` is prohibited to avoid interactions with expression grammar.
fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
self.parse_ty_common(false)
self.parse_ty_common(false, true)
}

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

let lo = self.span;
Expand Down Expand Up @@ -1574,7 +1613,7 @@ impl<'a> Parser<'a> {

// 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))
}
Expand Down Expand Up @@ -1630,9 +1669,10 @@ impl<'a> Parser<'a> {
}

// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
fn maybe_recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: T) -> PResult<'a, T> {
fn maybe_recover_from_bad_qpath<T: RecoverQPath>(&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() {
Expand Down Expand Up @@ -1966,7 +2006,7 @@ impl<'a> Parser<'a> {
|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
};
Expand Down Expand Up @@ -2373,7 +2413,7 @@ impl<'a> Parser<'a> {
}

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));
}
Expand Down Expand Up @@ -3740,7 +3780,7 @@ impl<'a> Parser<'a> {
}

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))
}
Expand Down
6 changes: 6 additions & 0 deletions src/test/ui/did_you_mean/bad-assoc-expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
14 changes: 13 additions & 1 deletion src/test/ui/did_you_mean/bad-assoc-expr.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

5 changes: 5 additions & 0 deletions src/test/ui/did_you_mean/bad-assoc-pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
14 changes: 13 additions & 1 deletion src/test/ui/did_you_mean/bad-assoc-pat.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand All @@ -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

15 changes: 15 additions & 0 deletions src/test/ui/did_you_mean/bad-assoc-ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,19 @@ type E = _::AssocTy;
//~^ 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() {}
38 changes: 37 additions & 1 deletion src/test/ui/did_you_mean/bad-assoc-ty.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down Expand Up @@ -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 `<u8 as Trait>::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 `<std::marker::Send + 'static as Trait>::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 `<std::ops::Fn(u8) -> u8 + 'static as Trait>::Output`

error: aborting due to 15 previous errors