-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Rust: Add inline expectations test for type inference #19198
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
1eca118
to
5c08cd6
Compare
if this.getArgList().getNumberOfArgs() = 0 | ||
then parenthesis = "()" | ||
else parenthesis = "(...)" | ||
) and |
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.
It would be better to implement this on ArgList
, but that might cause more changes so I'm leaving that for a follow up PR.
5c08cd6
to
715765a
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.
I think ideally this would have been two PRs, one for the inline expecatation tests change, and one of the changes to comment and type toStrings
s that cause a lot of noisy changes in the tests. Splitting it into different commits would have helped. It probably isn't worth doing retroactively though.
That aside, the use of inline expectations is an improvement that will pay off if we're expecting a lot of future changes to this test. 👍
} | ||
|
||
fn generic_field_access() { | ||
// Explicit type argument | ||
let x = GenericThing::<S> { a: S }; | ||
println!("{:?}", x.a); | ||
let x = GenericThing::<S> { a: S }; // $ type=x:A.S |
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.
What does this annotation mean exactly?
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 means that x
has a type which at parameter position A
contains S
. In this case x
has the type GenericThing<S>
and GenericThing
has a type parameter called A
, hence x
has S
at A
. For this line we could also add $ type=x:GenericThing
since the "root" of x
's type is GenericThing
.
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.
Can I ask you to (force push) a change that moves all ToString
changes into a separate commit before continuing my review, please?
then parenthesis = "()" | ||
else parenthesis = "(...)" | ||
) and | ||
result = base + separator + this.getIdentifier().toStringImpl() + parenthesis |
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.
It would be better to use the toStringPart
pattern here instead, to avoid computing intermediate strings
@@ -43,10 +43,15 @@ module Impl { | |||
} | |||
|
|||
override string toStringImpl() { |
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.
It would have been nice to have all toString
changes (including changes in .expected
files) in a separate commit.
715765a
to
d5d61dd
Compare
Done, now split in two commits :) |
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, minor suggestions
@@ -9,6 +9,6 @@ trait T1<T>: T2<S<T>> { | |||
|
|||
trait T2<T>: T1<S<T>> { | |||
fn bar(self) { | |||
self.foo() | |||
self.foo() // $ method=foo |
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 we should change this to using canonical paths, once that PR lands, because the comment as-is doesn't really tell us anything about the target.
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.
Yes, that is a good idea if they're not too cumbersome to write.
But this also works reasonably well. We only use just the name in the cases where there's a single method of a given name in scope, and then the method resolution would have to do something very wrong to find another method with the same name.
println!("{:?}", x1); | ||
|
||
let mut x2 = MyOption::new(); | ||
x2.set(S); | ||
x2.set(S); // $ method=MyOption::set | ||
println!("{:?}", x2); | ||
|
||
let mut x3 = MyOption::new(); // missing type `S` from `MyOption<S>` (but can resolve `MyTrait<S>`) |
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.
Can this comment be updated?
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.
Good question. I left this in place because the x3
is stringified as "mut x3"
. I think it might make more sense to just print it as "x3"
and I'd prefer to not write too many "unstable" stringifications in the annotations.
f.getPrecedingComment().getCommentText() = value | ||
or | ||
not exists(f.getPrecedingComment()) and | ||
value = f.getName().getText() |
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.
Perhaps add a TODO comment to use canonical name instead (if it exists)?
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.
Done 👍
Adds inline expectations tests for type inference.
The annotations for resolved method calls and field expressions are pretty straightforward and the annotations now subsume what we had in the expected file before.
I've also added annotations for inferred types. We obviously don't want to annotate every single expression, so these annotations are optional and can be used in important places only. These annotations depend on stringifying AST nodes which can be a bit annoying, but I don't think it's too bad is we only use them sparingly and can write the tests with that in mind.
Let's merge at least #19146 before this.