View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0000631 | LDMud 3.3 | Implementation | public | 2009-04-26 02:41 | 2018-01-29 21:57 |
| Reporter | Sorcerer | Assigned To | Gnomi | ||
| Priority | normal | Severity | minor | Reproducibility | always |
| Status | resolved | Resolution | fixed | ||
| Product Version | 3.3.718 | ||||
| Target Version | 3.3.719 | Fixed in Version | 3.3.719 | ||
| Summary | 0000631: Inconsistent behaviour of nested inline closures | ||||
| Description | Consider the following two functions: void test1() { int i=1; if (i) write("Fun ok\n"); funcall((: if (i) write("Inline 1 ok\n"); funcall((: int i=$1; if (i) write("Inline 2 ok\n"); :),i); :)); } void test2() { int i=1; if (i) write("Fun ok\n"); funcall((: if (i) write("Inline 1 ok\n"); funcall((: if (i) write("Inline 2 ok\n"); :)); :)); } Loading an object that defines these two functions results in an compiler warning "...line 7 before '$1; if (i)': Variable 'i' shadows previous declaration" which seems ok to me since i is in the implicit context of the 1st inline and therefore should also be in the implicit context of the 2nd one (calling test1() works fine). BUT: calling test2() in this example (which causes no compile-time warnings) results in the following runtime error as soon as the 2nd inline closure is evaluated: "(eval_instruction) context_identifier: inter_context is NULL". Now, either the implicit context of one inline closure is passed on as implicit context to another nested inline closure - in that case test2() has to work. Or the implicit context is not passed on - than test1() has to compile without compiler warnings, since i is not known in the scope of the 2nd inline closure. | ||||
| Tags | No tags attached. | ||||
| Attached Files | bug631.diff (26,902 bytes)
Index: trunk.inline/test/t-mantis.c
===================================================================
--- trunk.inline/test/t-mantis.c (Revision 2587)
+++ trunk.inline/test/t-mantis.c (Arbeitskopie)
@@ -180,6 +180,145 @@
return to_int("-"+num) == __INT_MIN__;
:)
}),
+ ({ "0000631-1", 0,
+ (:
+ int i=1;
+
+ return funcall(
+ (:
+ if(i)
+ return funcall((: return i; :));
+ :)) == 1;
+ :)
+ }),
+ ({ "0000631-2", 0,
+ (:
+ int i=1;
+
+ return funcall(
+ function int() : int j = 2
+ {
+ if(i)
+ return funcall((: return j; :));
+ }) == 2;
+ :)
+ }),
+ ({ "0000631-3", 0,
+ (:
+ int i=1;
+
+ return funcall(
+ function int()
+ {
+ int j = 2;
+ return funcall((: return i; :));
+ }) == 1;
+ :)
+ }),
+ ({ "0000631-4", 0,
+ (:
+ int i=1;
+
+ return funcall(
+ function int ()
+ {
+ return funcall(
+ function int () : int j=i
+ {
+ return j;
+ });
+ });
+ :)
+ }),
+ ({ "0000631-5", 0,
+ (:
+ int a = 1;
+
+ return funcall(
+ function int() : closure cl = (: a :)
+ {
+ return funcall(cl);
+ }) == 1;
+ :)
+ }),
+ ({ "0000631-6", 0,
+ (:
+ int a=1;
+
+ return funcall(
+ function int () : int b = a+1; int c = b+1
+ {
+ return c;
+ }) == 3;
+ :)
+ }),
+ ({ "0000631-7", 0, /* #631 in conjunction with #537. */
+ (:
+ closure c;
+
+ {
+ int a = 1;
+ }
+
+ c = function int () : int b
+ {
+ return b;
+ };
+
+ return funcall(c) == 0;
+ :)
+ }),
+ ({ "0000631-8", 0, /* #631 in conjunction with #537. */
+ (:
+ closure c;
+
+ c = function int () : int b = 2
+ {
+ return b;
+ };
+
+ {
+ int d;
+
+ return d == 0;
+ }
+
+ :)
+ }),
+ ({ "0000631-9", 0, /* Check, that the array is only freed once. */
+ (:
+ closure c = function int() : string* a = ({ "" })
+ {
+ return 0;
+ };
+
+ return closurep(c); /* As long as it doesn't crash... */
+ :)
+ }),
+ ({ "0000631-10", 0,
+ function int(int a, int b, int c)
+ {
+
+ return funcall(funcall(funcall(
+ function :
+ mixed i = 1;
+ mixed j = function :
+ mixed j = function { return i; }
+ { return j; };
+ { return j; }
+ ))) == 1;
+ }
+ }),
+ ({ "0000631-11", 0,
+ (:
+ return funcall(function int() :
+ closure c = function int() : int a = 1 { return 2; };
+ int b;
+ {
+ return b;
+ }) == 0;
+ :)
+ }),
});
void run_test()
Index: trunk.inline/src/prolang.y
===================================================================
--- trunk.inline/src/prolang.y (Revision 2587)
+++ trunk.inline/src/prolang.y (Arbeitskopie)
@@ -622,6 +622,11 @@
/* Index of the enclosing inline closure, or -1 if none.
*/
+ mp_int next;
+ /* Index of an enclosed inline closure.
+ * This is only used temporarily.
+ */
+
/* --- Compilation information --- */
mp_uint end;
/* While compiling the closure: end of the program code before
@@ -2684,7 +2689,7 @@
#ifdef USE_NEW_INLINES
/*-------------------------------------------------------------------------*/
static ident_t *
-add_context_name (ident_t *ident, fulltype_t type, int num)
+add_context_name (inline_closure_t *closure, ident_t *ident, fulltype_t type, int num)
/* Declare a new context variable <ident> with the type <type> for the
* currently compiled inline closure. The references of <type> are NOT adopted.
@@ -2697,7 +2702,7 @@
int depth;
block_scope_t * block;
- depth = current_inline->block_depth+1;
+ depth = closure->block_depth+1;
block = & block_scope[depth-1];
#ifdef DEBUG_INLINES
@@ -2710,6 +2715,13 @@
{
yyerror("Too many context variables");
}
+ else if (num < 0
+ && (block->first_local + block->num_locals >= 256
+ || block->first_local + block->num_locals >= MAX_LOCAL
+ ))
+ {
+ yyerror("Too many local variables");
+ }
else
{
ref_fulltype_data(&type);
@@ -2724,9 +2736,21 @@
/* Initialize the ident */
ident->type = I_TYPE_LOCAL;
- ident->u.local.num = num;
ident->u.local.depth = depth;
- ident->u.local.context = block->num_locals;
+ if (num < 0)
+ {
+ /* First initialize it as a local variable
+ * of the outer function, so they can be
+ * referenced during initialization.
+ */
+ ident->u.local.num = block->first_local + block->num_locals;
+ ident->u.local.context = -1;
+ }
+ else
+ {
+ ident->u.local.num = num;
+ ident->u.local.context = block->num_locals;
+ }
/* Put the ident into the list of all locals.
*/
@@ -2752,6 +2776,8 @@
/* Record the type */
type_of_context[block->num_locals] = type;
+ if (num < 0)
+ type_of_locals[ident->u.local.num] = type;
block->num_locals++;
}
@@ -2782,46 +2808,115 @@
&& depth <= current_inline->block_depth
)
{
- /* This local has been inherited - create the
- * proper context variable.
+ inline_closure_t *closure;
+ mp_int closure_nr;
+
+ closure = current_inline;
+
+ /* Get the active enclosing closure.
+ * Skip closures whose context is currently being parsed.
*/
- if (ident->u.local.context >= 0)
+ do
{
- if (!current_inline->parse_context
- && current_inline->prev != -1
- && depth <= INLINE_CLOSURE(current_inline->prev).block_depth
- )
+ closure_nr = closure->prev;
+ if (closure_nr == -1)
+ break;
+ closure = &(INLINE_CLOSURE(closure_nr));
+ }
+ while (closure->parse_context);
+
+ if (current_inline->parse_context && closure_nr == -1)
+ {
+ /* We're in the context initializer of the first inline closure.
+ * So this must be a reference to a local variable.
+ */
+ *pType = LOCAL_TYPE(current_inline->full_local_type_start
+ + ident->u.local.num
+ );
+ }
+ else
+ {
+ /* This local has been inherited - create the
+ * proper context variable.
+ *
+ * Let's go back to the first inline closure
+ * that has to inherit this variable.
+ * And record that path in the ->next pointer.
+ */
+
+ fulltype_t type;
+
+ closure = current_inline;
+ closure_nr = closure - &(INLINE_CLOSURE(0));
+ closure->next = -1;
+
+ /* Go through all inline closures to our local variable
+ * and record this way using the .next pointers.
+ *
+ * Stop at the last inline closure before the variable's
+ * scope, because the information about that scope was
+ * saved there.
+ */
+ for (;;)
{
- /* Can't use outer context variables when compiling
- * an inline closure body.
- */
- yyerrorf("Can't use context variable '%s' "
- "across closure boundaries", get_txt(ident->name));
- ident = redeclare_local(ident, Type_Any, block_depth);
- *pType = Type_Any;
+ inline_closure_t *outer_closure;
+ mp_int outer_closure_nr;
+
+ outer_closure_nr = closure->prev;
+ if (outer_closure_nr == -1)
+ /* It is a local variable of the current function. */
+ break;
+
+ outer_closure = &(INLINE_CLOSURE(outer_closure_nr));
+ outer_closure->next = closure_nr;
+
+ if (outer_closure->block_depth < depth)
+ /* The variable belongs to outer_closure. */
+ break;
+
+ closure = outer_closure;
+ closure_nr = outer_closure_nr;
}
+
+ if (ident->u.local.context >= 0)
+ {
+ /* It's a context variable. */
+ type = LOCAL_TYPE(closure->full_context_type_start
+ + ident->u.local.context
+ );
+ }
else
{
- /* We can use outer context variables when compiling
- * an inline closure context.
- */
- *pType = LOCAL_TYPE(current_inline->full_context_type_start
- + ident->u.local.context
- );
+ /* It's a local variable. */
+ type = LOCAL_TYPE(closure->full_local_type_start
+ + ident->u.local.num
+ );
}
- }
- else /* it's a local */
- {
- fulltype_t type;
- type = LOCAL_TYPE(current_inline->full_local_type_start
- + ident->u.local.num
- );
- if (!current_inline->parse_context)
+ /* Now pass this context variable through
+ * all surrounding inline closures.
+ */
+ while (MY_TRUE)
{
- ref_fulltype_data(&type);
- ident = add_context_name( ident, type, ident->u.local.num);
+ /* Skip closures whose context is being parsed,
+ * because current_inline is not created
+ * in their runtime.
+ */
+ if (!closure->parse_context)
+ {
+ ref_fulltype_data(&type);
+ ident = add_context_name(closure, ident, type,
+ ident->u.local.context >= 0
+ ? 256 + ident->u.local.context
+ : ident->u.local.num);
+ }
+
+ if (closure->next == -1)
+ break;
+
+ closure = &(INLINE_CLOSURE(closure->next));
}
+
*pType = type;
}
}
@@ -2833,6 +2928,39 @@
return ident;
} /* check_for_context_local() */
+/*-------------------------------------------------------------------------*/
+static void
+adapt_context_names (void)
+
+/* Convert all explicit context variables
+ * from local variables to context variables.
+ */
+
+{
+ int depth;
+ block_scope_t *scope;
+
+ depth = current_inline->block_depth+1;
+ scope = block_scope + depth - 1;
+
+ /* Are there locals of the given depth? */
+ if (all_locals && all_locals->u.local.depth >= depth)
+ {
+ ident_t *q = all_locals;
+
+ while (q != NULL && q->u.local.depth > depth)
+ q = q->next_all;
+
+ while (q != NULL && q->u.local.depth == depth)
+ {
+ q->u.local.context = q->u.local.num - scope->first_local;
+ q->u.local.num = -1;
+
+ q = q->next_all;
+ }
+ }
+} /* adapt_context_names() */
+
#endif /* USE_NEW_INLINES */
/*-------------------------------------------------------------------------*/
@@ -5293,6 +5421,7 @@
* its rightful place.
*/
{
+ int num_explicit_context = 0;
int depth = current_inline->block_depth+1;
block_scope_t * context = &(block_scope[depth-1]);
@@ -5337,8 +5466,16 @@
{
if (lcmap[i] != -1)
{
- ins_f_code(F_LOCAL);
- ins_byte(lcmap[i]);
+ if (lcmap[i] >= 256)
+ {
+ ins_f_code(F_CONTEXT_IDENTIFIER);
+ ins_byte(lcmap[i] - 256);
+ }
+ else
+ {
+ ins_f_code(F_LOCAL);
+ ins_byte(lcmap[i]);
+ }
got_mapped = MY_TRUE;
#ifdef DEBUG_INLINES
printf("DEBUG: -> F_LOCAL %d\n", lcmap[i]);
@@ -5353,16 +5490,21 @@
fatal("Explicite context var #%d has higher index than "
"implicite context variables.", i);
}
+ else
+ num_explicit_context++;
}
} /* Push local vars */
/* Add the context_closure instruction */
#ifdef DEBUG_INLINES
-printf("DEBUG: -> F_CONTEXT_CLOSURE %d %d\n", current_inline->function, context->num_locals);
+printf("DEBUG: -> F_CONTEXT_CLOSURE %d %d %d\n", current_inline->function
+ , num_explicit_context, context->num_locals - num_explicit_context);
#endif /* DEBUG_INLINES */
ins_f_code(F_CONTEXT_CLOSURE);
ins_short(current_inline->function);
- ins_short(context->num_locals);
+ ins_byte(context->first_local);
+ ins_short(num_explicit_context);
+ ins_short(context->num_locals - num_explicit_context);
} /* Complete F_CONTEXT_CLOSURE instruction */
@@ -6040,6 +6182,14 @@
/* deactivate argument scope while parsing explicit context */
block_scope[current_inline->block_depth+1].accessible = MY_FALSE;
current_inline->parse_context = MY_TRUE;
+ assert(block_scope[current_inline->block_depth].first_local == 0);
+ if (current_inline->prev != -1 && INLINE_CLOSURE(current_inline->prev).parse_context)
+ {
+ block_scope_t *scope = block_scope + INLINE_CLOSURE(current_inline->prev).block_depth;
+ block_scope[current_inline->block_depth].first_local = scope->first_local + scope->num_locals;
+ }
+ else
+ block_scope[current_inline->block_depth].first_local = current_inline->num_locals;
}
inline_opt_context
@@ -6049,10 +6199,54 @@
printf("DEBUG: After inline_opt_context: program size %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE);
#endif /* DEBUG_INLINES */
+ /* Complete the F_CLEAR_LOCALS at the beginning of the context block. */
+ block_scope_t *scope = block_scope + current_inline->block_depth;
+ inline_closure_t *outer_closure;
+ int * outer_max_num_locals;
+
+ if (scope->num_locals > scope->num_cleared)
+ {
+ mem_block[A_PROGRAM].block[scope->addr+2]
+ = (char)(scope->num_locals - scope->num_cleared);
+ }
+
/* reactivate argument scope */
block_scope[current_inline->block_depth+1].accessible = MY_TRUE;
current_inline->parse_context = MY_FALSE;
+ adapt_context_names();
+ /* Find the correct max_num_locals to update.
+ * That is the one of the last closure with parse_context set.
+ */
+ outer_max_num_locals = &(current_inline->max_num_locals);
+ outer_closure = current_inline;
+
+ while (outer_closure->prev != -1)
+ {
+ outer_closure = &(INLINE_CLOSURE(outer_closure->prev));
+ if (!outer_closure->parse_context)
+ break;
+ outer_max_num_locals = &(outer_closure->max_num_locals);
+ }
+
+ if (scope->first_local + scope->num_locals > *outer_max_num_locals)
+ *outer_max_num_locals = scope->first_local + scope->num_locals;
+
+ /* Check whether we clobbered some other local or context variables. */
+ if (scope->num_locals || scope->clobbered)
+ {
+ if (current_inline->prev != -1)
+ {
+ outer_closure = &(INLINE_CLOSURE(current_inline->prev));
+ if (outer_closure->parse_context)
+ block_scope[outer_closure->block_depth].clobbered = MY_TRUE;
+ else
+ block_scope[current_inline->block_depth-1].clobbered = MY_TRUE;
+ }
+ else
+ block_scope[current_inline->block_depth-1].clobbered = MY_TRUE;
+ }
+
if (!inline_closure_prototype($4))
YYACCEPT;
}
@@ -6115,7 +6309,7 @@
printf("DEBUG: After L_END_INLINE: program size %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE);
#endif /* DEBUG_INLINES */
- /* Complete the F_CLEAR_LOCALS at the baginning of the block. */
+ /* Complete the F_CLEAR_LOCALS at the beginning of the block. */
block_scope_t *scope = block_scope + block_depth - 1;
if (use_local_scopes && scope->num_locals > scope->num_cleared)
@@ -13950,10 +14144,9 @@
q = name;
}
else
- q = add_context_name(name, actual_type, -1);
+ q = add_context_name(current_inline, name, actual_type, -1);
- lv->u.simple[0] = F_PUSH_CONTEXT_LVALUE;
- lv->u.simple[1] = q->u.local.context;
+ scope = block_scope + current_inline->block_depth;
}
else
{
@@ -13961,30 +14154,32 @@
q = redeclare_local(name, actual_type, block_depth);
else
q = add_local_name(name, actual_type, block_depth);
+ }
- if (use_local_scopes && scope->clobbered)
- {
- /* finish the previous CLEAR_LOCALS, if any */
- if (scope->num_locals - 1 > scope->num_cleared)
- mem_block[A_PROGRAM].block[scope->addr+2]
- = (char)(scope->num_locals - 1 - scope->num_cleared);
- scope->clobbered = MY_FALSE;
- scope->num_cleared = scope->num_locals - 1;
- }
- if (use_local_scopes && scope->num_locals == scope->num_cleared + 1)
- {
- /* First definition of a local, so insert the
- * clear_locals bytecode and remember its position
- */
- scope->addr = mem_block[A_PROGRAM].current_size;
- ins_f_code(F_CLEAR_LOCALS);
- ins_byte(scope->first_local + scope->num_cleared);
- ins_byte(0);
- }
+ if (use_local_scopes && scope->clobbered)
+ {
+ /* finish the previous CLEAR_LOCALS, if any */
+ if (scope->num_locals - 1 > scope->num_cleared)
+ mem_block[A_PROGRAM].block[scope->addr+2]
+ = (char)(scope->num_locals - 1 - scope->num_cleared);
+ scope->clobbered = MY_FALSE;
+ scope->num_cleared = scope->num_locals - 1;
+ }
- lv->u.simple[0] = F_PUSH_LOCAL_VARIABLE_LVALUE;
- lv->u.simple[1] = q->u.local.num;
+ if (use_local_scopes && scope->num_locals == scope->num_cleared + 1)
+ {
+ /* First definition of a local, so insert the
+ * clear_locals bytecode and remember its position
+ */
+ scope->addr = mem_block[A_PROGRAM].current_size;
+ ins_f_code(F_CLEAR_LOCALS);
+ ins_byte(scope->first_local + scope->num_cleared);
+ ins_byte(0);
}
+
+ lv->u.simple[0] = F_PUSH_LOCAL_VARIABLE_LVALUE;
+ lv->u.simple[1] = q->u.local.num;
+
#else /* USE_NEW_INLINES */
if (redeclare)
q = redeclare_local(name, actual_type, block_depth);
@@ -14024,38 +14219,16 @@
* initializer, as the default svalue-0 is not a valid float value.
*/
- Bool need_value = MY_FALSE;
%line
-
-#ifdef USE_NEW_INLINES
- /* When parsing context variables, the context_closure instruction
- * expects a value on the stack. If we do a float initialization,
- * we leave the 0.0 on the stack, otherwise we'll push a 0.
- * For normal float locals, we'll create the bytecode to assign
- * the float 0.
- */
- need_value = current_inline && current_inline->parse_context;
-#endif /* USE_NEW_INLINES */
-
if (!(actual_type.typeflags & TYPE_MOD_POINTER)
&& (actual_type.typeflags & PRIMARY_TYPE_MASK) == TYPE_FLOAT
)
{
ins_f_code(F_FCONST0);
+ if (!add_lvalue_code(lv, F_VOID_ASSIGN))
+ return;
- if (!need_value)
- {
- if (!add_lvalue_code(lv, F_VOID_ASSIGN))
- return;
- }
-
- need_value = MY_FALSE;
} /* if (float variable) */
-
- if (need_value) /* If we still need a value... */
- {
- ins_number(0);
- }
}
} /* define_local_variable() */
@@ -14097,18 +14270,8 @@
if (type2.typeflags & TYPE_MOD_REFERENCE)
yyerror("Can't trace reference assignments");
- /* If we're parsing a context variable, just leave the
- * value on the stack for the context_closure instruction.
- * For normal locals, add the bytecode to create the lvalue
- * and do the assignment.
- */
-#ifdef USE_NEW_INLINES
- if (!current_inline || !current_inline->parse_context)
-#endif /* USE_NEW_INLINES */
- {
- if (!add_lvalue_code(lv, F_VOID_ASSIGN))
- return;
- } /* parsed context var */
+ if (!add_lvalue_code(lv, F_VOID_ASSIGN))
+ return;
} /* init_local_variable() */
/*-------------------------------------------------------------------------*/
Index: trunk.inline/src/interpret.c
===================================================================
--- trunk.inline/src/interpret.c (Revision 2587)
+++ trunk.inline/src/interpret.c (Arbeitskopie)
@@ -8543,7 +8543,7 @@
CASE(F_CLOSURE); /* --- closure <ix> <inhIndex> --- */
#ifdef USE_NEW_INLINES
- CASE(F_CONTEXT_CLOSURE); /* --- context_closure <ix> <num> --- */
+ CASE(F_CONTEXT_CLOSURE); /* --- context_closure <ix> <vix> <num_ex> <num_im> --- */
#endif /* USE_NEW_INLINES */
{
/* Push the closure value <ix> and <inhIndex> onto the stack.
@@ -8564,8 +8564,10 @@
* of the directly referenced inherited function.
#ifdef USE_NEW_INLINES
*
- * If it is a context closure, the context is sized to and initialized
- * with the uint16 <num> values on the stack.
+ * If it is a context closure, the context is sized to
+ * uint16 <num_ex>+<num_in> values, uint16 <num_ex> values
+ * are taken from the local variables beginning at <vix>,
+ * uint16 <num_im> values are taken from the stack.
#endif
*/
@@ -8573,18 +8575,21 @@
/* TODO: int32 */ int ix;
/* TODO: uint16 */ unsigned short inhIndex;
#ifdef USE_NEW_INLINES
- unsigned short context_size;
+ unsigned short explicit_context_size, implicit_context_size;
+ svalue_t * explicit_context;
#endif /* USE_NEW_INLINES */
inhIndex = 0;
#ifdef USE_NEW_INLINES
- context_size = 0;
+ explicit_context_size = implicit_context_size = 0;
#endif /* USE_NEW_INLINES */
LOAD_SHORT(tmp_ushort, pc);
#ifdef USE_NEW_INLINES
if (instruction == F_CONTEXT_CLOSURE)
{
- LOAD_SHORT(context_size, pc);
+ explicit_context = fp + LOAD_UINT8(pc);
+ LOAD_SHORT(explicit_context_size, pc);
+ LOAD_SHORT(implicit_context_size, pc);
}
else
{
@@ -8603,7 +8608,7 @@
#ifndef USE_NEW_INLINES
closure_literal(sp, ix, inhIndex);
#else /* USE_NEW_INLINES */
- closure_literal(sp, ix, inhIndex, context_size);
+ closure_literal(sp, ix, inhIndex, explicit_context_size + implicit_context_size);
#endif /* USE_NEW_INLINES */
/* If out of memory, this will set sp to svalue-0 and
* throw an error.
@@ -8618,13 +8623,29 @@
"closure type %d.\n", sp->x.closure_type);
#endif
/* Now copy the context values */
- if (context_size != 0)
+ if (explicit_context_size != 0)
{
unsigned short i;
- svalue_t * arg = sp - context_size;
svalue_t * context = sp->u.lambda->context;
- for (i = 0; i < context_size; i++)
+ for (i = 0; i < explicit_context_size; i++)
+ {
+ transfer_svalue_no_free(context+i, explicit_context+i);
+
+ /* Set it to T_INVALID, as it is still a variable of
+ * the function frame and will be freed on return.
+ */
+ explicit_context[i].type = T_INVALID;
+ }
+ }
+
+ if (implicit_context_size != 0)
+ {
+ unsigned short i;
+ svalue_t * arg = sp - implicit_context_size;
+ svalue_t * context = sp->u.lambda->context + explicit_context_size;
+
+ for (i = 0; i < implicit_context_size; i++)
transfer_svalue_no_free(context+i, arg+i);
/* Now move the created closure to the new top of the stack */
Index: trunk.inline/CHANGELOG
===================================================================
--- trunk.inline/CHANGELOG (Revision 2587)
+++ trunk.inline/CHANGELOG (Arbeitskopie)
@@ -1,6 +1,12 @@
This file lists all changes made to the game driver in all glory detail.
See the file HISTORY for a user-oriented summary of all the changes.
+??-May-2009 (Gnomi)
+ - (prolang.y, interpret.c) Corrected the handling of implicit context
+ variables in nested inline closures and allowed the initializers
+ of explicit context variables to reference other explicit context
+ variables. (Bug #631)
+
18-May-2009 (Gnomi)
- (pkg-xml2.c, arraylist.c, configure) Added support for XML parsing
using libxml2. (Bug #538, thanks, Bardioc!)
| ||||
|
|
See also issue 0000613, which is marked resolved for 3.3.718. |
|
|
Oh - I just realized it was filed against 718 but will be resolved only in 719. So this might solve this issue, too, but since I don't know for sure, please have a look at it anyways. |
|
|
I don't know how this was supposed to work. check_for_context_local() in prolang.y seems to assume that we can access variables of an outer context. But at runtime when calling the inner closure this outer context might not exist anymore. There is a second problem: funcall( function int() : int i = 1 { return funcall((: return i; :)); })); This fails because only locals can be adopted as an implied context variable, not outer context variables. This is not related to 0000613 which dealt only with lambda closures. |
|
|
And a third problem: int i = 1; funcall( function int() { int j = 2; return funcall((: return i; :)); })); This returns 2 (because i is the first local variable in its block, so is j). |
|
|
One more - which seems to me to be in agreement with the other cases: funcall(function int () { return funcall(function int () : int i=i { return i; }); }); throws an error, while funcall(function int () { i; return funcall(function int () : int i=i { return i; }); }); works fine (as soon as i is used in the outer inline-closure). |
|
|
The last one is a different problem, similar to the following: int x = 1; // global variable int fun() { int x = x; return x; } fun() will return 0, because the initializer (= x) references the local variable not the global one. The same happens when initializing the context variable int i = i, the parser initializes the context variable i with itself but at that time the context doesn't exist yet, so an error is thrown. I'll duplicate this bug for these problems. |
|
|
I attached a patch that fixes these problems (except 0000632). |
|
|
That's a somewhat different problem, which nevertheless i'd like to handle also in this bug: int a = 2; return funcall( function int() : int b = a; int c = b { return c; }); |
|
|
I uploaded a new patch that also fixes the last problem (0000631:0001065 and 0000631:0001082) by treating explicit context variables during initialization as real local variables of the outer function and let F_CONTEXT_CLOSURE take the values from there. |
|
|
Something is fishy here. Calling the following function results in an infinite loop in inl_transfer_svalue(), caused by an lvalue pointing to itself: void t(mixed a, mixed b, mixed c) { return funcall(funcall(funcall( function : mixed i = 1; mixed j = function : mixed j = function { return i; } { return j; }; { return j; } ))); } |
|
|
I'm using r2574 + your patch, configured with ./settings/wunderland --disable-use-ipv6 --enable-debug --enable-check-object-ref --enable-check-object-gc-ref |
|
|
I uploaded a modified patch. The old patch calculated the index of the first local variable wrongly when a closure was within the context of another closure. |
|
|
I updated the patch to r2584. |
|
|
Committed as r2588. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2009-04-26 02:41 | Sorcerer | New Issue | |
| 2009-04-26 02:43 | Sorcerer | Note Added: 0001061 | |
| 2009-04-26 02:45 | Sorcerer | Note Added: 0001062 | |
| 2009-04-26 14:49 | Gnomi | Assigned To | => Gnomi |
| 2009-04-26 14:49 | Gnomi | Status | new => confirmed |
| 2009-04-26 14:49 | Gnomi | Target Version | => 3.3.719 |
| 2009-04-26 17:02 | Gnomi | Note Added: 0001063 | |
| 2009-04-27 00:47 | Gnomi | Note Added: 0001064 | |
| 2009-04-27 02:43 | Sorcerer | Note Added: 0001065 | |
| 2009-04-29 03:40 | Gnomi | Note Added: 0001066 | |
| 2009-04-29 03:49 | Gnomi | Issue cloned: 0000632 | |
| 2009-04-29 03:49 | Gnomi | Relationship added | related to 0000632 |
| 2009-04-29 03:55 | Gnomi | File Added: bug631.diff | |
| 2009-04-29 03:56 | Gnomi | Note Added: 0001067 | |
| 2009-05-05 14:00 | Gnomi | Note Added: 0001082 | |
| 2009-05-09 05:22 | Gnomi | File Deleted: bug631.diff | |
| 2009-05-09 05:22 | Gnomi | File Added: bug631.diff | |
| 2009-05-09 05:51 | Gnomi | File Deleted: bug631.diff | |
| 2009-05-09 05:51 | Gnomi | File Added: bug631.diff | |
| 2009-05-09 06:04 | Gnomi | Note Added: 0001088 | |
| 2009-05-10 08:45 | fufu | Note Added: 0001091 | |
| 2009-05-10 08:47 | fufu | Note Added: 0001092 | |
| 2009-05-10 15:45 | Gnomi | File Deleted: bug631.diff | |
| 2009-05-10 15:45 | Gnomi | File Added: bug631.diff | |
| 2009-05-10 15:47 | Gnomi | Note Added: 0001099 | |
| 2009-05-11 00:32 | Gnomi | File Deleted: bug631.diff | |
| 2009-05-11 00:32 | Gnomi | File Added: bug631.diff | |
| 2009-05-12 09:04 | Gnomi | File Deleted: bug631.diff | |
| 2009-05-12 09:05 | Gnomi | File Added: bug631.diff | |
| 2009-05-12 09:06 | Gnomi | Note Added: 0001103 | |
| 2009-05-19 03:56 | Gnomi | File Deleted: bug631.diff | |
| 2009-05-19 03:57 | Gnomi | File Added: bug631.diff | |
| 2009-05-19 12:11 | Gnomi | Note Added: 0001118 | |
| 2009-05-19 12:11 | Gnomi | Status | confirmed => resolved |
| 2009-05-19 12:11 | Gnomi | Fixed in Version | => 3.3.719 |
| 2009-05-19 12:11 | Gnomi | Resolution | open => fixed |
| 2010-11-16 09:42 | Gnomi | Source_changeset_attached | => ldmud.git master 79e0cb56 |
| 2018-01-29 18:59 | Gnomi | Source_changeset_attached | => ldmud.git master 79e0cb56 |
| 2018-01-29 21:57 | Gnomi | Source_changeset_attached | => ldmud.git master 79e0cb56 |