github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/noder/stencil.go (about) 1 // Copyright 2021 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 // This file will evolve, since we plan to do a mix of stenciling and passing 6 // around dictionaries. 7 8 package noder 9 10 import ( 11 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 12 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 13 "github.com/bir3/gocompiler/src/cmd/compile/internal/objw" 14 "github.com/bir3/gocompiler/src/cmd/compile/internal/reflectdata" 15 "github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck" 16 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 17 "github.com/bir3/gocompiler/src/cmd/internal/obj" 18 "github.com/bir3/gocompiler/src/cmd/internal/src" 19 "fmt" 20 "github.com/bir3/gocompiler/src/go/constant" 21 ) 22 23 // Enable extra consistency checks. 24 const doubleCheck = false 25 26 func assert(p bool) { 27 base.Assert(p) 28 } 29 30 // For outputting debug information on dictionary format and instantiated dictionaries 31 // (type arg, derived types, sub-dictionary, and itab entries). 32 var infoPrintMode = false 33 34 func infoPrint(format string, a ...interface{}) { 35 if infoPrintMode { 36 fmt.Printf(format, a...) 37 } 38 } 39 40 var geninst genInst 41 42 func BuildInstantiations() { 43 geninst.instInfoMap = make(map[*types.Sym]*instInfo) 44 geninst.buildInstantiations() 45 geninst.instInfoMap = nil 46 } 47 48 // buildInstantiations scans functions for generic function calls and methods, and 49 // creates the required instantiations. It also creates instantiated methods for all 50 // fully-instantiated generic types that have been encountered already or new ones 51 // that are encountered during the instantiation process. It scans all declarations 52 // in typecheck.Target.Decls first, before scanning any new instantiations created. 53 func (g *genInst) buildInstantiations() { 54 // Instantiate the methods of instantiated generic types that we have seen so far. 55 g.instantiateMethods() 56 57 // Scan all currentdecls for call to generic functions/methods. 58 n := len(typecheck.Target.Decls) 59 for i := 0; i < n; i++ { 60 g.scanForGenCalls(typecheck.Target.Decls[i]) 61 } 62 63 // Scan all new instantiations created due to g.instantiateMethods() and the 64 // scan of current decls. This loop purposely runs until no new 65 // instantiations are created. 66 for i := 0; i < len(g.newInsts); i++ { 67 g.scanForGenCalls(g.newInsts[i]) 68 } 69 70 g.finalizeSyms() 71 72 // All the instantiations and dictionaries have been created. Now go through 73 // each new instantiation and transform the various operations that need to make 74 // use of their dictionary. 75 l := len(g.newInsts) 76 for _, fun := range g.newInsts { 77 info := g.instInfoMap[fun.Sym()] 78 g.dictPass(info) 79 if doubleCheck { 80 ir.Visit(info.fun, func(n ir.Node) { 81 if n.Op() != ir.OCONVIFACE { 82 return 83 } 84 c := n.(*ir.ConvExpr) 85 if c.X.Type().HasShape() && !c.X.Type().IsInterface() { 86 ir.Dump("BAD FUNCTION", info.fun) 87 ir.Dump("BAD CONVERSION", c) 88 base.Fatalf("converting shape type to interface") 89 } 90 }) 91 } 92 if base.Flag.W > 1 { 93 ir.Dump(fmt.Sprintf("\ndictpass %v", info.fun), info.fun) 94 } 95 } 96 assert(l == len(g.newInsts)) 97 g.newInsts = nil 98 } 99 100 // scanForGenCalls scans a single function (or global assignment), looking for 101 // references to generic functions/methods. At each such reference, it creates any 102 // required instantiation and transforms the reference. 103 func (g *genInst) scanForGenCalls(decl ir.Node) { 104 switch decl.Op() { 105 case ir.ODCLFUNC: 106 if decl.Type().HasTParam() { 107 // Skip any generic functions 108 return 109 } 110 // transformCall() below depends on CurFunc being set. 111 ir.CurFunc = decl.(*ir.Func) 112 113 case ir.OAS, ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV, ir.OASOP: 114 // These are all the various kinds of global assignments, 115 // whose right-hand-sides might contain a function 116 // instantiation. 117 118 default: 119 // The other possible ops at the top level are ODCLCONST 120 // and ODCLTYPE, which don't have any function 121 // instantiations. 122 return 123 } 124 125 // Search for any function references using generic function/methods. Then 126 // create the needed instantiated function if it hasn't been created yet, and 127 // change to calling that function directly. 128 modified := false 129 closureRequired := false 130 // declInfo will be non-nil exactly if we are scanning an instantiated function 131 declInfo := g.instInfoMap[decl.Sym()] 132 133 ir.Visit(decl, func(n ir.Node) { 134 if n.Op() == ir.OFUNCINST { 135 // generic F, not immediately called 136 closureRequired = true 137 } 138 if (n.Op() == ir.OMETHEXPR || n.Op() == ir.OMETHVALUE) && len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) { 139 // T.M or x.M, where T or x is generic, but not immediately 140 // called. Not necessary if the method selected is 141 // actually for an embedded interface field. 142 closureRequired = true 143 } 144 if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST { 145 // We have found a function call using a generic function 146 // instantiation. 147 call := n.(*ir.CallExpr) 148 inst := call.X.(*ir.InstExpr) 149 nameNode, isMeth := g.getInstNameNode(inst) 150 targs := typecheck.TypesOf(inst.Targs) 151 st := g.getInstantiation(nameNode, targs, isMeth).fun 152 dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, nameNode, targs, isMeth) 153 if infoPrintMode { 154 dictkind := "Main dictionary" 155 if usingSubdict { 156 dictkind = "Sub-dictionary" 157 } 158 if inst.X.Op() == ir.OMETHVALUE { 159 fmt.Printf("%s in %v at generic method call: %v - %v\n", dictkind, decl, inst.X, call) 160 } else { 161 fmt.Printf("%s in %v at generic function call: %v - %v\n", dictkind, decl, inst.X, call) 162 } 163 } 164 165 // Transform the Call now, which changes OCALL to 166 // OCALLFUNC and does typecheckaste/assignconvfn. Do 167 // it before installing the instantiation, so we are 168 // checking against non-shape param types in 169 // typecheckaste. 170 transformCall(call) 171 172 // Replace the OFUNCINST with a direct reference to the 173 // new stenciled function 174 call.X = st.Nname 175 if inst.X.Op() == ir.OMETHVALUE { 176 // When we create an instantiation of a method 177 // call, we make it a function. So, move the 178 // receiver to be the first arg of the function 179 // call. 180 call.Args.Prepend(inst.X.(*ir.SelectorExpr).X) 181 } 182 183 // Add dictionary to argument list. 184 call.Args.Prepend(dictValue) 185 modified = true 186 } 187 if n.Op() == ir.OCALLMETH && n.(*ir.CallExpr).X.Op() == ir.ODOTMETH && len(deref(n.(*ir.CallExpr).X.Type().Recv().Type).RParams()) > 0 { 188 // Method call on a generic type, which was instantiated by stenciling. 189 // Method calls on explicitly instantiated types will have an OFUNCINST 190 // and are handled above. 191 call := n.(*ir.CallExpr) 192 meth := call.X.(*ir.SelectorExpr) 193 targs := deref(meth.Type().Recv().Type).RParams() 194 195 t := meth.X.Type() 196 baseType := deref(t).OrigType() 197 var gf *ir.Name 198 for _, m := range baseType.Methods().Slice() { 199 if meth.Sel == m.Sym { 200 gf = m.Nname.(*ir.Name) 201 break 202 } 203 } 204 205 // Transform the Call now, which changes OCALL 206 // to OCALLFUNC and does typecheckaste/assignconvfn. 207 transformCall(call) 208 209 st := g.getInstantiation(gf, targs, true).fun 210 dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true) 211 if hasShapeTypes(targs) { 212 // We have to be using a subdictionary, since this is 213 // a generic method call. 214 assert(usingSubdict) 215 } else { 216 // We should use main dictionary, because the receiver is 217 // an instantiation already, see issue #53406. 218 assert(!usingSubdict) 219 } 220 221 // Transform to a function call, by appending the 222 // dictionary and the receiver to the args. 223 call.SetOp(ir.OCALLFUNC) 224 call.X = st.Nname 225 call.Args.Prepend(dictValue, meth.X) 226 modified = true 227 } 228 }) 229 230 // If we found a reference to a generic instantiation that wasn't an 231 // immediate call, then traverse the nodes of decl again (with 232 // EditChildren rather than Visit), where we actually change the 233 // reference to the instantiation to a closure that captures the 234 // dictionary, then does a direct call. 235 // EditChildren is more expensive than Visit, so we only do this 236 // in the infrequent case of an OFUNCINST without a corresponding 237 // call. 238 if closureRequired { 239 modified = true 240 var edit func(ir.Node) ir.Node 241 var outer *ir.Func 242 if f, ok := decl.(*ir.Func); ok { 243 outer = f 244 } 245 edit = func(x ir.Node) ir.Node { 246 if x.Op() == ir.OFUNCINST { 247 child := x.(*ir.InstExpr).X 248 if child.Op() == ir.OMETHEXPR || child.Op() == ir.OMETHVALUE { 249 // Call EditChildren on child (x.X), 250 // not x, so that we don't do 251 // buildClosure() on the 252 // METHEXPR/METHVALUE nodes as well. 253 ir.EditChildren(child, edit) 254 return g.buildClosure(outer, x) 255 } 256 } 257 ir.EditChildren(x, edit) 258 switch { 259 case x.Op() == ir.OFUNCINST: 260 return g.buildClosure(outer, x) 261 case (x.Op() == ir.OMETHEXPR || x.Op() == ir.OMETHVALUE) && 262 len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && 263 !types.IsInterfaceMethod(x.(*ir.SelectorExpr).Selection.Type): 264 return g.buildClosure(outer, x) 265 } 266 return x 267 } 268 edit(decl) 269 } 270 if base.Flag.W > 1 && modified { 271 ir.Dump(fmt.Sprintf("\nmodified %v", decl), decl) 272 } 273 ir.CurFunc = nil 274 // We may have seen new fully-instantiated generic types while 275 // instantiating any needed functions/methods in the above 276 // function. If so, instantiate all the methods of those types 277 // (which will then lead to more function/methods to scan in the loop). 278 g.instantiateMethods() 279 } 280 281 // buildClosure makes a closure to implement x, a OFUNCINST or OMETHEXPR/OMETHVALUE 282 // of generic type. outer is the containing function (or nil if closure is 283 // in a global assignment instead of a function). 284 func (g *genInst) buildClosure(outer *ir.Func, x ir.Node) ir.Node { 285 pos := x.Pos() 286 var target *ir.Func // target instantiated function/method 287 var dictValue ir.Node // dictionary to use 288 var rcvrValue ir.Node // receiver, if a method value 289 typ := x.Type() // type of the closure 290 var outerInfo *instInfo 291 if outer != nil { 292 outerInfo = g.instInfoMap[outer.Sym()] 293 } 294 usingSubdict := false 295 valueMethod := false 296 if x.Op() == ir.OFUNCINST { 297 inst := x.(*ir.InstExpr) 298 299 // Type arguments we're instantiating with. 300 targs := typecheck.TypesOf(inst.Targs) 301 302 // Find the generic function/method. 303 var gf *ir.Name 304 if inst.X.Op() == ir.ONAME { 305 // Instantiating a generic function call. 306 gf = inst.X.(*ir.Name) 307 } else if inst.X.Op() == ir.OMETHVALUE { 308 // Instantiating a method value x.M. 309 se := inst.X.(*ir.SelectorExpr) 310 rcvrValue = se.X 311 gf = se.Selection.Nname.(*ir.Name) 312 } else { 313 panic("unhandled") 314 } 315 316 // target is the instantiated function we're trying to call. 317 // For functions, the target expects a dictionary as its first argument. 318 // For method values, the target expects a dictionary and the receiver 319 // as its first two arguments. 320 // dictValue is the value to use for the dictionary argument. 321 target = g.getInstantiation(gf, targs, rcvrValue != nil).fun 322 dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, rcvrValue != nil) 323 if infoPrintMode { 324 dictkind := "Main dictionary" 325 if usingSubdict { 326 dictkind = "Sub-dictionary" 327 } 328 if rcvrValue == nil { 329 fmt.Printf("%s in %v for generic function value %v\n", dictkind, outer, inst.X) 330 } else { 331 fmt.Printf("%s in %v for generic method value %v\n", dictkind, outer, inst.X) 332 } 333 } 334 } else { // ir.OMETHEXPR or ir.METHVALUE 335 // Method expression T.M where T is a generic type. 336 se := x.(*ir.SelectorExpr) 337 if x.Op() == ir.OMETHVALUE { 338 rcvrValue = se.X 339 } 340 341 // se.X.Type() is the top-level type of the method expression. To 342 // correctly handle method expressions involving embedded fields, 343 // look up the generic method below using the type of the receiver 344 // of se.Selection, since that will be the type that actually has 345 // the method. 346 recv := deref(se.Selection.Type.Recv().Type) 347 targs := recv.RParams() 348 if len(targs) == 0 { 349 // The embedded type that actually has the method is not 350 // actually generic, so no need to build a closure. 351 return x 352 } 353 baseType := recv.OrigType() 354 var gf *ir.Name 355 for _, m := range baseType.Methods().Slice() { 356 if se.Sel == m.Sym { 357 gf = m.Nname.(*ir.Name) 358 break 359 } 360 } 361 if !gf.Type().Recv().Type.IsPtr() { 362 // Remember if value method, so we can detect (*T).M case. 363 valueMethod = true 364 } 365 target = g.getInstantiation(gf, targs, true).fun 366 dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, true) 367 if infoPrintMode { 368 dictkind := "Main dictionary" 369 if usingSubdict { 370 dictkind = "Sub-dictionary" 371 } 372 fmt.Printf("%s in %v for method expression %v\n", dictkind, outer, x) 373 } 374 } 375 376 // Build a closure to implement a function instantiation. 377 // 378 // func f[T any] (int, int) (int, int) { ...whatever... } 379 // 380 // Then any reference to f[int] not directly called gets rewritten to 381 // 382 // .dictN := ... dictionary to use ... 383 // func(a0, a1 int) (r0, r1 int) { 384 // return .inst.f[int](.dictN, a0, a1) 385 // } 386 // 387 // Similarly for method expressions, 388 // 389 // type g[T any] .... 390 // func (rcvr g[T]) f(a0, a1 int) (r0, r1 int) { ... } 391 // 392 // Any reference to g[int].f not directly called gets rewritten to 393 // 394 // .dictN := ... dictionary to use ... 395 // func(rcvr g[int], a0, a1 int) (r0, r1 int) { 396 // return .inst.g[int].f(.dictN, rcvr, a0, a1) 397 // } 398 // 399 // Also method values 400 // 401 // var x g[int] 402 // 403 // Any reference to x.f not directly called gets rewritten to 404 // 405 // .dictN := ... dictionary to use ... 406 // x2 := x 407 // func(a0, a1 int) (r0, r1 int) { 408 // return .inst.g[int].f(.dictN, x2, a0, a1) 409 // } 410 411 // Make a new internal function. 412 fn, formalParams, formalResults := startClosure(pos, outer, typ) 413 fn.SetWrapper(true) // See issue 52237 414 415 // This is the dictionary we want to use. 416 // It may be a constant, it may be the outer functions's dictionary, or it may be 417 // a subdictionary acquired from the outer function's dictionary. 418 // For the latter, dictVar is a variable in the outer function's scope, set to the subdictionary 419 // read from the outer function's dictionary. 420 var dictVar *ir.Name 421 var dictAssign *ir.AssignStmt 422 if outer != nil { 423 dictVar = ir.NewNameAt(pos, closureSym(outer, typecheck.LocalDictName, g.dnum)) 424 g.dnum++ 425 dictVar.Class = ir.PAUTO 426 typed(types.Types[types.TUINTPTR], dictVar) 427 dictVar.Curfn = outer 428 dictAssign = ir.NewAssignStmt(pos, dictVar, dictValue) 429 dictAssign.SetTypecheck(1) 430 dictVar.Defn = dictAssign 431 outer.Dcl = append(outer.Dcl, dictVar) 432 } 433 // assign the receiver to a temporary. 434 var rcvrVar *ir.Name 435 var rcvrAssign ir.Node 436 if rcvrValue != nil { 437 rcvrVar = ir.NewNameAt(pos, closureSym(outer, ".rcvr", g.dnum)) 438 g.dnum++ 439 typed(rcvrValue.Type(), rcvrVar) 440 rcvrAssign = ir.NewAssignStmt(pos, rcvrVar, rcvrValue) 441 rcvrAssign.SetTypecheck(1) 442 rcvrVar.Defn = rcvrAssign 443 if outer == nil { 444 rcvrVar.Class = ir.PEXTERN 445 typecheck.Target.Decls = append(typecheck.Target.Decls, rcvrAssign) 446 typecheck.Target.Externs = append(typecheck.Target.Externs, rcvrVar) 447 } else { 448 rcvrVar.Class = ir.PAUTO 449 rcvrVar.Curfn = outer 450 outer.Dcl = append(outer.Dcl, rcvrVar) 451 } 452 } 453 454 // Build body of closure. This involves just calling the wrapped function directly 455 // with the additional dictionary argument. 456 457 // First, figure out the dictionary argument. 458 var dict2Var ir.Node 459 if usingSubdict { 460 // Capture sub-dictionary calculated in the outer function 461 dict2Var = ir.CaptureName(pos, fn, dictVar) 462 typed(types.Types[types.TUINTPTR], dict2Var) 463 } else { 464 // Static dictionary, so can be used directly in the closure 465 dict2Var = dictValue 466 } 467 // Also capture the receiver variable. 468 var rcvr2Var *ir.Name 469 if rcvrValue != nil { 470 rcvr2Var = ir.CaptureName(pos, fn, rcvrVar) 471 } 472 473 // Build arguments to call inside the closure. 474 var args []ir.Node 475 476 // First the dictionary argument. 477 args = append(args, dict2Var) 478 // Then the receiver. 479 if rcvrValue != nil { 480 args = append(args, rcvr2Var) 481 } 482 // Then all the other arguments (including receiver for method expressions). 483 for i := 0; i < typ.NumParams(); i++ { 484 if x.Op() == ir.OMETHEXPR && i == 0 { 485 // If we are doing a method expression, we need to 486 // explicitly traverse any embedded fields in the receiver 487 // argument in order to call the method instantiation. 488 arg0 := formalParams[0].Nname.(ir.Node) 489 arg0 = typecheck.AddImplicitDots(ir.NewSelectorExpr(x.Pos(), ir.OXDOT, arg0, x.(*ir.SelectorExpr).Sel)).X 490 if valueMethod && arg0.Type().IsPtr() { 491 // For handling the (*T).M case: if we have a pointer 492 // receiver after following all the embedded fields, 493 // but it's a value method, add a star operator. 494 arg0 = ir.NewStarExpr(arg0.Pos(), arg0) 495 } 496 args = append(args, arg0) 497 } else { 498 args = append(args, formalParams[i].Nname.(*ir.Name)) 499 } 500 } 501 502 // Build call itself. 503 var innerCall ir.Node = ir.NewCallExpr(pos, ir.OCALL, target.Nname, args) 504 innerCall.(*ir.CallExpr).IsDDD = typ.IsVariadic() 505 if len(formalResults) > 0 { 506 innerCall = ir.NewReturnStmt(pos, []ir.Node{innerCall}) 507 } 508 // Finish building body of closure. 509 ir.CurFunc = fn 510 // TODO: set types directly here instead of using typecheck.Stmt 511 typecheck.Stmt(innerCall) 512 ir.CurFunc = nil 513 fn.Body = []ir.Node{innerCall} 514 515 // We're all done with the captured dictionary (and receiver, for method values). 516 ir.FinishCaptureNames(pos, outer, fn) 517 518 // Make a closure referencing our new internal function. 519 c := ir.UseClosure(fn.OClosure, typecheck.Target) 520 var init []ir.Node 521 if outer != nil { 522 init = append(init, dictAssign) 523 } 524 if rcvrValue != nil { 525 init = append(init, rcvrAssign) 526 } 527 return ir.InitExpr(init, c) 528 } 529 530 // instantiateMethods instantiates all the methods (and associated dictionaries) of 531 // all fully-instantiated generic types that have been added to typecheck.instTypeList. 532 // It continues until no more types are added to typecheck.instTypeList. 533 func (g *genInst) instantiateMethods() { 534 for { 535 instTypeList := typecheck.GetInstTypeList() 536 if len(instTypeList) == 0 { 537 break 538 } 539 typecheck.ClearInstTypeList() 540 for _, typ := range instTypeList { 541 assert(!typ.HasShape()) 542 // Mark runtime type as needed, since this ensures that the 543 // compiler puts out the needed DWARF symbols, when this 544 // instantiated type has a different package from the local 545 // package. 546 typecheck.NeedRuntimeType(typ) 547 // Lookup the method on the base generic type, since methods may 548 // not be set on imported instantiated types. 549 baseType := typ.OrigType() 550 for j := range typ.Methods().Slice() { 551 if baseType.Methods().Slice()[j].Nointerface() { 552 typ.Methods().Slice()[j].SetNointerface(true) 553 } 554 baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name) 555 // Eagerly generate the instantiations and dictionaries that implement these methods. 556 // We don't use the instantiations here, just generate them (and any 557 // further instantiations those generate, etc.). 558 // Note that we don't set the Func for any methods on instantiated 559 // types. Their signatures don't match so that would be confusing. 560 // Direct method calls go directly to the instantiations, implemented above. 561 // Indirect method calls use wrappers generated in reflectcall. Those wrappers 562 // will use these instantiations if they are needed (for interface tables or reflection). 563 _ = g.getInstantiation(baseNname, typ.RParams(), true) 564 _ = g.getDictionarySym(baseNname, typ.RParams(), true) 565 } 566 } 567 } 568 } 569 570 // getInstNameNode returns the name node for the method or function being instantiated, and a bool which is true if a method is being instantiated. 571 func (g *genInst) getInstNameNode(inst *ir.InstExpr) (*ir.Name, bool) { 572 if meth, ok := inst.X.(*ir.SelectorExpr); ok { 573 return meth.Selection.Nname.(*ir.Name), true 574 } else { 575 return inst.X.(*ir.Name), false 576 } 577 } 578 579 // getDictOrSubdict returns, for a method/function call or reference (node n) in an 580 // instantiation (described by instInfo), a node which is accessing a sub-dictionary 581 // or main/static dictionary, as needed, and also returns a boolean indicating if a 582 // sub-dictionary was accessed. nameNode is the particular function or method being 583 // called/referenced, and targs are the type arguments. 584 func (g *genInst) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Name, targs []*types.Type, isMeth bool) (ir.Node, bool) { 585 var dict ir.Node 586 usingSubdict := false 587 if declInfo != nil { 588 entry := -1 589 for i, de := range declInfo.dictInfo.subDictCalls { 590 if n == de.callNode { 591 entry = declInfo.dictInfo.startSubDict + i 592 break 593 } 594 } 595 // If the entry is not found, it may be that this node did not have 596 // any type args that depend on type params, so we need a main 597 // dictionary, not a sub-dictionary. 598 if entry >= 0 { 599 dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictInfo.dictLen) 600 usingSubdict = true 601 } 602 } 603 if !usingSubdict { 604 dict = g.getDictionaryValue(n.Pos(), nameNode, targs, isMeth) 605 } 606 return dict, usingSubdict 607 } 608 609 // checkFetchBody checks if a generic body can be fetched, but hasn't been loaded 610 // yet. If so, it imports the body. 611 func checkFetchBody(nameNode *ir.Name) { 612 if nameNode.Func.Body == nil && nameNode.Func.Inl != nil { 613 // If there is no body yet but Func.Inl exists, then we can 614 // import the whole generic body. 615 assert(nameNode.Func.Inl.Cost == 1 && nameNode.Sym().Pkg != types.LocalPkg) 616 typecheck.ImportBody(nameNode.Func) 617 assert(nameNode.Func.Inl.Body != nil) 618 nameNode.Func.Body = nameNode.Func.Inl.Body 619 nameNode.Func.Dcl = nameNode.Func.Inl.Dcl 620 } 621 } 622 623 // getInstantiation gets the instantiation and dictionary of the function or method nameNode 624 // with the type arguments shapes. If the instantiated function is not already 625 // cached, then it calls genericSubst to create the new instantiation. 626 func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMeth bool) *instInfo { 627 if nameNode.Func == nil { 628 // If nameNode.Func is nil, this must be a reference to a method of 629 // an imported instantiated type. We will have already called 630 // g.instantiateMethods() on the fully-instantiated type, so 631 // g.instInfoMap[sym] will be non-nil below. 632 rcvr := nameNode.Type().Recv() 633 if rcvr == nil || !deref(rcvr.Type).IsFullyInstantiated() { 634 base.FatalfAt(nameNode.Pos(), "Unexpected function instantiation %v with no body", nameNode) 635 } 636 } else { 637 checkFetchBody(nameNode) 638 } 639 640 var tparams []*types.Type 641 if isMeth { 642 // Get the type params from the method receiver (after skipping 643 // over any pointer) 644 recvType := nameNode.Type().Recv().Type 645 recvType = deref(recvType) 646 if recvType.IsFullyInstantiated() { 647 // Get the type of the base generic type, so we get 648 // its original typeparams. 649 recvType = recvType.OrigType() 650 } 651 tparams = recvType.RParams() 652 } else { 653 fields := nameNode.Type().TParams().Fields().Slice() 654 tparams = make([]*types.Type, len(fields)) 655 for i, f := range fields { 656 tparams[i] = f.Type 657 } 658 } 659 660 // Convert any non-shape type arguments to their shape, so we can reduce the 661 // number of instantiations we have to generate. You can actually have a mix 662 // of shape and non-shape arguments, because of inferred or explicitly 663 // specified concrete type args. 664 s1 := make([]*types.Type, len(shapes)) 665 for i, t := range shapes { 666 var tparam *types.Type 667 // Shapes are grouped differently for structural types, so we 668 // pass the type param to Shapify(), so we can distinguish. 669 tparam = tparams[i] 670 if !t.IsShape() { 671 s1[i] = typecheck.Shapify(t, i, tparam) 672 } else { 673 // Already a shape, but make sure it has the correct index. 674 s1[i] = typecheck.Shapify(shapes[i].Underlying(), i, tparam) 675 } 676 } 677 shapes = s1 678 679 sym := typecheck.MakeFuncInstSym(nameNode.Sym(), shapes, false, isMeth) 680 info := g.instInfoMap[sym] 681 if info == nil { 682 // If instantiation doesn't exist yet, create it and add 683 // to the list of decls. 684 info = &instInfo{ 685 dictInfo: &dictInfo{}, 686 } 687 info.dictInfo.shapeToBound = make(map[*types.Type]*types.Type) 688 689 if sym.Def != nil { 690 // This instantiation must have been imported from another 691 // package (because it was needed for inlining), so we should 692 // not re-generate it and have conflicting definitions for the 693 // symbol (issue #50121). It will have already gone through the 694 // dictionary transformations of dictPass, so we don't actually 695 // need the info.dictParam and info.shapeToBound info filled in 696 // below. We just set the imported instantiation as info.fun. 697 assert(sym.Pkg != types.LocalPkg) 698 info.fun = sym.Def.(*ir.Name).Func 699 assert(info.fun != nil) 700 g.instInfoMap[sym] = info 701 return info 702 } 703 704 // genericSubst fills in info.dictParam and info.shapeToBound. 705 st := g.genericSubst(sym, nameNode, tparams, shapes, isMeth, info) 706 info.fun = st 707 g.instInfoMap[sym] = info 708 709 // getInstInfo fills in info.dictInfo. 710 g.getInstInfo(st, shapes, info) 711 if base.Flag.W > 1 { 712 ir.Dump(fmt.Sprintf("\nstenciled %v", st), st) 713 } 714 715 // This ensures that the linker drops duplicates of this instantiation. 716 // All just works! 717 st.SetDupok(true) 718 typecheck.Target.Decls = append(typecheck.Target.Decls, st) 719 g.newInsts = append(g.newInsts, st) 720 } 721 return info 722 } 723 724 // Struct containing info needed for doing the substitution as we create the 725 // instantiation of a generic function with specified type arguments. 726 type subster struct { 727 g *genInst 728 isMethod bool // If a method is being instantiated 729 newf *ir.Func // Func node for the new stenciled function 730 ts typecheck.Tsubster 731 info *instInfo // Place to put extra info in the instantiation 732 skipClosure bool // Skip substituting closures 733 734 // Map from non-nil, non-ONAME node n to slice of all m, where m.Defn = n 735 defnMap map[ir.Node][]**ir.Name 736 } 737 738 // genericSubst returns a new function with name newsym. The function is an 739 // instantiation of a generic function or method specified by namedNode with type 740 // args shapes. For a method with a generic receiver, it returns an instantiated 741 // function type where the receiver becomes the first parameter. For either a generic 742 // method or function, a dictionary parameter is the added as the very first 743 // parameter. genericSubst fills in info.dictParam and info.shapeToBound. 744 func (g *genInst) genericSubst(newsym *types.Sym, nameNode *ir.Name, tparams []*types.Type, shapes []*types.Type, isMethod bool, info *instInfo) *ir.Func { 745 gf := nameNode.Func 746 // Pos of the instantiated function is same as the generic function 747 newf := ir.NewFunc(gf.Pos()) 748 newf.Pragma = gf.Pragma // copy over pragmas from generic function to stenciled implementation. 749 newf.Endlineno = gf.Endlineno 750 newf.Nname = ir.NewNameAt(gf.Pos(), newsym) 751 newf.Nname.Func = newf 752 newf.Nname.Defn = newf 753 newsym.Def = newf.Nname 754 savef := ir.CurFunc 755 // transformCall/transformReturn (called during stenciling of the body) 756 // depend on ir.CurFunc being set. 757 ir.CurFunc = newf 758 759 assert(len(tparams) == len(shapes)) 760 761 subst := &subster{ 762 g: g, 763 isMethod: isMethod, 764 newf: newf, 765 info: info, 766 ts: typecheck.Tsubster{ 767 Tparams: tparams, 768 Targs: shapes, 769 Vars: make(map[*ir.Name]*ir.Name), 770 }, 771 defnMap: make(map[ir.Node][]**ir.Name), 772 } 773 774 newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1) 775 776 // Create the needed dictionary param 777 dictionarySym := newsym.Pkg.Lookup(typecheck.LocalDictName) 778 dictionaryType := types.Types[types.TUINTPTR] 779 dictionaryName := ir.NewNameAt(gf.Pos(), dictionarySym) 780 typed(dictionaryType, dictionaryName) 781 dictionaryName.Class = ir.PPARAM 782 dictionaryName.Curfn = newf 783 newf.Dcl = append(newf.Dcl, dictionaryName) 784 for _, n := range gf.Dcl { 785 if n.Sym().Name == typecheck.LocalDictName { 786 panic("already has dictionary") 787 } 788 newf.Dcl = append(newf.Dcl, subst.localvar(n)) 789 } 790 dictionaryArg := types.NewField(gf.Pos(), dictionarySym, dictionaryType) 791 dictionaryArg.Nname = dictionaryName 792 info.dictParam = dictionaryName 793 794 // We add the dictionary as the first parameter in the function signature. 795 // We also transform a method type to the corresponding function type 796 // (make the receiver be the next parameter after the dictionary). 797 oldt := nameNode.Type() 798 var args []*types.Field 799 args = append(args, dictionaryArg) 800 args = append(args, oldt.Recvs().FieldSlice()...) 801 args = append(args, oldt.Params().FieldSlice()...) 802 803 // Replace the types in the function signature via subst.fields. 804 // Ugly: also, we have to insert the Name nodes of the parameters/results into 805 // the function type. The current function type has no Nname fields set, 806 // because it came via conversion from the types2 type. 807 newt := types.NewSignature(oldt.Pkg(), nil, nil, 808 subst.fields(ir.PPARAM, args, newf.Dcl), 809 subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), newf.Dcl)) 810 811 typed(newt, newf.Nname) 812 ir.MarkFunc(newf.Nname) 813 newf.SetTypecheck(1) 814 815 // Make sure name/type of newf is set before substituting the body. 816 newf.Body = subst.list(gf.Body) 817 if len(newf.Body) == 0 { 818 // Ensure the body is nonempty, for issue 49524. 819 // TODO: have some other way to detect the difference between 820 // a function declared with no body, vs. one with an empty body? 821 newf.Body = append(newf.Body, ir.NewBlockStmt(gf.Pos(), nil)) 822 } 823 824 if len(subst.defnMap) > 0 { 825 base.Fatalf("defnMap is not empty") 826 } 827 828 for i, tp := range tparams { 829 info.dictInfo.shapeToBound[shapes[i]] = subst.ts.Typ(tp.Bound()) 830 } 831 832 ir.CurFunc = savef 833 834 return subst.newf 835 } 836 837 // localvar creates a new name node for the specified local variable and enters it 838 // in subst.vars. It substitutes type arguments for type parameters in the type of 839 // name as needed. 840 func (subst *subster) localvar(name *ir.Name) *ir.Name { 841 m := ir.NewNameAt(name.Pos(), name.Sym()) 842 if name.IsClosureVar() { 843 m.SetIsClosureVar(true) 844 } 845 m.SetType(subst.ts.Typ(name.Type())) 846 m.BuiltinOp = name.BuiltinOp 847 m.Curfn = subst.newf 848 m.Class = name.Class 849 assert(name.Class != ir.PEXTERN && name.Class != ir.PFUNC) 850 m.Func = name.Func 851 subst.ts.Vars[name] = m 852 m.SetTypecheck(1) 853 m.DictIndex = name.DictIndex 854 if name.Defn != nil { 855 if name.Defn.Op() == ir.ONAME { 856 // This is a closure variable, so its Defn is the outer 857 // captured variable, which has already been substituted. 858 m.Defn = subst.node(name.Defn) 859 } else { 860 // The other values of Defn are nodes in the body of the 861 // function, so just remember the mapping so we can set Defn 862 // properly in node() when we create the new body node. We 863 // always call localvar() on all the local variables before 864 // we substitute the body. 865 slice := subst.defnMap[name.Defn] 866 subst.defnMap[name.Defn] = append(slice, &m) 867 } 868 } 869 if name.Outer != nil { 870 m.Outer = subst.node(name.Outer).(*ir.Name) 871 } 872 873 return m 874 } 875 876 // getDictionaryEntry gets the i'th entry in the dictionary dict. 877 func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node { 878 // Convert dictionary to *[N]uintptr 879 // All entries in the dictionary are pointers. They all point to static data, though, so we 880 // treat them as uintptrs so the GC doesn't need to keep track of them. 881 d := ir.NewConvExpr(pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], dict) 882 d.SetTypecheck(1) 883 d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(size)).PtrTo(), d) 884 d.SetTypecheck(1) 885 types.CheckSize(d.Type().Elem()) 886 887 // Load entry i out of the dictionary. 888 deref := ir.NewStarExpr(pos, d) 889 typed(d.Type().Elem(), deref) 890 idx := ir.NewConstExpr(constant.MakeUint64(uint64(i)), dict) // TODO: what to set orig to? 891 typed(types.Types[types.TUINTPTR], idx) 892 r := ir.NewIndexExpr(pos, deref, idx) 893 typed(types.Types[types.TUINTPTR], r) 894 return r 895 } 896 897 // getDictionaryEntryAddr gets the address of the i'th entry in dictionary dict. 898 func getDictionaryEntryAddr(pos src.XPos, dict *ir.Name, i int, size int) ir.Node { 899 a := ir.NewAddrExpr(pos, getDictionaryEntry(pos, dict, i, size)) 900 typed(types.Types[types.TUINTPTR].PtrTo(), a) 901 return a 902 } 903 904 // getDictionaryType returns a *runtime._type from the dictionary entry i (which 905 // refers to a type param or a derived type that uses type params). It uses the 906 // specified dictionary dictParam, rather than the one in info.dictParam. 907 func getDictionaryType(info *instInfo, dictParam *ir.Name, pos src.XPos, i int) ir.Node { 908 if i < 0 || i >= info.dictInfo.startSubDict { 909 base.Fatalf(fmt.Sprintf("bad dict index %d", i)) 910 } 911 912 r := getDictionaryEntry(pos, dictParam, i, info.dictInfo.startSubDict) 913 // change type of retrieved dictionary entry to *byte, which is the 914 // standard typing of a *runtime._type in the compiler 915 typed(types.Types[types.TUINT8].PtrTo(), r) 916 return r 917 } 918 919 // node is like DeepCopy(), but substitutes ONAME nodes based on subst.ts.vars, and 920 // also descends into closures. It substitutes type arguments for type parameters in 921 // all the new nodes and does the transformations that were delayed on the generic 922 // function. 923 func (subst *subster) node(n ir.Node) ir.Node { 924 // Use closure to capture all state needed by the ir.EditChildren argument. 925 var edit func(ir.Node) ir.Node 926 edit = func(x ir.Node) ir.Node { 927 // Analogous to ir.SetPos() at beginning of typecheck.typecheck() - 928 // allows using base.Pos during the transform functions, just like 929 // the tc*() functions. 930 ir.SetPos(x) 931 switch x.Op() { 932 case ir.OTYPE: 933 return ir.TypeNode(subst.ts.Typ(x.Type())) 934 935 case ir.ONAME: 936 if v := subst.ts.Vars[x.(*ir.Name)]; v != nil { 937 return v 938 } 939 if ir.IsBlank(x) { 940 // Special case, because a blank local variable is 941 // not in the fn.Dcl list. 942 m := ir.NewNameAt(x.Pos(), ir.BlankNode.Sym()) 943 return typed(subst.ts.Typ(x.Type()), m) 944 } 945 return x 946 case ir.ONONAME: 947 // This handles the identifier in a type switch guard 948 fallthrough 949 case ir.OLITERAL, ir.ONIL: 950 if x.Sym() != nil { 951 return x 952 } 953 } 954 m := ir.Copy(x) 955 956 slice, ok := subst.defnMap[x] 957 if ok { 958 // We just copied a non-ONAME node which was the Defn value 959 // of a local variable. Set the Defn value of the copied 960 // local variable to this new Defn node. 961 for _, ptr := range slice { 962 (*ptr).Defn = m 963 } 964 delete(subst.defnMap, x) 965 } 966 967 if _, isExpr := m.(ir.Expr); isExpr { 968 t := x.Type() 969 if t == nil { 970 // Check for known cases where t can be nil (call 971 // that has no return values, and key expressions) 972 // and otherwise cause a fatal error. 973 _, isCallExpr := m.(*ir.CallExpr) 974 _, isStructKeyExpr := m.(*ir.StructKeyExpr) 975 _, isKeyExpr := m.(*ir.KeyExpr) 976 if !isCallExpr && !isStructKeyExpr && !isKeyExpr && x.Op() != ir.OPANIC && 977 x.Op() != ir.OCLOSE { 978 base.FatalfAt(m.Pos(), "Nil type for %v", x) 979 } 980 } else if x.Op() != ir.OCLOSURE { 981 m.SetType(subst.ts.Typ(x.Type())) 982 } 983 } 984 985 old := subst.skipClosure 986 // For unsafe.{Alignof,Offsetof,Sizeof}, subster will transform them to OLITERAL nodes, 987 // and discard their arguments. However, their children nodes were already process before, 988 // thus if they contain any closure, the closure was still be added to package declarations 989 // queue for processing later. Thus, genInst will fail to generate instantiation for the 990 // closure because of lacking dictionary information, see issue #53390. 991 if call, ok := m.(*ir.CallExpr); ok && call.X.Op() == ir.ONAME { 992 switch call.X.Name().BuiltinOp { 993 case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: 994 subst.skipClosure = true 995 } 996 } 997 ir.EditChildren(m, edit) 998 subst.skipClosure = old 999 1000 m.SetTypecheck(1) 1001 1002 // Do the transformations that we delayed on the generic function 1003 // node, now that we have substituted in the type args. 1004 switch x.Op() { 1005 case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE: 1006 transformCompare(m.(*ir.BinaryExpr)) 1007 1008 case ir.OSLICE, ir.OSLICE3: 1009 transformSlice(m.(*ir.SliceExpr)) 1010 1011 case ir.OADD: 1012 m = transformAdd(m.(*ir.BinaryExpr)) 1013 1014 case ir.OINDEX: 1015 transformIndex(m.(*ir.IndexExpr)) 1016 1017 case ir.OAS2: 1018 as2 := m.(*ir.AssignListStmt) 1019 transformAssign(as2, as2.Lhs, as2.Rhs) 1020 1021 case ir.OAS: 1022 as := m.(*ir.AssignStmt) 1023 if as.Y != nil { 1024 // transformAssign doesn't handle the case 1025 // of zeroing assignment of a dcl (rhs[0] is nil). 1026 lhs, rhs := []ir.Node{as.X}, []ir.Node{as.Y} 1027 transformAssign(as, lhs, rhs) 1028 as.X, as.Y = lhs[0], rhs[0] 1029 } 1030 1031 case ir.OASOP: 1032 as := m.(*ir.AssignOpStmt) 1033 transformCheckAssign(as, as.X) 1034 1035 case ir.ORETURN: 1036 transformReturn(m.(*ir.ReturnStmt)) 1037 1038 case ir.OSEND: 1039 transformSend(m.(*ir.SendStmt)) 1040 1041 case ir.OSELECT: 1042 transformSelect(m.(*ir.SelectStmt)) 1043 1044 case ir.OCOMPLIT: 1045 transformCompLit(m.(*ir.CompLitExpr)) 1046 1047 case ir.OADDR: 1048 transformAddr(m.(*ir.AddrExpr)) 1049 1050 case ir.OLITERAL: 1051 t := m.Type() 1052 if t != x.Type() { 1053 // types2 will give us a constant with a type T, 1054 // if an untyped constant is used with another 1055 // operand of type T (in a provably correct way). 1056 // When we substitute in the type args during 1057 // stenciling, we now know the real type of the 1058 // constant. We may then need to change the 1059 // BasicLit.val to be the correct type (e.g. 1060 // convert an int64Val constant to a floatVal 1061 // constant). 1062 m.SetType(types.UntypedInt) // use any untyped type for DefaultLit to work 1063 m = typecheck.DefaultLit(m, t) 1064 } 1065 1066 case ir.OXDOT: 1067 // Finish the transformation of an OXDOT, unless this is 1068 // bound call or field access on a type param. A bound call 1069 // or field access on a type param will be transformed during 1070 // the dictPass. Otherwise, m will be transformed to an 1071 // OMETHVALUE node. It will be transformed to an ODOTMETH or 1072 // ODOTINTER node if we find in the OCALL case below that the 1073 // method value is actually called. 1074 mse := m.(*ir.SelectorExpr) 1075 if src := mse.X.Type(); !src.IsShape() { 1076 transformDot(mse, false) 1077 } 1078 1079 case ir.OCALL: 1080 call := m.(*ir.CallExpr) 1081 switch call.X.Op() { 1082 case ir.OTYPE: 1083 // Transform the conversion, now that we know the 1084 // type argument. 1085 m = transformConvCall(call) 1086 1087 case ir.OMETHVALUE, ir.OMETHEXPR: 1088 // Redo the transformation of OXDOT, now that we 1089 // know the method value is being called. Then 1090 // transform the call. 1091 call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT) 1092 transformDot(call.X.(*ir.SelectorExpr), true) 1093 transformCall(call) 1094 1095 case ir.ODOT, ir.ODOTPTR: 1096 // An OXDOT for a generic receiver was resolved to 1097 // an access to a field which has a function 1098 // value. Transform the call to that function, now 1099 // that the OXDOT was resolved. 1100 transformCall(call) 1101 1102 case ir.ONAME: 1103 name := call.X.Name() 1104 if name.BuiltinOp != ir.OXXX { 1105 m = transformBuiltin(call) 1106 } else { 1107 // This is the case of a function value that was a 1108 // type parameter (implied to be a function via a 1109 // structural constraint) which is now resolved. 1110 transformCall(call) 1111 } 1112 1113 case ir.OFUNCINST: 1114 // A call with an OFUNCINST will get transformed 1115 // in stencil() once we have created & attached the 1116 // instantiation to be called. 1117 // We must transform the arguments of the call now, though, 1118 // so that any needed CONVIFACE nodes are exposed, 1119 // so the dictionary format is correct. 1120 transformEarlyCall(call) 1121 1122 case ir.OXDOT: 1123 // This is the case of a bound call or a field access 1124 // on a typeparam, which will be handled in the 1125 // dictPass. As with OFUNCINST, we must transform the 1126 // arguments of the call now, so any needed CONVIFACE 1127 // nodes are exposed. 1128 transformEarlyCall(call) 1129 1130 case ir.ODOTTYPE, ir.ODOTTYPE2: 1131 // These are DOTTYPEs that could get transformed into 1132 // ODYNAMIC DOTTYPEs by the dict pass. 1133 1134 default: 1135 // Transform a call for all other values of 1136 // call.X.Op() that don't require any special 1137 // handling. 1138 transformCall(call) 1139 1140 } 1141 1142 case ir.OCLOSURE: 1143 if subst.skipClosure { 1144 break 1145 } 1146 // We're going to create a new closure from scratch, so clear m 1147 // to avoid using the ir.Copy by accident until we reassign it. 1148 m = nil 1149 1150 x := x.(*ir.ClosureExpr) 1151 // Need to duplicate x.Func.Nname, x.Func.Dcl, x.Func.ClosureVars, and 1152 // x.Func.Body. 1153 oldfn := x.Func 1154 newfn := ir.NewClosureFunc(oldfn.Pos(), subst.newf != nil) 1155 ir.NameClosure(newfn.OClosure, subst.newf) 1156 1157 saveNewf := subst.newf 1158 ir.CurFunc = newfn 1159 subst.newf = newfn 1160 newfn.Dcl = subst.namelist(oldfn.Dcl) 1161 1162 // Make a closure variable for the dictionary of the 1163 // containing function. 1164 cdict := ir.CaptureName(oldfn.Pos(), newfn, subst.info.dictParam) 1165 typed(types.Types[types.TUINTPTR], cdict) 1166 ir.FinishCaptureNames(oldfn.Pos(), saveNewf, newfn) 1167 newfn.ClosureVars = append(newfn.ClosureVars, subst.namelist(oldfn.ClosureVars)...) 1168 1169 // Copy that closure variable to a local one. 1170 // Note: this allows the dictionary to be captured by child closures. 1171 // See issue 47723. 1172 ldict := ir.NewNameAt(x.Pos(), newfn.Sym().Pkg.Lookup(typecheck.LocalDictName)) 1173 typed(types.Types[types.TUINTPTR], ldict) 1174 ldict.Class = ir.PAUTO 1175 ldict.Curfn = newfn 1176 newfn.Dcl = append(newfn.Dcl, ldict) 1177 as := ir.NewAssignStmt(x.Pos(), ldict, cdict) 1178 as.SetTypecheck(1) 1179 ldict.Defn = as 1180 newfn.Body.Append(as) 1181 1182 // Create inst info for the instantiated closure. The dict 1183 // param is the closure variable for the dictionary of the 1184 // outer function. Since the dictionary is shared, use the 1185 // same dictInfo. 1186 cinfo := &instInfo{ 1187 fun: newfn, 1188 dictParam: ldict, 1189 dictInfo: subst.info.dictInfo, 1190 } 1191 subst.g.instInfoMap[newfn.Nname.Sym()] = cinfo 1192 1193 typed(subst.ts.Typ(oldfn.Nname.Type()), newfn.Nname) 1194 typed(newfn.Nname.Type(), newfn.OClosure) 1195 newfn.SetTypecheck(1) 1196 1197 outerinfo := subst.info 1198 subst.info = cinfo 1199 // Make sure type of closure function is set before doing body. 1200 newfn.Body.Append(subst.list(oldfn.Body)...) 1201 subst.info = outerinfo 1202 subst.newf = saveNewf 1203 ir.CurFunc = saveNewf 1204 1205 m = ir.UseClosure(newfn.OClosure, typecheck.Target) 1206 subst.g.newInsts = append(subst.g.newInsts, m.(*ir.ClosureExpr).Func) 1207 m.(*ir.ClosureExpr).SetInit(subst.list(x.Init())) 1208 1209 case ir.OSWITCH: 1210 m := m.(*ir.SwitchStmt) 1211 if m.Tag != nil && m.Tag.Op() == ir.OTYPESW { 1212 break // Nothing to do here for type switches. 1213 } 1214 if m.Tag != nil && !types.IsComparable(m.Tag.Type()) { 1215 break // Nothing to do here for un-comparable types. 1216 } 1217 if m.Tag != nil && !m.Tag.Type().IsEmptyInterface() && m.Tag.Type().HasShape() { 1218 // To implement a switch on a value that is or has a type parameter, we first convert 1219 // that thing we're switching on to an interface{}. 1220 m.Tag = assignconvfn(m.Tag, types.Types[types.TINTER]) 1221 } 1222 for _, c := range m.Cases { 1223 for i, x := range c.List { 1224 // If we have a case that is or has a type parameter, convert that case 1225 // to an interface{}. 1226 if !x.Type().IsEmptyInterface() && x.Type().HasShape() { 1227 c.List[i] = assignconvfn(x, types.Types[types.TINTER]) 1228 } 1229 } 1230 } 1231 1232 } 1233 return m 1234 } 1235 1236 return edit(n) 1237 } 1238 1239 // dictPass takes a function instantiation and does the transformations on the 1240 // operations that need to make use of the dictionary param. 1241 func (g *genInst) dictPass(info *instInfo) { 1242 savef := ir.CurFunc 1243 ir.CurFunc = info.fun 1244 1245 callMap := make(map[ir.Node]bool) 1246 1247 var edit func(ir.Node) ir.Node 1248 edit = func(m ir.Node) ir.Node { 1249 if m.Op() == ir.OCALL && m.(*ir.CallExpr).X.Op() == ir.OXDOT { 1250 callMap[m.(*ir.CallExpr).X] = true 1251 } 1252 1253 ir.EditChildren(m, edit) 1254 1255 switch m.Op() { 1256 case ir.OCLOSURE: 1257 newf := m.(*ir.ClosureExpr).Func 1258 ir.CurFunc = newf 1259 outerinfo := info 1260 info = g.instInfoMap[newf.Nname.Sym()] 1261 1262 body := newf.Body 1263 for i, n := range body { 1264 body[i] = edit(n) 1265 } 1266 1267 info = outerinfo 1268 ir.CurFunc = info.fun 1269 1270 case ir.OXDOT: 1271 // This is the case of a dot access on a type param. This is 1272 // typically a bound call on the type param, but could be a 1273 // field access, if the constraint has a single structural type. 1274 mse := m.(*ir.SelectorExpr) 1275 src := mse.X.Type() 1276 assert(src.IsShape()) 1277 1278 if mse.X.Op() == ir.OTYPE { 1279 // Method expression T.M 1280 idx := findMethodExprClosure(info.dictInfo, mse) 1281 c := getDictionaryEntryAddr(m.Pos(), info.dictParam, info.dictInfo.startMethodExprClosures+idx, info.dictInfo.dictLen) 1282 m = ir.NewConvExpr(m.Pos(), ir.OCONVNOP, mse.Type(), c) 1283 m.SetTypecheck(1) 1284 } else { 1285 // If we can't find the selected method in the 1286 // AllMethods of the bound, then this must be an access 1287 // to a field of a structural type. If so, we skip the 1288 // dictionary lookups - transformDot() will convert to 1289 // the desired direct field access. 1290 if isBoundMethod(info.dictInfo, mse) { 1291 if callMap[m] { 1292 // The OCALL surrounding this XDOT will rewrite the call 1293 // to use the method expression closure directly. 1294 break 1295 } 1296 // Convert this method value to a closure. 1297 // TODO: use method expression closure. 1298 dst := info.dictInfo.shapeToBound[mse.X.Type()] 1299 // Implement x.M as a conversion-to-bound-interface 1300 // 1) convert x to the bound interface 1301 // 2) select method value M on that interface 1302 if src.IsInterface() { 1303 // If type arg is an interface (unusual case), 1304 // we do a type assert to the type bound. 1305 mse.X = assertToBound(info, info.dictParam, m.Pos(), mse.X, dst) 1306 } else { 1307 mse.X = convertUsingDictionary(info, info.dictParam, m.Pos(), mse.X, m, dst) 1308 } 1309 } 1310 transformDot(mse, false) 1311 } 1312 case ir.OCALL: 1313 call := m.(*ir.CallExpr) 1314 op := call.X.Op() 1315 if op == ir.OXDOT { 1316 // This is a call of a method value where the value has a type parameter type. 1317 // We transform to a call of the appropriate method expression closure 1318 // in the dictionary. 1319 // So if x has a type parameter type: 1320 // _ = x.m(a) 1321 // Rewrite to: 1322 // _ = methexpr<m>(x, a) 1323 se := call.X.(*ir.SelectorExpr) 1324 call.SetOp(ir.OCALLFUNC) 1325 idx := findMethodExprClosure(info.dictInfo, se) 1326 c := getDictionaryEntryAddr(se.Pos(), info.dictParam, info.dictInfo.startMethodExprClosures+idx, info.dictInfo.dictLen) 1327 t := typecheck.NewMethodType(se.Type(), se.X.Type()) 1328 call.X = ir.NewConvExpr(se.Pos(), ir.OCONVNOP, t, c) 1329 typed(t, call.X) 1330 call.Args.Prepend(se.X) 1331 break 1332 // TODO: deref case? 1333 } 1334 if op == ir.OMETHVALUE { 1335 // Redo the transformation of OXDOT, now that we 1336 // know the method value is being called. 1337 call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT) 1338 transformDot(call.X.(*ir.SelectorExpr), true) 1339 } 1340 transformCall(call) 1341 1342 case ir.OCONVIFACE: 1343 if m.Type().IsEmptyInterface() && m.(*ir.ConvExpr).X.Type().IsEmptyInterface() { 1344 // Was T->interface{}, after stenciling it is now interface{}->interface{}. 1345 // No longer need the conversion. See issue 48276. 1346 m.(*ir.ConvExpr).SetOp(ir.OCONVNOP) 1347 break 1348 } 1349 mce := m.(*ir.ConvExpr) 1350 // Note: x's argument is still typed as a type parameter. 1351 // m's argument now has an instantiated type. 1352 if mce.X.Type().HasShape() || (m.Type().HasShape() && !m.Type().IsEmptyInterface()) { 1353 m = convertUsingDictionary(info, info.dictParam, m.Pos(), mce.X, m, m.Type()) 1354 } 1355 case ir.ODOTTYPE, ir.ODOTTYPE2: 1356 dt := m.(*ir.TypeAssertExpr) 1357 if dt.Type().IsEmptyInterface() || (dt.Type().IsInterface() && !dt.Type().HasShape()) { 1358 break 1359 } 1360 if !dt.Type().HasShape() && !(dt.X.Type().HasShape() && !dt.X.Type().IsEmptyInterface()) { 1361 break 1362 } 1363 var rtype, itab ir.Node 1364 if dt.Type().IsInterface() || dt.X.Type().IsEmptyInterface() { 1365 // TODO(mdempsky): Investigate executing this block unconditionally. 1366 ix := findDictType(info, m.Type()) 1367 assert(ix >= 0) 1368 rtype = getDictionaryType(info, info.dictParam, dt.Pos(), ix) 1369 } else { 1370 // nonempty interface to noninterface. Need an itab. 1371 ix := -1 1372 for i, ic := range info.dictInfo.itabConvs { 1373 if ic == m { 1374 ix = info.dictInfo.startItabConv + i 1375 break 1376 } 1377 } 1378 assert(ix >= 0) 1379 itab = getDictionaryEntry(dt.Pos(), info.dictParam, ix, info.dictInfo.dictLen) 1380 } 1381 op := ir.ODYNAMICDOTTYPE 1382 if m.Op() == ir.ODOTTYPE2 { 1383 op = ir.ODYNAMICDOTTYPE2 1384 } 1385 m = ir.NewDynamicTypeAssertExpr(dt.Pos(), op, dt.X, rtype) 1386 m.(*ir.DynamicTypeAssertExpr).ITab = itab 1387 m.SetType(dt.Type()) 1388 m.SetTypecheck(1) 1389 case ir.OCASE: 1390 if _, ok := m.(*ir.CommClause); ok { 1391 // This is not a type switch. TODO: Should we use an OSWITCH case here instead of OCASE? 1392 break 1393 } 1394 m := m.(*ir.CaseClause) 1395 for i, c := range m.List { 1396 if c.Op() == ir.OTYPE && c.Type().HasShape() { 1397 // Use a *runtime._type for the dynamic type. 1398 ix := findDictType(info, m.List[i].Type()) 1399 assert(ix >= 0) 1400 dt := ir.NewDynamicType(c.Pos(), getDictionaryEntry(c.Pos(), info.dictParam, ix, info.dictInfo.dictLen)) 1401 1402 // For type switch from nonempty interfaces to non-interfaces, we need an itab as well. 1403 if !m.List[i].Type().IsInterface() { 1404 if _, ok := info.dictInfo.type2switchType[m.List[i]]; ok { 1405 // Type switch from nonempty interface. We need a *runtime.itab 1406 // for the dynamic type. 1407 ix := -1 1408 for j, ic := range info.dictInfo.itabConvs { 1409 if ic == m.List[i] { 1410 ix = info.dictInfo.startItabConv + j 1411 break 1412 } 1413 } 1414 assert(ix >= 0) 1415 dt.ITab = getDictionaryEntry(c.Pos(), info.dictParam, ix, info.dictInfo.dictLen) 1416 } 1417 } 1418 typed(m.List[i].Type(), dt) 1419 m.List[i] = dt 1420 } 1421 } 1422 1423 } 1424 return m 1425 } 1426 edit(info.fun) 1427 ir.CurFunc = savef 1428 } 1429 1430 // findDictType looks for type t in the typeparams or derived types in the generic 1431 // function info.gfInfo. This will indicate the dictionary entry with the 1432 // correct concrete type for the associated instantiated function. 1433 func findDictType(info *instInfo, t *types.Type) int { 1434 for i, dt := range info.dictInfo.shapeParams { 1435 if dt == t { 1436 return i 1437 } 1438 } 1439 for i, dt := range info.dictInfo.derivedTypes { 1440 if types.IdenticalStrict(dt, t) { 1441 return i + len(info.dictInfo.shapeParams) 1442 } 1443 } 1444 return -1 1445 } 1446 1447 // convertUsingDictionary converts instantiated value v (type v.Type()) to an interface 1448 // type dst, by returning a new set of nodes that make use of a dictionary entry. in is the 1449 // instantiated node of the CONVIFACE node or XDOT node (for a bound method call) that is causing the 1450 // conversion. 1451 func convertUsingDictionary(info *instInfo, dictParam *ir.Name, pos src.XPos, v ir.Node, in ir.Node, dst *types.Type) ir.Node { 1452 assert(v.Type().HasShape() || (in.Type().HasShape() && !in.Type().IsEmptyInterface())) 1453 assert(dst.IsInterface()) 1454 1455 if v.Type().IsInterface() { 1456 // Converting from an interface. The shape-ness of the source doesn't really matter, as 1457 // we'll be using the concrete type from the first interface word. 1458 if dst.IsEmptyInterface() { 1459 // Converting I2E. OCONVIFACE does that for us, and doesn't depend 1460 // on what the empty interface was instantiated with. No dictionary entry needed. 1461 v = ir.NewConvExpr(pos, ir.OCONVIFACE, dst, v) 1462 v.SetTypecheck(1) 1463 return v 1464 } 1465 if !in.Type().HasShape() { 1466 // Regular OCONVIFACE works if the destination isn't parameterized. 1467 v = ir.NewConvExpr(pos, ir.OCONVIFACE, dst, v) 1468 v.SetTypecheck(1) 1469 return v 1470 } 1471 1472 // We get the destination interface type from the dictionary and the concrete 1473 // type from the argument's itab. Call runtime.convI2I to get the new itab. 1474 tmp := typecheck.Temp(v.Type()) 1475 as := ir.NewAssignStmt(pos, tmp, v) 1476 as.SetTypecheck(1) 1477 itab := ir.NewUnaryExpr(pos, ir.OITAB, tmp) 1478 typed(types.Types[types.TUINTPTR].PtrTo(), itab) 1479 idata := ir.NewUnaryExpr(pos, ir.OIDATA, tmp) 1480 typed(types.Types[types.TUNSAFEPTR], idata) 1481 1482 fn := typecheck.LookupRuntime("convI2I") 1483 fn.SetTypecheck(1) 1484 types.CalcSize(fn.Type()) 1485 call := ir.NewCallExpr(pos, ir.OCALLFUNC, fn, nil) 1486 typed(types.Types[types.TUINT8].PtrTo(), call) 1487 ix := findDictType(info, in.Type()) 1488 assert(ix >= 0) 1489 inter := getDictionaryType(info, dictParam, pos, ix) 1490 call.Args = []ir.Node{inter, itab} 1491 i := ir.NewBinaryExpr(pos, ir.OEFACE, call, idata) 1492 typed(dst, i) 1493 i.PtrInit().Append(as) 1494 return i 1495 } 1496 1497 var rt ir.Node 1498 if !dst.IsEmptyInterface() { 1499 // We should have an itab entry in the dictionary. Using this itab 1500 // will be more efficient than converting to an empty interface first 1501 // and then type asserting to dst. 1502 ix := -1 1503 for i, ic := range info.dictInfo.itabConvs { 1504 if ic == in { 1505 ix = info.dictInfo.startItabConv + i 1506 break 1507 } 1508 } 1509 assert(ix >= 0) 1510 rt = getDictionaryEntry(pos, dictParam, ix, info.dictInfo.dictLen) 1511 } else { 1512 ix := findDictType(info, v.Type()) 1513 assert(ix >= 0) 1514 // Load the actual runtime._type of the type parameter from the dictionary. 1515 rt = getDictionaryType(info, dictParam, pos, ix) 1516 } 1517 1518 // Figure out what the data field of the interface will be. 1519 data := ir.NewConvExpr(pos, ir.OCONVIDATA, nil, v) 1520 typed(types.Types[types.TUNSAFEPTR], data) 1521 1522 // Build an interface from the type and data parts. 1523 var i ir.Node = ir.NewBinaryExpr(pos, ir.OEFACE, rt, data) 1524 typed(dst, i) 1525 return i 1526 } 1527 1528 func (subst *subster) namelist(l []*ir.Name) []*ir.Name { 1529 s := make([]*ir.Name, len(l)) 1530 for i, n := range l { 1531 s[i] = subst.localvar(n) 1532 } 1533 return s 1534 } 1535 1536 func (subst *subster) list(l []ir.Node) []ir.Node { 1537 s := make([]ir.Node, len(l)) 1538 for i, n := range l { 1539 s[i] = subst.node(n) 1540 } 1541 return s 1542 } 1543 1544 // fields sets the Nname field for the Field nodes inside a type signature, based 1545 // on the corresponding in/out parameters in dcl. It depends on the in and out 1546 // parameters being in order in dcl. 1547 func (subst *subster) fields(class ir.Class, oldfields []*types.Field, dcl []*ir.Name) []*types.Field { 1548 // Find the starting index in dcl of declarations of the class (either 1549 // PPARAM or PPARAMOUT). 1550 var i int 1551 for i = range dcl { 1552 if dcl[i].Class == class { 1553 break 1554 } 1555 } 1556 1557 // Create newfields nodes that are copies of the oldfields nodes, but 1558 // with substitution for any type params, and with Nname set to be the node in 1559 // Dcl for the corresponding PPARAM or PPARAMOUT. 1560 newfields := make([]*types.Field, len(oldfields)) 1561 for j := range oldfields { 1562 newfields[j] = oldfields[j].Copy() 1563 newfields[j].Type = subst.ts.Typ(oldfields[j].Type) 1564 // A PPARAM field will be missing from dcl if its name is 1565 // unspecified or specified as "_". So, we compare the dcl sym 1566 // with the field sym (or sym of the field's Nname node). (Unnamed 1567 // results still have a name like ~r2 in their Nname node.) If 1568 // they don't match, this dcl (if there is one left) must apply to 1569 // a later field. 1570 if i < len(dcl) && (dcl[i].Sym() == oldfields[j].Sym || 1571 (oldfields[j].Nname != nil && dcl[i].Sym() == oldfields[j].Nname.Sym())) { 1572 newfields[j].Nname = dcl[i] 1573 i++ 1574 } 1575 } 1576 return newfields 1577 } 1578 1579 // deref does a single deref of type t, if it is a pointer type. 1580 func deref(t *types.Type) *types.Type { 1581 if t.IsPtr() { 1582 return t.Elem() 1583 } 1584 return t 1585 } 1586 1587 // markTypeUsed marks type t as used in order to help avoid dead-code elimination of 1588 // needed methods. 1589 func markTypeUsed(t *types.Type, lsym *obj.LSym) { 1590 if t.IsInterface() { 1591 return 1592 } 1593 // TODO: This is somewhat overkill, we really only need it 1594 // for types that are put into interfaces. 1595 // Note: this relocation is also used in cmd/link/internal/ld/dwarf.go 1596 reflectdata.MarkTypeUsedInInterface(t, lsym) 1597 } 1598 1599 // getDictionarySym returns the dictionary for the named generic function gf, which 1600 // is instantiated with the type arguments targs. 1601 func (g *genInst) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) *types.Sym { 1602 if len(targs) == 0 { 1603 base.Fatalf("%s should have type arguments", gf.Sym().Name) 1604 } 1605 1606 // Enforce that only concrete types can make it to here. 1607 for _, t := range targs { 1608 if t.HasShape() { 1609 panic(fmt.Sprintf("shape %+v in dictionary for %s", t, gf.Sym().Name)) 1610 } 1611 } 1612 1613 // Get a symbol representing the dictionary. 1614 sym := typecheck.MakeDictSym(gf.Sym(), targs, isMeth) 1615 1616 // Initialize the dictionary, if we haven't yet already. 1617 lsym := sym.Linksym() 1618 if len(lsym.P) > 0 { 1619 // We already started creating this dictionary and its lsym. 1620 return sym 1621 } 1622 1623 infoPrint("=== Creating dictionary %v\n", sym.Name) 1624 off := 0 1625 // Emit an entry for each targ (concrete type or gcshape). 1626 for _, t := range targs { 1627 infoPrint(" * %v\n", t) 1628 s := reflectdata.TypeLinksym(t) 1629 off = objw.SymPtr(lsym, off, s, 0) 1630 markTypeUsed(t, lsym) 1631 } 1632 1633 instInfo := g.getInstantiation(gf, targs, isMeth) 1634 info := instInfo.dictInfo 1635 1636 subst := typecheck.Tsubster{ 1637 Tparams: info.shapeParams, 1638 Targs: targs, 1639 } 1640 // Emit an entry for each derived type (after substituting targs) 1641 for _, t := range info.derivedTypes { 1642 ts := subst.Typ(t) 1643 infoPrint(" - %v\n", ts) 1644 s := reflectdata.TypeLinksym(ts) 1645 off = objw.SymPtr(lsym, off, s, 0) 1646 markTypeUsed(ts, lsym) 1647 } 1648 // Emit an entry for each subdictionary (after substituting targs) 1649 for _, subDictInfo := range info.subDictCalls { 1650 var sym *types.Sym 1651 n := subDictInfo.callNode 1652 switch n.Op() { 1653 case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH: 1654 call := n.(*ir.CallExpr) 1655 if call.X.Op() == ir.OXDOT || call.X.Op() == ir.ODOTMETH { 1656 var nameNode *ir.Name 1657 se := call.X.(*ir.SelectorExpr) 1658 if se.X.Type().IsShape() { 1659 tparam := se.X.Type() 1660 // Ensure methods on all instantiating types are computed. 1661 typecheck.CalcMethods(tparam) 1662 if typecheck.Lookdot1(nil, se.Sel, tparam, tparam.AllMethods(), 0) != nil { 1663 // This is a method call enabled by a type bound. 1664 // We need this extra check for method expressions, 1665 // which don't add in the implicit XDOTs. 1666 tmpse := ir.NewSelectorExpr(src.NoXPos, ir.OXDOT, se.X, se.Sel) 1667 tmpse = typecheck.AddImplicitDots(tmpse) 1668 tparam = tmpse.X.Type() 1669 } 1670 if !tparam.IsShape() { 1671 // The method expression is not 1672 // really on a typeparam. 1673 break 1674 } 1675 ix := -1 1676 for i, shape := range info.shapeParams { 1677 if shape == tparam { 1678 ix = i 1679 break 1680 } 1681 } 1682 assert(ix >= 0) 1683 recvType := targs[ix] 1684 if recvType.IsInterface() || len(recvType.RParams()) == 0 { 1685 // No sub-dictionary entry is 1686 // actually needed, since the 1687 // type arg is not an 1688 // instantiated type that 1689 // will have generic methods. 1690 break 1691 } 1692 // This is a method call for an 1693 // instantiated type, so we need a 1694 // sub-dictionary. 1695 targs := recvType.RParams() 1696 genRecvType := recvType.OrigType() 1697 nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name) 1698 sym = g.getDictionarySym(nameNode, targs, true) 1699 } else { 1700 // This is the case of a normal 1701 // method call on a generic type. 1702 assert(subDictInfo.savedXNode == se) 1703 sym = g.getSymForMethodCall(se, &subst) 1704 } 1705 } else { 1706 inst, ok := call.X.(*ir.InstExpr) 1707 if ok { 1708 // Code hasn't been transformed yet 1709 assert(subDictInfo.savedXNode == inst) 1710 } 1711 // If !ok, then the generic method/function call has 1712 // already been transformed to a shape instantiation 1713 // call. Either way, use the SelectorExpr/InstExpr 1714 // node saved in info. 1715 cex := subDictInfo.savedXNode 1716 if se, ok := cex.(*ir.SelectorExpr); ok { 1717 sym = g.getSymForMethodCall(se, &subst) 1718 } else { 1719 inst := cex.(*ir.InstExpr) 1720 nameNode := inst.X.(*ir.Name) 1721 subtargs := typecheck.TypesOf(inst.Targs) 1722 for i, t := range subtargs { 1723 subtargs[i] = subst.Typ(t) 1724 } 1725 sym = g.getDictionarySym(nameNode, subtargs, false) 1726 } 1727 } 1728 1729 case ir.OFUNCINST: 1730 inst := n.(*ir.InstExpr) 1731 nameNode := inst.X.(*ir.Name) 1732 subtargs := typecheck.TypesOf(inst.Targs) 1733 for i, t := range subtargs { 1734 subtargs[i] = subst.Typ(t) 1735 } 1736 sym = g.getDictionarySym(nameNode, subtargs, false) 1737 1738 case ir.OXDOT, ir.OMETHEXPR, ir.OMETHVALUE: 1739 sym = g.getSymForMethodCall(n.(*ir.SelectorExpr), &subst) 1740 1741 default: 1742 assert(false) 1743 } 1744 1745 if sym == nil { 1746 // Unused sub-dictionary entry, just emit 0. 1747 off = objw.Uintptr(lsym, off, 0) 1748 infoPrint(" - Unused subdict entry\n") 1749 } else { 1750 off = objw.SymPtr(lsym, off, sym.Linksym(), 0) 1751 infoPrint(" - Subdict %v\n", sym.Name) 1752 } 1753 } 1754 1755 g.instantiateMethods() 1756 delay := &delayInfo{ 1757 gf: gf, 1758 targs: targs, 1759 sym: sym, 1760 off: off, 1761 isMeth: isMeth, 1762 } 1763 g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay) 1764 return sym 1765 } 1766 1767 // getSymForMethodCall gets the dictionary sym for a method call, method value, or method 1768 // expression that has selector se. subst gives the substitution from shape types to 1769 // concrete types. 1770 func (g *genInst) getSymForMethodCall(se *ir.SelectorExpr, subst *typecheck.Tsubster) *types.Sym { 1771 // For everything except method expressions, 'recvType = deref(se.X.Type)' would 1772 // also give the receiver type. For method expressions with embedded types, we 1773 // need to look at the type of the selection to get the final receiver type. 1774 recvType := deref(se.Selection.Type.Recv().Type) 1775 genRecvType := recvType.OrigType() 1776 nameNode := typecheck.Lookdot1(se, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name) 1777 subtargs := recvType.RParams() 1778 s2targs := make([]*types.Type, len(subtargs)) 1779 for i, t := range subtargs { 1780 s2targs[i] = subst.Typ(t) 1781 } 1782 return g.getDictionarySym(nameNode, s2targs, true) 1783 } 1784 1785 // finalizeSyms finishes up all dictionaries on g.dictSymsToFinalize, by writing out 1786 // any needed LSyms for itabs. The itab lsyms create wrappers which need various 1787 // dictionaries and method instantiations to be complete, so, to avoid recursive 1788 // dependencies, we finalize the itab lsyms only after all dictionaries syms and 1789 // instantiations have been created. 1790 // Also handles writing method expression closures into the dictionaries. 1791 func (g *genInst) finalizeSyms() { 1792 Outer: 1793 for _, d := range g.dictSymsToFinalize { 1794 infoPrint("=== Finalizing dictionary %s\n", d.sym.Name) 1795 1796 lsym := d.sym.Linksym() 1797 instInfo := g.getInstantiation(d.gf, d.targs, d.isMeth) 1798 info := instInfo.dictInfo 1799 1800 subst := typecheck.Tsubster{ 1801 Tparams: info.shapeParams, 1802 Targs: d.targs, 1803 } 1804 1805 // Emit an entry for each itab 1806 for _, n := range info.itabConvs { 1807 var srctype, dsttype *types.Type 1808 switch n.Op() { 1809 case ir.OXDOT, ir.OMETHVALUE: 1810 se := n.(*ir.SelectorExpr) 1811 srctype = subst.Typ(se.X.Type()) 1812 dsttype = subst.Typ(info.shapeToBound[se.X.Type()]) 1813 case ir.ODOTTYPE, ir.ODOTTYPE2: 1814 srctype = subst.Typ(n.(*ir.TypeAssertExpr).Type()) 1815 dsttype = subst.Typ(n.(*ir.TypeAssertExpr).X.Type()) 1816 case ir.OCONVIFACE: 1817 srctype = subst.Typ(n.(*ir.ConvExpr).X.Type()) 1818 dsttype = subst.Typ(n.Type()) 1819 case ir.OTYPE: 1820 srctype = subst.Typ(n.Type()) 1821 dsttype = subst.Typ(info.type2switchType[n]) 1822 default: 1823 base.Fatalf("itab entry with unknown op %s", n.Op()) 1824 } 1825 if srctype.IsInterface() || dsttype.IsEmptyInterface() { 1826 // No itab is wanted if src type is an interface. We 1827 // will use a type assert instead. 1828 d.off = objw.Uintptr(lsym, d.off, 0) 1829 infoPrint(" + Unused itab entry for %v\n", srctype) 1830 } else { 1831 // Make sure all new fully-instantiated types have 1832 // their methods created before generating any itabs. 1833 g.instantiateMethods() 1834 itabLsym := reflectdata.ITabLsym(srctype, dsttype) 1835 d.off = objw.SymPtr(lsym, d.off, itabLsym, 0) 1836 markTypeUsed(srctype, lsym) 1837 infoPrint(" + Itab for (%v,%v)\n", srctype, dsttype) 1838 } 1839 } 1840 1841 // Emit an entry for each method expression closure. 1842 // Each entry is a (captureless) closure pointing to the method on the instantiating type. 1843 // In other words, the entry is a runtime.funcval whose fn field is set to the method 1844 // in question, and has no other fields. The address of this dictionary entry can be 1845 // cast to a func of the appropriate type. 1846 // TODO: do these need to be done when finalizing, or can we do them earlier? 1847 for _, bf := range info.methodExprClosures { 1848 rcvr := d.targs[bf.idx] 1849 rcvr2 := deref(rcvr) 1850 found := false 1851 typecheck.CalcMethods(rcvr2) // Ensure methods on all instantiating types are computed. 1852 for _, f := range rcvr2.AllMethods().Slice() { 1853 if f.Sym.Name == bf.name { 1854 codePtr := ir.MethodSym(rcvr, f.Sym).Linksym() 1855 d.off = objw.SymPtr(lsym, d.off, codePtr, 0) 1856 infoPrint(" + MethodExprClosure for %v.%s\n", rcvr, bf.name) 1857 found = true 1858 break 1859 } 1860 } 1861 if !found { 1862 // We failed to find a method expression needed for this 1863 // dictionary. This may happen because we tried to create a 1864 // dictionary for an invalid instantiation. 1865 // 1866 // For example, in test/typeparam/issue54225.go, we attempt to 1867 // construct a dictionary for "Node[struct{}].contentLen", 1868 // even though "struct{}" does not implement "Value", so it 1869 // cannot actually be used as a type argument to "Node". 1870 // 1871 // The real issue here is we shouldn't be attempting to create 1872 // those dictionaries in the first place (e.g., CL 428356), 1873 // but that fix is scarier for backporting to Go 1.19. Too 1874 // many backport CLs to this code have fixed one issue while 1875 // introducing another. 1876 // 1877 // So as a hack, instead of calling Fatalf, we simply skip 1878 // calling objw.Global below, which prevents us from emitting 1879 // the broken dictionary. The linker's dead code elimination 1880 // should then naturally prune this invalid, unneeded 1881 // dictionary. Worst case, if the dictionary somehow *is* 1882 // needed by the final executable, we've just turned an ICE 1883 // into a link-time missing symbol failure. 1884 infoPrint(" ! abandoning dictionary %v; missing method expression %v.%s\n", d.sym.Name, rcvr, bf.name) 1885 continue Outer 1886 } 1887 } 1888 1889 objw.Global(lsym, int32(d.off), obj.DUPOK|obj.RODATA) 1890 infoPrint("=== Finalized dictionary %s\n", d.sym.Name) 1891 } 1892 g.dictSymsToFinalize = nil 1893 } 1894 1895 func (g *genInst) getDictionaryValue(pos src.XPos, gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node { 1896 sym := g.getDictionarySym(gf, targs, isMeth) 1897 1898 // Make (or reuse) a node referencing the dictionary symbol. 1899 var n *ir.Name 1900 if sym.Def != nil { 1901 n = sym.Def.(*ir.Name) 1902 } else { 1903 // We set the position of a static dictionary to be the position of 1904 // one of its uses. 1905 n = ir.NewNameAt(pos, sym) 1906 n.Curfn = ir.CurFunc 1907 n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter 1908 n.SetTypecheck(1) 1909 n.Class = ir.PEXTERN 1910 sym.Def = n 1911 } 1912 1913 // Return the address of the dictionary. Addr node gets position that was passed in. 1914 np := typecheck.NodAddrAt(pos, n) 1915 // Note: treat dictionary pointers as uintptrs, so they aren't pointers 1916 // with respect to GC. That saves on stack scanning work, write barriers, etc. 1917 // We can get away with it because dictionaries are global variables. 1918 // TODO: use a cast, or is typing directly ok? 1919 np.SetType(types.Types[types.TUINTPTR]) 1920 np.SetTypecheck(1) 1921 return np 1922 } 1923 1924 // hasShapeNodes returns true if the type of any node in targs has a shape. 1925 func hasShapeNodes(targs []ir.Ntype) bool { 1926 for _, n := range targs { 1927 if n.Type().HasShape() { 1928 return true 1929 } 1930 } 1931 return false 1932 } 1933 1934 // hasShapeTypes returns true if any type in targs has a shape. 1935 func hasShapeTypes(targs []*types.Type) bool { 1936 for _, t := range targs { 1937 if t.HasShape() { 1938 return true 1939 } 1940 } 1941 return false 1942 } 1943 1944 // getInstInfo get the dictionary format for a function instantiation- type params, derived 1945 // types, and needed subdictionaries, itabs, and method expression closures. 1946 func (g *genInst) getInstInfo(st *ir.Func, shapes []*types.Type, instInfo *instInfo) { 1947 info := instInfo.dictInfo 1948 info.shapeParams = shapes 1949 1950 for _, t := range info.shapeParams { 1951 b := info.shapeToBound[t] 1952 if b.HasShape() { 1953 // If a type bound is parameterized (unusual case), then we 1954 // may need its derived type to do a type assert when doing a 1955 // bound call for a type arg that is an interface. 1956 addType(info, nil, b) 1957 } 1958 } 1959 1960 for _, n := range st.Dcl { 1961 addType(info, n, n.Type()) 1962 n.DictIndex = uint16(findDictType(instInfo, n.Type()) + 1) 1963 } 1964 1965 if infoPrintMode { 1966 fmt.Printf(">>> InstInfo for %v\n", st) 1967 for _, t := range info.shapeParams { 1968 fmt.Printf(" Typeparam %v\n", t) 1969 } 1970 } 1971 1972 // Map to remember when we have seen an instantiated function value or method 1973 // expression/value as part of a call, so we can determine when we encounter 1974 // an uncalled function value or method expression/value. 1975 callMap := make(map[ir.Node]bool) 1976 1977 var visitFunc func(ir.Node) 1978 visitFunc = func(n ir.Node) { 1979 switch n.Op() { 1980 case ir.OFUNCINST: 1981 if !callMap[n] && hasShapeNodes(n.(*ir.InstExpr).Targs) { 1982 infoPrint(" Closure&subdictionary required at generic function value %v\n", n.(*ir.InstExpr).X) 1983 info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: nil}) 1984 } 1985 case ir.OMETHEXPR, ir.OMETHVALUE: 1986 if !callMap[n] && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) && 1987 len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && 1988 hasShapeTypes(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) { 1989 if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE { 1990 infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n) 1991 } else { 1992 infoPrint(" Closure&subdictionary required at generic meth value %v\n", n) 1993 } 1994 info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: nil}) 1995 } 1996 case ir.OCALL: 1997 ce := n.(*ir.CallExpr) 1998 if ce.X.Op() == ir.OFUNCINST { 1999 callMap[ce.X] = true 2000 if hasShapeNodes(ce.X.(*ir.InstExpr).Targs) { 2001 infoPrint(" Subdictionary at generic function/method call: %v - %v\n", ce.X.(*ir.InstExpr).X, n) 2002 // Save the instExpr node for the function call, 2003 // since we will lose this information when the 2004 // generic function call is transformed to a call 2005 // on the shape instantiation. 2006 info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: ce.X}) 2007 } 2008 } 2009 // Note: this XDOT code is not actually needed as long as we 2010 // continue to disable type parameters on RHS of type 2011 // declarations (#45639). 2012 if ce.X.Op() == ir.OXDOT { 2013 callMap[ce.X] = true 2014 if isBoundMethod(info, ce.X.(*ir.SelectorExpr)) { 2015 infoPrint(" Optional subdictionary at generic bound call: %v\n", n) 2016 info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: nil}) 2017 } 2018 } 2019 case ir.OCALLMETH: 2020 ce := n.(*ir.CallExpr) 2021 if ce.X.Op() == ir.ODOTMETH && 2022 len(deref(ce.X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 { 2023 callMap[ce.X] = true 2024 if hasShapeTypes(deref(ce.X.(*ir.SelectorExpr).X.Type()).RParams()) { 2025 infoPrint(" Subdictionary at generic method call: %v\n", n) 2026 // Save the selector for the method call, since we 2027 // will eventually lose this information when the 2028 // generic method call is transformed into a 2029 // function call on the method shape instantiation. 2030 info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: ce.X}) 2031 } 2032 } 2033 case ir.OCONVIFACE: 2034 if n.Type().IsInterface() && !n.Type().IsEmptyInterface() && 2035 (n.Type().HasShape() || n.(*ir.ConvExpr).X.Type().HasShape()) { 2036 infoPrint(" Itab for interface conv: %v\n", n) 2037 info.itabConvs = append(info.itabConvs, n) 2038 } 2039 case ir.OXDOT: 2040 se := n.(*ir.SelectorExpr) 2041 if se.X.Op() == ir.OTYPE && se.X.Type().IsShape() { 2042 // Method expression. 2043 addMethodExprClosure(info, se) 2044 break 2045 } 2046 if isBoundMethod(info, se) { 2047 if callMap[n] { 2048 // Method value called directly. Use method expression closure. 2049 addMethodExprClosure(info, se) 2050 break 2051 } 2052 // Method value not called directly. Still doing the old way. 2053 infoPrint(" Itab for bound call: %v\n", n) 2054 info.itabConvs = append(info.itabConvs, n) 2055 } 2056 2057 case ir.ODOTTYPE, ir.ODOTTYPE2: 2058 if !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() { 2059 infoPrint(" Itab for dot type: %v\n", n) 2060 info.itabConvs = append(info.itabConvs, n) 2061 } 2062 case ir.OCLOSURE: 2063 // Visit the closure body and add all relevant entries to the 2064 // dictionary of the outer function (closure will just use 2065 // the dictionary of the outer function). 2066 cfunc := n.(*ir.ClosureExpr).Func 2067 for _, n1 := range cfunc.Body { 2068 ir.Visit(n1, visitFunc) 2069 } 2070 for _, n := range cfunc.Dcl { 2071 n.DictIndex = uint16(findDictType(instInfo, n.Type()) + 1) 2072 } 2073 case ir.OSWITCH: 2074 ss := n.(*ir.SwitchStmt) 2075 if ss.Tag != nil && ss.Tag.Op() == ir.OTYPESW && 2076 !ss.Tag.(*ir.TypeSwitchGuard).X.Type().IsEmptyInterface() { 2077 for _, cc := range ss.Cases { 2078 for _, c := range cc.List { 2079 if c.Op() == ir.OTYPE && c.Type().HasShape() { 2080 // Type switch from a non-empty interface - might need an itab. 2081 infoPrint(" Itab for type switch: %v\n", c) 2082 info.itabConvs = append(info.itabConvs, c) 2083 if info.type2switchType == nil { 2084 info.type2switchType = map[ir.Node]*types.Type{} 2085 } 2086 info.type2switchType[c] = ss.Tag.(*ir.TypeSwitchGuard).X.Type() 2087 } 2088 } 2089 } 2090 } 2091 } 2092 addType(info, n, n.Type()) 2093 } 2094 2095 for _, stmt := range st.Body { 2096 ir.Visit(stmt, visitFunc) 2097 } 2098 if infoPrintMode { 2099 for _, t := range info.derivedTypes { 2100 fmt.Printf(" Derived type %v\n", t) 2101 } 2102 fmt.Printf(">>> Done Instinfo\n") 2103 } 2104 info.startSubDict = len(info.shapeParams) + len(info.derivedTypes) 2105 info.startItabConv = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) 2106 info.startMethodExprClosures = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) + len(info.itabConvs) 2107 info.dictLen = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) + len(info.itabConvs) + len(info.methodExprClosures) 2108 } 2109 2110 // isBoundMethod returns true if the selection indicated by se is a bound method of 2111 // se.X. se.X must be a shape type (i.e. substituted directly from a type param). If 2112 // isBoundMethod returns false, then the selection must be a field access of a 2113 // structural type. 2114 func isBoundMethod(info *dictInfo, se *ir.SelectorExpr) bool { 2115 bound := info.shapeToBound[se.X.Type()] 2116 return typecheck.Lookdot1(se, se.Sel, bound, bound.AllMethods(), 1) != nil 2117 } 2118 2119 func shapeIndex(info *dictInfo, t *types.Type) int { 2120 for i, s := range info.shapeParams { 2121 if s == t { 2122 return i 2123 } 2124 } 2125 base.Fatalf("can't find type %v in shape params", t) 2126 return -1 2127 } 2128 2129 // addMethodExprClosure adds the T.M method expression to the list of bound method expressions 2130 // used in the generic body. 2131 // isBoundMethod must have returned true on the same arguments. 2132 func addMethodExprClosure(info *dictInfo, se *ir.SelectorExpr) { 2133 idx := shapeIndex(info, se.X.Type()) 2134 name := se.Sel.Name 2135 for _, b := range info.methodExprClosures { 2136 if idx == b.idx && name == b.name { 2137 return 2138 } 2139 } 2140 infoPrint(" Method expression closure for %v.%s\n", info.shapeParams[idx], name) 2141 info.methodExprClosures = append(info.methodExprClosures, methodExprClosure{idx: idx, name: name}) 2142 } 2143 2144 // findMethodExprClosure finds the entry in the dictionary to use for the T.M 2145 // method expression encoded in se. 2146 // isBoundMethod must have returned true on the same arguments. 2147 func findMethodExprClosure(info *dictInfo, se *ir.SelectorExpr) int { 2148 idx := shapeIndex(info, se.X.Type()) 2149 name := se.Sel.Name 2150 for i, b := range info.methodExprClosures { 2151 if idx == b.idx && name == b.name { 2152 return i 2153 } 2154 } 2155 base.Fatalf("can't find method expression closure for %s %s", se.X.Type(), name) 2156 return -1 2157 } 2158 2159 // addType adds t to info.derivedTypes if it is parameterized type (which is not 2160 // just a simple shape) that is different from any existing type on 2161 // info.derivedTypes. 2162 func addType(info *dictInfo, n ir.Node, t *types.Type) { 2163 if t == nil || !t.HasShape() { 2164 return 2165 } 2166 if t.IsShape() { 2167 return 2168 } 2169 if t.Kind() == types.TFUNC && n != nil && 2170 (t.Recv() != nil || n.Op() == ir.ONAME && n.Name().Class == ir.PFUNC) { 2171 // Don't use the type of a named generic function or method, 2172 // since that is parameterized by other typeparams. 2173 // (They all come from arguments of a FUNCINST node.) 2174 return 2175 } 2176 if doubleCheck && !parameterizedBy(t, info.shapeParams) { 2177 base.Fatalf("adding type with invalid parameters %+v", t) 2178 } 2179 if t.Kind() == types.TSTRUCT && t.IsFuncArgStruct() { 2180 // Multiple return values are not a relevant new type (?). 2181 return 2182 } 2183 // Ignore a derived type we've already added. 2184 for _, et := range info.derivedTypes { 2185 if types.IdenticalStrict(t, et) { 2186 return 2187 } 2188 } 2189 info.derivedTypes = append(info.derivedTypes, t) 2190 } 2191 2192 // parameterizedBy returns true if t is parameterized by (at most) params. 2193 func parameterizedBy(t *types.Type, params []*types.Type) bool { 2194 return parameterizedBy1(t, params, map[*types.Type]bool{}) 2195 } 2196 func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Type]bool) bool { 2197 if visited[t] { 2198 return true 2199 } 2200 visited[t] = true 2201 2202 if t.Sym() != nil && len(t.RParams()) > 0 { 2203 // This defined type is instantiated. Check the instantiating types. 2204 for _, r := range t.RParams() { 2205 if !parameterizedBy1(r, params, visited) { 2206 return false 2207 } 2208 } 2209 return true 2210 } 2211 if t.IsShape() { 2212 // Check if t is one of the allowed parameters in scope. 2213 for _, p := range params { 2214 if p == t { 2215 return true 2216 } 2217 } 2218 // Couldn't find t in the list of allowed parameters. 2219 return false 2220 2221 } 2222 switch t.Kind() { 2223 case types.TARRAY, types.TPTR, types.TSLICE, types.TCHAN: 2224 return parameterizedBy1(t.Elem(), params, visited) 2225 2226 case types.TMAP: 2227 return parameterizedBy1(t.Key(), params, visited) && parameterizedBy1(t.Elem(), params, visited) 2228 2229 case types.TFUNC: 2230 return parameterizedBy1(t.TParams(), params, visited) && parameterizedBy1(t.Recvs(), params, visited) && parameterizedBy1(t.Params(), params, visited) && parameterizedBy1(t.Results(), params, visited) 2231 2232 case types.TSTRUCT: 2233 for _, f := range t.Fields().Slice() { 2234 if !parameterizedBy1(f.Type, params, visited) { 2235 return false 2236 } 2237 } 2238 return true 2239 2240 case types.TINTER: 2241 for _, f := range t.Methods().Slice() { 2242 if !parameterizedBy1(f.Type, params, visited) { 2243 return false 2244 } 2245 } 2246 return true 2247 2248 case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64, 2249 types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, 2250 types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128, types.TUNSAFEPTR: 2251 return true 2252 2253 case types.TUNION: 2254 for i := 0; i < t.NumTerms(); i++ { 2255 tt, _ := t.Term(i) 2256 if !parameterizedBy1(tt, params, visited) { 2257 return false 2258 } 2259 } 2260 return true 2261 2262 default: 2263 base.Fatalf("bad type kind %+v", t) 2264 return true 2265 } 2266 } 2267 2268 // startClosure starts creation of a closure that has the function type typ. It 2269 // creates all the formal params and results according to the type typ. On return, 2270 // the body and closure variables of the closure must still be filled in, and 2271 // ir.UseClosure() called. 2272 func startClosure(pos src.XPos, outer *ir.Func, typ *types.Type) (*ir.Func, []*types.Field, []*types.Field) { 2273 // Make a new internal function. 2274 fn := ir.NewClosureFunc(pos, outer != nil) 2275 ir.NameClosure(fn.OClosure, outer) 2276 2277 // Build formal argument and return lists. 2278 var formalParams []*types.Field // arguments of closure 2279 var formalResults []*types.Field // returns of closure 2280 for i := 0; i < typ.NumParams(); i++ { 2281 t := typ.Params().Field(i).Type 2282 arg := ir.NewNameAt(pos, closureSym(outer, "a", i)) 2283 arg.Class = ir.PPARAM 2284 typed(t, arg) 2285 arg.Curfn = fn 2286 fn.Dcl = append(fn.Dcl, arg) 2287 f := types.NewField(pos, arg.Sym(), t) 2288 f.Nname = arg 2289 f.SetIsDDD(typ.Params().Field(i).IsDDD()) 2290 formalParams = append(formalParams, f) 2291 } 2292 for i := 0; i < typ.NumResults(); i++ { 2293 t := typ.Results().Field(i).Type 2294 result := ir.NewNameAt(pos, closureSym(outer, "r", i)) // TODO: names not needed? 2295 result.Class = ir.PPARAMOUT 2296 typed(t, result) 2297 result.Curfn = fn 2298 fn.Dcl = append(fn.Dcl, result) 2299 f := types.NewField(pos, result.Sym(), t) 2300 f.Nname = result 2301 formalResults = append(formalResults, f) 2302 } 2303 2304 // Build an internal function with the right signature. 2305 closureType := types.NewSignature(typ.Pkg(), nil, nil, formalParams, formalResults) 2306 typed(closureType, fn.Nname) 2307 typed(typ, fn.OClosure) 2308 fn.SetTypecheck(1) 2309 return fn, formalParams, formalResults 2310 2311 } 2312 2313 // closureSym returns outer.Sym().Pkg.LookupNum(prefix, n). 2314 // If outer is nil, then types.LocalPkg is used instead. 2315 func closureSym(outer *ir.Func, prefix string, n int) *types.Sym { 2316 pkg := types.LocalPkg 2317 if outer != nil { 2318 pkg = outer.Sym().Pkg 2319 } 2320 return pkg.LookupNum(prefix, n) 2321 } 2322 2323 // assertToBound returns a new node that converts a node rcvr with interface type to 2324 // the 'dst' interface type. 2325 func assertToBound(info *instInfo, dictVar *ir.Name, pos src.XPos, rcvr ir.Node, dst *types.Type) ir.Node { 2326 if !dst.HasShape() { 2327 return typed(dst, ir.NewTypeAssertExpr(pos, rcvr, nil)) 2328 } 2329 2330 ix := findDictType(info, dst) 2331 assert(ix >= 0) 2332 rt := getDictionaryType(info, dictVar, pos, ix) 2333 return typed(dst, ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, rcvr, rt)) 2334 }