]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types: refactor the Context type map to accept arbitrary types
authorRobert Findley <rfindley@google.com>
Wed, 10 Nov 2021 03:20:18 +0000 (22:20 -0500)
committerRobert Findley <rfindley@google.com>
Fri, 12 Nov 2021 18:11:18 +0000 (18:11 +0000)
In preparation for storing *Signature types in Context, refactor the
type map to not depend on the *Named type API.

Change-Id: I0439d43aa4cc3a60a78f409a773a343a4fffd0fa
Reviewed-on: https://go-review.googlesource.com/c/go/+/362799
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>
src/go/types/context.go
src/go/types/instantiate.go
src/go/types/named.go
src/go/types/typexpr.go

index e89babcd705f25816e49674dc98452f171131b76..0c2b0958c109f2d1e79258c0146a38935a45610c 100644 (file)
@@ -18,15 +18,21 @@ import (
 // It is safe for concurrent use.
 type Context struct {
        mu      sync.Mutex
-       typeMap map[string][]*Named // type hash -> instances
-       nextID  int                 // next unique ID
-       seen    map[*Named]int      // assigned unique IDs
+       typeMap map[string][]ctxtEntry // type hash -> instances entries
+       nextID  int                    // next unique ID
+       seen    map[*Named]int         // assigned unique IDs
+}
+
+type ctxtEntry struct {
+       orig     Type
+       targs    []Type
+       instance Type // = orig[targs]
 }
 
 // NewContext creates a new Context.
 func NewContext() *Context {
        return &Context{
-               typeMap: make(map[string][]*Named),
+               typeMap: make(map[string][]ctxtEntry),
                seen:    make(map[*Named]int),
        }
 }
@@ -60,17 +66,17 @@ func (ctxt *Context) typeHash(typ Type, targs []Type) string {
 
 // lookup returns an existing instantiation of orig with targs, if it exists.
 // Otherwise, it returns nil.
-func (ctxt *Context) lookup(h string, orig *Named, targs []Type) *Named {
+func (ctxt *Context) lookup(h string, orig *Named, targs []Type) Type {
        ctxt.mu.Lock()
        defer ctxt.mu.Unlock()
 
        for _, e := range ctxt.typeMap[h] {
-               if identicalInstance(orig, targs, e.orig, e.TypeArgs().list()) {
-                       return e
+               if identicalInstance(orig, targs, e.orig, e.targs) {
+                       return e.instance
                }
                if debug {
                        // Panic during development to surface any imperfections in our hash.
-                       panic(fmt.Sprintf("non-identical instances: (orig: %s, targs: %v) and %s", orig, targs, e))
+                       panic(fmt.Sprintf("non-identical instances: (orig: %s, targs: %v) and %s", orig, targs, e.instance))
                }
        }
 
@@ -81,24 +87,29 @@ func (ctxt *Context) lookup(h string, orig *Named, targs []Type) *Named {
 // identical type is found with the type hash h, the previously seen type is
 // returned. Otherwise, n is returned, and recorded in the Context for the hash
 // h.
-func (ctxt *Context) update(h string, n *Named) *Named {
-       assert(n != nil)
+func (ctxt *Context) update(h string, orig Type, targs []Type, inst Type) Type {
+       assert(inst != nil)
 
        ctxt.mu.Lock()
        defer ctxt.mu.Unlock()
 
        for _, e := range ctxt.typeMap[h] {
-               if n == nil || Identical(n, e) {
-                       return e
+               if inst == nil || Identical(inst, e.instance) {
+                       return e.instance
                }
                if debug {
                        // Panic during development to surface any imperfections in our hash.
-                       panic(fmt.Sprintf("%s and %s are not identical", n, e))
+                       panic(fmt.Sprintf("%s and %s are not identical", inst, e.instance))
                }
        }
 
-       ctxt.typeMap[h] = append(ctxt.typeMap[h], n)
-       return n
+       ctxt.typeMap[h] = append(ctxt.typeMap[h], ctxtEntry{
+               orig:     orig,
+               targs:    targs,
+               instance: inst,
+       })
+
+       return inst
 }
 
 // idForType returns a unique ID for the pointer n.
index 1077ad81604f479e48580aed78d987fc2054db2b..814d457de3dfe08ec789e200589c51200cfba6a6 100644 (file)
@@ -52,20 +52,20 @@ func Instantiate(ctxt *Context, typ Type, targs []Type, validate bool) (Type, er
 // instance creates a type or function instance using the given original type
 // typ and arguments targs. For Named types the resulting instance will be
 // unexpanded.
-func (check *Checker) instance(pos token.Pos, typ Type, targs []Type, ctxt *Context) Type {
-       switch t := typ.(type) {
+func (check *Checker) instance(pos token.Pos, orig Type, targs []Type, ctxt *Context) Type {
+       switch orig := orig.(type) {
        case *Named:
                var h string
                if ctxt != nil {
-                       h = ctxt.typeHash(t, targs)
+                       h = ctxt.typeHash(orig, targs)
                        // typ may already have been instantiated with identical type arguments. In
                        // that case, re-use the existing instance.
-                       if named := ctxt.lookup(h, t, targs); named != nil {
+                       if named := ctxt.lookup(h, orig, targs); named != nil {
                                return named
                        }
                }
-               tname := NewTypeName(pos, t.obj.pkg, t.obj.name, nil)
-               named := check.newNamed(tname, t, nil, nil, nil) // underlying, tparams, and methods are set when named is resolved
+               tname := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil)
+               named := check.newNamed(tname, orig, nil, nil, nil) // underlying, tparams, and methods are set when named is resolved
                named.targs = NewTypeList(targs)
                named.resolver = func(ctxt *Context, n *Named) (*TypeParamList, Type, []*Func) {
                        return expandNamed(ctxt, n, pos)
@@ -73,23 +73,23 @@ func (check *Checker) instance(pos token.Pos, typ Type, targs []Type, ctxt *Cont
                if ctxt != nil {
                        // It's possible that we've lost a race to add named to the context.
                        // In this case, use whichever instance is recorded in the context.
-                       named = ctxt.update(h, named)
+                       named = ctxt.update(h, orig, targs, named).(*Named)
                }
                return named
 
        case *Signature:
-               tparams := t.TypeParams()
+               tparams := orig.TypeParams()
                if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {
                        return Typ[Invalid]
                }
                if tparams.Len() == 0 {
-                       return typ // nothing to do (minor optimization)
+                       return orig // nothing to do (minor optimization)
                }
-               sig := check.subst(pos, typ, makeSubstMap(tparams.list(), targs), ctxt).(*Signature)
+               sig := check.subst(pos, orig, makeSubstMap(tparams.list(), targs), ctxt).(*Signature)
                // If the signature doesn't use its type parameters, subst
                // will not make a copy. In that case, make a copy now (so
                // we can set tparams to nil w/o causing side-effects).
-               if sig == t {
+               if sig == orig {
                        copy := *sig
                        sig = &copy
                }
@@ -99,7 +99,7 @@ func (check *Checker) instance(pos token.Pos, typ Type, targs []Type, ctxt *Cont
                return sig
        }
        // only types and functions can be generic
-       panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
+       panic(fmt.Sprintf("%v: cannot instantiate %v", pos, orig))
 }
 
 // validateTArgLen verifies that the length of targs and tparams matches,
index 12d87af084208aa48bd9aed17992c68c80c7b1b6..ed3c426a12383da865c6fe7c26d21be51d5e3fc7 100644 (file)
@@ -255,7 +255,7 @@ func expandNamed(ctxt *Context, n *Named, instPos token.Pos) (tparams *TypeParam
                ctxt = check.bestContext(ctxt)
                h := ctxt.typeHash(n.orig, n.targs.list())
                // ensure that an instance is recorded for h to avoid infinite recursion.
-               ctxt.update(h, n)
+               ctxt.update(h, n.orig, n.TypeArgs().list(), n)
 
                smap := makeSubstMap(n.orig.tparams.list(), n.targs.list())
                underlying = n.check.subst(instPos, n.orig.underlying, smap, ctxt)
index 17d07649efe89feea8645489d370dbbc87b5fd9e..048bc95e15352fd739f6ad29d7f3a076775c398c 100644 (file)
@@ -411,7 +411,7 @@ func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named
        // create the instance
        h := check.conf.Context.typeHash(orig, targs)
        // targs may be incomplete, and require inference. In any case we should de-duplicate.
-       inst := check.conf.Context.lookup(h, orig, targs)
+       inst, _ := check.conf.Context.lookup(h, orig, targs).(*Named)
        // If inst is non-nil, we can't just return here. Inst may have been
        // constructed via recursive substitution, in which case we wouldn't do the
        // validation below. Ensure that the validation (and resulting errors) runs
@@ -420,7 +420,7 @@ func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named
                tname := NewTypeName(x.Pos(), orig.obj.pkg, orig.obj.name, nil)
                inst = check.newNamed(tname, orig, nil, nil, nil) // underlying, methods and tparams are set when named is resolved
                inst.targs = NewTypeList(targs)
-               inst = check.conf.Context.update(h, inst)
+               inst = check.conf.Context.update(h, orig, targs, inst).(*Named)
        }
        def.setUnderlying(inst)