unary minus

This commit is contained in:
2026-06-12 17:55:07 +02:00
parent 66e41e1d9a
commit 94e56f6888
14 changed files with 378 additions and 18 deletions
+54 -2
View File
@@ -125,7 +125,7 @@ eval_constant :: proc(checker: ^Checker, expr_id: ast.Expr_Id) -> Constant {
continue
}
expr := checker.ast_module.exprs[frame.expr]
if expr.kind != .Add {
if expr.kind != .Add && expr.kind != .Negate {
result := Constant{kind = .Not_Constant}
if expr.kind == .Integer {
result = Constant{kind = .Value, value = i128(expr.integer)}
@@ -142,6 +142,22 @@ eval_constant :: proc(checker: ^Checker, expr_id: ast.Expr_Id) -> Constant {
}
continue
}
if frame.stage == 1 && expr.kind == .Negate {
operand := Constant{kind = .Not_Constant}
if expr.left != ast.INVALID_EXPR && int(expr.left) < len(checker.constants) {
operand = checker.constants[expr.left]
}
result := Constant{kind = .Not_Constant}
if operand.kind == .Overflow {
result = Constant{kind = .Overflow}
} else if operand.kind == .Value {
value, overflow := intrinsics.overflow_sub(i128(0), operand.value)
result = Constant{kind = .Overflow} if overflow else Constant{kind = .Value, value = value}
}
checker.constants[frame.expr] = result
_ = pop(&stack)
continue
}
if frame.stage == 1 {
stack[frame_index].stage = 2
if expr.right != ast.INVALID_EXPR && int(expr.right) < len(checker.ast_module.exprs) &&
@@ -407,6 +423,8 @@ mark_expr_imports_used :: proc(checker: ^Checker, expr_id: ast.Expr_Id, file: as
switch expr.kind {
case .Call:
append(&stack, ..expr.args)
case .Negate:
append(&stack, expr.left)
case .Add:
append(&stack, expr.left, expr.right)
case .Invalid, .Integer, .Name:
@@ -644,7 +662,10 @@ infer_expr :: proc(
last = types.INVALID
_ = pop(&stack)
case .Integer:
last = types.smallest_signed_for_literal(expr.integer)
last = types.I64
if expr.integer <= 0x7fff_ffff_ffff_ffff {
last = types.smallest_signed_for_literal(i64(expr.integer))
}
_ = pop(&stack)
case .Name:
last = types.INVALID
@@ -661,6 +682,9 @@ infer_expr :: proc(
}
}
_ = pop(&stack)
case .Negate:
stack[frame_index].stage = 5
append(&stack, Infer_Frame{expr=expr.left, template=ast.INVALID_FUNCTION})
case .Add:
stack[frame_index].stage = 1
append(&stack, Infer_Frame{expr=expr.left, template=ast.INVALID_FUNCTION})
@@ -690,6 +714,13 @@ infer_expr :: proc(
}
continue
}
if frame.stage == 5 {
if !types.is_signed(last) {
last = types.INVALID
}
_ = pop(&stack)
continue
}
if frame.stage == 1 {
stack[frame_index].left = last
stack[frame_index].stage = 2
@@ -1097,6 +1128,9 @@ build_expr :: proc(
}
}
_ = pop(&stack)
case .Negate:
stack[frame_index].stage = 5
append(&stack, Build_Expr_Frame{expr=expr.left, expected=types.INVALID, template=ast.INVALID_FUNCTION})
case .Add:
stack[frame_index].stage = 1
append(&stack, Build_Expr_Frame{expr=expr.left, expected=types.INVALID, template=ast.INVALID_FUNCTION})
@@ -1147,6 +1181,24 @@ build_expr :: proc(
}
continue
}
if frame.stage == 5 {
operand := last
operand_type := checker.module.exprs[operand].type
if !types.is_signed(operand_type) {
id := source.add(checker.diagnostics, expr.span, "negation requires a signed integer")
last = invalid_hir_expr(checker, expr.span, id)
} else {
last = add_hir_expr(checker, hir.Expr{
kind=.Negate, span=expr.span, type=operand_type, left=operand,
target=hir.INVALID_REF, right=hir.INVALID_EXPR, diagnostic=source.INVALID_DIAGNOSTIC,
})
if types.is_signed(frame.expected) {
last = coerce_expr(checker, last, frame.expected, expr.span)
}
}
_ = pop(&stack)
continue
}
if frame.stage == 1 {
stack[frame_index].left = last
stack[frame_index].stage = 2