]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: externalize union type sets
authorRobert Griesemer <gri@golang.org>
Wed, 15 Dec 2021 19:24:56 +0000 (11:24 -0800)
committerRobert Griesemer <gri@golang.org>
Wed, 15 Dec 2021 20:26:10 +0000 (20:26 +0000)
This is a port of CL 371756 from go/types to types2 with
minor adjustments due to different error handling or AST.

Updates #50093

Change-Id: Iab6a4634f8fc917bf99df439d31098624085f52a
Reviewed-on: https://go-review.googlesource.com/c/go/+/372474
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/check.go
src/cmd/compile/internal/types2/predicates.go
src/cmd/compile/internal/types2/sizeof_test.go
src/cmd/compile/internal/types2/subst.go
src/cmd/compile/internal/types2/typeset.go
src/cmd/compile/internal/types2/union.go

index aacbb25b3b4f4dc981edf4813acc5168ec1232ca..22a921d0d78d45db48f2b3d0f0bc75f67ad897ac 100644 (file)
@@ -129,6 +129,7 @@ type Checker struct {
        imports       []*PkgName                  // list of imported packages
        dotImportMap  map[dotImportKey]*PkgName   // maps dot-imported objects to the package they were dot-imported through
        recvTParamMap map[*syntax.Name]*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
@@ -330,6 +331,7 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
        check.pkgPathMap = nil
        check.seenPkgMap = nil
        check.recvTParamMap = nil
+       check.unionTypeSets = nil
        check.defTypes = nil
        check.ctxt = nil
 
index cf2993f68b08b15e0258a8ff367a85a312b85a51..d982866f8ed8e7f7ff0bb75aaf749749e04c7fc1 100644 (file)
@@ -287,8 +287,11 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
 
        case *Union:
                if y, _ := y.(*Union); y != nil {
-                       xset := computeUnionTypeSet(nil, nopos, x)
-                       yset := computeUnionTypeSet(nil, 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, nopos, x)
+                       yset := computeUnionTypeSet(nil, unionSets, nopos, y)
                        return xset.terms.equal(yset.terms)
                }
 
index 99b846b80b91c1f355777331ca012ce54ee7f405..8db2d60e8053947dfef387dc98caba0663cce707 100644 (file)
@@ -27,7 +27,7 @@ func TestSizeof(t *testing.T) {
                {Pointer{}, 8, 16},
                {Tuple{}, 12, 24},
                {Signature{}, 28, 56},
-               {Union{}, 16, 32},
+               {Union{}, 12, 24},
                {Interface{}, 44, 88},
                {Map{}, 16, 32},
                {Chan{}, 12, 24},
index 516f2481279597af6dd9137b169097b21f7ce603..4108f6aa8542a9ea08a6de53e444a34b16c73b33 100644 (file)
@@ -130,7 +130,7 @@ func (subst *subster) typ(typ Type) Type {
                        // term list substitution may introduce duplicate terms (unlikely but possible).
                        // This is ok; lazy type set computation will determine the actual type set
                        // in normal form.
-                       return &Union{terms, nil}
+                       return &Union{terms}
                }
 
        case *Interface:
index cbb454aa6aa6c2472c1020fcd28e50d76e74f008..0d8d02662bf623086f31abe5315f0b42379b50d1 100644 (file)
@@ -199,6 +199,16 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
        // 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,
@@ -290,7 +300,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
                                check.versionErrorf(pos, "go1.18", "embedding interface element %s", u)
                                continue
                        }
-                       tset := computeUnionTypeSet(check, pos, u)
+                       tset := computeUnionTypeSet(check, unionSets, pos, u)
                        if tset == &invalidTypeSet {
                                continue // ignore invalid unions
                        }
@@ -358,13 +368,13 @@ var invalidTypeSet _TypeSet
 
 // computeUnionTypeSet may be called with check == nil.
 // The result is &invalidTypeSet if the union overflows.
-func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *_TypeSet {
-       if utyp.tset != nil {
-               return utyp.tset
+func computeUnionTypeSet(check *Checker, unionSets map[*Union]*_TypeSet, pos syntax.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 {
@@ -391,11 +401,11 @@ func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *_TypeSet
                        if check != nil {
                                check.errorf(pos, "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]
 }
index 97581fe863083ef21449b08db081bd6ac1eb3705..98dd6cedc7a22dc6eba35780cb0107d08e7e976d 100644 (file)
@@ -11,8 +11,7 @@ import "cmd/compile/internal/syntax"
 
 // 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.
@@ -21,7 +20,7 @@ func NewUnion(terms []*Term) *Union {
        if len(terms) == 0 {
                panic("empty union")
        }
-       return &Union{terms, nil}
+       return &Union{terms}
 }
 
 func (u *Union) Len() int         { return len(u.terms) }
@@ -107,7 +106,7 @@ func parseUnion(check *Checker, uexpr syntax.Expr) Type {
                }
        })
 
-       u := &Union{terms, nil}
+       u := &Union{terms}
        check.recordTypeAndValue(uexpr, typexpr, u, nil)
        return u
 }