Skip to content

Commit 7a3a2b1

Browse files
committed
go/types, types2: eagerly check that constraints are not type params
As a result of the change to the underlying of a type parameter to be its constraint interface, we had couple inaccuracies that combined to cause an infinite recursion when type checking the invalid type parameter list [A A]. - We deferred tpar.iface() using check.later twice: once in newTypeParam, and then again at the end of collectTypeParams. - We deferred the check that type parameter constraints are not type parameters, even though this is unnecessary: the constraint type is known. With these inaccuracies, tpar.iface() was executing before our guard against using type parameters as constraints, causing an infinite recursion through under(). Fix this by eagerly checking whether the constraint is a type parameter, and marking it invalid if so. Also remove the unnecessary calls to tpar.iface() at the end of collectTypeParams, as this will already have been scheduled by newTypeParam. Fixes #50321 Change-Id: I4eecbecf21656615867cb94be65b520e9e795bd1 Reviewed-on: https://go-review.googlesource.com/c/go/+/374294 Reviewed-by: Robert Griesemer <[email protected]> Trust: Robert Findley <[email protected]> Run-TryBot: Robert Findley <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent f009910 commit 7a3a2b1

File tree

4 files changed

+34
-32
lines changed

4 files changed

+34
-32
lines changed

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

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -657,33 +657,24 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel
657657
// Keep track of bounds for later validation.
658658
var bound Type
659659
var bounds []Type
660-
var posers []poser
661660
for i, f := range list {
662661
// Optimization: Re-use the previous type bound if it hasn't changed.
663662
// This also preserves the grouped output of type parameter lists
664663
// when printing type strings.
665664
if i == 0 || f.Type != list[i-1].Type {
666665
bound = check.bound(f.Type)
667-
bounds = append(bounds, bound)
668-
posers = append(posers, f.Type)
669-
}
670-
tparams[i].bound = bound
671-
}
672-
673-
check.later(func() {
674-
for i, bound := range bounds {
675666
if isTypeParam(bound) {
676667
// We may be able to allow this since it is now well-defined what
677668
// the underlying type and thus type set of a type parameter is.
678669
// But we may need some additional form of cycle detection within
679670
// type parameter lists.
680-
check.error(posers[i], "cannot use a type parameter as constraint")
671+
check.error(f.Type, "cannot use a type parameter as constraint")
672+
bound = Typ[Invalid]
681673
}
674+
bounds = append(bounds, bound)
682675
}
683-
for _, tpar := range tparams {
684-
tpar.iface() // compute type set
685-
}
686-
})
676+
tparams[i].bound = bound
677+
}
687678
}
688679

689680
func (check *Checker) bound(x syntax.Expr) Type {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
func Ln[A A /* ERROR cannot use a type parameter as constraint */ ](p A) {
8+
}

src/go/types/decl.go

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -708,34 +708,29 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList
708708

709709
index := 0
710710
var bounds []Type
711-
var posns []positioner // bound positions
712711
for _, f := range list.List {
713-
// TODO(rfindley) we should be able to rely on f.Type != nil at this point
712+
var bound Type
713+
// NOTE: we may be able to assert that f.Type != nil here, but this is not
714+
// an invariant of the AST, so we are cautious.
714715
if f.Type != nil {
715-
bound := check.bound(f.Type)
716-
bounds = append(bounds, bound)
717-
posns = append(posns, f.Type)
718-
for i := range f.Names {
719-
tparams[index+i].bound = bound
720-
}
721-
}
722-
index += len(f.Names)
723-
}
724-
725-
check.later(func() {
726-
for i, bound := range bounds {
716+
bound = check.bound(f.Type)
727717
if isTypeParam(bound) {
728718
// We may be able to allow this since it is now well-defined what
729719
// the underlying type and thus type set of a type parameter is.
730720
// But we may need some additional form of cycle detection within
731721
// type parameter lists.
732-
check.error(posns[i], _MisplacedTypeParam, "cannot use a type parameter as constraint")
722+
check.error(f.Type, _MisplacedTypeParam, "cannot use a type parameter as constraint")
723+
bound = Typ[Invalid]
733724
}
725+
} else {
726+
bound = Typ[Invalid]
734727
}
735-
for _, tpar := range tparams {
736-
tpar.iface() // compute type set
728+
bounds = append(bounds, bound)
729+
for i := range f.Names {
730+
tparams[index+i].bound = bound
737731
}
738-
})
732+
index += len(f.Names)
733+
}
739734
}
740735

741736
func (check *Checker) bound(x ast.Expr) Type {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
func Ln[A A /* ERROR cannot use a type parameter as constraint */ ](p A) {
8+
}

0 commit comments

Comments
 (0)