Make + in impl/dyn Trait non-associative

This commit is contained in:
Vadim Petrochenkov 2018-01-27 22:37:17 +03:00
parent d79f7cde06
commit f57ea7cb3d
3 changed files with 106 additions and 10 deletions

View File

@ -1528,6 +1528,7 @@ impl<'a> Parser<'a> {
maybe_whole!(self, NtTy, |x| x);
let lo = self.span;
let mut impl_dyn_multi = false;
let node = if self.eat(&token::OpenDelim(token::Paren)) {
// `(TYPE)` is a parenthesized type.
// `(TYPE,)` is a tuple with a single field of type TYPE.
@ -1614,12 +1615,17 @@ impl<'a> Parser<'a> {
self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
}
} else if self.eat_keyword(keywords::Impl) {
TyKind::ImplTrait(self.parse_ty_param_bounds_common(allow_plus)?)
// Always parse bounds greedily for better error recovery.
let bounds = self.parse_ty_param_bounds()?;
impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
TyKind::ImplTrait(bounds)
} else if self.check_keyword(keywords::Dyn) &&
self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) {
self.bump(); // `dyn`
TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?,
TraitObjectSyntax::Dyn)
// Always parse bounds greedily for better error recovery.
let bounds = self.parse_ty_param_bounds()?;
impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
} else if self.check(&token::Question) ||
self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)) {
// Bound list (trait object type)
@ -1655,6 +1661,7 @@ impl<'a> Parser<'a> {
let ty = Ty { node, span, id: ast::DUMMY_NODE_ID };
// Try to recover from use of `+` with incorrect priority.
self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
let ty = self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)?;
@ -1672,6 +1679,15 @@ impl<'a> Parser<'a> {
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
}
fn maybe_report_ambiguous_plus(&mut self, allow_plus: bool, impl_dyn_multi: bool, ty: &Ty) {
if !allow_plus && impl_dyn_multi {
let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
self.struct_span_err(ty.span, "ambiguous `+` in a type")
.span_suggestion(ty.span, "use parentheses to disambiguate", sum_with_parens)
.emit();
}
}
fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
// Do not add `+` to expected tokens.
if !allow_plus || self.token != token::BinOp(token::Plus) {

View File

@ -10,11 +10,15 @@
// compile-flags: -Z parse-only -Z continue-parse-after-error
fn f() -> impl A + {} // OK
fn f() -> impl A + B {} // OK
fn f() -> dyn A + B {} // OK
fn f() -> A + B {} // OK
impl S {
fn f(self) -> impl A + { // OK
let _ = |a, b| -> impl A + {}; // OK
}
fn f(self) -> impl A + B { // OK
let _ = |a, b| -> impl A + B {}; // OK
}
@ -26,21 +30,29 @@ impl S {
}
}
type A = fn() -> impl A +;
//~^ ERROR ambiguous `+` in a type
type A = fn() -> impl A + B;
//~^ ERROR expected a path on the left-hand side of `+`, not `fn() -> impl A`
//~^ ERROR ambiguous `+` in a type
type A = fn() -> dyn A + B;
//~^ ERROR expected a path on the left-hand side of `+`, not `fn() -> dyn A`
//~^ ERROR ambiguous `+` in a type
type A = fn() -> A + B;
//~^ ERROR expected a path on the left-hand side of `+`, not `fn() -> A`
type A = Fn() -> impl A + B; // OK, interpreted as `(Fn() -> impl A) + B`
type A = Fn() -> dyn A + B; // OK, interpreted as `(Fn() -> dyn A) + B`
type A = Fn() -> A + B; // OK, interpreted as `(Fn() -> A) + B`
type A = Fn() -> impl A +;
//~^ ERROR ambiguous `+` in a type
type A = Fn() -> impl A + B;
//~^ ERROR ambiguous `+` in a type
type A = Fn() -> dyn A + B;
//~^ ERROR ambiguous `+` in a type
type A = Fn() -> A + B; // OK, interpreted as `(Fn() -> A) + B` for compatibility
type A = &impl A +;
//~^ ERROR ambiguous `+` in a type
type A = &impl A + B;
//~^ ERROR expected a path on the left-hand side of `+`, not `&impl A`
//~^ ERROR ambiguous `+` in a type
type A = &dyn A + B;
//~^ ERROR expected a path on the left-hand side of `+`, not `&dyn A`
//~^ ERROR ambiguous `+` in a type
type A = &A + B;
//~^ ERROR expected a path on the left-hand side of `+`, not `&A`

View File

@ -0,0 +1,68 @@
error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:33:18
|
33 | type A = fn() -> impl A +;
| ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)`
error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:35:18
|
35 | type A = fn() -> impl A + B;
| ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)`
error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:37:18
|
37 | type A = fn() -> dyn A + B;
| ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)`
error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A`
--> $DIR/impl-trait-plus-priority.rs:39:10
|
39 | type A = fn() -> A + B;
| ^^^^^^^^^^^^^ perhaps you forgot parentheses?
error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:42:18
|
42 | type A = Fn() -> impl A +;
| ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)`
error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:44:18
|
44 | type A = Fn() -> impl A + B;
| ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)`
error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:46:18
|
46 | type A = Fn() -> dyn A + B;
| ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)`
error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:50:11
|
50 | type A = &impl A +;
| ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)`
error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:52:11
|
52 | type A = &impl A + B;
| ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)`
error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:54:11
|
54 | type A = &dyn A + B;
| ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)`
error[E0178]: expected a path on the left-hand side of `+`, not `&A`
--> $DIR/impl-trait-plus-priority.rs:56:10
|
56 | type A = &A + B;
| ^^^^^^ help: try adding parentheses: `&(A + B)`
error: aborting due to 11 previous errors