diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index 8dd04ff408..e32063a0af 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -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 { diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go index 7cce1f7e35..03ba9be55c 100644 --- a/src/go/types/typeparam.go +++ b/src/go/types/typeparam.go @@ -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