-
Notifications
You must be signed in to change notification settings - Fork 13.3k
improve lifetime annotation diagnostics #100976
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
span: Span, | ||
) { | ||
use rustc_lexer as lex; | ||
fn tokenize(mut input: &str) -> impl Iterator<Item = (lex::TokenKind, &str)> { |
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 makes me somewhat uncomfortable..
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.
Does it really matter? I mean it's only in the error path.
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.
Yeah, I think it does. There are lots of ways you can get spans to point at random things that aren't paths, like macro expansions, parser error recovery paths, etc. A lot of the error handling logic we have in borrowck is super fragile, and I think invoking the lexer of all things in borrowck is suspicious. How much effort would it be to pass down something like a hir id? or a rustc_middle Ty?
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 don't think passing Ty makes a difference, I'm trying to detect the use of Self
here.
About the HirId, I'm more worried about the correctness of such approach, the mir/thir would reference hir and that's an abstraction leakage IMO.
Probably a better thing can be done here is to compute uses_self: bool
field for each type annotation when building thir/mir. Bu this may be out of scope for this PR because I'm targeting a beta-backport. Is it ok to try this in a followup PR? or is there a chance that this gets backported anyway?
register lifetime annotations from closure signature and UFCS calls under `ConstraintCategory::TypeAnnotation` and make sure we don't report type annotation errors unless thy're the only thing to blame.
The diagnostic changes says it all :)
It should be ready now. Maybe best reviewed commit-by-commit. The output needs some bikeshedding though. |
let suggested_ty = | ||
tcx.fold_regions(tcx.type_of(impl_did), |_, _| tcx.mk_region(ty::ReErased)); | ||
err.help(format!("consider replacing `Self` with `{suggested_ty}`")); |
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.
Is there a way to format the ty with a turbofish? it currently suggests MyStruct<T>
instead of MyStruct::<T>
.
Also is it better to replace regions with dummy ReVar instead so that it is formatted as MyStruct<'_, T>
instead of MyStruct<T>
? but that maybe too verbose for the common case.
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 think you need something like
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::ValueNS); // The default is `Namespace::TypeNS
ty.print(printer).unwrap().into_buffer()
@@ -20,8 +20,9 @@ LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> { | |||
| lifetime `'a` defined here | |||
... | |||
LL | let me = Self::make_me(); | |||
| ^^^^^^^^^^^^^ requires that `'b` must outlive `'a` | |||
| ^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` |
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.
There is really no type annotation here :)
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.
My reasoning is that Self
is considered a type annotation, and the subsequent help note should make it clear.
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 can change it to use of Self requires ...
but this may produce false positives/negatives in some edge cases because the heuristics this relies on is not 100% reliable. This might not be ok given that this is the primary label of the error, but I'm not sure.
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 think calling Self a type annotation is a bit of a stretch. I'd like to see what the diagnostics look like with the change.
☔ The latest upstream changes (presumably #100944) made this pull request unmergeable. Please resolve the merge conflicts. |
use rustc_lexer as lex; | ||
fn tokenize(mut input: &str) -> impl Iterator<Item = (lex::TokenKind, &str)> { | ||
std::iter::from_fn(move || { | ||
if input.is_empty() { | ||
return None; | ||
} | ||
let token = lex::first_token(input); | ||
let token_str = &input[..(token.len as usize)]; | ||
input = &input[(token.len as usize)..]; | ||
Some((token.kind, token_str)) | ||
}) | ||
} | ||
|
||
let snippet = tcx.sess.source_map().span_to_snippet(span).unwrap_or_default(); | ||
let has_self = tokenize(&snippet) | ||
.find(|(tok, s)| *tok == lex::TokenKind::Ident && *s == "Self") | ||
.and_then(|_| tcx.opt_parent(tcx.typeck_root_def_id(body_did))) | ||
.filter(|parent_did| tcx.def_kind(parent_did) == DefKind::Impl); |
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 was going to suggest try to get the hir id somehow, but that's not available in borrowck. But you can use the body_did
and the span to find the right expr by creating a new Visitor
:
Once you have that it means that you could even provide a structured suggestion.
@aliemjay is |
@rustbot author |
@aliemjay FYI: when a PR is ready for review, send a message containing |
Closing this as inactive. Feel free to reöpen this pr or create a new pr if you get the time to work on this. Thanks |
ConstraintCategory::TypeAnnotation
.TypeAnnotation
error, we can be sure that the lifetime annotation is unnecessarily restrictive and we can safely suggest removing it.Self
where it forces unnecessary constraints and suggest a proper fix.TODO:
cc #100725, not closing it though.
resolves #100572
resolves #101393
resolves #69224
resolves #62185
r? @estebank