Skip to content
← Back

src/syntax/process/infer-effects/infer_store_free_edges.ghul

1
namespace Syntax.Process is
2
use System.Exception
3
4
use Ghul.Pipes
5
6
use Logging
7
use Trees
8
9
use Semantic.Types.Type
10
11
use Function = Semantic.Symbols.Function
12
use Symbol = Semantic.Symbols.Symbol
13
14
// Callee-edge construction: callee and construction-callee lists, dispatch edges,
15
// property-read edges and member reads.
16
partial INFER_STORE_FREE is
17
_add_callee(callee: Function?) is
18
if !_current? then
19
return
20
fi
21
22
if !callee? then
23
_disqualify_because("callee-null")
24
return
25
fi
26
27
let root = cast Function?(callee.root_specialized_from)
28
29
if !root? then
30
_disqualify_because("callee-no-root")
31
return
32
fi
33
34
_current.add_callee(root)
35
si
36
37
_add_construction_callee(callee: Function?) is
38
if !_current? then
39
return
40
fi
41
42
if !callee? then
43
_disqualify_because("ctor-callee-null")
44
return
45
fi
46
47
let root = cast Function?(callee.root_specialized_from)
48
49
if !root? then
50
_disqualify_because("ctor-callee-no-root")
51
return
52
fi
53
54
_current.add_construction_callee(root)
55
si
56
57
_add_callee_edges(symbol: Symbol?) is
58
if !_current? then
59
return
60
fi
61
62
if !symbol? then
63
_disqualify_because("callee-symbol-null")
64
return
65
fi
66
67
if isa Semantic.Symbols.FUNCTION_GROUP(symbol) then
68
for function in (cast Semantic.Symbols.FUNCTION_GROUP(symbol)).functions do
69
_add_callee(function)
70
od
71
elif isa Function(symbol) then
72
_add_callee(cast Function(symbol))
73
elif
74
_resolved_mode /\
75
isa Semantic.Symbols.LOCAL_ARGUMENT(symbol) /\
76
symbol.type? /\ symbol.type.is_function
77
then
78
// invoking a function-typed parameter: bounded by the
79
// values the enclosing function's own callers pass
80
if _current_record? then
81
_current_record.invokes_function_param = true
82
fi
83
elif _is_store_free_construction(symbol) then
84
// constructing a fresh exception writes only that new
85
// object, never a pre-existing heap slot, so it cannot
86
// invalidate a narrowing
87
elif isa Semantic.Symbols.Classy(symbol) /\ !symbol.is_reflected then
88
_add_construction_edges((cast Semantic.Symbols.Classy(symbol)).find_member("init"))
89
else
90
// a delegate-typed value, an imported constructor, or
91
// something stranger: the call's effect cannot be
92
// bounded
93
_disqualify_because("callee-not-a-function:{symbol.get_type().name}")
94
fi
95
si
96
97
// Constructing a source-declared type runs a constructor on an
98
// object nothing else can reach yet, so the caller is bounded
99
// by the constructor's construction-store-free classification
100
// rather than its strict one — a constructor writing its own
101
// instance state stays store-free from where the construction
102
// is written. Overload resolution has not run, so every `init`
103
// the type declares has to qualify.
104
_add_construction_edges(constructors: Symbol?) is
105
if isa Semantic.Symbols.FUNCTION_GROUP(constructors) then
106
for function in (cast Semantic.Symbols.FUNCTION_GROUP(constructors)).functions do
107
_add_construction_callee(function)
108
od
109
110
return
111
fi
112
113
if isa Function(constructors) then
114
_add_construction_callee(cast Function(constructors))
115
return
116
fi
117
118
_disqualify_because("constructor-unresolved")
119
si
120
121
// Constructing an imported exception type is store-free for
122
// narrowing: an exception constructor by .NET convention only
123
// records its arguments into the new exception's own state and
124
// invokes no behaviour on them, so no user code runs and no
125
// pre-existing heap slot is written. The constructor arguments
126
// are classified as the walk reaches them, so a storing
127
// argument still disqualifies. Restricted to reflected types so
128
// a user-declared exception - whose constructor could store -
129
// stays unbounded.
130
_is_store_free_construction(symbol: Symbol?) -> bool is
131
if !symbol? \/ !symbol.is_reflected \/ !isa Semantic.Symbols.Classy(symbol) then
132
return false
133
fi
134
135
let exception_type = _innate_symbol_lookup.get_exception_type()
136
let classy_type = (cast Semantic.Symbols.Classy(symbol)).type
137
138
return classy_type? /\ exception_type.is_assignable_from(classy_type)
139
si
140
141
// A property read runs its getter, and a call that reaches
142
// the getter may dispatch to any overriding property's getter.
143
// Property override links live on the Property symbols, not
144
// on the accessor functions, so the override closure is
145
// expanded here rather than through Function.overriders.
146
_add_property_read_edges(property: Semantic.Symbols.Property) is
147
if !_current? then
148
return
149
fi
150
151
if !property.read_function? then
152
_disqualify_because("property-no-getter")
153
return
154
fi
155
156
_add_callee(property.read_function)
157
158
let overriders = property.overriders
159
160
if !overriders? then
161
return
162
fi
163
164
for overrider in overriders do
165
if isa Semantic.Symbols.Property(overrider) then
166
_add_property_read_edges(cast Semantic.Symbols.Property(overrider))
167
else
168
_disqualify_because("overrider-not-a-property")
169
fi
170
od
171
si
172
173
_classify_member_read(symbol: Symbol?) is
174
if !symbol? then
175
return
176
fi
177
178
if isa Semantic.Symbols.Property(symbol) then
179
_add_property_read_edges(cast Semantic.Symbols.Property(symbol))
180
fi
181
182
// fields, locals, parameters, function groups (a bare
183
// function reference only creates a delegate), types and
184
// namespaces are harmless reads
185
186
if
187
_current_record? /\
188
(isa Semantic.Symbols.Field(symbol) \/ isa Semantic.Symbols.Property(symbol))
189
then
190
_current_record.reads.add(symbol.root_specialized_from)
191
fi
192
si
193
194
si
195
si