Module: MilkTea::TypePredicates

Included in:
CompatibilityHelpers, StoredRefSupportedVisitor
Defined in:
lib/milk_tea/core/types/predicates.rb

Instance Method Summary collapse

Instance Method Details

#arity_error_message(function_type, name, actual_count) ⇒ Object



461
462
463
464
465
466
467
# File 'lib/milk_tea/core/types/predicates.rb', line 461

def arity_error_message(function_type, name, actual_count)
  if function_type.is_a?(Types::Function) && function_type.variadic
    "function #{name} expects at least #{function_type.params.length} arguments, got #{actual_count}"
  else
    "function #{name} expects #{function_type.params.length} arguments, got #{actual_count}"
  end
end

#atomic_element_type(type) ⇒ Object



409
410
411
# File 'lib/milk_tea/core/types/predicates.rb', line 409

def atomic_element_type(type)
  type.arguments.first
end

#atomic_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


405
406
407
# File 'lib/milk_tea/core/types/predicates.rb', line 405

def atomic_type?(type)
  type.is_a?(Types::GenericInstance) && type.name == "atomic" && type.arguments.length == 1
end

#call_arity_matches?(function_type, actual_count) ⇒ Boolean

Returns:

  • (Boolean)


455
456
457
458
459
# File 'lib/milk_tea/core/types/predicates.rb', line 455

def call_arity_matches?(function_type, actual_count)
  return actual_count >= function_type.params.length if function_type.is_a?(Types::Function) && function_type.variadic

  actual_count == function_type.params.length
end

#callable_param_ref_supported?(type) ⇒ Boolean

Returns:

  • (Boolean)


477
478
479
480
481
482
483
484
485
486
487
488
489
# File 'lib/milk_tea/core/types/predicates.rb', line 477

def callable_param_ref_supported?(type)
  case type
  when Types::Proc
    type.params.all? { |param| ref_type?(param.type) || !contains_ref_type?(param.type) } &&
      !contains_ref_type?(type.return_type)
  when Types::Function
    type.params.all? { |param| ref_type?(param.type) || !contains_ref_type?(param.type) } &&
      !contains_ref_type?(type.return_type) &&
      (type.receiver_type.nil? || !contains_ref_type?(type.receiver_type))
  else
    false
  end
end

#char_pointer_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


373
374
375
# File 'lib/milk_tea/core/types/predicates.rb', line 373

def char_pointer_type?(type)
  pointer_type?(type) && type.arguments.first == Types::Registry.primitive("char")
end

#char_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


127
128
129
# File 'lib/milk_tea/core/types/predicates.rb', line 127

def char_type?(type)
  type.is_a?(Types::Primitive) && type.name == "char"
end

#collection_loop_binding_type(iterable_type, element_type) ⇒ Object



510
511
512
513
514
515
# File 'lib/milk_tea/core/types/predicates.rb', line 510

def collection_loop_binding_type(iterable_type, element_type)
  return nil unless Types.array_type?(iterable_type) || iterable_type.is_a?(Types::Span)
  return nil unless collection_loop_ref_element_type?(element_type)

  Types::Registry.generic_instance("ref", [element_type])
end

#collection_loop_ref_element_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


517
518
519
# File 'lib/milk_tea/core/types/predicates.rb', line 517

def collection_loop_ref_element_type?(type)
  type.is_a?(Types::Struct)
end

#collection_loop_type(type) ⇒ Object



503
504
505
506
507
508
# File 'lib/milk_tea/core/types/predicates.rb', line 503

def collection_loop_type(type)
  return type.arguments.first if Types.array_type?(type)
  return type.element_type if type.is_a?(Types::Span)

  nil
end

#const_pointer_to(type) ⇒ Object



451
452
453
# File 'lib/milk_tea/core/types/predicates.rb', line 451

def const_pointer_to(type)
  Types::Registry.generic_instance("const_ptr", [type])
end

#const_pointer_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


389
390
391
# File 'lib/milk_tea/core/types/predicates.rb', line 389

def const_pointer_type?(type)
  type.is_a?(Types::GenericInstance) && type.name == "const_ptr" && type.arguments.length == 1
end

#contains_ref_type?(type, visited = {}, allow_lifetimes: []) ⇒ Boolean

