Rust: Add predicate for certain type information #20155
Draft
+279
−91
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Motivated by performance problems seen in #20140 this PR introduces a new "phase" to type inference in the form of a new
inferCertainType
predicate.Motivation
There's a lot of places where we approximate things in type inference. These inaccuracies cause us to sometimes infer multiple types for the same term. Inaccurate types can lead to other inaccurate types and things can spiral and blow up from there. In the worst case we end up with cycles in type inference.
In #20140 performance blew up in Sway at a place where several cycles in inference happened. This PR adds a reduced version of that problem, which was caused by a type coercion that we don't handle. I don't see an easy way to handle such coercions correctly, and more generally think it'll be hard to make our entire type inference 100% correct.
Proposed solution
This PR adds a new "phase" to type inference, which is just a new predicate called
inferCertainType
. The idea is thatinferCertainType
contains a subset of the type inference that is sure to be 100% correct. This implies thatinferCertainType
(ideally) never contains multiple types for the same node and path.inferType
uses (and is a superset) ofinferCertainType
, but not the other way around. This means that we can useinferCertainType
negated ininferType
to eliminate or block inaccuracies when we actually have accurate information.This PR implements a minimum viable version of the idea which is sufficient to fix the cycle in Sway (and the test). We infer certain type information only for 1/ annotated terms and 2/ very simple calls and let the information propagate along a few equalities. The PR also uses a negated
inferCertainType
to blockinferTypeEquality
from letting (wrong) type information flow to a node where we have complete correct type information. This is what cuts the cycle in the example.Pros of this approach:
not inferCertainType(n, _)
, i.e., if the simple and correct rules give us a type we can stop inference there.Cons:
Results on #20140
With this PR the number of nodes with a type at the type path lenght limit in Sway is reduced from 76 and to 63.
When quick eval'ing
inferType
on Sway I see the following:main
So this PR seems to remove the blowup caused by #20140 for Sway.
Future work
As mentioned this is just a minimum viable implementation.
We should be able to move more stuff into
inferCertainType
.Right now
inferCertainType(n, path)
is only allowed to give results if we have complete information of the entire type tree forn
. It would be nice to lift this requirement s.t. it is allowed to have results as long as the type specifically atpath
is certain.This will make it much easier to soundly include things in
inferCertainType
. For instance, then we can have a certain root type forSome(a)
without necessarily having a certain type for the nested type.However, we still need to know when we have complete certain information of a node (to implement the block in
inferTypeEquality
). Ideally that could be derived frominferCertainType
by checking if the type tree is complete, but that is more work to implement.