refine distinct construction semantics

This commit is contained in:
2026-08-02 19:13:13 +02:00
parent b9526b5f06
commit f25f76adff
5 changed files with 88 additions and 36 deletions
+20 -9
View File
@@ -935,6 +935,14 @@ valid_layout_type :: proc(checker: ^Checker, value: types.Type) -> bool {
return types.is_runtime_value(value, &checker.module.types)
}
is_integer_bound_type :: proc(checker: ^Checker, value: types.Type) -> bool {
representation := value
if backing, ok := types.distinct_scalar_backing(value, &checker.module.types); ok {
representation = backing
}
return types.is_concrete_integer(representation)
}
type_builtin_value :: proc(checker: ^Checker, kind: Type_Builtin, value: types.Type) -> i128 {
#partial switch kind {
case .Size_Of:
@@ -984,11 +992,7 @@ build_type_builtin :: proc(
id := source.addf(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "layout target must be a sized runtime value type, got %s", type_label(checker, target))
return invalid_hir_expr(checker, expr.span, id, types.USIZE)
}
bound_representation := target
if backing, ok := types.distinct_scalar_backing(target, &checker.module.types); ok {
bound_representation = backing
}
if (kind == .Min_Value || kind == .Max_Value) && !types.is_concrete_integer(bound_representation) {
if (kind == .Min_Value || kind == .Max_Value) && !is_integer_bound_type(checker, target) {
id := source.addf(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "integer bound target must be a concrete integer type, got %s", type_label(checker, target))
return invalid_hir_expr(checker, expr.span, id, types.USIZE)
}
@@ -5423,7 +5427,7 @@ infer_expr :: proc(
last = types.USIZE
} else if len(expr.args) == 1 {
target, ok := resolve_type_argument(checker, expr.args[0], pkg, file)
last = target if ok && types.is_concrete_integer(target) else types.INVALID
last = target if ok && is_integer_bound_type(checker, target) else types.INVALID
} else {
last = types.INVALID
}
@@ -6821,7 +6825,7 @@ infer_all :: proc(checker: ^Checker) {
checker.global_types[index] = types.USIZE
} else if len(expr.args) == 1 {
target, ok := resolve_type_argument(checker, expr.args[0], global.pkg, global.file)
if ok && types.is_concrete_integer(target) {
if ok && is_integer_bound_type(checker, target) {
checker.global_types[index] = target
}
}
@@ -10313,14 +10317,21 @@ build_expr :: proc(
if frame.stage == 8 {
distinct_item, ok := types.node(&checker.module.types, frame.target_type)
actual := checker.module.exprs[last].type
if ok && distinct_item.kind == .Distinct &&
!types.can_retype_distinct(actual, frame.target_type, &checker.module.types) {
backing := types.resolve_alias(distinct_item.child, &checker.module.types)
if types.is_concrete_scalar(backing) && !types.is_bool(backing) {
last = build_scalar_cast(checker, last, backing, expr.span)
actual = checker.module.exprs[last].type
}
}
if !ok || distinct_item.kind != .Distinct ||
!types.can_retype_distinct(actual, frame.target_type, &checker.module.types) {
id := source.addf(
checker.diagnostics,
expr.span,
"distinct type '%s' requires an exact %s value, got %s",
"cannot construct distinct type '%s' from %s",
symbol_text(checker, expr.name),
types.name(distinct_item.child),
types.name(actual),
)
last = invalid_hir_expr(checker, expr.span, id, frame.target_type)