Returns:

  • (Boolean)


491
492
493
494
495
# File 'lib/milk_tea/core/types/predicates.rb', line 491

def contains_ref_type?(type, visited = {}, allow_lifetimes: [])
  visitor = ContainsRefTypeVisitor.new(allow_lifetimes:)
  visitor.visit(type)
  visitor.found?
end

#contains_type_var?(type) ⇒ Boolean

Returns:

  • (Boolean)


497
498
499
500
501
# File 'lib/milk_tea/core/types/predicates.rb', line 497

def contains_type_var?(type)
  visitor = ContainsTypeVarVisitor.new
  visitor.visit(type)
  visitor.found?
end

#contextual_int_to_float_compatibility?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


160
161
162
163
# File 'lib/milk_tea/core/types/predicates.rb', line 160

def contextual_int_to_float_compatibility?(actual_type, expected_type)
  actual_type.is_a?(Types::Primitive) && actual_type.integer? &&
    expected_type.is_a?(Types::Primitive) && expected_type.float?
end

#contextual_int_to_float_target?(type) ⇒ Boolean

Returns:

  • (Boolean)


165
166
167
# File 'lib/milk_tea/core/types/predicates.rb', line 165

def contextual_int_to_float_target?(type)
  type.is_a?(Types::Primitive) && type.float?
end

#dyn_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


423
424
425
# File 'lib/milk_tea/core/types/predicates.rb', line 423

def dyn_type?(type)
  type.is_a?(Types::Dyn)
end

#exact_integer_constant_value(value) ⇒ Object



89
90
91
92
93
94
95
# File 'lib/milk_tea/core/types/predicates.rb', line 89

def exact_integer_constant_value(value)
  return value if value.is_a?(Integer)
  return nil unless value.is_a?(Float) && value.finite?

  integer_value = value.to_i
  integer_value.to_f == value ? integer_value : nil
end

#exactly_representable_float32?(value) ⇒ Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/milk_tea/core/types/predicates.rb', line 112

def exactly_representable_float32?(value)
  [value].pack("f").unpack1("f") == value
end

#external_numeric_compatibility?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


131
132
133
134
135
136
137
138
139
# File 'lib/milk_tea/core/types/predicates.rb', line 131

def external_numeric_compatibility?(actual_type, expected_type)
  return false unless actual_type.is_a?(Types::Primitive) && expected_type.is_a?(Types::Primitive)
  return false unless actual_type.numeric? && expected_type.numeric?

  return lossless_external_integer_compatibility?(actual_type, expected_type) if actual_type.integer? && expected_type.integer?
  return expected_type.float_width >= actual_type.float_width if actual_type.float? && expected_type.float?

  false
end

#external_typed_null_pointer_compatibility?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


49
50
51
52
53
54
55
56
57
# File 'lib/milk_tea/core/types/predicates.rb', line 49

def external_typed_null_pointer_compatibility?(actual_type, expected_type)
  return false unless actual_type.is_a?(Types::Null)
  return false unless actual_type.target_type
  return false if expected_type.is_a?(Types::Nullable)
  return true if expected_type == Types::Registry.primitive("cstr") && char_pointer_type?(actual_type.target_type)
  return false unless pointer_type?(expected_type)

  actual_type.target_type == expected_type
end

#flatten_field_types(type) ⇒ Object



363
364
365
366
367
368
369
370
371
# File 'lib/milk_tea/core/types/predicates.rb', line 363

def flatten_field_types(type)
  if type.is_a?(Types::Primitive)
    [type]
  elsif type.respond_to?(:fields) && type.fields
    type.fields.values.flat_map { |ft| flatten_field_types(ft) }
  else
    [type]
  end
end

#float_constant_fits_type?(value, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/milk_tea/core/types/predicates.rb', line 74

def float_constant_fits_type?(value, expected_type)
  return false unless value.is_a?(Numeric)
  return false unless value.finite?

  if expected_type.name == "float"
    return value.abs <= (1 << 24) if value.is_a?(Integer)

    exactly_representable_float32?(value.to_f)
  else
    return true if expected_type.name == "double"

    false
  end
end

#foreign_boundary_element_compatible?(public_type, boundary_type) ⇒ Boolean

