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