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