aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/types2/typeparam.go
blob: 4b4282efe0b4b513c6c38c09d4aebf167fb63a84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package types2

import "sync/atomic"

// Note: This is a uint32 rather than a uint64 because the
// respective 64 bit atomic instructions are not available
// on all platforms.
var lastID uint32

// nextID returns a value increasing monotonically by 1 with
// each call, starting with 1. It may be called concurrently.
func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) }

// A TypeParam represents a type parameter type.
type TypeParam struct {
	check *Checker  // for lazy type bound completion
	id    uint64    // unique id, for debugging only
	obj   *TypeName // corresponding type name
	index int       // type parameter index in source order, starting at 0
	// TODO(rfindley): this could also be Typ[Invalid]. Verify that this is handled correctly.
	bound Type // *Named or *Interface; underlying type is always *Interface
}

// Obj returns the type name for the type parameter t.
func (t *TypeParam) Obj() *TypeName { return t.obj }

// NewTypeParam returns a new TypeParam. Type parameters may be set on a Named
// or Signature type by calling SetTParams. Setting a type parameter on more
// than one type will result in a panic.
//
// The bound argument can be nil, and set later via SetBound.
func (check *Checker) NewTypeParam(obj *TypeName, bound Type) *TypeParam {
	// Always increment lastID, even if it is not used.
	id := nextID()
	if check != nil {
		check.nextID++
		id = check.nextID
	}
	typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: bound}
	if obj.typ == nil {
		obj.typ = typ
	}
	return typ
}

// Index returns the index of the type param within its param list.
func (t *TypeParam) Index() int {
	return t.index
}

// SetId sets the unique id of a type param. Should only be used for type params
// in imported generic types.
func (t *TypeParam) SetId(id uint64) {
	t.id = id
}

// Constraint returns the type constraint specified for t.
func (t *TypeParam) Constraint() Type {
	// compute the type set if possible (we may not have an interface)
	if iface, _ := under(t.bound).(*Interface); iface != nil {
		// use the type bound position if we have one
		pos := nopos
		if n, _ := t.bound.(*Named); n != nil {
			pos = n.obj.pos
		}
		computeInterfaceTypeSet(t.check, pos, iface)
	}
	return t.bound
}

// SetConstraint sets the type constraint for t.
func (t *TypeParam) SetConstraint(bound Type) {
	if bound == nil {
		panic("nil constraint")
	}
	t.bound = bound
}

func (t *TypeParam) Underlying() Type { return t }
func (t *TypeParam) String() string   { return TypeString(t, nil) }

// TypeParams holds a list of type parameters bound to a type.
type TypeParams struct{ tparams []*TypeName }

// Len returns the number of type parameters in the list.
// It is safe to call on a nil receiver.
func (tps *TypeParams) Len() int {
	return len(tps.list())
}

// At returns the i'th type parameter in the list.
func (tps *TypeParams) At(i int) *TypeName {
	return tps.list()[i]
}

func (tps *TypeParams) list() []*TypeName {
	if tps == nil {
		return nil
	}
	return tps.tparams
}

func bindTParams(list []*TypeName) *TypeParams {
	if len(list) == 0 {
		return nil
	}
	for i, tp := range list {
		typ := tp.Type().(*TypeParam)
		if typ.index >= 0 {
			panic("type parameter bound more than once")
		}
		typ.index = i
	}
	return &TypeParams{tparams: list}
}

// ----------------------------------------------------------------------------
// Implementation

// iface returns the constraint interface of t.
func (t *TypeParam) iface() *Interface {
	if iface, _ := under(t.Constraint()).(*Interface); iface != nil {
		return iface
	}
	return &emptyInterface
}

// structuralType returns the structural type of the type parameter's constraint; or nil.
func (t *TypeParam) structuralType() Type {
	return t.iface().typeSet().structuralType()
}

func (t *TypeParam) is(f func(*term) bool) bool {
	return t.iface().typeSet().is(f)
}

func (t *TypeParam) underIs(f func(Type) bool) bool {
	return t.iface().typeSet().underIs(f)
}