Skip to content

Commit 631c4d7

Browse files
gh-151: Fix PARFOR pointer writeback.
1 parent 03d7345 commit 631c4d7

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

src/builtins.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,36 @@ static bool writeback_first_ptr(Interpreter* interp, Expr** arg_nodes, Env* env,
8989
interp->error_col = col;
9090
return false;
9191
}
92+
/*
93+
* If this interpreter is running with isolated env writes (PARFOR
94+
* worker), ensure we create a local binding in the per-iteration
95+
* environment so writeback does not mutate parent bindings directly.
96+
*/
97+
if (interp && interp->isolate_env_writes && env && env->parent) {
98+
/* create a local declaration if absent (use inferred decl type) */
99+
bool local_found = false;
100+
if (env->entries) {
101+
for (size_t __i = 0; __i < env->count; __i++) {
102+
EnvEntry* __e = &env->entries[__i];
103+
if (__e->name && strcmp(__e->name, name) == 0) { local_found = true; break; }
104+
}
105+
}
106+
if (!local_found) {
107+
/* best-effort: create a local (implicit) declaration to shadow parent.
108+
* Use TYPE_UNKNOWN for implicit builtins-created bindings so the PARFOR
109+
* merge step can distinguish explicit declarations (non-UNKNOWN)
110+
* from these ephemeral locals and skip merging them back.
111+
*/
112+
if (!env_define(env, name, TYPE_UNKNOWN)) {
113+
char buf[128];
114+
snprintf(buf, sizeof(buf), "%s writeback failed", rule);
115+
interp->error = strdup(buf);
116+
interp->error_line = line;
117+
interp->error_col = col;
118+
return false;
119+
}
120+
}
121+
}
92122
if (!env_assign(env, name, result, TYPE_UNKNOWN, false)) {
93123
char buf[128];
94124
snprintf(buf, sizeof(buf), "%s writeback failed", rule);
@@ -109,6 +139,32 @@ static bool writeback_ptr_node(Interpreter* interp, Expr* node, Env* env, Value
109139
interp->error_col = col;
110140
return false;
111141
}
142+
/* See comment in writeback_first_ptr: create a local binding for
143+
* isolated-per-iteration environments so parent bindings are not
144+
* modified directly by concurrent iterations.
145+
*/
146+
if (interp && interp->isolate_env_writes && env && env->parent) {
147+
bool local_found = false;
148+
if (env->entries) {
149+
for (size_t __i = 0; __i < env->count; __i++) {
150+
EnvEntry* __e = &env->entries[__i];
151+
if (__e->name && strcmp(__e->name, name) == 0) { local_found = true; break; }
152+
}
153+
}
154+
if (!local_found) {
155+
/* Create an implicit local entry (TYPE_UNKNOWN) so iterations
156+
* can write to a per-iteration copy without affecting parent.
157+
*/
158+
if (!env_define(env, name, TYPE_UNKNOWN)) {
159+
char buf[128];
160+
snprintf(buf, sizeof(buf), "%s writeback failed", rule);
161+
interp->error = strdup(buf);
162+
interp->error_line = line;
163+
interp->error_col = col;
164+
return false;
165+
}
166+
}
167+
}
112168
if (!env_assign(env, name, result, TYPE_UNKNOWN, false)) {
113169
char buf[128];
114170
snprintf(buf, sizeof(buf), "%s writeback failed", rule);

src/interpreter.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,14 @@ static int parfor_merge_iteration_env(ParforStart* start, char** merge_error) {
414414
continue;
415415
}
416416

417+
/* Skip implicit locals created by builtins during iteration (they
418+
* are declared with TYPE_UNKNOWN). Only explicitly-declared symbols
419+
* in the iteration body (non-UNKNOWN decl_type) are merged back.
420+
*/
421+
if (entry->decl_type == TYPE_UNKNOWN) {
422+
continue;
423+
}
424+
417425
if (!env_get_entry(parent_env, entry->name)) {
418426
env_define(parent_env, entry->name, entry->decl_type);
419427
}

0 commit comments

Comments
 (0)