feat: support checked explicit sentinel slices
This commit is contained in:
@@ -400,6 +400,9 @@ block_reads_name :: proc(checker: ^Checker, statements: []ast.Stmt_Id, name: sym
|
||||
case .Call, .Array, .Struct_Literal, .Slice:
|
||||
append(&expr_stack, ..expr.args)
|
||||
append(&expr_stack, expr.left)
|
||||
if expr.kind == .Slice {
|
||||
append(&expr_stack, expr.right)
|
||||
}
|
||||
case .Negate, .Not, .Bit_Not, .Address, .Deref, .Field, .Unwrap, .Try, .Keyed, .Enum_Literal, .Cast:
|
||||
append(&expr_stack, expr.left)
|
||||
case .Comptime:
|
||||
@@ -743,12 +746,18 @@ comptime_slice_bytes :: proc(
|
||||
pkg: ast.Package_Id,
|
||||
file: ast.File_Id,
|
||||
) -> (string, bool) {
|
||||
if expr.right != ast.INVALID_EXPR {
|
||||
return "", false
|
||||
}
|
||||
state := ct_state_make(checker, pkg, file, diagnose=false)
|
||||
defer ct_state_destroy(&state)
|
||||
value, flow, ok := ct_eval_slice_expr(&state, expr, 0)
|
||||
if !ok || flow.kind != .Normal {
|
||||
return "", false
|
||||
}
|
||||
if item, item_ok := types.container(state.values[value].type, &checker.module.types); item_ok && item.has_sentinel {
|
||||
return "", false
|
||||
}
|
||||
return ct_value_bytes(&state, value)
|
||||
}
|
||||
|
||||
@@ -2753,6 +2762,15 @@ match_inferred_type_pattern :: proc(
|
||||
values, bound, span, diagnose, depth+1,
|
||||
)
|
||||
}
|
||||
if actual_ok && actual_item.kind == .Slice {
|
||||
if pattern_item.has_sentinel && (!actual_item.has_sentinel || pattern_item.sentinel != actual_item.sentinel) {
|
||||
return false
|
||||
}
|
||||
return match_inferred_type_pattern(
|
||||
checker, function, prefix, pattern_item.child, actual_item.child,
|
||||
values, bound, span, diagnose, depth+1,
|
||||
)
|
||||
}
|
||||
}
|
||||
if !actual_ok || pattern_item.kind != actual_item.kind {
|
||||
resolved := type_from_syntax(checker, pattern, function.pkg, function.file)
|
||||
@@ -3786,6 +3804,9 @@ mark_expr_imports_used :: proc(checker: ^Checker, expr_id: ast.Expr_Id, file: as
|
||||
if expr.left != ast.INVALID_EXPR {
|
||||
append(&stack, expr.left)
|
||||
}
|
||||
if expr.kind == .Slice && expr.right != ast.INVALID_EXPR {
|
||||
append(&stack, expr.right)
|
||||
}
|
||||
case .Negate, .Not, .Bit_Not, .Address, .Deref, .Field, .Unwrap, .Try, .Keyed, .Enum_Literal, .Cast:
|
||||
append(&stack, expr.left)
|
||||
case .Comptime:
|
||||
@@ -5168,6 +5189,15 @@ infer_compound_expr :: proc(
|
||||
_ = record_demand(checker, bound, types.USIZE, locals, local_types, pkg, file)
|
||||
}
|
||||
}
|
||||
if expr.right != ast.INVALID_EXPR {
|
||||
state := ct_state_make(checker, pkg, file, diagnose=false)
|
||||
defer ct_state_destroy(&state)
|
||||
sentinel, sentinel_ok := checked_slice_sentinel(&state, expr.right, item.child)
|
||||
if !sentinel_ok {
|
||||
return types.INVALID
|
||||
}
|
||||
return types.slice(store, item.child, item.mutable, true, u64(sentinel))
|
||||
}
|
||||
preserve := item.has_sentinel && expr.args[1] == ast.INVALID_EXPR
|
||||
return types.slice(store, item.child, item.mutable, preserve, item.sentinel)
|
||||
case .Field:
|
||||
@@ -8773,6 +8803,22 @@ build_compound_expr :: proc(
|
||||
id := source.add(checker.diagnostics, expr.span, "many-item pointer slicing requires an explicit end bound")
|
||||
return invalid_hir_expr(checker, expr.span, id)
|
||||
}
|
||||
sentinel_expr := hir.INVALID_EXPR
|
||||
sentinel := item.sentinel
|
||||
if expr.right != ast.INVALID_EXPR {
|
||||
state := ct_state_make(checker, pkg, file)
|
||||
defer ct_state_destroy(&state)
|
||||
constant, sentinel_ok := checked_slice_sentinel(&state, expr.right, item.child)
|
||||
if !sentinel_ok {
|
||||
return invalid_hir_expr(checker, expr.span, state.diagnostic)
|
||||
}
|
||||
sentinel = u64(constant)
|
||||
sentinel_expr = add_hir_expr(checker, hir.Expr{
|
||||
kind=.Integer, span=checker.ast_module.exprs[expr.right].span, type=item.child, integer=i64(sentinel),
|
||||
target=hir.INVALID_REF, left=hir.INVALID_EXPR, right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
bounds := make([]hir.Expr_Id, 2, checker.allocator)
|
||||
bounds[0] = hir.INVALID_EXPR
|
||||
bounds[1] = hir.INVALID_EXPR
|
||||
@@ -8791,11 +8837,11 @@ build_compound_expr :: proc(
|
||||
}
|
||||
}
|
||||
}
|
||||
preserve_sentinel := item.has_sentinel && expr.args[1] == ast.INVALID_EXPR
|
||||
result_type := types.slice(store, item.child, item.mutable, preserve_sentinel, item.sentinel)
|
||||
preserve_sentinel := expr.right != ast.INVALID_EXPR || item.has_sentinel && expr.args[1] == ast.INVALID_EXPR
|
||||
result_type := types.slice(store, item.child, item.mutable, preserve_sentinel, sentinel)
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.Slice, span=expr.span, type=result_type, args=bounds, left=container,
|
||||
target=hir.INVALID_REF, right=hir.INVALID_EXPR, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
target=hir.INVALID_REF, right=sentinel_expr, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Field:
|
||||
if enum_type, enum_ok := enum_type_from_field_expr(checker, expr, pkg, file, true); enum_ok {
|
||||
|
||||
Reference in New Issue
Block a user