add constcast and immutable free
This commit is contained in:
@@ -5187,6 +5187,16 @@ infer_expr :: proc(
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if is_intrinsic_call(checker, expr, "constcast") {
|
||||
if len(expr.args) == 1 {
|
||||
operand := infer_nested_expr(checker, expr.args[0], locals, pkg, file, demanded, local_types)
|
||||
last, _ = types.restore_mutability(&checker.module.types, operand)
|
||||
} else {
|
||||
last = types.INVALID
|
||||
}
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if is_intrinsic_call(checker, expr, "compile_error") {
|
||||
last = types.VOID
|
||||
_ = pop(&stack)
|
||||
@@ -9056,6 +9066,17 @@ build_expr :: proc(
|
||||
append(&stack, Build_Expr_Frame{expr=expr.args[1], expected=types.INVALID, template=ast.INVALID_FUNCTION})
|
||||
continue
|
||||
}
|
||||
if is_intrinsic_call(checker, expr, "constcast") {
|
||||
if len(expr.args) != 1 {
|
||||
id := source.addf(checker.diagnostics, expr.span, "constcast! expects 1 argument, got %d", len(expr.args))
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
stack[frame_index].stage = 10
|
||||
append(&stack, Build_Expr_Frame{expr=expr.args[0], expected=types.INVALID, template=ast.INVALID_FUNCTION})
|
||||
continue
|
||||
}
|
||||
if is_intrinsic_call(checker, expr, "compile_error") {
|
||||
message := "compile_error! requires one comptime string argument"
|
||||
if len(expr.args) == 1 {
|
||||
@@ -9716,6 +9737,24 @@ build_expr :: proc(
|
||||
}
|
||||
_ = pop(&stack)
|
||||
}
|
||||
if frame.stage == 10 {
|
||||
result, ok := types.restore_mutability(&checker.module.types, checker.module.exprs[last].type)
|
||||
if !ok {
|
||||
id := source.add(checker.diagnostics, expr.span, "constcast! operand must be a pointer, optional pointer, or slice")
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
} else {
|
||||
last = add_hir_expr(checker, hir.Expr{
|
||||
kind=.Const_Cast,
|
||||
span=expr.span,
|
||||
type=result,
|
||||
left=last,
|
||||
target=hir.INVALID_REF,
|
||||
right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
_ = pop(&stack)
|
||||
}
|
||||
}
|
||||
return last
|
||||
}
|
||||
|
||||
@@ -3243,6 +3243,9 @@ ct_eval_call_expr :: proc(state: ^Ct_State, expr: ast.Expr, expected: types.Type
|
||||
if builtin := memory_builtin_call(checker, expr); builtin != .None {
|
||||
return ct_eval_memory_call(state, expr, builtin, depth+1)
|
||||
}
|
||||
if is_intrinsic_call(checker, expr, "constcast") {
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(state, .Not_Comptime, expr.span, "constcast! is not available during comptime evaluation")
|
||||
}
|
||||
if expr.intrinsic {
|
||||
if symbol.is_valid(expr.qualifier) {
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(state, .Not_Comptime, expr.span, "intrinsic calls must be unqualified")
|
||||
|
||||
@@ -107,6 +107,7 @@ Expr_Kind :: enum u8 {
|
||||
Retype,
|
||||
Scalar_Cast,
|
||||
Pointer_Cast,
|
||||
Const_Cast,
|
||||
Weaken_Pointer,
|
||||
Weaken_Slice,
|
||||
Decay_Array_Pointer,
|
||||
|
||||
@@ -102,6 +102,7 @@ Opcode :: enum u8 {
|
||||
Retype,
|
||||
Scalar_Cast,
|
||||
Pointer_Cast,
|
||||
Const_Cast,
|
||||
Weaken_Pointer,
|
||||
Weaken_Slice,
|
||||
Decay_Array_Pointer,
|
||||
|
||||
+11
-1
@@ -287,7 +287,7 @@ valid_value :: proc(
|
||||
.Load_Global, .Function_Address, .Address_Of, .Load, .Union_Tag, .Slice, .Length, .Slice_Ptr,
|
||||
.Fallible_Error, .Extract, .Select, .Unwrap,
|
||||
.Optional_Is_Some, .Optional_Value, .Orelse,
|
||||
.Widen, .Sum_Widen, .C_Coerce, .C_Vararg_Promote, .Retype, .Scalar_Cast, .Pointer_Cast, .Weaken_Pointer, .Weaken_Slice, .Decay_Array_Pointer,
|
||||
.Widen, .Sum_Widen, .C_Coerce, .C_Vararg_Promote, .Retype, .Scalar_Cast, .Pointer_Cast, .Const_Cast, .Weaken_Pointer, .Weaken_Slice, .Decay_Array_Pointer,
|
||||
.Neg_Checked, .Add_Checked, .Sub_Checked, .Mul_Checked, .Div_Checked,
|
||||
.Div_Trunc_Checked, .Div_Floor_Checked, .Div_Exact_Checked, .Div_Ceil_Checked,
|
||||
.Rem_Checked, .Mod_Checked,
|
||||
@@ -1930,6 +1930,16 @@ emit_instruction_stream :: proc(
|
||||
continue
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = select i1 true, ptr %%v%d, ptr null\n", instruction_index, instruction.a)
|
||||
case .Const_Cast:
|
||||
if !valid_instruction(instructions, instruction.a) ||
|
||||
!types.same_constcast_shape(instructions[instruction.a].type, instruction.type, &emitter.module.types) {
|
||||
emit_recovery_value(emitter, instruction_index, instruction, "invalid const cast operand")
|
||||
continue
|
||||
}
|
||||
type_name := llvm_type(instruction.type, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = select i1 true, %s ", instruction_index, type_name)
|
||||
write_operand(&emitter.builder, instructions, instruction.a, instructions[instruction.a].type, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, ", %s zeroinitializer\n", type_name)
|
||||
case .Weaken_Slice:
|
||||
if !valid_instruction(instructions, instruction.a) ||
|
||||
!types.can_weaken_slice(instructions[instruction.a].type, instruction.type, &emitter.module.types) {
|
||||
|
||||
@@ -768,7 +768,7 @@ lower_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
})
|
||||
}
|
||||
_ = pop(&stack)
|
||||
case .Widen, .Sum_Widen, .C_Coerce, .C_Vararg_Promote, .Retype, .Scalar_Cast, .Pointer_Cast, .Weaken_Pointer, .Weaken_Slice, .Decay_Array_Pointer:
|
||||
case .Widen, .Sum_Widen, .C_Coerce, .C_Vararg_Promote, .Retype, .Scalar_Cast, .Pointer_Cast, .Const_Cast, .Weaken_Pointer, .Weaken_Slice, .Decay_Array_Pointer:
|
||||
stack[frame_index].stage = 1
|
||||
append(&stack, Lower_Expr_Frame{expr=expr.left})
|
||||
case .Negate, .Bit_Not:
|
||||
@@ -837,6 +837,7 @@ lower_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
case .Retype: op = .Retype
|
||||
case .Scalar_Cast: op = .Scalar_Cast
|
||||
case .Pointer_Cast: op = .Pointer_Cast
|
||||
case .Const_Cast: op = .Const_Cast
|
||||
case: op = .Widen
|
||||
}
|
||||
last = append_instruction(state, ir.Instruction{
|
||||
|
||||
@@ -1340,6 +1340,45 @@ replace_pointer_child :: proc(store: ^Store, value, child: Type) -> (Type, bool)
|
||||
return intern(store, item), true
|
||||
}
|
||||
|
||||
restore_mutability :: proc(store: ^Store, value: Type) -> (Type, bool) {
|
||||
item, ok := node(store, resolve_alias(value, store))
|
||||
if !ok {
|
||||
return INVALID, false
|
||||
}
|
||||
if item.kind == .Optional {
|
||||
restored, restored_ok := restore_mutability(store, item.child)
|
||||
if !restored_ok || !is_pointer(restored, store) {
|
||||
return INVALID, false
|
||||
}
|
||||
return optional(store, restored), true
|
||||
}
|
||||
if item.kind != .Pointer && item.kind != .Slice {
|
||||
return INVALID, false
|
||||
}
|
||||
item.mutable = true
|
||||
return intern(store, item), true
|
||||
}
|
||||
|
||||
same_constcast_shape :: proc(from, to: Type, store: ^Store) -> bool {
|
||||
from_item, from_ok := node(store, resolve_alias(from, store))
|
||||
to_item, to_ok := node(store, resolve_alias(to, store))
|
||||
if !from_ok || !to_ok {
|
||||
return false
|
||||
}
|
||||
if from_item.kind == .Optional || to_item.kind == .Optional {
|
||||
return from_item.kind == .Optional && to_item.kind == .Optional &&
|
||||
is_pointer(from_item.child, store) && is_pointer(to_item.child, store) &&
|
||||
same_constcast_shape(from_item.child, to_item.child, store)
|
||||
}
|
||||
return (from_item.kind == .Pointer || from_item.kind == .Slice) &&
|
||||
from_item.kind == to_item.kind &&
|
||||
from_item.child == to_item.child &&
|
||||
from_item.many == to_item.many &&
|
||||
to_item.mutable &&
|
||||
from_item.has_sentinel == to_item.has_sentinel &&
|
||||
(!from_item.has_sentinel || from_item.sentinel == to_item.sentinel)
|
||||
}
|
||||
|
||||
same_pointer_shape :: proc(left, right: Type, store: ^Store) -> bool {
|
||||
left_item, left_ok := node(store, left)
|
||||
right_item, right_ok := node(store, right)
|
||||
|
||||
Reference in New Issue
Block a user