Skip to content
← Back

src/syntax/process/verify_compile_state.ghul

1
namespace Syntax.Process is
2
use Logging
3
use Trees
4
5
// Checks, once every body has compiled and the effect rounds have
6
// settled, that the state compile-expressions left on the tree is
7
// closed: every value's type is settled, with no inference
8
// placeholder, no ERROR and no type parameter foreign to the body
9
// that reads it, and every function literal's closure has settled
10
// argument and return types. Generate-il reads that state as if it
11
// were, and a slot the retry loop never converged reaches it as a
12
// bad instruction or a runtime failure with nothing to say where
13
// it came from. Reporting here names the node.
14
//
15
// Runs only on a build with no errors: a body that failed to
16
// resolve legitimately leaves ERROR behind, and the diagnostic that
17
// put it there is the one to read.
18
class VERIFY_COMPILE_STATE: DefaultVisitor is
19
_violations: int
20
_uninferred: Collections.LIST[Semantic.Symbols.Variable]
21
_uninferred_reads: Collections.LIST[Source.LOCATION]
22
23
violations: int => _violations
24
25
init(
26
logger: Logger,
27
symbol_table: Semantic.SYMBOL_TABLE,
28
namespaces: Semantic.NAMESPACES
29
)
30
is
31
super.init(logger, symbol_table, namespaces)
32
33
_uninferred = Collections.LIST[Semantic.Symbols.Variable]()
34
_uninferred_reads = Collections.LIST[Source.LOCATION]()
35
si
36
37
apply(node: Node) is
38
_violations = 0
39
_uninferred.clear()
40
_uninferred_reads.clear()
41
42
node.walk(self)
43
si
44
45
visit_default(node: Node) is
46
if let expression: Expressions.Expression = node then
47
_check_expression(expression)
48
fi
49
si
50
51
visit(function: Expressions.FUNCTION) is
52
if let closure: Semantic.Symbols.Closure = function.scope then
53
_check_closure(function, closure)
54
fi
55
56
super.visit(function)
57
si
58
59
_check_expression(expression: Expressions.Expression) is
60
let value = expression.value
61
62
if !value? then
63
return
64
fi
65
66
// A call that left a type parameter open makes the value's
67
// own type carry it too, so the call is judged first and
68
// what it reports stands for both.
69
let omitted = _check_called_function(expression, value)
70
71
let type = value.type
72
73
if !type? then
74
return
75
fi
76
77
_check_type(expression, "value", type, omitted)
78
si
79
80
// A call whose callee is still generic. The value's own type
81
// catches a type parameter that reaches the result, and a
82
// formal catches one an argument could pin, but a parameter
83
// the callee names only in its body reaches neither: nothing
84
// commits it, so nothing reports it, and the call emits a
85
// methodref naming a parameter with no argument.
86
_check_called_function(node: Node, value: IR.Values.Value) -> bool is
87
let called =
88
if let global_call: IR.Values.Call.GLOBAL = value then
89
global_call.function
90
elif let static_call: IR.Values.Call.STATIC = value then
91
static_call.function
92
elif let instance_call: IR.Values.Call.INSTANCE = value then
93
instance_call.function
94
elif let struct_call: IR.Values.Call.STRUCT = value then
95
struct_call.function
96
else
97
null
98
fi
99
100
if !called? then
101
return false
102
fi
103
104
let scope = _symbol_table.current_scope
105
106
for argument in called.generic_arguments do
107
if argument.has_function_generic_argument_foreign_to(scope) then
108
_report_uninferred_type_argument(node)
109
110
return true
111
fi
112
od
113
114
false
115
si
116
117
_report_uninferred_type_argument(node: Node) is
118
_violations = _violations + 1
119
120
_logger.error(node.location, "cannot infer type here")
121
si
122
123
_check_closure(function: Expressions.FUNCTION, closure: Semantic.Symbols.Closure) is
124
let return_type = closure.return_type
125
126
if return_type? then
127
_check_type(function, "closure return", return_type, false)
128
fi
129
130
let index mut = 0
131
132
for argument in closure.arguments do
133
_check_type(function, "closure argument {index}", argument, false)
134
index = index + 1
135
od
136
si
137
138
_check_type(node: Node, what: string, type: Semantic.Types.Type, omitted_type_argument: bool) is
139
let scope = _symbol_table.current_scope
140
141
if let placeholder: Semantic.Types.INFERRED_VARIABLE_TYPE = type then
142
_report_uninferred(placeholder.origin)
143
_uninferred_reads.add(node.location)
144
elif type.contains_inferred then
145
// A placeholder inside the type rather than as the whole
146
// of it - a constructor's type argument nothing pinned,
147
// say - names a variable the body could not infer just as
148
// a bare one does, and is the program's error rather than
149
// the compiler's.
150
let inner = _uninferred_within(type)
151
152
if inner.count > 0 then
153
for placeholder in inner do
154
_report_uninferred(placeholder.origin)
155
od
156
157
_uninferred_reads.add(node.location)
158
else
159
_report(node, "{what} holds an inference placeholder: {type}")
160
fi
161
elif type.is_error then
162
// Children are checked before their parents, so a read of
163
// an uninferred local inside this value has already been
164
// reported, and this ERROR is its consequence.
165
if !_contains_uninferred_read(node.location) then
166
_report(node, "{what} holds ERROR: {type}")
167
fi
168
elif type.has_function_generic_argument_foreign_to(scope) then
169
// The parameter the call left open reaches the value,
170
// and the call has already been reported. A parameter
171
// no omission explains still reaches here.
172
if !omitted_type_argument then
173
_report(node, "{what} holds a type parameter foreign to this body: {type}")
174
fi
175
fi
176
si
177
178
// The placeholders a type holds within it, in the order the type
179
// walk reaches them.
180
_uninferred_within(type: Semantic.Types.Type) -> Collections.List[Semantic.Types.INFERRED_VARIABLE_TYPE] is
181
let found = Collections.LIST[Semantic.Types.INFERRED_VARIABLE_TYPE]()
182
183
type.walk(
184
inner =>
185
if let placeholder: Semantic.Types.INFERRED_VARIABLE_TYPE = inner then
186
found.add(placeholder)
187
fi)
188
189
found
190
si
191
192
// A local whose uses, assignments and initializer never gave it
193
// a type is the program's error rather than the compiler's:
194
// reported once, where the local is declared.
195
_report_uninferred(variable: Semantic.Symbols.Variable) is
196
if _uninferred.contains(variable) then
197
return
198
fi
199
200
_uninferred.add(variable)
201
_violations = _violations + 1
202
203
_logger.error(variable.location, "cannot infer type here")
204
si
205
206
_contains_uninferred_read(location: Source.LOCATION) -> bool is
207
for read in _uninferred_reads do
208
if location.contains(read) then
209
return true
210
fi
211
od
212
213
return false
214
si
215
216
_report(node: Node, message: string) is
217
_violations = _violations + 1
218
219
_logger.error(node.location, "internal: unsettled compile state: {message}")
220
si
221
si
222
si