github.com/AndrienkoAleksandr/go@v0.0.19/src/go/types/instantiate.go (about) 1 // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. 2 3 // Copyright 2021 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 // This file implements instantiation of generic types 8 // through substitution of type parameters by type arguments. 9 10 package types 11 12 import ( 13 "errors" 14 "fmt" 15 "go/token" 16 . "internal/types/errors" 17 ) 18 19 // Instantiate instantiates the type orig with the given type arguments targs. 20 // orig must be a *Named or a *Signature type. If there is no error, the 21 // resulting Type is an instantiated type of the same kind (either a *Named or 22 // a *Signature). Methods attached to a *Named type are also instantiated, and 23 // associated with a new *Func that has the same position as the original 24 // method, but nil function scope. 25 // 26 // If ctxt is non-nil, it may be used to de-duplicate the instance against 27 // previous instances with the same identity. As a special case, generic 28 // *Signature origin types are only considered identical if they are pointer 29 // equivalent, so that instantiating distinct (but possibly identical) 30 // signatures will yield different instances. The use of a shared context does 31 // not guarantee that identical instances are deduplicated in all cases. 32 // 33 // If validate is set, Instantiate verifies that the number of type arguments 34 // and parameters match, and that the type arguments satisfy their 35 // corresponding type constraints. If verification fails, the resulting error 36 // may wrap an *ArgumentError indicating which type argument did not satisfy 37 // its corresponding type parameter constraint, and why. 38 // 39 // If validate is not set, Instantiate does not verify the type argument count 40 // or whether the type arguments satisfy their constraints. Instantiate is 41 // guaranteed to not return an error, but may panic. Specifically, for 42 // *Signature types, Instantiate will panic immediately if the type argument 43 // count is incorrect; for *Named types, a panic may occur later inside the 44 // *Named API. 45 func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, error) { 46 if ctxt == nil { 47 ctxt = NewContext() 48 } 49 if validate { 50 var tparams []*TypeParam 51 switch t := orig.(type) { 52 case *Named: 53 tparams = t.TypeParams().list() 54 case *Signature: 55 tparams = t.TypeParams().list() 56 } 57 if len(targs) != len(tparams) { 58 return nil, fmt.Errorf("got %d type arguments but %s has %d type parameters", len(targs), orig, len(tparams)) 59 } 60 if i, err := (*Checker)(nil).verify(nopos, tparams, targs, ctxt); err != nil { 61 return nil, &ArgumentError{i, err} 62 } 63 } 64 65 inst := (*Checker)(nil).instance(nopos, orig, targs, nil, ctxt) 66 return inst, nil 67 } 68 69 // instance instantiates the given original (generic) function or type with the 70 // provided type arguments and returns the resulting instance. If an identical 71 // instance exists already in the given contexts, it returns that instance, 72 // otherwise it creates a new one. 73 // 74 // If expanding is non-nil, it is the Named instance type currently being 75 // expanded. If ctxt is non-nil, it is the context associated with the current 76 // type-checking pass or call to Instantiate. At least one of expanding or ctxt 77 // must be non-nil. 78 // 79 // For Named types the resulting instance may be unexpanded. 80 func (check *Checker) instance(pos token.Pos, orig Type, targs []Type, expanding *Named, ctxt *Context) (res Type) { 81 // The order of the contexts below matters: we always prefer instances in the 82 // expanding instance context in order to preserve reference cycles. 83 // 84 // Invariant: if expanding != nil, the returned instance will be the instance 85 // recorded in expanding.inst.ctxt. 86 var ctxts []*Context 87 if expanding != nil { 88 ctxts = append(ctxts, expanding.inst.ctxt) 89 } 90 if ctxt != nil { 91 ctxts = append(ctxts, ctxt) 92 } 93 assert(len(ctxts) > 0) 94 95 // Compute all hashes; hashes may differ across contexts due to different 96 // unique IDs for Named types within the hasher. 97 hashes := make([]string, len(ctxts)) 98 for i, ctxt := range ctxts { 99 hashes[i] = ctxt.instanceHash(orig, targs) 100 } 101 102 // If local is non-nil, updateContexts return the type recorded in 103 // local. 104 updateContexts := func(res Type) Type { 105 for i := len(ctxts) - 1; i >= 0; i-- { 106 res = ctxts[i].update(hashes[i], orig, targs, res) 107 } 108 return res 109 } 110 111 // typ may already have been instantiated with identical type arguments. In 112 // that case, re-use the existing instance. 113 for i, ctxt := range ctxts { 114 if inst := ctxt.lookup(hashes[i], orig, targs); inst != nil { 115 return updateContexts(inst) 116 } 117 } 118 119 switch orig := orig.(type) { 120 case *Named: 121 res = check.newNamedInstance(pos, orig, targs, expanding) // substituted lazily 122 123 case *Signature: 124 assert(expanding == nil) // function instances cannot be reached from Named types 125 126 tparams := orig.TypeParams() 127 if !check.validateTArgLen(pos, tparams.Len(), len(targs)) { 128 return Typ[Invalid] 129 } 130 if tparams.Len() == 0 { 131 return orig // nothing to do (minor optimization) 132 } 133 sig := check.subst(pos, orig, makeSubstMap(tparams.list(), targs), nil, ctxt).(*Signature) 134 // If the signature doesn't use its type parameters, subst 135 // will not make a copy. In that case, make a copy now (so 136 // we can set tparams to nil w/o causing side-effects). 137 if sig == orig { 138 copy := *sig 139 sig = © 140 } 141 // After instantiating a generic signature, it is not generic 142 // anymore; we need to set tparams to nil. 143 sig.tparams = nil 144 res = sig 145 146 default: 147 // only types and functions can be generic 148 panic(fmt.Sprintf("%v: cannot instantiate %v", pos, orig)) 149 } 150 151 // Update all contexts; it's possible that we've lost a race. 152 return updateContexts(res) 153 } 154 155 // validateTArgLen verifies that the length of targs and tparams matches, 156 // reporting an error if not. If validation fails and check is nil, 157 // validateTArgLen panics. 158 func (check *Checker) validateTArgLen(pos token.Pos, ntparams, ntargs int) bool { 159 if ntargs != ntparams { 160 // TODO(gri) provide better error message 161 if check != nil { 162 check.errorf(atPos(pos), WrongTypeArgCount, "got %d arguments but %d type parameters", ntargs, ntparams) 163 return false 164 } 165 panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, ntargs, ntparams)) 166 } 167 return true 168 } 169 170 func (check *Checker) verify(pos token.Pos, tparams []*TypeParam, targs []Type, ctxt *Context) (int, error) { 171 smap := makeSubstMap(tparams, targs) 172 for i, tpar := range tparams { 173 // Ensure that we have a (possibly implicit) interface as type bound (go.dev/issue/51048). 174 tpar.iface() 175 // The type parameter bound is parameterized with the same type parameters 176 // as the instantiated type; before we can use it for bounds checking we 177 // need to instantiate it with the type arguments with which we instantiated 178 // the parameterized type. 179 bound := check.subst(pos, tpar.bound, smap, nil, ctxt) 180 var cause string 181 if !check.implements(pos, targs[i], bound, true, &cause) { 182 return i, errors.New(cause) 183 } 184 } 185 return -1, nil 186 } 187 188 // implements checks if V implements T. The receiver may be nil if implements 189 // is called through an exported API call such as AssignableTo. If constraint 190 // is set, T is a type constraint. 191 // 192 // If the provided cause is non-nil, it may be set to an error string 193 // explaining why V does not implement (or satisfy, for constraints) T. 194 func (check *Checker) implements(pos token.Pos, V, T Type, constraint bool, cause *string) bool { 195 Vu := under(V) 196 Tu := under(T) 197 if Vu == Typ[Invalid] || Tu == Typ[Invalid] { 198 return true // avoid follow-on errors 199 } 200 if p, _ := Vu.(*Pointer); p != nil && under(p.base) == Typ[Invalid] { 201 return true // avoid follow-on errors (see go.dev/issue/49541 for an example) 202 } 203 204 verb := "implement" 205 if constraint { 206 verb = "satisfy" 207 } 208 209 Ti, _ := Tu.(*Interface) 210 if Ti == nil { 211 if cause != nil { 212 var detail string 213 if isInterfacePtr(Tu) { 214 detail = check.sprintf("type %s is pointer to interface, not interface", T) 215 } else { 216 detail = check.sprintf("%s is not an interface", T) 217 } 218 *cause = check.sprintf("%s does not %s %s (%s)", V, verb, T, detail) 219 } 220 return false 221 } 222 223 // Every type satisfies the empty interface. 224 if Ti.Empty() { 225 return true 226 } 227 // T is not the empty interface (i.e., the type set of T is restricted) 228 229 // An interface V with an empty type set satisfies any interface. 230 // (The empty set is a subset of any set.) 231 Vi, _ := Vu.(*Interface) 232 if Vi != nil && Vi.typeSet().IsEmpty() { 233 return true 234 } 235 // type set of V is not empty 236 237 // No type with non-empty type set satisfies the empty type set. 238 if Ti.typeSet().IsEmpty() { 239 if cause != nil { 240 *cause = check.sprintf("cannot %s %s (empty type set)", verb, T) 241 } 242 return false 243 } 244 245 // V must implement T's methods, if any. 246 if m, _ := check.missingMethod(V, T, true, Identical, cause); m != nil /* !Implements(V, T) */ { 247 if cause != nil { 248 *cause = check.sprintf("%s does not %s %s %s", V, verb, T, *cause) 249 } 250 return false 251 } 252 253 // Only check comparability if we don't have a more specific error. 254 checkComparability := func() bool { 255 if !Ti.IsComparable() { 256 return true 257 } 258 // If T is comparable, V must be comparable. 259 // If V is strictly comparable, we're done. 260 if comparable(V, false /* strict comparability */, nil, nil) { 261 return true 262 } 263 // For constraint satisfaction, use dynamic (spec) comparability 264 // so that ordinary, non-type parameter interfaces implement comparable. 265 if constraint && comparable(V, true /* spec comparability */, nil, nil) { 266 // V is comparable if we are at Go 1.20 or higher. 267 if check == nil || check.allowVersion(check.pkg, atPos(pos), go1_20) { // atPos needed so that go/types generate passes 268 return true 269 } 270 if cause != nil { 271 *cause = check.sprintf("%s to %s comparable requires go1.20 or later", V, verb) 272 } 273 return false 274 } 275 if cause != nil { 276 *cause = check.sprintf("%s does not %s comparable", V, verb) 277 } 278 return false 279 } 280 281 // V must also be in the set of types of T, if any. 282 // Constraints with empty type sets were already excluded above. 283 if !Ti.typeSet().hasTerms() { 284 return checkComparability() // nothing to do 285 } 286 287 // If V is itself an interface, each of its possible types must be in the set 288 // of T types (i.e., the V type set must be a subset of the T type set). 289 // Interfaces V with empty type sets were already excluded above. 290 if Vi != nil { 291 if !Vi.typeSet().subsetOf(Ti.typeSet()) { 292 // TODO(gri) report which type is missing 293 if cause != nil { 294 *cause = check.sprintf("%s does not %s %s", V, verb, T) 295 } 296 return false 297 } 298 return checkComparability() 299 } 300 301 // Otherwise, V's type must be included in the iface type set. 302 var alt Type 303 if Ti.typeSet().is(func(t *term) bool { 304 if !t.includes(V) { 305 // If V ∉ t.typ but V ∈ ~t.typ then remember this type 306 // so we can suggest it as an alternative in the error 307 // message. 308 if alt == nil && !t.tilde && Identical(t.typ, under(t.typ)) { 309 tt := *t 310 tt.tilde = true 311 if tt.includes(V) { 312 alt = t.typ 313 } 314 } 315 return true 316 } 317 return false 318 }) { 319 if cause != nil { 320 var detail string 321 switch { 322 case alt != nil: 323 detail = check.sprintf("possibly missing ~ for %s in %s", alt, T) 324 case mentions(Ti, V): 325 detail = check.sprintf("%s mentions %s, but %s is not in the type set of %s", T, V, V, T) 326 default: 327 detail = check.sprintf("%s missing in %s", V, Ti.typeSet().terms) 328 } 329 *cause = check.sprintf("%s does not %s %s (%s)", V, verb, T, detail) 330 } 331 return false 332 } 333 334 return checkComparability() 335 } 336 337 // mentions reports whether type T "mentions" typ in an (embedded) element or term 338 // of T (whether typ is in the type set of T or not). For better error messages. 339 func mentions(T, typ Type) bool { 340 switch T := T.(type) { 341 case *Interface: 342 for _, e := range T.embeddeds { 343 if mentions(e, typ) { 344 return true 345 } 346 } 347 case *Union: 348 for _, t := range T.terms { 349 if mentions(t.typ, typ) { 350 return true 351 } 352 } 353 default: 354 if Identical(T, typ) { 355 return true 356 } 357 } 358 return false 359 }