Returns:

  • (Boolean)


204
205
206
207
208
209
210
# File 'lib/milk_tea/core/types/predicates.rb', line 204

def foreign_boundary_element_compatible?(public_type, boundary_type)
  return true if public_type == boundary_type
  return true if public_type == Types::Registry.string_view && boundary_type == Types::Registry.primitive("cstr")
  return true if public_type == Types::Registry.string_view && char_pointer_type?(boundary_type)

  foreign_identity_projection_compatible?(public_type, boundary_type)
end

#foreign_char_pointer_buffer_boundary_compatible?(public_type, boundary_type) ⇒ Boolean

Returns:

  • (Boolean)


194
195
196
197
198
199
200
201
202
# File 'lib/milk_tea/core/types/predicates.rb', line 194

def foreign_char_pointer_buffer_boundary_compatible?(public_type, boundary_type)
  return false unless char_pointer_type?(boundary_type)

  return true if public_type.is_a?(Types::Span) && public_type.element_type == Types::Registry.primitive("char")
  return true if char_array_text_type?(public_type)
  return true if str_buffer_type?(public_type)

  false
end

#foreign_external_layout_compatible?(actual_type, expected_type, seen = {}) ⇒ Boolean

Returns:

  • (Boolean)


302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/milk_tea/core/types/predicates.rb', line 302

def foreign_external_layout_compatible?(actual_type, expected_type, seen = {})
  return false unless actual_type.is_a?(Types::Struct) && expected_type.is_a?(Types::Struct)
  return false if actual_type.is_a?(Types::Union) != expected_type.is_a?(Types::Union)
  return false unless actual_type.external && expected_type.external
  return false unless actual_type.name == expected_type.name
  return false unless actual_type.packed == expected_type.packed
  return false unless actual_type.alignment == expected_type.alignment

  key = [actual_type.object_id, expected_type.object_id]
  return true if seen[key]

  seen[key] = true
  actual_fields = actual_type.fields
  expected_fields = expected_type.fields
  return false unless actual_fields.keys == expected_fields.keys

  actual_fields.all? do |field_name, field_type|
    foreign_external_layout_field_compatible?(field_type, expected_fields.fetch(field_name), seen)
  end
end

#foreign_external_layout_field_compatible?(actual_type, expected_type, seen) ⇒ Boolean

Returns:

  • (Boolean)


323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/milk_tea/core/types/predicates.rb', line 323

def foreign_external_layout_field_compatible?(actual_type, expected_type, seen)
  return true if actual_type == expected_type

  if actual_type.is_a?(Types::Nullable) && expected_type.is_a?(Types::Nullable)
    return foreign_external_layout_field_compatible?(actual_type.base, expected_type.base, seen)
  end

  if pointer_type?(actual_type) && pointer_type?(expected_type)
    return foreign_external_layout_field_compatible?(actual_type.arguments.first, expected_type.arguments.first, seen)
  end

  if array_type?(actual_type) && array_type?(expected_type)
    return false unless array_length(actual_type) == array_length(expected_type)

    return foreign_external_layout_field_compatible?(array_element_type(actual_type), array_element_type(expected_type), seen)
  end

  foreign_external_layout_compatible?(actual_type, expected_type, seen)
end

#foreign_function_type_projection_compatible?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/milk_tea/core/types/predicates.rb', line 264

def foreign_function_type_projection_compatible?(actual_type, expected_type)
  return false unless actual_type.is_a?(Types::Function) && expected_type.is_a?(Types::Function)
  return false unless actual_type.receiver_type == expected_type.receiver_type
  return false unless actual_type.variadic == expected_type.variadic
  return false unless actual_type.params.length == expected_type.params.length
  return false unless foreign_identity_projection_compatible?(actual_type.return_type, expected_type.return_type)

  actual_type.params.zip(expected_type.params).all? do |actual_param, expected_param|
    actual_param.mutable == expected_param.mutable &&
      actual_param.passing_mode == expected_param.passing_mode &&
      actual_param.boundary_type == expected_param.boundary_type &&
      foreign_identity_projection_compatible?(actual_param.type, expected_param.type)
  end
end

#foreign_identity_projection_cast_compatible?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/milk_tea/core/types/predicates.rb', line 217

