mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Allow switch &v in ... work to be consistent with for &e in ...
This commit is contained in:
+33
-1
@@ -2246,6 +2246,33 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) {
|
|||||||
return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable;
|
return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal void check_old_for_or_switch_value_usage(Ast *expr) {
|
||||||
|
Entity *e = entity_of_node(expr);
|
||||||
|
if (e != nullptr && (e->flags & EntityFlag_OldForOrSwitchValue) != 0) {
|
||||||
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
|
|
||||||
|
begin_error_block();
|
||||||
|
defer (end_error_block());
|
||||||
|
|
||||||
|
if ((e->flags & EntityFlag_ForValue) != 0) {
|
||||||
|
Type *parent_type = type_deref(e->Variable.for_loop_parent_type);
|
||||||
|
|
||||||
|
error(expr, "Assuming a for-in defined value is addressable as the iterable is passed by value has been disallowed with '-strict-style'.");
|
||||||
|
|
||||||
|
if (is_type_map(parent_type)) {
|
||||||
|
error_line("\tSuggestion: Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string));
|
||||||
|
} else {
|
||||||
|
error_line("\tSuggestion: Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GB_ASSERT((e->flags & EntityFlag_SwitchValue) != 0);
|
||||||
|
|
||||||
|
error(expr, "Assuming a switch-in defined value is addressable as the iterable is passed by value has been disallowed with '-strict-style'.");
|
||||||
|
error_line("\tSuggestion: Prefer doing 'switch &%.*s in ...'\n", LIT(e->token.string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
|
gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
|
||||||
switch (op.kind) {
|
switch (op.kind) {
|
||||||
case Token_And: { // Pointer address
|
case Token_And: { // Pointer address
|
||||||
@@ -2255,7 +2282,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
|
|||||||
gbString str = expr_to_string(ue->expr);
|
gbString str = expr_to_string(ue->expr);
|
||||||
defer (gb_string_free(str));
|
defer (gb_string_free(str));
|
||||||
|
|
||||||
Entity *e = entity_of_node(o->expr);
|
Entity *e = entity_of_node(ue->expr);
|
||||||
if (e != nullptr && (e->flags & EntityFlag_Param) != 0) {
|
if (e != nullptr && (e->flags & EntityFlag_Param) != 0) {
|
||||||
error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str);
|
error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str);
|
||||||
} else {
|
} else {
|
||||||
@@ -2306,6 +2333,11 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
|
|||||||
o->type = alloc_type_pointer(o->type);
|
o->type = alloc_type_pointer(o->type);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (build_context.strict_style && ast_node_expect(node, Ast_UnaryExpr)) {
|
||||||
|
ast_node(ue, UnaryExpr, node);
|
||||||
|
check_old_for_or_switch_value_usage(ue->expr);
|
||||||
|
}
|
||||||
|
|
||||||
o->type = alloc_type_pointer(o->type);
|
o->type = alloc_type_pointer(o->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-3
@@ -417,6 +417,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
case Addressing_Variable:
|
case Addressing_Variable:
|
||||||
|
check_old_for_or_switch_value_usage(lhs->expr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Addressing_MapIndex: {
|
case Addressing_MapIndex: {
|
||||||
@@ -1141,8 +1142,14 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
|
|||||||
syntax_error(as_token, "Expected 1 expression after 'in'");
|
syntax_error(as_token, "Expected 1 expression after 'in'");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
bool is_addressed = false;
|
||||||
|
|
||||||
Ast *lhs = as->lhs[0];
|
Ast *lhs = as->lhs[0];
|
||||||
Ast *rhs = as->rhs[0];
|
Ast *rhs = as->rhs[0];
|
||||||
|
if (lhs->kind == Ast_UnaryExpr && lhs->UnaryExpr.op.kind == Token_And) {
|
||||||
|
is_addressed = true;
|
||||||
|
lhs = lhs->UnaryExpr.expr;
|
||||||
|
}
|
||||||
|
|
||||||
check_expr(ctx, &x, rhs);
|
check_expr(ctx, &x, rhs);
|
||||||
check_assignment(ctx, &x, nullptr, str_lit("type switch expression"));
|
check_assignment(ctx, &x, nullptr, str_lit("type switch expression"));
|
||||||
@@ -1281,12 +1288,15 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_reference = false;
|
bool is_reference = is_addressed;
|
||||||
|
bool old_style = false;
|
||||||
|
|
||||||
if (is_ptr &&
|
if (!is_reference &&
|
||||||
|
is_ptr &&
|
||||||
cc->list.count == 1 &&
|
cc->list.count == 1 &&
|
||||||
case_type != nullptr) {
|
case_type != nullptr) {
|
||||||
is_reference = true;
|
is_reference = true;
|
||||||
|
old_style = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cc->list.count > 1 || saw_nil) {
|
if (cc->list.count > 1 || saw_nil) {
|
||||||
@@ -1305,9 +1315,12 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
|
|||||||
{
|
{
|
||||||
Entity *tag_var = alloc_entity_variable(ctx->scope, lhs->Ident.token, case_type, EntityState_Resolved);
|
Entity *tag_var = alloc_entity_variable(ctx->scope, lhs->Ident.token, case_type, EntityState_Resolved);
|
||||||
tag_var->flags |= EntityFlag_Used;
|
tag_var->flags |= EntityFlag_Used;
|
||||||
|
tag_var->flags |= EntityFlag_SwitchValue;
|
||||||
if (!is_reference) {
|
if (!is_reference) {
|
||||||
tag_var->flags |= EntityFlag_Value;
|
tag_var->flags |= EntityFlag_Value;
|
||||||
tag_var->flags |= EntityFlag_SwitchValue;
|
}
|
||||||
|
if (old_style) {
|
||||||
|
tag_var->flags |= EntityFlag_OldForOrSwitchValue;
|
||||||
}
|
}
|
||||||
add_entity(ctx, ctx->scope, lhs, tag_var);
|
add_entity(ctx, ctx->scope, lhs, tag_var);
|
||||||
add_entity_use(ctx, lhs, tag_var);
|
add_entity_use(ctx, lhs, tag_var);
|
||||||
@@ -1683,6 +1696,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
|||||||
error(token, "The %s variable '%.*s' cannot be made addressable", idx_name, LIT(str));
|
error(token, "The %s variable '%.*s' cannot be made addressable", idx_name, LIT(str));
|
||||||
}
|
}
|
||||||
} else if (i == addressable_index && use_by_reference_for_value) {
|
} else if (i == addressable_index && use_by_reference_for_value) {
|
||||||
|
entity->flags |= EntityFlag_OldForOrSwitchValue;
|
||||||
entity->flags &= ~EntityFlag_Value;
|
entity->flags &= ~EntityFlag_Value;
|
||||||
}
|
}
|
||||||
if (is_soa) {
|
if (is_soa) {
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ enum EntityFlag : u64 {
|
|||||||
EntityFlag_Require = 1ull<<50,
|
EntityFlag_Require = 1ull<<50,
|
||||||
EntityFlag_ByPtr = 1ull<<51, // enforce parameter is passed by pointer
|
EntityFlag_ByPtr = 1ull<<51, // enforce parameter is passed by pointer
|
||||||
|
|
||||||
|
EntityFlag_OldForOrSwitchValue = 1ull<<52,
|
||||||
|
|
||||||
EntityFlag_Overridden = 1ull<<63,
|
EntityFlag_Overridden = 1ull<<63,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user