Source file src/cmd/compile/internal/ir/copy.go
1 // Copyright 2020 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 package ir 6 7 import ( 8 "cmd/compile/internal/base" 9 "cmd/internal/src" 10 ) 11 12 // A Node may implement the Orig and SetOrig method to 13 // maintain a pointer to the "unrewritten" form of a Node. 14 // If a Node does not implement OrigNode, it is its own Orig. 15 // 16 // Note that both SepCopy and Copy have definitions compatible 17 // with a Node that does not implement OrigNode: such a Node 18 // is its own Orig, and in that case, that's what both want to return 19 // anyway (SepCopy unconditionally, and Copy only when the input 20 // is its own Orig as well, but if the output does not implement 21 // OrigNode, then neither does the input, making the condition true). 22 type OrigNode interface { 23 Node 24 Orig() Node 25 SetOrig(Node) 26 } 27 28 // origNode may be embedded into a Node to make it implement OrigNode. 29 type origNode struct { 30 orig Node `mknode:"-"` 31 } 32 33 func (n *origNode) Orig() Node { return n.orig } 34 func (n *origNode) SetOrig(o Node) { n.orig = o } 35 36 // Orig returns the “original” node for n. 37 // If n implements OrigNode, Orig returns n.Orig(). 38 // Otherwise Orig returns n itself. 39 func Orig(n Node) Node { 40 if n, ok := n.(OrigNode); ok { 41 o := n.Orig() 42 if o == nil { 43 Dump("Orig nil", n) 44 base.Fatalf("Orig returned nil") 45 } 46 return o 47 } 48 return n 49 } 50 51 // SepCopy returns a separate shallow copy of n, 52 // breaking any Orig link to any other nodes. 53 func SepCopy(n Node) Node { 54 n = n.copy() 55 if n, ok := n.(OrigNode); ok { 56 n.SetOrig(n) 57 } 58 return n 59 } 60 61 // Copy returns a shallow copy of n. 62 // If Orig(n) == n, then Orig(Copy(n)) == the copy. 63 // Otherwise the Orig link is preserved as well. 64 // 65 // The specific semantics surrounding Orig are subtle but right for most uses. 66 // See issues #26855 and #27765 for pitfalls. 67 func Copy(n Node) Node { 68 c := n.copy() 69 if n, ok := n.(OrigNode); ok && n.Orig() == n { 70 c.(OrigNode).SetOrig(c) 71 } 72 return c 73 } 74 75 // DeepCopy returns a “deep” copy of n, with its entire structure copied 76 // (except for shared nodes like ONAME, ONONAME, OLITERAL, and OTYPE). 77 // If pos.IsKnown(), it sets the source position of newly allocated Nodes to pos. 78 func DeepCopy(pos src.XPos, n Node) Node { 79 var edit func(Node) Node 80 edit = func(x Node) Node { 81 switch x.Op() { 82 case OPACK, ONAME, ONONAME, OLITERAL, ONIL, OTYPE: 83 return x 84 } 85 x = Copy(x) 86 if pos.IsKnown() { 87 x.SetPos(pos) 88 } 89 EditChildren(x, edit) 90 return x 91 } 92 return edit(n) 93 } 94 95 // DeepCopyList returns a list of deep copies (using DeepCopy) of the nodes in list. 96 func DeepCopyList(pos src.XPos, list []Node) []Node { 97 var out []Node 98 for _, n := range list { 99 out = append(out, DeepCopy(pos, n)) 100 } 101 return out 102 } 103