def foreign_identity_projection_cast_compatible?(actual_type, expected_type)
  return true if actual_type == expected_type
  return true if mutable_to_const_pointer_compatibility?(actual_type, expected_type)
  return true if same_external_opaque_c_name?(actual_type, expected_type)
  return true if foreign_function_type_projection_compatible?(actual_type, expected_type)
  return true if native_foreign_layout_compatible?(actual_type, expected_type)
  return true if native_foreign_layout_compatible?(expected_type, actual_type)
  return true if quat_vec4_layout_compatible?(actual_type, expected_type)

  if actual_type.is_a?(Types::Nullable) && expected_type.is_a?(Types::Nullable)
    return foreign_identity_projection_cast_compatible?(actual_type.base, expected_type.base)
  end

  return foreign_identity_projection_cast_compatible?(actual_type, expected_type.base) if expected_type.is_a?(Types::Nullable)
  return false if actual_type.is_a?(Types::Nullable)

  return true if same_external_opaque_handle_pointer_compatibility?(actual_type, expected_type)

  if pointer_type?(actual_type) && pointer_type?(expected_type)
    return false if const_pointer_type?(actual_type) && mutable_pointer_type?(expected_type)
    return true if void_pointer_type?(actual_type) || void_pointer_type?(expected_type)

    return true if foreign_identity_projection_cast_compatible?(actual_type.arguments.first, expected_type.arguments.first)

    return foreign_external_layout_compatible?(actual_type.arguments.first, expected_type.arguments.first)
  end

  return true if void_pointer_type?(actual_type) && opaque_type?(expected_type)
  return true if opaque_type?(actual_type) && void_pointer_type?(expected_type)
  return true if char_pointer_type?(actual_type) && expected_type == Types::Registry.primitive("cstr")
  return true if actual_type == Types::Registry.primitive("cstr") && char_pointer_type?(expected_type)

  false
end

#foreign_identity_projection_compatible?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


212
213
214
215
# File 'lib/milk_tea/core/types/predicates.rb', line 212

def foreign_identity_projection_compatible?(actual_type, expected_type)
  foreign_identity_projection_cast_compatible?(actual_type, expected_type) ||
    foreign_identity_projection_reinterpret_compatible?(actual_type, expected_type)
end

#foreign_identity_projection_reinterpret_compatible?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


291
292
293
294
295
296
297
298
299
300
# File 'lib/milk_tea/core/types/predicates.rb', line 291

def foreign_identity_projection_reinterpret_compatible?(actual_type, expected_type)
  if actual_type.is_a?(Types::Nullable) && expected_type.is_a?(Types::Nullable)
    return foreign_identity_projection_reinterpret_compatible?(actual_type.base, expected_type.base)
  end

  return foreign_identity_projection_reinterpret_compatible?(actual_type, expected_type.base) if expected_type.is_a?(Types::Nullable)
  return false if actual_type.is_a?(Types::Nullable)

  foreign_external_layout_compatible?(actual_type, expected_type)
end

#foreign_opaque_c_name(type) ⇒ Object



287
288
289
# File 'lib/milk_tea/core/types/predicates.rb', line 287

def foreign_opaque_c_name(type)
  type.linkage_name || type.name
end

#foreign_span_boundary_compatible?(public_type, boundary_type) ⇒ Boolean

Returns:

  • (Boolean)


188
189
190
191
192
# File 'lib/milk_tea/core/types/predicates.rb', line 188

def foreign_span_boundary_compatible?(public_type, boundary_type)
  return false unless public_type.is_a?(Types::Span) && boundary_type.is_a?(Types::Span)

  foreign_boundary_element_compatible?(public_type.element_type, boundary_type.element_type)
end

#function_type_matches_proc_type?(function_type, proc_type) ⇒ Boolean

Returns:

  • (Boolean)


28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/milk_tea/core/types/predicates.rb', line 28

def function_type_matches_proc_type?(function_type, proc_type)
  return false if function_type.receiver_type || function_type.variadic
  return false unless function_type.params.length == proc_type.params.length
  return false unless function_type.return_type == proc_type.return_type

  function_type.params.zip(proc_type.params).all? do |function_param, proc_param|
    next false unless function_param.mutable == proc_param.mutable

    function_param.type == proc_param.type ||
      same_external_opaque_handle_pointer_compatibility?(function_param.type, proc_param.type)
  end
