imports []*PkgName // list of imported packages
dotImportMap map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through
recvTParamMap map[*ast.Ident]*TypeParam // maps blank receiver type parameters to their type
+ unionTypeSets map[*Union]*_TypeSet // computed type sets for union types
mono monoGraph // graph for detecting non-monomorphizable instantiation loops
firstErr error // first error encountered
check.pkgPathMap = nil
check.seenPkgMap = nil
check.recvTParamMap = nil
+ check.unionTypeSets = nil
check.defTypes = nil
check.ctxt = nil
case *Union:
if y, _ := y.(*Union); y != nil {
- xset := computeUnionTypeSet(nil, token.NoPos, x)
- yset := computeUnionTypeSet(nil, token.NoPos, y)
+ // TODO(rfindley): can this be reached during type checking? If so,
+ // consider passing a type set map.
+ unionSets := make(map[*Union]*_TypeSet)
+ xset := computeUnionTypeSet(nil, unionSets, token.NoPos, x)
+ yset := computeUnionTypeSet(nil, unionSets, token.NoPos, y)
return xset.terms.equal(yset.terms)
}
// reason.
ityp.tset = &_TypeSet{terms: allTermlist} // TODO(gri) is this sufficient?
+ var unionSets map[*Union]*_TypeSet
+ if check != nil {
+ if check.unionTypeSets == nil {
+ check.unionTypeSets = make(map[*Union]*_TypeSet)
+ }
+ unionSets = check.unionTypeSets
+ } else {
+ unionSets = make(map[*Union]*_TypeSet)
+ }
+
// Methods of embedded interfaces are collected unchanged; i.e., the identity
// of a method I.m's Func Object of an interface I is the same as that of
// the method m in an interface that embeds interface I. On the other hand,
check.errorf(atPos(pos), _InvalidIfaceEmbed, "embedding interface element %s requires go1.18 or later", u)
continue
}
- tset := computeUnionTypeSet(check, pos, u)
+ tset := computeUnionTypeSet(check, unionSets, pos, u)
if tset == &invalidTypeSet {
continue // ignore invalid unions
}
// computeUnionTypeSet may be called with check == nil.
// The result is &invalidTypeSet if the union overflows.
-func computeUnionTypeSet(check *Checker, pos token.Pos, utyp *Union) *_TypeSet {
- if utyp.tset != nil {
- return utyp.tset
+func computeUnionTypeSet(check *Checker, unionSets map[*Union]*_TypeSet, pos token.Pos, utyp *Union) *_TypeSet {
+ if tset, _ := unionSets[utyp]; tset != nil {
+ return tset
}
// avoid infinite recursion (see also computeInterfaceTypeSet)
- utyp.tset = new(_TypeSet)
+ unionSets[utyp] = new(_TypeSet)
var allTerms termlist
for _, t := range utyp.terms {
if check != nil {
check.errorf(atPos(pos), _InvalidUnion, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
}
- utyp.tset = &invalidTypeSet
- return utyp.tset
+ unionSets[utyp] = &invalidTypeSet
+ return unionSets[utyp]
}
}
- utyp.tset.terms = allTerms
+ unionSets[utyp].terms = allTerms
- return utyp.tset
+ return unionSets[utyp]
}
// A Union represents a union of terms embedded in an interface.
type Union struct {
- terms []*Term // list of syntactical terms (not a canonicalized termlist)
- tset *_TypeSet // type set described by this union, computed lazily
+ terms []*Term // list of syntactical terms (not a canonicalized termlist)
}
// NewUnion returns a new Union type with the given terms.
if len(terms) == 0 {
panic("empty union")
}
- return &Union{terms, nil}
+ return &Union{terms}
}
func (u *Union) Len() int { return len(u.terms) }
}
})
- u := &Union{terms, nil}
+ u := &Union{terms}
check.recordTypeAndValue(uexpr, typexpr, u, nil)
return u
}