]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: generalize instanceHash to accept any type, rename to typeHash
authorRobert Findley <rfindley@google.com>
Tue, 31 Aug 2021 22:12:15 +0000 (18:12 -0400)
committerRobert Findley <rfindley@google.com>
Wed, 1 Sep 2021 00:35:54 +0000 (00:35 +0000)
This is a port of CL 345791 to go/types.

Change-Id: I673c22ad8b668f07aae4117555b1c0efb273fb78
Reviewed-on: https://go-review.googlesource.com/c/go/+/346556
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>

src/go/types/instantiate.go
src/go/types/named.go
src/go/types/stmt.go
src/go/types/subst.go
src/go/types/typestring.go

index fe4904f63a74be9c19efb6a7acafb85b300cc212..e89f645c8fa39281ec72806e2299a1474a1d322d 100644 (file)
@@ -119,7 +119,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, posList
 func (check *Checker) instance(pos token.Pos, typ Type, targs []Type) Type {
        switch t := typ.(type) {
        case *Named:
-               h := instantiatedHash(t, targs)
+               h := typeHash(t, targs)
                if check != nil {
                        // typ may already have been instantiated with identical type arguments. In
                        // that case, re-use the existing instance.
index 4ee76eb8357c9fa6ae08d66e147e4102eb71f9ef..45409566581a0fe68058338b3625681c6215acf3 100644 (file)
@@ -258,7 +258,7 @@ func (n *Named) expand(typMap map[string]*Named) *Named {
                                        // 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.list())
+                                       h := typeHash(n.orig, n.targs.list())
                                        typMap = map[string]*Named{h: n}
                                }
                        }
index 5ba57041bd75413f4d4e5e40bc81ba1c2e5fa2d3..e74862afef067eba0a3871e08bcfb7a903a4fd41 100644 (file)
@@ -302,7 +302,7 @@ L:
                                // talk about "case" rather than "type" because of nil case
                                Ts := "nil"
                                if T != nil {
-                                       Ts = T.String()
+                                       Ts = TypeString(T, check.qualifier)
                                }
                                check.errorf(e, _DuplicateCase, "duplicate case %s in type switch", Ts)
                                check.error(other, _DuplicateCase, "\tprevious case") // secondary error, \t indented
@@ -317,6 +317,47 @@ L:
        return
 }
 
+// TODO(gri) Once we are certain that typeHash is correct in all situations, use this version of caseTypes instead.
+//           (Currently it may be possible that different types have identical names and import paths due to ImporterFrom.)
+//
+// func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[string]ast.Expr) (T Type) {
+//     var dummy operand
+// L:
+//     for _, e := range types {
+//             // The spec allows the value nil instead of a type.
+//             var hash string
+//             if check.isNil(e) {
+//                     check.expr(&dummy, e) // run e through expr so we get the usual Info recordings
+//                     T = nil
+//                     hash = "<nil>" // avoid collision with a type named nil
+//             } else {
+//                     T = check.varType(e)
+//                     if T == Typ[Invalid] {
+//                             continue L
+//                     }
+//                     hash = typeHash(T, nil)
+//             }
+//             // look for duplicate types
+//             if other := seen[hash]; other != nil {
+//                     // talk about "case" rather than "type" because of nil case
+//                     Ts := "nil"
+//                     if T != nil {
+//                             Ts = TypeString(T, check.qualifier)
+//                     }
+//                     var err error_
+//                     err.errorf(e, "duplicate case %s in type switch", Ts)
+//                     err.errorf(other, "previous case")
+//                     check.report(&err)
+//                     continue L
+//             }
+//             seen[hash] = e
+//             if T != nil {
+//                     check.typeAssertion(e.Pos(), x, xtyp, T)
+//             }
+//     }
+//     return
+// }
+
 // stmt typechecks statement s.
 func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
        // statements must end with the same top scope as they started with
index f1bdbc34bd116d75e66aae5ab826f07970cdd8a6..c811f8a4df2db3c1e7ea8c0caace651dcf100c81 100644 (file)
@@ -217,7 +217,7 @@ func (subst *subster) typ(typ Type) Type {
                }
 
                // before creating a new named type, check if we have this one already
-               h := instantiatedHash(t, newTArgs)
+               h := typeHash(t, newTArgs)
                dump(">>> new type hash: %s", h)
                if named, found := subst.typMap[h]; found {
                        dump(">>> found %s", named)
@@ -256,17 +256,29 @@ func (subst *subster) typ(typ Type) Type {
        return typ
 }
 
-var instanceHashing = 0
+var typeHashing = 0
 
-func instantiatedHash(typ *Named, targs []Type) string {
+// typeHash returns a string representation of typ, which can be used as an exact
+// type hash: types that are identical produce identical string representations.
+// If typ is a *Named type and targs is not empty, typ is printed as if it were
+// instantiated with targs.
+func typeHash(typ Type, targs []Type) string {
+       assert(typ != nil)
        var buf bytes.Buffer
 
-       assert(instanceHashing == 0)
-       instanceHashing++
+       assert(typeHashing == 0)
+       typeHashing++
        w := newTypeWriter(&buf, nil)
-       w.typeName(typ.obj)
-       w.typeList(targs)
-       instanceHashing--
+       if named, _ := typ.(*Named); named != nil && len(targs) > 0 {
+               // Don't use WriteType because we need to use the provided targs
+               // and not any targs that might already be with the *Named type.
+               w.typeName(named.obj)
+               w.typeList(targs)
+       } else {
+               assert(targs == nil)
+               w.typ(typ)
+       }
+       typeHashing--
 
        if debug {
                // there should be no instance markers in type hashes
index 46e749c84af06b73cb2621b7382e17e40b5f0186..384122704438210fa188332c7a746eb427d3b580 100644 (file)
@@ -208,7 +208,7 @@ func (w *typeWriter) typ(typ Type) {
                // types. Write them to aid debugging, but don't write
                // them when we need an instance hash: whether a type
                // is fully expanded or not doesn't matter for identity.
-               if instanceHashing == 0 && t.instPos != nil {
+               if typeHashing == 0 && t.instPos != nil {
                        w.byte(instanceMarker)
                }
                w.typeName(t.obj)
@@ -292,7 +292,7 @@ func (w *typeWriter) tParamList(list []*TypeParam) {
 
 func (w *typeWriter) typeName(obj *TypeName) {
        if obj == nil {
-               assert(instanceHashing == 0) // we need an object for instance hashing
+               assert(typeHashing == 0) // we need an object for type hashing
                w.string("<Named w/o object>")
                return
        }
@@ -301,17 +301,18 @@ func (w *typeWriter) typeName(obj *TypeName) {
        }
        w.string(obj.name)
 
-       if instanceHashing != 0 {
+       if typeHashing != 0 {
                // For local defined types, use the (original!) TypeName's scope
                // numbers to disambiguate.
-               typ := obj.typ.(*Named)
-               // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
-               //           and whether the loop can iterate more than twice.
-               //           (It seems somehow connected to instance types.)
-               for typ.orig != typ {
-                       typ = typ.orig
+               if typ, _ := obj.typ.(*Named); typ != nil {
+                       // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
+                       //           and whether the loop can iterate more than twice.
+                       //           (It seems somehow connected to instance types.)
+                       for typ.orig != typ {
+                               typ = typ.orig
+                       }
+                       w.writeScopeNumbers(typ.obj.parent)
                }
-               w.writeScopeNumbers(typ.obj.parent)
        }
 }
 
@@ -333,7 +334,8 @@ func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
                        if i > 0 {
                                w.string(", ")
                        }
-                       if v.name != "" {
+                       // parameter names are ignored for type identity and thus type hashes
+                       if typeHashing == 0 && v.name != "" {
                                w.string(v.name)
                                w.byte(' ')
                        }
@@ -381,8 +383,8 @@ func (w *typeWriter) signature(sig *Signature) {
        }
 
        w.byte(' ')
-       if n == 1 && sig.results.vars[0].name == "" {
-               // single unnamed result
+       if n == 1 && (typeHashing != 0 || sig.results.vars[0].name == "") {
+               // single unnamed result (if typeHashing, name must be ignored)
                w.typ(sig.results.vars[0].typ)
                return
        }