}
func TestSpec(t *testing.T) { testDirFiles(t, "../../../../internal/types/testdata/spec", 0, false) }
func TestExamples(t *testing.T) {
- testDirFiles(t, "../../../../internal/types/testdata/examples", 60, false)
+ testDirFiles(t, "../../../../internal/types/testdata/examples", 125, false)
} // TODO(gri) narrow column tolerance
func TestFixedbugs(t *testing.T) {
testDirFiles(t, "../../../../internal/types/testdata/fixedbugs", 100, false)
u.tracef("type parameters: %s", tparams)
}
- // Repeatedly apply constraint type inference as long as
- // progress is being made.
+ // Unify type parameters with their constraints as long
+ // as progress is being made.
//
// This is an O(n^2) algorithm where n is the number of
// type parameters: if there is progress, at least one
- // type argument is inferred per iteration and we have
+ // type argument is inferred per iteration, and we have
// a doubly nested loop.
//
// In practice this is not a problem because the number
nn := u.unknowns()
for _, tpar := range tparams {
+ tx := u.at(tpar)
+ if traceInference && tx != nil {
+ u.tracef("%s = %s", tpar, tx)
+ }
+
// If there is a core term (i.e., a core type with tilde information)
// unify the type parameter with the core type.
if core, single := coreTerm(tpar); core != nil {
u.tracef("core(%s) = %s (single = %v)", tpar, core, single)
}
// A type parameter can be unified with its core type in two cases.
- tx := u.at(tpar)
switch {
case tx != nil:
// The corresponding type argument tx is known. There are 2 cases:
if traceInference {
u.tracef("core(%s) = nil", tpar)
}
+ if tx != nil {
+ // We don't have a core type, but the type argument tx is known.
+ // It must have (at least) all the methods of the type constraint,
+ // and the method signatures must unify; otherwise tx cannot satisfy
+ // the constraint.
+ constraint := tpar.iface()
+ if m, wrong := check.missingMethod(tx, constraint, true, u.unify); m != nil {
+ check.errorf(pos, CannotInferTypeArgs, "%s does not satisfy %s %s", tx, constraint, check.missingMethodCause(tx, constraint, m, wrong))
+ return nil
+ }
+ }
}
}
j++
}
}
- // untyped[:j] are the undices of parameters without a type yet
+ // untyped[:j] are the indices of parameters without a type yet
for _, i := range untyped[:j] {
tpar := params.At(i).typ.(*TypeParam)
arg := args[i]
u.tracef("type parameters: %s", tparams)
}
- // Repeatedly apply constraint type inference as long as
- // progress is being made.
+ // Unify type parameters with their constraints as long
+ // as progress is being made.
//
// This is an O(n^2) algorithm where n is the number of
// type parameters: if there is progress, at least one
- // type argument is inferred per iteration and we have
+ // type argument is inferred per iteration, and we have
// a doubly nested loop.
//
// In practice this is not a problem because the number
nn := u.unknowns()
for _, tpar := range tparams {
+ tx := u.at(tpar)
+ if traceInference && tx != nil {
+ u.tracef("%s = %s", tpar, tx)
+ }
+
// If there is a core term (i.e., a core type with tilde information)
// unify the type parameter with the core type.
if core, single := coreTerm(tpar); core != nil {
u.tracef("core(%s) = %s (single = %v)", tpar, core, single)
}
// A type parameter can be unified with its core type in two cases.
- tx := u.at(tpar)
switch {
case tx != nil:
// The corresponding type argument tx is known. There are 2 cases:
if traceInference {
u.tracef("core(%s) = nil", tpar)
}
+ if tx != nil {
+ // We don't have a core type, but the type argument tx is known.
+ // It must have (at least) all the methods of the type constraint,
+ // and the method signatures must unify; otherwise tx cannot satisfy
+ // the constraint.
+ constraint := tpar.iface()
+ if m, wrong := check.missingMethod(tx, constraint, true, u.unify); m != nil {
+ check.errorf(posn, CannotInferTypeArgs, "%s does not satisfy %s %s", tx, constraint, check.missingMethodCause(tx, constraint, m, wrong))
+ return nil
+ }
+ }
}
}
j++
}
}
- // untyped[:j] are the undices of parameters without a type yet
+ // untyped[:j] are the indices of parameters without a type yet
for _, i := range untyped[:j] {
tpar := params.At(i).typ.(*TypeParam)
arg := args[i]
// List[Elem].
related3 /* ERROR "cannot infer Slice" */ [int]()
}
+
+func wantsMethods[P interface{ m1(Q); m2() R }, Q, R any](P) {}
+
+type hasMethods1 struct{}
+
+func (hasMethods1) m1(int)
+func (hasMethods1) m2() string
+
+type hasMethods2 struct{}
+
+func (*hasMethods2) m1(int)
+func (*hasMethods2) m2() string
+
+type hasMethods3 interface{
+ m1(float64)
+ m2() complex128
+}
+
+type hasMethods4 interface{
+ m1()
+}
+
+func _() {
+ // wantsMethod can be called with arguments that have the relevant methods
+ // and wantsMethod's type arguments are inferred from those types' method
+ // signatures.
+ wantsMethods(hasMethods1{})
+ wantsMethods(&hasMethods1{})
+ // TODO(gri) improve error message (the cause is ptr vs non-pointer receiver)
+ wantsMethods /* ERROR "hasMethods2 does not satisfy interface{m1(Q); m2() R} (wrong type for method m1)" */ (hasMethods2{})
+ wantsMethods(&hasMethods2{})
+ wantsMethods(hasMethods3(nil))
+ wantsMethods /* ERROR "any does not satisfy interface{m1(Q); m2() R} (missing method m1)" */ (any(nil))
+ wantsMethods /* ERROR "hasMethods4 does not satisfy interface{m1(Q); m2() R} (wrong type for method m1)" */ (hasMethods4(nil))
+}
type T = interface { m(int) }
func _() {
- _ = f /* ERROR "cannot infer R" */ [T] // don't crash in type inference
+ _ = f[T]
}