fix: bug hunt
This commit is contained in:
@@ -5407,10 +5407,15 @@ infer_expr :: proc(
|
||||
}
|
||||
_, function_item, function_type, ok := types.callable_function(callee_type, &checker.module.types)
|
||||
if !ok {
|
||||
distinct_type := types.find_named(&checker.module.types, u32(target_pkg), u32(expr.name), file=u32(expr_lookup_file(expr, file)))
|
||||
distinct_item, distinct_ok := types.node(&checker.module.types, distinct_type)
|
||||
if available && distinct_ok && distinct_item.kind == .Distinct && len(expr.args) == 1 {
|
||||
stack[frame_index].left = distinct_type
|
||||
named_type := types.find_named(&checker.module.types, u32(target_pkg), u32(expr.name), file=u32(expr_lookup_file(expr, file)))
|
||||
named_item, named_ok := types.node(&checker.module.types, named_type)
|
||||
constructor_type := types.resolve_alias(named_type, &checker.module.types)
|
||||
constructor_item, constructor_ok := types.node(&checker.module.types, constructor_type)
|
||||
scalar_alias := named_ok && named_item.kind == .Alias &&
|
||||
types.is_concrete_scalar(constructor_type) && !types.is_bool(constructor_type)
|
||||
distinct_constructor := constructor_ok && constructor_item.kind == .Distinct
|
||||
if available && len(expr.args) == 1 && (scalar_alias || distinct_constructor) {
|
||||
stack[frame_index].left = constructor_type
|
||||
stack[frame_index].stage = 7
|
||||
append(&stack, Infer_Frame{expr=expr.args[0], template=ast.INVALID_FUNCTION})
|
||||
continue
|
||||
@@ -7633,6 +7638,41 @@ enum_member_hir :: proc(
|
||||
})
|
||||
}
|
||||
|
||||
build_scalar_cast :: proc(
|
||||
checker: ^Checker,
|
||||
value: hir.Expr_Id,
|
||||
target: types.Type,
|
||||
span: source.Span,
|
||||
) -> hir.Expr_Id {
|
||||
store := &checker.module.types
|
||||
actual := checker.module.exprs[value].type
|
||||
valid_target := types.is_concrete_scalar(target) && !types.is_bool(target)
|
||||
actual_repr := types.runtime_representation(actual, store)
|
||||
actual_item, actual_item_ok := types.node(store, actual)
|
||||
explicit_enum := actual_item_ok && actual_item.kind == .Enum && actual_item.explicit_backing
|
||||
valid_actual := (types.is_concrete_scalar(actual) || explicit_enum) &&
|
||||
types.is_concrete_scalar(actual_repr) && !types.is_bool(actual_repr)
|
||||
if !valid_target || !valid_actual {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
span,
|
||||
"scalar cast requires numeric scalar types, got %s to %s",
|
||||
types.name(actual),
|
||||
types.name(target),
|
||||
)
|
||||
return invalid_hir_expr(checker, span, id, target)
|
||||
}
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.Scalar_Cast,
|
||||
span=span,
|
||||
type=target,
|
||||
left=value,
|
||||
target=hir.INVALID_REF,
|
||||
right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
|
||||
build_function_value :: proc(
|
||||
checker: ^Checker,
|
||||
template: ast.Function_Id,
|
||||
@@ -8041,17 +8081,22 @@ build_compound_expr :: proc(
|
||||
)
|
||||
return invalid_hir_expr(checker, expr.span, id, expected)
|
||||
case .Enum_Literal:
|
||||
if types.is_tagged_union(expected, store) {
|
||||
index, field, found := find_struct_field(checker, expected, expr.name)
|
||||
literal_expected := expected
|
||||
optional_expected := types.is_optional(expected, store)
|
||||
if optional_expected {
|
||||
literal_expected = types.child_type(expected, store)
|
||||
}
|
||||
if types.is_tagged_union(literal_expected, store) {
|
||||
index, field, found := find_struct_field(checker, literal_expected, expr.name)
|
||||
if !found {
|
||||
id := source.addf(checker.diagnostics, expr.span, "unknown variant '.%s' on '%s'", symbol_text(checker, expr.name), type_label(checker, expected))
|
||||
id := source.addf(checker.diagnostics, expr.span, "unknown variant '.%s' on '%s'", symbol_text(checker, expr.name), type_label(checker, literal_expected))
|
||||
return invalid_hir_expr(checker, expr.span, id, expected)
|
||||
}
|
||||
values := make([]hir.Expr_Id, 1, checker.allocator)
|
||||
if expr.left == ast.INVALID_EXPR {
|
||||
if !types.is_void(field.type) {
|
||||
id := source.addf(checker.diagnostics, expr.span, "variant '.%s' on '%s' needs a payload; only void variants can be built from a bare '.%s'",
|
||||
symbol_text(checker, expr.name), type_label(checker, expected), symbol_text(checker, expr.name))
|
||||
symbol_text(checker, expr.name), type_label(checker, literal_expected), symbol_text(checker, expr.name))
|
||||
delete(values, checker.allocator)
|
||||
return invalid_hir_expr(checker, expr.span, id, expected)
|
||||
}
|
||||
@@ -8065,11 +8110,12 @@ build_compound_expr :: proc(
|
||||
values[0] = build_nested_expr(checker, expr.left, locals, global_reads, calls, field.type, pkg, file)
|
||||
values[0] = coerce_expr(checker, values[0], field.type, checker.module.exprs[values[0]].span)
|
||||
}
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.Struct, span=expr.span, type=expected, args=values, integer=i64(index),
|
||||
result := add_hir_expr(checker, hir.Expr{
|
||||
kind=.Struct, span=expr.span, type=literal_expected, args=values, integer=i64(index),
|
||||
target=hir.INVALID_REF, left=hir.INVALID_EXPR, right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
return coerce_expr(checker, result, expected, expr.span) if optional_expected else result
|
||||
}
|
||||
if expr.left != ast.INVALID_EXPR {
|
||||
id := source.addf(
|
||||
@@ -8080,7 +8126,7 @@ build_compound_expr :: proc(
|
||||
)
|
||||
return invalid_hir_expr(checker, expr.span, id, expected)
|
||||
}
|
||||
if !types.is_enum(expected, store) {
|
||||
if !types.is_enum(literal_expected, store) {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
expr.span,
|
||||
@@ -8089,36 +8135,12 @@ build_compound_expr :: proc(
|
||||
)
|
||||
return invalid_hir_expr(checker, expr.span, id, expected)
|
||||
}
|
||||
return enum_member_hir(checker, expected, expr.name, expr.span)
|
||||
result := enum_member_hir(checker, literal_expected, expr.name, expr.span)
|
||||
return coerce_expr(checker, result, expected, expr.span) if optional_expected else result
|
||||
case .Cast:
|
||||
target := type_from_syntax(checker, expr.type, pkg, file)
|
||||
value := build_nested_expr(checker, expr.left, locals, global_reads, calls, types.INVALID, pkg, file)
|
||||
actual := checker.module.exprs[value].type
|
||||
valid_target := types.is_concrete_scalar(target) && !types.is_bool(target)
|
||||
actual_repr := types.runtime_representation(actual, store)
|
||||
actual_item, actual_item_ok := types.node(store, actual)
|
||||
explicit_enum := actual_item_ok && actual_item.kind == .Enum && actual_item.explicit_backing
|
||||
valid_actual := (types.is_concrete_scalar(actual) || explicit_enum) &&
|
||||
types.is_concrete_scalar(actual_repr) && !types.is_bool(actual_repr)
|
||||
if !valid_target || !valid_actual {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
expr.span,
|
||||
"scalar cast requires numeric scalar types, got %s to %s",
|
||||
types.name(actual),
|
||||
types.name(target),
|
||||
)
|
||||
return invalid_hir_expr(checker, expr.span, id, target)
|
||||
}
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.Scalar_Cast,
|
||||
span=expr.span,
|
||||
type=target,
|
||||
left=value,
|
||||
target=hir.INVALID_REF,
|
||||
right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
return build_scalar_cast(checker, value, target, expr.span)
|
||||
case .Address:
|
||||
// `&<array literal>` (Zig's `&.{...}`): the operand is an rvalue with no
|
||||
// address, so promote it to an anonymous global constant and take *its*
|
||||
@@ -9369,10 +9391,36 @@ build_expr :: proc(
|
||||
}
|
||||
}
|
||||
if callee == hir.INVALID_EXPR {
|
||||
distinct_type := types.find_named(&checker.module.types, u32(target_pkg), u32(expr.name), file=u32(expr_lookup_file(expr, file)))
|
||||
distinct_item, distinct_ok := types.node(&checker.module.types, distinct_type)
|
||||
if distinct_ok && distinct_item.kind == .Distinct {
|
||||
if !is_runtime_type(checker, distinct_type) {
|
||||
named_type := types.find_named(&checker.module.types, u32(target_pkg), u32(expr.name), file=u32(expr_lookup_file(expr, file)))
|
||||
named_item, named_ok := types.node(&checker.module.types, named_type)
|
||||
constructor_type := types.resolve_alias(named_type, &checker.module.types)
|
||||
constructor_item, constructor_ok := types.node(&checker.module.types, constructor_type)
|
||||
scalar_alias := named_ok && named_item.kind == .Alias &&
|
||||
types.is_concrete_scalar(constructor_type) && !types.is_bool(constructor_type)
|
||||
if scalar_alias {
|
||||
if len(expr.args) != 1 {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
expr.span,
|
||||
"type alias '%s' expects 1 argument, got %d",
|
||||
symbol_text(checker, expr.name),
|
||||
len(expr.args),
|
||||
)
|
||||
last = invalid_hir_expr(checker, expr.span, id, constructor_type)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
stack[frame_index].target_type = constructor_type
|
||||
stack[frame_index].stage = 11
|
||||
append(&stack, Build_Expr_Frame{
|
||||
expr=expr.args[0],
|
||||
expected=types.INVALID,
|
||||
template=ast.INVALID_FUNCTION,
|
||||
})
|
||||
continue
|
||||
}
|
||||
if constructor_ok && constructor_item.kind == .Distinct {
|
||||
if !is_runtime_type(checker, constructor_type) {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
expr.span,
|
||||
@@ -9391,15 +9439,15 @@ build_expr :: proc(
|
||||
symbol_text(checker, expr.name),
|
||||
len(expr.args),
|
||||
)
|
||||
last = invalid_hir_expr(checker, expr.span, id, distinct_type)
|
||||
last = invalid_hir_expr(checker, expr.span, id, constructor_type)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
stack[frame_index].target_type = distinct_type
|
||||
stack[frame_index].target_type = constructor_type
|
||||
stack[frame_index].stage = 8
|
||||
append(&stack, Build_Expr_Frame{
|
||||
expr=expr.args[0],
|
||||
expected=distinct_item.child,
|
||||
expected=constructor_item.child,
|
||||
template=ast.INVALID_FUNCTION,
|
||||
})
|
||||
continue
|
||||
@@ -9988,6 +10036,10 @@ build_expr :: proc(
|
||||
}
|
||||
_ = pop(&stack)
|
||||
}
|
||||
if frame.stage == 11 {
|
||||
last = build_scalar_cast(checker, last, frame.target_type, expr.span)
|
||||
_ = pop(&stack)
|
||||
}
|
||||
}
|
||||
return last
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user