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
5package ir
6
7import (
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).
22type 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.
29type origNode struct {
30	orig Node `mknode:"-"`
31}
32
33func (n *origNode) Orig() Node     { return n.orig }
34func (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.
39func 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.
53func 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.
67func 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.
78func 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.
96func 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