From 84e3ed0cc8af432929c518240a53cf23878696f9 Mon Sep 17 00:00:00 2001 From: hl-valdemar Date: Tue, 27 Oct 2026 11:07:31 +0100 Subject: [PATCH] style: align layout and ownership documentation --- source/ast/ast.hon | 4 +- source/compilation/compilation.hon | 21 +- source/interpreter/interpreter.hon | 1 + source/ir/ir.hon | 3 + source/lexer/scan.hon | 2 +- source/llvm/llvm.hon | 9 +- source/loader/loader.hon | 32 ++- source/lower/lower.hon | 45 ++- source/parser/parse.hon | 17 +- source/sema/check/check.hon | 378 +++++++++++++++++--------- source/sema/specialize/specialize.hon | 121 ++++++--- std/fs/fs.hon | 18 +- std/mem/mem.hon | 7 +- std/process/process.hon | 8 +- std/strconv/strconv.hon | 4 +- std/strmap/strmap.hon | 6 +- 16 files changed, 459 insertions(+), 217 deletions(-) diff --git a/source/ast/ast.hon b/source/ast/ast.hon index 5ec5d9d..230d8f5 100644 --- a/source/ast/ast.hon +++ b/source/ast/ast.hon @@ -426,7 +426,7 @@ set_source proc( try arraylist.append(&builder.storage.sources, diagnostics.Source{ path = path, - text = text + text = text, }) builder.source = text builder.source_id = id @@ -446,7 +446,7 @@ remove_source proc(builder @mut Builder) void { builder.source = builder.storage.sources.items[usize(builder.source_id)].text } -#! borrows builder storage; refresh after builder mutation and never pass this view to deinit. +#! borrows `builder` storage; refresh after builder mutation and never pass this view to deinit. view proc(builder @Builder, root NodeId) Tree { return Tree{ storage = builder.storage, root = root } } diff --git a/source/compilation/compilation.hon b/source/compilation/compilation.hon index ade7fd9..c313e92 100644 --- a/source/compilation/compilation.hon +++ b/source/compilation/compilation.hon @@ -102,7 +102,7 @@ add_package proc(compilation @mut Compilation) PackageId ! mem.AllocError { } #! copies `path`, scans/parses into the shared arena and takes `bytes` only on success. -#! failure leaves bytes caller-owned and rolls back source diagnostics; interned names may remain. +#! failure leaves `bytes` caller-owned and rolls back source diagnostics; interned names may remain. add_source proc( compilation @mut Compilation, package PackageId, @@ -329,6 +329,7 @@ package_root proc(compilation @mut Compilation, package PackageId) ast.NodeId ! #! checks every package in a separate scope and lowers one module with root-only entry selection. #! returned IR borrows no frontend data; release it with ir.deinit. +#! temporary compilation storage uses the retained allocator and is released before returning. compile proc( compilation @mut Compilation, root_package PackageId, @@ -357,12 +358,16 @@ compile proc( name := strpool.no_str failure ?diagnostics.DiagnosticId := null for (diagnostic_store.list.items) |diagnostic, index| { - if (diagnostic.span.source == imported.path.source + if ( + diagnostic.span.source == imported.path.source and diagnostic.span.start == imported.path.start and diagnostic.span.end == imported.path.end - and (diagnostic.code == .package_unavailable + and ( + diagnostic.code == .package_unavailable or diagnostic.code == .invalid_import_path - or diagnostic.code == .import_cycle)) { + or diagnostic.code == .import_cycle + ) + ) { failure = diagnostics.DiagnosticId(index) break } @@ -379,8 +384,12 @@ compile proc( candidate :: path[start..] valid := candidate.len > 0 for (candidate) |byte, index| { - if (!(byte >= 'a' and byte <= 'z') and !(byte >= 'A' and byte <= 'Z') - and byte != '_' and !(index > 0 and byte >= '0' and byte <= '9')) valid = false + if ( + !(byte >= 'a' and byte <= 'z') + and !(byte >= 'A' and byte <= 'Z') + and byte != '_' + and !(index > 0 and byte >= '0' and byte <= '9') + ) valid = false } if (valid) { name = try strpool.intern(&compilation.strings, candidate) diff --git a/source/interpreter/interpreter.hon b/source/interpreter/interpreter.hon index 0732fd4..67b5e7c 100644 --- a/source/interpreter/interpreter.hon +++ b/source/interpreter/interpreter.hon @@ -93,6 +93,7 @@ run proc( #! executes an isolated compile-time module with bounded work and stack depth. #! ownership and diagnostic identities follow run. +#! temporary execution storage uses `allocator` and is released before returning. run_evaluation proc( allocator mem.Allocator, module @ir.Module, diff --git a/source/ir/ir.hon b/source/ir/ir.hon index 1ea6706..558d729 100644 --- a/source/ir/ir.hon +++ b/source/ir/ir.hon @@ -254,6 +254,7 @@ Module :: struct { entry_diagnostic diagnostics.DiagnosticId = diagnostics.no_diagnostic } +#! retains `allocator` for executable storage; release the returned module with deinit. init proc(allocator mem.Allocator) Module { return Module{ allocator = allocator, @@ -264,6 +265,7 @@ init proc(allocator mem.Allocator) Module { } } +#! retains `allocator` in its lists; transfer the function to a module using the same allocator for cleanup with deinit. init_function proc(allocator mem.Allocator) Function { return Function{ parameters = arraylist.init(allocator), @@ -273,6 +275,7 @@ init_function proc(allocator mem.Allocator) Function { } } +#! retains `allocator` in its lists; transfer the block to a module function for cleanup with deinit. init_block proc(allocator mem.Allocator) Block { return Block{ instructions = arraylist.init(allocator), diff --git a/source/lexer/scan.hon b/source/lexer/scan.hon index 5c16554..a210b53 100644 --- a/source/lexer/scan.hon +++ b/source/lexer/scan.hon @@ -287,7 +287,7 @@ scan proc( try add_token(state, Token{ span = make_span(source, cursor, cursor + 2), kind = value, - }) + }) cursor += 2 continue } diff --git a/source/llvm/llvm.hon b/source/llvm/llvm.hon index 39962c2..adfc5aa 100644 --- a/source/llvm/llvm.hon +++ b/source/llvm/llvm.hon @@ -91,8 +91,13 @@ emit proc( for (module.functions.items[..index]) |previous| { if (mem.eql(previous.external_name, function.external_name)) duplicate = true } - if (duplicate or mem.eql(function.external_name, "write") or mem.eql(function.external_name, "__error") - or mem.eql(function.external_name, "snprintf") or mem.eql(function.external_name, "exit")) continue + if ( + duplicate + or mem.eql(function.external_name, "write") + or mem.eql(function.external_name, "__error") + or mem.eql(function.external_name, "snprintf") + or mem.eql(function.external_name, "exit") + ) continue } values :: try mem.alloc(Type, allocator, function.value_count) defer mem.free(allocator, values) diff --git a/source/loader/loader.hon b/source/loader/loader.hon index 795312d..92cd1f9 100644 --- a/source/loader/loader.hon +++ b/source/loader/loader.hon @@ -13,6 +13,7 @@ Error :: alias ( | io.ReadError ) +#! returns caller-owned storage; release it with mem.free using the same allocator. @hide:file copy proc(allocator mem.Allocator, text []u8) []mut u8 ! mem.AllocError { bytes :: try mem.alloc(u8, allocator, text.len) @@ -21,6 +22,7 @@ copy proc(allocator mem.Allocator, text []u8) []mut u8 ! mem.AllocError { } #! returns an owned canonical package directory for either a file or directory input. +#! free the returned slice with mem.free using the same allocator; temporary storage is released before returning. directory proc(allocator mem.Allocator, path []u8) []mut u8 ! Error { resolved :: try fs.canonical(allocator, path) errdefer mem.free(allocator, resolved) @@ -34,11 +36,14 @@ directory proc(allocator mem.Allocator, path []u8) []mut u8 ! Error { return parent } +#! returns a caller-owned joined path; release it with mem.free using the same allocator. @hide:file join proc(allocator mem.Allocator, base, name []u8) []mut u8 ! mem.AllocError { separator :: if (base.len == 1 and base[0] == '/') usize(0) else usize(1) - if (base.len > maxval!(usize) - separator or name.len > maxval!(usize) - base.len - separator) - return .out_of_memory + if ( + base.len > maxval!(usize) - separator + or name.len > maxval!(usize) - base.len - separator + ) return .out_of_memory bytes :: try mem.alloc(u8, allocator, base.len + separator + name.len) memcopy!(bytes[..base.len], base) @@ -55,12 +60,15 @@ exists proc(allocator mem.Allocator, base, name []u8) bool ! Error { } #! finds the nearest ancestor build.hon/build.bro, otherwise uses the supplied directory. +#! free the returned slice with mem.free using the same allocator; temporary search storage is released before returning. project_root proc(allocator mem.Allocator, package_dir []u8) []mut u8 ! Error { end := package_dir.len while true { base :: package_dir[..end] - if (try exists(allocator, base, "build.hon") or try exists(allocator, base, "build.bro")) - return try copy(allocator, base) + if ( + try exists(allocator, base, "build.hon") + or try exists(allocator, base, "build.bro") + ) return try copy(allocator, base) if (end == 1) break while (end > 1 and package_dir[end - 1] != '/') end -= 1 @@ -70,9 +78,12 @@ project_root proc(allocator mem.Allocator, package_dir []u8) []mut u8 ! Error { } #! relative imports start at the importing package; @ imports start at the project root. +#! free the returned slice with mem.free using the same allocator; temporary path storage is released before returning. resolve proc(allocator mem.Allocator, root_dir, package_dir, import_path []u8) []mut u8 ! Error { if (import_path.len == 0 or import_path[0] == '/') return .invalid_path - for (import_path) |byte| if (byte == 0) return .invalid_path + for (import_path) |byte| { + if (byte == 0) return .invalid_path + } base := package_dir path := import_path if (path[0] == '@') { @@ -99,7 +110,8 @@ before proc(left, right []u8) bool { return left.len < right.len } -#! lists production sources in bytewise order; caller frees every path and the list. +#! lists production sources in bytewise order; free each path with mem.free using the same allocator. +#! release the list with arraylist.deinit, which uses its retained allocator; temporary directory storage is released before returning. files proc(allocator mem.Allocator, package_dir []u8) arraylist.ArrayList([]u8) ! Error { handle := try fs.open_directory(allocator, package_dir) closing := false @@ -116,8 +128,11 @@ files proc(allocator mem.Allocator, package_dir []u8) arraylist.ArrayList([]u8) and entry.kind != .unknown ) continue name :: entry.name - if ((!ends_with(name, ".hon") and !ends_with(name, ".bro")) - or ends_with(name, ".test.hon") or ends_with(name, ".test.bro")) continue + if ( + (!ends_with(name, ".hon") and !ends_with(name, ".bro")) + or ends_with(name, ".test.hon") + or ends_with(name, ".test.bro") + ) continue path :: try join(allocator, package_dir, name) errdefer mem.free(allocator, path) if (entry.kind != .file and try fs.kind(allocator, path) != .file) { @@ -157,6 +172,7 @@ sift proc(items []mut []u8, start, count usize) void { } #! the compiler limits source size to its u32 span address space; storage remains caller-owned. +#! release the returned list with arraylist.deinit, which uses its retained allocator. read_source proc(allocator mem.Allocator, runtime io.Io, path []u8) arraylist.ArrayList(u8) ! Error { return fs.read_file(allocator, runtime, path, usize(maxval!(u32))) catch |err| { match err { diff --git a/source/lower/lower.hon b/source/lower/lower.hon index b92df5d..a847db4 100644 --- a/source/lower/lower.hon +++ b/source/lower/lower.hon @@ -47,6 +47,7 @@ State :: struct { #! lowers checked source into caller-owned executable storage; release with ir.deinit. #! no frontend storage or source bytes are retained by the returned module. +#! retains `allocator` in the module; temporary lowering storage is released before returning. lower proc( allocator mem.Allocator, tree @ast.Tree, @@ -65,6 +66,7 @@ lower proc( } #! lowers the module arena, selecting an entry only from `root_package`. +#! retains `allocator` in the returned module; release it with ir.deinit; temporary lowering storage is released before returning. lower_package proc( allocator mem.Allocator, tree @ast.Tree, @@ -78,6 +80,7 @@ lower_package proc( #! lowers an isolated compile-time call wrapper without applying program entry-name rules. #! the caller supplies a checked parameterless function and owns the returned IR. +#! retains `allocator` in the returned module; release it with ir.deinit; temporary lowering storage is released before returning. lower_evaluation proc( allocator mem.Allocator, tree @ast.Tree, @@ -392,7 +395,9 @@ lower_global proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diag state.module.functions.items[state.function].result_array_type = global.array_type if (trap_binding(state, id)) return declaration :: ast.statement_decl(state.tree, id) - if (declaration.type) |annotation| if (trap_type(state, annotation)) return + if (declaration.type) |annotation| { + if (trap_type(state, annotation)) return + } value :: try lower_as(state, declaration.initializer, typecheck.type_of(state.checked, id)) if (state.terminated or trap_type(state, id)) return finish(state, value, declaration.span) @@ -792,10 +797,14 @@ lower_statement proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | d } .assignment_stmt: { assignment :: ast.assignment_stmt(tree, id) - if (ast.expr_kind(tree, assignment.target) == .index + if ( + ast.expr_kind(tree, assignment.target) == .index or ast.expr_kind(tree, assignment.target) == .unary - or (ast.expr_kind(tree, assignment.target) == .selection - and sema.binding(state.resolution, assignment.target).kind == .none)) { + or ( + ast.expr_kind(tree, assignment.target) == .selection + and sema.binding(state.resolution, assignment.target).kind == .none + ) + ) { value :: try lower_as(state, assignment.value, typecheck.type_of(state.checked, assignment.target)) if (state.terminated) return if (!is_place(state, assignment.target)) { @@ -837,7 +846,9 @@ lower_statement proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | d if (ast.expr_kind(tree, ast.statement_decl(tree, id).initializer) == .alias_expr) return if (trap_binding(state, id)) return declaration :: ast.statement_decl(tree, id) - if (declaration.type) |annotation| if (trap_type(state, annotation)) return + if (declaration.type) |annotation| { + if (trap_type(state, annotation)) return + } value :: try lower_as(state, declaration.initializer, typecheck.type_of(state.checked, id)) if (state.terminated or trap_type(state, id)) return _ = try emit(state, ir.Instruction{ @@ -1393,8 +1404,10 @@ convert_value proc(state @mut State, value ir.ValueId, actual, expected typechec length :: try usize_constant(state, typecheck.array_type(state.checked, actual.array_type).len, span) return try record_pair(state, try array_shape(state, expected), pointer, length, span) } - if (!typecheck.error_assignable(state.checked, actual, expected) - and !typecheck.error_assignable(state.checked, expected, actual)) return value + if ( + !typecheck.error_assignable(state.checked, actual, expected) + and !typecheck.error_assignable(state.checked, expected, actual) + ) return value source_union := false if (actual.kind == .record) source_union = typecheck.record_type(state.checked, actual.record_type).is_union if (expected.kind == .enumeration) { @@ -1701,8 +1714,10 @@ lower_place proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocError | if (state.terminated or trap_type(state, id)) return ir.no_value return try pointer_address(state, pointer, checked, span) } - if (ast.expr_kind(state.tree, id) == .selection - and sema.binding(state.resolution, id).kind == .none) { + if ( + ast.expr_kind(state.tree, id) == .selection + and sema.binding(state.resolution, id).kind == .none + ) { expression :: ast.selection_expr(state.tree, id) base_type :: typecheck.type_of(state.checked, expression.base) base := ir.no_value @@ -1892,8 +1907,10 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr return try lower_string(state, id) } .identifier, .selection: { - if (ast.expr_kind(tree, id) == .selection - and sema.binding(state.resolution, id).kind == .none) { + if ( + ast.expr_kind(tree, id) == .selection + and sema.binding(state.resolution, id).kind == .none + ) { selection :: ast.selection_expr(tree, id) base_type :: typecheck.type_of(state.checked, selection.base) if (base_type.kind == .slice or base_type.kind == .string or base_type.kind == .array) { @@ -2018,8 +2035,10 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr } left_type :: typecheck.type_of(state.checked, expression.left) right_type :: typecheck.type_of(state.checked, expression.right) - if ((expression.operator == .equal or expression.operator == .not_equal) - and (left_type.kind == .null or right_type.kind == .null)) { + if ( + (expression.operator == .equal or expression.operator == .not_equal) + and (left_type.kind == .null or right_type.kind == .null) + ) { optional_id :: if (left_type.kind == .null) expression.right else expression.left value :: try lower_expression(state, optional_id) if (state.terminated or trap_type(state, id)) return ir.no_value diff --git a/source/parser/parse.hon b/source/parser/parse.hon index b3ea0f2..209ce59 100644 --- a/source/parser/parse.hon +++ b/source/parser/parse.hon @@ -1174,9 +1174,12 @@ parse_record_field proc(state @mut State, declaration bool) ast.NodeId ! ParseEr name ?ast.NodeId := null type ?ast.NodeId := null value ?ast.NodeId := null - named :: member_name(current(state).kind) and ( - (!declaration and next_n_is(state, 1, .equal)) - or (declaration and starts_type(state.tokens[state.next_token + 1].kind)) + named :: ( + member_name(current(state).kind) + and ( + (!declaration and next_n_is(state, 1, .equal)) + or (declaration and starts_type(state.tokens[state.next_token + 1].kind)) + ) ) if (named) { token :: if (declaration) try consume(state, .ident) else try consume_member(state, false) @@ -1901,9 +1904,11 @@ consume proc(state @mut State, kind lexer.TokenKind) lexer.Token ! SyntaxError { @hide:file consume_either proc(state @mut State, kinds []lexer.TokenKind) lexer.Token ! SyntaxError { token :: current(state) - for (kinds) |kind| if token.kind == kind { - state.next_token += 1 - return token + for (kinds) |kind| { + if token.kind == kind { + state.next_token += 1 + return token + } } return .unexpected_token } diff --git a/source/sema/check/check.hon b/source/sema/check/check.hon index 6f3a151..78e1ee1 100644 --- a/source/sema/check/check.hon +++ b/source/sema/check/check.hon @@ -227,7 +227,7 @@ State :: struct { pointer_depth usize = 0 } -#! borrows resolution and diagnostics during checking; Result retains the AST borrow for signature comparisons. +#! borrows `resolution` and `diagnostic_store` during checking; Result retains the AST borrow for signature comparisons. #! temporary constraints are freed on every exit; Result owns types, aggregate descriptors, initializer mappings, and fallthrough obligations. check proc( allocator mem.Allocator, @@ -322,7 +322,7 @@ check_elaborated proc( try collect_declaration(&state, constraint) } else try collect_expression(&state, constraint) } - # Preserve binding errors before RHS errors propagate. Indexed writability + # preserve binding errors before RHS errors propagate. indexed writability # waits for shapes; neither check poisons the target's type. for 0..count |i| { if (cells[i].role != .assignment_stmt) continue @@ -357,8 +357,10 @@ check_elaborated proc( if (cells[i].role != .expression or !declaration_reference(tree, id)) continue if (cells[i].type.kind == .invalid) continue binding :: sema.binding(resolution, id) - if (binding.kind == .declaration and !cells[i].assignment_value - and !cells[usize(binding.data.declaration)].fixed and !has_narrowing(&state, id)) { + if ( + binding.kind == .declaration and !cells[i].assignment_value + and !cells[usize(binding.data.declaration)].fixed and !has_narrowing(&state, id) + ) { join(&state, id, binding.data.declaration) } } @@ -371,7 +373,8 @@ check_elaborated proc( if (assignment_values) { for (0..count) |i| { id :: ast.NodeId(i) - if (!cells[i].assignment_value + if ( + !cells[i].assignment_value or cells[i].role != .expression or !declaration_reference(tree, id) ) continue @@ -380,7 +383,7 @@ check_elaborated proc( if (binding.kind == .declaration) cells[i].type = types[usize(binding.data.declaration)] } } - # Calls use the signature result before contextual literal inference. + # calls use the signature result before contextual literal inference. try prepare_optional_captures(&state, false) for (0..count) |i| { id :: ast.NodeId(i) @@ -840,9 +843,13 @@ check_annotation proc(state @mut State, id ast.NodeId, allow_void bool) Type ! ( view :: ast.array_type(state.tree, id) element := try check_annotation(state, view.element, true) element_binding :: sema.binding(state.resolution, view.element) - if ((element_binding.kind == .builtin - and (element_binding.data.builtin == .int or element_binding.data.builtin == .float)) - or element.kind == .void or element.kind == .range) { + if ( + ( + element_binding.kind == .builtin + and (element_binding.data.builtin == .int or element_binding.data.builtin == .float) + ) + 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))) state.types[usize(view.element)] = element state.cells[usize(view.element)].type = element @@ -920,9 +927,11 @@ collect_declaration proc(state @mut State, id ast.NodeId) void ! (mem.AllocError state.cells[usize(id)].type = invalid_type(binding.data.diagnostic) } try collect_expression(state, declaration.initializer) - if (type_syntax(ast.expr_kind(state.tree, declaration.initializer)) + if ( + type_syntax(ast.expr_kind(state.tree, declaration.initializer)) and state.cells[usize(id)].type.kind != .invalid - and state.cells[usize(declaration.initializer)].type.kind != .none) { + and state.cells[usize(declaration.initializer)].type.kind != .none + ) { state.cells[usize(id)].fixed = true state.cells[usize(id)].type = state.cells[usize(declaration.initializer)].type } @@ -1208,8 +1217,10 @@ collect_expression proc(state @mut State, id ast.NodeId) void ! (mem.AllocError base :: ast.selection_expr(tree, id).base if (type_reference(state, base)) { checked :: try check_annotation(state, base, true) - if (checked.kind != .invalid - and (checked.kind != .enumeration or checked.nominal != ast.NodeId(maxval!(u32)))) { + if ( + checked.kind != .invalid + and (checked.kind != .enumeration or checked.nominal != ast.NodeId(maxval!(u32))) + ) { try fail(state, base, .type_not_value, ast.node_span(tree, base)) state.cells[usize(base)].type = state.types[usize(base)] } @@ -1219,8 +1230,10 @@ collect_expression proc(state @mut State, id ast.NodeId) void ! (mem.AllocError if (binding.kind == .declaration) { target :: binding.data.declaration role :: state.cells[usize(target)].role - if (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))) { + if ( + 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)) + ) { state.cells[usize(id)].type = invalid_type(try diagnostics.add(state.diagnostics, .type_not_value, ast.node_span(tree, id))) } } @@ -1451,11 +1464,13 @@ bool_equality proc(state @mut State, id ast.NodeId) bool { right :: group_type(state, expression.right) return ( (expression.operator == .equal or expression.operator == .not_equal) - and ((left.kind == .bool and right.kind == .bool) + and ( + (left.kind == .bool and right.kind == .bool) or left.kind == .enumeration or right.kind == .enumeration or left.kind == .pointer or right.kind == .pointer or left.kind == .optional or right.kind == .optional - or left.kind == .null or right.kind == .null) + or left.kind == .null or right.kind == .null + ) ) } @@ -1534,8 +1549,10 @@ demand proc(state @mut State, id ast.NodeId, expected Type, code diagnostics.Cod if (expected.kind == .fallible) { descriptor :: state.arrays.items[usize(expected.array_type)] actual := group_type(state, id) - if (state.cells[usize(id)].role == .expression and declaration_reference(state.tree, id) - and has_narrowing(state, id)) actual = try infer_shape(state, id, false) + if ( + state.cells[usize(id)].role == .expression and declaration_reference(state.tree, id) + and has_narrowing(state, id) + ) actual = try infer_shape(state, id, false) if (actual.kind == .fallible) return target := descriptor.element literal :: state.cells[index].literal @@ -1547,16 +1564,24 @@ demand proc(state @mut State, id ast.NodeId, expected Type, code diagnostics.Cod if (ast.record_literal(state.tree, literal).type) |annotation| { if (ast.expr_kind(state.tree, annotation) == .enum_literal) name = ast.enum_literal(state.tree, annotation) } - if (name == ast.NodeId(maxval!(u32)) and actual.kind == .none + if ( + name == ast.NodeId(maxval!(u32)) and actual.kind == .none and descriptor.element.kind != .record and descriptor.error_type.kind == .record - and !state.records.items[usize(descriptor.error_type.record_type)].is_union) target = descriptor.error_type + and !state.records.items[usize(descriptor.error_type.record_type)].is_union + ) target = descriptor.error_type } - if (name != ast.NodeId(maxval!(u32)) and type_has_variant(state, descriptor.error_type, name) - and !type_has_variant(state, descriptor.element, name)) target = descriptor.error_type - else if (actual.kind != .none and !assignable_type(state, actual, target) - and assignable_type(state, actual, descriptor.error_type)) target = descriptor.error_type - } else if (actual.kind != .none and !assignable_type(state, actual, target) - and assignable_type(state, actual, descriptor.error_type)) target = descriptor.error_type + if ( + name != ast.NodeId(maxval!(u32)) and type_has_variant(state, descriptor.error_type, name) + and !type_has_variant(state, descriptor.element, name) + ) target = descriptor.error_type + else if ( + actual.kind != .none and !assignable_type(state, actual, target) + and assignable_type(state, actual, descriptor.error_type) + ) target = descriptor.error_type + } else if ( + actual.kind != .none and !assignable_type(state, actual, target) + and assignable_type(state, actual, descriptor.error_type) + ) target = descriptor.error_type try demand(state, id, target, code) return } @@ -1587,9 +1612,11 @@ demand proc(state @mut State, id ast.NodeId, expected Type, code diagnostics.Cod } return } - if (expected.kind == .pointer and state.cells[usize(id)].role == .expression + if ( + expected.kind == .pointer and state.cells[usize(id)].role == .expression and ast.expr_kind(state.tree, id) == .unary - and ast.unary_expr(state.tree, id).operator == .address_of) { + and ast.unary_expr(state.tree, id).operator == .address_of + ) { state.cells[index].expected = expected try demand(state, ast.unary_expr(state.tree, id).operand, state.pointers.items[usize(expected.pointer_type)].element, code) @@ -1604,8 +1631,10 @@ demand proc(state @mut State, id ast.NodeId, expected Type, code diagnostics.Cod return } literal_node :: state.cells[index].literal - if (expected.nominal != ast.NodeId(maxval!(u32)) - and (expected.kind == .record or expected.kind == .array)) return + if ( + expected.nominal != ast.NodeId(maxval!(u32)) + and (expected.kind == .record or expected.kind == .array) + ) return if (literal_node != ast.NodeId(maxval!(u32)) and ast.expr_kind(state.tree, literal_node) == .enum_literal) { previous :: state.cells[index].expected if (previous.kind != .none and !same_type(state, previous, expected)) { @@ -1655,8 +1684,10 @@ demand proc(state @mut State, id ast.NodeId, expected Type, code diagnostics.Cod if (!numeric_kind(expected.kind)) return if (!state.cells[index].numeric and state.cells[index].type.kind != .none) return state.cells[index].numeric = true - if (state.cells[index].expected.kind != .none - and !same_type(state, state.cells[index].expected, expected)) { + if ( + state.cells[index].expected.kind != .none + and !same_type(state, state.cells[index].expected, expected) + ) { state.cells[index].type = invalid_type(try diagnostics.add(state.diagnostics, code, ast.node_span(state.tree, id))) return } @@ -1706,8 +1737,13 @@ mutable_target proc(state @mut State, id ast.NodeId, allow_global bool) bool { base :: group_type(state, view.base) if (base.kind == .pointer) { pointer :: state.pointers.items[usize(base.pointer_type)] - return pointer.mutable and (pointer.many - or (pointer.element.kind == .array and state.arrays.items[usize(pointer.element.array_type)].mutable)) + return ( + pointer.mutable + and ( + pointer.many + 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 return base.kind == .array and state.arrays.items[usize(base.array_type)].mutable and mutable_target(state, view.base, allow_global) @@ -1798,8 +1834,10 @@ assignable_type proc(state @State, actual, expected Type) bool { or error_subset(state.records.items, state.enums.items, actual, target.error_type) ) } - if ((composed_type(state, actual) or composed_type(state, expected)) - and error_subset(state.records.items, state.enums.items, actual, expected)) return true + if ( + (composed_type(state, actual) or composed_type(state, expected)) + and error_subset(state.records.items, state.enums.items, actual, expected) + ) return true if (expected.kind == .optional) { child :: state.arrays.items[usize(expected.array_type)].element if (actual.kind == .null) return true @@ -1851,9 +1889,11 @@ assignable_value proc(state @mut State, value ast.NodeId, actual, expected Type) if (!assignable_type(state, actual, expected)) return false target := expected while (target.kind == .optional) target = state.arrays.items[usize(target.array_type)].element - if (actual.kind == .array and target.kind == .slice + if ( + actual.kind == .array and target.kind == .slice and state.arrays.items[usize(target.array_type)].mutable - and addressable_target(state, value)) return mutable_target(state, value, true) + and addressable_target(state, value) + ) return mutable_target(state, value, true) return true } @@ -1907,8 +1947,10 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost try fail(state, value, .return_type_mismatch, ast.node_span(tree, value)) state.types[usize(id)] = state.types[usize(value)] } - } else if (expected.kind != .void - and !(expected.kind == .fallible and state.arrays.items[usize(expected.array_type)].element.kind == .void)) { + } else if ( + expected.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) } } @@ -1939,8 +1981,10 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost return } if (expression.operator == .dereference) { - if (state.types[usize(expression.operand)].kind != .invalid - and state.types[usize(expression.operand)].kind != .pointer) { + if ( + state.types[usize(expression.operand)].kind != .invalid + and state.types[usize(expression.operand)].kind != .pointer + ) { try fail(state, id, .invalid_dereference, expression.span) } return @@ -1966,11 +2010,15 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost } return } - if ((expression.operator == .equal or expression.operator == .not_equal) - and ((left.kind == .optional and right.kind == .null) or (left.kind == .null and right.kind == .optional))) return - if ((expression.operator == .equal or expression.operator == .not_equal) + if ( + (expression.operator == .equal or expression.operator == .not_equal) + and ((left.kind == .optional and right.kind == .null) or (left.kind == .null and right.kind == .optional)) + ) return + if ( + (expression.operator == .equal or expression.operator == .not_equal) and (left.kind == .bool or left.kind == .enumeration or left.kind == .pointer) - and (assignable_type(state, left, right) or assignable_type(state, right, left))) return + and (assignable_type(state, left, right) or assignable_type(state, right, left)) + ) return if (!numeric_kind(left.kind) or !numeric_kind(right.kind) or !same_type(state, left, right)) { try fail(state, id, .invalid_operand, expression.span) } else if (expression.operator == .divide and left.kind != .float) { @@ -2066,9 +2114,13 @@ validate_call proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | dia and state.enums.items[usize(actual.enum_type)].explicit_backing ) backing :: immediate_backing(state, actual) - if (actual.kind != .invalid - and (!numeric_kind(backing.kind) and !allowed_enum - or backing.nominal != ast.NodeId(maxval!(u32)))) { + if ( + actual.kind != .invalid + and ( + !numeric_kind(backing.kind) and !allowed_enum + or backing.nominal != ast.NodeId(maxval!(u32)) + ) + ) { try fail(state, argument, .invalid_operand, ast.node_span(tree, argument)) } } @@ -2167,14 +2219,18 @@ evaluate_integer proc(state @mut State, id ast.NodeId, allow_local bool) ?Consta binding :: sema.binding(state.resolution, id) if (binding.kind != .declaration) return null target :: binding.data.declaration - if (!state.cells[usize(target)].count_declaration - and (!allow_local or !state.cells[usize(target)].local)) return null + if ( + !state.cells[usize(target)].count_declaration + and (!allow_local or !state.cells[usize(target)].local) + ) return null declaration :: ast.statement_decl(state.tree, target) if (declaration.mutability != .constant) return null if (declaration.type) |annotation| { type_binding :: sema.binding(state.resolution, annotation) - if (!integer_kind(state.types[usize(annotation)].kind) - and (type_binding.kind != .builtin or !integer_kind(builtin_kind(type_binding.data.builtin)))) return null + if ( + !integer_kind(state.types[usize(annotation)].kind) + and (type_binding.kind != .builtin or !integer_kind(builtin_kind(type_binding.data.builtin))) + ) return null } return evaluate_integer(state, declaration.initializer, allow_local) } @@ -2224,8 +2280,10 @@ evaluate_integer proc(state @mut State, id ast.NodeId, allow_local bool) ?Consta @hide:file intern_pointer proc(state @mut State, descriptor PointerType) Type ! mem.AllocError { for state.pointers.items |existing, i| { - if (existing.mutable == descriptor.mutable and existing.many == descriptor.many - and same_type(state, existing.element, descriptor.element)) { + if ( + existing.mutable == descriptor.mutable and existing.many == descriptor.many + and same_type(state, existing.element, descriptor.element) + ) { return Type{ kind = .pointer, pointer_type = PointerId(i) } } } @@ -2241,10 +2299,12 @@ check_pointer_type proc(state @mut State, id ast.NodeId) Type ! (mem.AllocError element :: try check_annotation(state, view.element, true) if (element.kind == .invalid) return element binding :: sema.binding(state.resolution, view.element) - if (element.kind == .none or element.kind == .void or element.kind == .range + if ( + element.kind == .none or element.kind == .void or element.kind == .range or element.kind == .type_value 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 try intern_pointer(state, PointerType{ element = element, mutable = view.mutable, many = view.many }) @@ -2282,9 +2342,11 @@ check_function_type proc(state @mut State, id ast.NodeId) Type ! (mem.AllocError @hide:file intern_array proc(state @mut State, descriptor ArrayType) Type ! mem.AllocError { for state.arrays.items |existing, i| { - if (existing.kind == descriptor.kind and existing.len == descriptor.len and existing.mutable == descriptor.mutable + if ( + 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_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) } } } @@ -2527,8 +2589,10 @@ same_type proc(state @State, left, right Type) bool { and error_subset(state.records.items, state.enums.items, right, left) ) if (a.is_union or b.is_union) return false - if (a.declaration != ast.NodeId(maxval!(u32)) or b.declaration != ast.NodeId(maxval!(u32)) - or a.fields.len != b.fields.len) return false + if ( + a.declaration != ast.NodeId(maxval!(u32)) or b.declaration != ast.NodeId(maxval!(u32)) + or a.fields.len != b.fields.len + ) return false for a.fields |field, i| { other :: b.fields[i] if ((field.name == null) != (other.name == null)) return false @@ -2749,9 +2813,11 @@ infer_shape proc(state @mut State, id ast.NodeId, defaults bool) Type ! (mem.All } } } - if (state.cells[usize(id)].role == .expression + if ( + state.cells[usize(id)].role == .expression and ast.expr_kind(state.tree, id) == .selection - and sema.binding(state.resolution, id).kind == .none) { + and sema.binding(state.resolution, id).kind == .none + ) { view :: ast.selection_expr(state.tree, id) if (type_reference(state, view.base)) { enum_shape :: try check_annotation(state, view.base, false) @@ -2777,8 +2843,10 @@ infer_shape proc(state @mut State, id ast.NodeId, defaults bool) Type ! (mem.All } if (base.kind == .pointer and base.nominal == ast.NodeId(maxval!(u32))) { pointer :: state.pointers.items[usize(base.pointer_type)] - if (!pointer.many and pointer.element.kind == .array - and ast.expr_kind(state.tree, view.member) == .identifier) { + if ( + !pointer.many and pointer.element.kind == .array + and ast.expr_kind(state.tree, view.member) == .identifier + ) { member :: ast.source_text(state.tree, ast.node_span(state.tree, view.member)) if (mem.eql(member, "len")) { type :: Type{ kind = .usize } @@ -2837,8 +2905,10 @@ infer_shape proc(state @mut State, id ast.NodeId, defaults bool) Type ! (mem.All binding :: sema.binding(state.resolution, id) if (binding.kind == .declaration) { target :: binding.data.declaration - if (state.cells[usize(target)].role == .declaration and state.cells[usize(target)].fixed - and has_inferred_count(state, state.cells[usize(target)].type)) { + if ( + state.cells[usize(target)].role == .declaration and state.cells[usize(target)].fixed + and has_inferred_count(state, state.cells[usize(target)].type) + ) { declaration :: ast.statement_decl(state.tree, target) actual :: try infer_shape(state, declaration.initializer, defaults) if (actual.kind == .array and !has_inferred_count(state, actual)) { @@ -2931,8 +3001,10 @@ prepare_optional_captures proc(state @mut State, defaults bool) void ! (mem.Allo for (0..(state.cells.len)) |j| { if (state.cells[j].role != .expression or !declaration_reference(state.tree, ast.NodeId(j))) continue binding :: sema.binding(state.resolution, ast.NodeId(j)) - if (binding.kind == .declaration and binding.data.declaration == capture - and !has_narrowing(state, ast.NodeId(j))) seed(state, ast.NodeId(j), child) + if ( + binding.kind == .declaration and binding.data.declaration == capture + and !has_narrowing(state, ast.NodeId(j)) + ) seed(state, ast.NodeId(j), child) } } } @@ -2999,8 +3071,10 @@ apply_contexts proc(state @mut State, assignment_values, early bool) void ! (mem if (state.cells[i].role != .expression or state.cells[i].assignment_value != assignment_values or ast.expr_kind(tree, id) != .call) continue if (state.backings[i].kind != .none) { backing :: state.backings[i] - if (ast.call_arg_count(tree, id) == 1 - and (backing.nominal != ast.NodeId(maxval!(u32)) or !numeric_kind(backing.kind))) { + if ( + ast.call_arg_count(tree, id) == 1 + 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) } continue @@ -3029,9 +3103,11 @@ apply_contexts proc(state @mut State, assignment_values, early bool) void ! (mem @hide:file context_demand proc(state @mut State, id ast.NodeId, expected Type, code diagnostics.Code, early bool) void ! (mem.AllocError | diagnostics.CapacityError) { - if (early and expected.kind != .array and expected.kind != .record + if ( + early and expected.kind != .array and expected.kind != .record and expected.kind != .pointer and expected.kind != .slice and expected.kind != .optional and expected.kind != .fallible - and expected.kind != .enumeration and !integer_kind(expected.kind)) return + and expected.kind != .enumeration and !integer_kind(expected.kind) + ) return try demand(state, id, expected, code) } @@ -3080,13 +3156,16 @@ prepare_ranges proc(state @mut State, assignment_values, constrain bool) void ! } for 0..(state.cells.len) |i| { id :: ast.NodeId(i) - if (state.cells[i].role != .expression + if ( + state.cells[i].role != .expression or state.cells[i].assignment_value or !declaration_reference(tree, id) ) continue binding :: sema.binding(state.resolution, id) - if (binding.kind == .declaration and state.cells[usize(binding.data.declaration)].role == .loop_capture - and !has_narrowing(state, id)) { + if ( + binding.kind == .declaration and state.cells[usize(binding.data.declaration)].role == .loop_capture + and !has_narrowing(state, id) + ) { seed(state, id, group_type(state, binding.data.declaration)) } } @@ -3142,13 +3221,16 @@ specialize_annotations proc(state @mut State) void ! (mem.AllocError | diagnosti } for 0..(state.cells.len) |i| { id :: ast.NodeId(i) - if (state.cells[i].role != .expression + if ( + state.cells[i].role != .expression or state.cells[i].assignment_value or !declaration_reference(state.tree, id) ) continue binding :: sema.binding(state.resolution, id) - if (binding.kind == .declaration and state.cells[usize(binding.data.declaration)].fixed - and !has_narrowing(state, id)) { + if ( + binding.kind == .declaration and state.cells[usize(binding.data.declaration)].fixed + and !has_narrowing(state, id) + ) { seed(state, id, state.cells[usize(binding.data.declaration)].type) } } @@ -3187,8 +3269,10 @@ intern_record proc(state @mut State, declaration ast.NodeId, fields []mut Record for fields |field, j| { slot := j if (field.name) |name| slot = named_field(state.tree, existing.fields, name) - if (slot == no_index or (field.name == null and existing.fields[slot].name != null) - or !same_type(state, field.type, existing.fields[slot].type)) { + if ( + slot == no_index or (field.name == null and existing.fields[slot].name != null) + or !same_type(state, field.type, existing.fields[slot].type) + ) { equal = false break } @@ -3480,8 +3564,10 @@ check_type_expression proc(state @mut State, id ast.NodeId, nominal bool) Type ! and (operand_binding.data.builtin == .int or operand_binding.data.builtin == .float) ) if (kind == .distinct_type and type.kind != .invalid) { - if (type.kind == .none or type.kind == .void or type.kind == .range or type.kind == .type_value - or type.kind == .function or has_inferred_count(state, type) or constraint) { + if ( + type.kind == .none or type.kind == .void or type.kind == .range or type.kind == .type_value + or type.kind == .function or has_inferred_count(state, type) or constraint + ) { type = invalid_type(try diagnostics.add(state.diagnostics, .invalid_distinct_backing, ast.node_span(state.tree, id))) } else { state.backings[usize(id)] = type @@ -3570,13 +3656,18 @@ check_enum proc(state @mut State, id ast.NodeId) Type ! (mem.AllocError | diagno } else valid = false } if (!integer_fits(value, backing.kind)) valid = false - if (explicit and i != 0 and constant_order( - ConstantInteger{ magnitude = members[i - 1].magnitude, negative = members[i - 1].negative }, - value, - ) >= 0) valid = false + if ( + explicit and i != 0 + and constant_order( + ConstantInteger{ magnitude = members[i - 1].magnitude, negative = members[i - 1].negative }, + value, + ) >= 0 + ) valid = false for members[0..i] |member| { - if (ast.name_id(state.tree, member.name) == ast.name_id(state.tree, field.name?) - or (member.magnitude == value.magnitude and member.negative == value.negative)) valid = false + if ( + ast.name_id(state.tree, member.name) == ast.name_id(state.tree, field.name?) + or (member.magnitude == value.magnitude and member.negative == value.negative) + ) valid = false } if (!valid) { failure :: invalid_type(try diagnostics.add(state.diagnostics, .invalid_enum_value, field.span)) @@ -3648,8 +3739,10 @@ check_union proc(state @mut State, id ast.NodeId, nominal bool) Type ! (mem.Allo field :: ast.field(state.tree, ast.record_field(state.tree, id, i)) type :: try check_annotation(state, field.type?, true) if (type.kind == .invalid) return type - if (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)) { + if ( + 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) + ) { 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) { @@ -3896,8 +3989,10 @@ infer_match proc(state @mut State, id ast.NodeId, defaults bool) Type ! (mem.All ) if (tagged) key = descriptor.tag_type } - if (subject.kind != .none and !numeric_kind(subject.kind) and subject.kind != .bool - and !(subject.kind == .enumeration and subject.nominal == ast.NodeId(maxval!(u32))) and !tagged) { + if ( + subject.kind != .none and !numeric_kind(subject.kind) and subject.kind != .bool + and !(subject.kind == .enumeration and subject.nominal == ast.NodeId(maxval!(u32))) and !tagged + ) { try fail(state, id, .invalid_match_subject, ast.node_span(state.tree, id)) seed(state, id, state.types[usize(id)]) return state.types[usize(id)] @@ -3942,8 +4037,10 @@ infer_match proc(state @mut State, id ast.NodeId, defaults bool) Type ! (mem.All for 0..(state.cells.len) |j| { if (state.cells[j].role != .expression or !declaration_reference(state.tree, ast.NodeId(j))) continue binding :: sema.binding(state.resolution, ast.NodeId(j)) - if (binding.kind == .declaration and binding.data.declaration == capture - and !has_narrowing(state, ast.NodeId(j))) seed(state, ast.NodeId(j), payload) + if ( + binding.kind == .declaration and binding.data.declaration == capture + and !has_narrowing(state, ast.NodeId(j)) + ) seed(state, ast.NodeId(j), payload) } } } @@ -4103,10 +4200,20 @@ validate_match proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | di } else try compatible(state, pattern, key) current :: try pattern_interval(state, pattern, key) if (current) |interval| { - if ((interval.real and (interval.real_low > interval.real_high - or (!interval.inclusive and interval.real_low == interval.real_high))) - or (!interval.real and (constant_order(interval.low, interval.high) > 0 - or (!interval.inclusive and constant_order(interval.low, interval.high) == 0)))) { + if ( + ( + interval.real and ( + interval.real_low > interval.real_high + or (!interval.inclusive and interval.real_low == interval.real_high) + ) + ) + or ( + !interval.real 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)) } if (key.kind == .bool) { @@ -4145,8 +4252,10 @@ validate_match proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | di @hide:file global_variant proc(state @mut State, name ast.NodeId, payload Type) u64 ! mem.AllocError { for state.variants.items |variant, i| { - if (ast.name_id(state.tree, variant.name) == ast.name_id(state.tree, name) - and same_type(state, variant.payload, payload)) return u64(i + 1) + if ( + ast.name_id(state.tree, variant.name) == ast.name_id(state.tree, name) + and same_type(state, variant.payload, payload) + ) return u64(i + 1) } try arraylist.append(&state.variants, Variant{ name = name, payload = payload }) return u64(state.variants.items.len) @@ -4181,8 +4290,10 @@ error_subset proc(records []RecordType, enums []EnumType, actual, expected Type) if (!descriptor.is_union or descriptor.tag_type.kind != .enumeration) return false if (descriptor.composed and actual.kind == .record and !records[usize(actual.record_type)].is_union) { for descriptor.fields |field| { - if (field.type.kind == .record and field.type.record_type == actual.record_type - and field.type.nominal == actual.nominal) return true + if ( + field.type.kind == .record and field.type.record_type == actual.record_type + and field.type.nominal == actual.nominal + ) return true } return false } @@ -4199,8 +4310,10 @@ error_subset proc(records []RecordType, enums []EnumType, actual, expected Type) if (source.kind != .enumeration) return false origin :: enums[usize(source.enum_type)] if (origin.explicit_backing or destination.explicit_backing) { - if (!origin.explicit_backing or !destination.explicit_backing - or origin.declaration != destination.declaration or origin.backing != destination.backing) return false + if ( + !origin.explicit_backing or !destination.explicit_backing + or origin.declaration != destination.declaration or origin.backing != destination.backing + ) return false } for origin.members |member| { found := false @@ -4233,11 +4346,20 @@ check_fallible_type proc(state @mut State, id ast.NodeId) Type ! (mem.AllocError failure :: try check_annotation(state, expression.right, false) if (success.kind == .invalid) return success if (failure.kind == .invalid) return failure - valid_error :: failure.kind == .enumeration or (failure.kind == .record - and (!state.records.items[usize(failure.record_type)].is_union - or state.records.items[usize(failure.record_type)].tag_type.kind == .enumeration)) - if (!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)) { + valid_error :: ( + failure.kind == .enumeration + or ( + failure.kind == .record + and ( + !state.records.items[usize(failure.record_type)].is_union + or state.records.items[usize(failure.record_type)].tag_type.kind == .enumeration + ) + ) + ) + if ( + !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) + ) { 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 }) @@ -4275,8 +4397,10 @@ append_sum_variants proc(state @mut State, variants @mut arraylist.ArrayList(Sum name := ast.NodeId(maxval!(u32)) for 0..ast.package_decl_count(state.tree) |i| { declaration :: ast.package_decl(state.tree, i) - if (ast.decl_kind(state.tree, declaration) == .statement - and ast.statement_decl(state.tree, declaration).initializer == descriptor.declaration) name = declaration + if ( + ast.decl_kind(state.tree, declaration) == .statement + and ast.statement_decl(state.tree, declaration).initializer == descriptor.declaration + ) name = declaration } if (name == ast.NodeId(maxval!(u32))) { for 0..(state.cells.len) |i| { @@ -4362,8 +4486,10 @@ seed_capture proc(state @mut State, capture ast.NodeId, type Type) void { for 0..(state.cells.len) |i| { if (state.cells[i].role != .expression or !declaration_reference(state.tree, ast.NodeId(i))) continue binding :: sema.binding(state.resolution, ast.NodeId(i)) - if (binding.kind == .declaration and binding.data.declaration == capture - and !has_narrowing(state, ast.NodeId(i))) seed(state, ast.NodeId(i), type) + if ( + binding.kind == .declaration and binding.data.declaration == capture + and !has_narrowing(state, ast.NodeId(i)) + ) seed(state, ast.NodeId(i), type) } } @@ -4434,8 +4560,14 @@ validate_fallible_expression proc(state @mut State, id ast.NodeId) void ! (mem.A if (result.kind == .invalid) return if (result.kind != .fallible) { try fail(state, id, .try_outside_fallible, ast.node_span(state.tree, id)) - } else if (!error_subset(state.records.items, state.enums.items, descriptor.error_type, - state.arrays.items[usize(result.array_type)].error_type)) { + } else if ( + !error_subset( + state.records.items, + state.enums.items, + descriptor.error_type, + state.arrays.items[usize(result.array_type)].error_type, + ) + ) { try fail(state, id, .incompatible_propagated_error, ast.node_span(state.tree, id)) } } @@ -4445,8 +4577,10 @@ matching_narrowing_arm proc(state @State, id ast.NodeId) ast.NodeId { binding :: sema.binding(state.resolution, id) if (binding.kind != .declaration) return ast.NodeId(maxval!(u32)) target :: binding.data.declaration - if (state.cells[usize(target)].role == .declaration - and ast.statement_decl(state.tree, target).mutability == .variable) return ast.NodeId(maxval!(u32)) + if ( + state.cells[usize(target)].role == .declaration + and ast.statement_decl(state.tree, target).mutability == .variable + ) return ast.NodeId(maxval!(u32)) arm := state.cells[usize(id)].narrowing_arm while (arm != ast.NodeId(maxval!(u32))) { owner :: state.cells[usize(arm)].match_owner @@ -4467,8 +4601,10 @@ has_narrowing proc(state @State, id ast.NodeId) bool { arm_names_variant proc(state @State, arm, name ast.NodeId) bool { for 0..ast.match_pattern_count(state.tree, arm) |i| { pattern :: ast.match_pattern(state.tree, arm, i) - if (ast.expr_kind(state.tree, pattern) == .enum_literal - and ast.name_id(state.tree, ast.enum_literal(state.tree, pattern)) == ast.name_id(state.tree, name)) return true + if ( + ast.expr_kind(state.tree, pattern) == .enum_literal + and ast.name_id(state.tree, ast.enum_literal(state.tree, pattern)) == ast.name_id(state.tree, name) + ) return true } return false } diff --git a/source/sema/specialize/specialize.hon b/source/sema/specialize/specialize.hon index cca3637..a92f0cc 100644 --- a/source/sema/specialize/specialize.hon +++ b/source/sema/specialize/specialize.hon @@ -54,14 +54,17 @@ Instance :: struct { @hide:file Rewrite :: struct { target ast.NodeId, saved ast.NodeId } -#! owns an undo log and retained checking obligations; generated nodes belong to the caller's AST arena. +#! owns an undo log and retained checking obligations; deinit releases them with their retained allocator. +#! borrows the caller's AST builder; call deinit before finishing or deinitializing that builder. +#! generated nodes remain arena-owned and are released with the AST. Result :: struct { builder @mut ast.Builder changes arraylist.ArrayList(Rewrite) constraints arraylist.ArrayList(ast.NodeId) } -#! restores source nodes so the same compilation may be compiled again. +#! restores rewritten source nodes in the borrowed builder and releases the undo log and checking obligations. +#! does not remove generated arena nodes or restore resolution bindings. deinit proc(result @mut Result) void { index := result.changes.items.len while (index > 0) { @@ -94,8 +97,11 @@ State :: struct { type_execution_remaining usize = 0 } -#! elaborates templates into cached concrete declarations in the caller-owned arena. -#! resolution is extended to cover generated nodes; no template reaches checking or lowering. +#! elaborates templates into cached concrete declarations in the caller-owned `builder` arena. +#! extends `resolution` to cover generated nodes; no template reaches checking or lowering. +#! `allocator` supplies returned logs, temporary storage released on every exit, and replacement resolution bindings. +#! use the allocator retained by `resolution`; the returned Result borrows `builder` until the caller calls deinit. +#! on failure, restores rewritten source nodes and releases logs; generated nodes remain arena-owned. elaborate proc( allocator mem.Allocator, builder @mut ast.Builder, @@ -105,7 +111,7 @@ elaborate proc( ) Result ! Error { result := Result{ builder = builder, changes = arraylist.init(allocator), constraints = arraylist.init(allocator) } errdefer deinit(&result) - # Explicit evaluation is useful even in packages without generic declarations. + # explicit evaluation is useful even in packages without generic declarations. original :: ast.view(builder, root) needed := false for (0..ast.node_count(&original)) |i| { @@ -250,9 +256,11 @@ expand proc(state @mut State, id ast.NodeId) void ! Error { callee :: ast.call_expr(&state.tree, id).callee try expand(state, callee) resolved :: binding(state, callee) - if (resolved.kind == .declaration + if ( + resolved.kind == .declaration and ast.node_class(&state.tree, resolved.data.declaration) == .function - and template(state, resolved.data.declaration)) { + and template(state, resolved.data.declaration) + ) { try specialize_call(state, id, resolved.data.declaration) return } @@ -289,7 +297,7 @@ expand proc(state @mut State, id ast.NodeId) void ! Error { } } -# Only probe side-effect-free expressions. Ordinary calls stay runtime unless the +# only probe side-effect-free expressions. ordinary calls stay runtime unless the # source requests evaluation with $(); probing must not execute FFI or emit traps. @hide:file branch_constant proc(state @State, id ast.NodeId, depth usize) bool { @@ -362,7 +370,7 @@ specialize_call proc(state @mut State, call, function ast.NodeId) void ! Error { state.depth += 1 defer state.depth -= 1 count :: ast.function_param_count(&state.tree, function) - # A type result has no runtime call: every input participates in specialization. + # a type result has no runtime call: every input participates in specialization. type_result :: is_type(state, ast.function_decl(&state.tree, function).return_type) runtime := usize(0) for (0..count) |i| { @@ -551,13 +559,15 @@ instantiate proc(state @mut State, index usize, call ast.NodeId) void ! Error { } for (0..count) |n| { resolved :: binding(state, ast.NodeId(n)) - if (resolved.kind == .declaration and resolved.data.declaration == parameter - and ast.node_class(&state.tree, ast.NodeId(n)) == .expression) mapping[n] = replacement + if ( + resolved.kind == .declaration and resolved.data.declaration == parameter + and ast.node_class(&state.tree, ast.NodeId(n)) == .expression + ) mapping[n] = replacement } } clone :: try ast.clone_subtree(state.builder, function, mapping) try refresh(state) - # Copy original resolution, remapping references to cloned locals and runtime parameters. + # copy original resolution, remapping references to cloned locals and runtime parameters. for (0..count) |i| { target :: mapping[i] if (target == no_node or usize(target) < clone_start) continue @@ -655,7 +665,7 @@ reject_evaluation proc(state @mut State, call ast.NodeId) void ! Error { state.bindings.items[usize(call)] = sema.Binding{ kind = .invalid, data = sema.BindingData{ diagnostic = diagnostic } } } -# Failed deferred elaboration must not leave unchecked type expressions in the package. +# failed deferred elaboration must not leave unchecked type expressions in the package. @hide:file reject_type_result proc(state @mut State, call, result ast.NodeId, constraints_start usize) void ! Error { try reject_evaluation(state, call) @@ -714,8 +724,10 @@ argument_annotation proc( value :: try materialize(state, arguments[i]) for (0..mapping.len) |n| { resolved :: binding(state, ast.NodeId(n)) - if (resolved.kind == .declaration and resolved.data.declaration == parameter - and ast.node_class(&state.tree, ast.NodeId(n)) == .expression) mapping[n] = value.node + if ( + resolved.kind == .declaration and resolved.data.declaration == parameter + and ast.node_class(&state.tree, ast.NodeId(n)) == .expression + ) mapping[n] = value.node } } start :: ast.node_count(&state.tree) @@ -738,8 +750,8 @@ evaluate_expected proc(state @mut State, id, annotation ast.NodeId) Value ! Erro return try evaluate(state, id) } -# Values leaving the temporary interpreter must own no interpreter addresses or module IDs. -# Rebuild contextual source literals while the module and its escaped flat cells are alive. +# values leaving the temporary interpreter must own no interpreter addresses or module IDs. +# rebuild contextual source literals while the module and its escaped flat cells are alive. @hide:file serialize_value proc( state @mut State, module @ir.Module, checked @typecheck.Result, @@ -759,7 +771,7 @@ serialize_value proc( result = try ast.add_array_literal(state.builder, span, elements.items) } else if (type.kind == .record) { record :: typecheck.record_type(checked, type.record_type) - # Untagged storage has no active member; choosing one could discard bytes. + # untagged storage has no active member; choosing one could discard bytes. if (record.is_union and record.tag_type.kind != .enumeration) return no_node fields := arraylist.init(ast.NodeId, state.allocator) defer arraylist.deinit(&fields) @@ -786,7 +798,7 @@ serialize_value proc( child :: ir.aggregate_item(module, value, index) result = try serialize_value(state, module, checked, channel, child, span) if (result == no_node) return no_node - # Keep named success/error types distinct even when their members overlap. + # keep named success/error types distinct even when their members overlap. annotation := no_node if (channel.nominal != no_node) annotation = channel.nominal else if (channel.kind == .enumeration) annotation = typecheck.enum_type(checked, channel.enum_type).declaration @@ -927,7 +939,7 @@ evaluate_call proc(state @mut State, call ast.NodeId) Value ! Error { } try arraylist.append(&arguments, concrete.node) } - # Reuse checking, typed IR and the interpreter: compile-time arithmetic and local + # reuse checking, typed IR and the interpreter: compile-time arithmetic and local # inference must have exactly the same semantics as an ordinary runtime call. span :: ast.node_span(&state.tree, call) invocation :: try ast.add_call(state.builder, span, callee.node, arguments.items) @@ -1022,7 +1034,7 @@ TypeExecution :: struct { @hide:file TypeFlow :: enum { next, returned, break, continue, invalid } -# Type values cannot enter runtime IR. Execute their control flow here, substituting +# type values cannot enter runtime IR. execute their control flow here, substituting # owned constants into snapshots; ordinary value operations still use checked IR. @hide:file return_type_value proc(state @mut State, block, first_owned ast.NodeId) ast.NodeId ! Error { @@ -1054,7 +1066,7 @@ type_step proc(state @mut State, at ast.NodeId) bool ! Error { @hide:file prepare_type_snapshot proc(state @mut State, execution @mut TypeExecution, id ast.NodeId) void { if (usize(id) >= execution.mapping.len) return - # Substituted arguments belong to the caller, including nominal type identity. + # substituted arguments belong to the caller, including nominal type identity. if (id < execution.first_owned) { execution.mapping[usize(id)] = id return @@ -1105,7 +1117,7 @@ nominal_type_value proc(state @State, id ast.NodeId) bool { return kind == .record_type or kind == .union_type or kind == .enum_type or kind == .distinct_type } -# Select with ordinary checked IR so patterns, overlap and exhaustiveness have +# select with ordinary checked IR so patterns, overlap and exhaustiveness have # the same rules as runtime matching, without checking unexecuted type bodies. @hide:file type_match_arm proc(state @mut State, id ast.NodeId) usize ! Error { @@ -1117,7 +1129,7 @@ type_match_arm proc(state @mut State, id ast.NodeId) usize ! Error { for (0..ast.match_arm_count(&state.tree, id)) |i| { arm_id :: ast.match_arm(&state.tree, id, i) arm :: ast.match_arm_view(&state.tree, arm_id) - # Selector bodies omit source capture uses, but must retain their resolver failures. + # selector bodies omit source capture uses, but must retain their resolver failures. if (arm.capture) |capture| { resolved :: binding(state, capture) if (resolved.kind == .invalid) { @@ -1125,8 +1137,13 @@ type_match_arm proc(state @mut State, id ast.NodeId) usize ! Error { return no_index } } - if (i > 0 and arm.expression != ast.match_arm_view(&state.tree, - ast.match_arm(&state.tree, id, 0)).expression) { + if ( + i > 0 + and arm.expression != ast.match_arm_view( + &state.tree, + ast.match_arm(&state.tree, id, 0), + ).expression + ) { state.evaluation_diagnostic = try diagnostics.add(state.diagnostics, .type_mismatch, ast.node_span(&state.tree, arm_id)) return no_index @@ -1152,7 +1169,7 @@ type_match_arm proc(state @mut State, id ast.NodeId) usize ! Error { return usize(selected.magnitude) } -# Match checking has already validated every capture. Copy the active payload +# match checking has already validated every capture. copy the active payload # out of owned constant storage, never an address in the temporary interpreter. @hide:file type_match_capture proc(state @mut State, id ast.NodeId) ast.NodeId ! Error { @@ -1163,8 +1180,10 @@ type_match_capture proc(state @mut State, id ast.NodeId) ast.NodeId ! Error { payload :: ast.field(&state.tree, ast.record_field(&state.tree, value.node, 0)) for (0..ast.record_field_count(&state.tree, annotation)) |i| { field :: ast.field(&state.tree, ast.record_field(&state.tree, annotation, i)) - if (field.name != null and payload.name != null - and ast.name_id(&state.tree, field.name?) == ast.name_id(&state.tree, payload.name?)) { + if ( + field.name != null and payload.name != null + and ast.name_id(&state.tree, field.name?) == ast.name_id(&state.tree, payload.name?) + ) { result :: try ast.add_typed_constant(state.builder, ast.node_span(&state.tree, subject), field.type?, payload.value?) try refresh(state) @@ -1208,8 +1227,8 @@ type_value_expression proc(state @mut State, input ast.NodeId) ast.NodeId ! Erro return expression } -# Normalize only selected expression arms before ordinary expansion can visit them. -# Nominal results enter here after their instance declaration is cached. +# normalize only selected expression arms before ordinary expansion can visit them. +# nominal results enter here after their instance declaration is cached. @hide:file expand_type_matches proc(state @mut State, id ast.NodeId) bool ! Error { if (ast.node_class(&state.tree, id) == .expression and ast.expr_kind(&state.tree, id) == .match_expr) { @@ -1233,7 +1252,7 @@ type_execution_value proc(state @mut State, input, annotation ast.NodeId) ast.No expression :: try type_value_expression(state, input) if (expression == no_node) return no_node if (!try expand_type_matches(state, annotation)) return no_node - # A recursive record needs its cached declaration before expanding its fields. + # a recursive record needs its cached declaration before expanding its fields. if (is_type(state, annotation) and nominal_type_value(state, expression)) { concrete :: try materialize(state, Value{ kind = .type, node = expression }) constraint :: try ast.add_type_operand(state.builder, ast.node_span(&state.tree, expression), concrete.node, true) @@ -1327,9 +1346,11 @@ execute_type_statement proc(state @mut State, execution @mut TypeExecution, stat if (local.declaration == resolved.data.declaration) index = i } } - if (index == no_index + if ( + index == no_index or ast.node_class(&state.tree, execution.locals.items[index].declaration) != .statement - or ast.statement_decl(&state.tree, execution.locals.items[index].declaration).mutability != .variable) { + or ast.statement_decl(&state.tree, execution.locals.items[index].declaration).mutability != .variable + ) { state.evaluation_diagnostic = try diagnostics.add(state.diagnostics, .invalid_assignment_target, ast.node_span(&state.tree, assignment.target)) return .invalid @@ -1572,9 +1593,11 @@ evaluate_binary proc(state @mut State, id ast.NodeId) Value ! Error { result_type :: try builtin(state, id, kind) return try evaluate_ir(state, id, result_type) } - if (left.annotation != no_node and right.annotation != no_node + if ( + left.annotation != no_node and right.annotation != no_node and left.kind == .integer and right.kind == .integer - and !try same_type(state, left.annotation, right.annotation)) return Value{} + and !try same_type(state, left.annotation, right.annotation) + ) return Value{} if (view.operator == .equal or view.operator == .not_equal) { if (left.kind != right.kind) return Value{} equal :: try value_equal(state, left, right) @@ -1790,8 +1813,8 @@ type_hash proc(state @mut State, id ast.NodeId) usize ! Error { .optional_type: return mix(hash, try type_hash(state, ast.type_operand(&state.tree, node))) .sum_type: { view :: ast.binary_expr(&state.tree, node) - # Set fingerprints must ignore ordering, grouping and repeated members. - # Colliding fingerprints still use full type equality in the cache chain. + # set fingerprints must ignore ordering, grouping and repeated members. + # colliding fingerprints still use full type equality in the cache chain. return try type_hash(state, view.left) | try type_hash(state, view.right) } .fallible_type: { @@ -1914,9 +1937,11 @@ expression_type proc(state @mut State, id ast.NodeId, depth usize) ast.NodeId ! } .binary: { view :: ast.binary_expr(&state.tree, id) - if (view.operator == .equal or view.operator == .not_equal or view.operator == .less + if ( + view.operator == .equal or view.operator == .not_equal or view.operator == .less or view.operator == .less_equal or view.operator == .greater or view.operator == .greater_equal - or view.operator == .logical_and or view.operator == .logical_or) return try builtin(state, id, .bool) + or view.operator == .logical_and or view.operator == .logical_or + ) return try builtin(state, id, .bool) return try expression_type(state, view.left, depth + 1) } .selection: { @@ -1927,8 +1952,12 @@ expression_type proc(state @mut State, id ast.NodeId, depth usize) ast.NodeId ! if (base == no_node) return no_node member :: ast.source_text(&state.tree, ast.node_span(&state.tree, view.member)) base_kind :: ast.expr_kind(&state.tree, base) - if (mem.eql(member, "len") and (base_kind == .array_type or base_kind == .slice_type - or (binding(state, base).kind == .builtin and binding(state, base).data.builtin == .string))) + if ( + mem.eql(member, "len") and ( + base_kind == .array_type or base_kind == .slice_type + or (binding(state, base).kind == .builtin and binding(state, base).data.builtin == .string) + ) + ) return try builtin(state, id, .usize) if (base_kind != .record_type and base_kind != .union_type) return no_node for (0..ast.record_field_count(&state.tree, base)) |i| { @@ -2062,11 +2091,13 @@ materialize proc(state @mut State, value Value) Value ! Error { result := value span :: ast.node_span(&state.tree, value.node) if (value.kind == .type and nominal_type_value(state, value.node)) { - # Refer to declared nominal types, rather than reusing their definition as + # refer to declared nominal types, rather than reusing their definition as # an annotation and turning its value-role checker cell into an annotation. for (state.declarations.items) |declaration| { - if (ast.node_class(&state.tree, declaration) == .statement - and ast.statement_decl(&state.tree, declaration).initializer == value.node) { + if ( + ast.node_class(&state.tree, declaration) == .statement + and ast.statement_decl(&state.tree, declaration).initializer == value.node + ) { result.node = try reference(state, value.node, declaration) return result } diff --git a/std/fs/fs.hon b/std/fs/fs.hon index 3cffd9c..ac1c6e6 100644 --- a/std/fs/fs.hon +++ b/std/fs/fs.hon @@ -20,17 +20,21 @@ Entry :: struct { kind Kind } +#! returns caller-owned zero-terminated storage; release it with mem.free using the same allocator. @hide:file terminated proc(allocator mem.Allocator, text []u8) []mut u8 ! Error { if (text.len == 0 or text.len == maxval!(usize)) return .invalid_path - for (text) |byte| if (byte == 0) return .invalid_path + for (text) |byte| { + if (byte == 0) return .invalid_path + } bytes :: try mem.alloc(u8, allocator, text.len + 1) memcopy!(bytes[..text.len], text) bytes[text.len] = 0 return bytes } -#! returns an owned absolute path with symlinks resolved; free it with the same allocator. +#! returns an owned absolute path with symlinks resolved; release it with mem.free using the same allocator. +#! temporary path storage uses `allocator` and is released before returning. canonical proc(allocator mem.Allocator, path []u8) []mut u8 ! Error { input :: try terminated(allocator, path) defer mem.free(allocator, input) @@ -49,6 +53,7 @@ canonical proc(allocator mem.Allocator, path []u8) []mut u8 ! Error { } #! follows symlinks; nonexistent paths (including dangling links) return missing. +#! temporary path storage uses `allocator` and is released before returning. kind proc(allocator mem.Allocator, path []u8) Kind ! Error { input :: try terminated(allocator, path) defer mem.free(allocator, input) @@ -69,7 +74,9 @@ exists proc(allocator mem.Allocator, path []u8) bool ! Error { return (try kind(allocator, path)) != .missing } -#! opens an owned directory handle; path is borrowed only during this call. +#! opens an owned directory handle; `path` is borrowed only during this call. +#! temporary path storage uses `allocator` and is released before returning. +#! release the returned handle with close_directory. open_directory proc(allocator mem.Allocator, path []u8) Directory ! Error { input :: try terminated(allocator, path) defer mem.free(allocator, input) @@ -119,9 +126,10 @@ close_directory proc(directory @mut Directory) void ! Error { if (c.closedir(handle) != 0) return .directory_failed } -#! reads a regular file through runtime IO, accepting at most maximum bytes. +#! reads a regular file through runtime IO, accepting at most `maximum` bytes. #! follows symlinks and rejects devices/FIFOs before opening; metadata uses the host filesystem. -#! returned storage belongs to the caller; release with arraylist.deinit. all errors close the file. +#! returned storage belongs to the caller and retains `allocator`; release with arraylist.deinit. all errors close the file. +#! temporary path storage uses `allocator` and is released before returning. read_file proc( allocator mem.Allocator, runtime io.Io, diff --git a/std/mem/mem.hon b/std/mem/mem.hon index 1a08c9f..1725255 100644 --- a/std/mem/mem.hon +++ b/std/mem/mem.hon @@ -26,7 +26,8 @@ raw_alloc proc( } #! resize caller-owned storage with its original allocator and alignment. -#! on allocation failure with nonzero `new_size`, original storage remains caller-owned; release the result with raw_free. +#! on allocation failure with nonzero `new_size`, original storage remains caller-owned. +#! release returned storage with raw_free using the same allocator and alignment, with `new_size` as its size. raw_realloc proc( allocator Allocator, memory ?*mut u8, @@ -49,7 +50,9 @@ raw_free proc( eql proc($T type, left, right []T) bool { if (left.len != right.len) return false - for (0..left.len) |i| if (left[i] != right[i]) return false + for (0..left.len) |i| { + if (left[i] != right[i]) return false + } return true } diff --git a/std/process/process.hon b/std/process/process.hon index 0150a1b..17f5187 100644 --- a/std/process/process.hon +++ b/std/process/process.hon @@ -19,7 +19,7 @@ RunError :: enum { } #! run a program synchronously without a shell, searching PATH for `arguments[0]`. -#! arguments and zero-terminated strings are borrowed until this call returns. +#! `arguments` and zero-terminated strings are borrowed until this call returns. #! an empty argument vector, empty executable name, or embedded NUL is invalid. #! the child inherits the current environment and stdin/stdout/stderr. #! temporary argument descriptors use `allocator` and are freed on every return. @@ -28,7 +28,9 @@ run proc(allocator mem.Allocator, arguments [][;0]u8) i32 ! (mem.AllocError | Ru if (arguments.len == 0) return .invalid_arguments if (arguments[0].len == 0) return .invalid_arguments for arguments |argument| { - for (argument) |byte| if (byte == 0) return .invalid_arguments + for (argument) |byte| { + if (byte == 0) return .invalid_arguments + } } if (arguments.len == maxval!(usize)) return .out_of_memory @@ -61,6 +63,6 @@ run proc(allocator mem.Allocator, arguments [][;0]u8) i32 ! (mem.AllocError | Ru signal :: status[0] & 127 if (signal == 0) return i32(divtrunc!(status[0], 256) & 255) if (signal != 127) return i32(128 + signal) - # A traced child can report a stop even without WUNTRACED; wait for termination. + # a traced child can report a stop even without WUNTRACED; wait for termination. } } diff --git a/std/strconv/strconv.hon b/std/strconv/strconv.hon index 00b2d84..15aaf5c 100644 --- a/std/strconv/strconv.hon +++ b/std/strconv/strconv.hon @@ -58,7 +58,9 @@ parse_float proc(allocator mem.Allocator, text []u8) f64 ! (mem.AllocError | Par magnitude >= u64(9218868437227405312) or (magnitude == 0 and nonzero) or (range_error and magnitude >= u64(4607182418800017408)) - ) return .out_of_range + ) { + return .out_of_range + } return value } diff --git a/std/strmap/strmap.hon b/std/strmap/strmap.hon index 7e1c756..d33336d 100644 --- a/std/strmap/strmap.hon +++ b/std/strmap/strmap.hon @@ -31,8 +31,10 @@ init proc($V type, $N usize, $entries [N]Pair(V)) StaticStringMap(V) { compile_error!("static string map key is too long") } - for (0..i) |prior| if mem.eql(u8, entry.0, entries[prior].0) { - compile_error!("duplicate static string map key") + for (0..i) |prior| { + if mem.eql(u8, entry.0, entries[prior].0) { + compile_error!("duplicate static string map key") + } } keys[i] = entry.0