-
Notifications
You must be signed in to change notification settings - Fork 18k
cmd/compile/internal/types2: make type inference independent of function argument order #43056
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
Comments
I don't see why the type parameters have identical type. One is type |
The calls' value arguments |
I agree that either both of these calls of Unfortunately, we currently have an asymmetry in the unification algorithm: If one of the involved types is a defined type (here Since we started with In the 2nd case we start with In summary, unification produces the following calls: F[I](i, j)
F[interface{ Equal(I) bool}](j, i) It seems reasonable to postulate that if we enter unification with an underlying type of a named type to make it succeed, the inferred type should be the underlying type (here But then both calls in this example would fail (because instantiation fails). Alternatively, maybe the interface This problem only occurs with interfaces because those are the only types for which we can provide methods in the type literal; for all other types, we need a defined type to attach methods. There may be other work-arounds and changes to the inference algorithm that make this work "as expected". But is does seems accepting #8082 would solve this problem for interfaces. |
Change https://golang.org/cl/276692 mentions this issue: |
After review, the only non-superficial change was to delegate the call to under(...) to structuralType. Otherwise, update a few stale comments: + correct indices in the documentation for tparamsList + update smap->substMap in a few places + update type parameter syntax in a couple places I've spent a good amount of time reviewing this code, and it fundamentally LGTM (though I wish we didn't have to copy the logic from identical0). However, as demonstrated in #43056, this code is complicated and not always easy to reason about, particularly in the context of type checking where not all types may be complete. To further understand and verify this code I'd like to write more tests, but that must wait until the rest of the changes in go/types are imported from dev.go2go. Change-Id: Iabb9d3a6af988a2e1b3445cde6bc2431a80f8bfe Reviewed-on: https://go-review.googlesource.com/c/go/+/276692 Run-TryBot: Robert Findley <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Robert Findley <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
Slightly simpler, analogous case: package p
func f[T ~func(T)](a, b T) {}
type F func(F)
func _() {
var i F
var j func(F)
f(i, j)
f(j, i)
} |
Change https://golang.org/cl/377894 mentions this issue: |
The above CL addresses this issue, but it also adds complexity to the description of type inference. Per discussion w/ @ianlancetaylor , this is not necessarily a "bug": the error can be explained given the existing spec rules (in progress). It is also an extremely esoteric case that seems unlikely to occur frequently in practice. Decision is to postpone any action on this for the time being. We can keep the code in place as it is guarded by a flag. If we decide to act upon this, it will be trivial to enable this specific fix. |
…dent If we have more than 2 arguments, we may have arguments with named and unnamed types. If that is the case, permutate params and args such that the arguments with named types are first in the list. This doesn't affect type inference if all types are taken as is. But when we have inexact unification enabled (as is the case for function type inference), when a named type is unified with an unnamed type, unification proceeds with the underlying type of the named type because otherwise unification would fail right away. This leads to an asymmetry in type inference: in cases where arguments of named and unnamed types are passed to parameters with identical type, different types (named vs underlying) may be inferred depending on the order of the arguments. By ensuring that named types are seen first, order dependence is avoided and unification succeeds where it can. This CL implements the respectice code but keeps it disabled for now, pending decision whether we want to address this issue in the first place. For #43056. Change-Id: Ibe3b08ec2afe90a24a8c30cd1875d504bcc2ef39 Reviewed-on: https://go-review.googlesource.com/c/go/+/377894 Trust: Robert Griesemer <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]>
…dent If we have more than 2 arguments, we may have arguments with named and unnamed types. If that is the case, permutate params and args such that the arguments with named types are first in the list. This doesn't affect type inference if all types are taken as is. But when we have inexact unification enabled (as is the case for function type inference), when a named type is unified with an unnamed type, unification proceeds with the underlying type of the named type because otherwise unification would fail right away. This leads to an asymmetry in type inference: in cases where arguments of named and unnamed types are passed to parameters with identical type, different types (named vs underlying) may be inferred depending on the order of the arguments. By ensuring that named types are seen first, order dependence is avoided and unification succeeds where it can. This CL implements the respectice code but keeps it disabled for now, pending decision whether we want to address this issue in the first place. For golang#43056. Change-Id: Ibe3b08ec2afe90a24a8c30cd1875d504bcc2ef39 Reviewed-on: https://go-review.googlesource.com/c/go/+/377894 Trust: Robert Griesemer <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]>
Change https://go.dev/cl/413459 mentions this issue: |
If we have more than two function arguments to a generic function, we may have arguments with named and unnamed types. If that is the case, permutate params and args such that the arguments with named types are first in the list. This way, independent of parameter ordering, the type inference will produce the same result. This extra step is not explicitly outlined in the spec yet but we all agree that (parameter) order independence is an invariant that we should uphold for type inference. As we move towards less operational and more descriptive rules for type inference, we will incorporate this property as well. The actual fix for this bug existed before 1.18 but was not enabled. This CL merely enables the fix (switches a flag) and adjusts some tests. Fixes golang#43056. Change-Id: Ie4e40cf8438dfd82fa94b78068e4f6f6f53f83e6 Reviewed-on: https://go-review.googlesource.com/c/go/+/413459 Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
Change https://go.dev/cl/464348 mentions this issue: |
When unifying types, we always consider underlying types if inference would fail otherwise. If a type parameter has a (non-defined) type inferred and later matches against a defined type, make sure to keep that defined type instead. For #43056. Change-Id: I24e4cd2939df7c8069e505be10914017c1c1c288 Reviewed-on: https://go-review.googlesource.com/c/go/+/464348 Reviewed-by: Robert Griesemer <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Robert Griesemer <[email protected]> Run-TryBot: Robert Griesemer <[email protected]>
When unifying types, we always consider underlying types if inference would fail otherwise. If a type parameter has a (non-defined) type inferred and later matches against a defined type, make sure to keep that defined type instead. For golang#43056. Change-Id: I24e4cd2939df7c8069e505be10914017c1c1c288 Reviewed-on: https://go-review.googlesource.com/c/go/+/464348 Reviewed-by: Robert Griesemer <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Robert Griesemer <[email protected]> Run-TryBot: Robert Griesemer <[email protected]>
In the test case at https://go2goplay.golang.org/p/gEl3-egETB2, F(i, j) is accepted, but F(j, i) is not. Both of F's value parameters have identical type, so the behavior here should be consistent (either both accepted, or both rejected).
Based on my understanding from Robert (that type inference requires arguments to have identical type to the parameter, not mere assignability to it), I suspect the correct, consistent behavior is for both to be rejected.
Some more tests at https://go2goplay.golang.org/p/aVaXxBbK1j5. I plan to write a program to exhaustively generate test cases.
(My motivation for looking into this was adding type parameter support to rf, for type-polymorphic rewriting rules: rsc/rf#6)
/cc @griesemer @ianlancetaylor
The text was updated successfully, but these errors were encountered: