aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/types2/named.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/types2/named.go')
-rw-r--r--src/cmd/compile/internal/types2/named.go39
1 files changed, 32 insertions, 7 deletions
diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go
index adf3eb3822..b12e59b586 100644
--- a/src/cmd/compile/internal/types2/named.go
+++ b/src/cmd/compile/internal/types2/named.go
@@ -153,7 +153,7 @@ func (t *Named) AddMethod(m *Func) {
}
}
-func (t *Named) Underlying() Type { return t.load().underlying }
+func (t *Named) Underlying() Type { return t.load().expand(nil).underlying }
func (t *Named) String() string { return TypeString(t, nil) }
// ----------------------------------------------------------------------------
@@ -166,9 +166,9 @@ func (t *Named) String() string { return TypeString(t, nil) }
// is detected, the result is Typ[Invalid]. If a cycle is detected and
// n0.check != nil, the cycle is reported.
func (n0 *Named) under() Type {
- n0.expand()
+ n0.expand(nil)
- u := n0.Underlying()
+ u := n0.load().underlying
if u == Typ[Invalid] {
return u
@@ -206,7 +206,7 @@ func (n0 *Named) under() Type {
seen := map[*Named]int{n0: 0}
path := []Object{n0.obj}
for {
- u = n.Underlying()
+ u = n.load().underlying
if u == nil {
u = Typ[Invalid]
break
@@ -214,7 +214,7 @@ func (n0 *Named) under() Type {
var n1 *Named
switch u1 := u.(type) {
case *Named:
- u1.expand()
+ u1.expand(nil)
n1 = u1
}
if n1 == nil {
@@ -264,15 +264,40 @@ type instance struct {
// expand ensures that the underlying type of n is instantiated.
// The underlying type will be Typ[Invalid] if there was an error.
-func (n *Named) expand() {
+func (n *Named) expand(typMap map[string]*Named) *Named {
if n.instance != nil {
// n must be loaded before instantiation, in order to have accurate
// tparams. This is done implicitly by the call to n.TParams, but making it
// explicit is harmless: load is idempotent.
n.load()
- inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList)
+ if typMap == nil {
+ if n.check != nil {
+ typMap = n.check.typMap
+ } else {
+ // If we're instantiating lazily, we might be outside the scope of a
+ // type-checking pass. In that case we won't have a pre-existing
+ // typMap, but don't want to create a duplicate of the current instance
+ // in the process of expansion.
+ h := instantiatedHash(n.orig, n.targs)
+ typMap = map[string]*Named{h: n}
+ }
+ }
+
+ inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList, typMap)
n.underlying = inst
n.fromRHS = inst
n.instance = nil
}
+ return n
+}
+
+// safeUnderlying returns the underlying of typ without expanding instances, to
+// avoid infinite recursion.
+//
+// TODO(rfindley): eliminate this function or give it a better name.
+func safeUnderlying(typ Type) Type {
+ if t, _ := typ.(*Named); t != nil {
+ return t.load().underlying
+ }
+ return typ.Underlying()
}