Skip to content

Commit

Permalink
cmd/compile/internal/types2: implement types2.Instantiate
Browse files Browse the repository at this point in the history
Instantiation support for imports. This is experimental
but it also doesn't affect Go 1.17 as this code is not
executed unless we enable generics (in the parser).

Change-Id: If2da09ac3a557ec6a180707a53f75f3ce354f3e9
Reviewed-on: https://go-review.googlesource.com/c/go/+/314773
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: Dan Scales <danscales@google.com>
  • Loading branch information
griesemer committed May 5, 2021
1 parent caf4c94 commit 9e0facd
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 11 deletions.
63 changes: 63 additions & 0 deletions src/cmd/compile/internal/types2/instantiate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2021 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 types2

import (
"cmd/compile/internal/syntax"
"fmt"
)

// Instantiate instantiates the type typ with the given type arguments.
// typ must be a *Named or a *Signature type, it must be generic, and
// its number of type parameters must match the number of provided type
// arguments. The result is a new, instantiated (not generic) type of
// the same kind (either a *Named or a *Signature). The type arguments
// are not checked against the constraints of the type parameters.
// Any methods attached to a *Named are simply copied; they are not
// instantiated.
func Instantiate(pos syntax.Pos, typ Type, targs []Type) (res Type) {
// TODO(gri) This code is basically identical to the prolog
// in Checker.instantiate. Factor.
var tparams []*TypeName
switch t := typ.(type) {
case *Named:
tparams = t.tparams
case *Signature:
tparams = t.tparams
defer func() {
// If we had an unexpected failure somewhere don't panic below when
// asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
// is returned.
if _, ok := res.(*Signature); !ok {
return
}
// 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 t == res {
copy := *t
res = &copy
}
// After instantiating a generic signature, it is not generic
// anymore; we need to set tparams to nil.
res.(*Signature).tparams = nil
}()

default:
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
}

// the number of supplied types must match the number of type parameters
if len(targs) != len(tparams) {
panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams)))
}

if len(tparams) == 0 {
return typ // nothing to do (minor optimization)
}

smap := makeSubstMap(tparams, targs)
return (*Checker)(nil).subst(pos, typ, smap)
}
31 changes: 20 additions & 11 deletions src/cmd/compile/internal/types2/subst.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,9 @@ func (subst *subster) typ(typ Type) Type {
embeddeds, ecopied := subst.typeList(t.embeddeds)
if mcopied || types != t.types || ecopied {
iface := &Interface{methods: methods, types: types, embeddeds: embeddeds}
if subst.check == nil {
panic("internal error: cannot instantiate interfaces yet")
}
subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement
subst.check.completeInterface(nopos, iface)
return iface
Expand All @@ -327,12 +330,14 @@ func (subst *subster) typ(typ Type) Type {
}

case *Named:
subst.check.indent++
defer func() {
subst.check.indent--
}()
dump := func(format string, args ...interface{}) {
if subst.check.conf.Trace {
// dump is for debugging
dump := func(string, ...interface{}) {}
if subst.check != nil && subst.check.conf.Trace {
subst.check.indent++
defer func() {
subst.check.indent--
}()
dump = func(format string, args ...interface{}) {
subst.check.trace(subst.pos, format, args...)
}
}
Expand Down Expand Up @@ -377,17 +382,21 @@ func (subst *subster) typ(typ Type) Type {
// before creating a new named type, check if we have this one already
h := instantiatedHash(t, new_targs)
dump(">>> new type hash: %s", h)
if named, found := subst.check.typMap[h]; found {
dump(">>> found %s", named)
subst.cache[t] = named
return named
if subst.check != nil {
if named, found := subst.check.typMap[h]; found {
dump(">>> found %s", named)
subst.cache[t] = named
return named
}
}

// create a new named type and populate caches to avoid endless recursion
tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
named := subst.check.newNamed(tname, t, t.underlying, t.tparams, t.methods) // method signatures are updated lazily
named.targs = new_targs
subst.check.typMap[h] = named
if subst.check != nil {
subst.check.typMap[h] = named
}
subst.cache[t] = named

// do the substitution
Expand Down

0 comments on commit 9e0facd

Please sign in to comment.