end

#generic_integer_type_argument?(argument) ⇒ Boolean

Returns:

  • (Boolean)


525
526
527
# File 'lib/milk_tea/core/types/predicates.rb', line 525

def generic_integer_type_argument?(argument)
  integer_type_argument?(argument) || argument.is_a?(Types::TypeVar)
end

#integer_constant_fits_type?(value, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


67
68
69
70
71
72
# File 'lib/milk_tea/core/types/predicates.rb', line 67

def integer_constant_fits_type?(value, expected_type)
  integer_value = exact_integer_constant_value(value)
  return false if integer_value.nil?

  value_fits_integer_type?(integer_value, expected_type)
end

#integer_like_char_source_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
123
124
125
# File 'lib/milk_tea/core/types/predicates.rb', line 120

def integer_like_char_source_type?(type)
  return true if type.is_a?(Types::Primitive) && type.integer?
  return true if type.is_a?(Types::EnumBase) && type.backing_type.is_a?(Types::Primitive) && type.backing_type.integer?

  false
end

#integer_to_char_compatibility?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/milk_tea/core/types/predicates.rb', line 116

def integer_to_char_compatibility?(actual_type, expected_type)
  char_type?(expected_type) && integer_like_char_source_type?(actual_type)
end

#integer_type_argument?(argument) ⇒ Boolean

Returns:

  • (Boolean)


521
522
523
# File 'lib/milk_tea/core/types/predicates.rb', line 521

def integer_type_argument?(argument)
  argument.is_a?(Types::LiteralTypeArg) && argument.value.is_a?(Integer)
end

#lossless_external_integer_compatibility?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


141
142
143
144
145
146
147
148
149
150
151
# File 'lib/milk_tea/core/types/predicates.rb', line 141

def lossless_external_integer_compatibility?(actual_type, expected_type)
  return false unless actual_type.fixed_width_integer? && expected_type.fixed_width_integer?

  if actual_type.signed_integer? == expected_type.signed_integer?
    return expected_type.integer_width >= actual_type.integer_width
  end

  return false if actual_type.signed_integer?

  expected_type.signed_integer? && expected_type.integer_width > actual_type.integer_width
end

#lossless_integer_compatibility?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


153
154
155
156
157
158
# File 'lib/milk_tea/core/types/predicates.rb', line 153

def lossless_integer_compatibility?(actual_type, expected_type)
  return false unless actual_type.is_a?(Types::Primitive) && expected_type.is_a?(Types::Primitive)
  return false unless actual_type.integer? && expected_type.integer?

  lossless_external_integer_compatibility?(actual_type, expected_type)
end

#method_dispatch_receiver_type(receiver_type) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/milk_tea/core/types/predicates.rb', line 5

def method_dispatch_receiver_type(receiver_type)
  return receiver_type.definition if receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::VariantInstance)
  if receiver_type.is_a?(Types::Nullable)
    dispatch_base_type = method_dispatch_receiver_type(receiver_type.base)
    return receiver_type if dispatch_base_type == receiver_type.base

    return Types::Registry.nullable(dispatch_base_type)
  end
  return receiver_type unless receiver_type.is_a?(Types::GenericInstance)

  dispatch_receiver_type = Types::Registry.generic_instance(
    receiver_type.name,
    receiver_type.arguments.each_with_index.map do |argument, index|
      argument.is_a?(Types::LiteralTypeArg) ? argument : Types::TypeVar.new("__receiver_arg#{index}")
    end,
  )
  dispatch_receiver_type == receiver_type ? receiver_type : dispatch_receiver_type
end

#mutable_pointer_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


385
386
387
# File 'lib/milk_tea/core/types/predicates.rb', line 385

def mutable_pointer_type?(type)
  type.is_a?(Types::GenericInstance) && type.name == "ptr" && type.arguments.length == 1
end

#mutable_to_const_pointer_compatibility?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


169
170
171
172
173
174
175
176
# File 'lib/milk_tea/core/types/predicates.rb', line 169

def mutable_to_const_pointer_compatibility?(actual_type, expected_type)
  return mutable_to_const_pointer_compatibility?(actual_type.base, expected_type.base) if actual_type.is_a?(Types::Nullable) && expected_type.is_a?(Types::Nullable)
  return mutable_to_const_pointer_compatibility?(actual_type, expected_type.base) if expected_type.is_a?(Types::Nullable)
  return false if actual_type.is_a?(Types::Nullable)
  return false unless (mutable_pointer_type?(actual_type) || own_type?(actual_type)) && const_pointer_type?(expected_type)

  pointee_type(actual_type) == pointee_type(expected_type)
end

#native_foreign_layout_compatible?(native_type, foreign_type) ⇒ Boolean

Returns:

  • (Boolean)


347
348
349
350
351
352
353
354
355
356
# File 'lib/milk_tea/core/types/predicates.rb', line 347

def native_foreign_layout_compatible?(native_type, foreign_type)
  return false unless (native_type.is_a?(Types::Vector) || native_type.is_a?(Types::Matrix) || native_type.is_a?(Types::Quaternion))
  return false unless foreign_type.is_a?(Types::Struct) && foreign_type.external

  native_flat = flatten_field_types(native_type)
  foreign_flat = flatten_field_types(foreign_type)
  return false unless native_flat.size == foreign_flat.size

  native_flat.zip(foreign_flat).all? { |nf, ff| nf == ff }
end

#null_assignable_to?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


41
42
43
44
45
46
47
# File 'lib/milk_tea/core/types/predicates.rb', line 41

def null_assignable_to?(actual_type, expected_type)
  return false unless actual_type.is_a?(Types::Null)
  return false unless expected_type.is_a?(Types::Nullable)
  return true unless actual_type.target_type

  actual_type.target_type == expected_type.base
end

#numeric_constant_fits_type?(value, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


59
60
61
62
63
64
65
# File 'lib/milk_tea/core/types/predicates.rb', line 59

def numeric_constant_fits_type?(value, expected_type)
  if expected_type.integer?
    integer_constant_fits_type?(value, expected_type)
  else
    float_constant_fits_type?(value, expected_type)
  end
end

#opaque_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


377
378
379
# File 'lib/milk_tea/core/types/predicates.rb', line 377

def opaque_type?(type)
  type.is_a?(Types::Opaque)
end

#own_to_raw_pointer_compatibility?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


178
179
180
181
182
183
184
185
186
# File 'lib/milk_tea/core/types/predicates.rb', line 178

def own_to_raw_pointer_compatibility?(actual_type, expected_type)
  return own_to_raw_pointer_compatibility?(actual_type.base, expected_type.base) if actual_type.is_a?(Types::Nullable) && expected_type.is_a?(Types::Nullable)
  return own_to_raw_pointer_compatibility?(actual_type, expected_type.base) if expected_type.is_a?(Types::Nullable)
  return false if actual_type.is_a?(Types::Nullable)
  return false unless own_type?(actual_type)
  return false unless mutable_pointer_type?(expected_type) || const_pointer_type?(expected_type)

  pointee_type(actual_type) == pointee_type(expected_type)
end

#own_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


393
394
395
# File 'lib/milk_tea/core/types/predicates.rb', line 393

def own_type?(type)
  type.is_a?(Types::GenericInstance) && type.name == "own" && type.arguments.length == 1
end

#owned_referent_type(type) ⇒ Object



397
398
399
# File 'lib/milk_tea/core/types/predicates.rb', line 397

def owned_referent_type(type)
  type.arguments.first if own_type?(type)
end

#pointee_type(type) ⇒ Object



439
440
441
442
443
# File 'lib/milk_tea/core/types/predicates.rb', line 439

def pointee_type(type)
  return unless pointer_type?(type)

  type.arguments.first
end

#pointer_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


381
382
383
# File 'lib/milk_tea/core/types/predicates.rb', line 381

def pointer_type?(type)
  mutable_pointer_type?(type) || const_pointer_type?(type) || own_type?(type)
end

#proc_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


435
436
437
# File 'lib/milk_tea/core/types/predicates.rb', line 435

def proc_type?(type)
  type.is_a?(Types::Proc)
end

#quat_vec4_layout_compatible?(a, b) ⇒ Boolean

Returns:

  • (Boolean)


358
359
360
361
# File 'lib/milk_tea/core/types/predicates.rb', line 358

def quat_vec4_layout_compatible?(a, b)
  (a.is_a?(Types::Quaternion) && b.is_a?(Types::Vector) && b.width == 4 && b.element_type.name == "float") ||
    (b.is_a?(Types::Quaternion) && a.is_a?(Types::Vector) && a.width == 4 && a.element_type.name == "float")
end

#ref_lifetime(type) ⇒ Object



417
418
419
420
421
# File 'lib/milk_tea/core/types/predicates.rb', line 417

def ref_lifetime(type)
  return unless type.is_a?(Types::GenericInstance) && type.name == "ref" && type.arguments.length == 2

  type.arguments.first
end

#ref_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


401
402
403
# File 'lib/milk_tea/core/types/predicates.rb', line 401

def ref_type?(type)
  type.is_a?(Types::GenericInstance) && type.name == "ref" && [1, 2].include?(type.arguments.length)
end

#ref_type_without_lifetime?(type) ⇒ Boolean

Returns:

  • (Boolean)


413
414
415
# File 'lib/milk_tea/core/types/predicates.rb', line 413

def ref_type_without_lifetime?(type)
  type.is_a?(Types::GenericInstance) && type.name == "ref" && type.arguments.length == 1
end

#referenced_type(type) ⇒ Object



445
446
447
448
449
# File 'lib/milk_tea/core/types/predicates.rb', line 445

def referenced_type(type)
  return unless ref_type?(type)

  type.arguments.length == 1 ? type.arguments.first : type.arguments[1]
end

#same_external_opaque_c_name?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


279
280
281
282
283
284
285
# File 'lib/milk_tea/core/types/predicates.rb', line 279

def same_external_opaque_c_name?(actual_type, expected_type)
  return false unless actual_type.is_a?(Types::Opaque) && expected_type.is_a?(Types::Opaque)
  return false unless actual_type.external || actual_type.linkage_name
  return false unless expected_type.external || expected_type.linkage_name

  foreign_opaque_c_name(actual_type) == foreign_opaque_c_name(expected_type)
end

#same_external_opaque_handle_pointer_compatibility?(actual_type, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


252
253
254
255
256
257
258
259
260
261
262
# File 'lib/milk_tea/core/types/predicates.rb', line 252

def same_external_opaque_handle_pointer_compatibility?(actual_type, expected_type)
  if actual_type.is_a?(Types::Opaque) && pointer_type?(expected_type)
    return same_external_opaque_c_name?(actual_type, expected_type.arguments.first)
  end

  if pointer_type?(actual_type) && expected_type.is_a?(Types::Opaque)
    return same_external_opaque_c_name?(actual_type.arguments.first, expected_type)
  end

  false
end

#string_builder_ref_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


473
474
475
# File 'lib/milk_tea/core/types/predicates.rb', line 473

def string_builder_ref_type?(type)
  ref_type?(type) && string_builder_type?(referenced_type(type))
end

#string_builder_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


469
470
471
# File 'lib/milk_tea/core/types/predicates.rb', line 469

def string_builder_type?(type)
  type.respond_to?(:name) && type.respond_to?(:module_name) && type.name == "String" && type.module_name == "std.string"
end

#struct_with_target_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


431
432
433
# File 'lib/milk_tea/core/types/predicates.rb', line 431

def struct_with_target_type?(type)
  type.is_a?(Types::Struct) || type.is_a?(Types::Vector) || type.is_a?(Types::Matrix) || type.is_a?(Types::Quaternion)
end

#task_root_proc_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


24
25
26
# File 'lib/milk_tea/core/types/predicates.rb', line 24

def task_root_proc_type?(type)
  proc_type?(type) && type.params.empty? && type.return_type.is_a?(Types::Task)
end

#task_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


427
428
429
# File 'lib/milk_tea/core/types/predicates.rb', line 427

def task_type?(type)
  type.is_a?(Types::Task)
end

#validate_generic_type!(name, arguments, &error) ⇒ Object



529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
# File 'lib/milk_tea/core/types/predicates.rb', line 529

def validate_generic_type!(name, arguments, &error)
  case name
  when "ptr"
    error.call("ptr requires exactly one type argument") unless arguments.length == 1
    error.call("ptr type argument must be a type") if arguments.first.is_a?(Types::LiteralTypeArg)
  when "const_ptr"
    error.call("const_ptr requires exactly one type argument") unless arguments.length == 1
    error.call("const_ptr type argument must be a type") if arguments.first.is_a?(Types::LiteralTypeArg)
    error.call("const_ptr cannot target ref types") if contains_ref_type?(arguments.first)
  when "own"
    error.call("own requires exactly one type argument") unless arguments.length == 1
    error.call("own type argument must be a type") if arguments.first.is_a?(Types::LiteralTypeArg)
  when "ref"
    unless [1, 2].include?(arguments.length)
      error.call("ref requires exactly one type argument")
    end
    type_arg = arguments.length == 1 ? arguments.first : arguments[1]
    error.call("ref type argument must be a type") if type_arg.is_a?(Types::LiteralTypeArg)
    error.call("ref cannot target void") if type_arg.is_a?(Types::Primitive) && type_arg.void?
    if contains_ref_type?(type_arg)
      unless (type_arg.is_a?(Types::Struct) || type_arg.is_a?(Types::StructInstance)) && type_arg.lifetime_params&.any?
        error.call("ref cannot target another ref type")
      end
    end
  when "span"
    error.call("span requires exactly one type argument") unless arguments.length == 1
    error.call("span element type must be a type") if arguments.first.is_a?(Types::LiteralTypeArg)
  when "array"
    error.call("array requires exactly two type arguments") unless arguments.length == 2
    error.call("array element type must be a type") if arguments.first.is_a?(Types::LiteralTypeArg)
    error.call("array length must be an integer literal, named const, or type parameter") unless generic_integer_type_argument?(arguments[1])
    error.call("array length must be positive") if integer_type_argument?(arguments[1]) && !arguments[1].value.positive?
  when "SoA"
    error.call("SoA requires exactly two type arguments") unless arguments.length == 2
    error.call("SoA element type must be a type") if arguments.first.is_a?(Types::LiteralTypeArg)
    error.call("SoA element type must be a struct with fields") unless arguments.first.respond_to?(:fields) && arguments.first.fields.any?
    error.call("SoA length must be an integer literal, named const, or type parameter") unless generic_integer_type_argument?(arguments[1])
    error.call("SoA length must be positive") if integer_type_argument?(arguments[1]) && !arguments[1].value.positive?
  when "str_buffer"
    error.call("str_buffer requires exactly one type argument") unless arguments.length == 1
    error.call("str_buffer capacity must be an integer literal, named const, or type parameter") unless generic_integer_type_argument?(arguments.first)
    error.call("str_buffer capacity must be positive") if integer_type_argument?(arguments.first) && !arguments.first.value.positive?
  when "Task"
    error.call("Task requires exactly one type argument") unless arguments.length == 1
    error.call("Task result type must be a type") if arguments.first.is_a?(Types::LiteralTypeArg)
  when "atomic"
    error.call("atomic requires exactly one type argument") unless arguments.length == 1
    arg = arguments.first
    error.call("atomic type argument must be a type") if arg.is_a?(Types::LiteralTypeArg)
    error.call("atomic type argument must be a primitive integer or bool") unless arg.is_a?(Types::Primitive) && (arg.integer? || arg.boolean?)
  else
    error.call("unknown generic type #{name}")
  end
end

#value_fits_integer_type?(value, expected_type) ⇒ Boolean

Returns:

  • (Boolean)


97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/milk_tea/core/types/predicates.rb', line 97

def value_fits_integer_type?(value, expected_type)
  return false unless expected_type.is_a?(Types::Primitive) && expected_type.integer?

  width = expected_type.integer_width
  return false if width.nil?

  min_value, max_value = if expected_type.signed_integer?
                           [-(1 << (width - 1)), (1 << (width - 1)) - 1]
                         else
                           [0, (1 << width) - 1]
                         end

  value >= min_value && value <= max_value
end

#void_pointer_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


343
344
345
# File 'lib/milk_tea/core/types/predicates.rb', line 343

def void_pointer_type?(type)
  pointer_type?(type) && type.arguments.first == Types::Registry.primitive("void")
end