| // Copyright 2020 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 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) |
| |
| // Note: Some map entries are not references. |
| // If modified, they must be assigned back. |
| |
| for e, tv := range info.Types { |
| if typ := s.typ(tv.Type); typ != tv.Type { |
| tv.Type = typ |
| info.Types[e] = tv |
| } |
| } |
| |
| inferred := getInferred(info) |
| for e, inf := range inferred { |
| changed := false |
| for i, targ := range inf.Targs { |
| 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 { |
| inferred[e] = inf |
| } |
| } |
| |
| for _, obj := range info.Defs { |
| if obj != nil { |
| if typ := s.typ(obj.Type()); typ != obj.Type() { |
| obj.setType(typ) |
| } |
| } |
| } |
| |
| for _, obj := range info.Uses { |
| if obj != nil { |
| if typ := s.typ(obj.Type()); typ != obj.Type() { |
| obj.setType(typ) |
| } |
| } |
| } |
| |
| // TODO(gri) sanitize as needed |
| // - info.Implicits |
| // - info.Selections |
| // - info.Scopes |
| // - info.InitOrder |
| } |
| |
| type sanitizer map[Type]Type |
| |
| func (s sanitizer) typ(typ Type) Type { |
| if typ == nil { |
| return nil |
| } |
| |
| if t, found := s[typ]; found { |
| return t |
| } |
| s[typ] = typ |
| |
| switch t := typ.(type) { |
| case *Basic, *bottom, *top: |
| // nothing to do |
| |
| case *Array: |
| if elem := s.typ(t.elem); elem != t.elem { |
| t.elem = elem |
| } |
| |
| case *Slice: |
| if elem := s.typ(t.elem); elem != t.elem { |
| t.elem = elem |
| } |
| |
| case *Struct: |
| s.varList(t.fields) |
| |
| case *Pointer: |
| if base := s.typ(t.base); base != t.base { |
| t.base = base |
| } |
| |
| case *Tuple: |
| s.tuple(t) |
| |
| case *Signature: |
| s.var_(t.recv) |
| s.tuple(t.params) |
| s.tuple(t.results) |
| |
| case *_Sum: |
| s.typeList(t.types) |
| |
| case *Interface: |
| s.funcList(t.methods) |
| if types := s.typ(t.types); types != t.types { |
| t.types = types |
| } |
| s.typeList(t.embeddeds) |
| s.funcList(t.allMethods) |
| if allTypes := s.typ(t.allTypes); allTypes != t.allTypes { |
| t.allTypes = allTypes |
| } |
| |
| case *Map: |
| 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: |
| if elem := s.typ(t.elem); elem != t.elem { |
| t.elem = elem |
| } |
| |
| case *Named: |
| if debug && t.check != nil { |
| panic("internal error: Named.check != nil") |
| } |
| 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: |
| if bound := s.typ(t.bound); bound != t.bound { |
| t.bound = bound |
| } |
| |
| case *instance: |
| typ = t.expand() |
| s[t] = typ |
| |
| default: |
| panic("unimplemented") |
| } |
| |
| return typ |
| } |
| |
| func (s sanitizer) var_(v *Var) { |
| if v != nil { |
| if typ := s.typ(v.typ); typ != v.typ { |
| v.typ = typ |
| } |
| } |
| } |
| |
| func (s sanitizer) varList(list []*Var) { |
| for _, v := range list { |
| s.var_(v) |
| } |
| } |
| |
| func (s sanitizer) tuple(t *Tuple) { |
| if t != nil { |
| s.varList(t.vars) |
| } |
| } |
| |
| func (s sanitizer) func_(f *Func) { |
| if f != nil { |
| if typ := s.typ(f.typ); typ != f.typ { |
| f.typ = typ |
| } |
| } |
| } |
| |
| func (s sanitizer) funcList(list []*Func) { |
| for _, f := range list { |
| s.func_(f) |
| } |
| } |
| |
| func (s sanitizer) typeList(list []Type) { |
| for i, t := range list { |
| if typ := s.typ(t); typ != t { |
| list[i] = typ |
| } |
| } |
| } |