-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Rust: Type inference for for
loops and array expressions
#19754
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
base: main
Are you sure you want to change the base?
Conversation
@hvitved do you think this is heading in the right direction? |
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.
Great start!
@@ -1124,6 +1124,37 @@ private Type inferIndexExprType(IndexExpr ie, TypePath path) { | |||
) | |||
} | |||
|
|||
pragma[nomagic] | |||
private Type inferArrayExprType(ArrayExpr ae, TypePath 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.
I think this should be implemented inside the typeEquality
predicate instead.
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. 👍
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.
You also need a
/** Gets the root type of the array expression `ae`. */
pragma[nomagic]
private Type inferArrayExprType(ArrayExpr ae) { exists(ae) and result = TArrayType() }
predicate, similar to inferRefExprType
.
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 see. Done. Got a couple of extra expected results.
( | ||
iterablePath.isCons(any(ArrayTypeParameter tp), path) and | ||
result = iterableType | ||
// TODO: iterables (containers, ranges etc) |
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.
We may as well pull out the logic from inferIndexExprType
that handles arrays, slices, and Vec
s, and reuse it 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.
Also done, but it doesn't catch any additional test cases. I think at some point we're going to need to cover the general case for iterables.
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.
The reason why we are not seeing results for Vec
is that we cannot yet infer the type of e.g. vec![1, 2, 3]
, which desugars to
<[_]>::into_vec(
#[rustc_box]
alloc::boxed::Box::new([1, 2, 3]),
)
and we cannot currently resolve the into_vec
call.
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.
Ah, then I'll add a simpler test case that we will hopefully cover.
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.
If you add an explicit : Vec<i32>
type annotation it ought to work.
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've added some variations with Vec
and we get ... none of them. There's probably something very narrow I could write that we would get a Vec
type for, but there's clearly not enough here to work on most normal code involving Vec
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.
... I read your comment again and added a case with an explicit type annotation. That does work, though it feels narrow as people usually don't seem to use explicit types much when they don't need to.
|
||
// for loops with containers | ||
|
||
let vals3 = vec![1, 2, 3]; // $ MISSING: type=vals3:Vec<i32> |
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 not how to make expected type annotations for constructed types, instead you should use the format type=<element>:<path>.<type>
(see
else value = element + ":" + path.toString() + "." + t.toString() |
type=vals3:T.i32
.
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.
Ah, I think I was relying on the test runner to start suggesting correct syntax, which it doesn't really do for optional results. I've updated the expectations now as best I can - there may still be add mistakes.
Ready for review: there are gaps (and apparently a conflict with main), but we get some useful results and I'd like to push towards merging this ASAP. |
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.
Looks really great 👍. I've left a few minor comments.
exists(TypePath path0 | | ||
iterablePath.isCons(any(RefTypeParameter tp), path0) and | ||
path0.isCons(any(SliceTypeParameter tp), 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.
This makes the last case look more like the prior cases:
exists(TypePath path0 | | |
iterablePath.isCons(any(RefTypeParameter tp), path0) and | |
path0.isCons(any(SliceTypeParameter tp), path) | |
) | |
iterablePath | |
.stripPrefix(TypePath::cons(TRefTypeParameter(), | |
TypePath::singleton(any(SliceTypeParameter tp)))) = path |
@@ -1881,6 +1881,109 @@ mod method_determined_by_argument_type { | |||
} | |||
} | |||
|
|||
mod loops { | |||
struct MyCallable { | |||
} |
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.
The type inference tests are currently formatted with rustfmt and I think it would be nice to keep doing that.
map1.insert(1, Box::new("one")); // $ method=insert | ||
map1.insert(2, Box::new("two")); // $ method=insert | ||
for key in map1.keys() { } // $ method=keys MISSING: type=key:i32 | ||
for value in map1.values() { } // $ method=values MISSING: type=value:Box type=value:Box.T:&T.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 type annotation has two :
s. I think the later should be a .
or tweaked in some other way.
Adds type inference for
for
loops and array expressions. Currently forfor
loops this is limited to loops iterating through arrays.@hvitved please advise.
Iterator
type and perhaps understandIntoIterator
.