mirror of
https://github.com/golang/go
synced 2024-11-11 22:10:22 -07:00
go/types: don't write during sanitizeInfo if nothing has changed
In its final phase, the typechecker walks the types it produces to ensure that no unexpanded type instances leak through the API. However, this also walks shared types (such as those in the universe scope), resulting in a potential data race during concurrent typechecking passes. Fix this by being careful not to write if nothing needs to be changed. Since any shared types should already be sanitized, this should eliminate data races. For #44434 Change-Id: Iadb2e78863efe0e974e69a00e255f26cfaf9386a Reviewed-on: https://go-review.googlesource.com/c/go/+/294411 Trust: Robert Findley <rfindley@google.com> Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Findley <rfindley@google.com> Reviewed-by: Robert Griesemer <gri@golang.org> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
9a99515c8f
commit
26713b5fef
@ -6,6 +6,11 @@ package types
|
||||
|
||||
// sanitizeInfo walks the types contained in info to ensure that all instances
|
||||
// are expanded.
|
||||
//
|
||||
// This includes some objects that may be shared across concurrent
|
||||
// type-checking passes (such as those in the universe scope), so we are
|
||||
// careful here not to write types that are already sanitized. This avoids a
|
||||
// data race as any shared types should already be sanitized.
|
||||
func sanitizeInfo(info *Info) {
|
||||
var s sanitizer = make(map[Type]Type)
|
||||
|
||||
@ -13,27 +18,42 @@ func sanitizeInfo(info *Info) {
|
||||
// If modified, they must be assigned back.
|
||||
|
||||
for e, tv := range info.Types {
|
||||
tv.Type = s.typ(tv.Type)
|
||||
info.Types[e] = tv
|
||||
if typ := s.typ(tv.Type); typ != tv.Type {
|
||||
tv.Type = typ
|
||||
info.Types[e] = tv
|
||||
}
|
||||
}
|
||||
|
||||
for e, inf := range info.Inferred {
|
||||
changed := false
|
||||
for i, targ := range inf.Targs {
|
||||
inf.Targs[i] = s.typ(targ)
|
||||
if typ := s.typ(targ); typ != targ {
|
||||
inf.Targs[i] = typ
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
if typ := s.typ(inf.Sig); typ != inf.Sig {
|
||||
inf.Sig = typ.(*Signature)
|
||||
changed = true
|
||||
}
|
||||
if changed {
|
||||
info.Inferred[e] = inf
|
||||
}
|
||||
inf.Sig = s.typ(inf.Sig).(*Signature)
|
||||
info.Inferred[e] = inf
|
||||
}
|
||||
|
||||
for _, obj := range info.Defs {
|
||||
if obj != nil {
|
||||
obj.setType(s.typ(obj.Type()))
|
||||
if typ := s.typ(obj.Type()); typ != obj.Type() {
|
||||
obj.setType(typ)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, obj := range info.Uses {
|
||||
if obj != nil {
|
||||
obj.setType(s.typ(obj.Type()))
|
||||
if typ := s.typ(obj.Type()); typ != obj.Type() {
|
||||
obj.setType(typ)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,16 +77,22 @@ func (s sanitizer) typ(typ Type) Type {
|
||||
// nothing to do
|
||||
|
||||
case *Array:
|
||||
t.elem = s.typ(t.elem)
|
||||
if elem := s.typ(t.elem); elem != t.elem {
|
||||
t.elem = elem
|
||||
}
|
||||
|
||||
case *Slice:
|
||||
t.elem = s.typ(t.elem)
|
||||
if elem := s.typ(t.elem); elem != t.elem {
|
||||
t.elem = elem
|
||||
}
|
||||
|
||||
case *Struct:
|
||||
s.varList(t.fields)
|
||||
|
||||
case *Pointer:
|
||||
t.base = s.typ(t.base)
|
||||
if base := s.typ(t.base); base != t.base {
|
||||
t.base = base
|
||||
}
|
||||
|
||||
case *Tuple:
|
||||
s.tuple(t)
|
||||
@ -87,20 +113,32 @@ func (s sanitizer) typ(typ Type) Type {
|
||||
s.typ(t.allTypes)
|
||||
|
||||
case *Map:
|
||||
t.key = s.typ(t.key)
|
||||
t.elem = s.typ(t.elem)
|
||||
if key := s.typ(t.key); key != t.key {
|
||||
t.key = key
|
||||
}
|
||||
if elem := s.typ(t.elem); elem != t.elem {
|
||||
t.elem = elem
|
||||
}
|
||||
|
||||
case *Chan:
|
||||
t.elem = s.typ(t.elem)
|
||||
if elem := s.typ(t.elem); elem != t.elem {
|
||||
t.elem = elem
|
||||
}
|
||||
|
||||
case *Named:
|
||||
t.orig = s.typ(t.orig)
|
||||
t.underlying = s.typ(t.underlying)
|
||||
if orig := s.typ(t.orig); orig != t.orig {
|
||||
t.orig = orig
|
||||
}
|
||||
if under := s.typ(t.underlying); under != t.underlying {
|
||||
t.underlying = under
|
||||
}
|
||||
s.typeList(t.targs)
|
||||
s.funcList(t.methods)
|
||||
|
||||
case *TypeParam:
|
||||
t.bound = s.typ(t.bound)
|
||||
if bound := s.typ(t.bound); bound != t.bound {
|
||||
t.bound = bound
|
||||
}
|
||||
|
||||
case *instance:
|
||||
typ = t.expand()
|
||||
@ -115,7 +153,9 @@ func (s sanitizer) typ(typ Type) Type {
|
||||
|
||||
func (s sanitizer) var_(v *Var) {
|
||||
if v != nil {
|
||||
v.typ = s.typ(v.typ)
|
||||
if typ := s.typ(v.typ); typ != v.typ {
|
||||
v.typ = typ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +173,9 @@ func (s sanitizer) tuple(t *Tuple) {
|
||||
|
||||
func (s sanitizer) func_(f *Func) {
|
||||
if f != nil {
|
||||
f.typ = s.typ(f.typ)
|
||||
if typ := s.typ(f.typ); typ != f.typ {
|
||||
f.typ = typ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,6 +187,8 @@ func (s sanitizer) funcList(list []*Func) {
|
||||
|
||||
func (s sanitizer) typeList(list []Type) {
|
||||
for i, t := range list {
|
||||
list[i] = s.typ(t)
|
||||
if typ := s.typ(t); typ != t {
|
||||
list[i] = typ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user