"strings"
)
-// 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
-// than type parameters, and params and args must match in number (incl. zero).
-// If successful, infer returns the complete list of type arguments, one for each type parameter.
-// Otherwise the result is nil and appropriate errors will be reported.
-//
+// infer1 is an implementation of infer.
// Inference proceeds as follows. Starting with given type arguments:
//
// 1. apply FTI (function type inference) with typed arguments,
// 4. apply CTI.
//
// The process stops as soon as all type arguments are known or an error occurs.
-func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (result []Type) {
- if useNewTypeInference {
- return check.infer2(pos, tparams, targs, params, args)
- }
-
+func (check *Checker) infer1(pos syntax.Pos, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand, silent bool) (result []Type) {
if debug {
defer func() {
assert(result == nil || len(result) == len(tparams))
u := newUnifier(tparams, targs)
errorf := func(kind string, tpar, targ Type, arg *operand) {
+ if silent {
+ return
+ }
// provide a better error message if we can
targs, index := u.inferred()
if index == 0 {
// At least one type argument couldn't be inferred.
assert(targs != nil && index >= 0 && targs[index] == nil)
tpar := tparams[index]
- check.errorf(pos, CannotInferTypeArgs, "cannot infer %s (%s)", tpar.obj.name, tpar.obj.pos)
+ if !silent {
+ check.errorf(pos, CannotInferTypeArgs, "cannot infer %s (%s)", tpar.obj.name, tpar.obj.pos)
+ }
return nil
}
. "internal/types/errors"
)
-const useNewTypeInference = false
-
-// infer2 attempts to infer the complete set of type arguments for generic function instantiation/call
+// 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
// than type parameters, and params and args must match in number (incl. zero).
// If successful, infer returns the complete list of given and inferred type arguments, one for each
// 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")
+ }
+ }
+ return r2
+}
+
+// infer2 is an implementation of infer.
func (check *Checker) infer2(pos syntax.Pos, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (inferred []Type) {
if debug {
defer func() {
// A comparer is used to compare types.
type comparer struct {
- ignoreTags bool // if set, identical ignores struct tags
+ ignoreTags bool // if set, identical ignores struct tags
+ ignoreInvalids bool // if set, identical treats an invalid type as identical to any type
}
// For changes to this code the corresponding changes should be made to unifier.nify.
return true
}
+ if c.ignoreInvalids && (x == Typ[Invalid] || y == Typ[Invalid]) {
+ return true
+ }
+
switch x := x.(type) {
case *Basic:
// Basic types are singletons except for the rune and byte
ast.Inspect(f, func(n ast.Node) bool {
switch n := n.(type) {
case *ast.FuncDecl:
- if n.Name.Name == "infer" || n.Name.Name == "infer2" {
+ if n.Name.Name == "infer" || n.Name.Name == "infer1" || n.Name.Name == "infer2" {
// rewrite (pos token.Pos, ...) to (posn positioner, ...)
par := n.Type.Params.List[0]
if len(par.Names) == 1 && par.Names[0].Name == "pos" {
n.Args[0] = arg
return false
}
- case "errorf", "infer2":
+ case "errorf", "infer1", "infer2":
// rewrite check.errorf(pos, ...) to check.errorf(posn, ...)
+ // rewrite check.infer1(pos, ...) to check.infer1(posn, ...)
// rewrite check.infer2(pos, ...) to check.infer2(posn, ...)
if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "pos" {
pos := n.Args[0].Pos()
"strings"
)
-// 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
-// than type parameters, and params and args must match in number (incl. zero).
-// If successful, infer returns the complete list of type arguments, one for each type parameter.
-// Otherwise the result is nil and appropriate errors will be reported.
-//
+// infer1 is an implementation of infer.
// Inference proceeds as follows. Starting with given type arguments:
//
// 1. apply FTI (function type inference) with typed arguments,
// 4. apply CTI.
//
// The process stops as soon as all type arguments are known or an error occurs.
-func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (result []Type) {
- if useNewTypeInference {
- return check.infer2(posn, tparams, targs, params, args)
- }
-
+func (check *Checker) infer1(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand, silent bool) (result []Type) {
if debug {
defer func() {
assert(result == nil || len(result) == len(tparams))
u := newUnifier(tparams, targs)
errorf := func(kind string, tpar, targ Type, arg *operand) {
+ if silent {
+ return
+ }
// provide a better error message if we can
targs, index := u.inferred()
if index == 0 {
// At least one type argument couldn't be inferred.
assert(targs != nil && index >= 0 && targs[index] == nil)
tpar := tparams[index]
- check.errorf(posn, CannotInferTypeArgs, "cannot infer %s (%s)", tpar.obj.name, tpar.obj.pos)
+ if !silent {
+ check.errorf(posn, CannotInferTypeArgs, "cannot infer %s (%s)", tpar.obj.name, tpar.obj.pos)
+ }
return nil
}
. "internal/types/errors"
)
-const useNewTypeInference = false
-
-// infer2 attempts to infer the complete set of type arguments for generic function instantiation/call
+// 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
// than type parameters, and params and args must match in number (incl. zero).
// If successful, infer returns the complete list of given and inferred type arguments, one for each
// 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")
+ }
+ }
+ return r2
+}
+
+// infer2 is an implementation of infer.
func (check *Checker) infer2(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (inferred []Type) {
if debug {
defer func() {
// A comparer is used to compare types.
type comparer struct {
- ignoreTags bool // if set, identical ignores struct tags
+ ignoreTags bool // if set, identical ignores struct tags
+ ignoreInvalids bool // if set, identical treats an invalid type as identical to any type
}
// For changes to this code the corresponding changes should be made to unifier.nify.
return true
}
+ if c.ignoreInvalids && (x == Typ[Invalid] || y == Typ[Invalid]) {
+ return true
+ }
+
switch x := x.(type) {
case *Basic:
// Basic types are singletons except for the rune and byte