github.com/AndrienkoAleksandr/go@v0.0.19/src/go/types/subst.go (about) 1 // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. 2 3 // Copyright 2018 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 type parameter substitution. 8 9 package types 10 11 import ( 12 "go/token" 13 ) 14 15 type substMap map[*TypeParam]Type 16 17 // makeSubstMap creates a new substitution map mapping tpars[i] to targs[i]. 18 // If targs[i] is nil, tpars[i] is not substituted. 19 func makeSubstMap(tpars []*TypeParam, targs []Type) substMap { 20 assert(len(tpars) == len(targs)) 21 proj := make(substMap, len(tpars)) 22 for i, tpar := range tpars { 23 proj[tpar] = targs[i] 24 } 25 return proj 26 } 27 28 // makeRenameMap is like makeSubstMap, but creates a map used to rename type 29 // parameters in from with the type parameters in to. 30 func makeRenameMap(from, to []*TypeParam) substMap { 31 assert(len(from) == len(to)) 32 proj := make(substMap, len(from)) 33 for i, tpar := range from { 34 proj[tpar] = to[i] 35 } 36 return proj 37 } 38 39 func (m substMap) empty() bool { 40 return len(m) == 0 41 } 42 43 func (m substMap) lookup(tpar *TypeParam) Type { 44 if t := m[tpar]; t != nil { 45 return t 46 } 47 return tpar 48 } 49 50 // subst returns the type typ with its type parameters tpars replaced by the 51 // corresponding type arguments targs, recursively. subst doesn't modify the 52 // incoming type. If a substitution took place, the result type is different 53 // from the incoming type. 54 // 55 // If expanding is non-nil, it is the instance type currently being expanded. 56 // One of expanding or ctxt must be non-nil. 57 func (check *Checker) subst(pos token.Pos, typ Type, smap substMap, expanding *Named, ctxt *Context) Type { 58 assert(expanding != nil || ctxt != nil) 59 60 if smap.empty() { 61 return typ 62 } 63 64 // common cases 65 switch t := typ.(type) { 66 case *Basic: 67 return typ // nothing to do 68 case *TypeParam: 69 return smap.lookup(t) 70 } 71 72 // general case 73 subst := subster{ 74 pos: pos, 75 smap: smap, 76 check: check, 77 expanding: expanding, 78 ctxt: ctxt, 79 } 80 return subst.typ(typ) 81 } 82 83 type subster struct { 84 pos token.Pos 85 smap substMap 86 check *Checker // nil if called via Instantiate 87 expanding *Named // if non-nil, the instance that is being expanded 88 ctxt *Context 89 } 90 91 func (subst *subster) typ(typ Type) Type { 92 switch t := typ.(type) { 93 case nil: 94 // Call typOrNil if it's possible that typ is nil. 95 panic("nil typ") 96 97 case *Basic: 98 // nothing to do 99 100 case *Array: 101 elem := subst.typOrNil(t.elem) 102 if elem != t.elem { 103 return &Array{len: t.len, elem: elem} 104 } 105 106 case *Slice: 107 elem := subst.typOrNil(t.elem) 108 if elem != t.elem { 109 return &Slice{elem: elem} 110 } 111 112 case *Struct: 113 if fields, copied := subst.varList(t.fields); copied { 114 s := &Struct{fields: fields, tags: t.tags} 115 s.markComplete() 116 return s 117 } 118 119 case *Pointer: 120 base := subst.typ(t.base) 121 if base != t.base { 122 return &Pointer{base: base} 123 } 124 125 case *Tuple: 126 return subst.tuple(t) 127 128 case *Signature: 129 // Preserve the receiver: it is handled during *Interface and *Named type 130 // substitution. 131 // 132 // Naively doing the substitution here can lead to an infinite recursion in 133 // the case where the receiver is an interface. For example, consider the 134 // following declaration: 135 // 136 // type T[A any] struct { f interface{ m() } } 137 // 138 // In this case, the type of f is an interface that is itself the receiver 139 // type of all of its methods. Because we have no type name to break 140 // cycles, substituting in the recv results in an infinite loop of 141 // recv->interface->recv->interface->... 142 recv := t.recv 143 144 params := subst.tuple(t.params) 145 results := subst.tuple(t.results) 146 if params != t.params || results != t.results { 147 return &Signature{ 148 rparams: t.rparams, 149 // TODO(gri) why can't we nil out tparams here, rather than in instantiate? 150 tparams: t.tparams, 151 // instantiated signatures have a nil scope 152 recv: recv, 153 params: params, 154 results: results, 155 variadic: t.variadic, 156 } 157 } 158 159 case *Union: 160 terms, copied := subst.termlist(t.terms) 161 if copied { 162 // term list substitution may introduce duplicate terms (unlikely but possible). 163 // This is ok; lazy type set computation will determine the actual type set 164 // in normal form. 165 return &Union{terms} 166 } 167 168 case *Interface: 169 methods, mcopied := subst.funcList(t.methods) 170 embeddeds, ecopied := subst.typeList(t.embeddeds) 171 if mcopied || ecopied { 172 iface := subst.check.newInterface() 173 iface.embeddeds = embeddeds 174 iface.implicit = t.implicit 175 iface.complete = t.complete 176 // If we've changed the interface type, we may need to replace its 177 // receiver if the receiver type is the original interface. Receivers of 178 // *Named type are replaced during named type expansion. 179 // 180 // Notably, it's possible to reach here and not create a new *Interface, 181 // even though the receiver type may be parameterized. For example: 182 // 183 // type T[P any] interface{ m() } 184 // 185 // In this case the interface will not be substituted here, because its 186 // method signatures do not depend on the type parameter P, but we still 187 // need to create new interface methods to hold the instantiated 188 // receiver. This is handled by Named.expandUnderlying. 189 iface.methods, _ = replaceRecvType(methods, t, iface) 190 return iface 191 } 192 193 case *Map: 194 key := subst.typ(t.key) 195 elem := subst.typ(t.elem) 196 if key != t.key || elem != t.elem { 197 return &Map{key: key, elem: elem} 198 } 199 200 case *Chan: 201 elem := subst.typ(t.elem) 202 if elem != t.elem { 203 return &Chan{dir: t.dir, elem: elem} 204 } 205 206 case *Named: 207 // dump is for debugging 208 dump := func(string, ...interface{}) {} 209 if subst.check != nil && subst.check.conf._Trace { 210 subst.check.indent++ 211 defer func() { 212 subst.check.indent-- 213 }() 214 dump = func(format string, args ...interface{}) { 215 subst.check.trace(subst.pos, format, args...) 216 } 217 } 218 219 // subst is called during expansion, so in this function we need to be 220 // careful not to call any methods that would cause t to be expanded: doing 221 // so would result in deadlock. 222 // 223 // So we call t.Origin().TypeParams() rather than t.TypeParams(). 224 orig := t.Origin() 225 n := orig.TypeParams().Len() 226 if n == 0 { 227 dump(">>> %s is not parameterized", t) 228 return t // type is not parameterized 229 } 230 231 var newTArgs []Type 232 if t.TypeArgs().Len() != n { 233 return Typ[Invalid] // error reported elsewhere 234 } 235 236 // already instantiated 237 dump(">>> %s already instantiated", t) 238 // For each (existing) type argument targ, determine if it needs 239 // to be substituted; i.e., if it is or contains a type parameter 240 // that has a type argument for it. 241 for i, targ := range t.TypeArgs().list() { 242 dump(">>> %d targ = %s", i, targ) 243 new_targ := subst.typ(targ) 244 if new_targ != targ { 245 dump(">>> substituted %d targ %s => %s", i, targ, new_targ) 246 if newTArgs == nil { 247 newTArgs = make([]Type, n) 248 copy(newTArgs, t.TypeArgs().list()) 249 } 250 newTArgs[i] = new_targ 251 } 252 } 253 254 if newTArgs == nil { 255 dump(">>> nothing to substitute in %s", t) 256 return t // nothing to substitute 257 } 258 259 // Create a new instance and populate the context to avoid endless 260 // recursion. The position used here is irrelevant because validation only 261 // occurs on t (we don't call validType on named), but we use subst.pos to 262 // help with debugging. 263 return subst.check.instance(subst.pos, orig, newTArgs, subst.expanding, subst.ctxt) 264 265 case *TypeParam: 266 return subst.smap.lookup(t) 267 268 default: 269 unreachable() 270 } 271 272 return typ 273 } 274 275 // typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid]. 276 // A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_)) 277 // where an array/slice element is accessed before it is set up. 278 func (subst *subster) typOrNil(typ Type) Type { 279 if typ == nil { 280 return Typ[Invalid] 281 } 282 return subst.typ(typ) 283 } 284 285 func (subst *subster) var_(v *Var) *Var { 286 if v != nil { 287 if typ := subst.typ(v.typ); typ != v.typ { 288 return substVar(v, typ) 289 } 290 } 291 return v 292 } 293 294 func substVar(v *Var, typ Type) *Var { 295 copy := *v 296 copy.typ = typ 297 copy.origin = v.Origin() 298 return © 299 } 300 301 func (subst *subster) tuple(t *Tuple) *Tuple { 302 if t != nil { 303 if vars, copied := subst.varList(t.vars); copied { 304 return &Tuple{vars: vars} 305 } 306 } 307 return t 308 } 309 310 func (subst *subster) varList(in []*Var) (out []*Var, copied bool) { 311 out = in 312 for i, v := range in { 313 if w := subst.var_(v); w != v { 314 if !copied { 315 // first variable that got substituted => allocate new out slice 316 // and copy all variables 317 new := make([]*Var, len(in)) 318 copy(new, out) 319 out = new 320 copied = true 321 } 322 out[i] = w 323 } 324 } 325 return 326 } 327 328 func (subst *subster) func_(f *Func) *Func { 329 if f != nil { 330 if typ := subst.typ(f.typ); typ != f.typ { 331 return substFunc(f, typ) 332 } 333 } 334 return f 335 } 336 337 func substFunc(f *Func, typ Type) *Func { 338 copy := *f 339 copy.typ = typ 340 copy.origin = f.Origin() 341 return © 342 } 343 344 func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) { 345 out = in 346 for i, f := range in { 347 if g := subst.func_(f); g != f { 348 if !copied { 349 // first function that got substituted => allocate new out slice 350 // and copy all functions 351 new := make([]*Func, len(in)) 352 copy(new, out) 353 out = new 354 copied = true 355 } 356 out[i] = g 357 } 358 } 359 return 360 } 361 362 func (subst *subster) typeList(in []Type) (out []Type, copied bool) { 363 out = in 364 for i, t := range in { 365 if u := subst.typ(t); u != t { 366 if !copied { 367 // first function that got substituted => allocate new out slice 368 // and copy all functions 369 new := make([]Type, len(in)) 370 copy(new, out) 371 out = new 372 copied = true 373 } 374 out[i] = u 375 } 376 } 377 return 378 } 379 380 func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) { 381 out = in 382 for i, t := range in { 383 if u := subst.typ(t.typ); u != t.typ { 384 if !copied { 385 // first function that got substituted => allocate new out slice 386 // and copy all functions 387 new := make([]*Term, len(in)) 388 copy(new, out) 389 out = new 390 copied = true 391 } 392 out[i] = NewTerm(t.tilde, u) 393 } 394 } 395 return 396 } 397 398 // replaceRecvType updates any function receivers that have type old to have 399 // type new. It does not modify the input slice; if modifications are required, 400 // the input slice and any affected signatures will be copied before mutating. 401 // 402 // The resulting out slice contains the updated functions, and copied reports 403 // if anything was modified. 404 func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) { 405 out = in 406 for i, method := range in { 407 sig := method.Type().(*Signature) 408 if sig.recv != nil && sig.recv.Type() == old { 409 if !copied { 410 // Allocate a new methods slice before mutating for the first time. 411 // This is defensive, as we may share methods across instantiations of 412 // a given interface type if they do not get substituted. 413 out = make([]*Func, len(in)) 414 copy(out, in) 415 copied = true 416 } 417 newsig := *sig 418 newsig.recv = substVar(sig.recv, new) 419 out[i] = substFunc(method, &newsig) 420 } 421 } 422 return 423 }