Class: MilkTea::SemanticAnalyzer::Checker
- Inherits:
-
Object
- Object
- MilkTea::SemanticAnalyzer::Checker
show all
- Includes:
- CompatibilityHelpers
- Defined in:
- lib/milk_tea/core/semantic_analyzer.rb,
lib/milk_tea/core/semantic_analyzer/calls.rb,
lib/milk_tea/core/semantic_analyzer/generics.rb,
lib/milk_tea/core/semantic_analyzer/top_level.rb,
lib/milk_tea/core/semantic_analyzer/attributes.rb,
lib/milk_tea/core/semantic_analyzer/statements.rb,
lib/milk_tea/core/semantic_analyzer/expressions.rb,
lib/milk_tea/core/semantic_analyzer/nullability.rb,
lib/milk_tea/core/semantic_analyzer/flow_refinement.rb,
lib/milk_tea/core/semantic_analyzer/name_resolution.rb,
lib/milk_tea/core/semantic_analyzer/analysis_context.rb,
lib/milk_tea/core/semantic_analyzer/function_binding.rb,
lib/milk_tea/core/semantic_analyzer/type_declaration.rb,
lib/milk_tea/core/semantic_analyzer/foreign_functions.rb,
lib/milk_tea/core/semantic_analyzer/type_compatibility.rb,
lib/milk_tea/core/semantic_analyzer/interface_conformance.rb
Constant Summary
collapse
- STRUCTURAL_PHASES =
%i[
install_builtin_types
install_builtin_attributes
install_imports
install_prelude_types
declare_named_types
resolve_generic_type_param_constraints
resolve_type_aliases
declare_attributes
resolve_aggregate_fields
resolve_enum_members
resolve_variant_arms
collect_emit_declarations
declare_top_level_values
check_attribute_applications
declare_functions
check_interface_conformances
].freeze
CompatibilityHelpers::ATOMIC_METHOD_KINDS, CompatibilityHelpers::BUILTIN_CSTR, CompatibilityHelpers::EVENT_METHOD_KINDS, CompatibilityHelpers::EVENT_METHOD_NAMES, CompatibilityHelpers::SIMD_METHOD_KINDS, CompatibilityHelpers::STR_BUFFER_METHOD_KINDS, CompatibilityHelpers::STR_BUFFER_METHOD_NAMES
Instance Attribute Summary collapse
Instance Method Summary
collapse
#event_subscription_result_type, #event_wait_result_type, #range_expr?, #type_ref_from_specialization
#arity_error_message, #call_arity_matches?, #callable_param_ref_supported?, #char_pointer_type?, #char_type?, #const_pointer_to, #const_pointer_type?, #contains_ref_type?, #contextual_int_to_float_compatibility?, #contextual_int_to_float_target?, #dyn_type?, #exact_integer_constant_value, #exactly_representable_float32?, #external_numeric_compatibility?, #external_typed_null_pointer_compatibility?, #flatten_field_types, #float_constant_fits_type?, #foreign_boundary_element_compatible?, #foreign_char_pointer_buffer_boundary_compatible?, #foreign_external_layout_compatible?, #foreign_external_layout_field_compatible?, #foreign_function_type_projection_compatible?, #foreign_identity_projection_cast_compatible?, #foreign_identity_projection_compatible?, #foreign_identity_projection_reinterpret_compatible?, #foreign_opaque_c_name, #foreign_span_boundary_compatible?, #function_type_matches_proc_type?, #integer_constant_fits_type?, #integer_like_char_source_type?, #integer_to_char_compatibility?, #lossless_external_integer_compatibility?, #lossless_integer_compatibility?, #method_dispatch_receiver_type, #mutable_pointer_type?, #mutable_to_const_pointer_compatibility?, #native_foreign_layout_compatible?, #null_assignable_to?, #numeric_constant_fits_type?, #opaque_type?, #own_to_raw_pointer_compatibility?, #own_type?, #owned_referent_type, #pointee_type, #pointer_type?, #proc_type?, #quat_vec4_layout_compatible?, #ref_lifetime, #ref_type?, #ref_type_without_lifetime?, #referenced_type, #same_external_opaque_c_name?, #same_external_opaque_handle_pointer_compatibility?, #string_builder_ref_type?, #string_builder_type?, #struct_with_target_type?, #task_root_proc_type?, #task_type?, #value_fits_integer_type?, #void_pointer_type?
Constructor Details
#initialize(ast, imported_modules: {}, allow_missing_imports: false, path: nil, global_import_index: {}) ⇒ Checker
Returns a new instance of Checker.
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 140
def initialize(ast, imported_modules: {}, allow_missing_imports: false, path: nil, global_import_index: {})
@path = path
@allow_missing_imports = allow_missing_imports
@ctx = ModuleContext.new(
ast:,
module_name: ast.module_name&.to_s,
module_kind: ast.module_kind,
imported_modules:,
global_import_index:,
const_declarations: ast.declarations.grep(AST::ConstDecl).each_with_object({}) { |decl, result| result[decl.name] = decl },
)
@null_type = Types::Null.new
@error_type = Types::Error.new
@loop_depth = 0
@unsafe_depth = 0
@compile_time_depth = 0
@foreign_mapping_depth = 0
@async_function_depth = 0
@checked_function_bindings = {}
@checking_function_bindings = {}
@evaluating_const_values = []
@evaluated_const_values = {}
@error_node_stack = []
@local_completion_frames = []
@active_local_completion_stack = []
@resolved_expr_types = {}
@resolved_call_kinds = {}
@const_values = {}
@next_binding_id = 1
@binding_name_by_id = {}
@binding_type_by_id = {}
@identifier_binding_ids = {}
@declaration_binding_ids = {}
@mutating_argument_identifier_ids = {}
@mutable_lvalue_argument_identifier_ids = {}
@editable_receiver_expression_ids = {}
@preassigned_local_binding_ids = {}
@nullability_flow_result = nil
@unsafe_statement_lines = []
@callable_value_identifier_sites = {}
@callable_value_member_access_sites = {}
@required_unsafe_lines = []
@uses_parallel_for = false
@current_specialization_owner = nil
@return_context_stack = []
end
|
Instance Attribute Details
#ctx ⇒ Object
Returns the value of attribute ctx.
134
135
136
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 134
def ctx
@ctx
end
|
Instance Method Details
#catch_structural ⇒ Object
312
313
314
315
316
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 312
def catch_structural
yield
rescue SemanticError => e
@structural_errors << e
end
|
#check ⇒ Object
206
207
208
209
210
211
212
213
214
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 206
def check
STRUCTURAL_PHASES.each { |phase| send(phase) }
check_top_level_values
finalize_top_level_const_values
check_top_level_static_asserts
check_functions
build_analysis
end
|
#check_collecting_errors ⇒ Object
Like check, but collects per-function errors instead of raising at first.
Structural phases (imports, type resolution, declaration) collect errors per
declaration so that the maximum number of diagnostics are surfaced.
Returns { analysis: Analysis, errors: [SemanticError] }.
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 278
def check_collecting_errors
@collecting_errors = true
@structural_errors = []
STRUCTURAL_PHASES.each { |phase| catch_structural { send(phase) } }
errors = @structural_errors.dup
begin
check_top_level_values
rescue SemanticError => e
errors << e
end
errors.concat(@structural_errors.drop(errors.length))
begin
finalize_top_level_const_values
rescue SemanticError => e
errors << e
end
begin
check_top_level_static_asserts
rescue SemanticError => e
errors << e
end
check_functions_collecting(errors)
analysis = build_analysis
{ analysis: analysis, errors: errors.uniq { |e| [e.message, e.line, e.column, e.length] } }
end
|
#collect_emit_declarations ⇒ Object
216
217
218
219
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 216
def collect_emit_declarations
collect_emit_from_declarations(expanded_declarations)
@ctx.ast.declarations.grep(AST::ConstDecl).each { |decl| @ctx.const_declarations[decl.name] ||= decl }
end
|
#collect_emit_from_declarations(declarations) ⇒ Object
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 221
def collect_emit_from_declarations(declarations)
declarations.each do |decl|
case decl
when AST::FunctionDef
next unless decl.const && decl.body
collect_emit_from_statements(decl.body)
when AST::WhenStmt
body = when_chosen_body(decl)
collect_emit_from_declarations(body) if body
when AST::StructDecl, AST::ExtendingBlock
end
end
end
|
#collect_emit_from_node(node) ⇒ Object
259
260
261
262
263
264
265
266
267
268
269
270
271
272
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 259
def collect_emit_from_node(node)
case node
when AST::FunctionDef
node.body&.each do |stmt|
if stmt.is_a?(AST::EmitStmt)
nested = stmt.declaration
next if nested.is_a?(AST::ErrorExpr)
@ctx.ast.declarations << nested
collect_emit_from_node(nested)
end
end
end
end
|
#collect_emit_from_statements(statements) ⇒ Object
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 237
def collect_emit_from_statements(statements)
statements.each do |stmt|
case stmt
when AST::EmitStmt
emit_decl = stmt.declaration
next if emit_decl.is_a?(AST::ErrorExpr)
@ctx.ast.declarations << emit_decl
collect_emit_from_node(emit_decl)
when AST::WhenStmt
body = when_chosen_body(stmt) || []
body.each { |nested| collect_emit_from_statements([nested]) }
when AST::ForStmt, AST::WhileStmt, AST::IfStmt, AST::MatchStmt
next unless stmt.inline
stmt.body&.each { |s| collect_emit_from_statements([s]) }
if stmt.is_a?(AST::IfStmt)
stmt.else_body&.each { |s| collect_emit_from_statements([s]) }
end
end
end
end
|
#collect_structural_error(error) ⇒ Object
318
319
320
321
322
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 318
def collect_structural_error(error)
raise error unless @collecting_errors
@structural_errors << error
end
|
#module_name ⇒ Object
136
137
138
|
# File 'lib/milk_tea/core/semantic_analyzer.rb', line 136
def module_name
@ctx.module_name
end
|