style: compact inner groups and simple guard bodies
This commit is contained in:
@@ -105,18 +105,12 @@ render_block proc(renderer @mut Renderer, tree @ast.Tree, block ast.NodeId, dept
|
|||||||
try append_text(renderer, ast.source_text(tree, ast.node_span(tree, loop.iterable)))
|
try append_text(renderer, ast.source_text(tree, ast.node_span(tree, loop.iterable)))
|
||||||
try append_text(renderer, " |")
|
try append_text(renderer, " |")
|
||||||
if (loop.pointer_capture) try append_text(renderer, "@")
|
if (loop.pointer_capture) try append_text(renderer, "@")
|
||||||
if (loop.capture) |capture| {
|
if (loop.capture) |capture| try append_text(renderer, ast.source_text(tree, ast.node_span(tree, capture)))
|
||||||
try append_text(renderer, ast.source_text(tree, ast.node_span(tree, capture)))
|
else try append_text(renderer, "_")
|
||||||
} else {
|
|
||||||
try append_text(renderer, "_")
|
|
||||||
}
|
|
||||||
if (loop.index_capture) {
|
if (loop.index_capture) {
|
||||||
try append_text(renderer, ", ")
|
try append_text(renderer, ", ")
|
||||||
if (loop.index) |index| {
|
if (loop.index) |index| try append_text(renderer, ast.source_text(tree, ast.node_span(tree, index)))
|
||||||
try append_text(renderer, ast.source_text(tree, ast.node_span(tree, index)))
|
else try append_text(renderer, "_")
|
||||||
} else {
|
|
||||||
try append_text(renderer, "_")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try append_text(renderer, "|\n")
|
try append_text(renderer, "|\n")
|
||||||
try render_block(renderer, tree, loop.body, depth + 1)
|
try render_block(renderer, tree, loop.body, depth + 1)
|
||||||
|
|||||||
@@ -347,9 +347,7 @@ compile proc(
|
|||||||
for (0..ast.package_decl_count(&tree)) |i| try arraylist.append(&declarations, ast.package_decl(&tree, i))
|
for (0..ast.package_decl_count(&tree)) |i| try arraylist.append(&declarations, ast.package_decl(&tree, i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compilation.module_root == null) {
|
if (compilation.module_root == null) compilation.module_root = try ast.add_package(&compilation.builder, diagnostics.Span{ start = 0, end = 0 }, declarations.items)
|
||||||
compilation.module_root = try ast.add_package(&compilation.builder, diagnostics.Span{ start = 0, end = 0 }, declarations.items)
|
|
||||||
}
|
|
||||||
imports := arraylist.init(sema.Import, compilation.allocator)
|
imports := arraylist.init(sema.Import, compilation.allocator)
|
||||||
defer arraylist.deinit(&imports)
|
defer arraylist.deinit(&imports)
|
||||||
tree := ast.view(&compilation.builder, compilation.module_root?)
|
tree := ast.view(&compilation.builder, compilation.module_root?)
|
||||||
@@ -362,11 +360,9 @@ compile proc(
|
|||||||
diagnostic.span.source == imported.path.source
|
diagnostic.span.source == imported.path.source
|
||||||
and diagnostic.span.start == imported.path.start
|
and diagnostic.span.start == imported.path.start
|
||||||
and diagnostic.span.end == imported.path.end
|
and diagnostic.span.end == imported.path.end
|
||||||
and (
|
and (diagnostic.code == .package_unavailable
|
||||||
diagnostic.code == .package_unavailable
|
|
||||||
or diagnostic.code == .invalid_import_path
|
or diagnostic.code == .invalid_import_path
|
||||||
or diagnostic.code == .import_cycle
|
or diagnostic.code == .import_cycle)
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
failure = diagnostics.DiagnosticId(index)
|
failure = diagnostics.DiagnosticId(index)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -170,9 +170,7 @@ execute proc(
|
|||||||
for (frames.items) |frame| free_frame(allocator, frame)
|
for (frames.items) |frame| free_frame(allocator, frame)
|
||||||
arraylist.deinit(&frames)
|
arraylist.deinit(&frames)
|
||||||
}
|
}
|
||||||
if (module.functions.items[usize(entry)].external_name.len != 0) {
|
if (module.functions.items[usize(entry)].external_name.len != 0) return try runtime_trap(diagnostic_store, .unsupported_foreign_call, module.functions.items[usize(entry)].span)
|
||||||
return try runtime_trap(diagnostic_store, .unsupported_foreign_call, module.functions.items[usize(entry)].span)
|
|
||||||
}
|
|
||||||
try push_frame(allocator, module, &frames, entry, ir.no_value, null)
|
try push_frame(allocator, module, &frames, entry, ir.no_value, null)
|
||||||
|
|
||||||
while frames.items.len != 0 {
|
while frames.items.len != 0 {
|
||||||
@@ -204,9 +202,7 @@ execute proc(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
value := ir.Value{}
|
value := ir.Value{}
|
||||||
if terminator.value != ir.no_value {
|
if (terminator.value != ir.no_value) value = frames.items[frame_index].values[usize(terminator.value)]
|
||||||
value = frames.items[frame_index].values[usize(terminator.value)]
|
|
||||||
}
|
|
||||||
completed :: frames.items[frame_index]
|
completed :: frames.items[frame_index]
|
||||||
# transfer leaves while the completed frame still owns its backing.
|
# transfer leaves while the completed frame still owns its backing.
|
||||||
if completed.global |global_index| {
|
if completed.global |global_index| {
|
||||||
@@ -222,9 +218,7 @@ execute proc(
|
|||||||
}
|
}
|
||||||
return Outcome{ value = value }
|
return Outcome{ value = value }
|
||||||
}
|
}
|
||||||
if completed.destination != ir.no_value {
|
if (completed.destination != ir.no_value) copy_value(module, &frames.items[frame_index - 1].values[usize(completed.destination)], value)
|
||||||
copy_value(module, &frames.items[frame_index - 1].values[usize(completed.destination)], value)
|
|
||||||
}
|
|
||||||
_ = arraylist.pop(&frames)
|
_ = arraylist.pop(&frames)
|
||||||
free_frame(allocator, completed)
|
free_frame(allocator, completed)
|
||||||
continue
|
continue
|
||||||
@@ -237,9 +231,7 @@ execute proc(
|
|||||||
.constant: value = instruction.constant
|
.constant: value = instruction.constant
|
||||||
.load_local: {
|
.load_local: {
|
||||||
local :: &frames.items[frame_index].locals[usize(instruction.slot)]
|
local :: &frames.items[frame_index].locals[usize(instruction.slot)]
|
||||||
if !local.initialized {
|
if (!local.initialized) return try runtime_trap(diagnostic_store, .read_before_initialization, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .read_before_initialization, instruction.span)
|
|
||||||
}
|
|
||||||
value = local.value
|
value = local.value
|
||||||
}
|
}
|
||||||
.store_local: {
|
.store_local: {
|
||||||
@@ -250,9 +242,7 @@ execute proc(
|
|||||||
}
|
}
|
||||||
.assign_local: {
|
.assign_local: {
|
||||||
local :: &frames.items[frame_index].locals[usize(instruction.slot)]
|
local :: &frames.items[frame_index].locals[usize(instruction.slot)]
|
||||||
if (!local.initialized) {
|
if (!local.initialized) return try runtime_trap(diagnostic_store, .write_before_initialization, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .write_before_initialization, instruction.span)
|
|
||||||
}
|
|
||||||
copy_value(module, &local.value, frames.items[frame_index].values[usize(instruction.left)])
|
copy_value(module, &local.value, frames.items[frame_index].values[usize(instruction.left)])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -283,13 +273,9 @@ execute proc(
|
|||||||
}
|
}
|
||||||
.call: {
|
.call: {
|
||||||
callable :: frames.items[frame_index].values[usize(instruction.left)]
|
callable :: frames.items[frame_index].values[usize(instruction.left)]
|
||||||
if (callable.data.function == maxval!(ir.FunctionId)) {
|
if (callable.data.function == maxval!(ir.FunctionId)) return try runtime_trap(diagnostic_store, .null_unwrap, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .null_unwrap, instruction.span)
|
|
||||||
}
|
|
||||||
callee :: callable.data.function
|
callee :: callable.data.function
|
||||||
if (module.functions.items[usize(callee)].external_name.len != 0) {
|
if (module.functions.items[usize(callee)].external_name.len != 0) return try runtime_trap(diagnostic_store, .unsupported_foreign_call, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .unsupported_foreign_call, instruction.span)
|
|
||||||
}
|
|
||||||
try push_frame(allocator, module, &frames, callee, instruction.destination, null)
|
try push_frame(allocator, module, &frames, callee, instruction.destination, null)
|
||||||
# frame indices survive stack growth; pointers into frames.items do not.
|
# frame indices survive stack growth; pointers into frames.items do not.
|
||||||
for (0..instruction.arguments_count) |argument_index| {
|
for (0..instruction.arguments_count) |argument_index| {
|
||||||
@@ -346,9 +332,7 @@ execute proc(
|
|||||||
start :: frames.items[frame_index].values[usize(instruction.left)].data.unsigned
|
start :: frames.items[frame_index].values[usize(instruction.left)].data.unsigned
|
||||||
end :: frames.items[frame_index].values[usize(instruction.right)].data.unsigned
|
end :: frames.items[frame_index].values[usize(instruction.right)].data.unsigned
|
||||||
if (start > end) return try runtime_trap(diagnostic_store, .invalid_slice_bounds, instruction.span)
|
if (start > end) return try runtime_trap(diagnostic_store, .invalid_slice_bounds, instruction.span)
|
||||||
if (instruction.extra != ir.no_value and end > frames.items[frame_index].values[usize(instruction.extra)].data.unsigned) {
|
if (instruction.extra != ir.no_value and end > frames.items[frame_index].values[usize(instruction.extra)].data.unsigned) return try runtime_trap(diagnostic_store, .invalid_slice_bounds, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .invalid_slice_bounds, instruction.span)
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
.optional_check: {
|
.optional_check: {
|
||||||
@@ -423,17 +407,13 @@ execute proc(
|
|||||||
base :: frames.items[frame_index].values[usize(instruction.left)]
|
base :: frames.items[frame_index].values[usize(instruction.left)]
|
||||||
index :: frames.items[frame_index].values[usize(instruction.right)].data.unsigned
|
index :: frames.items[frame_index].values[usize(instruction.right)].data.unsigned
|
||||||
shape :: module.arrays.items[usize(base.array_type)]
|
shape :: module.arrays.items[usize(base.array_type)]
|
||||||
if (index >= u64(shape.len)) {
|
if (index >= u64(shape.len)) return try runtime_trap(diagnostic_store, .index_out_of_bounds, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .index_out_of_bounds, instruction.span)
|
|
||||||
}
|
|
||||||
value = ir.aggregate_item(module, base, usize(index))
|
value = ir.aggregate_item(module, base, usize(index))
|
||||||
}
|
}
|
||||||
.field: {
|
.field: {
|
||||||
base :: frames.items[frame_index].values[usize(instruction.left)]
|
base :: frames.items[frame_index].values[usize(instruction.left)]
|
||||||
shape :: module.arrays.items[usize(base.array_type)]
|
shape :: module.arrays.items[usize(base.array_type)]
|
||||||
if (shape.is_union and !ir.union_active(module, base, usize(instruction.slot))) {
|
if (shape.is_union and !ir.union_active(module, base, usize(instruction.slot))) return try runtime_trap(diagnostic_store, .inactive_union_field, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .inactive_union_field, instruction.span)
|
|
||||||
}
|
|
||||||
value = ir.aggregate_item(module, base, usize(instruction.slot))
|
value = ir.aggregate_item(module, base, usize(instruction.slot))
|
||||||
}
|
}
|
||||||
.address_local: {
|
.address_local: {
|
||||||
@@ -489,9 +469,7 @@ execute proc(
|
|||||||
base :: frames.items[frame_index].addresses[usize(base_id)]
|
base :: frames.items[frame_index].addresses[usize(base_id)]
|
||||||
index :: frames.items[frame_index].values[usize(instruction.right)].data.unsigned
|
index :: frames.items[frame_index].values[usize(instruction.right)].data.unsigned
|
||||||
shape :: module.arrays.items[usize(base.array_type)]
|
shape :: module.arrays.items[usize(base.array_type)]
|
||||||
if (index >= u64(shape.len)) {
|
if (index >= u64(shape.len)) return try runtime_trap(diagnostic_store, .index_out_of_bounds, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .index_out_of_bounds, instruction.span)
|
|
||||||
}
|
|
||||||
width :: if (base.raw or base.byte_view) ir.storage_size(module, shape.element, shape.element_array) else element_cells(module, shape)
|
width :: if (base.raw or base.byte_view) ir.storage_size(module, shape.element, shape.element_array) else element_cells(module, shape)
|
||||||
start :: usize(index) * width
|
start :: usize(index) * width
|
||||||
address := base
|
address := base
|
||||||
@@ -513,9 +491,7 @@ execute proc(
|
|||||||
if base.initialized |initialized| {
|
if base.initialized |initialized| {
|
||||||
if (!initialized^) return try runtime_trap(diagnostic_store, .read_before_initialization, instruction.span)
|
if (!initialized^) return try runtime_trap(diagnostic_store, .read_before_initialization, instruction.span)
|
||||||
}
|
}
|
||||||
if (!ir.union_active(module, read_address(module, base, scratch), usize(instruction.slot))) {
|
if (!ir.union_active(module, read_address(module, base, scratch), usize(instruction.slot))) return try runtime_trap(diagnostic_store, .inactive_union_field, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .inactive_union_field, instruction.span)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
raw :: base.raw or shape.is_union
|
raw :: base.raw or shape.is_union
|
||||||
width :: if (raw or base.byte_view) ir.storage_size(module, field.type, field.array_type) else if (ir.aggregate(field.type)) module.arrays.items[usize(field.array_type)].cells else 1
|
width :: if (raw or base.byte_view) ir.storage_size(module, field.type, field.array_type) else if (ir.aggregate(field.type)) module.arrays.items[usize(field.array_type)].cells else 1
|
||||||
@@ -548,9 +524,7 @@ execute proc(
|
|||||||
}
|
}
|
||||||
.pointer_address: {
|
.pointer_address: {
|
||||||
handle :: frames.items[frame_index].values[usize(instruction.left)].data.unsigned
|
handle :: frames.items[frame_index].values[usize(instruction.left)].data.unsigned
|
||||||
if (handle >= u64(pointers.items.len)) {
|
if (handle >= u64(pointers.items.len)) return try runtime_trap(diagnostic_store, .invalid_pointer_access, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .invalid_pointer_access, instruction.span)
|
|
||||||
}
|
|
||||||
location :: pointers.items[usize(handle)]
|
location :: pointers.items[usize(handle)]
|
||||||
if (pointer_address(module, location, instruction.pointee, instruction.array_type)) |address| {
|
if (pointer_address(module, location, instruction.pointee, instruction.array_type)) |address| {
|
||||||
frames.items[frame_index].addresses[usize(instruction.destination)] = address
|
frames.items[frame_index].addresses[usize(instruction.destination)] = address
|
||||||
@@ -561,19 +535,13 @@ execute proc(
|
|||||||
}
|
}
|
||||||
.pointer_offset: {
|
.pointer_offset: {
|
||||||
handle :: frames.items[frame_index].values[usize(instruction.left)].data.unsigned
|
handle :: frames.items[frame_index].values[usize(instruction.left)].data.unsigned
|
||||||
if (handle >= u64(pointers.items.len)) {
|
if (handle >= u64(pointers.items.len)) return try runtime_trap(diagnostic_store, .invalid_pointer_access, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .invalid_pointer_access, instruction.span)
|
|
||||||
}
|
|
||||||
address := pointers.items[usize(handle)]
|
address := pointers.items[usize(handle)]
|
||||||
index :: frames.items[frame_index].values[usize(instruction.right)].data.unsigned
|
index :: frames.items[frame_index].values[usize(instruction.right)].data.unsigned
|
||||||
stride :: ir.storage_size(module, instruction.pointee, instruction.array_type)
|
stride :: ir.storage_size(module, instruction.pointee, instruction.array_type)
|
||||||
if (stride != 0 and index > u64(divtrunc!(maxval!(usize) - address.byte_offset, stride))) {
|
if (stride != 0 and index > u64(divtrunc!(maxval!(usize) - address.byte_offset, stride))) return try runtime_trap(diagnostic_store, .invalid_pointer_access, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .invalid_pointer_access, instruction.span)
|
|
||||||
}
|
|
||||||
address.byte_offset += usize(index) * stride
|
address.byte_offset += usize(index) * stride
|
||||||
if (address.byte_offset > pointer_size(module, address)) {
|
if (address.byte_offset > pointer_size(module, address)) return try runtime_trap(diagnostic_store, .invalid_pointer_access, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .invalid_pointer_access, instruction.span)
|
|
||||||
}
|
|
||||||
value = try pointer_value(&pointers, address)
|
value = try pointer_value(&pointers, address)
|
||||||
}
|
}
|
||||||
.load_address, .store_address: {
|
.load_address, .store_address: {
|
||||||
@@ -604,9 +572,7 @@ execute proc(
|
|||||||
if instruction.type == .float {
|
if instruction.type == .float {
|
||||||
value = ir.Value{ type = .float, data = ir.ValueData{ real = -operand.data.real } }
|
value = ir.Value{ type = .float, data = ir.ValueData{ real = -operand.data.real } }
|
||||||
} else {
|
} else {
|
||||||
if operand.data.integer == ir.integer_min(instruction.type) {
|
if (operand.data.integer == ir.integer_min(instruction.type)) return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
|
|
||||||
}
|
|
||||||
value = ir.Value{ type = instruction.type, data = ir.ValueData{ integer = -operand.data.integer } }
|
value = ir.Value{ type = instruction.type, data = ir.ValueData{ integer = -operand.data.integer } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -638,9 +604,7 @@ execute proc(
|
|||||||
} else {
|
} else {
|
||||||
result :: checked_integer(instruction.op, left.data.integer, right.data.integer)
|
result :: checked_integer(instruction.op, left.data.integer, right.data.integer)
|
||||||
if result |result_integer| {
|
if result |result_integer| {
|
||||||
if (result_integer < ir.integer_min(instruction.type) or result_integer > i64(ir.integer_max(instruction.type))) {
|
if (result_integer < ir.integer_min(instruction.type) or result_integer > i64(ir.integer_max(instruction.type))) return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
|
||||||
return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
|
|
||||||
}
|
|
||||||
value = ir.Value{ type = instruction.type, data = ir.ValueData{ integer = result_integer } }
|
value = ir.Value{ type = instruction.type, data = ir.ValueData{ integer = result_integer } }
|
||||||
} else {
|
} else {
|
||||||
return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
|
return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
|
||||||
@@ -699,9 +663,7 @@ execute proc(
|
|||||||
value = ir.Value{ type = .bool, data = ir.ValueData{ boolean = result } }
|
value = ir.Value{ type = .bool, data = ir.ValueData{ boolean = result } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if instruction.destination != ir.no_value {
|
if (instruction.destination != ir.no_value) copy_value(module, &frames.items[frame_index].values[usize(instruction.destination)], value)
|
||||||
copy_value(module, &frames.items[frame_index].values[usize(instruction.destination)], value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -434,9 +434,7 @@ storage_size proc(module @Module, type Type, shape ArrayId) usize {
|
|||||||
|
|
||||||
#! loads a scalar or borrows an aggregate from byte cells without allocating.
|
#! loads a scalar or borrows an aggregate from byte cells without allocating.
|
||||||
read_storage proc(module @Module, type Type, shape ArrayId, cells []mut Value, raw bool) Value {
|
read_storage proc(module @Module, type Type, shape ArrayId, cells []mut Value, raw bool) Value {
|
||||||
if (aggregate(type)) {
|
if (aggregate(type)) return Value{ type = type, array_type = shape, raw = raw, data = ValueData{ elements = cells[..storage_size(module, type, shape)] } }
|
||||||
return Value{ type = type, array_type = shape, raw = raw, data = ValueData{ elements = cells[..storage_size(module, type, shape)] } }
|
|
||||||
}
|
|
||||||
bits u64 := 0
|
bits u64 := 0
|
||||||
size :: storage_size(module, type, shape)
|
size :: storage_size(module, type, shape)
|
||||||
count :: if (size > 8) usize(8) else size
|
count :: if (size > 8) usize(8) else size
|
||||||
|
|||||||
@@ -358,14 +358,10 @@ scan_ident proc(
|
|||||||
cursor := start + 1
|
cursor := start + 1
|
||||||
while (
|
while (
|
||||||
cursor < program.len
|
cursor < program.len
|
||||||
and (
|
and (is_alpha(program[cursor])
|
||||||
is_alpha(program[cursor])
|
|
||||||
or is_digit(program[cursor])
|
or is_digit(program[cursor])
|
||||||
or program[cursor] == '_'
|
or program[cursor] == '_')
|
||||||
)
|
) cursor += 1
|
||||||
) {
|
|
||||||
cursor += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
kind :: strmap.get(&keywords, program[start..cursor]) orelse .ident
|
kind :: strmap.get(&keywords, program[start..cursor]) orelse .ident
|
||||||
# member contexts accept keywords and therefore need their interned spelling too.
|
# member contexts accept keywords and therefore need their interned spelling too.
|
||||||
|
|||||||
@@ -201,9 +201,8 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
|
|||||||
.optional_check: {
|
.optional_check: {
|
||||||
operand :: try load(state, instruction.left)
|
operand :: try load(state, instruction.left)
|
||||||
failed :: fresh(state)
|
failed :: fresh(state)
|
||||||
if (state.values[usize(instruction.left)].kind == .bool) {
|
if (state.values[usize(instruction.left)].kind == .bool) try io.print(" %r{} = xor i1 %r{}, true\n", output, {failed, operand})
|
||||||
try io.print(" %r{} = xor i1 %r{}, true\n", output, {failed, operand})
|
else try io.print(" %r{} = icmp eq ptr %r{}, null\n", output, {failed, operand})
|
||||||
} else try io.print(" %r{} = icmp eq ptr %r{}, null\n", output, {failed, operand})
|
|
||||||
try check_failure(state, failed, .null_unwrap, instruction.span)
|
try check_failure(state, failed, .null_unwrap, instruction.span)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,9 +104,7 @@ emit proc(
|
|||||||
mem.set(values, Type{})
|
mem.set(values, Type{})
|
||||||
for (function.blocks.items) |block| {
|
for (function.blocks.items) |block| {
|
||||||
for (block.instructions.items) |instruction| {
|
for (block.instructions.items) |instruction| {
|
||||||
if (instruction.destination != ir.no_value) {
|
if (instruction.destination != ir.no_value) values[usize(instruction.destination)] = Type{ kind = instruction.type, shape = instruction.array_type }
|
||||||
values[usize(instruction.destination)] = Type{ kind = instruction.type, shape = instruction.array_type }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state := State{ output = output, module = module, line_starts = line_starts.items, values = values }
|
state := State{ output = output, module = module, line_starts = line_starts.items, values = values }
|
||||||
|
|||||||
+14
-39
@@ -170,9 +170,7 @@ lower_module proc(
|
|||||||
|
|
||||||
@hide:file
|
@hide:file
|
||||||
lower_type proc(state @State, type typecheck.Type) ir.Type {
|
lower_type proc(state @State, type typecheck.Type) ir.Type {
|
||||||
if (type.kind == .enumeration) {
|
if (type.kind == .enumeration) return lower_type(state, typecheck.Type{ kind = typecheck.enum_type(state.checked, type.enum_type).backing })
|
||||||
return lower_type(state, typecheck.Type{ kind = typecheck.enum_type(state.checked, type.enum_type).backing })
|
|
||||||
}
|
|
||||||
if (type.kind == .slice) return .record
|
if (type.kind == .slice) return .record
|
||||||
if (type.kind == .fallible) return .record
|
if (type.kind == .fallible) return .record
|
||||||
if (type.kind == .optional) return lower_optional_type(state, typecheck.array_type(state.checked, type.array_type).element)
|
if (type.kind == .optional) return lower_optional_type(state, typecheck.array_type(state.checked, type.array_type).element)
|
||||||
@@ -562,11 +560,9 @@ lower_cleanups proc(state @mut State, depth usize, error_value ir.ValueId) void
|
|||||||
id :: state.cleanups.items[index]
|
id :: state.cleanups.items[index]
|
||||||
if (ast.stmt_kind(state.tree, id) == .errdefer_stmt and error_value == ir.no_value) continue
|
if (ast.stmt_kind(state.tree, id) == .errdefer_stmt and error_value == ir.no_value) continue
|
||||||
cleanup :: ast.cleanup_stmt(state.tree, id)
|
cleanup :: ast.cleanup_stmt(state.tree, id)
|
||||||
if (cleanup.capture) |capture| {
|
if (cleanup.capture) |capture| _ = try emit(state, ir.Instruction{
|
||||||
_ = try emit(state, ir.Instruction{
|
|
||||||
op = .store_local, left = error_value, slot = state.storage[usize(capture)].index, span = cleanup.span,
|
op = .store_local, left = error_value, slot = state.storage[usize(capture)].index, span = cleanup.span,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
try lower_block(state, cleanup.body, true)
|
try lower_block(state, cleanup.body, true)
|
||||||
if (state.terminated) return
|
if (state.terminated) return
|
||||||
}
|
}
|
||||||
@@ -800,10 +796,8 @@ lower_statement proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | d
|
|||||||
if (
|
if (
|
||||||
ast.expr_kind(tree, assignment.target) == .index
|
ast.expr_kind(tree, assignment.target) == .index
|
||||||
or ast.expr_kind(tree, assignment.target) == .unary
|
or ast.expr_kind(tree, assignment.target) == .unary
|
||||||
or (
|
or (ast.expr_kind(tree, assignment.target) == .selection
|
||||||
ast.expr_kind(tree, assignment.target) == .selection
|
and sema.binding(state.resolution, assignment.target).kind == .none)
|
||||||
and sema.binding(state.resolution, assignment.target).kind == .none
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
value :: try lower_as(state, assignment.value, typecheck.type_of(state.checked, assignment.target))
|
value :: try lower_as(state, assignment.value, typecheck.type_of(state.checked, assignment.target))
|
||||||
if (state.terminated) return
|
if (state.terminated) return
|
||||||
@@ -865,9 +859,7 @@ lower_statement proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | d
|
|||||||
value := ir.no_value
|
value := ir.no_value
|
||||||
if (statement.value) |expression| value = try lower_as(state, expression, state.return_type)
|
if (statement.value) |expression| value = try lower_as(state, expression, state.return_type)
|
||||||
if (state.terminated or trap_type(state, id)) return
|
if (state.terminated or trap_type(state, id)) return
|
||||||
if (statement.value == null and state.return_type.kind == .fallible) {
|
if (statement.value == null and state.return_type.kind == .fallible) value = try wrap_fallible(state, value, state.return_type, false, statement.span)
|
||||||
value = try wrap_fallible(state, value, state.return_type, false, statement.span)
|
|
||||||
}
|
|
||||||
try lower_return(state, value, statement.span)
|
try lower_return(state, value, statement.span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1080,11 +1072,8 @@ lower_union proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocError |
|
|||||||
count :: ast.record_field_count(tree, id)
|
count :: ast.record_field_count(tree, id)
|
||||||
contextual := false
|
contextual := false
|
||||||
if (view.type) |annotation| contextual = ast.expr_kind(tree, annotation) == .enum_literal
|
if (view.type) |annotation| contextual = ast.expr_kind(tree, annotation) == .enum_literal
|
||||||
if (contextual and field.type == .record and (count != 1 or ast.field(tree, ast.record_field(tree, id, 0)).name != null)) {
|
if (contextual and field.type == .record and (count != 1 or ast.field(tree, ast.record_field(tree, id, 0)).name != null)) payload = try lower_record_as(state, id, typecheck.union_payload_type(state.checked, id))
|
||||||
payload = try lower_record_as(state, id, typecheck.union_payload_type(state.checked, id))
|
else if (count != 0) payload = try lower_as(state, ast.field(tree, ast.record_field(tree, id, 0)).value?, typecheck.union_payload_type(state.checked, id))
|
||||||
} else if (count != 0) {
|
|
||||||
payload = try lower_as(state, ast.field(tree, ast.record_field(tree, id, 0)).value?, typecheck.union_payload_type(state.checked, id))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (state.terminated) return ir.no_value
|
if (state.terminated) return ir.no_value
|
||||||
return try emit(state, ir.Instruction{
|
return try emit(state, ir.Instruction{
|
||||||
@@ -1826,9 +1815,7 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr
|
|||||||
if (!trap_type(state, id)) unreachable
|
if (!trap_type(state, id)) unreachable
|
||||||
}
|
}
|
||||||
.array_type, .pointer_type, .function_type, .record_type, .enum_type, .union_type, .distinct_type, .slice_type, .optional_type, .fallible_type, .sum_type: {
|
.array_type, .pointer_type, .function_type, .record_type, .enum_type, .union_type, .distinct_type, .slice_type, .optional_type, .fallible_type, .sum_type: {
|
||||||
if (!trap_type(state, id)) {
|
if (!trap_type(state, id)) trap(state, try diagnostics.add(state.diagnostics, .type_not_value, span), span)
|
||||||
trap(state, try diagnostics.add(state.diagnostics, .type_not_value, span), span)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.alias_expr: return try lower_expression(state, ast.type_operand(tree, id))
|
.alias_expr: return try lower_expression(state, ast.type_operand(tree, id))
|
||||||
.enum_literal: {
|
.enum_literal: {
|
||||||
@@ -1843,9 +1830,7 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr
|
|||||||
.builtin_call: return try lower_builtin(state, id)
|
.builtin_call: return try lower_builtin(state, id)
|
||||||
.record_literal: {
|
.record_literal: {
|
||||||
checked :: typecheck.type_of(state.checked, id)
|
checked :: typecheck.type_of(state.checked, id)
|
||||||
if (checked.kind == .record and typecheck.record_type(state.checked, checked.record_type).is_union) {
|
if (checked.kind == .record and typecheck.record_type(state.checked, checked.record_type).is_union) return try lower_union(state, id)
|
||||||
return try lower_union(state, id)
|
|
||||||
}
|
|
||||||
return try lower_record_as(state, id, checked)
|
return try lower_record_as(state, id, checked)
|
||||||
}
|
}
|
||||||
.array_literal: {
|
.array_literal: {
|
||||||
@@ -2014,9 +1999,7 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr
|
|||||||
text :: ast.literal_text(tree, expression.operand)
|
text :: ast.literal_text(tree, expression.operand)
|
||||||
magnitude_limit :: ir.integer_max(type) + 1
|
magnitude_limit :: ir.integer_max(type) + 1
|
||||||
if (integer_magnitude(text, magnitude_limit)) |magnitude| {
|
if (integer_magnitude(text, magnitude_limit)) |magnitude| {
|
||||||
if (magnitude == magnitude_limit) {
|
if (magnitude == magnitude_limit) return try constant(state, ir.Value{ type = type, data = ir.ValueData{ integer = ir.integer_min(type) } }, span)
|
||||||
return try constant(state, ir.Value{ type = type, data = ir.ValueData{ integer = ir.integer_min(type) } }, span)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
operand :: try lower_expression(state, expression.operand)
|
operand :: try lower_expression(state, expression.operand)
|
||||||
@@ -2030,9 +2013,7 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr
|
|||||||
}
|
}
|
||||||
.binary: {
|
.binary: {
|
||||||
expression :: ast.binary_expr(tree, id)
|
expression :: ast.binary_expr(tree, id)
|
||||||
if (expression.operator == .logical_and or expression.operator == .logical_or) {
|
if (expression.operator == .logical_and or expression.operator == .logical_or) return try lower_logical(state, id)
|
||||||
return try lower_logical(state, id)
|
|
||||||
}
|
|
||||||
left_type :: typecheck.type_of(state.checked, expression.left)
|
left_type :: typecheck.type_of(state.checked, expression.left)
|
||||||
right_type :: typecheck.type_of(state.checked, expression.right)
|
right_type :: typecheck.type_of(state.checked, expression.right)
|
||||||
if (
|
if (
|
||||||
@@ -2100,9 +2081,7 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr
|
|||||||
for (0..count) |i| {
|
for (0..count) |i| {
|
||||||
signature :: typecheck.type_of(state.checked, ast.call_expr(tree, id).callee).function
|
signature :: typecheck.type_of(state.checked, ast.call_expr(tree, id).callee).function
|
||||||
expected := typecheck.Type{}
|
expected := typecheck.Type{}
|
||||||
if (signature != ast.NodeId(maxval!(u32)) and i < ast.function_param_count(tree, signature)) {
|
if (signature != ast.NodeId(maxval!(u32)) and i < ast.function_param_count(tree, signature)) expected = typecheck.type_of(state.checked, ast.param(tree, ast.function_param(tree, signature, i)).type)
|
||||||
expected = typecheck.type_of(state.checked, ast.param(tree, ast.function_param(tree, signature, i)).type)
|
|
||||||
}
|
|
||||||
argument :: try lower_as(state, ast.call_arg(tree, id, i), expected)
|
argument :: try lower_as(state, ast.call_arg(tree, id, i), expected)
|
||||||
if (state.terminated) return ir.no_value
|
if (state.terminated) return ir.no_value
|
||||||
state.arguments.items[scratch_start + i] = argument
|
state.arguments.items[scratch_start + i] = argument
|
||||||
@@ -2162,13 +2141,9 @@ lower_number proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocError
|
|||||||
text :: ast.literal_text(state.tree, id)
|
text :: ast.literal_text(state.tree, id)
|
||||||
type :: lower_type(state, typecheck.type_of(state.checked, id))
|
type :: lower_type(state, typecheck.type_of(state.checked, id))
|
||||||
if (ir.integer_bits(type) != 0 and !ir.unsigned_integer(type)) {
|
if (ir.integer_bits(type) != 0 and !ir.unsigned_integer(type)) {
|
||||||
if (integer_magnitude(text, ir.integer_max(type))) |magnitude| {
|
if (integer_magnitude(text, ir.integer_max(type))) |magnitude| return try constant(state, ir.Value{ type = type, data = ir.ValueData{ integer = i64(magnitude) } }, span)
|
||||||
return try constant(state, ir.Value{ type = type, data = ir.ValueData{ integer = i64(magnitude) } }, span)
|
|
||||||
}
|
|
||||||
} else if (ir.unsigned_integer(type)) {
|
} else if (ir.unsigned_integer(type)) {
|
||||||
if (integer_magnitude(text, ir.integer_max(type))) |magnitude| {
|
if (integer_magnitude(text, ir.integer_max(type))) |magnitude| return try constant(state, ir.Value{ type = type, data = ir.ValueData{ unsigned = magnitude } }, span)
|
||||||
return try constant(state, ir.Value{ type = type, data = ir.ValueData{ unsigned = magnitude } }, span)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
value :: strconv.parse_float(state.module.allocator, text) catch |err| {
|
value :: strconv.parse_float(state.module.allocator, text) catch |err| {
|
||||||
match err {
|
match err {
|
||||||
|
|||||||
@@ -1695,11 +1695,8 @@ array_context_inference_empty_shapes_and_scalar_leaf_families test {
|
|||||||
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
||||||
defer interpreter.deinit(&outcome)
|
defer interpreter.deinit(&outcome)
|
||||||
try testing.expect(outcome.trap == null)
|
try testing.expect(outcome.trap == null)
|
||||||
if (outcome.value.type == .string) {
|
if (outcome.value.type == .string) try testing.expect(mem.eql(ir.string_bytes(&module, outcome.value.data.string), "two"))
|
||||||
try testing.expect(mem.eql(ir.string_bytes(&module, outcome.value.data.string), "two"))
|
else try testing.expect(outcome.value.data.boolean)
|
||||||
} else {
|
|
||||||
try testing.expect(outcome.value.data.boolean)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-33
@@ -277,8 +277,7 @@ parse_block proc(state @mut State) ast.NodeId ! ParseError {
|
|||||||
parse_statement proc(state @mut State, allow_else bool) ast.NodeId ! ParseError {
|
parse_statement proc(state @mut State, allow_else bool) ast.NodeId ! ParseError {
|
||||||
if (
|
if (
|
||||||
next_is(state, .ident)
|
next_is(state, .ident)
|
||||||
and (
|
and (next_n_is(state, 1, .ident)
|
||||||
next_n_is(state, 1, .ident)
|
|
||||||
or next_n_is(state, 1, .struct)
|
or next_n_is(state, 1, .struct)
|
||||||
or next_n_is(state, 1, .enum) or next_n_is(state, 1, .union)
|
or next_n_is(state, 1, .enum) or next_n_is(state, 1, .union)
|
||||||
or next_n_is(state, 1, .distinct)
|
or next_n_is(state, 1, .distinct)
|
||||||
@@ -289,11 +288,8 @@ parse_statement proc(state @mut State, allow_else bool) ast.NodeId ! ParseError
|
|||||||
or (next_n_is(state, 1, .star) and pointer_binding_starts(state))
|
or (next_n_is(state, 1, .star) and pointer_binding_starts(state))
|
||||||
or (next_n_is(state, 1, .open_bracket) and array_starts_type(state))
|
or (next_n_is(state, 1, .open_bracket) and array_starts_type(state))
|
||||||
or next_n_is(state, 1, .double_colon)
|
or next_n_is(state, 1, .double_colon)
|
||||||
or next_n_is(state, 1, .colon_equal)
|
or next_n_is(state, 1, .colon_equal))
|
||||||
)
|
) return try parse_statement_decl(state)
|
||||||
) {
|
|
||||||
return try parse_statement_decl(state)
|
|
||||||
}
|
|
||||||
match current(state).kind {
|
match current(state).kind {
|
||||||
.if: return try parse_if(state)
|
.if: return try parse_if(state)
|
||||||
.while: return try parse_while(state, allow_else)
|
.while: return try parse_while(state, allow_else)
|
||||||
@@ -343,17 +339,13 @@ parse_return proc(state @mut State, allow_else bool) ast.NodeId ! ParseError {
|
|||||||
next_is(state, .newline) or next_is(state, .close_curly) or next_is(state, .eof)
|
next_is(state, .newline) or next_is(state, .close_curly) or next_is(state, .eof)
|
||||||
or (state.match_arm_body and next_is(state, .comma))
|
or (state.match_arm_body and next_is(state, .comma))
|
||||||
or (allow_else and next_is(state, .else))
|
or (allow_else and next_is(state, .else))
|
||||||
) {
|
) return try ast.add_return_stmt(state.builder, keyword.span, null)
|
||||||
return try ast.add_return_stmt(state.builder, keyword.span, null)
|
|
||||||
}
|
|
||||||
value :: try parse_expr(state)
|
value :: try parse_expr(state)
|
||||||
if (
|
if (
|
||||||
!next_is(state, .newline) and !next_is(state, .close_curly) and !next_is(state, .eof)
|
!next_is(state, .newline) and !next_is(state, .close_curly) and !next_is(state, .eof)
|
||||||
and !(allow_else and next_is(state, .else))
|
and !(allow_else and next_is(state, .else))
|
||||||
and !(state.match_arm_body and next_is(state, .comma))
|
and !(state.match_arm_body and next_is(state, .comma))
|
||||||
) {
|
) return .unexpected_token
|
||||||
return .unexpected_token
|
|
||||||
}
|
|
||||||
# include consumed grouping punctuation, which has no separate expression node.
|
# include consumed grouping punctuation, which has no separate expression node.
|
||||||
end :: state.tokens[state.next_token - 1].span.end
|
end :: state.tokens[state.next_token - 1].span.end
|
||||||
return try ast.add_return_stmt(
|
return try ast.add_return_stmt(
|
||||||
@@ -395,9 +387,7 @@ parse_assignment proc(state @mut State, target ast.NodeId, allow_else bool) ast.
|
|||||||
and !next_is(state, .eof)
|
and !next_is(state, .eof)
|
||||||
and !(allow_else and next_is(state, .else))
|
and !(allow_else and next_is(state, .else))
|
||||||
and !(state.match_arm_body and next_is(state, .comma))
|
and !(state.match_arm_body and next_is(state, .comma))
|
||||||
) {
|
) return .unexpected_token
|
||||||
return .unexpected_token
|
|
||||||
}
|
|
||||||
end :: state.tokens[state.next_token - 1].span.end
|
end :: state.tokens[state.next_token - 1].span.end
|
||||||
return try ast.add_assignment_stmt(
|
return try ast.add_assignment_stmt(
|
||||||
state.builder,
|
state.builder,
|
||||||
@@ -1176,10 +1166,8 @@ parse_record_field proc(state @mut State, declaration bool) ast.NodeId ! ParseEr
|
|||||||
value ?ast.NodeId := null
|
value ?ast.NodeId := null
|
||||||
named :: (
|
named :: (
|
||||||
member_name(current(state).kind)
|
member_name(current(state).kind)
|
||||||
and (
|
and ((!declaration and next_n_is(state, 1, .equal))
|
||||||
(!declaration and next_n_is(state, 1, .equal))
|
or (declaration and starts_type(state.tokens[state.next_token + 1].kind)))
|
||||||
or (declaration and starts_type(state.tokens[state.next_token + 1].kind))
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if (named) {
|
if (named) {
|
||||||
token :: if (declaration) try consume(state, .ident) else try consume_member(state, false)
|
token :: if (declaration) try consume(state, .ident) else try consume_member(state, false)
|
||||||
@@ -1596,14 +1584,12 @@ pointer_binding_starts proc(state @State) bool {
|
|||||||
named_binding_starts proc(state @State) bool {
|
named_binding_starts proc(state @State) bool {
|
||||||
return (
|
return (
|
||||||
next_is(state, .ident)
|
next_is(state, .ident)
|
||||||
and (
|
and (next_n_is(state, 1, .double_colon) or next_n_is(state, 1, .colon_equal)
|
||||||
next_n_is(state, 1, .double_colon) or next_n_is(state, 1, .colon_equal)
|
|
||||||
or next_n_is(state, 1, .ident) or next_n_is(state, 1, .proc) or next_n_is(state, 1, .match)
|
or next_n_is(state, 1, .ident) or next_n_is(state, 1, .proc) or next_n_is(state, 1, .match)
|
||||||
or next_n_is(state, 1, .at)
|
or next_n_is(state, 1, .at)
|
||||||
or next_n_is(state, 1, .question)
|
or next_n_is(state, 1, .question)
|
||||||
or (next_n_is(state, 1, .open_paren) and pointer_binding_starts(state))
|
or (next_n_is(state, 1, .open_paren) and pointer_binding_starts(state))
|
||||||
or (next_n_is(state, 1, .star) and pointer_binding_starts(state))
|
or (next_n_is(state, 1, .star) and pointer_binding_starts(state)))
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1699,9 +1685,7 @@ parse_primary proc(state @mut State) ast.NodeId ! ParseError {
|
|||||||
else: {
|
else: {
|
||||||
diagnostic :: try unexpected_diagnostic(state)
|
diagnostic :: try unexpected_diagnostic(state)
|
||||||
|
|
||||||
if !is_expression_recovery_boundary(token.kind) {
|
if (!is_expression_recovery_boundary(token.kind)) state.next_token += 1
|
||||||
state.next_token += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return try ast.add_invalid_expr(state.builder, token.span, diagnostic)
|
return try ast.add_invalid_expr(state.builder, token.span, diagnostic)
|
||||||
}
|
}
|
||||||
@@ -1846,9 +1830,7 @@ recovery_closes_delimiters proc(state @State, paren_depth, square_depth usize) b
|
|||||||
.ident: {
|
.ident: {
|
||||||
if (i + 1 < state.tokens.len) {
|
if (i + 1 < state.tokens.len) {
|
||||||
next :: state.tokens[i + 1].kind
|
next :: state.tokens[i + 1].kind
|
||||||
if (next == .double_colon or next == .colon_equal or next == .ident or next == .proc) {
|
if (next == .double_colon or next == .colon_equal or next == .ident or next == .proc) return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else: {}
|
else: {}
|
||||||
@@ -1865,9 +1847,7 @@ recovery_closes_delimiters proc(state @State, paren_depth, square_depth usize) b
|
|||||||
@hide:file
|
@hide:file
|
||||||
unexpected_diagnostic proc(state @mut State) diagnostics.DiagnosticId ! (mem.AllocError | diagnostics.CapacityError) {
|
unexpected_diagnostic proc(state @mut State) diagnostics.DiagnosticId ! (mem.AllocError | diagnostics.CapacityError) {
|
||||||
token :: current(state)
|
token :: current(state)
|
||||||
if (token.kind == .invalid and token.data.diagnostic != diagnostics.no_diagnostic) {
|
if (token.kind == .invalid and token.data.diagnostic != diagnostics.no_diagnostic) return token.data.diagnostic
|
||||||
return token.data.diagnostic
|
|
||||||
}
|
|
||||||
return try diagnostics.add(state.diagnostics, .unexpected_token, token.span)
|
return try diagnostics.add(state.diagnostics, .unexpected_token, token.span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -442,11 +442,8 @@ parses_return_boundaries_and_recovers_trailing_tokens test {
|
|||||||
try testing.expect_equal(ast.StmtKind.expression, ast.stmt_kind(&tree, ast.block_statement(&tree, body, 1)))
|
try testing.expect_equal(ast.StmtKind.expression, ast.stmt_kind(&tree, ast.block_statement(&tree, body, 1)))
|
||||||
grouped :: ast.return_stmt(&tree, ast.block_statement(&tree, body, 2))
|
grouped :: ast.return_stmt(&tree, ast.block_statement(&tree, body, 2))
|
||||||
try testing.expect_equal("return (3 + 4)", ast.source_text(&tree, grouped.span))
|
try testing.expect_equal("return (3 + 4)", ast.source_text(&tree, grouped.span))
|
||||||
if (grouped.value) |value| {
|
if (grouped.value) |value| try testing.expect_equal(ast.ExprKind.binary, ast.expr_kind(&tree, value))
|
||||||
try testing.expect_equal(ast.ExprKind.binary, ast.expr_kind(&tree, value))
|
else return .expectation_failed
|
||||||
} else {
|
|
||||||
return .expectation_failed
|
|
||||||
}
|
|
||||||
try testing.expect_equal(ast.StmtKind.invalid, ast.stmt_kind(&tree, ast.block_statement(&tree, body, 3)))
|
try testing.expect_equal(ast.StmtKind.invalid, ast.stmt_kind(&tree, ast.block_statement(&tree, body, 3)))
|
||||||
after :: ast.statement_decl(&tree, ast.block_statement(&tree, body, 4))
|
after :: ast.statement_decl(&tree, ast.block_statement(&tree, body, 4))
|
||||||
try testing.expect_equal("after", ast.source_text(&tree, after.name))
|
try testing.expect_equal("after", ast.source_text(&tree, after.name))
|
||||||
@@ -1146,9 +1143,8 @@ rejects_control_tails_and_preserves_following_declarations test {
|
|||||||
}
|
}
|
||||||
conditional :: ast.if_stmt(&tree, ast.block_statement(&tree, loop.body, 4))
|
conditional :: ast.if_stmt(&tree, ast.block_statement(&tree, loop.body, 4))
|
||||||
try testing.expect_equal(ast.StmtKind.invalid, ast.stmt_kind(&tree, ast.block_statement(&tree, conditional.then_block, 0)))
|
try testing.expect_equal(ast.StmtKind.invalid, ast.stmt_kind(&tree, ast.block_statement(&tree, conditional.then_block, 0)))
|
||||||
if (conditional.else_block) |other| {
|
if (conditional.else_block) |other| try testing.expect_equal(ast.StmtKind.continue_stmt, ast.stmt_kind(&tree, ast.block_statement(&tree, other, 0)))
|
||||||
try testing.expect_equal(ast.StmtKind.continue_stmt, ast.stmt_kind(&tree, ast.block_statement(&tree, other, 0)))
|
else return .expectation_failed
|
||||||
} else return .expectation_failed
|
|
||||||
try testing.expect_equal(ast.StmtKind.declaration, ast.stmt_kind(&tree, ast.block_statement(&tree, body, 1)))
|
try testing.expect_equal(ast.StmtKind.declaration, ast.stmt_kind(&tree, ast.block_statement(&tree, body, 1)))
|
||||||
try testing.expect_equal(ast.DeclKind.statement, ast.decl_kind(&tree, ast.package_decl(&tree, 5)))
|
try testing.expect_equal(ast.DeclKind.statement, ast.decl_kind(&tree, ast.package_decl(&tree, 5)))
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-121
@@ -360,9 +360,7 @@ check_elaborated proc(
|
|||||||
if (
|
if (
|
||||||
binding.kind == .declaration and !cells[i].assignment_value
|
binding.kind == .declaration and !cells[i].assignment_value
|
||||||
and !cells[usize(binding.data.declaration)].fixed and !has_narrowing(&state, id)
|
and !cells[usize(binding.data.declaration)].fixed and !has_narrowing(&state, id)
|
||||||
) {
|
) join(&state, id, binding.data.declaration)
|
||||||
join(&state, id, binding.data.declaration)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# assignment inputs observe established declaration types, never contribute
|
# assignment inputs observe established declaration types, never contribute
|
||||||
@@ -844,10 +842,8 @@ check_annotation proc(state @mut State, id ast.NodeId, allow_void bool) Type ! (
|
|||||||
element := try check_annotation(state, view.element, true)
|
element := try check_annotation(state, view.element, true)
|
||||||
element_binding :: sema.binding(state.resolution, view.element)
|
element_binding :: sema.binding(state.resolution, view.element)
|
||||||
if (
|
if (
|
||||||
(
|
(element_binding.kind == .builtin
|
||||||
element_binding.kind == .builtin
|
and (element_binding.data.builtin == .int or element_binding.data.builtin == .float))
|
||||||
and (element_binding.data.builtin == .int or element_binding.data.builtin == .float)
|
|
||||||
)
|
|
||||||
or element.kind == .void or element.kind == .range
|
or element.kind == .void or element.kind == .range
|
||||||
) {
|
) {
|
||||||
element = invalid_type(try diagnostics.add(state.diagnostics, .invalid_array_element_type, ast.node_span(state.tree, view.element)))
|
element = invalid_type(try diagnostics.add(state.diagnostics, .invalid_array_element_type, ast.node_span(state.tree, view.element)))
|
||||||
@@ -1233,9 +1229,7 @@ collect_expression proc(state @mut State, id ast.NodeId) void ! (mem.AllocError
|
|||||||
if (
|
if (
|
||||||
role != .parameter and role != .loop_capture and ast.decl_kind(tree, target) == .statement
|
role != .parameter and role != .loop_capture and ast.decl_kind(tree, target) == .statement
|
||||||
and type_syntax(ast.expr_kind(tree, ast.statement_decl(tree, target).initializer))
|
and type_syntax(ast.expr_kind(tree, ast.statement_decl(tree, target).initializer))
|
||||||
) {
|
) state.cells[usize(id)].type = invalid_type(try diagnostics.add(state.diagnostics, .type_not_value, ast.node_span(tree, id)))
|
||||||
state.cells[usize(id)].type = invalid_type(try diagnostics.add(state.diagnostics, .type_not_value, ast.node_span(tree, id)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
match binding.kind {
|
match binding.kind {
|
||||||
.invalid: state.cells[usize(id)].type = invalid_type(binding.data.diagnostic)
|
.invalid: state.cells[usize(id)].type = invalid_type(binding.data.diagnostic)
|
||||||
@@ -1464,13 +1458,11 @@ bool_equality proc(state @mut State, id ast.NodeId) bool {
|
|||||||
right :: group_type(state, expression.right)
|
right :: group_type(state, expression.right)
|
||||||
return (
|
return (
|
||||||
(expression.operator == .equal or expression.operator == .not_equal)
|
(expression.operator == .equal or expression.operator == .not_equal)
|
||||||
and (
|
and ((left.kind == .bool and right.kind == .bool)
|
||||||
(left.kind == .bool and right.kind == .bool)
|
|
||||||
or left.kind == .enumeration or right.kind == .enumeration
|
or left.kind == .enumeration or right.kind == .enumeration
|
||||||
or left.kind == .pointer or right.kind == .pointer
|
or left.kind == .pointer or right.kind == .pointer
|
||||||
or left.kind == .optional or right.kind == .optional
|
or left.kind == .optional or right.kind == .optional
|
||||||
or left.kind == .null or right.kind == .null
|
or left.kind == .null or right.kind == .null)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1739,10 +1731,8 @@ mutable_target proc(state @mut State, id ast.NodeId, allow_global bool) bool {
|
|||||||
pointer :: state.pointers.items[usize(base.pointer_type)]
|
pointer :: state.pointers.items[usize(base.pointer_type)]
|
||||||
return (
|
return (
|
||||||
pointer.mutable
|
pointer.mutable
|
||||||
and (
|
and (pointer.many
|
||||||
pointer.many
|
or (pointer.element.kind == .array and state.arrays.items[usize(pointer.element.array_type)].mutable))
|
||||||
or (pointer.element.kind == .array and state.arrays.items[usize(pointer.element.array_type)].mutable)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (base.kind == .slice) return state.arrays.items[usize(base.array_type)].mutable
|
if (base.kind == .slice) return state.arrays.items[usize(base.array_type)].mutable
|
||||||
@@ -1950,9 +1940,7 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost
|
|||||||
} else if (
|
} else if (
|
||||||
expected.kind != .void
|
expected.kind != .void
|
||||||
and !(expected.kind == .fallible and state.arrays.items[usize(expected.array_type)].element.kind == .void)
|
and !(expected.kind == .fallible and state.arrays.items[usize(expected.array_type)].element.kind == .void)
|
||||||
) {
|
) try fail(state, id, .return_type_mismatch, statement.span)
|
||||||
try fail(state, id, .return_type_mismatch, statement.span)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.expression: {
|
.expression: {
|
||||||
match ast.expr_kind(tree, id) {
|
match ast.expr_kind(tree, id) {
|
||||||
@@ -1975,24 +1963,18 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (expression.operator == .unwrap) {
|
if (expression.operator == .unwrap) {
|
||||||
if (state.types[usize(expression.operand)].kind != .optional and state.types[usize(expression.operand)].kind != .invalid) {
|
if (state.types[usize(expression.operand)].kind != .optional and state.types[usize(expression.operand)].kind != .invalid) try fail(state, id, .invalid_operand, expression.span)
|
||||||
try fail(state, id, .invalid_operand, expression.span)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (expression.operator == .dereference) {
|
if (expression.operator == .dereference) {
|
||||||
if (
|
if (
|
||||||
state.types[usize(expression.operand)].kind != .invalid
|
state.types[usize(expression.operand)].kind != .invalid
|
||||||
and state.types[usize(expression.operand)].kind != .pointer
|
and state.types[usize(expression.operand)].kind != .pointer
|
||||||
) {
|
) try fail(state, id, .invalid_dereference, expression.span)
|
||||||
try fail(state, id, .invalid_dereference, expression.span)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
operand :: state.types[usize(expression.operand)]
|
operand :: state.types[usize(expression.operand)]
|
||||||
if (operand.kind != .invalid and (!numeric_kind(operand.kind) or unsigned_kind(operand.kind))) {
|
if (operand.kind != .invalid and (!numeric_kind(operand.kind) or unsigned_kind(operand.kind))) try fail(state, id, .invalid_operand, ast.node_span(tree, id))
|
||||||
try fail(state, id, .invalid_operand, ast.node_span(tree, id))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.binary: {
|
.binary: {
|
||||||
expression :: ast.binary_expr(tree, id)
|
expression :: ast.binary_expr(tree, id)
|
||||||
@@ -2005,9 +1987,7 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost
|
|||||||
right :: state.types[usize(expression.right)]
|
right :: state.types[usize(expression.right)]
|
||||||
if (left.kind == .invalid or right.kind == .invalid) return
|
if (left.kind == .invalid or right.kind == .invalid) return
|
||||||
if (pointer_addition(state, id)) {
|
if (pointer_addition(state, id)) {
|
||||||
if (right.kind != .usize or right.nominal != ast.NodeId(maxval!(u32))) {
|
if (right.kind != .usize or right.nominal != ast.NodeId(maxval!(u32))) try fail(state, id, .invalid_operand, expression.span)
|
||||||
try fail(state, id, .invalid_operand, expression.span)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -2019,11 +1999,8 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost
|
|||||||
and (left.kind == .bool or left.kind == .enumeration or left.kind == .pointer)
|
and (left.kind == .bool or left.kind == .enumeration or left.kind == .pointer)
|
||||||
and (assignable_type(state, left, right) or assignable_type(state, right, left))
|
and (assignable_type(state, left, right) or assignable_type(state, right, left))
|
||||||
) return
|
) return
|
||||||
if (!numeric_kind(left.kind) or !numeric_kind(right.kind) or !same_type(state, left, right)) {
|
if (!numeric_kind(left.kind) or !numeric_kind(right.kind) or !same_type(state, left, right)) try fail(state, id, .invalid_operand, expression.span)
|
||||||
try fail(state, id, .invalid_operand, expression.span)
|
else if (expression.operator == .divide and left.kind != .float) try fail(state, id, .integer_division, expression.span)
|
||||||
} else if (expression.operator == .divide and left.kind != .float) {
|
|
||||||
try fail(state, id, .integer_division, expression.span)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.range: {
|
.range: {
|
||||||
if (state.cells[usize(id)].match_pattern) return
|
if (state.cells[usize(id)].match_pattern) return
|
||||||
@@ -2032,12 +2009,8 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost
|
|||||||
end_type :: state.types[usize(expression.end)]
|
end_type :: state.types[usize(expression.end)]
|
||||||
family TypeKind :: if (integer_kind(start_type.kind)) start_type.kind
|
family TypeKind :: if (integer_kind(start_type.kind)) start_type.kind
|
||||||
else if (integer_kind(end_type.kind)) end_type.kind else .int
|
else if (integer_kind(end_type.kind)) end_type.kind else .int
|
||||||
if (start_type.kind != .invalid and (!integer_kind(start_type.kind) or start_type.kind != family)) {
|
if (start_type.kind != .invalid and (!integer_kind(start_type.kind) or start_type.kind != family)) try fail(state, expression.start, .invalid_range_bound, ast.node_span(tree, expression.start))
|
||||||
try fail(state, expression.start, .invalid_range_bound, ast.node_span(tree, expression.start))
|
if (end_type.kind != .invalid and (!integer_kind(end_type.kind) or end_type.kind != family)) try fail(state, expression.end, .invalid_range_bound, ast.node_span(tree, expression.end))
|
||||||
}
|
|
||||||
if (end_type.kind != .invalid and (!integer_kind(end_type.kind) or end_type.kind != family)) {
|
|
||||||
try fail(state, expression.end, .invalid_range_bound, ast.node_span(tree, expression.end))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.array_literal: {
|
.array_literal: {
|
||||||
actual :: state.types[usize(id)]
|
actual :: state.types[usize(id)]
|
||||||
@@ -2045,11 +2018,8 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost
|
|||||||
element :: state.arrays.items[usize(actual.array_type)].element
|
element :: state.arrays.items[usize(actual.array_type)].element
|
||||||
for 0..ast.array_element_count(tree, id) |i| {
|
for 0..ast.array_element_count(tree, id) |i| {
|
||||||
child :: ast.array_element(tree, id, i)
|
child :: ast.array_element(tree, id, i)
|
||||||
if (element.kind == .void or element.kind == .range) {
|
if (element.kind == .void or element.kind == .range) try fail(state, child, .invalid_array_element_type, ast.node_span(tree, child))
|
||||||
try fail(state, child, .invalid_array_element_type, ast.node_span(tree, child))
|
else try compatible(state, child, element)
|
||||||
} else {
|
|
||||||
try compatible(state, child, element)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (array_cells(state, actual) == null) try fail(state, id, .array_size_overflow, ast.node_span(tree, id))
|
if (array_cells(state, actual) == null) try fail(state, id, .array_size_overflow, ast.node_span(tree, id))
|
||||||
}
|
}
|
||||||
@@ -2057,9 +2027,7 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost
|
|||||||
actual :: state.types[usize(id)]
|
actual :: state.types[usize(id)]
|
||||||
if (actual.kind != .record) return
|
if (actual.kind != .record) return
|
||||||
descriptor := state.records.items[usize(actual.record_type)]
|
descriptor := state.records.items[usize(actual.record_type)]
|
||||||
if (state.variant_slots[usize(id)] != no_index and state.backings[usize(id)].kind == .record) {
|
if (state.variant_slots[usize(id)] != no_index and state.backings[usize(id)].kind == .record) descriptor = state.records.items[usize(state.backings[usize(id)].record_type)]
|
||||||
descriptor = state.records.items[usize(state.backings[usize(id)].record_type)]
|
|
||||||
}
|
|
||||||
fields :: descriptor.fields
|
fields :: descriptor.fields
|
||||||
slot :: state.slots[usize(id)]
|
slot :: state.slots[usize(id)]
|
||||||
if (slot == no_index) return
|
if (slot == no_index) return
|
||||||
@@ -2073,12 +2041,8 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost
|
|||||||
view :: ast.index_expr(tree, id)
|
view :: ast.index_expr(tree, id)
|
||||||
base :: state.types[usize(view.base)]
|
base :: state.types[usize(view.base)]
|
||||||
index :: state.types[usize(view.index)]
|
index :: state.types[usize(view.index)]
|
||||||
if (index.kind != .invalid and (index.kind != .usize or index.nominal != ast.NodeId(maxval!(u32)))) {
|
if (index.kind != .invalid and (index.kind != .usize or index.nominal != ast.NodeId(maxval!(u32)))) try fail(state, view.index, .invalid_index_type, ast.node_span(tree, view.index))
|
||||||
try fail(state, view.index, .invalid_index_type, ast.node_span(tree, view.index))
|
if (base.kind != .invalid and !indexable_type(state, base)) try fail(state, id, .not_indexable, ast.node_span(tree, view.base))
|
||||||
}
|
|
||||||
if (base.kind != .invalid and !indexable_type(state, base)) {
|
|
||||||
try fail(state, id, .not_indexable, ast.node_span(tree, view.base))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.call: try validate_call(state, id)
|
.call: try validate_call(state, id)
|
||||||
.builtin_call: _ = try infer_builtin(state, id, true)
|
.builtin_call: _ = try infer_builtin(state, id, true)
|
||||||
@@ -2116,13 +2080,9 @@ validate_call proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | dia
|
|||||||
backing :: immediate_backing(state, actual)
|
backing :: immediate_backing(state, actual)
|
||||||
if (
|
if (
|
||||||
actual.kind != .invalid
|
actual.kind != .invalid
|
||||||
and (
|
and (!numeric_kind(backing.kind) and !allowed_enum
|
||||||
!numeric_kind(backing.kind) and !allowed_enum
|
or backing.nominal != ast.NodeId(maxval!(u32)))
|
||||||
or backing.nominal != ast.NodeId(maxval!(u32))
|
) try fail(state, argument, .invalid_operand, ast.node_span(tree, argument))
|
||||||
)
|
|
||||||
) {
|
|
||||||
try fail(state, argument, .invalid_operand, ast.node_span(tree, argument))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -2283,9 +2243,7 @@ intern_pointer proc(state @mut State, descriptor PointerType) Type ! mem.AllocEr
|
|||||||
if (
|
if (
|
||||||
existing.mutable == descriptor.mutable and existing.many == descriptor.many
|
existing.mutable == descriptor.mutable and existing.many == descriptor.many
|
||||||
and same_type(state, existing.element, descriptor.element)
|
and same_type(state, existing.element, descriptor.element)
|
||||||
) {
|
) return Type{ kind = .pointer, pointer_type = PointerId(i) }
|
||||||
return Type{ kind = .pointer, pointer_type = PointerId(i) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try arraylist.append(&state.pointers, descriptor)
|
try arraylist.append(&state.pointers, descriptor)
|
||||||
return Type{ kind = .pointer, pointer_type = PointerId(state.pointers.items.len - 1) }
|
return Type{ kind = .pointer, pointer_type = PointerId(state.pointers.items.len - 1) }
|
||||||
@@ -2304,9 +2262,7 @@ check_pointer_type proc(state @mut State, id ast.NodeId) Type ! (mem.AllocError
|
|||||||
or element.kind == .type_value
|
or element.kind == .type_value
|
||||||
or has_inferred_count(state, element)
|
or has_inferred_count(state, element)
|
||||||
or (binding.kind == .builtin and (binding.data.builtin == .int or binding.data.builtin == .float))
|
or (binding.kind == .builtin and (binding.data.builtin == .int or binding.data.builtin == .float))
|
||||||
) {
|
) return invalid_type(try diagnostics.add(state.diagnostics, .invalid_pointer_type, ast.node_span(state.tree, id)))
|
||||||
return invalid_type(try diagnostics.add(state.diagnostics, .invalid_pointer_type, ast.node_span(state.tree, id)))
|
|
||||||
}
|
|
||||||
return try intern_pointer(state, PointerType{ element = element, mutable = view.mutable, many = view.many })
|
return try intern_pointer(state, PointerType{ element = element, mutable = view.mutable, many = view.many })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2346,9 +2302,7 @@ intern_array proc(state @mut State, descriptor ArrayType) Type ! mem.AllocError
|
|||||||
existing.kind == descriptor.kind and existing.len == descriptor.len and existing.mutable == descriptor.mutable
|
existing.kind == descriptor.kind and existing.len == descriptor.len and existing.mutable == descriptor.mutable
|
||||||
and same_sentinel(existing.sentinel, descriptor.sentinel) and same_type(state, existing.element, descriptor.element)
|
and same_sentinel(existing.sentinel, descriptor.sentinel) and same_type(state, existing.element, descriptor.element)
|
||||||
and same_type(state, existing.error_type, descriptor.error_type)
|
and same_type(state, existing.error_type, descriptor.error_type)
|
||||||
) {
|
) return Type{ kind = descriptor.kind, array_type = ArrayId(i) }
|
||||||
return Type{ kind = descriptor.kind, array_type = ArrayId(i) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try arraylist.append(&state.arrays, descriptor)
|
try arraylist.append(&state.arrays, descriptor)
|
||||||
return Type{ kind = descriptor.kind, array_type = ArrayId(state.arrays.items.len - 1) }
|
return Type{ kind = descriptor.kind, array_type = ArrayId(state.arrays.items.len - 1) }
|
||||||
@@ -3074,9 +3028,7 @@ apply_contexts proc(state @mut State, assignment_values, early bool) void ! (mem
|
|||||||
if (
|
if (
|
||||||
ast.call_arg_count(tree, id) == 1
|
ast.call_arg_count(tree, id) == 1
|
||||||
and (backing.nominal != ast.NodeId(maxval!(u32)) or !numeric_kind(backing.kind))
|
and (backing.nominal != ast.NodeId(maxval!(u32)) or !numeric_kind(backing.kind))
|
||||||
) {
|
) try context_demand(state, ast.call_arg(tree, id, 0), backing, .type_mismatch, early)
|
||||||
try context_demand(state, ast.call_arg(tree, id, 0), backing, .type_mismatch, early)
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (conversion_kind(state, id) != .none) {
|
if (conversion_kind(state, id) != .none) {
|
||||||
@@ -3165,9 +3117,7 @@ prepare_ranges proc(state @mut State, assignment_values, constrain bool) void !
|
|||||||
if (
|
if (
|
||||||
binding.kind == .declaration and state.cells[usize(binding.data.declaration)].role == .loop_capture
|
binding.kind == .declaration and state.cells[usize(binding.data.declaration)].role == .loop_capture
|
||||||
and !has_narrowing(state, id)
|
and !has_narrowing(state, id)
|
||||||
) {
|
) seed(state, id, group_type(state, binding.data.declaration))
|
||||||
seed(state, id, group_type(state, binding.data.declaration))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3230,9 +3180,7 @@ specialize_annotations proc(state @mut State) void ! (mem.AllocError | diagnosti
|
|||||||
if (
|
if (
|
||||||
binding.kind == .declaration and state.cells[usize(binding.data.declaration)].fixed
|
binding.kind == .declaration and state.cells[usize(binding.data.declaration)].fixed
|
||||||
and !has_narrowing(state, id)
|
and !has_narrowing(state, id)
|
||||||
) {
|
) seed(state, id, state.cells[usize(binding.data.declaration)].type)
|
||||||
seed(state, id, state.cells[usize(binding.data.declaration)].type)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3742,9 +3690,7 @@ check_union proc(state @mut State, id ast.NodeId, nominal bool) Type ! (mem.Allo
|
|||||||
if (
|
if (
|
||||||
type.kind == .none or type.kind == .range or type.kind == .type_value or field.value != null
|
type.kind == .none or type.kind == .range or type.kind == .type_value or field.value != null
|
||||||
or (type.kind == .void and tag.kind == .none and !view.auto_tag)
|
or (type.kind == .void and tag.kind == .none and !view.auto_tag)
|
||||||
) {
|
) return invalid_type(try diagnostics.add(state.diagnostics, .invalid_record_field_type, field.span))
|
||||||
return invalid_type(try diagnostics.add(state.diagnostics, .invalid_record_field_type, field.span))
|
|
||||||
}
|
|
||||||
if (field.name == null or named_field(state.tree, fields[0..i], field.name?) != no_index) {
|
if (field.name == null or named_field(state.tree, fields[0..i], field.name?) != no_index) {
|
||||||
return invalid_type(try diagnostics.add(state.diagnostics, .duplicate_field, field.span))
|
return invalid_type(try diagnostics.add(state.diagnostics, .duplicate_field, field.span))
|
||||||
}
|
}
|
||||||
@@ -4201,21 +4147,13 @@ validate_match proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | di
|
|||||||
current :: try pattern_interval(state, pattern, key)
|
current :: try pattern_interval(state, pattern, key)
|
||||||
if (current) |interval| {
|
if (current) |interval| {
|
||||||
if (
|
if (
|
||||||
(
|
(interval.real and (
|
||||||
interval.real and (
|
|
||||||
interval.real_low > interval.real_high
|
interval.real_low > interval.real_high
|
||||||
or (!interval.inclusive and interval.real_low == interval.real_high)
|
or (!interval.inclusive and interval.real_low == interval.real_high)))
|
||||||
)
|
or (!interval.real and (
|
||||||
)
|
|
||||||
or (
|
|
||||||
!interval.real and (
|
|
||||||
constant_order(interval.low, interval.high) > 0
|
constant_order(interval.low, interval.high) > 0
|
||||||
or (!interval.inclusive and constant_order(interval.low, interval.high) == 0)
|
or (!interval.inclusive and constant_order(interval.low, interval.high) == 0)))
|
||||||
)
|
) try fail(state, id, .invalid_match_pattern, ast.node_span(state.tree, pattern))
|
||||||
)
|
|
||||||
) {
|
|
||||||
try fail(state, id, .invalid_match_pattern, ast.node_span(state.tree, pattern))
|
|
||||||
}
|
|
||||||
if (key.kind == .bool) {
|
if (key.kind == .bool) {
|
||||||
if (interval.low.magnitude == 0) seen_false = true else seen_true = true
|
if (interval.low.magnitude == 0) seen_false = true else seen_true = true
|
||||||
}
|
}
|
||||||
@@ -4348,20 +4286,14 @@ check_fallible_type proc(state @mut State, id ast.NodeId) Type ! (mem.AllocError
|
|||||||
if (failure.kind == .invalid) return failure
|
if (failure.kind == .invalid) return failure
|
||||||
valid_error :: (
|
valid_error :: (
|
||||||
failure.kind == .enumeration
|
failure.kind == .enumeration
|
||||||
or (
|
or (failure.kind == .record
|
||||||
failure.kind == .record
|
and (!state.records.items[usize(failure.record_type)].is_union
|
||||||
and (
|
or state.records.items[usize(failure.record_type)].tag_type.kind == .enumeration))
|
||||||
!state.records.items[usize(failure.record_type)].is_union
|
|
||||||
or state.records.items[usize(failure.record_type)].tag_type.kind == .enumeration
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
!valid_error or success.kind == .none or success.kind == .range or success.kind == .type_value
|
!valid_error or success.kind == .none or success.kind == .range or success.kind == .type_value
|
||||||
or success.kind == .anyopaque or has_inferred_count(state, success)
|
or success.kind == .anyopaque or has_inferred_count(state, success)
|
||||||
) {
|
) return invalid_type(try diagnostics.add(state.diagnostics, .invalid_fallible_type, ast.node_span(state.tree, id)))
|
||||||
return invalid_type(try diagnostics.add(state.diagnostics, .invalid_fallible_type, ast.node_span(state.tree, id)))
|
|
||||||
}
|
|
||||||
type :: try intern_array(state, ArrayType{ kind = .fallible, element = success, error_type = failure })
|
type :: try intern_array(state, ArrayType{ kind = .fallible, element = success, error_type = failure })
|
||||||
state.cells[usize(id)].type = type
|
state.cells[usize(id)].type = type
|
||||||
return type
|
return type
|
||||||
@@ -4536,14 +4468,10 @@ validate_fallible_expression proc(state @mut State, id ast.NodeId) void ! (mem.A
|
|||||||
if (catching) {
|
if (catching) {
|
||||||
expression :: ast.catch_expr(state.tree, id)
|
expression :: ast.catch_expr(state.tree, id)
|
||||||
if (expression.handler_is_block) {
|
if (expression.handler_is_block) {
|
||||||
if (descriptor.element.kind != .void and block_falls_through(state, expression.handler)) {
|
if (descriptor.element.kind != .void and block_falls_through(state, expression.handler)) try fail(state, expression.handler, .catch_type_mismatch, ast.node_span(state.tree, expression.handler))
|
||||||
try fail(state, expression.handler, .catch_type_mismatch, ast.node_span(state.tree, expression.handler))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
actual :: state.types[usize(expression.handler)]
|
actual :: state.types[usize(expression.handler)]
|
||||||
if (actual.kind != .invalid and !assignable_value(state, expression.handler, actual, descriptor.element)) {
|
if (actual.kind != .invalid and !assignable_value(state, expression.handler, actual, descriptor.element)) try fail(state, expression.handler, .catch_type_mismatch, ast.node_span(state.tree, expression.handler))
|
||||||
try fail(state, expression.handler, .catch_type_mismatch, ast.node_span(state.tree, expression.handler))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -4558,18 +4486,15 @@ validate_fallible_expression proc(state @mut State, id ast.NodeId) void ! (mem.A
|
|||||||
}
|
}
|
||||||
result :: state.types[usize(annotation)]
|
result :: state.types[usize(annotation)]
|
||||||
if (result.kind == .invalid) return
|
if (result.kind == .invalid) return
|
||||||
if (result.kind != .fallible) {
|
if (result.kind != .fallible) try fail(state, id, .try_outside_fallible, ast.node_span(state.tree, id))
|
||||||
try fail(state, id, .try_outside_fallible, ast.node_span(state.tree, id))
|
else if (
|
||||||
} else if (
|
|
||||||
!error_subset(
|
!error_subset(
|
||||||
state.records.items,
|
state.records.items,
|
||||||
state.enums.items,
|
state.enums.items,
|
||||||
descriptor.error_type,
|
descriptor.error_type,
|
||||||
state.arrays.items[usize(result.array_type)].error_type,
|
state.arrays.items[usize(result.array_type)].error_type,
|
||||||
)
|
)
|
||||||
) {
|
) try fail(state, id, .incompatible_propagated_error, ast.node_span(state.tree, id))
|
||||||
try fail(state, id, .incompatible_propagated_error, ast.node_span(state.tree, id))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@hide:file
|
@hide:file
|
||||||
|
|||||||
@@ -168,11 +168,8 @@ rejects_fixed_family_conversion_integer_division_and_conflicting_demands test {
|
|||||||
for conflicts |declaration| {
|
for conflicts |declaration| {
|
||||||
try testing.expect_equal(TypeKind.invalid, type_of(&result, declaration).kind)
|
try testing.expect_equal(TypeKind.invalid, type_of(&result, declaration).kind)
|
||||||
diagnostic :: type_of(&result, declaration).diagnostic
|
diagnostic :: type_of(&result, declaration).diagnostic
|
||||||
if (diagnostics.get(&diagnostic_store, diagnostic)) |error| {
|
if (diagnostics.get(&diagnostic_store, diagnostic)) |error| try testing.expect_equal(diagnostics.Code.type_mismatch, error.code)
|
||||||
try testing.expect_equal(diagnostics.Code.type_mismatch, error.code)
|
else return .expectation_failed
|
||||||
} else {
|
|
||||||
return .expectation_failed
|
|
||||||
}
|
|
||||||
try testing.expect_equal(diagnostic, type_of(&result, ast.statement_decl(&tree, declaration).initializer).diagnostic)
|
try testing.expect_equal(diagnostic, type_of(&result, ast.statement_decl(&tree, declaration).initializer).diagnostic)
|
||||||
}
|
}
|
||||||
conflict_uses [4]usize :: [8, 9, 11, 12]
|
conflict_uses [4]usize :: [8, 9, 11, 12]
|
||||||
@@ -294,11 +291,8 @@ separates_type_annotations_from_values_and_restricts_void_storage test {
|
|||||||
defer deinit(&result)
|
defer deinit(&result)
|
||||||
|
|
||||||
bad :: ast.statement_decl(&tree, ast.package_decl(&tree, 1))
|
bad :: ast.statement_decl(&tree, ast.package_decl(&tree, 1))
|
||||||
if (bad.type) |annotation| {
|
if (bad.type) |annotation| _ = try expect_error(&result, &diagnostic_store, annotation, .expected_type, ast.node_span(&tree, annotation))
|
||||||
_ = try expect_error(&result, &diagnostic_store, annotation, .expected_type, ast.node_span(&tree, annotation))
|
else return .expectation_failed
|
||||||
} else {
|
|
||||||
return .expectation_failed
|
|
||||||
}
|
|
||||||
_ = try expect_error(&result, &diagnostic_store, bad.initializer, .invalid_operand, ast.node_span(&tree, bad.initializer))
|
_ = try expect_error(&result, &diagnostic_store, bad.initializer, .invalid_operand, ast.node_span(&tree, bad.initializer))
|
||||||
builtin :: ast.statement_decl(&tree, ast.package_decl(&tree, 2)).initializer
|
builtin :: ast.statement_decl(&tree, ast.package_decl(&tree, 2)).initializer
|
||||||
_ = try expect_error(&result, &diagnostic_store, builtin, .type_not_value, ast.node_span(&tree, builtin))
|
_ = try expect_error(&result, &diagnostic_store, builtin, .type_not_value, ast.node_span(&tree, builtin))
|
||||||
@@ -322,11 +316,8 @@ separates_type_annotations_from_values_and_restricts_void_storage test {
|
|||||||
try testing.expect_equal(void_error, type_of(&result, void_b).diagnostic)
|
try testing.expect_equal(void_error, type_of(&result, void_b).diagnostic)
|
||||||
try expect_kind(&result, ast.function_decl(&tree, void_function).return_type, .void)
|
try expect_kind(&result, ast.function_decl(&tree, void_function).return_type, .void)
|
||||||
storage :: ast.statement_decl(&tree, ast.package_decl(&tree, 5))
|
storage :: ast.statement_decl(&tree, ast.package_decl(&tree, 5))
|
||||||
if (storage.type) |annotation| {
|
if (storage.type) |annotation| _ = try expect_error(&result, &diagnostic_store, annotation, .invalid_void_type, ast.node_span(&tree, annotation))
|
||||||
_ = try expect_error(&result, &diagnostic_store, annotation, .invalid_void_type, ast.node_span(&tree, annotation))
|
else return .expectation_failed
|
||||||
} else {
|
|
||||||
return .expectation_failed
|
|
||||||
}
|
|
||||||
holder :: ast.statement_decl(&tree, ast.package_decl(&tree, 8)).initializer
|
holder :: ast.statement_decl(&tree, ast.package_decl(&tree, 8)).initializer
|
||||||
_ = try expect_error(&result, &diagnostic_store, holder, .type_mismatch, ast.node_span(&tree, holder))
|
_ = try expect_error(&result, &diagnostic_store, holder, .type_mismatch, ast.node_span(&tree, holder))
|
||||||
operand :: ast.statement_decl(&tree, ast.package_decl(&tree, 9)).initializer
|
operand :: ast.statement_decl(&tree, ast.package_decl(&tree, 9)).initializer
|
||||||
@@ -677,11 +668,8 @@ returns_supply_numeric_context_and_resolve_forward_local_and_parameter_names tes
|
|||||||
}
|
}
|
||||||
identity :: ast.package_decl(&tree, 1)
|
identity :: ast.package_decl(&tree, 1)
|
||||||
identity_body :: ast.function_decl(&tree, identity).body
|
identity_body :: ast.function_decl(&tree, identity).body
|
||||||
if (ast.return_stmt(&tree, ast.block_statement(&tree, identity_body, 0)).value) |value| {
|
if (ast.return_stmt(&tree, ast.block_statement(&tree, identity_body, 0)).value) |value| try testing.expect_equal(ast.function_param(&tree, identity, 0), sema.binding(&resolution, value).data.declaration)
|
||||||
try testing.expect_equal(ast.function_param(&tree, identity, 0), sema.binding(&resolution, value).data.declaration)
|
else return .expectation_failed
|
||||||
} else {
|
|
||||||
return .expectation_failed
|
|
||||||
}
|
|
||||||
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1429,11 +1417,8 @@ logical_operand_errors_are_independent_and_skipped_rhs_preserves_bool test {
|
|||||||
try expect_kind(&result, loop.condition, .bool)
|
try expect_kind(&result, loop.condition, .bool)
|
||||||
returned :: ast.block_statement(&tree, body, 6)
|
returned :: ast.block_statement(&tree, body, 6)
|
||||||
try expect_kind(&result, returned, .void)
|
try expect_kind(&result, returned, .void)
|
||||||
if (ast.return_stmt(&tree, returned).value) |value| {
|
if (ast.return_stmt(&tree, returned).value) |value| try expect_kind(&result, value, .bool)
|
||||||
try expect_kind(&result, value, .bool)
|
else return .expectation_failed
|
||||||
} else {
|
|
||||||
return .expectation_failed
|
|
||||||
}
|
|
||||||
try testing.expect_equal(7, code_count(&diagnostic_store, .unknown_name))
|
try testing.expect_equal(7, code_count(&diagnostic_store, .unknown_name))
|
||||||
try testing.expect_equal(8, code_count(&diagnostic_store, .invalid_operand))
|
try testing.expect_equal(8, code_count(&diagnostic_store, .invalid_operand))
|
||||||
try testing.expect_equal(15, diagnostics.count(&diagnostic_store))
|
try testing.expect_equal(15, diagnostics.count(&diagnostic_store))
|
||||||
@@ -2271,9 +2256,7 @@ nested_array_numeric_context_flows_through_index_children_before_defaults test {
|
|||||||
for usize(1)..usize(4) |i| {
|
for usize(1)..usize(4) |i| {
|
||||||
element_kind TypeKind :: if (i == 2) .float else .array
|
element_kind TypeKind :: if (i == 2) .float else .array
|
||||||
type :: try expect_array(result, ast.package_decl(tree, i), 2, false, element_kind)
|
type :: try expect_array(result, ast.package_decl(tree, i), 2, false, element_kind)
|
||||||
if (type.element.kind == .array) {
|
if (type.element.kind == .array) try testing.expect_equal(TypeKind.float, array_type(result, type.element.array_type).element.kind)
|
||||||
try testing.expect_equal(TypeKind.float, array_type(result, type.element.array_type).element.kind)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
matrix :: ast.statement_decl(tree, ast.package_decl(tree, 1)).initializer
|
matrix :: ast.statement_decl(tree, ast.package_decl(tree, 1)).initializer
|
||||||
for 0..ast.array_element_count(tree, matrix) |i| {
|
for 0..ast.array_element_count(tree, matrix) |i| {
|
||||||
|
|||||||
+6
-18
@@ -349,9 +349,7 @@ resolve_function proc(
|
|||||||
for (0..ast.function_param_count(tree, id)) |i| {
|
for (0..ast.function_param_count(tree, id)) |i| {
|
||||||
parameter :: ast.function_param(tree, id, i)
|
parameter :: ast.function_param(tree, id, i)
|
||||||
try resolve_expr(state, &signature, ast.param(tree, parameter).type)
|
try resolve_expr(state, &signature, ast.param(tree, parameter).type)
|
||||||
if (ast.param(tree, parameter).comptime) {
|
if (ast.param(tree, parameter).comptime) try predeclare(state, &signature, parameter, ast.param(tree, parameter).name)
|
||||||
try predeclare(state, &signature, parameter, ast.param(tree, parameter).name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try resolve_expr(state, &signature, function.return_type)
|
try resolve_expr(state, &signature, function.return_type)
|
||||||
scope := Scope{
|
scope := Scope{
|
||||||
@@ -381,9 +379,7 @@ resolve_block proc(state @mut State, scope @mut Scope, id ast.NodeId) void ! (me
|
|||||||
tree :: state.tree
|
tree :: state.tree
|
||||||
for (0..ast.block_statement_count(tree, id)) |i| {
|
for (0..ast.block_statement_count(tree, id)) |i| {
|
||||||
statement :: ast.block_statement(tree, id, i)
|
statement :: ast.block_statement(tree, id, i)
|
||||||
if ast.stmt_kind(tree, statement) == .declaration {
|
if (ast.stmt_kind(tree, statement) == .declaration) try predeclare(state, scope, statement, ast.statement_decl(tree, statement).name)
|
||||||
try predeclare(state, scope, statement, ast.statement_decl(tree, statement).name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (0..ast.block_statement_count(tree, id)) |i| {
|
for (0..ast.block_statement_count(tree, id)) |i| {
|
||||||
statement :: ast.block_statement(tree, id, i)
|
statement :: ast.block_statement(tree, id, i)
|
||||||
@@ -423,12 +419,8 @@ resolve_block proc(state @mut State, scope @mut Scope, id ast.NodeId) void ! (me
|
|||||||
parent = scope,
|
parent = scope,
|
||||||
}
|
}
|
||||||
defer hashmap.deinit(&body_scope.names)
|
defer hashmap.deinit(&body_scope.names)
|
||||||
if (loop.capture) |capture| {
|
if (loop.capture) |capture| try predeclare(state, &body_scope, capture, ast.node_span(tree, capture))
|
||||||
try predeclare(state, &body_scope, capture, ast.node_span(tree, capture))
|
if (loop.index) |index| try predeclare(state, &body_scope, index, ast.node_span(tree, index))
|
||||||
}
|
|
||||||
if (loop.index) |index| {
|
|
||||||
try predeclare(state, &body_scope, index, ast.node_span(tree, index))
|
|
||||||
}
|
|
||||||
try resolve_block(state, &body_scope, loop.body)
|
try resolve_block(state, &body_scope, loop.body)
|
||||||
}
|
}
|
||||||
.invalid: resolve_invalid(state, statement)
|
.invalid: resolve_invalid(state, statement)
|
||||||
@@ -451,9 +443,7 @@ resolve_statement_decl proc(
|
|||||||
id ast.NodeId,
|
id ast.NodeId,
|
||||||
) void ! (mem.AllocError | diagnostics.CapacityError) {
|
) void ! (mem.AllocError | diagnostics.CapacityError) {
|
||||||
declaration :: ast.statement_decl(state.tree, id)
|
declaration :: ast.statement_decl(state.tree, id)
|
||||||
if (ast.expr_kind(state.tree, declaration.initializer) == .alias_expr) {
|
if (ast.expr_kind(state.tree, declaration.initializer) == .alias_expr) state.aliases[usize(id)] = ast.type_operand(state.tree, declaration.initializer)
|
||||||
state.aliases[usize(id)] = ast.type_operand(state.tree, declaration.initializer)
|
|
||||||
}
|
|
||||||
if (declaration.type) |type| try resolve_expr(state, scope, type)
|
if (declaration.type) |type| try resolve_expr(state, scope, type)
|
||||||
try resolve_expr(state, scope, declaration.initializer)
|
try resolve_expr(state, scope, declaration.initializer)
|
||||||
}
|
}
|
||||||
@@ -562,9 +552,7 @@ resolve_expr proc(
|
|||||||
try resolve_expr(state, scope, expression.operand)
|
try resolve_expr(state, scope, expression.operand)
|
||||||
handler_scope := Scope{ names = hashmap.init(state.allocator), parent = scope }
|
handler_scope := Scope{ names = hashmap.init(state.allocator), parent = scope }
|
||||||
defer hashmap.deinit(&handler_scope.names)
|
defer hashmap.deinit(&handler_scope.names)
|
||||||
if (expression.capture) |capture| {
|
if (expression.capture) |capture| try predeclare(state, &handler_scope, capture, ast.node_span(tree, capture))
|
||||||
try predeclare(state, &handler_scope, capture, ast.node_span(tree, capture))
|
|
||||||
}
|
|
||||||
if (expression.handler_is_block) try resolve_block(state, &handler_scope, expression.handler)
|
if (expression.handler_is_block) try resolve_block(state, &handler_scope, expression.handler)
|
||||||
else try resolve_expr(state, &handler_scope, expression.handler)
|
else try resolve_expr(state, &handler_scope, expression.handler)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -581,9 +581,8 @@ range_captures_preserve_duplicate_builtin_and_discard_errors test {
|
|||||||
} else return .expectation_failed
|
} else return .expectation_failed
|
||||||
}
|
}
|
||||||
indexed :: ast.for_stmt(&tree, ast.block_statement(&tree, body, 3))
|
indexed :: ast.for_stmt(&tree, ast.block_statement(&tree, body, 3))
|
||||||
if (indexed.index) |index| {
|
if (indexed.index) |index| try testing.expect_equal(BindingKind.invalid, binding(&resolution, index).kind)
|
||||||
try testing.expect_equal(BindingKind.invalid, binding(&resolution, index).kind)
|
else return .expectation_failed
|
||||||
} else return .expectation_failed
|
|
||||||
if (indexed.capture) |capture| {
|
if (indexed.capture) |capture| {
|
||||||
reference :: ast.statement_expr(&tree, ast.block_statement(&tree, indexed.body, 0))
|
reference :: ast.statement_expr(&tree, ast.block_statement(&tree, indexed.body, 0))
|
||||||
try testing.expect_equal(capture, binding(&resolution, reference).data.declaration)
|
try testing.expect_equal(capture, binding(&resolution, reference).data.declaration)
|
||||||
|
|||||||
@@ -528,11 +528,8 @@ specialize_call proc(state @mut State, call, function ast.NodeId) void ! Error {
|
|||||||
}
|
}
|
||||||
callee :: try reference(state, call, target)
|
callee :: try reference(state, call, target)
|
||||||
replacement := no_node
|
replacement := no_node
|
||||||
if (state.instances.items[instance].type != no_node) {
|
if (state.instances.items[instance].type != no_node) replacement = try ast.add_type_operand(state.builder, ast.node_span(&state.tree, call), callee, true)
|
||||||
replacement = try ast.add_type_operand(state.builder, ast.node_span(&state.tree, call), callee, true)
|
else replacement = try ast.add_call(state.builder, ast.node_span(&state.tree, call), callee, runtime_arguments.items)
|
||||||
} else {
|
|
||||||
replacement = try ast.add_call(state.builder, ast.node_span(&state.tree, call), callee, runtime_arguments.items)
|
|
||||||
}
|
|
||||||
try replace(state, call, replacement)
|
try replace(state, call, replacement)
|
||||||
try refresh(state)
|
try refresh(state)
|
||||||
}
|
}
|
||||||
@@ -1554,13 +1551,10 @@ evaluate proc(state @mut State, id ast.NodeId) Value ! Error {
|
|||||||
.unary: {
|
.unary: {
|
||||||
view :: ast.unary_expr(&state.tree, id)
|
view :: ast.unary_expr(&state.tree, id)
|
||||||
value := try evaluate(state, view.operand)
|
value := try evaluate(state, view.operand)
|
||||||
if (view.operator == .negate and value.kind == .integer) {
|
if (view.operator == .negate and value.kind == .integer) value.negative = value.magnitude != 0 and !value.negative
|
||||||
value.negative = value.magnitude != 0 and !value.negative
|
else if (view.operator == .negate and value.kind == .real) value.magnitude = value.magnitude xor (u64(1) << 63)
|
||||||
} else if (view.operator == .negate and value.kind == .real) {
|
else if (view.operator == .logical_not and value.kind == .boolean) value.boolean = !value.boolean
|
||||||
value.magnitude = value.magnitude xor (u64(1) << 63)
|
else return Value{}
|
||||||
} else if (view.operator == .logical_not and value.kind == .boolean) {
|
|
||||||
value.boolean = !value.boolean
|
|
||||||
} else return Value{}
|
|
||||||
value.node = id
|
value.node = id
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
@@ -1642,9 +1636,7 @@ evaluate_binary proc(state @mut State, id ast.NodeId) Value ! Error {
|
|||||||
if (left.magnitude > maxval!(u64) - right.magnitude) return Value{}
|
if (left.magnitude > maxval!(u64) - right.magnitude) return Value{}
|
||||||
return try integer_value(state, id, left.magnitude + right.magnitude, left.negative, annotation)
|
return try integer_value(state, id, left.magnitude + right.magnitude, left.negative, annotation)
|
||||||
}
|
}
|
||||||
if (left.magnitude < right.magnitude) {
|
if (left.magnitude < right.magnitude) return try integer_value(state, id, right.magnitude - left.magnitude, right.negative, annotation)
|
||||||
return try integer_value(state, id, right.magnitude - left.magnitude, right.negative, annotation)
|
|
||||||
}
|
|
||||||
return try integer_value(state, id, left.magnitude - right.magnitude,
|
return try integer_value(state, id, left.magnitude - right.magnitude,
|
||||||
left.magnitude != right.magnitude and left.negative, annotation)
|
left.magnitude != right.magnitude and left.negative, annotation)
|
||||||
}
|
}
|
||||||
@@ -1666,9 +1658,7 @@ same_type proc(state @mut State, left, right ast.NodeId) bool ! Error {
|
|||||||
if (a == b) return true
|
if (a == b) return true
|
||||||
x :: binding(state, a)
|
x :: binding(state, a)
|
||||||
y :: binding(state, b)
|
y :: binding(state, b)
|
||||||
if (x.kind == .builtin or y.kind == .builtin) {
|
if (x.kind == .builtin or y.kind == .builtin) return x.kind == .builtin and y.kind == .builtin and builtin_identity(x.data.builtin) == builtin_identity(y.data.builtin)
|
||||||
return x.kind == .builtin and y.kind == .builtin and builtin_identity(x.data.builtin) == builtin_identity(y.data.builtin)
|
|
||||||
}
|
|
||||||
kind :: ast.expr_kind(&state.tree, a)
|
kind :: ast.expr_kind(&state.tree, a)
|
||||||
if (kind == .sum_type or ast.expr_kind(&state.tree, b) == .sum_type)
|
if (kind == .sum_type or ast.expr_kind(&state.tree, b) == .sum_type)
|
||||||
return try type_subset(state, a, b) and try type_subset(state, b, a)
|
return try type_subset(state, a, b) and try type_subset(state, b, a)
|
||||||
@@ -1908,9 +1898,7 @@ expression_type proc(state @mut State, id ast.NodeId, depth usize) ast.NodeId !
|
|||||||
callee :: ast.call_expr(&state.tree, id).callee
|
callee :: ast.call_expr(&state.tree, id).callee
|
||||||
destination :: binding(state, callee)
|
destination :: binding(state, callee)
|
||||||
if (destination.kind == .builtin) return callee
|
if (destination.kind == .builtin) return callee
|
||||||
if (destination.kind == .declaration and ast.node_class(&state.tree, destination.data.declaration) == .function) {
|
if (destination.kind == .declaration and ast.node_class(&state.tree, destination.data.declaration) == .function) return try canonical_type(state, ast.function_decl(&state.tree, destination.data.declaration).return_type)
|
||||||
return try canonical_type(state, ast.function_decl(&state.tree, destination.data.declaration).return_type)
|
|
||||||
}
|
|
||||||
signature :: try expression_type(state, callee, depth + 1)
|
signature :: try expression_type(state, callee, depth + 1)
|
||||||
if (signature != no_node and ast.expr_kind(&state.tree, signature) == .function_type)
|
if (signature != no_node and ast.expr_kind(&state.tree, signature) == .function_type)
|
||||||
return try canonical_type(state, ast.callable_result(&state.tree, signature))
|
return try canonical_type(state, ast.callable_result(&state.tree, signature))
|
||||||
|
|||||||
@@ -38,15 +38,10 @@ reserve proc(
|
|||||||
new_capacity := 8
|
new_capacity := 8
|
||||||
if list.capacity >= 8 {
|
if list.capacity >= 8 {
|
||||||
half :: divtrunc!(list.capacity, 2)
|
half :: divtrunc!(list.capacity, 2)
|
||||||
if list.capacity > maxval!(usize) - half {
|
if (list.capacity > maxval!(usize) - half) new_capacity = min_capacity
|
||||||
new_capacity = min_capacity
|
else new_capacity = list.capacity + half
|
||||||
} else {
|
|
||||||
new_capacity = list.capacity + half
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if new_capacity < min_capacity {
|
|
||||||
new_capacity = min_capacity
|
|
||||||
}
|
}
|
||||||
|
if (new_capacity < min_capacity) new_capacity = min_capacity
|
||||||
|
|
||||||
length :: list.items.len
|
length :: list.items.len
|
||||||
allocation :: list.items.ptr[..list.capacity]
|
allocation :: list.items.ptr[..list.capacity]
|
||||||
@@ -60,9 +55,7 @@ reserve proc(
|
|||||||
|
|
||||||
append proc($T type, list @mut ArrayList(T), value T) void ! mem.AllocError {
|
append proc($T type, list @mut ArrayList(T), value T) void ! mem.AllocError {
|
||||||
length :: list.items.len
|
length :: list.items.len
|
||||||
if length == maxval!(usize) {
|
if (length == maxval!(usize)) return .out_of_memory
|
||||||
return .out_of_memory
|
|
||||||
}
|
|
||||||
try reserve(list, length + 1)
|
try reserve(list, length + 1)
|
||||||
list.items = list.items.ptr[..length + 1]
|
list.items = list.items.ptr[..length + 1]
|
||||||
list.items[length] = value
|
list.items[length] = value
|
||||||
|
|||||||
+5
-13
@@ -71,11 +71,8 @@ get proc(
|
|||||||
if (map.count == 0) return null
|
if (map.count == 0) return null
|
||||||
|
|
||||||
hash usize := 0
|
hash usize := 0
|
||||||
if $(hash_key == null) {
|
if ($(hash_key == null)) hash = normalize(auto_hash(K, key))
|
||||||
hash = normalize(auto_hash(K, key))
|
else hash = normalize(call_hash(K, hash_key?, key))
|
||||||
} else {
|
|
||||||
hash = normalize(call_hash(K, hash_key?, key))
|
|
||||||
}
|
|
||||||
idx := hash & (map.entries.len - 1)
|
idx := hash & (map.entries.len - 1)
|
||||||
|
|
||||||
while true {
|
while true {
|
||||||
@@ -114,9 +111,7 @@ put proc(
|
|||||||
if (entry.hash == 0) continue
|
if (entry.hash == 0) continue
|
||||||
|
|
||||||
idx := entry.hash & (new_entries.len - 1)
|
idx := entry.hash & (new_entries.len - 1)
|
||||||
while new_entries[idx].hash != 0 {
|
while (new_entries[idx].hash != 0) idx = (idx + 1) & (new_entries.len - 1)
|
||||||
idx = (idx + 1) & (new_entries.len - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
new_entries[idx] = entry
|
new_entries[idx] = entry
|
||||||
}
|
}
|
||||||
@@ -126,11 +121,8 @@ put proc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
hash usize := 0
|
hash usize := 0
|
||||||
if $(hash_key == null) {
|
if ($(hash_key == null)) hash = normalize(auto_hash(K, key))
|
||||||
hash = normalize(auto_hash(K, key))
|
else hash = normalize(call_hash(K, hash_key?, key))
|
||||||
} else {
|
|
||||||
hash = normalize(call_hash(K, hash_key?, key))
|
|
||||||
}
|
|
||||||
idx := hash & (map.entries.len - 1)
|
idx := hash & (map.entries.len - 1)
|
||||||
|
|
||||||
while true {
|
while true {
|
||||||
|
|||||||
+6
-18
@@ -269,9 +269,7 @@ parse_format proc($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
|||||||
while cursor < format.len {
|
while cursor < format.len {
|
||||||
byte :: format[cursor]
|
byte :: format[cursor]
|
||||||
if byte == '{' {
|
if byte == '{' {
|
||||||
if cursor + 1 >= format.len {
|
if (cursor + 1 >= format.len) compile_error!("io.print format has an unmatched '{'")
|
||||||
compile_error!("io.print format has an unmatched '{'")
|
|
||||||
}
|
|
||||||
if cursor > literal_start {
|
if cursor > literal_start {
|
||||||
tokens[token_count] = FormatToken{
|
tokens[token_count] = FormatToken{
|
||||||
kind = .literal,
|
kind = .literal,
|
||||||
@@ -298,9 +296,7 @@ parse_format proc($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
|||||||
kind FormatTokenKind := .default
|
kind FormatTokenKind := .default
|
||||||
width := 2
|
width := 2
|
||||||
if next != '}' {
|
if next != '}' {
|
||||||
if cursor + 2 >= format.len or format[cursor + 2] != '}' {
|
if (cursor + 2 >= format.len or format[cursor + 2] != '}') compile_error!("io.print format expects a one-character specifier")
|
||||||
compile_error!("io.print format expects a one-character specifier")
|
|
||||||
}
|
|
||||||
|
|
||||||
width = 3
|
width = 3
|
||||||
if (next == 's') kind = .string
|
if (next == 's') kind = .string
|
||||||
@@ -314,9 +310,7 @@ parse_format proc($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
|||||||
else compile_error!("io.print format has an unknown specifier")
|
else compile_error!("io.print format has an unknown specifier")
|
||||||
}
|
}
|
||||||
|
|
||||||
if argument_count >= field_count {
|
if (argument_count >= field_count) compile_error!("io.print format argument count does not match the tuple")
|
||||||
compile_error!("io.print format argument count does not match the tuple")
|
|
||||||
}
|
|
||||||
|
|
||||||
tokens[token_count] = FormatToken{
|
tokens[token_count] = FormatToken{
|
||||||
kind = kind,
|
kind = kind,
|
||||||
@@ -333,9 +327,7 @@ parse_format proc($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if byte == '}' {
|
if byte == '}' {
|
||||||
if cursor + 1 >= format.len or format[cursor + 1] != '}' {
|
if (cursor + 1 >= format.len or format[cursor + 1] != '}') compile_error!("io.print format has an unmatched '}'")
|
||||||
compile_error!("io.print format has an unmatched '}'")
|
|
||||||
}
|
|
||||||
if cursor > literal_start {
|
if cursor > literal_start {
|
||||||
tokens[token_count] = FormatToken{
|
tokens[token_count] = FormatToken{
|
||||||
kind = .literal,
|
kind = .literal,
|
||||||
@@ -368,9 +360,7 @@ parse_format proc($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if argument_count != field_count {
|
if (argument_count != field_count) compile_error!("io.print format argument count does not match the tuple")
|
||||||
compile_error!("io.print format argument count does not match the tuple")
|
|
||||||
}
|
|
||||||
return tokens
|
return tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,9 +456,7 @@ write_decimal proc($T type, output Writer, value T) void ! WriteError {
|
|||||||
write_character proc($T type, output Writer, value T) void ! WriteError {
|
write_character proc($T type, output Writer, value T) void ! WriteError {
|
||||||
match typeinfo!(T) {
|
match typeinfo!(T) {
|
||||||
.integer: {
|
.integer: {
|
||||||
if minval!(T) < 0 or maxval!(T) > 255 {
|
if (minval!(T) < 0 or maxval!(T) > 255) compile_error!("io.print '{c}' requires an unsigned integer that fits in u8")
|
||||||
compile_error!("io.print '{c}' requires an unsigned integer that fits in u8")
|
|
||||||
}
|
|
||||||
buffer [1]u8 :: [u8(value)]
|
buffer [1]u8 :: [u8(value)]
|
||||||
try write_all(output, buffer[..])
|
try write_all(output, buffer[..])
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-6
@@ -70,9 +70,7 @@ alloc proc($T type, allocator Allocator, count usize) []mut T ! AllocError {
|
|||||||
element_size :: sizeof!(T)
|
element_size :: sizeof!(T)
|
||||||
if (element_size == 0) return empty_slice(T, count)
|
if (element_size == 0) return empty_slice(T, count)
|
||||||
|
|
||||||
if count > divtrunc!(maxval!(usize), element_size) {
|
if (count > divtrunc!(maxval!(usize), element_size)) return .out_of_memory
|
||||||
return .out_of_memory
|
|
||||||
}
|
|
||||||
|
|
||||||
memory :: raw_alloc(allocator, count * element_size, alignof!(T))
|
memory :: raw_alloc(allocator, count * element_size, alignof!(T))
|
||||||
if memory |bytes| {
|
if memory |bytes| {
|
||||||
@@ -194,9 +192,7 @@ c_realloc proc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if memory |old_memory| {
|
if memory |old_memory| {
|
||||||
if alignment <= malloc_alignment {
|
if (alignment <= malloc_alignment) return ptrcast!(c.realloc(old_memory, c_ulong(new_size)))
|
||||||
return ptrcast!(c.realloc(old_memory, c_ulong(new_size)))
|
|
||||||
}
|
|
||||||
|
|
||||||
new_memory :: c_alloc(null, new_size, alignment)
|
new_memory :: c_alloc(null, new_size, alignment)
|
||||||
if new_memory |new_bytes| {
|
if new_memory |new_bytes| {
|
||||||
|
|||||||
@@ -58,9 +58,7 @@ parse_float proc(allocator mem.Allocator, text []u8) f64 ! (mem.AllocError | Par
|
|||||||
magnitude >= u64(9218868437227405312)
|
magnitude >= u64(9218868437227405312)
|
||||||
or (magnitude == 0 and nonzero)
|
or (magnitude == 0 and nonzero)
|
||||||
or (range_error and magnitude >= u64(4607182418800017408))
|
or (range_error and magnitude >= u64(4607182418800017408))
|
||||||
) {
|
) return .out_of_range
|
||||||
return .out_of_range
|
|
||||||
}
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,23 +18,17 @@ Pair proc($V type) type {
|
|||||||
#! initializes a static string map from a list of key-value pairs (constructed at compile-time).
|
#! initializes a static string map from a list of key-value pairs (constructed at compile-time).
|
||||||
#! returned views use compile-time storage and require no cleanup.
|
#! returned views use compile-time storage and require no cleanup.
|
||||||
init proc($V type, $N usize, $entries [N]Pair(V)) StaticStringMap(V) {
|
init proc($V type, $N usize, $entries [N]Pair(V)) StaticStringMap(V) {
|
||||||
if N > usize(maxval!(u32)) {
|
if (N > usize(maxval!(u32))) compile_error!("static string map has too many entries")
|
||||||
compile_error!("static string map has too many entries")
|
|
||||||
}
|
|
||||||
|
|
||||||
keys [N]mut []u8 := undefined
|
keys [N]mut []u8 := undefined
|
||||||
values [N]mut V := undefined
|
values [N]mut V := undefined
|
||||||
|
|
||||||
# assert no duplicate keys
|
# assert no duplicate keys
|
||||||
for entries |entry, i| {
|
for entries |entry, i| {
|
||||||
if entry.0.len > usize(maxval!(u32)) {
|
if (entry.0.len > usize(maxval!(u32))) compile_error!("static string map key is too long")
|
||||||
compile_error!("static string map key is too long")
|
|
||||||
}
|
|
||||||
|
|
||||||
for (0..i) |prior| {
|
for (0..i) |prior| {
|
||||||
if mem.eql(u8, entry.0, entries[prior].0) {
|
if mem.eql(u8, entry.0, entries[prior].0) compile_error!("duplicate static string map key")
|
||||||
compile_error!("duplicate static string map key")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keys[i] = entry.0
|
keys[i] = entry.0
|
||||||
|
|||||||
Reference in New Issue
Block a user