Skip to content

Commit 0df6df1

Browse files
committed
go/types: generalize instanceHash to accept any type, rename to typeHash
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 <[email protected]> Run-TryBot: Robert Findley <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent 3c8c9e1 commit 0df6df1

File tree

5 files changed

+79
-24
lines changed

5 files changed

+79
-24
lines changed

src/go/types/instantiate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, posList
119119
func (check *Checker) instance(pos token.Pos, typ Type, targs []Type) Type {
120120
switch t := typ.(type) {
121121
case *Named:
122-
h := instantiatedHash(t, targs)
122+
h := typeHash(t, targs)
123123
if check != nil {
124124
// typ may already have been instantiated with identical type arguments. In
125125
// that case, re-use the existing instance.

src/go/types/named.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ func (n *Named) expand(typMap map[string]*Named) *Named {
258258
// type-checking pass. In that case we won't have a pre-existing
259259
// typMap, but don't want to create a duplicate of the current instance
260260
// in the process of expansion.
261-
h := instantiatedHash(n.orig, n.targs.list())
261+
h := typeHash(n.orig, n.targs.list())
262262
typMap = map[string]*Named{h: n}
263263
}
264264
}

src/go/types/stmt.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ L:
302302
// talk about "case" rather than "type" because of nil case
303303
Ts := "nil"
304304
if T != nil {
305-
Ts = T.String()
305+
Ts = TypeString(T, check.qualifier)
306306
}
307307
check.errorf(e, _DuplicateCase, "duplicate case %s in type switch", Ts)
308308
check.error(other, _DuplicateCase, "\tprevious case") // secondary error, \t indented
@@ -317,6 +317,47 @@ L:
317317
return
318318
}
319319

320+
// TODO(gri) Once we are certain that typeHash is correct in all situations, use this version of caseTypes instead.
321+
// (Currently it may be possible that different types have identical names and import paths due to ImporterFrom.)
322+
//
323+
// func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[string]ast.Expr) (T Type) {
324+
// var dummy operand
325+
// L:
326+
// for _, e := range types {
327+
// // The spec allows the value nil instead of a type.
328+
// var hash string
329+
// if check.isNil(e) {
330+
// check.expr(&dummy, e) // run e through expr so we get the usual Info recordings
331+
// T = nil
332+
// hash = "<nil>" // avoid collision with a type named nil
333+
// } else {
334+
// T = check.varType(e)
335+
// if T == Typ[Invalid] {
336+
// continue L
337+
// }
338+
// hash = typeHash(T, nil)
339+
// }
340+
// // look for duplicate types
341+
// if other := seen[hash]; other != nil {
342+
// // talk about "case" rather than "type" because of nil case
343+
// Ts := "nil"
344+
// if T != nil {
345+
// Ts = TypeString(T, check.qualifier)
346+
// }
347+
// var err error_
348+
// err.errorf(e, "duplicate case %s in type switch", Ts)
349+
// err.errorf(other, "previous case")
350+
// check.report(&err)
351+
// continue L
352+
// }
353+
// seen[hash] = e
354+
// if T != nil {
355+
// check.typeAssertion(e.Pos(), x, xtyp, T)
356+
// }
357+
// }
358+
// return
359+
// }
360+
320361
// stmt typechecks statement s.
321362
func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
322363
// statements must end with the same top scope as they started with

src/go/types/subst.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ func (subst *subster) typ(typ Type) Type {
217217
}
218218

219219
// before creating a new named type, check if we have this one already
220-
h := instantiatedHash(t, newTArgs)
220+
h := typeHash(t, newTArgs)
221221
dump(">>> new type hash: %s", h)
222222
if named, found := subst.typMap[h]; found {
223223
dump(">>> found %s", named)
@@ -256,17 +256,29 @@ func (subst *subster) typ(typ Type) Type {
256256
return typ
257257
}
258258

259-
var instanceHashing = 0
259+
var typeHashing = 0
260260

261-
func instantiatedHash(typ *Named, targs []Type) string {
261+
// typeHash returns a string representation of typ, which can be used as an exact
262+
// type hash: types that are identical produce identical string representations.
263+
// If typ is a *Named type and targs is not empty, typ is printed as if it were
264+
// instantiated with targs.
265+
func typeHash(typ Type, targs []Type) string {
266+
assert(typ != nil)
262267
var buf bytes.Buffer
263268

264-
assert(instanceHashing == 0)
265-
instanceHashing++
269+
assert(typeHashing == 0)
270+
typeHashing++
266271
w := newTypeWriter(&buf, nil)
267-
w.typeName(typ.obj)
268-
w.typeList(targs)
269-
instanceHashing--
272+
if named, _ := typ.(*Named); named != nil && len(targs) > 0 {
273+
// Don't use WriteType because we need to use the provided targs
274+
// and not any targs that might already be with the *Named type.
275+
w.typeName(named.obj)
276+
w.typeList(targs)
277+
} else {
278+
assert(targs == nil)
279+
w.typ(typ)
280+
}
281+
typeHashing--
270282

271283
if debug {
272284
// there should be no instance markers in type hashes

src/go/types/typestring.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ func (w *typeWriter) typ(typ Type) {
208208
// types. Write them to aid debugging, but don't write
209209
// them when we need an instance hash: whether a type
210210
// is fully expanded or not doesn't matter for identity.
211-
if instanceHashing == 0 && t.instPos != nil {
211+
if typeHashing == 0 && t.instPos != nil {
212212
w.byte(instanceMarker)
213213
}
214214
w.typeName(t.obj)
@@ -292,7 +292,7 @@ func (w *typeWriter) tParamList(list []*TypeParam) {
292292

293293
func (w *typeWriter) typeName(obj *TypeName) {
294294
if obj == nil {
295-
assert(instanceHashing == 0) // we need an object for instance hashing
295+
assert(typeHashing == 0) // we need an object for type hashing
296296
w.string("<Named w/o object>")
297297
return
298298
}
@@ -301,17 +301,18 @@ func (w *typeWriter) typeName(obj *TypeName) {
301301
}
302302
w.string(obj.name)
303303

304-
if instanceHashing != 0 {
304+
if typeHashing != 0 {
305305
// For local defined types, use the (original!) TypeName's scope
306306
// numbers to disambiguate.
307-
typ := obj.typ.(*Named)
308-
// TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
309-
// and whether the loop can iterate more than twice.
310-
// (It seems somehow connected to instance types.)
311-
for typ.orig != typ {
312-
typ = typ.orig
307+
if typ, _ := obj.typ.(*Named); typ != nil {
308+
// TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
309+
// and whether the loop can iterate more than twice.
310+
// (It seems somehow connected to instance types.)
311+
for typ.orig != typ {
312+
typ = typ.orig
313+
}
314+
w.writeScopeNumbers(typ.obj.parent)
313315
}
314-
w.writeScopeNumbers(typ.obj.parent)
315316
}
316317
}
317318

@@ -333,7 +334,8 @@ func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
333334
if i > 0 {
334335
w.string(", ")
335336
}
336-
if v.name != "" {
337+
// parameter names are ignored for type identity and thus type hashes
338+
if typeHashing == 0 && v.name != "" {
337339
w.string(v.name)
338340
w.byte(' ')
339341
}
@@ -381,8 +383,8 @@ func (w *typeWriter) signature(sig *Signature) {
381383
}
382384

383385
w.byte(' ')
384-
if n == 1 && sig.results.vars[0].name == "" {
385-
// single unnamed result
386+
if n == 1 && (typeHashing != 0 || sig.results.vars[0].name == "") {
387+
// single unnamed result (if typeHashing, name must be ignored)
386388
w.typ(sig.results.vars[0].typ)
387389
return
388390
}

0 commit comments

Comments
 (0)