Source file src/go/types/typeparam.go
1 // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. 2 // Source: ../../cmd/compile/internal/types2/typeparam.go 3 4 // Copyright 2011 The Go Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file. 7 8 package types 9 10 import "sync/atomic" 11 12 // Note: This is a uint32 rather than a uint64 because the 13 // respective 64 bit atomic instructions are not available 14 // on all platforms. 15 var lastID atomic.Uint32 16 17 // nextID returns a value increasing monotonically by 1 with 18 // each call, starting with 1. It may be called concurrently. 19 func nextID() uint64 { return uint64(lastID.Add(1)) } 20 21 // A TypeParam represents the type of a type parameter in a generic declaration. 22 // 23 // A TypeParam has a name; use the [TypeParam.Obj] method to access 24 // its [TypeName] object. 25 type TypeParam struct { 26 check *Checker // for lazy type bound completion 27 id uint64 // unique id, for debugging only 28 obj *TypeName // corresponding type name 29 index int // type parameter index in source order, starting at 0 30 bound Type // any type, but underlying is eventually *Interface for correct programs (see TypeParam.iface) 31 } 32 33 // NewTypeParam returns a new TypeParam. Type parameters may be set on a Named 34 // type by calling SetTypeParams. Setting a type parameter on more than one type 35 // will result in a panic. 36 // 37 // The constraint argument can be nil, and set later via SetConstraint. If the 38 // constraint is non-nil, it must be fully defined. 39 func NewTypeParam(obj *TypeName, constraint Type) *TypeParam { 40 return (*Checker)(nil).newTypeParam(obj, constraint) 41 } 42 43 // check may be nil 44 func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam { 45 // Always increment lastID, even if it is not used. 46 id := nextID() 47 if check != nil { 48 check.nextID++ 49 id = check.nextID 50 } 51 typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: constraint} 52 if obj.typ == nil { 53 obj.typ = typ 54 } 55 // iface may mutate typ.bound, so we must ensure that iface() is called 56 // at least once before the resulting TypeParam escapes. 57 if check != nil { 58 check.needsCleanup(typ) 59 } else if constraint != nil { 60 typ.iface() 61 } 62 return typ 63 } 64 65 // Obj returns the type name for the type parameter t. 66 func (t *TypeParam) Obj() *TypeName { return t.obj } 67 68 // Index returns the index of the type param within its param list, or -1 if 69 // the type parameter has not yet been bound to a type. 70 func (t *TypeParam) Index() int { 71 return t.index 72 } 73 74 // Constraint returns the type constraint specified for t. 75 func (t *TypeParam) Constraint() Type { 76 return t.bound 77 } 78 79 // SetConstraint sets the type constraint for t. 80 // 81 // It must be called by users of NewTypeParam after the bound's underlying is 82 // fully defined, and before using the type parameter in any way other than to 83 // form other types. Once SetConstraint returns the receiver, t is safe for 84 // concurrent use. 85 func (t *TypeParam) SetConstraint(bound Type) { 86 if bound == nil { 87 panic("nil constraint") 88 } 89 t.bound = bound 90 // iface may mutate t.bound (if bound is not an interface), so ensure that 91 // this is done before returning. 92 t.iface() 93 } 94 95 // Underlying returns the [underlying type] of the type parameter t, which is 96 // the underlying type of its constraint. This type is always an interface. 97 // 98 // [underlying type]: https://go.dev/ref/spec#Underlying_types. 99 func (t *TypeParam) Underlying() Type { 100 return t.iface() 101 } 102 103 func (t *TypeParam) String() string { return TypeString(t, nil) } 104 105 // ---------------------------------------------------------------------------- 106 // Implementation 107 108 func (t *TypeParam) cleanup() { 109 t.iface() 110 t.check = nil 111 } 112 113 // iface returns the constraint interface of t. 114 func (t *TypeParam) iface() *Interface { 115 bound := t.bound 116 117 // determine constraint interface 118 var ityp *Interface 119 switch u := under(bound).(type) { 120 case *Basic: 121 if !isValid(u) { 122 // error is reported elsewhere 123 return &emptyInterface 124 } 125 case *Interface: 126 if isTypeParam(bound) { 127 // error is reported in Checker.collectTypeParams 128 return &emptyInterface 129 } 130 ityp = u 131 } 132 133 // If we don't have an interface, wrap constraint into an implicit interface. 134 if ityp == nil { 135 ityp = NewInterfaceType(nil, []Type{bound}) 136 ityp.implicit = true 137 t.bound = ityp // update t.bound for next time (optimization) 138 } 139 140 // compute type set if necessary 141 if ityp.tset == nil { 142 // pos is used for tracing output; start with the type parameter position. 143 pos := t.obj.pos 144 // use the (original or possibly instantiated) type bound position if we have one 145 if n := asNamed(bound); n != nil { 146 pos = n.obj.pos 147 } 148 computeInterfaceTypeSet(t.check, pos, ityp) 149 } 150 151 return ityp 152 } 153 154 // is calls f with the specific type terms of t's constraint and reports whether 155 // all calls to f returned true. If there are no specific terms, is 156 // returns the result of f(nil). 157 func (t *TypeParam) is(f func(*term) bool) bool { 158 return t.iface().typeSet().is(f) 159 } 160 161 // typeset is an iterator over the (type/underlying type) pairs of the 162 // specific type terms of t's constraint. 163 // If there are no specific terms, typeset calls yield with (nil, nil). 164 // In any case, typeset is guaranteed to call yield at least once. 165 func (t *TypeParam) typeset(yield func(t, u Type) bool) { 166 t.iface().typeSet().typeset(yield) 167 } 168