]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: record all instances, not just inferred instances
authorRobert Griesemer <gri@golang.org>
Wed, 22 Sep 2021 16:55:10 +0000 (09:55 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 28 Sep 2021 16:36:22 +0000 (16:36 +0000)
This is a port of CL 349629 from go/types to types2, adjusted to
make it work for types2. It also includes the necessary compiler
changes, provided by mdempsky.

Change-Id: If8de174cee9c69df0d0642fcec1ee7622b7c3852
Reviewed-on: https://go-review.googlesource.com/c/go/+/351455
Trust: Robert Griesemer <gri@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Dan Scales <danscales@google.com>
src/cmd/compile/internal/noder/expr.go
src/cmd/compile/internal/noder/irgen.go
src/cmd/compile/internal/noder/object.go
src/cmd/compile/internal/noder/writer.go
src/cmd/compile/internal/types2/api.go
src/cmd/compile/internal/types2/api_test.go
src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/check.go
src/cmd/compile/internal/types2/typexpr.go

index 9852ad964c98f37eb309d07c3fbb99d3296598ce..3dd7737c9ff15e6a7824e1684fea7771c95c0bf6 100644 (file)
@@ -114,86 +114,27 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
 
        case *syntax.CallExpr:
                fun := g.expr(expr.Fun)
-
-               // The key for the Inferred map is the CallExpr (if inferring
-               // types required the function arguments) or the IndexExpr below
-               // (if types could be inferred without the function arguments).
-               if inferred, ok := g.info.Inferred[expr]; ok && inferred.TArgs.Len() > 0 {
-                       // This is the case where inferring types required the
-                       // types of the function arguments.
-                       targs := make([]ir.Node, inferred.TArgs.Len())
-                       for i := range targs {
-                               targs[i] = ir.TypeNode(g.typ(inferred.TArgs.At(i)))
-                       }
-                       if fun.Op() == ir.OFUNCINST {
-                               if len(fun.(*ir.InstExpr).Targs) < len(targs) {
-                                       // Replace explicit type args with the full list that
-                                       // includes the additional inferred type args.
-                                       // Substitute the type args for the type params in
-                                       // the generic function's type.
-                                       fun.(*ir.InstExpr).Targs = targs
-                                       newt := g.substType(fun.(*ir.InstExpr).X.Type(), fun.(*ir.InstExpr).X.Type().TParams(), targs)
-                                       typed(newt, fun)
-                               }
-                       } else {
-                               // Create a function instantiation here, given there
-                               // are only inferred type args (e.g. min(5,6), where
-                               // min is a generic function). Substitute the type
-                               // args for the type params in the generic function's
-                               // type.
-                               inst := ir.NewInstExpr(pos, ir.OFUNCINST, fun, targs)
-                               newt := g.substType(fun.Type(), fun.Type().TParams(), targs)
-                               typed(newt, inst)
-                               fun = inst
-                       }
-
-               }
                return Call(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots)
 
        case *syntax.IndexExpr:
-               var targs []ir.Node
-
-               if inferred, ok := g.info.Inferred[expr]; ok && inferred.TArgs.Len() > 0 {
-                       // This is the partial type inference case where the types
-                       // can be inferred from other type arguments without using
-                       // the types of the function arguments.
-                       targs = make([]ir.Node, inferred.TArgs.Len())
-                       for i := range targs {
-                               targs[i] = ir.TypeNode(g.typ(inferred.TArgs.At(i)))
-                       }
-               } else if _, ok := expr.Index.(*syntax.ListExpr); ok {
-                       targs = g.exprList(expr.Index)
-               } else {
-                       index := g.expr(expr.Index)
-                       if index.Op() != ir.OTYPE {
+               args := unpackListExpr(expr.Index)
+               if len(args) == 1 {
+                       tv, ok := g.info.Types[args[0]]
+                       assert(ok)
+                       if tv.IsValue() {
                                // This is just a normal index expression
-                               n := Index(pos, g.typ(typ), g.expr(expr.X), index)
+                               n := Index(pos, g.typ(typ), g.expr(expr.X), g.expr(args[0]))
                                if !g.delayTransform() {
                                        // transformIndex will modify n.Type() for OINDEXMAP.
                                        transformIndex(n)
                                }
                                return n
                        }
-                       // This is generic function instantiation with a single type
-                       targs = []ir.Node{index}
-               }
-               // This is a generic function instantiation (e.g. min[int]).
-               // Generic type instantiation is handled in the type
-               // section of expr() above (using g.typ).
-               x := g.expr(expr.X)
-               if x.Op() != ir.ONAME || x.Type().Kind() != types.TFUNC {
-                       panic("Incorrect argument for generic func instantiation")
                }
-               n := ir.NewInstExpr(pos, ir.OFUNCINST, x, targs)
-               newt := g.typ(typ)
-               // Substitute the type args for the type params in the uninstantiated
-               // function's type. If there aren't enough type args, then the rest
-               // will be inferred at the call node, so don't try the substitution yet.
-               if x.Type().TParams().NumFields() == len(targs) {
-                       newt = g.substType(g.typ(typ), x.Type().TParams(), targs)
-               }
-               typed(newt, n)
-               return n
+
+               // expr.Index is a list of type args, so we ignore it, since types2 has
+               // already provided this info with the Info.Instances map.
+               return g.expr(expr.X)
 
        case *syntax.SelectorExpr:
                // Qualified identifier.
index e01e753a1dacdffe84e64e82fcb362d63f34bb4d..c1a4f30f4ac4a4e618f93bc222d688013fb9ae36 100644 (file)
@@ -59,7 +59,7 @@ func checkFiles(noders []*noder) (posMap, *types2.Package, *types2.Info) {
                Selections: make(map[*syntax.SelectorExpr]*types2.Selection),
                Implicits:  make(map[syntax.Node]types2.Object),
                Scopes:     make(map[syntax.Node]*types2.Scope),
-               Inferred:   make(map[syntax.Expr]types2.Inferred),
+               Instances:  make(map[*syntax.Name]types2.Instance),
                // expand as needed
        }
 
index 40c0b9cf4222072d4b92e22bceb9a51b555ad932..37a995b5199cf70f127fd03feb92b9e27ef2973c 100644 (file)
@@ -22,9 +22,10 @@ func (g *irgen) def(name *syntax.Name) (*ir.Name, types2.Object) {
        return g.obj(obj), obj
 }
 
-// use returns the Name node associated with the use of name. The returned node
-// will have the correct type and be marked as typechecked.
-func (g *irgen) use(name *syntax.Name) *ir.Name {
+// use returns the Name or InstExpr node associated with the use of name,
+// possibly instantiated by type arguments. The returned node will have
+// the correct type and be marked as typechecked.
+func (g *irgen) use(name *syntax.Name) ir.Node {
        obj2, ok := g.info.Uses[name]
        if !ok {
                base.FatalfAt(g.pos(name), "unknown name %v", name)
@@ -36,6 +37,20 @@ func (g *irgen) use(name *syntax.Name) *ir.Name {
                obj.SetTypecheck(1)
                obj.SetType(obj.Defn.Type())
        }
+
+       if obj.Class == ir.PFUNC {
+               if inst, ok := g.info.Instances[name]; ok {
+                       // This is the case where inferring types required the
+                       // types of the function arguments.
+                       targs := make([]ir.Node, inst.TypeArgs.Len())
+                       for i := range targs {
+                               targs[i] = ir.TypeNode(g.typ(inst.TypeArgs.At(i)))
+                       }
+                       typ := g.substType(obj.Type(), obj.Type().TParams(), targs)
+                       return typed(typ, ir.NewInstExpr(g.pos(name), ir.OFUNCINST, obj, targs))
+               }
+       }
+
        return obj
 }
 
index 9edf5fc97aa6da3996fce44fa30273ef0270d5b6..47de9920339c2d36b256eff9dae15436ead6cc17 100644 (file)
@@ -337,7 +337,7 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
                w.typ(typ.Elem())
 
        case *types2.Signature:
-               assert(typ.TypeParams() == nil)
+               base.Assertf(typ.TypeParams() == nil, "unexpected type params: %v", typ)
                w.code(typeSignature)
                w.signature(typ)
 
@@ -1158,11 +1158,16 @@ func (w *writer) optLabel(label *syntax.Name) {
 func (w *writer) expr(expr syntax.Expr) {
        expr = unparen(expr) // skip parens; unneeded after typecheck
 
-       obj, targs := lookupObj(w.p.info, expr)
+       obj, inst := lookupObj(w.p.info, expr)
+       targs := inst.TypeArgs
 
        if tv, ok := w.p.info.Types[expr]; ok {
                // TODO(mdempsky): Be more judicious about which types are marked as "needed".
-               w.needType(tv.Type)
+               if inst.Type != nil {
+                       w.needType(inst.Type)
+               } else {
+                       w.needType(tv.Type)
+               }
 
                if tv.IsType() {
                        w.code(exprType)
@@ -1303,16 +1308,7 @@ func (w *writer) expr(expr syntax.Expr) {
                                }
                        }
 
-                       if inf, ok := w.p.info.Inferred[expr]; ok {
-                               obj, _ := lookupObj(w.p.info, expr.Fun)
-                               assert(obj != nil)
-
-                               // As if w.expr(expr.Fun), but using inf.TArgs instead.
-                               w.code(exprName)
-                               w.obj(obj, inf.TArgs)
-                       } else {
-                               w.expr(expr.Fun)
-                       }
+                       w.expr(expr.Fun)
                        w.bool(false) // not a method call (i.e., normal function call)
                }
 
@@ -1756,31 +1752,17 @@ func isGlobal(obj types2.Object) bool {
 }
 
 // lookupObj returns the object that expr refers to, if any. If expr
-// is an explicit instantiation of a generic object, then the type
-// arguments are returned as well.
-func lookupObj(info *types2.Info, expr syntax.Expr) (obj types2.Object, targs *types2.TypeList) {
+// is an explicit instantiation of a generic object, then the instance
+// object is returned as well.
+func lookupObj(info *types2.Info, expr syntax.Expr) (obj types2.Object, inst types2.Instance) {
        if index, ok := expr.(*syntax.IndexExpr); ok {
-               if inf, ok := info.Inferred[index]; ok {
-                       targs = inf.TArgs
-               } else {
-                       args := unpackListExpr(index.Index)
-
-                       if len(args) == 1 {
-                               tv, ok := info.Types[args[0]]
-                               assert(ok)
-                               if tv.IsValue() {
-                                       return // normal index expression
-                               }
-                       }
-
-                       list := make([]types2.Type, len(args))
-                       for i, arg := range args {
-                               tv, ok := info.Types[arg]
-                               assert(ok)
-                               assert(tv.IsType())
-                               list[i] = tv.Type
+               args := unpackListExpr(index.Index)
+               if len(args) == 1 {
+                       tv, ok := info.Types[args[0]]
+                       assert(ok)
+                       if tv.IsValue() {
+                               return // normal index expression
                        }
-                       targs = types2.NewTypeList(list)
                }
 
                expr = index.X
@@ -1795,7 +1777,8 @@ func lookupObj(info *types2.Info, expr syntax.Expr) (obj types2.Object, targs *t
        }
 
        if name, ok := expr.(*syntax.Name); ok {
-               obj, _ = info.Uses[name]
+               obj = info.Uses[name]
+               inst = info.Instances[name]
        }
        return
 }
index 6914e6c89f7ca28337b7b4c4bae1420a96cc1eba..b0e86357b70f1e790a43814364ea8e14b6fe28be 100644 (file)
@@ -214,11 +214,19 @@ type Info struct {
        // qualified identifiers are collected in the Uses map.
        Types map[syntax.Expr]TypeAndValue
 
-       // Inferred maps calls of parameterized functions that use
-       // type inference to the inferred type arguments and signature
-       // of the function called. The recorded "call" expression may be
-       // an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]).
-       Inferred map[syntax.Expr]Inferred
+       // Instances maps identifiers denoting parameterized types or functions to
+       // their type arguments and instantiated type.
+       //
+       // For example, Instances will map the identifier for 'T' in the type
+       // instantiation T[int, string] to the type arguments [int, string] and
+       // resulting instantiated *Named type. Given a parameterized function
+       // func F[A any](A), Instances will map the identifier for 'F' in the call
+       // expression F(int(1)) to the inferred type arguments [int], and resulting
+       // instantiated *Signature.
+       //
+       // Invariant: Instantiating Uses[id].Type() with Instances[id].TypeArgs
+       // results in an equivalent of Instances[id].Type.
+       Instances map[*syntax.Name]Instance
 
        // Defs maps identifiers to the objects they define (including
        // package names, dots "." of dot-imports, and blank "_" identifiers).
@@ -375,11 +383,13 @@ func (tv TypeAndValue) HasOk() bool {
        return tv.mode == commaok || tv.mode == mapindex
 }
 
-// Inferred reports the inferred type arguments and signature
-// for a parameterized function call that uses type inference.
-type Inferred struct {
-       TArgs *TypeList
-       Sig   *Signature
+// Instance reports the type arguments and instantiated type for type and
+// function instantiations. For type instantiations, Type will be of dynamic
+// type *Named. For function instantiations, Type will be of dynamic type
+// *Signature.
+type Instance struct {
+       TypeArgs *TypeList
+       Type     Type
 }
 
 // An Initializer describes a package-level variable, or a list of variables in case
index cd5a61332a780b9b609a373d5f985d6fa1bada63..ca81620a78ef938d8b0268554f3b34673d455e29 100644 (file)
@@ -382,12 +382,12 @@ func TestTypesInfo(t *testing.T) {
        }
 }
 
-func TestInferredInfo(t *testing.T) {
+func TestInstanceInfo(t *testing.T) {
        var tests = []struct {
                src   string
-               fun   string
+               name  string
                targs []string
-               sig   string
+               typ   string
        }{
                {genericPkg + `p0; func f[T any](T) {}; func _() { f(42) }`,
                        `f`,
@@ -417,33 +417,33 @@ func TestInferredInfo(t *testing.T) {
 
                // we don't know how to translate these but we can type-check them
                {genericPkg + `q0; type T struct{}; func (T) m[P any](P) {}; func _(x T) { x.m(42) }`,
-                       `x.m`,
+                       `m`,
                        []string{`int`},
                        `func(int)`,
                },
                {genericPkg + `q1; type T struct{}; func (T) m[P any](P) P { panic(0) }; func _(x T) { x.m(42) }`,
-                       `x.m`,
+                       `m`,
                        []string{`int`},
                        `func(int) int`,
                },
                {genericPkg + `q2; type T struct{}; func (T) m[P any](...P) P { panic(0) }; func _(x T) { x.m(42) }`,
-                       `x.m`,
+                       `m`,
                        []string{`int`},
                        `func(...int) int`,
                },
                {genericPkg + `q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C) {}; func _(x T) { x.m(1.2, new(string), []byte{}) }`,
-                       `x.m`,
+                       `m`,
                        []string{`float64`, `string`, `byte`},
                        `func(float64, *string, []byte)`,
                },
                {genericPkg + `q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B) {}; func _(x T) { x.m(1.2, new(byte)) }`,
-                       `x.m`,
+                       `m`,
                        []string{`float64`, `byte`},
                        `func(float64, *byte, ...[]byte)`,
                },
 
                {genericPkg + `r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q) {}; func _[P any](x T[P]) { x.m(42) }`,
-                       `x.m`,
+                       `m`,
                        []string{`int`},
                        `func(int)`,
                },
@@ -480,66 +480,130 @@ func TestInferredInfo(t *testing.T) {
                        []string{`string`, `*string`},
                        `func() string`,
                },
-               {genericPkg + `t2; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T { return nil }; func _() { _ = f[int] }`,
+               {genericPkg + `t2; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
                        `f`,
-                       []string{`int`, `chan<- int`},
-                       `func() []int`,
+                       []string{`string`, `*string`},
+                       `func() string`,
                },
                {genericPkg + `t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
                        `f`,
                        []string{`int`, `chan<- int`, `chan<- []*chan<- int`},
                        `func() []int`,
                },
+               {genericPkg + `t4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
+                       `f`,
+                       []string{`int`, `chan<- int`, `chan<- []*chan<- int`},
+                       `func() []int`,
+               },
+               {genericPkg + `i0; import lib "generic_lib"; func _() { lib.F(42) }`,
+                       `F`,
+                       []string{`int`},
+                       `func(int)`,
+               },
+               {genericPkg + `type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`,
+                       `T`,
+                       []string{`int`},
+                       `struct{x int}`,
+               },
+               {genericPkg + `type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`,
+                       `T`,
+                       []string{`int`},
+                       `struct{x int}`,
+               },
+               {genericPkg + `type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`,
+                       `T`,
+                       []string{`int`},
+                       `struct{x int}`,
+               },
+               {genericPkg + `type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`,
+                       `T`,
+                       []string{`[]int`, `int`},
+                       `struct{x []int; y int}`,
+               },
+               {genericPkg + `type4; import lib "generic_lib"; var _ lib.T[int]`,
+                       `T`,
+                       []string{`int`},
+                       `[]int`,
+               },
        }
 
        for _, test := range tests {
-               info := Info{Inferred: make(map[syntax.Expr]Inferred)}
-               name, err := mayTypecheck(t, "InferredInfo", test.src, &info)
-               if err != nil {
-                       t.Errorf("package %s: %v", name, err)
-                       continue
-               }
+               const lib = `package generic_lib
 
-               // look for inferred type arguments and signature
-               var targs *TypeList
-               var sig *Signature
-               for call, inf := range info.Inferred {
-                       var fun syntax.Expr
-                       switch x := call.(type) {
-                       case *syntax.CallExpr:
-                               fun = x.Fun
-                       case *syntax.IndexExpr:
-                               fun = x.X
-                       default:
-                               panic(fmt.Sprintf("unexpected call expression type %T", call))
+func F[P any](P) {}
+
+type T[P any] []P
+`
+
+               imports := make(testImporter)
+               conf := Config{Importer: imports}
+               instances := make(map[*syntax.Name]Instance)
+               uses := make(map[*syntax.Name]Object)
+               makePkg := func(src string) *Package {
+                       f, err := parseSrc("p.go", src)
+                       if err != nil {
+                               t.Fatal(err)
                        }
-                       if syntax.String(fun) == test.fun {
-                               targs = inf.TArgs
-                               sig = inf.Sig
+                       pkg, err := conf.Check("", []*syntax.File{f}, &Info{Instances: instances, Uses: uses})
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       imports[pkg.Name()] = pkg
+                       return pkg
+               }
+               makePkg(lib)
+               pkg := makePkg(test.src)
+
+               // look for instance information
+               var targs []Type
+               var typ Type
+               for ident, inst := range instances {
+                       if syntax.String(ident) == test.name {
+                               for i := 0; i < inst.TypeArgs.Len(); i++ {
+                                       targs = append(targs, inst.TypeArgs.At(i))
+                               }
+                               typ = inst.Type
+
+                               // Check that we can find the corresponding parameterized type.
+                               ptype := uses[ident].Type()
+                               lister, _ := ptype.(interface{ TypeParams() *TypeParamList })
+                               if lister == nil || lister.TypeParams().Len() == 0 {
+                                       t.Errorf("package %s: info.Types[%v] = %v, want parameterized type", pkg.Name(), ident, ptype)
+                                       continue
+                               }
+
+                               // Verify the invariant that re-instantiating the generic type with
+                               // TypeArgs results in an equivalent type.
+                               inst2, err := Instantiate(nil, ptype, targs, true)
+                               if err != nil {
+                                       t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err)
+                               }
+                               if !Identical(inst.Type, inst2) {
+                                       t.Errorf("%v and %v are not identical", inst.Type, inst2)
+                               }
                                break
                        }
                }
                if targs == nil {
-                       t.Errorf("package %s: no inferred information found for %s", name, test.fun)
+                       t.Errorf("package %s: no instance information found for %s", pkg.Name(), test.name)
                        continue
                }
 
                // check that type arguments are correct
-               if targs.Len() != len(test.targs) {
-                       t.Errorf("package %s: got %d type arguments; want %d", name, targs.Len(), len(test.targs))
+               if len(targs) != len(test.targs) {
+                       t.Errorf("package %s: got %d type arguments; want %d", pkg.Name(), len(targs), len(test.targs))
                        continue
                }
-               for i := 0; i < targs.Len(); i++ {
-                       targ := targs.At(i)
+               for i, targ := range targs {
                        if got := targ.String(); got != test.targs[i] {
-                               t.Errorf("package %s, %d. type argument: got %s; want %s", name, i, got, test.targs[i])
+                               t.Errorf("package %s, %d. type argument: got %s; want %s", pkg.Name(), i, got, test.targs[i])
                                continue
                        }
                }
 
-               // check that signature is correct
-               if got := sig.String(); got != test.sig {
-                       t.Errorf("package %s: got %s; want %s", name, got, test.sig)
+               // check that the types match
+               if got := typ.Underlying().String(); got != test.typ {
+                       t.Errorf("package %s: got %s; want %s", pkg.Name(), got, test.typ)
                }
        }
 }
index 99afecaf197eecde8490b5b407b5862207d4a560..5cf292ce8ad0cedadcf352663f9cbfc4096ee376 100644 (file)
@@ -38,8 +38,6 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
                return
        }
 
-       // if we don't have enough type arguments, try type inference
-       inferred := false
        if got < want {
                targs = check.infer(inst.Pos(), sig.TypeParams().list(), targs, nil, nil)
                if targs == nil {
@@ -49,7 +47,6 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
                        return
                }
                got = len(targs)
-               inferred = true
        }
        assert(got == want)
 
@@ -62,9 +59,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
        // instantiate function signature
        res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature)
        assert(res.TypeParams().Len() == 0) // signature is not generic anymore
-       if inferred {
-               check.recordInferred(inst, targs, res)
-       }
+       check.recordInstance(inst.X, targs, res)
        x.typ = res
        x.mode = value
        x.expr = inst
@@ -346,7 +341,7 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
                // compute result signature
                rsig = check.instantiate(call.Pos(), sig, targs, nil).(*Signature)
                assert(rsig.TypeParams().Len() == 0) // signature is not generic anymore
-               check.recordInferred(call, targs, rsig)
+               check.recordInstance(call.Fun, targs, rsig)
 
                // Optimization: Only if the parameter list was adjusted do we
                // need to compute it from the adjusted list; otherwise we can
index 24a05e6b370f5436c74dcb64f5b1acd967610a3a..e45598e0ef1af40d8a8895c2467ebc7fb757cb40 100644 (file)
@@ -415,12 +415,36 @@ func (check *Checker) recordCommaOkTypes(x syntax.Expr, a [2]Type) {
        }
 }
 
-func (check *Checker) recordInferred(call syntax.Expr, targs []Type, sig *Signature) {
-       assert(call != nil)
-       assert(sig != nil)
-       if m := check.Inferred; m != nil {
-               m[call] = Inferred{NewTypeList(targs), sig}
+// recordInstance records instantiation information into check.Info, if the
+// Instances map is non-nil. The given expr must be an ident, selector, or
+// index (list) expr with ident or selector operand.
+//
+// TODO(rfindley): the expr parameter is fragile. See if we can access the
+// instantiated identifier in some other way.
+func (check *Checker) recordInstance(expr syntax.Expr, targs []Type, typ Type) {
+       ident := instantiatedIdent(expr)
+       assert(ident != nil)
+       assert(typ != nil)
+       if m := check.Instances; m != nil {
+               m[ident] = Instance{NewTypeList(targs), typ}
+       }
+}
+
+func instantiatedIdent(expr syntax.Expr) *syntax.Name {
+       var selOrIdent syntax.Expr
+       switch e := expr.(type) {
+       case *syntax.IndexExpr:
+               selOrIdent = e.X
+       case *syntax.SelectorExpr, *syntax.Name:
+               selOrIdent = e
+       }
+       switch x := selOrIdent.(type) {
+       case *syntax.Name:
+               return x
+       case *syntax.SelectorExpr:
+               return x.Sel
        }
+       panic("instantiated ident not found")
 }
 
 func (check *Checker) recordDef(id *syntax.Name, obj Object) {
index 7f75a96bd837649a83ab121487d09997148ec0ed..3bfce2ebf25115849a13cd71c06fc0e55dc90c53 100644 (file)
@@ -408,6 +408,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def
 
        typ := check.instantiate(x.Pos(), base, targs, posList)
        def.setUnderlying(typ)
+       check.recordInstance(x, targs, typ)
 
        // make sure we check instantiation works at least once
        // and that the resulting type is valid