Rollup merge of #46827 - petrochenkov:assocrecov2, r=estebank
syntax: Follow-up to the incorrect qpath recovery PR cc https://github.com/rust-lang/rust/pull/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
This commit is contained in:
commit
2917ac6b59
@ -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<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
|
||||
{
|
||||
@ -520,38 +543,6 @@ pub fn walk<F>(&self, it: &mut F) -> bool
|
||||
}
|
||||
}
|
||||
|
||||
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 }`
|
||||
@ -919,10 +910,8 @@ fn to_bound(&self) -> Option<TyParamBound> {
|
||||
_ => 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()),
|
||||
@ -951,13 +940,6 @@ fn to_ty(&self) -> Option<P<Ty>> {
|
||||
|
||||
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 {
|
||||
@ -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))
|
||||
|
@ -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 */
|
||||
@ -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<Ty>> {
|
||||
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<Ty>> {
|
||||
/// 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;
|
||||
@ -1577,7 +1616,7 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
|
||||
|
||||
// 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<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() {
|
||||
@ -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<Expr>> {
|
||||
}
|
||||
|
||||
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<Pat>> {
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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 `<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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user