github.com/bir3/gocompiler@v0.9.2202/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 "github.com/bir3/gocompiler/src/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.embedPos = t.embedPos 175 iface.implicit = t.implicit 176 assert(t.complete) // otherwise we are copying incomplete data 177 iface.complete = t.complete 178 // If we've changed the interface type, we may need to replace its 179 // receiver if the receiver type is the original interface. Receivers of 180 // *Named type are replaced during named type expansion. 181 // 182 // Notably, it's possible to reach here and not create a new *Interface, 183 // even though the receiver type may be parameterized. For example: 184 // 185 // type T[P any] interface{ m() } 186 // 187 // In this case the interface will not be substituted here, because its 188 // method signatures do not depend on the type parameter P, but we still 189 // need to create new interface methods to hold the instantiated 190 // receiver. This is handled by Named.expandUnderlying. 191 iface.methods, _ = replaceRecvType(methods, t, iface) 192 193 // If check != nil, check.newInterface will have saved the interface for later completion. 194 if subst.check == nil { // golang/go#61561: all newly created interfaces must be completed 195 iface.typeSet() 196 } 197 return iface 198 } 199 200 case *Map: 201 key := subst.typ(t.key) 202 elem := subst.typ(t.elem) 203 if key != t.key || elem != t.elem { 204 return &Map{key: key, elem: elem} 205 } 206 207 case *Chan: 208 elem := subst.typ(t.elem) 209 if elem != t.elem { 210 return &Chan{dir: t.dir, elem: elem} 211 } 212 213 case *Named: 214 // dump is for debugging 215 dump := func(string, ...interface{}) {} 216 if subst.check != nil && subst.check.conf._Trace { 217 subst.check.indent++ 218 defer func() { 219 subst.check.indent-- 220 }() 221 dump = func(format string, args ...interface{}) { 222 subst.check.trace(subst.pos, format, args...) 223 } 224 } 225 226 // subst is called during expansion, so in this function we need to be 227 // careful not to call any methods that would cause t to be expanded: doing 228 // so would result in deadlock. 229 // 230 // So we call t.Origin().TypeParams() rather than t.TypeParams(). 231 orig := t.Origin() 232 n := orig.TypeParams().Len() 233 if n == 0 { 234 dump(">>> %s is not parameterized", t) 235 return t // type is not parameterized 236 } 237 238 var newTArgs []Type 239 if t.TypeArgs().Len() != n { 240 return Typ[Invalid] // error reported elsewhere 241 } 242 243 // already instantiated 244 dump(">>> %s already instantiated", t) 245 // For each (existing) type argument targ, determine if it needs 246 // to be substituted; i.e., if it is or contains a type parameter 247 // that has a type argument for it. 248 for i, targ := range t.TypeArgs().list() { 249 dump(">>> %d targ = %s", i, targ) 250 new_targ := subst.typ(targ) 251 if new_targ != targ { 252 dump(">>> substituted %d targ %s => %s", i, targ, new_targ) 253 if newTArgs == nil { 254 newTArgs = make([]Type, n) 255 copy(newTArgs, t.TypeArgs().list()) 256 } 257 newTArgs[i] = new_targ 258 } 259 } 260 261 if newTArgs == nil { 262 dump(">>> nothing to substitute in %s", t) 263 return t // nothing to substitute 264 } 265 266 // Create a new instance and populate the context to avoid endless 267 // recursion. The position used here is irrelevant because validation only 268 // occurs on t (we don't call validType on named), but we use subst.pos to 269 // help with debugging. 270 return subst.check.instance(subst.pos, orig, newTArgs, subst.expanding, subst.ctxt) 271 272 case *TypeParam: 273 return subst.smap.lookup(t) 274 275 default: 276 unreachable() 277 } 278 279 return typ 280 } 281 282 // typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid]. 283 // A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_)) 284 // where an array/slice element is accessed before it is set up. 285 func (subst *subster) typOrNil(typ Type) Type { 286 if typ == nil { 287 return Typ[Invalid] 288 } 289 return subst.typ(typ) 290 } 291 292 func (subst *subster) var_(v *Var) *Var { 293 if v != nil { 294 if typ := subst.typ(v.typ); typ != v.typ { 295 return substVar(v, typ) 296 } 297 } 298 return v 299 } 300 301 func substVar(v *Var, typ Type) *Var { 302 copy := *v 303 copy.typ = typ 304 copy.origin = v.Origin() 305 return © 306 } 307 308 func (subst *subster) tuple(t *Tuple) *Tuple { 309 if t != nil { 310 if vars, copied := subst.varList(t.vars); copied { 311 return &Tuple{vars: vars} 312 } 313 } 314 return t 315 } 316 317 func (subst *subster) varList(in []*Var) (out []*Var, copied bool) { 318 out = in 319 for i, v := range in { 320 if w := subst.var_(v); w != v { 321 if !copied { 322 // first variable that got substituted => allocate new out slice 323 // and copy all variables 324 new := make([]*Var, len(in)) 325 copy(new, out) 326 out = new 327 copied = true 328 } 329 out[i] = w 330 } 331 } 332 return 333 } 334 335 func (subst *subster) func_(f *Func) *Func { 336 if f != nil { 337 if typ := subst.typ(f.typ); typ != f.typ { 338 return substFunc(f, typ) 339 } 340 } 341 return f 342 } 343 344 func substFunc(f *Func, typ Type) *Func { 345 copy := *f 346 copy.typ = typ 347 copy.origin = f.Origin() 348 return © 349 } 350 351 func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) { 352 out = in 353 for i, f := range in { 354 if g := subst.func_(f); g != f { 355 if !copied { 356 // first function that got substituted => allocate new out slice 357 // and copy all functions 358 new := make([]*Func, len(in)) 359 copy(new, out) 360 out = new 361 copied = true 362 } 363 out[i] = g 364 } 365 } 366 return 367 } 368 369 func (subst *subster) typeList(in []Type) (out []Type, copied bool) { 370 out = in 371 for i, t := range in { 372 if u := subst.typ(t); u != t { 373 if !copied { 374 // first function that got substituted => allocate new out slice 375 // and copy all functions 376 new := make([]Type, len(in)) 377 copy(new, out) 378 out = new 379 copied = true 380 } 381 out[i] = u 382 } 383 } 384 return 385 } 386 387 func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) { 388 out = in 389 for i, t := range in { 390 if u := subst.typ(t.typ); u != t.typ { 391 if !copied { 392 // first function that got substituted => allocate new out slice 393 // and copy all functions 394 new := make([]*Term, len(in)) 395 copy(new, out) 396 out = new 397 copied = true 398 } 399 out[i] = NewTerm(t.tilde, u) 400 } 401 } 402 return 403 } 404 405 // replaceRecvType updates any function receivers that have type old to have 406 // type new. It does not modify the input slice; if modifications are required, 407 // the input slice and any affected signatures will be copied before mutating. 408 // 409 // The resulting out slice contains the updated functions, and copied reports 410 // if anything was modified. 411 func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) { 412 out = in 413 for i, method := range in { 414 sig := method.Type().(*Signature) 415 if sig.recv != nil && sig.recv.Type() == old { 416 if !copied { 417 // Allocate a new methods slice before mutating for the first time. 418 // This is defensive, as we may share methods across instantiations of 419 // a given interface type if they do not get substituted. 420 out = make([]*Func, len(in)) 421 copy(out, in) 422 copied = true 423 } 424 newsig := *sig 425 newsig.recv = substVar(sig.recv, new) 426 out[i] = substFunc(method, &newsig) 427 } 428 } 429 return 430 }