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  

View as plain text