mt-lang 0.2.19 → 0.2.20

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '076938689f867b9d3d7f60eab7f4654c03a45ea69b429f1af17c86a3afef51a5'
4
- data.tar.gz: 6f01bf9d070e1307666949acf47d99170d6b28c0048c868a6310663f2d55c919
3
+ metadata.gz: 98c4dc25b7d1fb3ab4931eed5fd30c29e30448a3b2c3fe85d6b58d823fab7baa
4
+ data.tar.gz: a025a925117c16e69f85667f4411a5d09b92ac0ea65e6ec061111578db39001a
5
5
  SHA512:
6
- metadata.gz: 8141047ac65832b64b8eab1d565b5c3eb3bf8841b5541624605179a1e4bc0479f4dab16a92b3b7055e2eb844e37781aac7acab2aa812b348e53d9a151a16fe97
7
- data.tar.gz: e5ead28d45b33a6c7fdb5c46f84cdd9a887e6bca593b841687a1d1124ba904f02ee09bdb1ef8dab87f2b8dcfcd6480190e94cea57e8b3b4853148d06d199f6e6
6
+ metadata.gz: e18ef0444a502981b66eed892a94ccc92918c2d1254669d912e27a8e43b552d360cbc9d4eaf386935b141700ee992eedb365093c00bd67e35e3d878e20f17fbb
7
+ data.tar.gz: 1e642ded750895e1cabc818bff33c7a88beffc463975d46dc98a2a45cb7eb07d53ee57580fee90fd31b3d8af011e4477a41779044c535513a444457bcd12a902
data/lib/milk_tea/base.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require "pathname"
4
4
 
5
5
  module MilkTea
6
- VERSION = "0.2.19"
6
+ VERSION = "0.2.20"
7
7
 
8
8
  def self.root
9
9
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
@@ -450,6 +450,21 @@ module MilkTea
450
450
  raise_sema_error("safe array indexing requires an addressable array value; bind it to a local first")
451
451
  end
452
452
 
453
+ if array_type?(receiver_type) && expression.index.is_a?(AST::IntegerLiteral)
454
+ length = array_length(receiver_type)
455
+ index_val = expression.index.value
456
+ if index_val >= length || index_val < 0
457
+ raise_sema_error("array index #{index_val} is out of bounds for array[T, #{length}]", expression)
458
+ end
459
+ end
460
+
461
+ if array_type?(receiver_type) && expression.index.is_a?(AST::UnaryOp) && expression.index.operator == "-" &&
462
+ expression.index.operand.is_a?(AST::IntegerLiteral)
463
+ length = array_length(receiver_type)
464
+ index_val = -expression.index.operand.value
465
+ raise_sema_error("array index #{index_val} is out of bounds for array[T, #{length}]", expression)
466
+ end
467
+
453
468
  infer_index_result_type(receiver_type, index_type)
454
469
  end
455
470
 
@@ -185,6 +185,7 @@ module MilkTea
185
185
 
186
186
  validate_consuming_foreign_expression!(statement.value, scopes:, root_allowed: false) if statement.value
187
187
  value_type = statement.value ? infer_expression(statement.value, scopes:, expected_type: return_type) : @ctx.types.fetch("void")
188
+ check_stack_pointer_escape_in_return(statement.value, scopes:) if statement.value
188
189
  ensure_assignable!(
189
190
  value_type,
190
191
  return_type,
@@ -1322,6 +1323,64 @@ module MilkTea
1322
1323
  end
1323
1324
  end
1324
1325
 
1326
+ # Walks the returned expression tree to detect ptr_of/ref_of/const_ptr_of
1327
+ # applied to a stack-local variable whose address must not escape the
1328
+ # function. Only flags when the pointer value itself (not a computed
1329
+ # result through a function call) reaches the return.
1330
+ def check_stack_pointer_escape_in_return(expression, scopes:)
1331
+ return unless expression
1332
+
1333
+ if expression.is_a?(AST::Call)
1334
+ check_stack_escape_call(expression, scopes:)
1335
+ elsif expression.is_a?(AST::BinaryOp)
1336
+ check_stack_pointer_escape_in_return(expression.left, scopes:)
1337
+ check_stack_pointer_escape_in_return(expression.right, scopes:)
1338
+ elsif expression.is_a?(AST::UnaryOp)
1339
+ check_stack_pointer_escape_in_return(expression.operand, scopes:)
1340
+ end
1341
+ end
1342
+
1343
+ def check_stack_escape_call(expression, scopes:)
1344
+ callee = expression.callee
1345
+ return unless callee.is_a?(AST::Identifier)
1346
+ return unless %w[ptr_of ref_of const_ptr_of].include?(callee.name)
1347
+ return if expression.arguments.empty?
1348
+
1349
+ arg = expression.arguments.first
1350
+ source = arg.respond_to?(:value) ? arg.value : arg
1351
+ check_stack_local_source(source, scopes:, builtin: callee.name)
1352
+ end
1353
+
1354
+ def check_stack_local_source(expression, scopes:, builtin:)
1355
+ case expression
1356
+ when AST::Identifier
1357
+ binding = lookup_local_binding(expression.name, scopes)
1358
+ return unless binding
1359
+ return unless %i[let var param].include?(binding.kind)
1360
+ return if stack_safe_pointer_source?(binding)
1361
+ raise_sema_error(
1362
+ "#{builtin}(#{expression.name}) cannot be returned: pointer to function-local storage",
1363
+ expression,
1364
+ )
1365
+ when AST::MemberAccess
1366
+ check_stack_local_source(expression.receiver, scopes:, builtin:)
1367
+ when AST::IndexAccess
1368
+ check_stack_local_source(expression.receiver, scopes:, builtin:)
1369
+ end
1370
+ end
1371
+
1372
+ def lookup_local_binding(name, scopes)
1373
+ scopes.reverse_each do |scope|
1374
+ return scope[name] if scope.key?(name)
1375
+ end
1376
+ nil
1377
+ end
1378
+
1379
+ def stack_safe_pointer_source?(binding)
1380
+ return false unless binding.type
1381
+ ref_type?(binding.type) || own_type?(binding.type)
1382
+ end
1383
+
1325
1384
  end
1326
1385
  end
1327
1386
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mt-lang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.19
4
+ version: 0.2.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Long (Teefan) Tran
@@ -586,7 +586,7 @@ metadata:
586
586
  homepage_uri: https://teefan.github.io/mt-lang/
587
587
  source_code_uri: https://github.com/teefan/mt-lang
588
588
  post_install_message: |
589
- Milk Tea 0.2.19 installed!
589
+ Milk Tea 0.2.20 installed!
590
590
 
591
591
  System requirements:
592
592
  - A C compiler (gcc or clang) must be available on PATH