blob: 727ec173eac81a4077be56e5f1a1affe9372e88b [file] [log] [blame]
// 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
}
}
}