-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Improve parse errors for stray lifetimes in type position #139854
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
Conversation
Namely, use a more sensical primary span. Don't pretty-print AST nodes for the diagnostic message. Why: * It's lossy (e.g., it doesn't replicate trailing `+`s in trait objects. * It's prone to leak error nodes (printed as `(/*ERROR*/)`) since the LHS can easily represent recovered code (e.g., `fn(i32?) + T`).
r? @davidtwco rustbot has assigned @davidtwco. Use |
// In Rust 2021 and beyond, we assume that the user didn't intend to write a bare trait | ||
// 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() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm open to dropping the edition check making us emit the new message and output TyKind::Error
in all editions (undoing parts of PR #69760), thereby removing NeedPlusAfterTraitObjectLifetime
entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm open to also suggesting dyn 'a + /* Trait */
when facing 'a
in modern editions, too.
This comment has been minimized.
This comment has been minimized.
e9e8414
to
f8c5436
Compare
// 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just an explainer for what's already going on here.
In commit fmease@f8c5436 which I've since removed from this PR, I've experimented with removing this which would've allowed us to suggest removing parentheses in maybe_recover_from_bad_type_plus
for type ('a) + Bounds…
(that's a FIXME in tests/ui/parser/trait-object-lifetime-parens.rs
) but that made things worse (more verbose output, nasty boolean flag, still false-positives (e.g., (?'a) + Bound
where ?
is invalid but we recover which we can't detect later)).
f8c5436
to
6242335
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@bors r+ |
…iaskrgr Rollup of 9 pull requests Successful merges: - rust-lang#135340 (Add `explicit_extern_abis` Feature and Enforce Explicit ABIs) - rust-lang#139440 (rustc_target: RISC-V: feature addition batch 2) - rust-lang#139667 (cfi: Remove #[no_sanitize(cfi)] for extern weak functions) - rust-lang#139828 (Don't require rigid alias's trait to hold) - rust-lang#139854 (Improve parse errors for stray lifetimes in type position) - rust-lang#139889 (Clean UI tests 3 of n) - rust-lang#139894 (Fix `opt-dist` CLI flag and make it work without LLD) - rust-lang#139900 (stepping into impls for normalization is unproductive) - rust-lang#139915 (replace some #[rustc_intrinsic] usage with use of the libcore declarations) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of rust-lang#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 rust-lang#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 rust-lang#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 rust-lang#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.
While technically & syntactically speaking lifetimes do begin1 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 #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 #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.
Footnotes
For example, in the context of decl macros, this implies that a lone
'a
always matches syntax fragmentty
("even if" there's a later macro matcher expecting syntax fragmentlifetime
). Rephrased, lifetimes (in type contexts) commit to the type parser. ↩