Rollup merge of #139854 - fmease:modern-diag-for-lt-in-ty, r=davidtwco
Improve parse errors for stray lifetimes in type position While technically & syntactically speaking lifetimes do begin[^1] types in type contexts (this essentially excludes generic argument lists) and require a following `+` to form a complete type (`'a +` denotes a bare trait object type), the likelihood that a user meant to write a lifetime-prefixed bare trait object type in *modern* editions (Rust ≥2021) when placing a lifetime into a type context is incredibly low (they would need to add at least three tokens to turn it into a *semantically* well-formed TOT: `'a` → `dyn 'a + Trait`). Therefore let's *lie* in modern editions (just like in PR https://github.com/rust-lang/rust/pull/131239, a precedent if you will) by stating "*expected type, found lifetime*" in such cases which is a lot more a approachable, digestible and friendly compared to "*lifetime in trait object type must be followed by `+`*" (as added in PR https://github.com/rust-lang/rust/pull/69760). I've also added recovery for "ampersand-less" reference types (e.g., `'a ()`, `'a mut Ty`) in modern editions because it was trivial to do and I think it's not unlikely to occur in practice. Fixes #133413. [^1]: For example, in the context of decl macros, this implies that a lone `'a` always matches syntax fragment `ty` ("even if" there's a later macro matcher expecting syntax fragment `lifetime`). Rephrased, lifetimes (in type contexts) *commit* to the type parser.
This commit is contained in:
commit
7ab385e2e1
25 changed files with 283 additions and 92 deletions
|
@ -543,7 +543,7 @@ parse_maybe_recover_from_bad_qpath_stage_2 =
|
||||||
.suggestion = types that don't start with an identifier need to be surrounded with angle brackets in qualified paths
|
.suggestion = types that don't start with an identifier need to be surrounded with angle brackets in qualified paths
|
||||||
|
|
||||||
parse_maybe_recover_from_bad_type_plus =
|
parse_maybe_recover_from_bad_type_plus =
|
||||||
expected a path on the left-hand side of `+`, not `{$ty}`
|
expected a path on the left-hand side of `+`
|
||||||
|
|
||||||
parse_maybe_report_ambiguous_plus =
|
parse_maybe_report_ambiguous_plus =
|
||||||
ambiguous `+` in a type
|
ambiguous `+` in a type
|
||||||
|
@ -642,7 +642,9 @@ parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual bi
|
||||||
.suggestion = add `mut` to each binding
|
.suggestion = add `mut` to each binding
|
||||||
parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
|
parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
|
||||||
.suggestion = remove the `mut` prefix
|
.suggestion = remove the `mut` prefix
|
||||||
parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+`
|
|
||||||
|
parse_need_plus_after_trait_object_lifetime = lifetimes must be followed by `+` to form a trait object type
|
||||||
|
.suggestion = consider adding a trait bound after the potential lifetime bound
|
||||||
|
|
||||||
parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}`
|
parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}`
|
||||||
.suggestion = consider creating a new `{$kw_str}` definition instead of nesting
|
.suggestion = consider creating a new `{$kw_str}` definition instead of nesting
|
||||||
|
|
|
@ -30,7 +30,6 @@ pub(crate) struct AmbiguousPlus {
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_maybe_recover_from_bad_type_plus, code = E0178)]
|
#[diag(parse_maybe_recover_from_bad_type_plus, code = E0178)]
|
||||||
pub(crate) struct BadTypePlus {
|
pub(crate) struct BadTypePlus {
|
||||||
pub ty: String,
|
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
|
@ -2806,6 +2805,8 @@ pub(crate) struct ReturnTypesUseThinArrow {
|
||||||
pub(crate) struct NeedPlusAfterTraitObjectLifetime {
|
pub(crate) struct NeedPlusAfterTraitObjectLifetime {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
#[suggestion(code = " + /* Trait */", applicability = "has-placeholders")]
|
||||||
|
pub suggestion: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
|
|
@ -1657,19 +1657,19 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
self.bump(); // `+`
|
self.bump(); // `+`
|
||||||
let _bounds = self.parse_generic_bounds()?;
|
let _bounds = self.parse_generic_bounds()?;
|
||||||
let sum_span = ty.span.to(self.prev_token.span);
|
|
||||||
|
|
||||||
let sub = match &ty.kind {
|
let sub = match &ty.kind {
|
||||||
TyKind::Ref(_lifetime, mut_ty) => {
|
TyKind::Ref(_lifetime, mut_ty) => {
|
||||||
let lo = mut_ty.ty.span.shrink_to_lo();
|
let lo = mut_ty.ty.span.shrink_to_lo();
|
||||||
let hi = self.prev_token.span.shrink_to_hi();
|
let hi = self.prev_token.span.shrink_to_hi();
|
||||||
BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } }
|
BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } }
|
||||||
}
|
}
|
||||||
TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span },
|
TyKind::Ptr(..) | TyKind::BareFn(..) => {
|
||||||
_ => BadTypePlusSub::ExpectPath { span: sum_span },
|
BadTypePlusSub::ForgotParen { span: ty.span.to(self.prev_token.span) }
|
||||||
|
}
|
||||||
|
_ => BadTypePlusSub::ExpectPath { span: ty.span },
|
||||||
};
|
};
|
||||||
|
|
||||||
self.dcx().emit_err(BadTypePlus { ty: pprust::ty_to_string(ty), span: sum_span, sub });
|
self.dcx().emit_err(BadTypePlus { span: ty.span, sub });
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rustc_ast::{
|
||||||
Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
|
Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
|
||||||
TyKind, UnsafeBinderTy,
|
TyKind, UnsafeBinderTy,
|
||||||
};
|
};
|
||||||
use rustc_errors::{Applicability, PResult};
|
use rustc_errors::{Applicability, Diag, PResult};
|
||||||
use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym};
|
use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym};
|
||||||
use thin_vec::{ThinVec, thin_vec};
|
use thin_vec::{ThinVec, thin_vec};
|
||||||
|
|
||||||
|
@ -411,6 +411,9 @@ impl<'a> Parser<'a> {
|
||||||
TyKind::Path(None, path) if maybe_bounds => {
|
TyKind::Path(None, path) if maybe_bounds => {
|
||||||
self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true)
|
self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true)
|
||||||
}
|
}
|
||||||
|
// For `('a) + …`, we know that `'a` in type position already lead to an error being
|
||||||
|
// emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and
|
||||||
|
// other irrelevant consequential errors.
|
||||||
TyKind::TraitObject(bounds, TraitObjectSyntax::None)
|
TyKind::TraitObject(bounds, TraitObjectSyntax::None)
|
||||||
if maybe_bounds && bounds.len() == 1 && !trailing_plus =>
|
if maybe_bounds && bounds.len() == 1 && !trailing_plus =>
|
||||||
{
|
{
|
||||||
|
@ -425,12 +428,60 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
|
fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
|
||||||
let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
|
// A lifetime only begins a bare trait object type if it is followed by `+`!
|
||||||
let bounds = self.parse_generic_bounds_common(allow_plus)?;
|
if self.token.is_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()) {
|
||||||
if lt_no_plus {
|
// In Rust 2021 and beyond, we assume that the user didn't intend to write a bare trait
|
||||||
self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
|
// object type with a leading lifetime bound since that seems very unlikely given the
|
||||||
|
// fact that `dyn`-less trait objects are *semantically* invalid.
|
||||||
|
if self.psess.edition.at_least_rust_2021() {
|
||||||
|
let lt = self.expect_lifetime();
|
||||||
|
let mut err = self.dcx().struct_span_err(lo, "expected type, found lifetime");
|
||||||
|
err.span_label(lo, "expected type");
|
||||||
|
return Ok(match self.maybe_recover_ref_ty_no_leading_ampersand(lt, lo, err) {
|
||||||
|
Ok(ref_ty) => ref_ty,
|
||||||
|
Err(err) => TyKind::Err(err.emit()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime {
|
||||||
|
span: lo,
|
||||||
|
suggestion: lo.shrink_to_hi(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(TyKind::TraitObject(
|
||||||
|
self.parse_generic_bounds_common(allow_plus)?,
|
||||||
|
TraitObjectSyntax::None,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_recover_ref_ty_no_leading_ampersand<'cx>(
|
||||||
|
&mut self,
|
||||||
|
lt: Lifetime,
|
||||||
|
lo: Span,
|
||||||
|
mut err: Diag<'cx>,
|
||||||
|
) -> Result<TyKind, Diag<'cx>> {
|
||||||
|
if !self.may_recover() {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
|
let mutbl = self.parse_mutability();
|
||||||
|
match self.parse_ty_no_plus() {
|
||||||
|
Ok(ty) => {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
lo.shrink_to_lo(),
|
||||||
|
"you might have meant to write a reference type here",
|
||||||
|
"&",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
err.emit();
|
||||||
|
Ok(TyKind::Ref(Some(lt), MutTy { ty, mutbl }))
|
||||||
|
}
|
||||||
|
Err(diag) => {
|
||||||
|
diag.cancel();
|
||||||
|
self.restore_snapshot(snapshot);
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_remaining_bounds_path(
|
fn parse_remaining_bounds_path(
|
||||||
|
|
|
@ -1,41 +1,43 @@
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/E0178.rs:6:8
|
--> $DIR/E0178.rs:6:8
|
||||||
|
|
|
|
||||||
LL | w: &'a Foo + Copy,
|
LL | w: &'a Foo + Copy,
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
help: try adding parentheses
|
help: try adding parentheses
|
||||||
|
|
|
|
||||||
LL | w: &'a (Foo + Copy),
|
LL | w: &'a (Foo + Copy),
|
||||||
| + +
|
| + +
|
||||||
|
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/E0178.rs:7:8
|
--> $DIR/E0178.rs:7:8
|
||||||
|
|
|
|
||||||
LL | x: &'a Foo + 'a,
|
LL | x: &'a Foo + 'a,
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
help: try adding parentheses
|
help: try adding parentheses
|
||||||
|
|
|
|
||||||
LL | x: &'a (Foo + 'a),
|
LL | x: &'a (Foo + 'a),
|
||||||
| + +
|
| + +
|
||||||
|
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `&'a mut Foo`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/E0178.rs:8:8
|
--> $DIR/E0178.rs:8:8
|
||||||
|
|
|
|
||||||
LL | y: &'a mut Foo + 'a,
|
LL | y: &'a mut Foo + 'a,
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: try adding parentheses
|
help: try adding parentheses
|
||||||
|
|
|
|
||||||
LL | y: &'a mut (Foo + 'a),
|
LL | y: &'a mut (Foo + 'a),
|
||||||
| + +
|
| + +
|
||||||
|
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> Foo`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/E0178.rs:9:8
|
--> $DIR/E0178.rs:9:8
|
||||||
|
|
|
|
||||||
LL | z: fn() -> Foo + 'a,
|
LL | z: fn() -> Foo + 'a,
|
||||||
| ^^^^^^^^^^^^^^^^ perhaps you forgot parentheses?
|
| ^^^^^^^^^^^-----
|
||||||
|
| |
|
||||||
|
| perhaps you forgot parentheses?
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `&Copy`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12
|
--> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12
|
||||||
|
|
|
|
||||||
LL | let _: &Copy + 'static;
|
LL | let _: &Copy + 'static;
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
help: try adding parentheses
|
help: try adding parentheses
|
||||||
|
|
|
|
||||||
LL | let _: &(Copy + 'static);
|
LL | let _: &(Copy + 'static);
|
||||||
| + +
|
| + +
|
||||||
|
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12
|
--> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12
|
||||||
|
|
|
|
||||||
LL | let _: &'static Copy + 'static;
|
LL | let _: &'static Copy + 'static;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: try adding parentheses
|
help: try adding parentheses
|
||||||
|
|
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ trait X {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
|
fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
|
||||||
//~^ ERROR: lifetime in trait object type must be followed by `+`
|
//~^ ERROR: lifetimes must be followed by `+` to form a trait object type
|
||||||
//~| ERROR: parenthesized generic arguments cannot be used
|
//~| ERROR: parenthesized generic arguments cannot be used
|
||||||
//~| ERROR associated type takes 0 generic arguments but 1 generic argument
|
//~| ERROR associated type takes 0 generic arguments but 1 generic argument
|
||||||
//~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
|
//~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
error: lifetime in trait object type must be followed by `+`
|
error: lifetimes must be followed by `+` to form a trait object type
|
||||||
--> $DIR/gat-trait-path-parenthesised-args.rs:5:29
|
--> $DIR/gat-trait-path-parenthesised-args.rs:5:29
|
||||||
|
|
|
|
||||||
LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
|
LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
|
||||||
| ^^
|
| ^^
|
||||||
|
|
|
||||||
|
help: consider adding a trait bound after the potential lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn foo<'a>(arg: Box<dyn X<Y('a + /* Trait */) = &'a ()>>) {}
|
||||||
|
| +++++++++++++
|
||||||
|
|
||||||
error: parenthesized generic arguments cannot be used in associated type constraints
|
error: parenthesized generic arguments cannot be used in associated type constraints
|
||||||
--> $DIR/gat-trait-path-parenthesised-args.rs:5:27
|
--> $DIR/gat-trait-path-parenthesised-args.rs:5:27
|
||||||
|
|
|
@ -27,7 +27,7 @@ type A = fn() -> impl A + B;
|
||||||
type A = fn() -> dyn A + B;
|
type A = fn() -> dyn A + B;
|
||||||
//~^ ERROR ambiguous `+` in a type
|
//~^ ERROR ambiguous `+` in a type
|
||||||
type A = fn() -> A + B;
|
type A = fn() -> A + B;
|
||||||
//~^ ERROR expected a path on the left-hand side of `+`, not `fn() -> A`
|
//~^ ERROR expected a path on the left-hand side of `+`
|
||||||
|
|
||||||
type A = Fn() -> impl A +;
|
type A = Fn() -> impl A +;
|
||||||
//~^ ERROR ambiguous `+` in a type
|
//~^ ERROR ambiguous `+` in a type
|
||||||
|
@ -44,6 +44,6 @@ type A = &impl A + B;
|
||||||
type A = &dyn A + B;
|
type A = &dyn A + B;
|
||||||
//~^ ERROR ambiguous `+` in a type
|
//~^ ERROR ambiguous `+` in a type
|
||||||
type A = &A + B;
|
type A = &A + B;
|
||||||
//~^ ERROR expected a path on the left-hand side of `+`, not `&A`
|
//~^ ERROR expected a path on the left-hand side of `+`
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -31,11 +31,13 @@ help: try adding parentheses
|
||||||
LL | type A = fn() -> (dyn A + B);
|
LL | type A = fn() -> (dyn A + B);
|
||||||
| + +
|
| + +
|
||||||
|
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/impl-trait-plus-priority.rs:29:10
|
--> $DIR/impl-trait-plus-priority.rs:29:10
|
||||||
|
|
|
|
||||||
LL | type A = fn() -> A + B;
|
LL | type A = fn() -> A + B;
|
||||||
| ^^^^^^^^^^^^^ perhaps you forgot parentheses?
|
| ^^^^^^^^^----
|
||||||
|
| |
|
||||||
|
| perhaps you forgot parentheses?
|
||||||
|
|
||||||
error: ambiguous `+` in a type
|
error: ambiguous `+` in a type
|
||||||
--> $DIR/impl-trait-plus-priority.rs:32:18
|
--> $DIR/impl-trait-plus-priority.rs:32:18
|
||||||
|
@ -103,11 +105,11 @@ help: try adding parentheses
|
||||||
LL | type A = &(dyn A + B);
|
LL | type A = &(dyn A + B);
|
||||||
| + +
|
| + +
|
||||||
|
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `&A`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/impl-trait-plus-priority.rs:46:10
|
--> $DIR/impl-trait-plus-priority.rs:46:10
|
||||||
|
|
|
|
||||||
LL | type A = &A + B;
|
LL | type A = &A + B;
|
||||||
| ^^^^^^
|
| ^^
|
||||||
|
|
|
|
||||||
help: try adding parentheses
|
help: try adding parentheses
|
||||||
|
|
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ mac!('a);
|
||||||
|
|
||||||
// avoid false positives
|
// avoid false positives
|
||||||
fn y<'a>(y: &mut 'a + Send) {
|
fn y<'a>(y: &mut 'a + Send) {
|
||||||
//~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a`
|
//~^ ERROR expected a path on the left-hand side of `+`
|
||||||
//~| ERROR at least one trait is required for an object type
|
//~| ERROR at least one trait is required for an object type
|
||||||
let z = y as &mut 'a + Send;
|
let z = y as &mut 'a + Send;
|
||||||
//~^ ERROR expected value, found trait `Send`
|
//~^ ERROR expected value, found trait `Send`
|
||||||
|
|
|
@ -10,11 +10,11 @@ LL - fn x<'a>(x: &mut 'a i32){}
|
||||||
LL + fn x<'a>(x: &'a mut i32){}
|
LL + fn x<'a>(x: &'a mut i32){}
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/issue-73568-lifetime-after-mut.rs:14:13
|
--> $DIR/issue-73568-lifetime-after-mut.rs:14:13
|
||||||
|
|
|
|
||||||
LL | fn y<'a>(y: &mut 'a + Send) {
|
LL | fn y<'a>(y: &mut 'a + Send) {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
help: try adding parentheses
|
help: try adding parentheses
|
||||||
|
|
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
error: lifetimes must be followed by `+` to form a trait object type
|
||||||
|
--> $DIR/trait-object-macro-matcher.rs:17:8
|
||||||
|
|
|
||||||
|
LL | m!('static);
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider adding a trait bound after the potential lifetime bound
|
||||||
|
|
|
||||||
|
LL | m!('static + /* Trait */);
|
||||||
|
| +++++++++++++
|
||||||
|
|
||||||
|
error: lifetimes must be followed by `+` to form a trait object type
|
||||||
|
--> $DIR/trait-object-macro-matcher.rs:17:8
|
||||||
|
|
|
||||||
|
LL | m!('static);
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
help: consider adding a trait bound after the potential lifetime bound
|
||||||
|
|
|
||||||
|
LL | m!('static + /* Trait */);
|
||||||
|
| +++++++++++++
|
||||||
|
|
||||||
|
error[E0224]: at least one trait is required for an object type
|
||||||
|
--> $DIR/trait-object-macro-matcher.rs:17:8
|
||||||
|
|
|
||||||
|
LL | m!('static);
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0224`.
|
|
@ -0,0 +1,16 @@
|
||||||
|
error: expected type, found lifetime
|
||||||
|
--> $DIR/trait-object-macro-matcher.rs:17:8
|
||||||
|
|
|
||||||
|
LL | m!('static);
|
||||||
|
| ^^^^^^^ expected type
|
||||||
|
|
||||||
|
error: expected type, found lifetime
|
||||||
|
--> $DIR/trait-object-macro-matcher.rs:17:8
|
||||||
|
|
|
||||||
|
LL | m!('static);
|
||||||
|
| ^^^^^^^ expected type
|
||||||
|
|
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
// A single lifetime is not parsed as a type.
|
// A single lifetime is not parsed as a type.
|
||||||
// `ty` matcher in particular doesn't accept a single lifetime
|
// `ty` matcher in particular doesn't accept a single lifetime
|
||||||
|
|
||||||
|
//@ revisions: e2015 e2021
|
||||||
|
//@[e2015] edition: 2015
|
||||||
|
//@[e2021] edition: 2021
|
||||||
|
|
||||||
macro_rules! m {
|
macro_rules! m {
|
||||||
($t: ty) => {
|
($t: ty) => {
|
||||||
let _: $t;
|
let _: $t;
|
||||||
|
@ -8,8 +12,10 @@ macro_rules! m {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
//[e2021]~vv ERROR expected type, found lifetime
|
||||||
|
//[e2021]~v ERROR expected type, found lifetime
|
||||||
m!('static);
|
m!('static);
|
||||||
//~^ ERROR lifetime in trait object type must be followed by `+`
|
//[e2015]~^ ERROR lifetimes must be followed by `+` to form a trait object type
|
||||||
//~| ERROR lifetime in trait object type must be followed by `+`
|
//[e2015]~| ERROR lifetimes must be followed by `+` to form a trait object type
|
||||||
//~| ERROR at least one trait is required for an object type
|
//[e2015]~| ERROR at least one trait is required for an object type
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
error: lifetime in trait object type must be followed by `+`
|
|
||||||
--> $DIR/trait-object-macro-matcher.rs:11:8
|
|
||||||
|
|
|
||||||
LL | m!('static);
|
|
||||||
| ^^^^^^^
|
|
||||||
|
|
||||||
error: lifetime in trait object type must be followed by `+`
|
|
||||||
--> $DIR/trait-object-macro-matcher.rs:11:8
|
|
||||||
|
|
|
||||||
LL | m!('static);
|
|
||||||
| ^^^^^^^
|
|
||||||
|
|
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
|
||||||
|
|
||||||
error[E0224]: at least one trait is required for an object type
|
|
||||||
--> $DIR/trait-object-macro-matcher.rs:11:8
|
|
||||||
|
|
|
||||||
LL | m!('static);
|
|
||||||
| ^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0224`.
|
|
13
tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs
Normal file
13
tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
struct Entity<'a> {
|
||||||
|
name: 'a str, //~ ERROR expected type, found lifetime
|
||||||
|
//~^ HELP you might have meant to write a reference type here
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Buffer<'buf> {
|
||||||
|
bytes: 'buf mut [u8], //~ ERROR expected type, found lifetime
|
||||||
|
//~^ HELP you might have meant to write a reference type here
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
24
tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr
Normal file
24
tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
error: expected type, found lifetime
|
||||||
|
--> $DIR/recover-ampersand-less-ref-ty.rs:4:11
|
||||||
|
|
|
||||||
|
LL | name: 'a str,
|
||||||
|
| ^^ expected type
|
||||||
|
|
|
||||||
|
help: you might have meant to write a reference type here
|
||||||
|
|
|
||||||
|
LL | name: &'a str,
|
||||||
|
| +
|
||||||
|
|
||||||
|
error: expected type, found lifetime
|
||||||
|
--> $DIR/recover-ampersand-less-ref-ty.rs:9:12
|
||||||
|
|
|
||||||
|
LL | bytes: 'buf mut [u8],
|
||||||
|
| ^^^^ expected type
|
||||||
|
|
|
||||||
|
help: you might have meant to write a reference type here
|
||||||
|
|
|
||||||
|
LL | bytes: &'buf mut [u8],
|
||||||
|
| +
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -5,12 +5,8 @@
|
||||||
auto trait Auto {}
|
auto trait Auto {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _: Box<((Auto)) + Auto>;
|
let _: Box<((Auto)) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
|
||||||
//~^ ERROR expected a path on the left-hand side of `+`, not `((Auto))`
|
let _: Box<(Auto + Auto) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
|
||||||
let _: Box<(Auto + Auto) + Auto>;
|
let _: Box<(Auto +) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
|
||||||
//~^ ERROR expected a path on the left-hand side of `+`, not `(Auto + Auto)`
|
let _: Box<(dyn Auto) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
|
||||||
let _: Box<(Auto +) + Auto>;
|
|
||||||
//~^ ERROR expected a path on the left-hand side of `+`, not `(Auto)`
|
|
||||||
let _: Box<(dyn Auto) + Auto>;
|
|
||||||
//~^ ERROR expected a path on the left-hand side of `+`, not `(dyn Auto)`
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `((Auto))`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/trait-object-bad-parens.rs:8:16
|
--> $DIR/trait-object-bad-parens.rs:8:16
|
||||||
|
|
|
|
||||||
LL | let _: Box<((Auto)) + Auto>;
|
LL | let _: Box<((Auto)) + Auto>;
|
||||||
| ^^^^^^^^^^^^^^^ expected a path
|
| ^^^^^^^^ expected a path
|
||||||
|
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `(Auto + Auto)`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/trait-object-bad-parens.rs:10:16
|
--> $DIR/trait-object-bad-parens.rs:9:16
|
||||||
|
|
|
|
||||||
LL | let _: Box<(Auto + Auto) + Auto>;
|
LL | let _: Box<(Auto + Auto) + Auto>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ expected a path
|
| ^^^^^^^^^^^^^ expected a path
|
||||||
|
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `(Auto)`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/trait-object-bad-parens.rs:12:16
|
--> $DIR/trait-object-bad-parens.rs:10:16
|
||||||
|
|
|
|
||||||
LL | let _: Box<(Auto +) + Auto>;
|
LL | let _: Box<(Auto +) + Auto>;
|
||||||
| ^^^^^^^^^^^^^^^ expected a path
|
| ^^^^^^^^ expected a path
|
||||||
|
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `(dyn Auto)`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/trait-object-bad-parens.rs:14:16
|
--> $DIR/trait-object-bad-parens.rs:11:16
|
||||||
|
|
|
|
||||||
LL | let _: Box<(dyn Auto) + Auto>;
|
LL | let _: Box<(dyn Auto) + Auto>;
|
||||||
| ^^^^^^^^^^^^^^^^^ expected a path
|
| ^^^^^^^^^^ expected a path
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: parenthesized lifetime bounds are not supported
|
error: parenthesized lifetime bounds are not supported
|
||||||
--> $DIR/trait-object-lifetime-parens.rs:5:21
|
--> $DIR/trait-object-lifetime-parens.rs:9:21
|
||||||
|
|
|
|
||||||
LL | fn f<'a, T: Trait + ('a)>() {}
|
LL | fn f<'a, T: Trait + ('a)>() {}
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
@ -11,7 +11,7 @@ LL + fn f<'a, T: Trait + 'a>() {}
|
||||||
|
|
|
|
||||||
|
|
||||||
error: parenthesized lifetime bounds are not supported
|
error: parenthesized lifetime bounds are not supported
|
||||||
--> $DIR/trait-object-lifetime-parens.rs:8:24
|
--> $DIR/trait-object-lifetime-parens.rs:12:24
|
||||||
|
|
|
|
||||||
LL | let _: Box<Trait + ('a)>;
|
LL | let _: Box<Trait + ('a)>;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
@ -22,11 +22,16 @@ LL - let _: Box<Trait + ('a)>;
|
||||||
LL + let _: Box<Trait + 'a>;
|
LL + let _: Box<Trait + 'a>;
|
||||||
|
|
|
|
||||||
|
|
||||||
error: lifetime in trait object type must be followed by `+`
|
error: lifetimes must be followed by `+` to form a trait object type
|
||||||
--> $DIR/trait-object-lifetime-parens.rs:10:17
|
--> $DIR/trait-object-lifetime-parens.rs:16:17
|
||||||
|
|
|
|
||||||
LL | let _: Box<('a) + Trait>;
|
LL | let _: Box<('a) + Trait>;
|
||||||
| ^^
|
| ^^
|
||||||
|
|
|
||||||
|
help: consider adding a trait bound after the potential lifetime bound
|
||||||
|
|
|
||||||
|
LL | let _: Box<('a + /* Trait */) + Trait>;
|
||||||
|
| +++++++++++++
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
51
tests/ui/parser/trait-object-lifetime-parens.e2021.stderr
Normal file
51
tests/ui/parser/trait-object-lifetime-parens.e2021.stderr
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
error: parenthesized lifetime bounds are not supported
|
||||||
|
--> $DIR/trait-object-lifetime-parens.rs:9:21
|
||||||
|
|
|
||||||
|
LL | fn f<'a, T: Trait + ('a)>() {}
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
help: remove the parentheses
|
||||||
|
|
|
||||||
|
LL - fn f<'a, T: Trait + ('a)>() {}
|
||||||
|
LL + fn f<'a, T: Trait + 'a>() {}
|
||||||
|
|
|
||||||
|
|
||||||
|
error: parenthesized lifetime bounds are not supported
|
||||||
|
--> $DIR/trait-object-lifetime-parens.rs:12:24
|
||||||
|
|
|
||||||
|
LL | let _: Box<Trait + ('a)>;
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
help: remove the parentheses
|
||||||
|
|
|
||||||
|
LL - let _: Box<Trait + ('a)>;
|
||||||
|
LL + let _: Box<Trait + 'a>;
|
||||||
|
|
|
||||||
|
|
||||||
|
error: expected type, found lifetime
|
||||||
|
--> $DIR/trait-object-lifetime-parens.rs:16:17
|
||||||
|
|
|
||||||
|
LL | let _: Box<('a) + Trait>;
|
||||||
|
| ^^ expected type
|
||||||
|
|
||||||
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
|
--> $DIR/trait-object-lifetime-parens.rs:16:16
|
||||||
|
|
|
||||||
|
LL | let _: Box<('a) + Trait>;
|
||||||
|
| ^^^^ expected a path
|
||||||
|
|
||||||
|
error[E0782]: expected a type, found a trait
|
||||||
|
--> $DIR/trait-object-lifetime-parens.rs:12:16
|
||||||
|
|
|
||||||
|
LL | let _: Box<Trait + ('a)>;
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: you can add the `dyn` keyword if you want a trait object
|
||||||
|
|
|
||||||
|
LL | let _: Box<dyn Trait + ('a)>;
|
||||||
|
| +++
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0178, E0782.
|
||||||
|
For more information about an error, try `rustc --explain E0178`.
|
|
@ -1,4 +1,8 @@
|
||||||
#![allow(bare_trait_objects)]
|
//@ revisions: e2015 e2021
|
||||||
|
//@[e2015] edition: 2015
|
||||||
|
//@[e2021] edition: 2021
|
||||||
|
|
||||||
|
#![cfg_attr(e2015, allow(bare_trait_objects))]
|
||||||
|
|
||||||
trait Trait {}
|
trait Trait {}
|
||||||
|
|
||||||
|
@ -6,8 +10,12 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s
|
||||||
|
|
||||||
fn check<'a>() {
|
fn check<'a>() {
|
||||||
let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
|
let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
|
||||||
// FIXME: It'd be great if we could add suggestion to the following case.
|
//[e2021]~^ ERROR expected a type, found a trait
|
||||||
let _: Box<('a) + Trait>; //~ ERROR lifetime in trait object type must be followed by `+`
|
// FIXME: It'd be great if we could suggest removing the parentheses here too.
|
||||||
|
//[e2015]~v ERROR lifetimes must be followed by `+` to form a trait object type
|
||||||
|
let _: Box<('a) + Trait>;
|
||||||
|
//[e2021]~^ ERROR expected type, found lifetime
|
||||||
|
//[e2021]~| ERROR expected a path on the left-hand side of `+`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -4,6 +4,6 @@ trait Trait<'a> {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _: &for<'a> Trait<'a> + 'static;
|
let _: &for<'a> Trait<'a> + 'static;
|
||||||
//~^ ERROR expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>`
|
//~^ ERROR expected a path on the left-hand side of `+`
|
||||||
//~| HELP try adding parentheses
|
//~| HELP try adding parentheses
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0178]: expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>`
|
error[E0178]: expected a path on the left-hand side of `+`
|
||||||
--> $DIR/trait-object-polytrait-priority.rs:6:12
|
--> $DIR/trait-object-polytrait-priority.rs:6:12
|
||||||
|
|
|
|
||||||
LL | let _: &for<'a> Trait<'a> + 'static;
|
LL | let _: &for<'a> Trait<'a> + 'static;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: try adding parentheses
|
help: try adding parentheses
|
||||||
|
|
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue