]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: factor out list substitution code (cleanup)
authorRobert Griesemer <gri@golang.org>
Thu, 23 May 2024 04:47:35 +0000 (21:47 -0700)
committerGopher Robot <gobot@golang.org>
Fri, 26 Jul 2024 20:05:46 +0000 (20:05 +0000)
- Replace the various subst.XList methods with a generic function.
- Rename comparable function to comparableType to avoid shadowing
  predeclared type comparable.
- Rename substFunc/Var to cloneFunc/Var which is more accurate.

Change-Id: I3243f2093e4c43a537766f47e3348402de517090
Reviewed-on: https://go-review.googlesource.com/c/go/+/587775
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
12 files changed:
src/cmd/compile/internal/types2/expr.go
src/cmd/compile/internal/types2/instantiate.go
src/cmd/compile/internal/types2/named.go
src/cmd/compile/internal/types2/predicates.go
src/cmd/compile/internal/types2/subst.go
src/cmd/compile/internal/types2/typeset.go
src/go/types/expr.go
src/go/types/instantiate.go
src/go/types/named.go
src/go/types/predicates.go
src/go/types/subst.go
src/go/types/typeset.go

index 92949a924dede172901d905f23fe77005b3de09b..b25cf89fb4efa88014fb501645ba33a2fd896224 100644 (file)
@@ -601,7 +601,7 @@ func (check *Checker) incomparableCause(typ Type) string {
        }
        // see if we can extract a more specific error
        var cause string
