|  | // Copyright 2020 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package ir | 
|  |  | 
|  | import ( | 
|  | "cmd/compile/internal/base" | 
|  | "cmd/internal/src" | 
|  | ) | 
|  |  | 
|  | // A Node may implement the Orig and SetOrig method to | 
|  | // maintain a pointer to the "unrewritten" form of a Node. | 
|  | // If a Node does not implement OrigNode, it is its own Orig. | 
|  | // | 
|  | // Note that both SepCopy and Copy have definitions compatible | 
|  | // with a Node that does not implement OrigNode: such a Node | 
|  | // is its own Orig, and in that case, that's what both want to return | 
|  | // anyway (SepCopy unconditionally, and Copy only when the input | 
|  | // is its own Orig as well, but if the output does not implement | 
|  | // OrigNode, then neither does the input, making the condition true). | 
|  | type OrigNode interface { | 
|  | Node | 
|  | Orig() Node | 
|  | SetOrig(Node) | 
|  | } | 
|  |  | 
|  | // origNode may be embedded into a Node to make it implement OrigNode. | 
|  | type origNode struct { | 
|  | orig Node `mknode:"-"` | 
|  | } | 
|  |  | 
|  | func (n *origNode) Orig() Node     { return n.orig } | 
|  | func (n *origNode) SetOrig(o Node) { n.orig = o } | 
|  |  | 
|  | // Orig returns the “original” node for n. | 
|  | // If n implements OrigNode, Orig returns n.Orig(). | 
|  | // Otherwise Orig returns n itself. | 
|  | func Orig(n Node) Node { | 
|  | if n, ok := n.(OrigNode); ok { | 
|  | o := n.Orig() | 
|  | if o == nil { | 
|  | Dump("Orig nil", n) | 
|  | base.Fatalf("Orig returned nil") | 
|  | } | 
|  | return o | 
|  | } | 
|  | return n | 
|  | } | 
|  |  | 
|  | // SepCopy returns a separate shallow copy of n, | 
|  | // breaking any Orig link to any other nodes. | 
|  | func SepCopy(n Node) Node { | 
|  | n = n.copy() | 
|  | if n, ok := n.(OrigNode); ok { | 
|  | n.SetOrig(n) | 
|  | } | 
|  | return n | 
|  | } | 
|  |  | 
|  | // Copy returns a shallow copy of n. | 
|  | // If Orig(n) == n, then Orig(Copy(n)) == the copy. | 
|  | // Otherwise the Orig link is preserved as well. | 
|  | // | 
|  | // The specific semantics surrounding Orig are subtle but right for most uses. | 
|  | // See issues #26855 and #27765 for pitfalls. | 
|  | func Copy(n Node) Node { | 
|  | c := n.copy() | 
|  | if n, ok := n.(OrigNode); ok && n.Orig() == n { | 
|  | c.(OrigNode).SetOrig(c) | 
|  | } | 
|  | return c | 
|  | } | 
|  |  | 
|  | // DeepCopy returns a “deep” copy of n, with its entire structure copied | 
|  | // (except for shared nodes like ONAME, ONONAME, OLITERAL, and OTYPE). | 
|  | // If pos.IsKnown(), it sets the source position of newly allocated Nodes to pos. | 
|  | func DeepCopy(pos src.XPos, n Node) Node { | 
|  | var edit func(Node) Node | 
|  | edit = func(x Node) Node { | 
|  | switch x.Op() { | 
|  | case OPACK, ONAME, ONONAME, OLITERAL, ONIL, OTYPE: | 
|  | return x | 
|  | } | 
|  | x = Copy(x) | 
|  | if pos.IsKnown() { | 
|  | x.SetPos(pos) | 
|  | } | 
|  | EditChildren(x, edit) | 
|  | return x | 
|  | } | 
|  | return edit(n) | 
|  | } | 
|  |  | 
|  | // DeepCopyList returns a list of deep copies (using DeepCopy) of the nodes in list. | 
|  | func DeepCopyList(pos src.XPos, list []Node) []Node { | 
|  | var out []Node | 
|  | for _, n := range list { | 
|  | out = append(out, DeepCopy(pos, n)) | 
|  | } | 
|  | return out | 
|  | } |