aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/check_expr.cpp')
-rw-r--r--src/check_expr.cpp121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 968b6ec1e..1401793a5 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -3826,6 +3826,15 @@ gb_internal void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type,
update_untyped_expr_type(c, ore->expr, type, final);
case_end;
+ case_ast_node(obe, OrBranchExpr, e);
+ if (old->value.kind != ExactValue_Invalid) {
+ // See above note in UnaryExpr case
+ break;
+ }
+
+ update_untyped_expr_type(c, obe->expr, type, final);
+ case_end;
+
case_ast_node(oee, OrElseExpr, e);
if (old->value.kind != ExactValue_Invalid) {
// See above note in UnaryExpr case
@@ -8193,6 +8202,104 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no
return Expr_Expr;
}
+gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
+ ast_node(be, OrBranchExpr, node);
+
+ String name = be->token.string;
+ Operand x = {};
+ check_multi_expr_with_type_hint(c, &x, be->expr, type_hint);
+ if (x.mode == Addressing_Invalid) {
+ o->mode = Addressing_Value;
+ o->type = t_invalid;
+ o->expr = node;
+ return Expr_Expr;
+ }
+
+ Type *left_type = nullptr;
+ Type *right_type = nullptr;
+ check_or_return_split_types(c, &x, name, &left_type, &right_type);
+ add_type_and_value(c, be->expr, x.mode, x.type, x.value);
+
+ if (right_type == nullptr) {
+ check_or_else_expr_no_value_error(c, name, x, type_hint);
+ } else {
+ if (is_type_boolean(right_type) || type_has_nil(right_type)) {
+ // okay
+ } else {
+ gbString s = type_to_string(right_type);
+ error(node, "'%.*s' requires a boolean or nil-able type, got %s", s);
+ gb_string_free(s);
+ }
+ }
+
+ o->expr = node;
+ o->type = left_type;
+ if (left_type != nullptr) {
+ o->mode = Addressing_Value;
+ } else {
+ o->mode = Addressing_NoValue;
+ }
+
+ if (c->curr_proc_sig == nullptr) {
+ error(node, "'%.*s' can only be used within a procedure", LIT(name));
+ }
+
+ Ast *label = be->label;
+
+ switch (be->token.kind) {
+ case Token_or_break:
+ if ((c->stmt_flags & Stmt_BreakAllowed) == 0 && label == nullptr) {
+ error(be->token, "'%.*s' only allowed in non-inline loops or 'switch' statements", LIT(name));
+ }
+ break;
+ case Token_or_continue:
+ if ((c->stmt_flags & Stmt_ContinueAllowed) == 0 && label == nullptr) {
+ error(be->token, "'%.*s' only allowed in non-inline loops", LIT(name));
+ }
+ break;
+ }
+
+ if (label != nullptr) {
+ if (label->kind != Ast_Ident) {
+ error(label, "A branch statement's label name must be an identifier");
+ return Expr_Expr;
+ }
+ Ast *ident = label;
+ String name = ident->Ident.token.string;
+ Operand o = {};
+ Entity *e = check_ident(c, &o, ident, nullptr, nullptr, false);
+ if (e == nullptr) {
+ error(ident, "Undeclared label name: %.*s", LIT(name));
+ return Expr_Expr;
+ }
+ add_entity_use(c, ident, e);
+ if (e->kind != Entity_Label) {
+ error(ident, "'%.*s' is not a label", LIT(name));
+ return Expr_Expr;
+ }
+ Ast *parent = e->Label.parent;
+ GB_ASSERT(parent != nullptr);
+ switch (parent->kind) {
+ case Ast_BlockStmt:
+ case Ast_IfStmt:
+ case Ast_SwitchStmt:
+ if (be->token.kind != Token_or_break) {
+ error(label, "Label '%.*s' can only be used with 'or_break'", LIT(e->token.string));
+ }
+ break;
+ case Ast_RangeStmt:
+ case Ast_ForStmt:
+ if ((be->token.kind != Token_or_break) && (be->token.kind != Token_or_continue)) {
+ error(label, "Label '%.*s' can only be used with 'or_break' and 'or_continue'", LIT(e->token.string));
+ }
+ break;
+
+ }
+ }
+
+ return Expr_Expr;
+}
+
gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<Ast *> const &elems, Operand *o, Type *type, bool &is_constant) {
Type *bt = base_type(type);
@@ -9947,6 +10054,10 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
return check_or_return_expr(c, o, node, type_hint);
case_end;
+ case_ast_node(re, OrBranchExpr, node);
+ return check_or_branch_expr(c, o, node, type_hint);
+ case_end;
+
case_ast_node(cl, CompoundLit, node);
kind = check_compound_literal(c, o, node, type_hint);
case_end;
@@ -10513,6 +10624,16 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
str = gb_string_appendc(str, " or_return");
case_end;
+ case_ast_node(oe, OrBranchExpr, node);
+ str = write_expr_to_string(str, oe->expr, shorthand);
+ str = gb_string_append_rune(str, ' ');
+ str = string_append_token(str, oe->token);
+ if (oe->label) {
+ str = gb_string_append_rune(str, ' ');
+ str = write_expr_to_string(str, oe->label, shorthand);
+ }
+ case_end;
+
case_ast_node(pe, ParenExpr, node);
str = gb_string_append_rune(str, '(');
str = write_expr_to_string(str, pe->expr, shorthand);