@@ -60,7 +60,8 @@ function copy(x::PhiCNode)
6060 return PhiCNode (new_values)
6161end
6262
63- # copy parts of an AST that the compiler mutates
63+ # copy parts of an IR that the compiler mutates
64+ # (this is not a general-purpose copy for an Expr AST)
6465function copy_exprs (@nospecialize (x))
6566 if isa (x, Expr)
6667 return copy (x)
@@ -91,10 +92,86 @@ function copy(c::CodeInfo)
9192 return cnew
9293end
9394
95+ function isequal_exprarg (@nospecialize (x), @nospecialize (y))
96+ x isa typeof (y) || return false
97+ x === y && return true
98+ # c.f. list of types in copy_expr also
99+ if x isa Expr
100+ x == (y:: Expr ) && return true
101+ elseif x isa QuoteNode
102+ x == (y:: QuoteNode ) && return true
103+ elseif x isa PhiNode
104+ x == (y:: PhiNode ) && return true
105+ elseif x isa PhiCNode
106+ x == (y:: PhiCNode ) && return true
107+ elseif x isa CodeInfo
108+ x == (y:: CodeInfo ) && return true
109+ end
110+ return false
111+ end
112+
113+
114+ function isequal_exprargs (x:: Array{Any,1} , y:: Array{Any,1} )
115+ l = length (x)
116+ l == length (y) || return false
117+ for i = 1 : l
118+ if ! isassigned (x, i)
119+ # phi and phic values are permitted to be undef
120+ isassigned (y, i) && return false
121+ else
122+ isassigned (y, i) || return false
123+ isequal_exprarg (x[i], y[i]) || return false
124+ end
125+ end
126+ return true
127+ end
128+
129+ # define == such that == inputs to parsing (including line numbers) yield == outputs from lowering (including all metadata)
130+ # (aside from cases where parsing just returns a number, which are ambiguous here)
131+ == (x:: Expr , y:: Expr ) = x. head === y. head && isequal_exprargs (x. args, y. args)
132+
133+ == (x:: QuoteNode , y:: QuoteNode ) = isequal_exprarg (x. value, y. value)
134+
135+ == (stmt1:: Core.PhiNode , stmt2:: Core.PhiNode ) = isequal (stmt1. edges, stmt2. edges) && isequal_exprargs (stmt1. values, stmt2. values)
136+
137+ == (stmt1:: Core.PhiCNode , stmt2:: Core.PhiCNode ) = isequal_exprargs (stmt1. values, stmt2. values)
138+
139+ function == (stmt1:: CodeInfo , stmt2:: CodeInfo )
140+ for i in 1 : nfields (stmt1)
141+ if ! isdefined (stmt1, i)
142+ isdefined (stmt2, i) && return false
143+ else
144+ isdefined (stmt2, i) || return false
145+ f1 = getfield (stmt1, i)
146+ f2 = getfield (stmt2, i)
147+ f1 isa typeof (f2) || return false
148+ if f1 isa Vector{Any}
149+ # code or types vectors
150+ isequal_exprargs (f1, f2:: Vector{Any} ) || return false
151+ elseif f1 isa DebugInfo
152+ f1 == f2:: DebugInfo || return false
153+ elseif f1 isa Vector
154+ # misc data
155+ l = length (f1)
156+ l == length (f2:: Vector ) || return false
157+ for i = 1 : l
158+ f1[i] === f2[i] || return false
159+ end
160+ else
161+ # misc fields
162+ f1 === f2 || return false
163+ end
164+ end
165+ end
166+ return true
167+ end
94168
95- == (x:: Expr , y:: Expr ) = x. head === y. head && isequal (x. args, y. args)
96- == (x:: QuoteNode , y:: QuoteNode ) = isequal (x. value, y. value)
97- == (stmt1:: Core.PhiNode , stmt2:: Core.PhiNode ) = stmt1. edges == stmt2. edges && stmt1. values == stmt2. values
169+ function == (x:: DebugInfo , y:: DebugInfo )
170+ for i in 1 : nfields (x)
171+ getfield (x, i) == getfield (y, i) || return false
172+ end
173+ return true
174+ end
98175
99176"""
100177 macroexpand(m::Module, x; recursive=true)
@@ -1662,14 +1739,45 @@ end
16621739is_meta_expr_head (head:: Symbol ) = head === :boundscheck || head === :meta || head === :loopinfo
16631740is_meta_expr (@nospecialize x) = isa (x, Expr) && is_meta_expr_head (x. head)
16641741
1665- function is_self_quoting (@nospecialize (x))
1666- return isa (x,Number) || isa (x,AbstractString) || isa (x,Tuple) || isa (x,Type) ||
1667- isa (x,Char) || x === nothing || isa (x,Function)
1668- end
1742+ """
1743+ isa_ast_node(x)
16691744
1670- function quoted (@nospecialize (x))
1671- return is_self_quoting (x) ? x : QuoteNode (x)
1672- end
1745+ Return false if `x` is not interpreted specially by any of inference, lowering,
1746+ or codegen as either an AST or IR special form.
1747+ """
1748+ function isa_ast_node (@nospecialize x)
1749+ # c.f. Core.IR module, augmented with AST types
1750+ return x isa NewvarNode ||
1751+ x isa CodeInfo ||
1752+ x isa LineNumberNode ||
1753+ x isa GotoNode ||
1754+ x isa GotoIfNot ||
1755+ x isa EnterNode ||
1756+ x isa ReturnNode ||
1757+ x isa SSAValue ||
1758+ x isa SlotNumber ||
1759+ x isa Argument ||
1760+ x isa QuoteNode ||
1761+ x isa GlobalRef ||
1762+ x isa Symbol ||
1763+ x isa PiNode ||
1764+ x isa PhiNode ||
1765+ x isa PhiCNode ||
1766+ x isa UpsilonNode ||
1767+ x isa Expr
1768+ end
1769+
1770+ is_self_quoting (@nospecialize (x)) = ! isa_ast_node (x)
1771+
1772+ """
1773+ quoted(x)
1774+
1775+ Return `x` made safe for inserting as a constant into IR. Note that this does
1776+ not make it safe for inserting into an AST, since eval will sometimes copy some
1777+ types of AST object inside, and even may sometimes evaluate and interpolate any
1778+ `\$ ` inside, depending on the context.
1779+ """
1780+ quoted (@nospecialize (x)) = isa_ast_node (x) ? QuoteNode (x) : x
16731781
16741782# Implementation of generated functions
16751783function generated_body_to_codeinfo (ex:: Expr , defmod:: Module , isva:: Bool )
0 commit comments