aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-04-19 16:02:36 +0100
committergingerBill <bill@gingerbill.org>2021-04-19 16:02:36 +0100
commit0eb75886d16307091d5379d53fac9a3cca8d5a7d (patch)
tree7d4df5b8c28bd41b0917ae119b8e42200952b540 /src/check_expr.cpp
parent36125696240469d0adcb78caa8093f581debdcb2 (diff)
Allow assignment of procedure calls with `#optional_ok` to single values
Diffstat (limited to 'src/check_expr.cpp')
-rw-r--r--src/check_expr.cpp32
1 files changed, 23 insertions, 9 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index bf097580b..02a37c522 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -651,12 +651,26 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
}
Ast *expr = unparen_expr(operand->expr);
- if (expr != nullptr && expr->kind == Ast_AutoCast) {
- Operand x = *operand;
- x.expr = expr->AutoCast.expr;
- bool ok = check_cast_internal(c, &x, type);
- if (ok) {
- return MAXIMUM_TYPE_DISTANCE;
+ if (expr != nullptr) {
+ if (expr->kind == Ast_AutoCast) {
+ Operand x = *operand;
+ x.expr = expr->AutoCast.expr;
+ bool ok = check_cast_internal(c, &x, type);
+ if (ok) {
+ return MAXIMUM_TYPE_DISTANCE;
+ }
+ } else if (expr->kind == Ast_CallExpr) {
+ // NOTE(bill, 2021-04-19): Allow assignment of procedure calls with #optional_ok
+ ast_node(ce, CallExpr, expr);
+ Type *pt = base_type(type_of_expr(ce->proc));
+ if (pt->kind == Type_Proc && pt->Proc.optional_ok) {
+ Operand x = *operand;
+ x.type = pt->Proc.results->Tuple.variables[0]->type;
+ i64 res = check_distance_between_types(c, &x, type);
+ if (res >= 0) {
+ return res+1;
+ }
+ }
}
}
@@ -694,7 +708,7 @@ bool check_is_assignable_to(CheckerContext *c, Operand *operand, Type *type) {
return check_is_assignable_to_with_score(c, operand, type, &score);
}
-void add_optional_ok_for_procedure(Type *type, Operand *operand) {
+void add_optional_ok_for_procedure(Type *type, Operand *operand, Type *type_hint) {
type = base_type(type);
if (type->kind == Type_Proc && type->Proc.optional_ok) {
operand->mode = Addressing_OptionalOk;
@@ -757,7 +771,7 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
Entity *e = procs[i];
add_entity_use(c, operand->expr, e);
good = true;
- add_optional_ok_for_procedure(e->type, operand);
+ add_optional_ok_for_procedure(e->type, operand, type);
break;
}
}
@@ -8254,7 +8268,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr
if (type == nullptr) {
type = pt;
}
- add_optional_ok_for_procedure(type, operand);
+ add_optional_ok_for_procedure(type, operand, type_hint);
}
// add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value);