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