bare func declaration identities (comptime)
This commit is contained in:
+192
-39
@@ -597,7 +597,8 @@ build_static_value :: proc(checker: ^Checker, value: Ct_Value, span: source.Span
|
||||
})
|
||||
}
|
||||
if value.kind == .Function {
|
||||
return build_function_value(checker, ast.Function_Id(u32(value.index)), span, expected)
|
||||
value_expected := expected if types.is_valid(expected) else value.type
|
||||
return build_function_value(checker, ast.Function_Id(u32(value.index)), span, value_expected)
|
||||
}
|
||||
if value.kind == .Array || value.kind == .Struct || value.kind == .Range {
|
||||
children := ct_child_slice(&checker.static_state, value)
|
||||
@@ -1174,6 +1175,38 @@ is_runtime_type :: proc(checker: ^Checker, value: types.Type) -> bool {
|
||||
return types.is_runtime_value(value, &checker.module.types)
|
||||
}
|
||||
|
||||
is_comptime_value_type :: proc(checker: ^Checker, value: types.Type, depth := 0) -> bool {
|
||||
if depth > 256 || !types.is_valid(value) {
|
||||
return false
|
||||
}
|
||||
if is_runtime_type(checker, value) {
|
||||
return true
|
||||
}
|
||||
item, ok := types.node(&checker.module.types, value)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if item.kind == .Function {
|
||||
return true
|
||||
}
|
||||
if item.kind == .Array || item.kind == .Optional || item.kind == .Alias || item.kind == .Distinct {
|
||||
return is_comptime_value_type(checker, item.child, depth+1)
|
||||
}
|
||||
if item.kind == .Struct || item.kind == .Union {
|
||||
if !item.declared || item.opaque || item.c_layout ||
|
||||
(item.kind == .Union && !types.is_tagged_union(value, &checker.module.types)) {
|
||||
return false
|
||||
}
|
||||
for field in types.fields_for(&checker.module.types, value) {
|
||||
if !types.is_void(field.type) && !is_comptime_value_type(checker, field.type, depth+1) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
is_undefined_expr :: proc(checker: ^Checker, expr_id: ast.Expr_Id) -> bool {
|
||||
if expr_id == ast.INVALID_EXPR || int(expr_id) >= len(checker.ast_module.exprs) {
|
||||
return false
|
||||
@@ -2006,7 +2039,7 @@ call_mapping_semantically_valid :: proc(
|
||||
break
|
||||
}
|
||||
}
|
||||
if !is_runtime_type(checker, actual) {
|
||||
if !is_runtime_type(checker, actual) && !can_implicitly_convert_type(checker, actual, declared) {
|
||||
return false, fmt.aprintf(
|
||||
"argument %d is not a runtime value", source_index+1,
|
||||
allocator=checker.allocator,
|
||||
@@ -2814,7 +2847,7 @@ resolve_generated_struct_type :: proc(checker: ^Checker, expr_id: ast.Expr_Id, p
|
||||
defer delete(fields, checker.allocator)
|
||||
for field, index in template_fields {
|
||||
resolved := type_from_syntax(checker, field.type, pkg, file)
|
||||
if !is_runtime_type(checker, resolved) || types.is_void(resolved) {
|
||||
if (!is_runtime_type(checker, resolved) && !is_comptime_value_type(checker, resolved)) || types.is_void(resolved) {
|
||||
if expr.tuple {
|
||||
source.addf(checker.diagnostics, expr.span, "tuple element %d requires a concrete runtime type, got %s", index, type_label(checker, resolved))
|
||||
} else {
|
||||
@@ -3112,7 +3145,7 @@ function_value_signature :: proc(
|
||||
return params, result, true
|
||||
}
|
||||
|
||||
function_pointer_type_for_template :: proc(
|
||||
function_type_for_template :: proc(
|
||||
checker: ^Checker,
|
||||
template: ast.Function_Id,
|
||||
demanded: ^[dynamic]Spec_Id = nil,
|
||||
@@ -3125,7 +3158,6 @@ function_pointer_type_for_template :: proc(
|
||||
defer delete(params, checker.allocator)
|
||||
function := checker.ast_module.functions[template]
|
||||
function_type := types.function(&checker.module.types, params, result, function.c_abi, function.variadic)
|
||||
pointer_type := types.pointer(&checker.module.types, function_type, false, false)
|
||||
spec := INVALID_SPEC
|
||||
if demanded == nil {
|
||||
if demand_spec {
|
||||
@@ -3137,7 +3169,40 @@ function_pointer_type_for_template :: proc(
|
||||
spec = find_spec(checker, template, params)
|
||||
mark_spec_demanded(checker, spec, demanded)
|
||||
}
|
||||
return pointer_type, spec, spec != INVALID_SPEC || !demand_spec
|
||||
return function_type, spec, spec != INVALID_SPEC || !demand_spec
|
||||
}
|
||||
|
||||
function_pointer_type_for_template :: proc(
|
||||
checker: ^Checker,
|
||||
template: ast.Function_Id,
|
||||
demanded: ^[dynamic]Spec_Id = nil,
|
||||
demand_spec := true,
|
||||
) -> (types.Type, Spec_Id, bool) {
|
||||
function_type, spec, ok := function_type_for_template(checker, template, demanded, demand_spec)
|
||||
if !ok {
|
||||
return types.INVALID, spec, false
|
||||
}
|
||||
return types.pointer(&checker.module.types, function_type, false, false), spec, true
|
||||
}
|
||||
|
||||
function_expr_type_for_template :: proc(
|
||||
checker: ^Checker,
|
||||
template: ast.Function_Id,
|
||||
expected: types.Type,
|
||||
demanded: ^[dynamic]Spec_Id = nil,
|
||||
) -> (types.Type, bool) {
|
||||
function_type, _, ok := function_type_for_template(checker, template, demanded)
|
||||
if !ok {
|
||||
return types.INVALID, false
|
||||
}
|
||||
pointer_expected := expected
|
||||
if types.is_optional(pointer_expected, &checker.module.types) {
|
||||
pointer_expected = types.child_type(pointer_expected, &checker.module.types)
|
||||
}
|
||||
if types.can_coerce_function_pointer(function_type, pointer_expected, &checker.module.types) {
|
||||
return pointer_expected, true
|
||||
}
|
||||
return function_type, true
|
||||
}
|
||||
|
||||
contains_name :: proc(names: []symbol.Id, name: symbol.Id) -> bool {
|
||||
@@ -3358,7 +3423,7 @@ validate_declarations :: proc(checker: ^Checker) {
|
||||
)
|
||||
}
|
||||
if !is_type_metatype_syntax(checker, param.type) &&
|
||||
!is_runtime_type(checker, param_type) && param_type != types.RANGE {
|
||||
!is_comptime_value_type(checker, param_type) && param_type != types.RANGE {
|
||||
checker.template_diagnostics[function_id] = source.addf(
|
||||
checker.diagnostics,
|
||||
param.span,
|
||||
@@ -3366,6 +3431,13 @@ validate_declarations :: proc(checker: ^Checker) {
|
||||
symbol_text(checker, param.name),
|
||||
)
|
||||
}
|
||||
} else if !has_comptime && !signature_poisoned && types.is_comptime_only(param_type, &checker.module.types) {
|
||||
checker.template_diagnostics[function_id] = source.addf(
|
||||
checker.diagnostics,
|
||||
param.span,
|
||||
"parameter '%s' has a comptime-only type; prefix it with '$'",
|
||||
symbol_text(checker, param.name),
|
||||
)
|
||||
} else if !has_comptime && !signature_poisoned {
|
||||
if diagnostic := add_unsupported_type_diagnostic(checker, param.span, param_type);
|
||||
diagnostic != source.INVALID_DIAGNOSTIC {
|
||||
@@ -3904,7 +3976,14 @@ validate_type_nodes :: proc(checker: ^Checker) {
|
||||
// not enter this state and retain the existing validation below.
|
||||
} else if comptime_meta {
|
||||
// Reflection metadata is compile-time-only and may contain `type`.
|
||||
} else if !types.is_runtime_value(field.type, &checker.module.types) {
|
||||
} else if item.c_layout && !types.is_runtime_value(field.type, &checker.module.types) {
|
||||
source.add(
|
||||
checker.diagnostics,
|
||||
source.Span{},
|
||||
"c_struct fields must have C-layout-compatible types",
|
||||
)
|
||||
} else if !types.is_runtime_value(field.type, &checker.module.types) &&
|
||||
!is_comptime_value_type(checker, field.type) {
|
||||
source.add(
|
||||
checker.diagnostics,
|
||||
source.Span{},
|
||||
@@ -4505,8 +4584,8 @@ infer_expr :: proc(
|
||||
_ = pop(&stack)
|
||||
case .Function_Literal:
|
||||
template := ast.Function_Id(u32(expr.integer))
|
||||
pointer_type, _, ok := function_pointer_type_for_template(checker, template, demanded)
|
||||
last = pointer_type if ok else types.INVALID
|
||||
function_type, ok := function_expr_type_for_template(checker, template, frame.expected, demanded)
|
||||
last = function_type if ok else types.INVALID
|
||||
_ = pop(&stack)
|
||||
case .Name:
|
||||
last = types.INVALID
|
||||
@@ -4614,9 +4693,9 @@ infer_expr :: proc(
|
||||
if template != ast.INVALID_FUNCTION &&
|
||||
len(checker.ast_module.functions[template].unsupported_reason) == 0 &&
|
||||
checker.template_diagnostics[template] == source.INVALID_DIAGNOSTIC {
|
||||
pointer_type, _, ok := function_pointer_type_for_template(checker, template, demanded)
|
||||
function_type, ok := function_expr_type_for_template(checker, template, frame.expected, demanded)
|
||||
if ok {
|
||||
last = pointer_type
|
||||
last = function_type
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4631,7 +4710,7 @@ infer_expr :: proc(
|
||||
case .Call:
|
||||
if expr.left != ast.INVALID_EXPR {
|
||||
callee_type := infer_nested_expr(checker, expr.left, locals, pkg, file, demanded, local_types)
|
||||
_, function_item, function_type, ok := types.function_pointer(callee_type, &checker.module.types)
|
||||
_, function_item, function_type, ok := types.callable_function(callee_type, &checker.module.types)
|
||||
if !ok {
|
||||
last = types.INVALID
|
||||
_ = pop(&stack)
|
||||
@@ -4732,7 +4811,7 @@ infer_expr :: proc(
|
||||
continue
|
||||
}
|
||||
if callee_type, handled := infer_qualified_value_field_type(checker, expr, locals, pkg, file, demanded); handled {
|
||||
_, function_item, function_type, ok := types.function_pointer(callee_type, &checker.module.types)
|
||||
_, function_item, function_type, ok := types.callable_function(callee_type, &checker.module.types)
|
||||
if !ok {
|
||||
last = types.INVALID
|
||||
_ = pop(&stack)
|
||||
@@ -4760,6 +4839,19 @@ infer_expr :: proc(
|
||||
callee_type := types.INVALID
|
||||
if !symbol.is_valid(expr.qualifier) {
|
||||
callee_type = find_infer_local(locals, expr.name)
|
||||
if !types.is_valid(callee_type) {
|
||||
if binding, ok := current_static_binding(checker, expr.name); ok {
|
||||
callee_type = binding.type
|
||||
if binding.value != INVALID_CT_VALUE && int(binding.value) < len(checker.static_state.values) {
|
||||
function_value := checker.static_state.values[binding.value]
|
||||
if function_value.kind == .Function {
|
||||
_, _, _ = function_pointer_type_for_template(
|
||||
checker, ast.Function_Id(u32(function_value.index)), demanded,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !types.is_valid(callee_type) {
|
||||
if value, ok := current_comptime_value(checker, expr.name); ok && value.kind == .Static {
|
||||
callee_type = value.type
|
||||
@@ -4780,7 +4872,7 @@ infer_expr :: proc(
|
||||
callee_type = checker.global_types[global]
|
||||
}
|
||||
}
|
||||
_, function_item, function_type, ok := types.function_pointer(callee_type, &checker.module.types)
|
||||
_, 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)
|
||||
@@ -6269,6 +6361,7 @@ can_implicitly_convert_type :: proc(checker: ^Checker, actual, expected: types.T
|
||||
types.can_coerce_c_integer(actual, expected, checker.target) ||
|
||||
types.can_coerce_c_scalar(actual, expected, checker.target) ||
|
||||
types.can_weaken_pointer(actual, expected, store) ||
|
||||
types.can_coerce_function_pointer(actual, expected, store) ||
|
||||
types.can_weaken_slice(actual, expected, store) ||
|
||||
types.can_decay_slice_c_string(actual, expected, store) ||
|
||||
types.can_decay_array_pointer(actual, expected, store) ||
|
||||
@@ -6297,6 +6390,13 @@ coerce_expr :: proc(
|
||||
if types.equal(actual, expected) {
|
||||
return expr_id
|
||||
}
|
||||
if types.can_coerce_function_pointer(actual, expected, &checker.module.types) {
|
||||
expr := checker.module.exprs[expr_id]
|
||||
if expr.kind == .Function {
|
||||
expr.type = expected
|
||||
return add_hir_expr(checker, expr)
|
||||
}
|
||||
}
|
||||
if types.can_weaken_pointer(actual, expected, &checker.module.types) {
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.Weaken_Pointer,
|
||||
@@ -6355,6 +6455,7 @@ coerce_expr :: proc(
|
||||
if types.is_optional(expected, &checker.module.types) {
|
||||
child := types.child_type(expected, &checker.module.types)
|
||||
if types.equal(actual, child) ||
|
||||
types.can_coerce_function_pointer(actual, child, &checker.module.types) ||
|
||||
types.can_widen(actual, child) ||
|
||||
types.can_coerce_c_integer(actual, child, checker.target) ||
|
||||
types.can_coerce_c_scalar(actual, child, checker.target) ||
|
||||
@@ -6933,14 +7034,16 @@ build_function_value :: proc(
|
||||
}
|
||||
defer delete(params, checker.allocator)
|
||||
function_type := types.function(&checker.module.types, params, result, function.c_abi, function.variadic)
|
||||
pointer_type := types.pointer(&checker.module.types, function_type, false, false)
|
||||
value_type := function_type
|
||||
expected_pointer := expected
|
||||
if types.is_optional(expected_pointer, &checker.module.types) {
|
||||
expected_pointer = types.child_type(expected_pointer, &checker.module.types)
|
||||
}
|
||||
if _, _, expected_function, ok := types.function_pointer(expected_pointer, &checker.module.types); ok &&
|
||||
types.equal(expected_function, function_type) {
|
||||
pointer_type = expected_pointer
|
||||
value_type = expected_pointer
|
||||
} else if types.equal(expected, function_type) {
|
||||
value_type = expected
|
||||
}
|
||||
spec := find_spec(checker, template, params)
|
||||
if spec == INVALID_SPEC {
|
||||
@@ -6950,14 +7053,14 @@ build_function_value :: proc(
|
||||
"could not resolve callback specialization of '%s'",
|
||||
symbol_text(checker, function.name),
|
||||
)
|
||||
return invalid_hir_expr(checker, span, id, pointer_type)
|
||||
return invalid_hir_expr(checker, span, id, value_type)
|
||||
}
|
||||
function_id := checker.specs[spec].hir_id
|
||||
assert(function_id != hir.INVALID_FUNCTION)
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.Function,
|
||||
span=span,
|
||||
type=pointer_type,
|
||||
type=value_type,
|
||||
target=hir.function_ref(function_id),
|
||||
left=hir.INVALID_EXPR,
|
||||
right=hir.INVALID_EXPR,
|
||||
@@ -7917,6 +8020,15 @@ build_expr :: proc(
|
||||
}
|
||||
expr := checker.ast_module.exprs[frame.expr]
|
||||
if frame.stage == 0 {
|
||||
if expr.kind == .Name || expr.kind == .Field || expr.kind == .Index || expr.kind == .Unwrap {
|
||||
if specialized, ok := try_build_specialization_expr(
|
||||
checker, frame.expr, frame.expected, pkg, file,
|
||||
); ok {
|
||||
last = specialized
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
}
|
||||
constant := Constant{}
|
||||
_, static_name := current_static_binding(checker, expr.name)
|
||||
if expr.kind != .Name || symbol.is_valid(expr.qualifier) || !static_name {
|
||||
@@ -8257,12 +8369,20 @@ build_expr :: proc(
|
||||
non_callable_global := false
|
||||
if !symbol.is_valid(expr.qualifier) {
|
||||
if local, ok := find_build_local(locals, expr.name); ok {
|
||||
if _, _, _, callable := types.function_pointer(local.type, &checker.module.types); callable {
|
||||
if _, _, _, callable := types.callable_function(local.type, &checker.module.types); callable {
|
||||
callee = build_local_expr(checker, local, expr.span)
|
||||
} else {
|
||||
non_callable = true
|
||||
}
|
||||
}
|
||||
if callee == hir.INVALID_EXPR && !non_callable {
|
||||
if binding, ok := current_static_binding(checker, expr.name); ok &&
|
||||
binding.value != INVALID_CT_VALUE && int(binding.value) < len(checker.static_state.values) {
|
||||
callee = build_static_value(
|
||||
checker, checker.static_state.values[binding.value], expr.span, binding.type,
|
||||
)
|
||||
}
|
||||
}
|
||||
if callee == hir.INVALID_EXPR && !non_callable {
|
||||
if value, ok := current_comptime_value(checker, expr.name);
|
||||
ok && value.kind == .Static && value.static_value != INVALID_CT_VALUE &&
|
||||
@@ -8275,7 +8395,7 @@ build_expr :: proc(
|
||||
}
|
||||
if callee == hir.INVALID_EXPR && !non_callable {
|
||||
if global := find_global(checker, expr.name, target_pkg, expr_lookup_file(expr, file)); global != ast.INVALID_GLOBAL {
|
||||
if _, _, _, callable := types.function_pointer(checker.global_types[global], &checker.module.types); callable {
|
||||
if _, _, _, callable := types.callable_function(checker.global_types[global], &checker.module.types); callable {
|
||||
callee = build_global_reference(checker, global, expr.span, global_reads)
|
||||
} else {
|
||||
non_callable = true
|
||||
@@ -8322,7 +8442,7 @@ build_expr :: proc(
|
||||
id := source.INVALID_DIAGNOSTIC
|
||||
if non_callable {
|
||||
id = add_call_resolution_diagnostic(checker, expr, target_pkg, file) if non_callable_global else
|
||||
source.add(checker.diagnostics, expr.span, "call target is not a function pointer")
|
||||
source.add(checker.diagnostics, expr.span, "call target is not callable")
|
||||
} else {
|
||||
id = add_unsupported_diagnostic(checker, expr.span, target_pkg, expr.name)
|
||||
if id == source.INVALID_DIAGNOSTIC {
|
||||
@@ -8333,10 +8453,10 @@ build_expr :: proc(
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
_, function_item, function_type, _ := types.function_pointer(checker.module.exprs[callee].type, &checker.module.types)
|
||||
_, function_item, function_type, _ := types.callable_function(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"
|
||||
message := "function expects at least %d arguments, got %d" if function_item.variadic else
|
||||
"function expects %d arguments, got %d"
|
||||
id := source.addf(checker.diagnostics, expr.span, message, function_item.field_count, len(expr.args))
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
@@ -8705,16 +8825,16 @@ build_expr :: proc(
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
_, function_item, function_type, ok := types.function_pointer(checker.module.exprs[callee].type, &checker.module.types)
|
||||
_, function_item, function_type, ok := types.callable_function(checker.module.exprs[callee].type, &checker.module.types)
|
||||
if !ok {
|
||||
id := source.add(checker.diagnostics, expr.span, "call target is not a function pointer")
|
||||
id := source.add(checker.diagnostics, expr.span, "call target is not callable")
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
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"
|
||||
message := "function expects at least %d arguments, got %d" if function_item.variadic else
|
||||
"function expects %d arguments, got %d"
|
||||
id := source.addf(checker.diagnostics, expr.span, message, function_item.field_count, len(expr.args))
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
@@ -8739,7 +8859,7 @@ build_expr :: proc(
|
||||
if frame.arg_index+1 < len(expr.args) {
|
||||
next := frame.arg_index+1
|
||||
callee_type := checker.module.exprs[frame.left].type
|
||||
_, function_item, function_type, _ := types.function_pointer(callee_type, &checker.module.types)
|
||||
_, function_item, function_type, _ := types.callable_function(callee_type, &checker.module.types)
|
||||
arg_expected := callable_arg_expected(function_type, function_item, &checker.module.types, next)
|
||||
if !is_runtime_type(checker, arg_expected) {
|
||||
arg_expected = types.INVALID
|
||||
@@ -8760,9 +8880,9 @@ build_expr :: proc(
|
||||
continue
|
||||
}
|
||||
callee_type := checker.module.exprs[frame.left].type
|
||||
_, function_item, function_type, ok := types.function_pointer(callee_type, &checker.module.types)
|
||||
_, function_item, function_type, ok := types.callable_function(callee_type, &checker.module.types)
|
||||
if !ok {
|
||||
id := source.add(checker.diagnostics, expr.span, "call target is not a function pointer")
|
||||
id := source.add(checker.diagnostics, expr.span, "call target is not callable")
|
||||
delete(stack[frame_index].built_args, checker.allocator)
|
||||
stack[frame_index].built_args = nil
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
@@ -8789,7 +8909,7 @@ build_expr :: proc(
|
||||
}
|
||||
result := function_item.child
|
||||
if !types.is_valid(result) {
|
||||
id := source.add(checker.diagnostics, expr.span, "could not resolve function pointer result type")
|
||||
id := source.add(checker.diagnostics, expr.span, "could not resolve callable result type")
|
||||
delete(stack[frame_index].built_args, checker.allocator)
|
||||
stack[frame_index].built_args = nil
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
@@ -9524,6 +9644,21 @@ build_block :: proc(
|
||||
value_type = types.INVALID
|
||||
}
|
||||
}
|
||||
if types.is_comptime_only(value_type, &checker.module.types) {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
statement.span,
|
||||
"local '%s' has a comptime-only type and cannot be stored at runtime",
|
||||
symbol_text(checker, statement.name),
|
||||
)
|
||||
append(&body, hir.stmt_id(len(checker.module.statements)))
|
||||
append(&checker.module.statements, hir.Stmt{
|
||||
kind = .Trap, span = statement.span, expr = hir.INVALID_EXPR,
|
||||
local = hir.INVALID_LOCAL, diagnostic = id,
|
||||
})
|
||||
ctx.problematic^ = true
|
||||
continue
|
||||
}
|
||||
if _, found := find_build_local(ctx.locals^[duplicate_start:], statement.name); found {
|
||||
id := source.addf(
|
||||
checker.diagnostics, statement.span,
|
||||
@@ -12145,6 +12280,14 @@ build_function :: proc(checker: ^Checker, id: Spec_Id) {
|
||||
signature_diagnostic := source.INVALID_DIAGNOSTIC
|
||||
unresolved_result := !types.is_void(spec.result) && !is_runtime_type(checker, spec.result)
|
||||
if unresolved_result {
|
||||
if types.is_comptime_only(spec.result, &checker.module.types) {
|
||||
signature_diagnostic = source.addf(
|
||||
checker.diagnostics,
|
||||
function.span,
|
||||
"function '%s' has a comptime-only result and cannot return it through the runtime ABI",
|
||||
symbol_text(checker, function.name),
|
||||
)
|
||||
}
|
||||
checker.specs[id].result = types.I64
|
||||
spec.result = types.I64
|
||||
}
|
||||
@@ -12554,12 +12697,22 @@ build_globals :: proc(checker: ^Checker) {
|
||||
expr = invalid_hir_expr(checker, global.span, diagnostic, global_type)
|
||||
}
|
||||
if diagnostic == source.INVALID_DIAGNOSTIC && !is_runtime_type(checker, global_type) {
|
||||
diagnostic = source.addf(
|
||||
checker.diagnostics,
|
||||
global.span,
|
||||
"could not resolve a concrete type for global '%s'",
|
||||
symbol_text(checker, global.name),
|
||||
)
|
||||
if types.is_comptime_only(global_type, &checker.module.types) ||
|
||||
types.is_comptime_only(declared, &checker.module.types) {
|
||||
diagnostic = source.addf(
|
||||
checker.diagnostics,
|
||||
global.span,
|
||||
"global '%s' has a comptime-only type and cannot be stored at runtime",
|
||||
symbol_text(checker, global.name),
|
||||
)
|
||||
} else {
|
||||
diagnostic = source.addf(
|
||||
checker.diagnostics,
|
||||
global.span,
|
||||
"could not resolve a concrete type for global '%s'",
|
||||
symbol_text(checker, global.name),
|
||||
)
|
||||
}
|
||||
global_type = types.I64
|
||||
expr = invalid_hir_expr(checker, global.span, diagnostic, global_type)
|
||||
}
|
||||
|
||||
@@ -624,9 +624,15 @@ ct_coerce_value :: proc(state: ^Ct_State, id: Ct_Value_Id, expected: types.Type,
|
||||
return ct_add_value(state, value), true
|
||||
}
|
||||
if value.kind == .Function {
|
||||
_, _, actual_function, actual_ok := types.function_pointer(value.type, store)
|
||||
actual_item, actual_ok := types.node(store, value.type)
|
||||
_, _, expected_function, expected_ok := types.function_pointer(expected, store)
|
||||
if actual_ok && expected_ok && types.equal(actual_function, expected_function) {
|
||||
if actual_ok && actual_item.kind == .Function && expected_ok &&
|
||||
types.equal(value.type, expected_function) {
|
||||
value.type = expected
|
||||
return ct_add_value(state, value), true
|
||||
}
|
||||
_, _, actual_function, actual_pointer := types.function_pointer(value.type, store)
|
||||
if actual_pointer && expected_ok && types.equal(actual_function, expected_function) {
|
||||
value.type = expected
|
||||
return ct_add_value(state, value), true
|
||||
}
|
||||
@@ -928,7 +934,8 @@ ct_materialize_value :: proc(
|
||||
}
|
||||
return invalid_hir_expr(checker, span, state.diagnostic, value.type)
|
||||
case .Function:
|
||||
return build_function_value(checker, ast.Function_Id(u32(value.index)), span, expected)
|
||||
value_expected := expected if types.is_valid(expected) else value.type
|
||||
return build_function_value(checker, ast.Function_Id(u32(value.index)), span, value_expected)
|
||||
case .None:
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.None, span=span, type=value.type,
|
||||
@@ -1076,16 +1083,20 @@ ct_eval_expr :: proc(
|
||||
if global == ast.INVALID_GLOBAL || int(global) >= len(checker.ast_module.globals) {
|
||||
template := find_template(checker, expr.name, target_pkg, expr_lookup_file(expr, state.file))
|
||||
if template != ast.INVALID_FUNCTION {
|
||||
pointer_type, _, function_ok := function_pointer_type_for_template(
|
||||
function_type, _, function_ok := function_type_for_template(
|
||||
checker,
|
||||
template,
|
||||
state.demanded,
|
||||
state.demanded != nil,
|
||||
)
|
||||
if function_ok {
|
||||
return ct_add_value(state, Ct_Value{
|
||||
kind=.Function, type=pointer_type, index=u64(template),
|
||||
}), ct_flow(.Normal), true
|
||||
id := ct_add_value(state, Ct_Value{
|
||||
kind=.Function, type=function_type, index=u64(template),
|
||||
})
|
||||
if types.is_valid(expected) {
|
||||
return ct_coerce_expr_value(state, id, expected, expr.span)
|
||||
}
|
||||
return id, ct_flow(.Normal), true
|
||||
}
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_failf(state, .Not_Comptime, expr.span, "function '%s' is not comptime-callable as a value", symbol_text(checker, expr.name))
|
||||
}
|
||||
@@ -1099,7 +1110,7 @@ ct_eval_expr :: proc(
|
||||
return ct_eval_expr(state, g.expr, global_expected, depth+1)
|
||||
case .Function_Literal:
|
||||
template := ast.Function_Id(u32(expr.integer))
|
||||
pointer_type, _, ok := function_pointer_type_for_template(
|
||||
function_type, _, ok := function_type_for_template(
|
||||
checker,
|
||||
template,
|
||||
state.demanded,
|
||||
@@ -1110,9 +1121,13 @@ ct_eval_expr :: proc(
|
||||
state, .Not_Comptime, expr.span, "function literal is not comptime-callable as a value",
|
||||
)
|
||||
}
|
||||
return ct_add_value(state, Ct_Value{
|
||||
kind=.Function, type=pointer_type, index=u64(template),
|
||||
}), ct_flow(.Normal), true
|
||||
id := ct_add_value(state, Ct_Value{
|
||||
kind=.Function, type=function_type, index=u64(template),
|
||||
})
|
||||
if types.is_valid(expected) {
|
||||
return ct_coerce_expr_value(state, id, expected, expr.span)
|
||||
}
|
||||
return id, ct_flow(.Normal), true
|
||||
case .Comptime:
|
||||
if expr.left != ast.INVALID_EXPR {
|
||||
return ct_eval_expr(state, expr.left, expected, depth+1)
|
||||
@@ -4164,3 +4179,27 @@ build_comptime_expr :: proc(
|
||||
}
|
||||
return invalid_hir_expr(checker, expr.span, diagnostic, expected)
|
||||
}
|
||||
|
||||
try_build_specialization_expr :: proc(
|
||||
checker: ^Checker,
|
||||
expr_id: ast.Expr_Id,
|
||||
expected: types.Type,
|
||||
pkg: ast.Package_Id,
|
||||
file: ast.File_Id,
|
||||
) -> (hir.Expr_Id, bool) {
|
||||
if len(checker.current_comptime_values) == 0 && len(checker.static_bindings) == 0 ||
|
||||
expr_id == ast.INVALID_EXPR || int(expr_id) >= len(checker.ast_module.exprs) {
|
||||
return hir.INVALID_EXPR, false
|
||||
}
|
||||
state := ct_state_make(checker, pkg, file, values=checker.current_comptime_values, diagnose=false)
|
||||
defer ct_state_destroy(&state)
|
||||
value, flow, ok := ct_eval_expr(&state, expr_id, expected, 0)
|
||||
if !ok || flow.kind != .Normal || value == INVALID_CT_VALUE || int(value) >= len(state.values) {
|
||||
return hir.INVALID_EXPR, false
|
||||
}
|
||||
static := state.values[value]
|
||||
if static.kind != .Function {
|
||||
return hir.INVALID_EXPR, false
|
||||
}
|
||||
return ct_materialize_value(&state, value, checker.ast_module.exprs[expr_id].span, expected), true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user