Skip to content

Commit b44f222

Browse files
griesemergopherbot
authored andcommitted
go/types, types2: consider methods when unifying type parameters and constraints
An inferred type argument must implement its type parameter's constraint's methods whether or not a core type exists. This allows us to infer type parameters used in method signatures. Fixes #51593. Change-Id: I1fddb05a71d442641b4311d8e30a13ea9bdb4db5 Reviewed-on: https://go-review.googlesource.com/c/go/+/472298 TryBot-Result: Gopher Robot <[email protected]> Auto-Submit: Robert Griesemer <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 09852e7 commit b44f222

File tree

5 files changed

+77
-12
lines changed

5 files changed

+77
-12
lines changed

src/cmd/compile/internal/types2/check_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ func TestCheck(t *testing.T) {
326326
}
327327
func TestSpec(t *testing.T) { testDirFiles(t, "../../../../internal/types/testdata/spec", 0, false) }
328328
func TestExamples(t *testing.T) {
329-
testDirFiles(t, "../../../../internal/types/testdata/examples", 60, false)
329+
testDirFiles(t, "../../../../internal/types/testdata/examples", 125, false)
330330
} // TODO(gri) narrow column tolerance
331331
func TestFixedbugs(t *testing.T) {
332332
testDirFiles(t, "../../../../internal/types/testdata/fixedbugs", 100, false)

src/cmd/compile/internal/types2/infer.go

+20-5
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,12 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
186186
u.tracef("type parameters: %s", tparams)
187187
}
188188

189-
// Repeatedly apply constraint type inference as long as
190-
// progress is being made.
189+
// Unify type parameters with their constraints as long
190+
// as progress is being made.
191191
//
192192
// This is an O(n^2) algorithm where n is the number of
193193
// type parameters: if there is progress, at least one
194-
// type argument is inferred per iteration and we have
194+
// type argument is inferred per iteration, and we have
195195
// a doubly nested loop.
196196
//
197197
// In practice this is not a problem because the number
@@ -205,14 +205,18 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
205205
nn := u.unknowns()
206206

207207
for _, tpar := range tparams {
208+
tx := u.at(tpar)
209+
if traceInference && tx != nil {
210+
u.tracef("%s = %s", tpar, tx)
211+
}
212+
208213
// If there is a core term (i.e., a core type with tilde information)
209214
// unify the type parameter with the core type.
210215
if core, single := coreTerm(tpar); core != nil {
211216
if traceInference {
212217
u.tracef("core(%s) = %s (single = %v)", tpar, core, single)
213218
}
214219
// A type parameter can be unified with its core type in two cases.
215-
tx := u.at(tpar)
216220
switch {
217221
case tx != nil:
218222
// The corresponding type argument tx is known. There are 2 cases:
@@ -239,6 +243,17 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
239243
if traceInference {
240244
u.tracef("core(%s) = nil", tpar)
241245
}
246+
if tx != nil {
247+
// We don't have a core type, but the type argument tx is known.
248+
// It must have (at least) all the methods of the type constraint,
249+
// and the method signatures must unify; otherwise tx cannot satisfy
250+
// the constraint.
251+
constraint := tpar.iface()
252+
if m, wrong := check.missingMethod(tx, constraint, true, u.unify); m != nil {
253+
check.errorf(pos, CannotInferTypeArgs, "%s does not satisfy %s %s", tx, constraint, check.missingMethodCause(tx, constraint, m, wrong))
254+
return nil
255+
}
256+
}
242257
}
243258
}
244259

@@ -273,7 +288,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
273288
j++
274289
}
275290
}
276-
// untyped[:j] are the undices of parameters without a type yet
291+
// untyped[:j] are the indices of parameters without a type yet
277292
for _, i := range untyped[:j] {
278293
tpar := params.At(i).typ.(*TypeParam)
279294
arg := args[i]

src/go/types/infer.go

+20-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/internal/types/testdata/examples/inference.go

+35
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,38 @@ func _() {
114114
// List[Elem].
115115
related3 /* ERROR "cannot infer Slice" */ [int]()
116116
}
117+
118+
func wantsMethods[P interface{ m1(Q); m2() R }, Q, R any](P) {}
119+
120+
type hasMethods1 struct{}
121+
122+
func (hasMethods1) m1(int)
123+
func (hasMethods1) m2() string
124+
125+
type hasMethods2 struct{}
126+
127+
func (*hasMethods2) m1(int)
128+
func (*hasMethods2) m2() string
129+
130+
type hasMethods3 interface{
131+
m1(float64)
132+
m2() complex128
133+
}
134+
135+
type hasMethods4 interface{
136+
m1()
137+
}
138+
139+
func _() {
140+
// wantsMethod can be called with arguments that have the relevant methods
141+
// and wantsMethod's type arguments are inferred from those types' method
142+
// signatures.
143+
wantsMethods(hasMethods1{})
144+
wantsMethods(&hasMethods1{})
145+
// TODO(gri) improve error message (the cause is ptr vs non-pointer receiver)
146+
wantsMethods /* ERROR "hasMethods2 does not satisfy interface{m1(Q); m2() R} (wrong type for method m1)" */ (hasMethods2{})
147+
wantsMethods(&hasMethods2{})
148+
wantsMethods(hasMethods3(nil))
149+
wantsMethods /* ERROR "any does not satisfy interface{m1(Q); m2() R} (missing method m1)" */ (any(nil))
150+
wantsMethods /* ERROR "hasMethods4 does not satisfy interface{m1(Q); m2() R} (wrong type for method m1)" */ (hasMethods4(nil))
151+
}

src/internal/types/testdata/fixedbugs/issue51593.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ func f[P interface{ m(R) }, R any]() {}
99
type T = interface { m(int) }
1010

1111
func _() {
12-
_ = f /* ERROR "cannot infer R" */ [T] // don't crash in type inference
12+
_ = f[T]
1313
}

0 commit comments

Comments
 (0)