mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Fix #1888
This commit is contained in:
+6
-2
@@ -8643,6 +8643,8 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
Ast *first_arg = x.expr->SelectorExpr.expr;
|
Ast *first_arg = x.expr->SelectorExpr.expr;
|
||||||
GB_ASSERT(first_arg != nullptr);
|
GB_ASSERT(first_arg != nullptr);
|
||||||
|
|
||||||
|
first_arg->state_flags |= StateFlag_SelectorCallExpr;
|
||||||
|
|
||||||
Type *pt = base_type(x.type);
|
Type *pt = base_type(x.type);
|
||||||
GB_ASSERT(pt->kind == Type_Proc);
|
GB_ASSERT(pt->kind == Type_Proc);
|
||||||
Type *first_type = nullptr;
|
Type *first_type = nullptr;
|
||||||
@@ -8668,6 +8670,7 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
y.mode = first_arg->tav.mode;
|
y.mode = first_arg->tav.mode;
|
||||||
y.type = first_arg->tav.type;
|
y.type = first_arg->tav.type;
|
||||||
y.value = first_arg->tav.value;
|
y.value = first_arg->tav.value;
|
||||||
|
|
||||||
if (check_is_assignable_to(c, &y, first_type)) {
|
if (check_is_assignable_to(c, &y, first_type)) {
|
||||||
// Do nothing, it's valid
|
// Do nothing, it's valid
|
||||||
} else {
|
} else {
|
||||||
@@ -10034,9 +10037,10 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
|
|||||||
str = write_expr_to_string(str, ce->proc, shorthand);
|
str = write_expr_to_string(str, ce->proc, shorthand);
|
||||||
str = gb_string_appendc(str, "(");
|
str = gb_string_appendc(str, "(");
|
||||||
|
|
||||||
for_array(i, ce->args) {
|
isize idx0 = cast(isize)ce->was_selector;
|
||||||
|
for (isize i = idx0; i < ce->args.count; i++) {
|
||||||
Ast *arg = ce->args[i];
|
Ast *arg = ce->args[i];
|
||||||
if (i > 0) {
|
if (i > idx0) {
|
||||||
str = gb_string_appendc(str, ", ");
|
str = gb_string_appendc(str, ", ");
|
||||||
}
|
}
|
||||||
str = write_expr_to_string(str, arg, shorthand);
|
str = write_expr_to_string(str, arg, shorthand);
|
||||||
|
|||||||
@@ -292,6 +292,8 @@ struct lbProcedure {
|
|||||||
LLVMMetadataRef debug_info;
|
LLVMMetadataRef debug_info;
|
||||||
|
|
||||||
lbCopyElisionHint copy_elision_hint;
|
lbCopyElisionHint copy_elision_hint;
|
||||||
|
|
||||||
|
PtrMap<Ast *, lbValue> selector_values;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+28
-10
@@ -2993,9 +2993,8 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
|
|||||||
return lb_build_addr_ptr(p, ue->expr);
|
return lb_build_addr_ptr(p, ue->expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr);
|
||||||
lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||||
lbModule *m = p->module;
|
|
||||||
|
|
||||||
u16 prev_state_flags = p->state_flags;
|
u16 prev_state_flags = p->state_flags;
|
||||||
defer (p->state_flags = prev_state_flags);
|
defer (p->state_flags = prev_state_flags);
|
||||||
|
|
||||||
@@ -3022,6 +3021,32 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
|||||||
p->state_flags = out;
|
p->state_flags = out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// IMPORTANT NOTE(bill):
|
||||||
|
// Selector Call Expressions (foo->bar(...))
|
||||||
|
// must only evaluate `foo` once as it gets transformed into
|
||||||
|
// `foo.bar(foo, ...)`
|
||||||
|
// And if `foo` is a procedure call or something more complex, storing the value
|
||||||
|
// once is a very good idea
|
||||||
|
// If a stored value is found, it must be removed from the cache
|
||||||
|
if (expr->state_flags & StateFlag_SelectorCallExpr) {
|
||||||
|
lbValue *pp = map_get(&p->selector_values, expr);
|
||||||
|
if (pp != nullptr) {
|
||||||
|
lbValue res = *pp;
|
||||||
|
map_remove(&p->selector_values, expr);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lbValue res = lb_build_expr_internal(p, expr);
|
||||||
|
if (expr->state_flags & StateFlag_SelectorCallExpr) {
|
||||||
|
map_set(&p->selector_values, expr, res);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||||
|
lbModule *m = p->module;
|
||||||
|
|
||||||
expr = unparen_expr(expr);
|
expr = unparen_expr(expr);
|
||||||
|
|
||||||
TokenPos expr_pos = ast_token(expr).pos;
|
TokenPos expr_pos = ast_token(expr).pos;
|
||||||
@@ -3119,14 +3144,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
|||||||
|
|
||||||
case_ast_node(se, SelectorCallExpr, expr);
|
case_ast_node(se, SelectorCallExpr, expr);
|
||||||
GB_ASSERT(se->modified_call);
|
GB_ASSERT(se->modified_call);
|
||||||
TypeAndValue tav = type_and_value_of_expr(expr);
|
return lb_build_call_expr(p, se->call);
|
||||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
|
||||||
lbValue res = lb_build_call_expr(p, se->call);
|
|
||||||
|
|
||||||
ast_node(ce, CallExpr, se->call);
|
|
||||||
ce->sce_temp_data = gb_alloc_copy(permanent_allocator(), &res, gb_size_of(res));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(te, TernaryIfExpr, expr);
|
case_ast_node(te, TernaryIfExpr, expr);
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
|||||||
p->branch_blocks.allocator = a;
|
p->branch_blocks.allocator = a;
|
||||||
p->context_stack.allocator = a;
|
p->context_stack.allocator = a;
|
||||||
p->scope_stack.allocator = a;
|
p->scope_stack.allocator = a;
|
||||||
|
map_init(&p->selector_values, a);
|
||||||
|
|
||||||
if (p->is_foreign) {
|
if (p->is_foreign) {
|
||||||
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
||||||
@@ -2832,10 +2833,6 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
|
|||||||
expr = unparen_expr(expr);
|
expr = unparen_expr(expr);
|
||||||
ast_node(ce, CallExpr, expr);
|
ast_node(ce, CallExpr, expr);
|
||||||
|
|
||||||
if (ce->sce_temp_data) {
|
|
||||||
return *(lbValue *)ce->sce_temp_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
lbValue res = lb_build_call_expr_internal(p, expr);
|
lbValue res = lb_build_call_expr_internal(p, expr);
|
||||||
|
|
||||||
if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures
|
if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ Ast *clone_ast(Ast *node) {
|
|||||||
case Ast_SelectorCallExpr:
|
case Ast_SelectorCallExpr:
|
||||||
n->SelectorCallExpr.expr = clone_ast(n->SelectorCallExpr.expr);
|
n->SelectorCallExpr.expr = clone_ast(n->SelectorCallExpr.expr);
|
||||||
n->SelectorCallExpr.call = clone_ast(n->SelectorCallExpr.call);
|
n->SelectorCallExpr.call = clone_ast(n->SelectorCallExpr.call);
|
||||||
|
GB_ASSERT(n->SelectorCallExpr.modified_call);
|
||||||
break;
|
break;
|
||||||
case Ast_IndexExpr:
|
case Ast_IndexExpr:
|
||||||
n->IndexExpr.expr = clone_ast(n->IndexExpr.expr);
|
n->IndexExpr.expr = clone_ast(n->IndexExpr.expr);
|
||||||
|
|||||||
+3
-1
@@ -282,6 +282,8 @@ enum StateFlag : u8 {
|
|||||||
StateFlag_type_assert = 1<<2,
|
StateFlag_type_assert = 1<<2,
|
||||||
StateFlag_no_type_assert = 1<<3,
|
StateFlag_no_type_assert = 1<<3,
|
||||||
|
|
||||||
|
StateFlag_SelectorCallExpr = 1<<6,
|
||||||
|
|
||||||
StateFlag_BeenHandled = 1<<7,
|
StateFlag_BeenHandled = 1<<7,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -411,7 +413,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
|||||||
Token ellipsis; \
|
Token ellipsis; \
|
||||||
ProcInlining inlining; \
|
ProcInlining inlining; \
|
||||||
bool optional_ok_one; \
|
bool optional_ok_one; \
|
||||||
void *sce_temp_data; \
|
bool was_selector; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
||||||
AST_KIND(EnumFieldValue, "enum field value", struct { \
|
AST_KIND(EnumFieldValue, "enum field value", struct { \
|
||||||
|
|||||||
Reference in New Issue
Block a user