// 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 {
+ if traceInference {
+ 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.x.at(i)
switch {
if core.tilde && !isTypeParam(tx) {
tx = under(tx)
}
- if !u.unify(tx, core.typ) {
- // TODO(gri) improve error message by providing the type arguments
- // which we know already
- // Don't use term.String() as it always qualifies types, even if they
- // are in the current package.
- tilde := ""
- if core.tilde {
- tilde = "~"
- }
- check.errorf(pos, InvalidTypeArg, "%s does not match %s%s", tx, tilde, core.typ)
- return nil, 0
- }
+ // Unification may fail because it operates with limited information (core type),
+ // even if a given type argument satisfies the corresponding type constraint.
+ // For instance, given [P T1|T2, ...] where the type argument for P is (named
+ // type) T1, and T1 and T2 have the same built-in (named) type T0 as underlying
+ // type, the core type will be the named type T0, which doesn't match T1.
+ // Yet the instantiation of P with T1 is clearly valid (see #53650).
+ // Reporting an error if unification fails would be incorrect in this case.
+ // On the other hand, it is safe to ignore failing unification during constraint
+ // type inference because if the failure is true, an error will be reported when
+ // checking instantiation.
+ u.unify(tx, core.typ)
case single && !core.tilde:
// The corresponding type argument tx is unknown and there's a single
if nn == 0 {
break // all type arguments are known
}
+ } else {
+ if traceInference {
+ u.tracef("core(%s) = nil", tpar)
+ }
}
}
// 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 {
+ if traceInference {
+ 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.x.at(i)
switch {
if core.tilde && !isTypeParam(tx) {
tx = under(tx)
}
- if !u.unify(tx, core.typ) {
- // TODO(gri) improve error message by providing the type arguments
- // which we know already
- // Don't use term.String() as it always qualifies types, even if they
- // are in the current package.
- tilde := ""
- if core.tilde {
- tilde = "~"
- }
- check.errorf(posn, InvalidTypeArg, "%s does not match %s%s", tx, tilde, core.typ)
- return nil, 0
- }
+ // Unification may fail because it operates with limited information (core type),
+ // even if a given type argument satisfies the corresponding type constraint.
+ // For instance, given [P T1|T2, ...] where the type argument for P is (named
+ // type) T1, and T1 and T2 have the same built-in (named) type T0 as underlying
+ // type, the core type will be the named type T0, which doesn't match T1.
+ // Yet the instantiation of P with T1 is clearly valid (see #53650).
+ // Reporting an error if unification fails would be incorrect in this case.
+ // On the other hand, it is safe to ignore failing unification during constraint
+ // type inference because if the failure is true, an error will be reported when
+ // checking instantiation.
+ u.unify(tx, core.typ)
case single && !core.tilde:
// The corresponding type argument tx is unknown and there's a single
if nn == 0 {
break // all type arguments are known
}
+ } else {
+ if traceInference {
+ u.tracef("core(%s) = nil", tpar)
+ }
}
}
}
func _() {
- _ = app /* ERROR "int does not match" */ [int]
+ _ = app /* ERROR "cannot infer T" */ [int]
}
--- /dev/null
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import (
+ "reflect"
+ "testing"
+)
+
+type T1 int
+type T2 int
+
+func f[P T1 | T2, _ []P]() {}
+
+var _ = f[T1]
+
+// test case from issue
+
+type BaseT interface {
+ Type1 | Type2
+}
+type BaseType int
+type Type1 BaseType
+type Type2 BaseType // float64
+
+type ValueT[T BaseT] struct {
+ A1 T
+}
+
+func NewType1() *ValueT[Type1] {
+ r := NewT[Type1]()
+ return r
+}
+func NewType2() *ValueT[Type2] {
+ r := NewT[Type2]()
+ return r
+}
+
+func NewT[TBase BaseT, TVal ValueT[TBase]]() *TVal {
+ ret := TVal{}
+ return &ret
+}
+func TestGoType(t *testing.T) {
+ r1 := NewType1()
+ r2 := NewType2()
+ t.Log(r1, r2)
+ t.Log(reflect.TypeOf(r1), reflect.TypeOf(r2))
+ fooT1(r1.A1)
+ fooT2(r2.A1)
+}
+
+func fooT1(t1 Type1) {
+
+}
+func fooT2(t2 Type2) {
+
+}