1// Copyright 2021 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package types 6 7import ( 8 "go/token" 9 "testing" 10) 11 12func TestContextHashCollisions(t *testing.T) { 13 if debug { 14 t.Skip("hash collisions are expected, and would fail debug assertions") 15 } 16 // Unit test the de-duplication fall-back logic in Context. 17 // 18 // We can't test this via Instantiate because this is only a fall-back in 19 // case our hash is imperfect. 20 // 21 // These lookups and updates use reasonable looking types in an attempt to 22 // make them robust to internal type assertions, but could equally well use 23 // arbitrary types. 24 25 // Create some distinct origin types. nullaryP and nullaryQ have no 26 // parameters and are identical (but have different type parameter names). 27 // unaryP has a parameter. 28 var nullaryP, nullaryQ, unaryP Type 29 { 30 // type nullaryP = func[P any]() 31 tparam := NewTypeParam(NewTypeName(token.NoPos, nil, "P", nil), &emptyInterface) 32 nullaryP = NewSignatureType(nil, nil, []*TypeParam{tparam}, nil, nil, false) 33 } 34 { 35 // type nullaryQ = func[Q any]() 36 tparam := NewTypeParam(NewTypeName(token.NoPos, nil, "Q", nil), &emptyInterface) 37 nullaryQ = NewSignatureType(nil, nil, []*TypeParam{tparam}, nil, nil, false) 38 } 39 { 40 // type unaryP = func[P any](_ P) 41 tparam := NewTypeParam(NewTypeName(token.NoPos, nil, "P", nil), &emptyInterface) 42 params := NewTuple(NewVar(token.NoPos, nil, "_", tparam)) 43 unaryP = NewSignatureType(nil, nil, []*TypeParam{tparam}, params, nil, false) 44 } 45 46 ctxt := NewContext() 47 48 // Update the context with an instantiation of nullaryP. 49 inst := NewSignatureType(nil, nil, nil, nil, nil, false) 50 if got := ctxt.update("", nullaryP, []Type{Typ[Int]}, inst); got != inst { 51 t.Error("bad") 52 } 53 54 // unaryP is not identical to nullaryP, so we should not get inst when 55 // instantiated with identical type arguments. 56 if got := ctxt.lookup("", unaryP, []Type{Typ[Int]}); got != nil { 57 t.Error("bad") 58 } 59 60 // nullaryQ is identical to nullaryP, so we *should* get inst when 61 // instantiated with identical type arguments. 62 if got := ctxt.lookup("", nullaryQ, []Type{Typ[Int]}); got != inst { 63 t.Error("bad") 64 } 65 66 // ...but verify we don't get inst with different type arguments. 67 if got := ctxt.lookup("", nullaryQ, []Type{Typ[String]}); got != nil { 68 t.Error("bad") 69 } 70} 71