github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/noder/transform.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 contains transformation functions on nodes, which are the 6 // transformations that the typecheck package does that are distinct from the 7 // typechecking functionality. These transform functions are pared-down copies of 8 // the original typechecking functions, with all code removed that is related to: 9 // 10 // - Detecting compile-time errors (already done by types2) 11 // - Setting the actual type of existing nodes (already done based on 12 // type info from types2) 13 // - Dealing with untyped constants (which types2 has already resolved) 14 // 15 // Each of the transformation functions requires that node passed in has its type 16 // and typecheck flag set. If the transformation function replaces or adds new 17 // nodes, it will set the type and typecheck flag for those new nodes. 18 19 package noder 20 21 import ( 22 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 23 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 24 "github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck" 25 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 26 "fmt" 27 "github.com/bir3/gocompiler/src/go/constant" 28 ) 29 30 // Transformation functions for expressions 31 32 // transformAdd transforms an addition operation (currently just addition of 33 // strings). Corresponds to the "binary operators" case in typecheck.typecheck1. 34 func transformAdd(n *ir.BinaryExpr) ir.Node { 35 assert(n.Type() != nil && n.Typecheck() == 1) 36 l := n.X 37 if l.Type().IsString() { 38 var add *ir.AddStringExpr 39 if l.Op() == ir.OADDSTR { 40 add = l.(*ir.AddStringExpr) 41 add.SetPos(n.Pos()) 42 } else { 43 add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l}) 44 } 45 r := n.Y 46 if r.Op() == ir.OADDSTR { 47 r := r.(*ir.AddStringExpr) 48 add.List.Append(r.List.Take()...) 49 } else { 50 add.List.Append(r) 51 } 52 typed(l.Type(), add) 53 return add 54 } 55 return n 56 } 57 58 // Corresponds to typecheck.stringtoruneslit. 59 func stringtoruneslit(n *ir.ConvExpr) ir.Node { 60 if n.X.Op() != ir.OLITERAL || n.X.Val().Kind() != constant.String { 61 base.Fatalf("stringtoarraylit %v", n) 62 } 63 64 var list []ir.Node 65 i := 0 66 eltType := n.Type().Elem() 67 for _, r := range ir.StringVal(n.X) { 68 elt := ir.NewKeyExpr(base.Pos, ir.NewInt(int64(i)), ir.NewInt(int64(r))) 69 // Change from untyped int to the actual element type determined 70 // by types2. No need to change elt.Key, since the array indexes 71 // are just used for setting up the element ordering. 72 elt.Value.SetType(eltType) 73 list = append(list, elt) 74 i++ 75 } 76 77 nn := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, n.Type(), list) 78 typed(n.Type(), nn) 79 // Need to transform the OCOMPLIT. 80 return transformCompLit(nn) 81 } 82 83 // transformConv transforms an OCONV node as needed, based on the types involved, 84 // etc. Corresponds to typecheck.tcConv. 85 func transformConv(n *ir.ConvExpr) ir.Node { 86 t := n.X.Type() 87 op, why := typecheck.Convertop(n.X.Op() == ir.OLITERAL, t, n.Type()) 88 if op == ir.OXXX { 89 // types2 currently ignores pragmas, so a 'notinheap' mismatch is the 90 // one type-related error that it does not catch. This error will be 91 // caught here by Convertop (see two checks near beginning of 92 // Convertop) and reported at the end of noding. 93 base.ErrorfAt(n.Pos(), "cannot convert %L to type %v%s", n.X, n.Type(), why) 94 return n 95 } 96 n.SetOp(op) 97 switch n.Op() { 98 case ir.OCONVNOP: 99 if t.Kind() == n.Type().Kind() { 100 switch t.Kind() { 101 case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128: 102 // Floating point casts imply rounding and 103 // so the conversion must be kept. 104 n.SetOp(ir.OCONV) 105 } 106 } 107 108 // Do not convert to []byte literal. See CL 125796. 109 // Generated code and compiler memory footprint is better without it. 110 case ir.OSTR2BYTES: 111 // ok 112 113 case ir.OSTR2RUNES: 114 if n.X.Op() == ir.OLITERAL { 115 return stringtoruneslit(n) 116 } 117 118 case ir.OBYTES2STR: 119 assert(t.IsSlice()) 120 assert(t.Elem().Kind() == types.TUINT8) 121 if t.Elem() != types.ByteType && t.Elem() != types.Types[types.TUINT8] { 122 // If t is a slice of a user-defined byte type B (not uint8 123 // or byte), then add an extra CONVNOP from []B to []byte, so 124 // that the call to slicebytetostring() added in walk will 125 // typecheck correctly. 126 n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.ByteType), n.X) 127 n.X.SetTypecheck(1) 128 } 129 130 case ir.ORUNES2STR: 131 assert(t.IsSlice()) 132 assert(t.Elem().Kind() == types.TINT32) 133 if t.Elem() != types.RuneType && t.Elem() != types.Types[types.TINT32] { 134 // If t is a slice of a user-defined rune type B (not uint32 135 // or rune), then add an extra CONVNOP from []B to []rune, so 136 // that the call to slicerunetostring() added in walk will 137 // typecheck correctly. 138 n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.RuneType), n.X) 139 n.X.SetTypecheck(1) 140 } 141 142 } 143 return n 144 } 145 146 // transformConvCall transforms a conversion call. Corresponds to the OTYPE part of 147 // typecheck.tcCall. 148 func transformConvCall(n *ir.CallExpr) ir.Node { 149 assert(n.Type() != nil && n.Typecheck() == 1) 150 arg := n.Args[0] 151 n1 := ir.NewConvExpr(n.Pos(), ir.OCONV, nil, arg) 152 typed(n.X.Type(), n1) 153 return transformConv(n1) 154 } 155 156 // transformCall transforms a normal function/method call. Corresponds to last half 157 // (non-conversion, non-builtin part) of typecheck.tcCall. This code should work even 158 // in the case of OCALL/OFUNCINST. 159 func transformCall(n *ir.CallExpr) { 160 // Set base.Pos, since transformArgs below may need it, but transformCall 161 // is called in some passes that don't set base.Pos. 162 ir.SetPos(n) 163 // n.Type() can be nil for calls with no return value 164 assert(n.Typecheck() == 1) 165 typecheck.RewriteNonNameCall(n) 166 transformArgs(n) 167 l := n.X 168 t := l.Type() 169 170 switch l.Op() { 171 case ir.ODOTINTER: 172 n.SetOp(ir.OCALLINTER) 173 174 case ir.ODOTMETH: 175 l := l.(*ir.SelectorExpr) 176 n.SetOp(ir.OCALLMETH) 177 178 tp := t.Recv().Type 179 180 if l.X == nil || !types.Identical(l.X.Type(), tp) { 181 base.Fatalf("method receiver") 182 } 183 184 default: 185 n.SetOp(ir.OCALLFUNC) 186 } 187 188 typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args) 189 if l.Op() == ir.ODOTMETH && len(deref(n.X.Type().Recv().Type).RParams()) == 0 { 190 typecheck.FixMethodCall(n) 191 } 192 if t.NumResults() == 1 { 193 if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME { 194 if sym := n.X.(*ir.Name).Sym(); types.IsRuntimePkg(sym.Pkg) && sym.Name == "getg" { 195 // Emit code for runtime.getg() directly instead of calling function. 196 // Most such rewrites (for example the similar one for math.Sqrt) should be done in walk, 197 // so that the ordering pass can make sure to preserve the semantics of the original code 198 // (in particular, the exact time of the function call) by introducing temporaries. 199 // In this case, we know getg() always returns the same result within a given function 200 // and we want to avoid the temporaries, so we do the rewrite earlier than is typical. 201 n.SetOp(ir.OGETG) 202 } 203 } 204 return 205 } 206 } 207 208 // transformEarlyCall transforms the arguments of a call with an OFUNCINST node. 209 func transformEarlyCall(n *ir.CallExpr) { 210 transformArgs(n) 211 typecheckaste(ir.OCALL, n.X, n.IsDDD, n.X.Type().Params(), n.Args) 212 } 213 214 // transformCompare transforms a compare operation (currently just equals/not 215 // equals). Corresponds to the "comparison operators" case in 216 // typecheck.typecheck1, including tcArith. 217 func transformCompare(n *ir.BinaryExpr) { 218 assert(n.Type() != nil && n.Typecheck() == 1) 219 if (n.Op() == ir.OEQ || n.Op() == ir.ONE) && !types.Identical(n.X.Type(), n.Y.Type()) { 220 // Comparison is okay as long as one side is assignable to the 221 // other. The only allowed case where the conversion is not CONVNOP is 222 // "concrete == interface". In that case, check comparability of 223 // the concrete type. The conversion allocates, so only do it if 224 // the concrete type is huge. 225 l, r := n.X, n.Y 226 lt, rt := l.Type(), r.Type() 227 converted := false 228 if rt.Kind() != types.TBLANK { 229 aop, _ := typecheck.Assignop(lt, rt) 230 if aop != ir.OXXX { 231 types.CalcSize(lt) 232 if lt.HasShape() || rt.IsInterface() == lt.IsInterface() || lt.Size() >= 1<<16 { 233 l = ir.NewConvExpr(base.Pos, aop, rt, l) 234 l.SetTypecheck(1) 235 } 236 237 converted = true 238 } 239 } 240 241 if !converted && lt.Kind() != types.TBLANK { 242 aop, _ := typecheck.Assignop(rt, lt) 243 if aop != ir.OXXX { 244 types.CalcSize(rt) 245 if rt.HasShape() || rt.IsInterface() == lt.IsInterface() || rt.Size() >= 1<<16 { 246 r = ir.NewConvExpr(base.Pos, aop, lt, r) 247 r.SetTypecheck(1) 248 } 249 } 250 } 251 n.X, n.Y = l, r 252 } 253 } 254 255 // Corresponds to typecheck.implicitstar. 256 func implicitstar(n ir.Node) ir.Node { 257 // insert implicit * if needed for fixed array 258 t := n.Type() 259 if !t.IsPtr() { 260 return n 261 } 262 t = t.Elem() 263 if !t.IsArray() { 264 return n 265 } 266 star := ir.NewStarExpr(base.Pos, n) 267 star.SetImplicit(true) 268 return typed(t, star) 269 } 270 271 // transformIndex transforms an index operation. Corresponds to typecheck.tcIndex. 272 func transformIndex(n *ir.IndexExpr) { 273 assert(n.Type() != nil && n.Typecheck() == 1) 274 n.X = implicitstar(n.X) 275 l := n.X 276 t := l.Type() 277 if t.Kind() == types.TMAP { 278 n.Index = assignconvfn(n.Index, t.Key()) 279 n.SetOp(ir.OINDEXMAP) 280 // Set type to just the map value, not (value, bool). This is 281 // different from types2, but fits the later stages of the 282 // compiler better. 283 n.SetType(t.Elem()) 284 n.Assigned = false 285 } 286 } 287 288 // transformSlice transforms a slice operation. Corresponds to typecheck.tcSlice. 289 func transformSlice(n *ir.SliceExpr) { 290 assert(n.Type() != nil && n.Typecheck() == 1) 291 l := n.X 292 if l.Type().IsArray() { 293 addr := typecheck.NodAddr(n.X) 294 addr.SetImplicit(true) 295 typed(types.NewPtr(n.X.Type()), addr) 296 n.X = addr 297 l = addr 298 } 299 t := l.Type() 300 if t.IsString() { 301 n.SetOp(ir.OSLICESTR) 302 } else if t.IsPtr() && t.Elem().IsArray() { 303 if n.Op().IsSlice3() { 304 n.SetOp(ir.OSLICE3ARR) 305 } else { 306 n.SetOp(ir.OSLICEARR) 307 } 308 } 309 } 310 311 // Transformation functions for statements 312 313 // Corresponds to typecheck.checkassign. 314 func transformCheckAssign(stmt ir.Node, n ir.Node) { 315 if n.Op() == ir.OINDEXMAP { 316 n := n.(*ir.IndexExpr) 317 n.Assigned = true 318 return 319 } 320 } 321 322 // Corresponds to typecheck.assign. 323 func transformAssign(stmt ir.Node, lhs, rhs []ir.Node) { 324 checkLHS := func(i int, typ *types.Type) { 325 transformCheckAssign(stmt, lhs[i]) 326 } 327 328 cr := len(rhs) 329 if len(rhs) == 1 { 330 if rtyp := rhs[0].Type(); rtyp != nil && rtyp.IsFuncArgStruct() { 331 cr = rtyp.NumFields() 332 } 333 } 334 335 // x, ok = y 336 assignOK: 337 for len(lhs) == 2 && cr == 1 { 338 stmt := stmt.(*ir.AssignListStmt) 339 r := rhs[0] 340 341 switch r.Op() { 342 case ir.OINDEXMAP: 343 stmt.SetOp(ir.OAS2MAPR) 344 case ir.ORECV: 345 stmt.SetOp(ir.OAS2RECV) 346 case ir.ODOTTYPE: 347 r := r.(*ir.TypeAssertExpr) 348 stmt.SetOp(ir.OAS2DOTTYPE) 349 r.SetOp(ir.ODOTTYPE2) 350 case ir.ODYNAMICDOTTYPE: 351 r := r.(*ir.DynamicTypeAssertExpr) 352 stmt.SetOp(ir.OAS2DOTTYPE) 353 r.SetOp(ir.ODYNAMICDOTTYPE2) 354 default: 355 break assignOK 356 } 357 checkLHS(0, r.Type()) 358 checkLHS(1, types.UntypedBool) 359 t := lhs[0].Type() 360 if t != nil && rhs[0].Type().HasShape() && t.IsInterface() && !types.IdenticalStrict(t, rhs[0].Type()) { 361 // This is a multi-value assignment (map, channel, or dot-type) 362 // where the main result is converted to an interface during the 363 // assignment. Normally, the needed CONVIFACE is not created 364 // until (*orderState).as2ok(), because the AS2* ops and their 365 // sub-ops are so tightly intertwined. But we need to create the 366 // CONVIFACE now to enable dictionary lookups. So, assign the 367 // results first to temps, so that we can manifest the CONVIFACE 368 // in assigning the first temp to lhs[0]. If we added the 369 // CONVIFACE into rhs[0] directly, we would break a lot of later 370 // code that depends on the tight coupling between the AS2* ops 371 // and their sub-ops. (Issue #50642). 372 v := typecheck.Temp(rhs[0].Type()) 373 ok := typecheck.Temp(types.Types[types.TBOOL]) 374 as := ir.NewAssignListStmt(base.Pos, stmt.Op(), []ir.Node{v, ok}, []ir.Node{r}) 375 as.Def = true 376 as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, v)) 377 as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, ok)) 378 as.SetTypecheck(1) 379 // Change stmt to be a normal assignment of the temps to the final 380 // left-hand-sides. We re-create the original multi-value assignment 381 // so that it assigns to the temps and add it as an init of stmt. 382 // 383 // TODO: fix the order of evaluation, so that the lval of lhs[0] 384 // is evaluated before rhs[0] (similar to problem in #50672). 385 stmt.SetOp(ir.OAS2) 386 stmt.PtrInit().Append(as) 387 // assignconvfn inserts the CONVIFACE. 388 stmt.Rhs = []ir.Node{assignconvfn(v, t), ok} 389 } 390 return 391 } 392 393 if len(lhs) != cr { 394 for i := range lhs { 395 checkLHS(i, nil) 396 } 397 return 398 } 399 400 // x,y,z = f() 401 if cr > len(rhs) { 402 stmt := stmt.(*ir.AssignListStmt) 403 stmt.SetOp(ir.OAS2FUNC) 404 r := rhs[0].(*ir.CallExpr) 405 rtyp := r.Type() 406 407 mismatched := false 408 failed := false 409 for i := range lhs { 410 result := rtyp.Field(i).Type 411 checkLHS(i, result) 412 413 if lhs[i].Type() == nil || result == nil { 414 failed = true 415 } else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) { 416 mismatched = true 417 } 418 } 419 if mismatched && !failed { 420 typecheck.RewriteMultiValueCall(stmt, r) 421 } 422 return 423 } 424 425 for i, r := range rhs { 426 checkLHS(i, r.Type()) 427 if lhs[i].Type() != nil { 428 rhs[i] = assignconvfn(r, lhs[i].Type()) 429 } 430 } 431 } 432 433 // Corresponds to typecheck.typecheckargs. Really just deals with multi-value calls. 434 func transformArgs(n ir.InitNode) { 435 var list []ir.Node 436 switch n := n.(type) { 437 default: 438 base.Fatalf("transformArgs %+v", n.Op()) 439 case *ir.CallExpr: 440 list = n.Args 441 if n.IsDDD { 442 return 443 } 444 case *ir.ReturnStmt: 445 list = n.Results 446 } 447 if len(list) != 1 { 448 return 449 } 450 451 t := list[0].Type() 452 if t == nil || !t.IsFuncArgStruct() { 453 return 454 } 455 456 // Save n as n.Orig for fmt.go. 457 if ir.Orig(n) == n { 458 n.(ir.OrigNode).SetOrig(ir.SepCopy(n)) 459 } 460 461 // Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...). 462 typecheck.RewriteMultiValueCall(n, list[0]) 463 } 464 465 // assignconvfn converts node n for assignment to type t. Corresponds to 466 // typecheck.assignconvfn. 467 func assignconvfn(n ir.Node, t *types.Type) ir.Node { 468 if t.Kind() == types.TBLANK { 469 return n 470 } 471 472 if n.Op() == ir.OPAREN { 473 n = n.(*ir.ParenExpr).X 474 } 475 476 if types.IdenticalStrict(n.Type(), t) { 477 return n 478 } 479 480 op, why := Assignop(n.Type(), t) 481 if op == ir.OXXX { 482 base.Fatalf("found illegal assignment %+v -> %+v; %s", n.Type(), t, why) 483 } 484 485 r := ir.NewConvExpr(base.Pos, op, t, n) 486 r.SetTypecheck(1) 487 r.SetImplicit(true) 488 return r 489 } 490 491 func Assignop(src, dst *types.Type) (ir.Op, string) { 492 if src == dst { 493 return ir.OCONVNOP, "" 494 } 495 if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil { 496 return ir.OXXX, "" 497 } 498 499 // 1. src type is identical to dst (taking shapes into account) 500 if types.Identical(src, dst) { 501 // We already know from assignconvfn above that IdenticalStrict(src, 502 // dst) is false, so the types are not exactly the same and one of 503 // src or dst is a shape. If dst is an interface (which means src is 504 // an interface too), we need a real OCONVIFACE op; otherwise we need a 505 // OCONVNOP. See issue #48453. 506 if dst.IsInterface() { 507 return ir.OCONVIFACE, "" 508 } else { 509 return ir.OCONVNOP, "" 510 } 511 } 512 return typecheck.Assignop1(src, dst) 513 } 514 515 // Corresponds to typecheck.typecheckaste, but we add an extra flag convifaceOnly 516 // only. If convifaceOnly is true, we only do interface conversion. We use this to do 517 // early insertion of CONVIFACE nodes during noder2, when the function or args may 518 // have typeparams. 519 func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes) { 520 var t *types.Type 521 var i int 522 523 lno := base.Pos 524 defer func() { base.Pos = lno }() 525 526 var n ir.Node 527 if len(nl) == 1 { 528 n = nl[0] 529 } 530 531 i = 0 532 for _, tl := range tstruct.Fields().Slice() { 533 t = tl.Type 534 if tl.IsDDD() { 535 if isddd { 536 n = nl[i] 537 ir.SetPos(n) 538 if n.Type() != nil { 539 nl[i] = assignconvfn(n, t) 540 } 541 return 542 } 543 544 // TODO(mdempsky): Make into ... call with implicit slice. 545 for ; i < len(nl); i++ { 546 n = nl[i] 547 ir.SetPos(n) 548 if n.Type() != nil { 549 nl[i] = assignconvfn(n, t.Elem()) 550 } 551 } 552 return 553 } 554 555 n = nl[i] 556 ir.SetPos(n) 557 if n.Type() != nil { 558 nl[i] = assignconvfn(n, t) 559 } 560 i++ 561 } 562 } 563 564 // transformSend transforms a send statement, converting the value to appropriate 565 // type for the channel, as needed. Corresponds of typecheck.tcSend. 566 func transformSend(n *ir.SendStmt) { 567 n.Value = assignconvfn(n.Value, n.Chan.Type().Elem()) 568 } 569 570 // transformReturn transforms a return node, by doing the needed assignments and 571 // any necessary conversions. Corresponds to typecheck.tcReturn() 572 func transformReturn(rs *ir.ReturnStmt) { 573 transformArgs(rs) 574 nl := rs.Results 575 if ir.HasNamedResults(ir.CurFunc) && len(nl) == 0 { 576 return 577 } 578 579 typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), nl) 580 } 581 582 // transformSelect transforms a select node, creating an assignment list as needed 583 // for each case. Corresponds to typecheck.tcSelect(). 584 func transformSelect(sel *ir.SelectStmt) { 585 for _, ncase := range sel.Cases { 586 if ncase.Comm != nil { 587 n := ncase.Comm 588 oselrecv2 := func(dst, recv ir.Node, def bool) { 589 selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv}) 590 if dst.Op() == ir.ONAME && dst.(*ir.Name).Defn == n { 591 // Must fix Defn for dst, since we are 592 // completely changing the node. 593 dst.(*ir.Name).Defn = selrecv 594 } 595 selrecv.Def = def 596 selrecv.SetTypecheck(1) 597 selrecv.SetInit(n.Init()) 598 ncase.Comm = selrecv 599 } 600 switch n.Op() { 601 case ir.OAS: 602 // convert x = <-c into x, _ = <-c 603 // remove implicit conversions; the eventual assignment 604 // will reintroduce them. 605 n := n.(*ir.AssignStmt) 606 if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE { 607 r := r.(*ir.ConvExpr) 608 if r.Implicit() { 609 n.Y = r.X 610 } 611 } 612 oselrecv2(n.X, n.Y, n.Def) 613 614 case ir.OAS2RECV: 615 n := n.(*ir.AssignListStmt) 616 n.SetOp(ir.OSELRECV2) 617 618 case ir.ORECV: 619 // convert <-c into _, _ = <-c 620 n := n.(*ir.UnaryExpr) 621 oselrecv2(ir.BlankNode, n, false) 622 623 case ir.OSEND: 624 break 625 } 626 } 627 } 628 } 629 630 // transformAsOp transforms an AssignOp statement. Corresponds to OASOP case in 631 // typecheck1. 632 func transformAsOp(n *ir.AssignOpStmt) { 633 transformCheckAssign(n, n.X) 634 } 635 636 // transformDot transforms an OXDOT (or ODOT) or ODOT, ODOTPTR, ODOTMETH, 637 // ODOTINTER, or OMETHVALUE, as appropriate. It adds in extra nodes as needed to 638 // access embedded fields. Corresponds to typecheck.tcDot. 639 func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node { 640 assert(n.Type() != nil && n.Typecheck() == 1) 641 if n.Op() == ir.OXDOT { 642 n = typecheck.AddImplicitDots(n) 643 n.SetOp(ir.ODOT) 644 645 // Set the Selection field and typecheck flag for any new ODOT nodes 646 // added by AddImplicitDots(), and also transform to ODOTPTR if 647 // needed. Equivalent to 'n.X = typecheck(n.X, ctxExpr|ctxType)' in 648 // tcDot. 649 for n1 := n; n1.X.Op() == ir.ODOT; { 650 n1 = n1.X.(*ir.SelectorExpr) 651 if !n1.Implicit() { 652 break 653 } 654 t1 := n1.X.Type() 655 if t1.IsPtr() && !t1.Elem().IsInterface() { 656 t1 = t1.Elem() 657 n1.SetOp(ir.ODOTPTR) 658 } 659 typecheck.Lookdot(n1, t1, 0) 660 n1.SetTypecheck(1) 661 } 662 } 663 664 t := n.X.Type() 665 666 if n.X.Op() == ir.OTYPE { 667 return transformMethodExpr(n) 668 } 669 670 if t.IsPtr() && !t.Elem().IsInterface() { 671 t = t.Elem() 672 n.SetOp(ir.ODOTPTR) 673 } 674 675 f := typecheck.Lookdot(n, t, 0) 676 assert(f != nil) 677 678 if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && !isCall { 679 n.SetOp(ir.OMETHVALUE) 680 // This converts a method type to a function type. See issue 47775. 681 n.SetType(typecheck.NewMethodType(n.Type(), nil)) 682 } 683 return n 684 } 685 686 // Corresponds to typecheck.typecheckMethodExpr. 687 func transformMethodExpr(n *ir.SelectorExpr) (res ir.Node) { 688 t := n.X.Type() 689 690 // Compute the method set for t. 691 var ms *types.Fields 692 if t.IsInterface() { 693 ms = t.AllMethods() 694 } else { 695 mt := types.ReceiverBaseType(t) 696 typecheck.CalcMethods(mt) 697 ms = mt.AllMethods() 698 699 // The method expression T.m requires a wrapper when T 700 // is different from m's declared receiver type. We 701 // normally generate these wrappers while writing out 702 // runtime type descriptors, which is always done for 703 // types declared at package scope. However, we need 704 // to make sure to generate wrappers for anonymous 705 // receiver types too. 706 if mt.Sym() == nil { 707 typecheck.NeedRuntimeType(t) 708 } 709 } 710 711 s := n.Sel 712 m := typecheck.Lookdot1(n, s, t, ms, 0) 713 if !t.HasShape() { 714 // It's OK to not find the method if t is instantiated by shape types, 715 // because we will use the methods on the generic type anyway. 716 assert(m != nil) 717 } 718 719 n.SetOp(ir.OMETHEXPR) 720 n.Selection = m 721 n.SetType(typecheck.NewMethodType(m.Type, n.X.Type())) 722 return n 723 } 724 725 // Corresponds to typecheck.tcAppend. 726 func transformAppend(n *ir.CallExpr) ir.Node { 727 transformArgs(n) 728 args := n.Args 729 t := args[0].Type() 730 assert(t.IsSlice()) 731 732 if n.IsDDD { 733 // assignconvfn is of args[1] not required here, as the 734 // types of args[0] and args[1] don't need to match 735 // (They will both have an underlying type which are 736 // slices of identical base types, or be []byte and string.) 737 // See issue 53888. 738 return n 739 } 740 741 as := args[1:] 742 for i, n := range as { 743 assert(n.Type() != nil) 744 as[i] = assignconvfn(n, t.Elem()) 745 } 746 return n 747 } 748 749 // Corresponds to typecheck.tcComplex. 750 func transformComplex(n *ir.BinaryExpr) ir.Node { 751 l := n.X 752 r := n.Y 753 754 assert(types.Identical(l.Type(), r.Type())) 755 756 var t *types.Type 757 switch l.Type().Kind() { 758 case types.TFLOAT32: 759 t = types.Types[types.TCOMPLEX64] 760 case types.TFLOAT64: 761 t = types.Types[types.TCOMPLEX128] 762 default: 763 panic(fmt.Sprintf("transformComplex: unexpected type %v", l.Type())) 764 } 765 766 // Must set the type here for generics, because this can't be determined 767 // by substitution of the generic types. 768 typed(t, n) 769 return n 770 } 771 772 // Corresponds to typecheck.tcDelete. 773 func transformDelete(n *ir.CallExpr) ir.Node { 774 transformArgs(n) 775 args := n.Args 776 assert(len(args) == 2) 777 778 l := args[0] 779 r := args[1] 780 781 args[1] = assignconvfn(r, l.Type().Key()) 782 return n 783 } 784 785 // Corresponds to typecheck.tcMake. 786 func transformMake(n *ir.CallExpr) ir.Node { 787 args := n.Args 788 789 n.Args = nil 790 l := args[0] 791 t := l.Type() 792 assert(t != nil) 793 794 i := 1 795 var nn ir.Node 796 switch t.Kind() { 797 case types.TSLICE: 798 l = args[i] 799 i++ 800 var r ir.Node 801 if i < len(args) { 802 r = args[i] 803 i++ 804 } 805 nn = ir.NewMakeExpr(n.Pos(), ir.OMAKESLICE, l, r) 806 807 case types.TMAP: 808 if i < len(args) { 809 l = args[i] 810 i++ 811 } else { 812 l = ir.NewInt(0) 813 } 814 nn = ir.NewMakeExpr(n.Pos(), ir.OMAKEMAP, l, nil) 815 nn.SetEsc(n.Esc()) 816 817 case types.TCHAN: 818 l = nil 819 if i < len(args) { 820 l = args[i] 821 i++ 822 } else { 823 l = ir.NewInt(0) 824 } 825 nn = ir.NewMakeExpr(n.Pos(), ir.OMAKECHAN, l, nil) 826 default: 827 panic(fmt.Sprintf("transformMake: unexpected type %v", t)) 828 } 829 830 assert(i == len(args)) 831 typed(n.Type(), nn) 832 return nn 833 } 834 835 // Corresponds to typecheck.tcPanic. 836 func transformPanic(n *ir.UnaryExpr) ir.Node { 837 n.X = assignconvfn(n.X, types.Types[types.TINTER]) 838 return n 839 } 840 841 // Corresponds to typecheck.tcPrint. 842 func transformPrint(n *ir.CallExpr) ir.Node { 843 transformArgs(n) 844 return n 845 } 846 847 // Corresponds to typecheck.tcRealImag. 848 func transformRealImag(n *ir.UnaryExpr) ir.Node { 849 l := n.X 850 var t *types.Type 851 852 // Determine result type. 853 switch l.Type().Kind() { 854 case types.TCOMPLEX64: 855 t = types.Types[types.TFLOAT32] 856 case types.TCOMPLEX128: 857 t = types.Types[types.TFLOAT64] 858 default: 859 panic(fmt.Sprintf("transformRealImag: unexpected type %v", l.Type())) 860 } 861 862 // Must set the type here for generics, because this can't be determined 863 // by substitution of the generic types. 864 typed(t, n) 865 return n 866 } 867 868 // Corresponds to typecheck.tcLenCap. 869 func transformLenCap(n *ir.UnaryExpr) ir.Node { 870 n.X = implicitstar(n.X) 871 return n 872 } 873 874 // Corresponds to Builtin part of tcCall. 875 func transformBuiltin(n *ir.CallExpr) ir.Node { 876 // n.Type() can be nil for builtins with no return value 877 assert(n.Typecheck() == 1) 878 fun := n.X.(*ir.Name) 879 op := fun.BuiltinOp 880 881 switch op { 882 case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER: 883 n.SetOp(op) 884 n.X = nil 885 switch op { 886 case ir.OAPPEND: 887 return transformAppend(n) 888 case ir.ODELETE: 889 return transformDelete(n) 890 case ir.OMAKE: 891 return transformMake(n) 892 case ir.OPRINT, ir.OPRINTN: 893 return transformPrint(n) 894 case ir.ORECOVER: 895 // nothing more to do 896 return n 897 } 898 899 case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL: 900 transformArgs(n) 901 fallthrough 902 903 case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF, ir.OUNSAFESLICEDATA, ir.OUNSAFESTRINGDATA: 904 u := ir.NewUnaryExpr(n.Pos(), op, n.Args[0]) 905 u1 := typed(n.Type(), ir.InitExpr(n.Init(), u)) // typecheckargs can add to old.Init 906 switch op { 907 case ir.OCAP, ir.OLEN: 908 return transformLenCap(u1.(*ir.UnaryExpr)) 909 case ir.OREAL, ir.OIMAG: 910 return transformRealImag(u1.(*ir.UnaryExpr)) 911 case ir.OPANIC: 912 return transformPanic(u1.(*ir.UnaryExpr)) 913 case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: 914 // This corresponds to the EvalConst() call near end of typecheck(). 915 return typecheck.EvalConst(u1) 916 case ir.OCLOSE, ir.ONEW, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA: 917 // nothing more to do 918 return u1 919 } 920 921 case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING: 922 transformArgs(n) 923 b := ir.NewBinaryExpr(n.Pos(), op, n.Args[0], n.Args[1]) 924 n1 := typed(n.Type(), ir.InitExpr(n.Init(), b)) 925 if op != ir.OCOMPLEX { 926 // nothing more to do 927 return n1 928 } 929 return transformComplex(n1.(*ir.BinaryExpr)) 930 931 default: 932 panic(fmt.Sprintf("transformBuiltin: unexpected op %v", op)) 933 } 934 935 return n 936 } 937 938 func hasKeys(l ir.Nodes) bool { 939 for _, n := range l { 940 if n.Op() == ir.OKEY || n.Op() == ir.OSTRUCTKEY { 941 return true 942 } 943 } 944 return false 945 } 946 947 // transformArrayLit runs assignconvfn on each array element and returns the 948 // length of the slice/array that is needed to hold all the array keys/indexes 949 // (one more than the highest index). Corresponds to typecheck.typecheckarraylit. 950 func transformArrayLit(elemType *types.Type, bound int64, elts []ir.Node) int64 { 951 var key, length int64 952 for i, elt := range elts { 953 ir.SetPos(elt) 954 r := elts[i] 955 var kv *ir.KeyExpr 956 if elt.Op() == ir.OKEY { 957 elt := elt.(*ir.KeyExpr) 958 key = typecheck.IndexConst(elt.Key) 959 assert(key >= 0) 960 kv = elt 961 r = elt.Value 962 } 963 964 r = assignconvfn(r, elemType) 965 if kv != nil { 966 kv.Value = r 967 } else { 968 elts[i] = r 969 } 970 971 key++ 972 if key > length { 973 length = key 974 } 975 } 976 977 return length 978 } 979 980 // transformCompLit transforms n to an OARRAYLIT, OSLICELIT, OMAPLIT, or 981 // OSTRUCTLIT node, with any needed conversions. Corresponds to 982 // typecheck.tcCompLit (and includes parts corresponding to tcStructLitKey). 983 func transformCompLit(n *ir.CompLitExpr) (res ir.Node) { 984 assert(n.Type() != nil && n.Typecheck() == 1) 985 lno := base.Pos 986 defer func() { 987 base.Pos = lno 988 }() 989 990 // Save original node (including n.Right) 991 n.SetOrig(ir.Copy(n)) 992 993 ir.SetPos(n) 994 995 t := n.Type() 996 997 switch t.Kind() { 998 default: 999 base.Fatalf("transformCompLit %v", t.Kind()) 1000 1001 case types.TARRAY: 1002 transformArrayLit(t.Elem(), t.NumElem(), n.List) 1003 n.SetOp(ir.OARRAYLIT) 1004 1005 case types.TSLICE: 1006 length := transformArrayLit(t.Elem(), -1, n.List) 1007 n.SetOp(ir.OSLICELIT) 1008 n.Len = length 1009 1010 case types.TMAP: 1011 for _, l := range n.List { 1012 ir.SetPos(l) 1013 assert(l.Op() == ir.OKEY) 1014 l := l.(*ir.KeyExpr) 1015 1016 r := l.Key 1017 l.Key = assignconvfn(r, t.Key()) 1018 1019 r = l.Value 1020 l.Value = assignconvfn(r, t.Elem()) 1021 } 1022 1023 n.SetOp(ir.OMAPLIT) 1024 1025 case types.TSTRUCT: 1026 // Need valid field offsets for Xoffset below. 1027 types.CalcSize(t) 1028 1029 if len(n.List) != 0 && !hasKeys(n.List) { 1030 // simple list of values 1031 ls := n.List 1032 for i, n1 := range ls { 1033 ir.SetPos(n1) 1034 1035 f := t.Field(i) 1036 n1 = assignconvfn(n1, f.Type) 1037 ls[i] = ir.NewStructKeyExpr(base.Pos, f, n1) 1038 } 1039 assert(len(ls) >= t.NumFields()) 1040 } else { 1041 // keyed list 1042 ls := n.List 1043 for i, l := range ls { 1044 ir.SetPos(l) 1045 1046 kv := l.(*ir.KeyExpr) 1047 key := kv.Key 1048 1049 s := key.Sym() 1050 if types.IsExported(s.Name) && s.Pkg != types.LocalPkg { 1051 // Exported field names should always have 1052 // local pkg. We only need to do this 1053 // adjustment for generic functions that are 1054 // being transformed after being imported 1055 // from another package. 1056 s = typecheck.Lookup(s.Name) 1057 } 1058 1059 // An OXDOT uses the Sym field to hold 1060 // the field to the right of the dot, 1061 // so s will be non-nil, but an OXDOT 1062 // is never a valid struct literal key. 1063 assert(!(s == nil || key.Op() == ir.OXDOT || s.IsBlank())) 1064 1065 f := typecheck.Lookdot1(nil, s, t, t.Fields(), 0) 1066 l := ir.NewStructKeyExpr(l.Pos(), f, kv.Value) 1067 ls[i] = l 1068 1069 l.Value = assignconvfn(l.Value, f.Type) 1070 } 1071 } 1072 1073 n.SetOp(ir.OSTRUCTLIT) 1074 } 1075 1076 return n 1077 } 1078 1079 // transformAddr corresponds to typecheck.tcAddr. 1080 func transformAddr(n *ir.AddrExpr) { 1081 switch n.X.Op() { 1082 case ir.OARRAYLIT, ir.OMAPLIT, ir.OSLICELIT, ir.OSTRUCTLIT: 1083 n.SetOp(ir.OPTRLIT) 1084 } 1085 }