-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
improve lifetime annotation diagnostics #100976
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