Skip to content
← Back

src/syntax/process/function_values.ghul

1
namespace Syntax.Process is
2
use Function = Semantic.Symbols.Function
3
use Symbol = Semantic.Symbols.Symbol
4
5
// Resolves a compiled value to the function it denotes, when the
6
// value's shape names one: a lambda literal compiled to a
7
// closure, a delegate constructed from a named function, a
8
// function pointer, an immutable local holding one of those.
9
// Populated by the resolved-mode effects walk, which notes each
10
// immutable local whose initializer named a function; consumed
11
// there and by the pure-slot judge.
12
class FUNCTION_VALUES is
13
// Immutable locals whose initializer named a function value,
14
// recorded by the current effects round's walk.
15
_local_function_values: Collections.MutableMap[Symbol, Function]
16
17
init() is
18
_local_function_values = Collections.MAP[Symbol, Function]()
19
si
20
21
note_local(symbol: Symbol, function: Function) is
22
_local_function_values[symbol] = function
23
si
24
25
// Dropped at the start of each effects round: the walk that is
26
// about to run re-records every live local, so anything left
27
// from an earlier round is either redundant or stale — a
28
// retained symbol whose initializer no longer names a function
29
// must stop resolving, and abandoned symbol generations must
30
// not be kept reachable for the life of an analysis process.
31
clear() is
32
_local_function_values.clear()
33
si
34
35
// Dropped for one file ahead of a round that re-walks only it:
36
// the locals recorded there are re-recorded by that walk, and
37
// every other file's stay current.
38
drop_file(file_name: string) is
39
let stale = Collections.LIST[Symbol]()
40
41
for symbol in _local_function_values.keys do
42
if symbol.location.file_name =~ file_name then
43
stale.add(symbol)
44
fi
45
od
46
47
for symbol in stale do
48
_local_function_values.remove(symbol)
49
od
50
si
51
52
function_value_of(value: IR.Values.Value?) -> Function? is
53
if !value? then
54
return null
55
fi
56
57
if let view: IR.Values.NARROW_VIEW = value then
58
return function_value_of(view.underlying)
59
fi
60
61
if let wrapper: IR.Values.WRAPPER = value then
62
return function_value_of(wrapper.value)
63
fi
64
65
if let wrapper: IR.Values.TYPE_WRAPPER = value then
66
return function_value_of(wrapper.value)
67
fi
68
69
if let memoized: IR.Values.MEMOIZED_DELEGATE = value then
70
return function_value_of(memoized.inner)
71
fi
72
73
if let wrap: IR.Values.PACK_WRAP = value then
74
if let wrapped = function_value_of(wrap.inner) then
75
return wrapped
76
fi
77
fi
78
79
// a capturing literal lowers to a block — frame setup,
80
// then the delegate load the block leaves behind, which
81
// may itself be spilled to a temp and reloaded
82
if let block: IR.Values.BLOCK = value then
83
return function_value_of(_block_result_source(block))
84
fi
85
86
if let load: IR.Values.Load.DELEGATE = value then
87
return function_value_of(load.function)
88
fi
89
90
if let load: IR.Values.Load.INSTANCE_ANONYMOUS_FUNCTION = value then
91
return cast Function?(load.symbol)
92
fi
93
94
if let load: IR.Values.Load.STATIC_ANONYMOUS_FUNCTION = value then
95
return cast Function?(load.symbol)
96
fi
97
98
if let load: IR.Values.Load.GLOBAL_ANONYMOUS_FUNCTION = value then
99
return cast Function?(load.symbol)
100
fi
101
102
// an immutable local can only ever hold its initializer's
103
// value, so a load of one denotes whatever function that
104
// named
105
if let load: IR.Values.Load.LOCAL_VARIABLE = value then
106
if _local_function_values.contains_key(load.symbol) then
107
return _local_function_values[load.symbol]
108
fi
109
110
return null
111
fi
112
113
// two closure-frame fields also name their value: the
114
// `$recurse` capture is the frame's own closure referring
115
// to itself, and a capture of an immutable local holds
116
// whatever that local does
117
if let load: IR.Values.Load.INSTANCE_FIELD = value then
118
if let frame_field: Semantic.Symbols.Field = load.symbol then
119
if frame_field.is_recurse_capture then
120
if let frame: Semantic.Symbols.FRAME = frame_field.owner then
121
return frame.closure
122
fi
123
fi
124
125
if let captured = frame_field.captured_symbol then
126
if _local_function_values.contains_key(captured) then
127
return _local_function_values[captured]
128
fi
129
fi
130
fi
131
132
return null
133
fi
134
135
return value.referenced_function
136
si
137
138
// The value a block leaves behind. When that is a temp
139
// reload, the value stored into the temp — the entry
140
// immediately before the matching store, since STORE_TEMP
141
// consumes what the previous entry pushed. Temp names are
142
// synthesized unique within the enclosing body, so a name
143
// match identifies the store.
144
_block_result_source(block: IR.Values.BLOCK) -> IR.Values.Value? is
145
let result = block.result_value
146
147
if let load: IR.Values.Load.TEMP = result then
148
let entries = block.values
149
150
for i in 1..entries.count do
151
if let store: IR.Values.STORE_TEMP = entries[i] then
152
if store.name =~ load.name then
153
return entries[i - 1]
154
fi
155
fi
156
od
157
fi
158
159
return result
160
si
161
si
162
si