return
}
// provide a better error message if we can
- targs, index := u.inferred()
- if index == 0 {
+ targs := u.inferred(tparams)
+ if targs[0] == nil {
// The first type parameter couldn't be inferred.
// If none of them could be inferred, don't try
// to provide the inferred type in the error msg.
}
// If we've got all type arguments, we're done.
- var index int
- targs, index = u.inferred()
- if index < 0 {
+ targs = u.inferred(tparams)
+ if u.unknowns() == 0 {
return targs
}
// See how far we get with constraint type inference.
// Note that even if we don't have any type arguments, constraint type inference
// may produce results for constraints that explicitly specify a type.
- targs, index = check.inferB(tparams, targs)
+ targs, index := check.inferB(tparams, targs)
if targs == nil || index < 0 {
return targs
}
}
// If we've got all type arguments, we're done.
- targs, index = u.inferred()
- if index < 0 {
+ targs = u.inferred(tparams)
+ if u.unknowns() == 0 {
return targs
}
n = nn
}
- // u.inferred() now contains the incoming type arguments plus any additional type
+ // u.inferred(tparams) now contains the incoming type arguments plus any additional type
// arguments which were inferred from core terms. The newly inferred non-nil
// entries may still contain references to other type parameters.
// For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int
// was given, unification produced the type list [int, []C, *A]. We eliminate the
// remaining type parameters by substituting the type parameters in this type list
// until nothing changes anymore.
- types, _ = u.inferred()
+ types = u.inferred(tparams)
if debug {
for i, targ := range targs {
assert(targ == nil || types[i] == targ)
. "internal/types/errors"
)
+// If compareWithInfer1, infer2 results must match infer1 results.
+// Disable before releasing Go 1.21.
+const compareWithInfer1 = true
+
// infer attempts to infer the complete set of type arguments for generic function instantiation/call
// based on the given type parameters tparams, type arguments targs, function parameters params, and
// function arguments args, if any. There must be at least one type parameter, no more type arguments
// type parameter. Otherwise the result is nil and appropriate errors will be reported.
func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) []Type {
r2 := check.infer2(pos, tparams, targs, params, args)
- r1 := check.infer1(pos, tparams, targs, params, args, r2 == nil) // be silent on errors if infer2 failed
- assert(len(r2) == len(r1))
- for i, targ2 := range r2 {
- targ1 := r1[i]
- var c comparer
- c.ignoreInvalids = true
- if !c.identical(targ2, targ1, nil) {
- tpar := tparams[i]
- check.dump("%v: type argument for %s: infer1: %s, infer2: %s", tpar.Obj().Pos(), tpar, targ1, targ2)
- panic("inconsistent type inference")
+
+ if compareWithInfer1 {
+ r1 := check.infer1(pos, tparams, targs, params, args, r2 == nil) // be silent on errors if infer2 failed
+ assert(len(r2) == len(r1))
+ for i, targ2 := range r2 {
+ targ1 := r1[i]
+ var c comparer
+ c.ignoreInvalids = true
+ if !c.identical(targ2, targ1, nil) {
+ tpar := tparams[i]
+ check.dump("%v: type argument for %s: infer1: %s, infer2: %s", tpar.Obj().Pos(), tpar, targ1, targ2)
+ panic("inconsistent type inference")
+ }
}
}
+
return r2
}
errorf := func(kind string, tpar, targ Type, arg *operand) {
// provide a better error message if we can
- targs, index := u.inferred()
- if index == 0 {
+ targs := u.inferred(tparams)
+ if targs[0] == nil {
// The first type parameter couldn't be inferred.
// If none of them could be inferred, don't try
// to provide the inferred type in the error msg.
}
if traceInference {
- inferred, _ := u.inferred()
+ inferred := u.inferred(tparams)
u.tracef("=> %s ➞ %s\n", tparams, inferred)
}
}
if traceInference {
- inferred, _ := u.inferred()
+ inferred := u.inferred(tparams)
u.tracef("=> %s ➞ %s\n", tparams, inferred)
}
// --- simplify ---
- // u.inferred() now contains the incoming type arguments plus any additional type
+ // u.inferred(tparams) now contains the incoming type arguments plus any additional type
// arguments which were inferred. The inferred non-nil entries may still contain
// references to other type parameters found in constraints.
// For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int
// was given, unification produced the type list [int, []C, *A]. We eliminate the
// remaining type parameters by substituting the type parameters in this type list
// until nothing changes anymore.
- inferred, _ = u.inferred()
+ inferred = u.inferred(tparams)
if debug {
for i, targ := range targs {
assert(targ == nil || inferred[i] == targ)
// A unifier is created by calling newUnifier.
type unifier struct {
// tparams is the initial list of type parameters provided.
- // Only used to print/return types in reproducible order.
+ // Only used to print types in reproducible order.
tparams []*TypeParam
// handles maps each type parameter to its inferred type through
// an indirection *Type called (inferred type) "handle".
return n
}
-// inferred returns the list of inferred types (via unification) for the type parameters
-// recorded with u, and an index. If all types were inferred, the returned index is < 0.
-// Otherwise, it is the index of the first type parameter which couldn't be inferred;
-// i.e., for which list[index] is nil.
-func (u *unifier) inferred() (list []Type, index int) {
- list = make([]Type, len(u.tparams))
- index = -1
- for i, x := range u.tparams {
- t := u.at(x)
- list[i] = t
- if index < 0 && t == nil {
- index = i
- }
+// inferred returns the list of inferred types for the given type parameter list.
+// The result is never nil and has the same length as tparams; result types that
+// could not be inferred are nil. Corresponding type parameters and result types
+// have identical indices.
+func (u *unifier) inferred(tparams []*TypeParam) []Type {
+ list := make([]Type, len(tparams))
+ for i, x := range tparams {
+ list[i] = u.at(x)
}
- return
+ return list
}
func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool {
return
}
// provide a better error message if we can
- targs, index := u.inferred()
- if index == 0 {
+ targs := u.inferred(tparams)
+ if targs[0] == nil {
// The first type parameter couldn't be inferred.
// If none of them could be inferred, don't try
// to provide the inferred type in the error msg.
}
// If we've got all type arguments, we're done.
- var index int
- targs, index = u.inferred()
- if index < 0 {
+ targs = u.inferred(tparams)
+ if u.unknowns() == 0 {
return targs
}
// See how far we get with constraint type inference.
// Note that even if we don't have any type arguments, constraint type inference
// may produce results for constraints that explicitly specify a type.
- targs, index = check.inferB(tparams, targs)
+ targs, index := check.inferB(tparams, targs)
if targs == nil || index < 0 {
return targs
}
}
// If we've got all type arguments, we're done.
- targs, index = u.inferred()
- if index < 0 {
+ targs = u.inferred(tparams)
+ if u.unknowns() == 0 {
return targs
}
n = nn
}
- // u.inferred() now contains the incoming type arguments plus any additional type
+ // u.inferred(tparams) now contains the incoming type arguments plus any additional type
// arguments which were inferred from core terms. The newly inferred non-nil
// entries may still contain references to other type parameters.
// For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int
// was given, unification produced the type list [int, []C, *A]. We eliminate the
// remaining type parameters by substituting the type parameters in this type list
// until nothing changes anymore.
- types, _ = u.inferred()
+ types = u.inferred(tparams)
if debug {
for i, targ := range targs {
assert(targ == nil || types[i] == targ)
. "internal/types/errors"
)
+// If compareWithInfer1, infer2 results must match infer1 results.
+// Disable before releasing Go 1.21.
+const compareWithInfer1 = true
+
// infer attempts to infer the complete set of type arguments for generic function instantiation/call
// based on the given type parameters tparams, type arguments targs, function parameters params, and
// function arguments args, if any. There must be at least one type parameter, no more type arguments
// type parameter. Otherwise the result is nil and appropriate errors will be reported.
func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) []Type {
r2 := check.infer2(posn, tparams, targs, params, args)
- r1 := check.infer1(posn, tparams, targs, params, args, r2 == nil) // be silent on errors if infer2 failed
- assert(len(r2) == len(r1))
- for i, targ2 := range r2 {
- targ1 := r1[i]
- var c comparer
- c.ignoreInvalids = true
- if !c.identical(targ2, targ1, nil) {
- tpar := tparams[i]
- check.dump("%v: type argument for %s: infer1: %s, infer2: %s", tpar.Obj().Pos(), tpar, targ1, targ2)
- panic("inconsistent type inference")
+
+ if compareWithInfer1 {
+ r1 := check.infer1(posn, tparams, targs, params, args, r2 == nil) // be silent on errors if infer2 failed
+ assert(len(r2) == len(r1))
+ for i, targ2 := range r2 {
+ targ1 := r1[i]
+ var c comparer
+ c.ignoreInvalids = true
+ if !c.identical(targ2, targ1, nil) {
+ tpar := tparams[i]
+ check.dump("%v: type argument for %s: infer1: %s, infer2: %s", tpar.Obj().Pos(), tpar, targ1, targ2)
+ panic("inconsistent type inference")
+ }
}
}
+
return r2
}
errorf := func(kind string, tpar, targ Type, arg *operand) {
// provide a better error message if we can
- targs, index := u.inferred()
- if index == 0 {
+ targs := u.inferred(tparams)
+ if targs[0] == nil {
// The first type parameter couldn't be inferred.
// If none of them could be inferred, don't try
// to provide the inferred type in the error msg.
}
if traceInference {
- inferred, _ := u.inferred()
+ inferred := u.inferred(tparams)
u.tracef("=> %s ➞ %s\n", tparams, inferred)
}
}
if traceInference {
- inferred, _ := u.inferred()
+ inferred := u.inferred(tparams)
u.tracef("=> %s ➞ %s\n", tparams, inferred)
}
// --- simplify ---
- // u.inferred() now contains the incoming type arguments plus any additional type
+ // u.inferred(tparams) now contains the incoming type arguments plus any additional type
// arguments which were inferred. The inferred non-nil entries may still contain
// references to other type parameters found in constraints.
// For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int
// was given, unification produced the type list [int, []C, *A]. We eliminate the
// remaining type parameters by substituting the type parameters in this type list
// until nothing changes anymore.
- inferred, _ = u.inferred()
+ inferred = u.inferred(tparams)
if debug {
for i, targ := range targs {
assert(targ == nil || inferred[i] == targ)
// A unifier is created by calling newUnifier.
type unifier struct {
// tparams is the initial list of type parameters provided.
- // Only used to print/return types in reproducible order.
+ // Only used to print types in reproducible order.
tparams []*TypeParam
// handles maps each type parameter to its inferred type through
// an indirection *Type called (inferred type) "handle".
return n
}
-// inferred returns the list of inferred types (via unification) for the type parameters
-// recorded with u, and an index. If all types were inferred, the returned index is < 0.
-// Otherwise, it is the index of the first type parameter which couldn't be inferred;
-// i.e., for which list[index] is nil.
-func (u *unifier) inferred() (list []Type, index int) {
- list = make([]Type, len(u.tparams))
- index = -1
- for i, x := range u.tparams {
- t := u.at(x)
- list[i] = t
- if index < 0 && t == nil {
- index = i
- }
+// inferred returns the list of inferred types for the given type parameter list.
+// The result is never nil and has the same length as tparams; result types that
+// could not be inferred are nil. Corresponding type parameters and result types
+// have identical indices.
+func (u *unifier) inferred(tparams []*TypeParam) []Type {
+ list := make([]Type, len(tparams))
+ for i, x := range tparams {
+ list[i] = u.at(x)
}
- return
+ return list
}
func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool {