if tdecl.TParamList != nil {
check.openScope(tdecl, "type parameters")
defer check.closeScope()
- named.tparams = check.collectTypeParams(tdecl.TParamList)
+ check.collectTypeParams(&named.tparams, tdecl.TParamList)
}
// determine underlying type of named
}
}
-func (check *Checker) collectTypeParams(list []*syntax.Field) *TParamList {
+func (check *Checker) collectTypeParams(dst **TParamList, list []*syntax.Field) {
tparams := make([]*TypeParam, len(list))
// Declare type parameters up-front.
tparams[i] = check.declareTypeParam(f.Name)
}
+ // Set the type parameters before collecting the type constraints because
+ // the parameterized type may be used by the constraints (issue #47887).
+ // Example: type T[P T[P]] interface{}
+ *dst = bindTParams(tparams)
+
var bound Type
for i, f := range list {
// Optimization: Re-use the previous type bound if it hasn't changed.
}
tparams[i].bound = bound
}
-
- return bindTParams(tparams)
}
func (check *Checker) declareTypeParam(name *syntax.Name) *TypeParam {
+ // Use Typ[Invalid] for the type constraint to ensure that a type
+ // is present even if the actual constraint has not been assigned
+ // yet.
+ // TODO(gri) Need to systematically review all uses of type parameter
+ // constraints to make sure we don't rely on them if they
+ // are not properly set yet.
tname := NewTypeName(name.Pos(), check.pkg, name.Value, nil)
- tpar := check.NewTypeParam(tname, nil) // assigns type to tname as a side-effect
+ tpar := check.NewTypeParam(tname, Typ[Invalid]) // assigns type to tname as a side-effect
check.declare(check.scope, name, tname, check.scope.pos) // TODO(gri) check scope position
return tpar
}
--- /dev/null
+// Copyright 2021 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
+
+// parameterized types with self-recursive constraints
+type (
+ T1[P T1[P]] interface{}
+ T2[P, Q T2[P, Q]] interface{}
+ T3[P T2[P, Q], Q interface{ ~string }] interface{}
+
+ T4a[P T4a[P]] interface{ ~int }
+ T4b[P T4b[int]] interface{ ~int }
+ T4c[P T4c[string /* ERROR string does not satisfy T4c\[string\] */]] interface{ ~int }
+
+ // mutually recursive constraints
+ T5[P T6[P]] interface{ int }
+ T6[P T5[P]] interface{ int }
+)
+
+// verify that constraints are checked as expected
+var (
+ _ T1[int]
+ _ T2[int, string]
+ _ T3[int, string]
+)
+
+// test case from issue
+
+type Eq[a Eq[a]] interface {
+ Equal(that a) bool
+}