feat: infer complete ptrcast target types
This commit is contained in:
@@ -934,6 +934,30 @@ valid_ptrcast_child :: proc(checker: ^Checker, value: types.Type) -> bool {
|
||||
types.is_opaque_struct(value, &checker.module.types))
|
||||
}
|
||||
|
||||
ptrcast_target_child :: proc(checker: ^Checker, value: types.Type) -> (types.Type, bool) {
|
||||
item, ok := types.node(&checker.module.types, types.resolve_alias(value, &checker.module.types))
|
||||
if !ok {
|
||||
return types.INVALID, false
|
||||
}
|
||||
if item.kind == .Optional {
|
||||
item, ok = types.node(&checker.module.types, types.resolve_alias(item.child, &checker.module.types))
|
||||
}
|
||||
if !ok || item.kind != .Pointer || !valid_ptrcast_child(checker, item.child) {
|
||||
return types.INVALID, false
|
||||
}
|
||||
return item.child, true
|
||||
}
|
||||
|
||||
ptrcast_retyped_source :: proc(checker: ^Checker, source, target: types.Type) -> (types.Type, bool) {
|
||||
child, child_ok := ptrcast_target_child(checker, target)
|
||||
if !child_ok {
|
||||
return types.INVALID, false
|
||||
}
|
||||
retyped, retyped_ok := types.replace_pointer_child(&checker.module.types, source, child)
|
||||
return retyped, retyped_ok &&
|
||||
can_implicitly_convert_type(checker, retyped, target)
|
||||
}
|
||||
|
||||
valid_layout_type :: proc(checker: ^Checker, value: types.Type) -> bool {
|
||||
return types.is_runtime_value(value, &checker.module.types)
|
||||
}
|
||||
@@ -5655,18 +5679,20 @@ infer_expr :: proc(
|
||||
continue
|
||||
}
|
||||
if is_ptrcast_call(checker, expr) {
|
||||
if len(expr.args) != 2 {
|
||||
if len(expr.args) != 1 && len(expr.args) != 2 {
|
||||
last = types.INVALID
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
child, child_ok := resolve_type_argument(checker, expr.args[0], pkg, file)
|
||||
operand := infer_nested_expr(checker, expr.args[1], locals, pkg, file, demanded, local_types)
|
||||
result := types.INVALID
|
||||
if child_ok && valid_ptrcast_child(checker, child) {
|
||||
result, _ = types.replace_pointer_child(&checker.module.types, operand, child)
|
||||
target := frame.expected
|
||||
operand_index := 0
|
||||
if len(expr.args) == 2 {
|
||||
target, _ = resolve_type_argument(checker, expr.args[0], pkg, file)
|
||||
operand_index = 1
|
||||
}
|
||||
last = result
|
||||
operand := infer_nested_expr(checker, expr.args[operand_index], locals, pkg, file, demanded, local_types)
|
||||
_, target_ok := ptrcast_retyped_source(checker, operand, target)
|
||||
last = target if target_ok else types.INVALID
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
@@ -9802,28 +9828,39 @@ build_expr :: proc(
|
||||
continue
|
||||
}
|
||||
if is_ptrcast_call(checker, expr) {
|
||||
if len(expr.args) != 2 {
|
||||
id := source.addf(checker.diagnostics, expr.span, "ptrcast! expects 2 arguments, got %d", len(expr.args))
|
||||
if len(expr.args) != 1 && len(expr.args) != 2 {
|
||||
id := source.addf(checker.diagnostics, expr.span, "ptrcast! expects 1 or 2 arguments, got %d", len(expr.args))
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
target, target_ok := resolve_type_argument(checker, expr.args[0], pkg, file)
|
||||
if !target_ok {
|
||||
id := source.add(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "ptrcast! target must be a type")
|
||||
target := frame.expected
|
||||
operand_index := 0
|
||||
if len(expr.args) == 2 {
|
||||
target_ok: bool
|
||||
target, target_ok = resolve_type_argument(checker, expr.args[0], pkg, file)
|
||||
if !target_ok {
|
||||
id := source.add(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "ptrcast! target must be a type")
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
operand_index = 1
|
||||
} else if !types.is_valid(target) {
|
||||
id := source.add(checker.diagnostics, expr.span, "cannot infer ptrcast! target type; pass a pointer type explicitly")
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if !valid_ptrcast_child(checker, target) {
|
||||
id := source.addf(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "ptrcast! target must be a sized runtime object type, got %s", type_label(checker, target))
|
||||
if _, target_ok := ptrcast_target_child(checker, target); !target_ok {
|
||||
id := source.addf(checker.diagnostics, expr.span, "ptrcast! target must be a pointer or optional pointer to a sized runtime object type, got %s", type_label(checker, target))
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
stack[frame_index].target_type = target
|
||||
stack[frame_index].stage = 9
|
||||
append(&stack, Build_Expr_Frame{expr=expr.args[1], expected=types.INVALID, template=ast.INVALID_FUNCTION})
|
||||
append(&stack, Build_Expr_Frame{expr=expr.args[operand_index], expected=types.INVALID, template=ast.INVALID_FUNCTION})
|
||||
continue
|
||||
}
|
||||
if is_intrinsic_call(checker, expr, "constcast") {
|
||||
@@ -10556,20 +10593,30 @@ build_expr :: proc(
|
||||
_ = pop(&stack)
|
||||
}
|
||||
if frame.stage == 9 {
|
||||
result, ok := types.replace_pointer_child(&checker.module.types, checker.module.exprs[last].type, frame.target_type)
|
||||
if !ok {
|
||||
actual := checker.module.exprs[last].type
|
||||
retyped, ok := ptrcast_retyped_source(checker, actual, frame.target_type)
|
||||
if !types.is_pointer(actual, &checker.module.types) &&
|
||||
!types.is_optional_pointer(actual, &checker.module.types) {
|
||||
id := source.add(checker.diagnostics, expr.span, "ptrcast! operand must be a pointer or optional pointer")
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
} else if !ok {
|
||||
id := source.addf(
|
||||
checker.diagnostics, expr.span,
|
||||
"ptrcast! cannot convert pointer shape from %s to %s",
|
||||
type_label(checker, actual), type_label(checker, frame.target_type),
|
||||
)
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
} else {
|
||||
last = add_hir_expr(checker, hir.Expr{
|
||||
cast_expr := add_hir_expr(checker, hir.Expr{
|
||||
kind=.Pointer_Cast,
|
||||
span=expr.span,
|
||||
type=result,
|
||||
type=retyped,
|
||||
left=last,
|
||||
target=hir.INVALID_REF,
|
||||
right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
last = coerce_expr(checker, cast_expr, frame.target_type, expr.span)
|
||||
}
|
||||
_ = pop(&stack)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user