mt-lang 0.3.39 → 0.3.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/ast.rb +2 -2
- data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -6
- data/lib/milk_tea/core/bindings/module_binding.rb +1 -1
- data/lib/milk_tea/core/intrinsics.rb +23 -1
- data/lib/milk_tea/core/lowering/functions.rb +3 -0
- data/lib/milk_tea/core/lowering/resolve.rb +4 -65
- data/lib/milk_tea/core/lowering/utils.rb +0 -17
- data/lib/milk_tea/core/lowering.rb +1 -2
- data/lib/milk_tea/core/module_binder.rb +4 -15
- data/lib/milk_tea/core/module_loader.rb +41 -8
- data/lib/milk_tea/core/parser/declarations.rb +24 -17
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +2 -111
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -2
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +26 -17
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +26 -42
- data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -59
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +0 -2
- data/lib/milk_tea/core/types/predicates.rb +57 -0
- data/lib/milk_tea/core/types/registry.rb +14 -2
- data/lib/milk_tea/core/types.rb +0 -4
- data/lib/milk_tea/lsp/server/code_actions.rb +13 -7
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +56 -12
- data/lib/milk_tea/lsp/server/text_documents.rb +18 -2
- data/lib/milk_tea/lsp/workspace/caches.rb +28 -1
- data/lib/milk_tea/lsp/workspace/dependency_graph.rb +31 -0
- data/lib/milk_tea/lsp/workspace/store.rb +7 -1
- data/lib/milk_tea/lsp/workspace.rb +6 -0
- data/lib/milk_tea/tooling/formatter.rb +2 -3
- data/lib/milk_tea/tooling/linter/fix_engine.rb +46 -0
- data/lib/milk_tea/tooling/linter/rules.rb +32 -0
- data/lib/milk_tea/tooling/linter.rb +4 -0
- data/lib/milk_tea/tooling.rb +0 -1
- metadata +2 -3
- data/lib/milk_tea/tooling/cst_formatter.rb +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 91b5015b218da9925b56895b551063fca825ca776fc336fe898ef17e332aae4e
|
|
4
|
+
data.tar.gz: 46e4a2da80edfb7c64fc847ee10844c9f5d36572df35105ab6ed51e2455d347a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0c1dcedaf98ef374c9dd21cded75f8512c755a63e4a3a155e494d9edf098b2d53da3b258edab5d63066a2a9eaa3c2a3883aa69241608509085caf398c1edecc1
|
|
7
|
+
data.tar.gz: a427c7ad0f2475b7dc5cccadcb6cc143ab195f906b7b9b13407a7e754043fd8550495c7dc750f5f27c92e2eca13477d9f6697650bddd515403526812b1dac06b
|
data/lib/milk_tea/base.rb
CHANGED
data/lib/milk_tea/core/ast.rb
CHANGED
|
@@ -111,8 +111,8 @@ module MilkTea
|
|
|
111
111
|
InterfaceDecl = Data.define(:name, :type_params, :methods, :visibility, :line, :column) do
|
|
112
112
|
def initialize(name:, type_params: [], methods:, visibility:, line: nil, column: nil) = super
|
|
113
113
|
end
|
|
114
|
-
ExtendingBlock = Data.define(:type_name, :methods, :line, :column) do
|
|
115
|
-
def initialize(type_name:, methods:, line: nil, column: nil) = super
|
|
114
|
+
ExtendingBlock = Data.define(:type_name, :methods, :line, :column, :inline) do
|
|
115
|
+
def initialize(type_name:, methods:, line: nil, column: nil, inline: false) = super
|
|
116
116
|
end
|
|
117
117
|
InterfaceMethodDecl = Data.define(:name, :params, :return_type, :kind, :async, :attributes, :line, :column) do
|
|
118
118
|
def initialize(name:, params:, return_type:, kind:, async:, attributes: [], line: nil, column: nil) = super
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module MilkTea
|
|
4
4
|
module Bindings
|
|
5
|
-
AttributeBinding = Data.define(:name, :targets, :params, :module_name, :builtin
|
|
5
|
+
AttributeBinding = Data.define(:name, :targets, :params, :module_name, :builtin)
|
|
6
6
|
BUILTIN_ATTRIBUTE_NAMES = %w[packed align deprecated test expect_fatal].freeze
|
|
7
7
|
|
|
8
8
|
def self.builtin_attribute_binding(name, types)
|
|
@@ -14,7 +14,6 @@ module MilkTea
|
|
|
14
14
|
params: [].freeze,
|
|
15
15
|
module_name: nil,
|
|
16
16
|
builtin: true,
|
|
17
|
-
ast: nil,
|
|
18
17
|
)
|
|
19
18
|
when "align"
|
|
20
19
|
AttributeBinding.new(
|
|
@@ -23,7 +22,6 @@ module MilkTea
|
|
|
23
22
|
params: [Types::Registry.parameter("bytes", types.fetch("ptr_uint"))].freeze,
|
|
24
23
|
module_name: nil,
|
|
25
24
|
builtin: true,
|
|
26
|
-
ast: nil,
|
|
27
25
|
)
|
|
28
26
|
when "deprecated"
|
|
29
27
|
AttributeBinding.new(
|
|
@@ -32,7 +30,6 @@ module MilkTea
|
|
|
32
30
|
params: [Types::Registry.parameter("message", types.fetch("str"))].freeze,
|
|
33
31
|
module_name: nil,
|
|
34
32
|
builtin: true,
|
|
35
|
-
ast: nil,
|
|
36
33
|
)
|
|
37
34
|
when "test"
|
|
38
35
|
AttributeBinding.new(
|
|
@@ -41,7 +38,6 @@ module MilkTea
|
|
|
41
38
|
params: [].freeze,
|
|
42
39
|
module_name: nil,
|
|
43
40
|
builtin: true,
|
|
44
|
-
ast: nil,
|
|
45
41
|
)
|
|
46
42
|
when "expect_fatal"
|
|
47
43
|
AttributeBinding.new(
|
|
@@ -50,7 +46,6 @@ module MilkTea
|
|
|
50
46
|
params: [].freeze,
|
|
51
47
|
module_name: nil,
|
|
52
48
|
builtin: true,
|
|
53
|
-
ast: nil,
|
|
54
49
|
)
|
|
55
50
|
end
|
|
56
51
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module MilkTea
|
|
4
4
|
module Bindings
|
|
5
|
-
ModuleBinding = Data.define(:name, :types, :type_declarations, :interfaces, :attributes, :attribute_applications, :values, :functions, :methods, :implemented_interfaces, :imports, :private_types, :private_interfaces, :private_attributes, :private_values, :private_functions, :private_methods
|
|
5
|
+
ModuleBinding = Data.define(:name, :types, :type_declarations, :interfaces, :attributes, :attribute_applications, :values, :functions, :methods, :implemented_interfaces, :imports, :private_types, :private_interfaces, :private_attributes, :private_values, :private_functions, :private_methods) do
|
|
6
6
|
def private_type?(name)
|
|
7
7
|
private_types.key?(name)
|
|
8
8
|
end
|
|
@@ -84,5 +84,27 @@ module MilkTea
|
|
|
84
84
|
def string_literal_cstr_compatibility?(expression, expected_type)
|
|
85
85
|
expression.is_a?(AST::StringLiteral) && !expression.cstring && expected_type == BUILTIN_CSTR
|
|
86
86
|
end
|
|
87
|
+
|
|
88
|
+
def current_nested_types
|
|
89
|
+
@current_nested_types
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Resolves the receiver type's short name (self-reference) and its own
|
|
93
|
+
# nested types as a bare-name scope for method bodies and signatures.
|
|
94
|
+
def method_receiver_nested_scope(receiver_type)
|
|
95
|
+
return nil unless receiver_type.respond_to?(:name)
|
|
96
|
+
|
|
97
|
+
nested = receiver_type.respond_to?(:nested_types) ? receiver_type.nested_types : nil
|
|
98
|
+
scope = { receiver_type.name => receiver_type }
|
|
99
|
+
scope = scope.merge(nested) if nested && !nested.empty?
|
|
100
|
+
scope
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Looks up a bare type name, consulting the active method-receiver nested
|
|
104
|
+
# scope before the module type namespace so nested types self-reference
|
|
105
|
+
# by their short name inside their own methods.
|
|
106
|
+
def lookup_named_type(name)
|
|
107
|
+
(@current_nested_types && @current_nested_types[name]) || @ctx.types[name]
|
|
108
|
+
end
|
|
87
109
|
end
|
|
88
|
-
end
|
|
110
|
+
end
|
|
@@ -118,8 +118,10 @@ module MilkTea
|
|
|
118
118
|
parameter_setup = []
|
|
119
119
|
previous_type_substitutions = @ctx.current_type_substitutions
|
|
120
120
|
previous_value_type_params = @ctx.current_value_type_params
|
|
121
|
+
previous_nested_types = @current_nested_types
|
|
121
122
|
@ctx.current_type_substitutions = binding.type_substitutions
|
|
122
123
|
@ctx.current_value_type_params = resolve_value_type_params(decl.type_params)
|
|
124
|
+
@current_nested_types = method_receiver_nested_scope(binding.declared_receiver_type)
|
|
123
125
|
|
|
124
126
|
return lower_async_function_decl(binding, receiver_type:) if binding.async
|
|
125
127
|
|
|
@@ -179,6 +181,7 @@ module MilkTea
|
|
|
179
181
|
ensure
|
|
180
182
|
@ctx.current_type_substitutions = previous_type_substitutions
|
|
181
183
|
@ctx.current_value_type_params = previous_value_type_params
|
|
184
|
+
@current_nested_types = previous_nested_types
|
|
182
185
|
end
|
|
183
186
|
|
|
184
187
|
def resolve_value_type_params(type_params)
|
|
@@ -444,7 +444,7 @@ module MilkTea
|
|
|
444
444
|
return [:compile_time_builtin, callee.name, nil, compile_time_builtin_function_type(callee.name, arguments, env)]
|
|
445
445
|
end
|
|
446
446
|
|
|
447
|
-
type =
|
|
447
|
+
type = lookup_named_type(callee.name)
|
|
448
448
|
if type.is_a?(Types::Struct) || type.is_a?(Types::StringView) || task_type?(type) || type.is_a?(Types::Vector) || type.is_a?(Types::Matrix) || type.is_a?(Types::Quaternion)
|
|
449
449
|
return [:struct_literal, nil, nil, type]
|
|
450
450
|
end
|
|
@@ -606,7 +606,6 @@ module MilkTea
|
|
|
606
606
|
return [:array_as_span, nil, callee.receiver, Types::Registry.span(array_element_type(field_receiver_type))]
|
|
607
607
|
end
|
|
608
608
|
|
|
609
|
-
member_type = field_receiver_type.respond_to?(:field) ? field_receiver_type.field(callee.member) : nil
|
|
610
609
|
member_type = field_receiver_type.respond_to?(:field) ? field_receiver_type.field(callee.member) : nil
|
|
611
610
|
return [:callable_value, nil, nil, member_type, nil] if callable_type?(member_type)
|
|
612
611
|
|
|
@@ -1055,7 +1054,7 @@ module MilkTea
|
|
|
1055
1054
|
end
|
|
1056
1055
|
end
|
|
1057
1056
|
|
|
1058
|
-
def type_contains_array_storage?(type
|
|
1057
|
+
def type_contains_array_storage?(type)
|
|
1059
1058
|
visitor = Types::ContainsArrayStorageVisitor.new
|
|
1060
1059
|
visitor.visit(type)
|
|
1061
1060
|
visitor.found?
|
|
@@ -1118,62 +1117,6 @@ module MilkTea
|
|
|
1118
1117
|
expected_type || null_type
|
|
1119
1118
|
end
|
|
1120
1119
|
|
|
1121
|
-
def common_numeric_type(left_type, right_type)
|
|
1122
|
-
left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
|
|
1123
|
-
right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
|
|
1124
|
-
return left_type if left_type == right_type
|
|
1125
|
-
return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
|
|
1126
|
-
return unless left_type.numeric? && right_type.numeric?
|
|
1127
|
-
|
|
1128
|
-
return common_integer_type(left_type, right_type) if left_type.integer? && right_type.integer?
|
|
1129
|
-
return wider_float_type(left_type, right_type) if left_type.float? && right_type.float?
|
|
1130
|
-
|
|
1131
|
-
float_type, integer_type = left_type.float? ? [left_type, right_type] : [right_type, left_type]
|
|
1132
|
-
return unless integer_type.integer? && integer_type.fixed_width_integer?
|
|
1133
|
-
|
|
1134
|
-
float_type
|
|
1135
|
-
end
|
|
1136
|
-
|
|
1137
|
-
def common_integer_type(left_type, right_type)
|
|
1138
|
-
left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
|
|
1139
|
-
right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
|
|
1140
|
-
return left_type if left_type == right_type
|
|
1141
|
-
return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
|
|
1142
|
-
return unless left_type.integer? && right_type.integer?
|
|
1143
|
-
return unless left_type.fixed_width_integer? && right_type.fixed_width_integer?
|
|
1144
|
-
|
|
1145
|
-
# Mirrors the semantic analyzer's rule: same signedness picks the wider
|
|
1146
|
-
# type; mixed signed/unsigned promotes to the narrowest signed type that
|
|
1147
|
-
# holds both operands' full ranges (a strictly-wider signed type covers
|
|
1148
|
-
# an unsigned operand, otherwise widen to the next signed width). Mixing
|
|
1149
|
-
# with a 64-bit unsigned type has no safe signed common type.
|
|
1150
|
-
if left_type.signed_integer? == right_type.signed_integer?
|
|
1151
|
-
return left_type.integer_width >= right_type.integer_width ? left_type : right_type
|
|
1152
|
-
end
|
|
1153
|
-
|
|
1154
|
-
signed_type, unsigned_type = if left_type.signed_integer?
|
|
1155
|
-
[left_type, right_type]
|
|
1156
|
-
else
|
|
1157
|
-
[right_type, left_type]
|
|
1158
|
-
end
|
|
1159
|
-
|
|
1160
|
-
return signed_type if signed_type.integer_width > unsigned_type.integer_width
|
|
1161
|
-
|
|
1162
|
-
signed_type_above_width(unsigned_type.integer_width)
|
|
1163
|
-
end
|
|
1164
|
-
|
|
1165
|
-
def signed_type_above_width(width)
|
|
1166
|
-
case width
|
|
1167
|
-
when 8 then @ctx.types.fetch("short")
|
|
1168
|
-
when 16 then @ctx.types.fetch("int")
|
|
1169
|
-
when 32 then @ctx.types.fetch("long")
|
|
1170
|
-
end
|
|
1171
|
-
end
|
|
1172
|
-
|
|
1173
|
-
def wider_float_type(left_type, right_type)
|
|
1174
|
-
left_type.float_width >= right_type.float_width ? left_type : right_type
|
|
1175
|
-
end
|
|
1176
|
-
|
|
1177
1120
|
def aggregate_arithmetic_result_type(operator, left_type, right_type)
|
|
1178
1121
|
if left_type.is_a?(Types::Vector) && right_type.is_a?(Types::Vector) && left_type.name == right_type.name
|
|
1179
1122
|
return left_type
|
|
@@ -1217,7 +1160,7 @@ module MilkTea
|
|
|
1217
1160
|
when AST::Identifier
|
|
1218
1161
|
return current_type_params[expression.name] if current_type_params.key?(expression.name)
|
|
1219
1162
|
|
|
1220
|
-
|
|
1163
|
+
lookup_named_type(expression.name)
|
|
1221
1164
|
when AST::MemberAccess
|
|
1222
1165
|
return nil unless expression.receiver.is_a?(AST::Identifier)
|
|
1223
1166
|
|
|
@@ -1870,10 +1813,6 @@ module MilkTea
|
|
|
1870
1813
|
def top_level_function(name)
|
|
1871
1814
|
@lowerer.instance_variable_get(:@ctx).functions&.[](name)
|
|
1872
1815
|
end
|
|
1873
|
-
|
|
1874
|
-
def raise_sema_error(message)
|
|
1875
|
-
raise CompileTime::Error, message
|
|
1876
|
-
end
|
|
1877
1816
|
end
|
|
1878
1817
|
|
|
1879
1818
|
def evaluate_reflection_target_argument(expression, env:)
|
|
@@ -2532,7 +2471,7 @@ module MilkTea
|
|
|
2532
2471
|
elsif parts.length == 1 && type_params.key?(parts.first)
|
|
2533
2472
|
type_params.fetch(parts.first)
|
|
2534
2473
|
elsif parts.length == 1
|
|
2535
|
-
type =
|
|
2474
|
+
type = lookup_named_type(parts.first)
|
|
2536
2475
|
raise LoweringError.new("unknown type #{parts.first}", line: 0, column: 0, path: @ctx.current_analysis_path) unless type
|
|
2537
2476
|
raise LoweringError.new("generic type #{parts.first} requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
2538
2477
|
|
|
@@ -155,18 +155,6 @@ module MilkTea
|
|
|
155
155
|
receiver_type
|
|
156
156
|
end
|
|
157
157
|
|
|
158
|
-
def collection_loop_type(type)
|
|
159
|
-
super
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def collection_loop_binding_type(iterable_type, element_type)
|
|
163
|
-
super
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def collection_loop_ref_element_type?(type)
|
|
167
|
-
super
|
|
168
|
-
end
|
|
169
|
-
|
|
170
158
|
def collection_loop_item_value(iterable_ref, iterable_type, index_ref, element_type)
|
|
171
159
|
if array_type?(iterable_type)
|
|
172
160
|
IR::Index.new(receiver: iterable_ref, index: index_ref, type: element_type)
|
|
@@ -248,11 +236,6 @@ module MilkTea
|
|
|
248
236
|
raise LoweringError.new("cannot index #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
|
|
249
237
|
end
|
|
250
238
|
|
|
251
|
-
def contains_type_var?(type)
|
|
252
|
-
super
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
|
|
256
239
|
def stored_ref_supported_type?(type, visited = {})
|
|
257
240
|
return true unless type
|
|
258
241
|
|
|
@@ -100,7 +100,6 @@ module MilkTea
|
|
|
100
100
|
include Intrinsics
|
|
101
101
|
|
|
102
102
|
attr_accessor :bypass_sema_type_cache
|
|
103
|
-
attr_reader :recorded_expr_types
|
|
104
103
|
|
|
105
104
|
include Lowering::Scans
|
|
106
105
|
include Lowering::Declarations
|
|
@@ -122,6 +121,7 @@ module MilkTea
|
|
|
122
121
|
@program = program
|
|
123
122
|
@ctx = LoweringContext.new
|
|
124
123
|
@artifacts = Artifacts.new
|
|
124
|
+
@error_type = Types::Error.new
|
|
125
125
|
@synthetic_proc_counter = 0
|
|
126
126
|
@parallel_for_counter = 0
|
|
127
127
|
@async_binding_counter = 0
|
|
@@ -130,7 +130,6 @@ module MilkTea
|
|
|
130
130
|
end
|
|
131
131
|
|
|
132
132
|
def lower
|
|
133
|
-
@recorded_expr_types = {} if @bypass_sema_type_cache
|
|
134
133
|
ir_program, _modules, _synths = lower_and_assemble
|
|
135
134
|
ir_program
|
|
136
135
|
end
|
|
@@ -42,7 +42,7 @@ module MilkTea
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
methods, private_methods = exported_methods(analysis, types)
|
|
45
|
-
implemented_interfaces
|
|
45
|
+
implemented_interfaces = exported_interface_implementations(analysis, types, interfaces)
|
|
46
46
|
|
|
47
47
|
Bindings::ModuleBinding.new(
|
|
48
48
|
name: analysis.module_name,
|
|
@@ -62,7 +62,6 @@ module MilkTea
|
|
|
62
62
|
private_values:,
|
|
63
63
|
private_functions:,
|
|
64
64
|
private_methods:,
|
|
65
|
-
private_implemented_interfaces:,
|
|
66
65
|
)
|
|
67
66
|
end
|
|
68
67
|
|
|
@@ -102,28 +101,18 @@ module MilkTea
|
|
|
102
101
|
|
|
103
102
|
def exported_interface_implementations(analysis, exported_types, exported_interfaces)
|
|
104
103
|
implemented_interfaces = {}
|
|
105
|
-
private_implemented_interfaces = {}
|
|
106
104
|
|
|
107
105
|
analysis.implemented_interfaces.each do |receiver_type, interfaces|
|
|
108
|
-
public_interfaces =
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
interfaces.each do |interface|
|
|
112
|
-
visible = exported_method_receiver?(receiver_type, analysis, exported_types) &&
|
|
106
|
+
public_interfaces = interfaces.select do |interface|
|
|
107
|
+
exported_method_receiver?(receiver_type, analysis, exported_types) &&
|
|
113
108
|
exported_interface_binding?(interface, analysis, exported_interfaces) &&
|
|
114
109
|
exported_interface_methods?(receiver_type, interface, analysis, exported_types)
|
|
115
|
-
if visible
|
|
116
|
-
public_interfaces << interface
|
|
117
|
-
else
|
|
118
|
-
hidden_interfaces << interface
|
|
119
|
-
end
|
|
120
110
|
end
|
|
121
111
|
|
|
122
112
|
implemented_interfaces[receiver_type] = public_interfaces.freeze unless public_interfaces.empty?
|
|
123
|
-
private_implemented_interfaces[receiver_type] = hidden_interfaces.freeze unless hidden_interfaces.empty?
|
|
124
113
|
end
|
|
125
114
|
|
|
126
|
-
|
|
115
|
+
implemented_interfaces.freeze
|
|
127
116
|
end
|
|
128
117
|
|
|
129
118
|
def exported_interface_methods?(receiver_type, interface, analysis, exported_types)
|
|
@@ -158,7 +158,30 @@ module MilkTea
|
|
|
158
158
|
|
|
159
159
|
def load_file(path)
|
|
160
160
|
resolved_path = self.class.resolve_source_path(path, platform: @platform, error_class: ModuleLoadError)
|
|
161
|
-
@ast_cache[resolved_path] ||=
|
|
161
|
+
@ast_cache[resolved_path] ||= cached_or_parse_file(resolved_path)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Parse +resolved_path+, reusing the shared-cache parsed AST when the source
|
|
165
|
+
# is disk-backed and unchanged. ASTs are immutable Data, so sharing them
|
|
166
|
+
# across loaders (and worker threads) is safe; node_ids are assigned at
|
|
167
|
+
# parse time and analyses keep their own per-node result hashes. Source
|
|
168
|
+
# files covered by source_overrides are always re-parsed so live editor
|
|
169
|
+
# buffers win.
|
|
170
|
+
def cached_or_parse_file(resolved_path)
|
|
171
|
+
if use_shared_cache_for?(resolved_path)
|
|
172
|
+
mtime = source_mtime(resolved_path)
|
|
173
|
+
if mtime
|
|
174
|
+
entry = @shared_cache[[:ast, resolved_path]]
|
|
175
|
+
return entry[:ast] if entry && entry[:mtime] == mtime
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
ast = parse_file(resolved_path)
|
|
180
|
+
if use_shared_cache_for?(resolved_path)
|
|
181
|
+
mtime = source_mtime(resolved_path)
|
|
182
|
+
@shared_cache[[:ast, resolved_path]] = { mtime:, ast: } if mtime
|
|
183
|
+
end
|
|
184
|
+
ast
|
|
162
185
|
end
|
|
163
186
|
|
|
164
187
|
def check_file(path)
|
|
@@ -166,7 +189,14 @@ module MilkTea
|
|
|
166
189
|
end
|
|
167
190
|
|
|
168
191
|
def with_check_context(path, &block)
|
|
169
|
-
Types::Registry.reset!
|
|
192
|
+
# NOTE: Types::Registry.reset! is intentionally NOT called here. The LSP
|
|
193
|
+
# runs check_program_collecting concurrently on diagnostics workers and
|
|
194
|
+
# the request thread; a reset would clear the global intern pool while
|
|
195
|
+
# another thread is mid-analysis, causing threads to intern duplicate type
|
|
196
|
+
# instances. Interning is idempotent and the pool stays small (bounded by
|
|
197
|
+
# the type universe), so it is safe to let it grow for the process
|
|
198
|
+
# lifetime. Single-threaded entry points that want a clean slate (Build#build,
|
|
199
|
+
# server re-initialize) reset explicitly.
|
|
170
200
|
requested_path = File.expand_path(path)
|
|
171
201
|
previous_platform = @platform
|
|
172
202
|
@platform ||= self.class.platform_suffix_for_path(requested_path)
|
|
@@ -541,7 +571,7 @@ module MilkTea
|
|
|
541
571
|
return [resolved_path, nil, @analysis_cache[resolved_path]] if @analysis_cache.key?(resolved_path)
|
|
542
572
|
return [resolved_path, nil, extra_cache[resolved_path]] if extra_cache&.key?(resolved_path)
|
|
543
573
|
|
|
544
|
-
if
|
|
574
|
+
if use_shared_cache_for?(resolved_path)
|
|
545
575
|
entry = @shared_cache[resolved_path]
|
|
546
576
|
if entry
|
|
547
577
|
mtime = source_mtime(resolved_path)
|
|
@@ -566,7 +596,7 @@ module MilkTea
|
|
|
566
596
|
end
|
|
567
597
|
|
|
568
598
|
def update_shared_cache(resolved_path, analysis)
|
|
569
|
-
return unless
|
|
599
|
+
return unless use_shared_cache_for?(resolved_path)
|
|
570
600
|
|
|
571
601
|
mtime = source_mtime(resolved_path)
|
|
572
602
|
@shared_cache[resolved_path] = { mtime:, analysis: } if mtime
|
|
@@ -691,7 +721,6 @@ module MilkTea
|
|
|
691
721
|
private_values: full_binding.private_values,
|
|
692
722
|
private_functions: full_binding.private_functions,
|
|
693
723
|
private_methods: full_binding.private_methods,
|
|
694
|
-
private_implemented_interfaces: full_binding.private_implemented_interfaces,
|
|
695
724
|
)
|
|
696
725
|
end
|
|
697
726
|
end
|
|
@@ -728,12 +757,16 @@ module MilkTea
|
|
|
728
757
|
implemented_interfaces: {}, imports: {},
|
|
729
758
|
private_types: {}, private_interfaces: {}, private_attributes: {},
|
|
730
759
|
private_values: {}, private_functions: {}, private_methods: {},
|
|
731
|
-
private_implemented_interfaces: {},
|
|
732
760
|
)
|
|
733
761
|
end
|
|
734
762
|
|
|
735
|
-
|
|
736
|
-
|
|
763
|
+
# The shared cache stores per-module analyses keyed by resolved path. It is
|
|
764
|
+
# consulted only for paths NOT covered by source_overrides: source-overridden
|
|
765
|
+
# files reflect live editor buffers (or in-memory sources) that never match
|
|
766
|
+
# disk, so their entries would be stale by construction. This lets a single
|
|
767
|
+
# open document invalidate only itself while imported modules stay cached.
|
|
768
|
+
def use_shared_cache_for?(resolved_path)
|
|
769
|
+
@shared_cache && !@source_overrides.key?(resolved_path)
|
|
737
770
|
end
|
|
738
771
|
end
|
|
739
772
|
end
|
|
@@ -369,10 +369,11 @@ module MilkTea
|
|
|
369
369
|
AST::AttributeDecl.new(name: name_token.lexeme, targets:, params:, visibility:, line:, column: name_token.column)
|
|
370
370
|
end
|
|
371
371
|
|
|
372
|
-
def parse_struct_decl(packed: false, alignment: nil, visibility: :private, attributes: [],
|
|
372
|
+
def parse_struct_decl(packed: false, alignment: nil, visibility: :private, attributes: [], qualified_parts: [])
|
|
373
373
|
line = previous.line
|
|
374
374
|
name_token = consume_name("expected struct name")
|
|
375
375
|
name = name_token.lexeme
|
|
376
|
+
qualified_name = qualified_parts + [name]
|
|
376
377
|
lifetime_params, type_params = parse_struct_decl_params
|
|
377
378
|
implements = parse_implements_clause
|
|
378
379
|
c_name = parse_optional_c_name
|
|
@@ -380,29 +381,33 @@ module MilkTea
|
|
|
380
381
|
receiver_type_param_names = type_params.map(&:name)
|
|
381
382
|
members = with_type_param_names(receiver_type_param_names) do
|
|
382
383
|
parse_recoverable_block do
|
|
383
|
-
parse_struct_member
|
|
384
|
+
parse_struct_member(qualified_name)
|
|
384
385
|
end
|
|
385
386
|
end
|
|
386
387
|
fields = members.filter_map { |kind, member| member if kind == :field }
|
|
387
388
|
events = members.filter_map { |kind, member| member if kind == :event }
|
|
388
389
|
nested_types = members.filter_map { |kind, member| member if kind == :nested_type }
|
|
389
390
|
methods = members.filter_map { |kind, member| member if kind == :method }
|
|
391
|
+
nested_extending_blocks = members.filter_map { |kind, _, blocks| blocks if kind == :nested_type }.flatten(1)
|
|
390
392
|
struct_decl = AST::StructDecl.new(name:, type_params:, implements:, c_name:, fields:, events:, nested_types:, attributes:, packed:, alignment:, visibility:, lifetime_params:, line:, column: name_token.column)
|
|
391
393
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
394
|
+
extending_blocks = []
|
|
395
|
+
extending_blocks << inline_methods_extending_block(qualified_name, type_params, methods, name_token) if methods.any?
|
|
396
|
+
extending_blocks.concat(nested_extending_blocks)
|
|
397
|
+
|
|
398
|
+
extending_blocks.empty? ? struct_decl : [struct_decl, *extending_blocks]
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def inline_methods_extending_block(qualified_name, type_params, methods, name_token)
|
|
402
|
+
type_ref_args = type_params.map do |tp|
|
|
403
|
+
AST::TypeArgument.new(
|
|
404
|
+
value: AST::TypeRef.new(name: AST::QualifiedName.new(parts: [tp.name]), arguments: [], nullable: false, line: tp.line, column: tp.column),
|
|
405
|
+
line: tp.line,
|
|
406
|
+
column: tp.column,
|
|
407
|
+
)
|
|
405
408
|
end
|
|
409
|
+
type_ref = AST::TypeRef.new(name: AST::QualifiedName.new(parts: qualified_name), arguments: type_ref_args, nullable: false, line: name_token.line, column: name_token.column)
|
|
410
|
+
AST::ExtendingBlock.new(type_name: type_ref, methods:, line: name_token.line, column: name_token.column, inline: true)
|
|
406
411
|
end
|
|
407
412
|
|
|
408
413
|
def parse_struct_decl_params
|
|
@@ -459,7 +464,7 @@ module MilkTea
|
|
|
459
464
|
result
|
|
460
465
|
end
|
|
461
466
|
|
|
462
|
-
def parse_struct_member
|
|
467
|
+
def parse_struct_member(qualified_name)
|
|
463
468
|
field_attributes = parse_attribute_applications
|
|
464
469
|
|
|
465
470
|
if check_method_start?
|
|
@@ -475,7 +480,9 @@ module MilkTea
|
|
|
475
480
|
|
|
476
481
|
if check(:struct) && !check_next(:colon)
|
|
477
482
|
advance
|
|
478
|
-
|
|
483
|
+
result = parse_struct_decl(visibility:, attributes: field_attributes, qualified_parts: qualified_name)
|
|
484
|
+
nested_decl, *nested_blocks = result.is_a?(Array) ? result : [result]
|
|
485
|
+
return [:nested_type, nested_decl, nested_blocks]
|
|
479
486
|
end
|
|
480
487
|
|
|
481
488
|
raise error(visibility_token, "public is only allowed on struct events") if visibility == :public
|