distinct type aliasing
This commit is contained in:
+127
-24
@@ -870,6 +870,15 @@ validate_declarations :: proc(checker: ^Checker) {
|
||||
validate_type_nodes :: proc(checker: ^Checker) {
|
||||
for item, index in checker.module.types.nodes {
|
||||
id := types.DYNAMIC_START+types.Type(index)
|
||||
if item.kind == .Distinct &&
|
||||
(!item.declared || !types.is_runtime_value(item.child, &checker.module.types)) {
|
||||
source.addf(
|
||||
checker.diagnostics,
|
||||
source.Span{},
|
||||
"distinct type '%s' requires a concrete runtime backing type",
|
||||
symbol_text(checker, symbol.Id(item.name)),
|
||||
)
|
||||
}
|
||||
if item.has_sentinel {
|
||||
value := i128(item.sentinel)
|
||||
if types.is_signed(item.child, checker.target) {
|
||||
@@ -1311,6 +1320,14 @@ infer_expr :: proc(
|
||||
}
|
||||
_, function_item, function_type, ok := types.function_pointer(callee_type, &checker.module.types)
|
||||
if !ok {
|
||||
distinct_type := types.find_named(&checker.module.types, u32(target_pkg), u32(expr.name))
|
||||
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
|
||||
stack[frame_index].stage = 7
|
||||
append(&stack, Infer_Frame{expr=expr.args[0], template=ast.INVALID_FUNCTION})
|
||||
continue
|
||||
}
|
||||
last = types.INVALID
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
@@ -1426,6 +1443,10 @@ infer_expr :: proc(
|
||||
stack[frame_index].args = nil
|
||||
_ = pop(&stack)
|
||||
}
|
||||
if frame.stage == 7 {
|
||||
last = frame.left
|
||||
_ = pop(&stack)
|
||||
}
|
||||
}
|
||||
return last
|
||||
}
|
||||
@@ -1951,6 +1972,7 @@ build_float_expr :: proc(checker: ^Checker, expr: ast.Expr, expected: types.Type
|
||||
Build_Expr_Frame :: struct {
|
||||
expr: ast.Expr_Id,
|
||||
expected: types.Type,
|
||||
target_type: types.Type,
|
||||
stage: u8,
|
||||
left: hir.Expr_Id,
|
||||
arg_index: int,
|
||||
@@ -2701,38 +2723,81 @@ build_expr :: proc(
|
||||
template := find_template(checker, expr.name, target_pkg)
|
||||
if template == ast.INVALID_FUNCTION {
|
||||
callee := hir.INVALID_EXPR
|
||||
callee_from_global := false
|
||||
non_callable := false
|
||||
non_callable_global := false
|
||||
if !symbol.is_valid(expr.qualifier) {
|
||||
if local, ok := find_build_local(locals, expr.name); ok {
|
||||
callee = add_hir_expr(checker, hir.Expr{
|
||||
kind=.Local, span=expr.span, type=local.type, target=hir.local_ref(local.id),
|
||||
left=hir.INVALID_EXPR, right=hir.INVALID_EXPR, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
if _, _, _, callable := types.function_pointer(local.type, &checker.module.types); callable {
|
||||
callee = add_hir_expr(checker, hir.Expr{
|
||||
kind=.Local, span=expr.span, type=local.type, target=hir.local_ref(local.id),
|
||||
left=hir.INVALID_EXPR, right=hir.INVALID_EXPR, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
} else {
|
||||
non_callable = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if callee == hir.INVALID_EXPR {
|
||||
if callee == hir.INVALID_EXPR && !non_callable {
|
||||
if global := find_global(checker, expr.name, target_pkg); global != ast.INVALID_GLOBAL {
|
||||
callee = build_global_reference(checker, global, expr.span, global_reads)
|
||||
callee_from_global = true
|
||||
if _, _, _, callable := types.function_pointer(checker.global_types[global], &checker.module.types); callable {
|
||||
callee = build_global_reference(checker, global, expr.span, global_reads)
|
||||
} else {
|
||||
non_callable = true
|
||||
non_callable_global = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if callee == hir.INVALID_EXPR {
|
||||
id := add_unsupported_diagnostic(checker, expr.span, target_pkg, expr.name)
|
||||
if id == source.INVALID_DIAGNOSTIC {
|
||||
id = add_call_resolution_diagnostic(checker, expr, target_pkg)
|
||||
distinct_type := types.find_named(&checker.module.types, u32(target_pkg), u32(expr.name))
|
||||
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) {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
expr.span,
|
||||
"distinct type '%s' has no concrete runtime backing type",
|
||||
symbol_text(checker, expr.name),
|
||||
)
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if len(expr.args) != 1 {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
expr.span,
|
||||
"distinct type '%s' expects 1 argument, got %d",
|
||||
symbol_text(checker, expr.name),
|
||||
len(expr.args),
|
||||
)
|
||||
last = invalid_hir_expr(checker, expr.span, id, distinct_type)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
stack[frame_index].target_type = distinct_type
|
||||
stack[frame_index].stage = 8
|
||||
append(&stack, Build_Expr_Frame{
|
||||
expr=expr.args[0],
|
||||
expected=distinct_item.child,
|
||||
template=ast.INVALID_FUNCTION,
|
||||
})
|
||||
continue
|
||||
}
|
||||
id := source.INVALID_DIAGNOSTIC
|
||||
if non_callable {
|
||||
id = add_call_resolution_diagnostic(checker, expr, target_pkg) if non_callable_global else
|
||||
source.add(checker.diagnostics, expr.span, "call target is not a function pointer")
|
||||
} else {
|
||||
id = add_unsupported_diagnostic(checker, expr.span, target_pkg, expr.name)
|
||||
if id == source.INVALID_DIAGNOSTIC {
|
||||
id = add_call_resolution_diagnostic(checker, expr, target_pkg)
|
||||
}
|
||||
}
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
_, function_item, function_type, ok := types.function_pointer(checker.module.exprs[callee].type, &checker.module.types)
|
||||
if !ok {
|
||||
id := add_call_resolution_diagnostic(checker, expr, target_pkg) if callee_from_global else
|
||||
source.add(checker.diagnostics, expr.span, "call target is not a function pointer")
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
_, function_item, function_type, _ := types.function_pointer(checker.module.exprs[callee].type, &checker.module.types)
|
||||
if !valid_callable_arity(function_item, len(expr.args)) {
|
||||
message := "function pointer expects at least %d arguments, got %d" if function_item.variadic else
|
||||
"function pointer expects %d arguments, got %d"
|
||||
@@ -2999,6 +3064,32 @@ build_expr :: proc(
|
||||
}
|
||||
_ = pop(&stack)
|
||||
}
|
||||
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.equal(actual, distinct_item.child) {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
expr.span,
|
||||
"distinct type '%s' requires an exact %s value, got %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)
|
||||
} else {
|
||||
last = add_hir_expr(checker, hir.Expr{
|
||||
kind=.Retype,
|
||||
span=expr.span,
|
||||
type=frame.target_type,
|
||||
left=last,
|
||||
target=hir.INVALID_REF,
|
||||
right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
_ = pop(&stack)
|
||||
}
|
||||
}
|
||||
return last
|
||||
}
|
||||
@@ -3783,6 +3874,21 @@ expr_problematic :: proc(checker: ^Checker, expr_id: hir.Expr_Id) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
static_integer_value :: proc(module: ^hir.Module, expr_id: hir.Expr_Id) -> (i64, bool) {
|
||||
current := expr_id
|
||||
for current != hir.INVALID_EXPR && int(current) < len(module.exprs) {
|
||||
expr := module.exprs[current]
|
||||
if expr.kind == .Integer {
|
||||
return expr.integer, true
|
||||
}
|
||||
if expr.kind != .Retype {
|
||||
break
|
||||
}
|
||||
current = expr.left
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
build_globals :: proc(checker: ^Checker) {
|
||||
for global, global_index in checker.ast_module.globals {
|
||||
if global.external {
|
||||
@@ -3864,11 +3970,8 @@ build_globals :: proc(checker: ^Checker) {
|
||||
)
|
||||
expr = invalid_hir_expr(checker, global.span, diagnostic)
|
||||
}
|
||||
is_static := checker.module.exprs[expr].kind == .Integer && diagnostic == source.INVALID_DIAGNOSTIC
|
||||
static_value: i64
|
||||
if is_static {
|
||||
static_value = checker.module.exprs[expr].integer
|
||||
}
|
||||
static_value, is_static := static_integer_value(&checker.module, expr)
|
||||
is_static = is_static && diagnostic == source.INVALID_DIAGNOSTIC
|
||||
_ = hir.global_id(len(checker.module.globals))
|
||||
append(
|
||||
&checker.module.globals,
|
||||
|
||||
Reference in New Issue
Block a user