mirror of
https://github.com/golang/go
synced 2024-11-17 10:04:43 -07:00
go/types: ensure that constructed type parameters are immutable
TypeParam.iface may mutate TypeParam.bound in the event that the type parameter bound is not an interface. Ensure that iface() is called before the type-checking pass returns, and before NewTypeParam or TypeParam.SetConstraint exits. Fixes #49788 Change-Id: I72279acf5f0223161671c04887bc2c3df4158927 Reviewed-on: https://go-review.googlesource.com/c/go/+/367614 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
c402d64f37
commit
186f375ecf
@ -21,7 +21,7 @@ type TypeParam struct {
|
||||
id uint64 // unique id, for debugging only
|
||||
obj *TypeName // corresponding type name
|
||||
index int // type parameter index in source order, starting at 0
|
||||
bound Type // any type, but eventually an *Interface for correct programs (see TypeParam.iface)
|
||||
bound Type // any type, but underlying is eventually *Interface for correct programs (see TypeParam.iface)
|
||||
}
|
||||
|
||||
// Obj returns the type name for the type parameter t.
|
||||
@ -47,6 +47,15 @@ func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
||||
if obj.typ == nil {
|
||||
obj.typ = typ
|
||||
}
|
||||
// iface may mutate typ.bound, so we must ensure that iface() is called
|
||||
// at least once before the resulting TypeParam escapes.
|
||||
if check != nil {
|
||||
check.later(func() {
|
||||
typ.iface()
|
||||
})
|
||||
} else if constraint != nil {
|
||||
typ.iface()
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
@ -62,11 +71,17 @@ func (t *TypeParam) Constraint() Type {
|
||||
}
|
||||
|
||||
// SetConstraint sets the type constraint for t.
|
||||
//
|
||||
// SetConstraint should not be called concurrently, but once SetConstraint
|
||||
// returns the receiver t is safe for concurrent use.
|
||||
func (t *TypeParam) SetConstraint(bound Type) {
|
||||
if bound == nil {
|
||||
panic("nil constraint")
|
||||
}
|
||||
t.bound = bound
|
||||
// iface may mutate t.bound (if bound is not an interface), so ensure that
|
||||
// this is done before returning.
|
||||
t.iface()
|
||||
}
|
||||
|
||||
func (t *TypeParam) Underlying() Type {
|
||||
|
@ -24,7 +24,7 @@ type TypeParam struct {
|
||||
id uint64 // unique id, for debugging only
|
||||
obj *TypeName // corresponding type name
|
||||
index int // type parameter index in source order, starting at 0
|
||||
bound Type // any type, but eventually an *Interface for correct programs (see TypeParam.iface)
|
||||
bound Type // any type, but underlying is eventually *Interface for correct programs (see TypeParam.iface)
|
||||
}
|
||||
|
||||
// NewTypeParam returns a new TypeParam. Type parameters may be set on a Named
|
||||
@ -47,6 +47,15 @@ func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
||||
if obj.typ == nil {
|
||||
obj.typ = typ
|
||||
}
|
||||
// iface may mutate typ.bound, so we must ensure that iface() is called
|
||||
// at least once before the resulting TypeParam escapes.
|
||||
if check != nil {
|
||||
check.later(func() {
|
||||
typ.iface()
|
||||
})
|
||||
} else if constraint != nil {
|
||||
typ.iface()
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
@ -65,11 +74,17 @@ func (t *TypeParam) Constraint() Type {
|
||||
}
|
||||
|
||||
// SetConstraint sets the type constraint for t.
|
||||
//
|
||||
// SetConstraint should not be called concurrently, but once SetConstraint
|
||||
// returns the receiver t is safe for concurrent use.
|
||||
func (t *TypeParam) SetConstraint(bound Type) {
|
||||
if bound == nil {
|
||||
panic("nil constraint")
|
||||
}
|
||||
t.bound = bound
|
||||
// iface may mutate t.bound (if bound is not an interface), so ensure that
|
||||
// this is done before returning.
|
||||
t.iface()
|
||||
}
|
||||
|
||||
func (t *TypeParam) Underlying() Type {
|
||||
@ -104,7 +119,6 @@ func (t *TypeParam) iface() *Interface {
|
||||
}
|
||||
|
||||
// If we don't have an interface, wrap constraint into an implicit interface.
|
||||
// TODO(gri) mark it as implicit - see comment in Checker.bound
|
||||
if ityp == nil {
|
||||
ityp = NewInterfaceType(nil, []Type{bound})
|
||||
ityp.implicit = true
|
||||
|
Loading…
Reference in New Issue
Block a user