-       comparable(typ, true, nil, func(format string, args ...interface{}) {
+       comparableType(typ, true, nil, func(format string, args ...interface{}) {
                cause = check.sprintf(format, args...)
        })
        return cause
index 308d1f550ad4fabe3fe1079b3209e0dc88ad9f18..732d076ec3a4a8484b8dca230cd467f654e91ad4 100644 (file)
@@ -288,12 +288,12 @@ func (check *Checker) implements(pos syntax.Pos, V, T Type, constraint bool, cau
                }
                // If T is comparable, V must be comparable.
                // If V is strictly comparable, we're done.
-               if comparable(V, false /* strict comparability */, nil, nil) {
+               if comparableType(V, false /* strict comparability */, nil, nil) {
                        return true
                }
                // For constraint satisfaction, use dynamic (spec) comparability
                // so that ordinary, non-type parameter interfaces implement comparable.
-               if constraint && comparable(V, true /* spec comparability */, nil, nil) {
+               if constraint && comparableType(V, true /* spec comparability */, nil, nil) {
                        // V is comparable if we are at Go 1.20 or higher.
                        if check == nil || check.allowVersion(atPos(pos), go1_20) { // atPos needed so that go/types generate passes
                                return true
index 1859b27aa4edfbe156245e1e6e3a73ecd15cdaa3..241371b72fea4d19cb608b9c5ec6fb74361a1320 100644 (file)
@@ -430,8 +430,8 @@ func (t *Named) expandMethod(i int) *Func {
                rtyp = t
        }
 
-       sig.recv = substVar(origSig.recv, rtyp)
-       return substFunc(origm, sig)
+       sig.recv = cloneVar(origSig.recv, rtyp)
+       return cloneFunc(origm, sig)
 }
 
 // SetUnderlying sets the underlying type and marks t as complete.
index 6403be6bcb571939131fa6d5f8cb19c209eb150a..155a70fb1912846fb8cc41895ac74e13b96f4c8e 100644 (file)
@@ -146,12 +146,12 @@ func isGeneric(t Type) bool {
 
 // Comparable reports whether values of type T are comparable.
 func Comparable(T Type) bool {
-       return comparable(T, true, nil, nil)
+       return comparableType(T, true, nil, nil)
 }
 
 // If dynamic is set, non-type parameter interfaces are always comparable.
 // If reportf != nil, it may be used to report why T is not comparable.
-func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool {
+func comparableType(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool {
        if seen[T] {
                return true
        }
@@ -169,7 +169,7 @@ func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, .
                return true
        case *Struct:
                for _, f := range t.fields {
-                       if !comparable(f.typ, dynamic, seen, nil) {
+                       if !comparableType(f.typ, dynamic, seen, nil) {
                                if reportf != nil {
                                        reportf("struct containing %s cannot be compared", f.typ)
                                }
@@ -178,7 +178,7 @@ func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, .
                }
                return true
        case *Array:
-               if !comparable(t.elem, dynamic, seen, nil) {
+               if !comparableType(t.elem, dynamic, seen, nil) {
                        if reportf != nil {
                                reportf("%s cannot be compared", t)
                        }
index 7c4cd732501e43a5553f626d910a89950a58e74b..70fb232aa1feacfa95f98051d21c9c2647397699 100644 (file)
@@ -113,8 +113,7 @@ func (subst *subster) typ(typ Type) Type {
                // For each (existing) type argument determine if it needs
                // to be substituted; i.e., if it is or contains a type parameter
                // that has a type argument for it.
-               targs, updated := subst.typeList(t.TypeArgs().list())
-               if updated {
+               if targs := substList(t.TypeArgs().list(), subst.typ); targs != nil {
                        return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.expanding, subst.ctxt)
                }
 
@@ -131,7 +130,7 @@ func (subst *subster) typ(typ Type) Type {
                }
 
        case *Struct:
-               if fields, copied := subst.varList(t.fields); copied {
+               if fields := substList(t.fields, subst.var_); fields != nil {
                        s := &Struct{fields: fields, tags: t.tags}
                        s.markComplete()
                        return s
@@ -178,8 +177,7 @@ func (subst *subster) typ(typ Type) Type {
                }
 
        case *Union:
-               terms, copied := subst.termlist(t.terms)
-               if copied {
+               if terms := substList(t.terms, subst.term); terms != nil {
                        // 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.
@@ -187,9 +185,15 @@ func (subst *subster) typ(typ Type) Type {
                }
 
        case *Interface:
-               methods, mcopied := subst.funcList(t.methods)
-               embeddeds, ecopied := subst.typeList(t.embeddeds)
-               if mcopied || ecopied {
+               methods := substList(t.methods, subst.func_)
+               embeddeds := substList(t.embeddeds, subst.typ)
+               if methods != nil || embeddeds != nil {
+                       if methods == nil {
+                               methods = t.methods
+                       }
+                       if embeddeds == nil {
+                               embeddeds = t.embeddeds
+                       }
                        iface := subst.check.newInterface()
                        iface.embeddeds = embeddeds
                        iface.embedPos = t.embedPos
@@ -251,8 +255,7 @@ func (subst *subster) typ(typ Type) Type {
                // For each (existing) type argument determine if it needs
                // to be substituted; i.e., if it is or contains a type parameter
                // that has a type argument for it.
-               targs, updated := subst.typeList(t.TypeArgs().list())
-               if updated {
+               if targs := substList(t.TypeArgs().list(), subst.typ); targs != nil {
                        // Create a new instance and populate the context to avoid endless
                        // recursion. The position used here is irrelevant because validation only
                        // occurs on t (we don't call validType on named), but we use subst.pos to
@@ -283,13 +286,13 @@ func (subst *subster) typOrNil(typ Type) Type {
 func (subst *subster) var_(v *Var) *Var {
        if v != nil {
                if typ := subst.typ(v.typ); typ != v.typ {
-                       return substVar(v, typ)
+                       return cloneVar(v, typ)
                }
        }
        return v
 }
 
-func substVar(v *Var, typ Type) *Var {
+func cloneVar(v *Var, typ Type) *Var {
        copy := *v
        copy.typ = typ
        copy.origin = v.Origin()
@@ -298,26 +301,26 @@ func substVar(v *Var, typ Type) *Var {
 
 func (subst *subster) tuple(t *Tuple) *Tuple {
        if t != nil {
-               if vars, copied := subst.varList(t.vars); copied {
+               if vars := substList(t.vars, subst.var_); vars != nil {
                        return &Tuple{vars: vars}
                }
        }
        return t
 }
 
-func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
-       out = in
-       for i, v := range in {
-               if w := subst.var_(v); w != v {
-                       if !copied {
-                               // first variable that got substituted => allocate new out slice
-                               // and copy all variables
-                               new := make([]*Var, len(in))
-                               copy(new, out)
-                               out = new
-                               copied = true
+// substList applies subst to each element of the incoming slice.
+// If at least one element changes, the result is a new slice with
+// all the (possibly updated) elements of the incoming slice;
+// otherwise the result it nil. The incoming slice is unchanged.
+func substList[T comparable](in []T, subst func(T) T) (out []T) {
+       for i, t := range in {
+               if u := subst(t); u != t {
+                       if out == nil {
+                               // lazily allocate a new slice on first substitution
+                               out = make([]T, len(in))
+                               copy(out, in)
                        }
-                       out[i] = w
+                       out[i] = u
                }
        }
        return
@@ -326,71 +329,24 @@ func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
 func (subst *subster) func_(f *Func) *Func {
        if f != nil {
                if typ := subst.typ(f.typ); typ != f.typ {
-                       return substFunc(f, typ)
+                       return cloneFunc(f, typ)
                }
        }
        return f
 }
 
-func substFunc(f *Func, typ Type) *Func {
+func cloneFunc(f *Func, typ Type) *Func {
        copy := *f
        copy.typ = typ
        copy.origin = f.Origin()
        return &copy
 }
 
-func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
-       out = in
-       for i, f := range in {
-               if g := subst.func_(f); g != f {
-                       if !copied {
-                               // first function that got substituted => allocate new out slice
-                               // and copy all functions
-                               new := make([]*Func, len(in))
-                               copy(new, out)
-                               out = new
-                               copied = true
-                       }
-                       out[i] = g
-               }
-       }
-       return
-}
-
-func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
-       out = in
-       for i, t := range in {
-               if u := subst.typ(t); u != t {
-                       if !copied {
-                               // first function that got substituted => allocate new out slice
-                               // and copy all functions
-                               new := make([]Type, len(in))
-                               copy(new, out)
-                               out = new
-                               copied = true
-                       }
-                       out[i] = u
-               }
-       }
-       return
-}
-
-func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) {
-       out = in
-       for i, t := range in {
-               if u := subst.typ(t.typ); u != t.typ {
-                       if !copied {
-                               // first function that got substituted => allocate new out slice
-                               // and copy all functions
-                               new := make([]*Term, len(in))
-                               copy(new, out)
-                               out = new
-                               copied = true
-                       }
-                       out[i] = NewTerm(t.tilde, u)
-               }
+func (subst *subster) term(t *Term) *Term {
+       if typ := subst.typ(t.typ); typ != t.typ {
+               return NewTerm(t.tilde, typ)
        }
-       return
+       return t
 }
 
 // replaceRecvType updates any function receivers that have type old to have
@@ -413,8 +369,8 @@ func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) {
                                copied = true
                        }
                        newsig := *sig
-                       newsig.recv = substVar(sig.recv, new)
-                       out[i] = substFunc(method, &newsig)
+                       newsig.recv = cloneVar(sig.recv, new)
+                       out[i] = cloneFunc(method, &newsig)
                }
        }
        return
index 0457502e393942f313465603d408ef28da126650..9ea0a3e8f9ea28c5f95f9a4d86456328f3ea995b 100644 (file)
@@ -44,7 +44,7 @@ func (s *_TypeSet) IsComparable(seen map[Type]bool) bool {
                return s.comparable
        }
        return s.is(func(t *term) bool {
-               return t != nil && comparable(t.typ, false, seen, nil)
+               return t != nil && comparableType(t.typ, false, seen, nil)
        })
 }
 
@@ -332,7 +332,7 @@ func intersectTermLists(xterms termlist, xcomp bool, yterms termlist, ycomp bool
                i := 0
                for _, t := range terms {
                        assert(t.typ != nil)
-                       if comparable(t.typ, false /* strictly comparable */, nil, nil) {
+                       if comparableType(t.typ, false /* strictly comparable */, nil, nil) {
                                terms[i] = t
                                i++
                        }
index cf8ceddc9ace1590a47c600a10c9faac35cd93b3..ac125c666b6c51d49d0167e1962a4b05bb775f1a 100644 (file)
@@ -579,7 +579,7 @@ func (check *Checker) incomparableCause(typ Type) string {
        }
        // see if we can extract a more specific error
        var cause string
-       comparable(typ, true, nil, func(format string, args ...interface{}) {
+       comparableType(typ, true, nil, func(format string, args ...interface{}) {
                cause = check.sprintf(format, args...)
        })
        return cause
index 0435f2bf261647f38c4b4e6c8270f22d7a346ee5..cef495314e735d8f553cf5f238ba26074ef460ce 100644 (file)
@@ -291,12 +291,12 @@ func (check *Checker) implements(pos token.Pos, V, T Type, constraint bool, caus
                }
                // If T is comparable, V must be comparable.
                // If V is strictly comparable, we're done.
-               if comparable(V, false /* strict comparability */, nil, nil) {
+               if comparableType(V, false /* strict comparability */, nil, nil) {
                        return true
                }
                // For constraint satisfaction, use dynamic (spec) comparability
                // so that ordinary, non-type parameter interfaces implement comparable.
-               if constraint && comparable(V, true /* spec comparability */, nil, nil) {
+               if constraint && comparableType(V, true /* spec comparability */, nil, nil) {
                        // V is comparable if we are at Go 1.20 or higher.
                        if check == nil || check.allowVersion(atPos(pos), go1_20) { // atPos needed so that go/types generate passes
                                return true
index b44fa9d788c34587fc30c5a1b7febd6e2b8dbabe..316cdc9bba41ff3ddd26dbcbf86319379ad89676 100644 (file)
@@ -433,8 +433,8 @@ func (t *Named) expandMethod(i int) *Func {
                rtyp = t
        }
 
-       sig.recv = substVar(origSig.recv, rtyp)
-       return substFunc(origm, sig)
+       sig.recv = cloneVar(origSig.recv, rtyp)
+       return cloneFunc(origm, sig)
 }
 
 // SetUnderlying sets the underlying type and marks t as complete.
index ba7901b3c31b17d77555ae89006c24fe0af4649e..4bfbdccc6f3b46ccc20b5e545531cc20f121f612 100644 (file)
@@ -149,12 +149,12 @@ func isGeneric(t Type) bool {
 
 // Comparable reports whether values of type T are comparable.
 func Comparable(T Type) bool {
-       return comparable(T, true, nil, nil)
+       return comparableType(T, true, nil, nil)
 }
 
 // If dynamic is set, non-type parameter interfaces are always comparable.
 // If reportf != nil, it may be used to report why T is not comparable.
-func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool {
+func comparableType(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool {
        if seen[T] {
                return true
        }
@@ -172,7 +172,7 @@ func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, .
                return true
        case *Struct:
                for _, f := range t.fields {
-                       if !comparable(f.typ, dynamic, seen, nil) {
+                       if !comparableType(f.typ, dynamic, seen, nil) {
                                if reportf != nil {
                                        reportf("struct containing %s cannot be compared", f.typ)
                                }
@@ -181,7 +181,7 @@ func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, .
                }
                return true
        case *Array:
-               if !comparable(t.elem, dynamic, seen, nil) {
+               if !comparableType(t.elem, dynamic, seen, nil) {
                        if reportf != nil {
                                reportf("%s cannot be compared", t)
                        }
index 6be106d3aa99d6ae78a68569239f36c7ac03eef6..838ce073f942ce0f8aa3f61076821f3e40329fb3 100644 (file)
@@ -116,8 +116,7 @@ func (subst *subster) typ(typ Type) Type {
                // For each (existing) type argument determine if it needs
                // to be substituted; i.e., if it is or contains a type parameter
                // that has a type argument for it.
-               targs, updated := subst.typeList(t.TypeArgs().list())
-               if updated {
+               if targs := substList(t.TypeArgs().list(), subst.typ); targs != nil {
                        return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.expanding, subst.ctxt)
                }
 
@@ -134,7 +133,7 @@ func (subst *subster) typ(typ Type) Type {
                }
 
        case *Struct:
-               if fields, copied := subst.varList(t.fields); copied {
+               if fields := substList(t.fields, subst.var_); fields != nil {
                        s := &Struct{fields: fields, tags: t.tags}
                        s.markComplete()
                        return s
@@ -181,8 +180,7 @@ func (subst *subster) typ(typ Type) Type {
                }
 
        case *Union:
-               terms, copied := subst.termlist(t.terms)
-               if copied {
+               if terms := substList(t.terms, subst.term); terms != nil {
                        // 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.
@@ -190,9 +188,15 @@ func (subst *subster) typ(typ Type) Type {
                }
 
        case *Interface:
-               methods, mcopied := subst.funcList(t.methods)
-               embeddeds, ecopied := subst.typeList(t.embeddeds)
-               if mcopied || ecopied {
+               methods := substList(t.methods, subst.func_)
+               embeddeds := substList(t.embeddeds, subst.typ)
+               if methods != nil || embeddeds != nil {
+                       if methods == nil {
+                               methods = t.methods
+                       }
+                       if embeddeds == nil {
+                               embeddeds = t.embeddeds
+                       }
                        iface := subst.check.newInterface()
                        iface.embeddeds = embeddeds
                        iface.embedPos = t.embedPos
@@ -254,8 +258,7 @@ func (subst *subster) typ(typ Type) Type {
                // For each (existing) type argument determine if it needs
                // to be substituted; i.e., if it is or contains a type parameter
                // that has a type argument for it.
-               targs, updated := subst.typeList(t.TypeArgs().list())
-               if updated {
+               if targs := substList(t.TypeArgs().list(), subst.typ); targs != nil {
                        // Create a new instance and populate the context to avoid endless
                        // recursion. The position used here is irrelevant because validation only
                        // occurs on t (we don't call validType on named), but we use subst.pos to
@@ -286,13 +289,13 @@ func (subst *subster) typOrNil(typ Type) Type {
 func (subst *subster) var_(v *Var) *Var {
        if v != nil {
                if typ := subst.typ(v.typ); typ != v.typ {
-                       return substVar(v, typ)
+                       return cloneVar(v, typ)
                }
        }
        return v
 }
 
-func substVar(v *Var, typ Type) *Var {
+func cloneVar(v *Var, typ Type) *Var {
        copy := *v
        copy.typ = typ
        copy.origin = v.Origin()
@@ -301,26 +304,26 @@ func substVar(v *Var, typ Type) *Var {
 
 func (subst *subster) tuple(t *Tuple) *Tuple {
        if t != nil {
-               if vars, copied := subst.varList(t.vars); copied {
+               if vars := substList(t.vars, subst.var_); vars != nil {
                        return &Tuple{vars: vars}
                }
        }
        return t
 }
 
-func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
-       out = in
-       for i, v := range in {
-               if w := subst.var_(v); w != v {
-                       if !copied {
-                               // first variable that got substituted => allocate new out slice
-                               // and copy all variables
-                               new := make([]*Var, len(in))
-                               copy(new, out)
-                               out = new
-                               copied = true
+// substList applies subst to each element of the incoming slice.
+// If at least one element changes, the result is a new slice with
+// all the (possibly updated) elements of the incoming slice;
+// otherwise the result it nil. The incoming slice is unchanged.
+func substList[T comparable](in []T, subst func(T) T) (out []T) {
+       for i, t := range in {
+               if u := subst(t); u != t {
+                       if out == nil {
+                               // lazily allocate a new slice on first substitution
+                               out = make([]T, len(in))
+                               copy(out, in)
                        }
-                       out[i] = w
+                       out[i] = u
                }
        }
        return
@@ -329,71 +332,24 @@ func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
 func (subst *subster) func_(f *Func) *Func {
        if f != nil {
                if typ := subst.typ(f.typ); typ != f.typ {
-                       return substFunc(f, typ)
+                       return cloneFunc(f, typ)
                }
        }
        return f
 }
 
-func substFunc(f *Func, typ Type) *Func {
+func cloneFunc(f *Func, typ Type) *Func {
        copy := *f
        copy.typ = typ
        copy.origin = f.Origin()
        return &copy
 }
 
-func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
-       out = in
-       for i, f := range in {
-               if g := subst.func_(f); g != f {
-                       if !copied {
-                               // first function that got substituted => allocate new out slice
-                               // and copy all functions
-                               new := make([]*Func, len(in))
-                               copy(new, out)
-                               out = new
-                               copied = true
-                       }
-                       out[i] = g
-               }
-       }
-       return
-}
-
-func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
-       out = in
-       for i, t := range in {
-               if u := subst.typ(t); u != t {
-                       if !copied {
-                               // first function that got substituted => allocate new out slice
-                               // and copy all functions
-                               new := make([]Type, len(in))
-                               copy(new, out)
-                               out = new
-                               copied = true
-                       }
-                       out[i] = u
-               }
-       }
-       return
-}
-
-func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) {
-       out = in
-       for i, t := range in {
-               if u := subst.typ(t.typ); u != t.typ {
-                       if !copied {
-                               // first function that got substituted => allocate new out slice
-                               // and copy all functions
-                               new := make([]*Term, len(in))
-                               copy(new, out)
-                               out = new
-                               copied = true
-                       }
-                       out[i] = NewTerm(t.tilde, u)
-               }
+func (subst *subster) term(t *Term) *Term {
+       if typ := subst.typ(t.typ); typ != t.typ {
+               return NewTerm(t.tilde, typ)
        }
-       return
+       return t
 }
 
 // replaceRecvType updates any function receivers that have type old to have
@@ -416,8 +372,8 @@ func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) {
                                copied = true
                        }
                        newsig := *sig
-                       newsig.recv = substVar(sig.recv, new)
-                       out[i] = substFunc(method, &newsig)
+                       newsig.recv = cloneVar(sig.recv, new)
+                       out[i] = cloneFunc(method, &newsig)
                }
        }
        return
index d280bf2f5ff5cf5ac7d8b18cf8f9980da8dfc82e..28f0a45468477061bed9b166fca55e783304fccb 100644 (file)
@@ -47,7 +47,7 @@ func (s *_TypeSet) IsComparable(seen map[Type]bool) bool {
                return s.comparable
        }
        return s.is(func(t *term) bool {
-               return t != nil && comparable(t.typ, false, seen, nil)
+               return t != nil && comparableType(t.typ, false, seen, nil)
        })
 }
 
@@ -335,7 +335,7 @@ func intersectTermLists(xterms termlist, xcomp bool, yterms termlist, ycomp bool
                i := 0
                for _, t := range terms {
                        assert(t.typ != nil)
-                       if comparable(t.typ, false /* strictly comparable */, nil, nil) {
+                       if comparableType(t.typ, false /* strictly comparable */, nil, nil) {
                                terms[i] = t
                                i++
                        }