Fix core dump in example from Samuele Pedroni:
authorJeremy Hylton <jeremy@alum.mit.edu>
Thu, 1 Mar 2001 06:09:34 +0000 (06:09 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Thu, 1 Mar 2001 06:09:34 +0000 (06:09 +0000)
from __future__ import nested_scopes
x=7
def f():
    x=1
    def g():
        global x
        def i():
            def h():
                return x
            return h()
        return i()
    return g()

print f()
print x

This kind of code didn't work correctly because x was treated as free
in i, leading to an attempt to load x in g to make a closure for i.

Solution is to make global decl apply to nested scopes unless their is
an assignment.  Thus, x in h is global.

Python/compile.c

index bd6a679658d18dbe42aae8ddc6822ee09e6cb3c4..efef05b25a9265c3a58b61bc9b59b787d331d5e3 100644 (file)
@@ -179,6 +179,8 @@ code_hash(PyCodeObject *co)
        return h;
 }
 
+/* XXX code objects need to participate in GC? */
+
 PyTypeObject PyCode_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,
@@ -2132,8 +2134,13 @@ com_make_closure(struct compiling *c, PyCodeObject *co)
                else /* (reftype == FREE) */
                        arg = com_lookup_arg(c->c_freevars, name);
                if (arg == -1) {
-                       fprintf(stderr, "lookup %s in %s %d %d\n",
-                               PyObject_REPR(name), c->c_name, reftype, arg);
+                       fprintf(stderr, "lookup %s in %s %d %d\n"
+                               "freevars of %s: %s\n",
+                               PyObject_REPR(name), 
+                               c->c_name, 
+                               reftype, arg,
+                               PyString_AS_STRING(co->co_name),
+                               PyObject_REPR(co->co_freevars));
                        Py_FatalError("com_make_closure()");
                }
                com_addoparg(c, LOAD_CLOSURE, arg);
@@ -4424,8 +4431,8 @@ symtable_update_free_vars(struct symtable *st)
                child = (PySymtableEntryObject *)
                        PyList_GET_ITEM(ste->ste_children, i);
                while (PyDict_Next(child->ste_symbols, &pos, &name, &o)) {
-                       int v = PyInt_AS_LONG(o);
-                       if (!(is_free(v)))
+                       int flags = PyInt_AS_LONG(o);
+                       if (!(is_free(flags)))
                                continue; /* avoids indentation */
                        if (list == NULL) {
                                list = PyList_New(0);
@@ -4438,18 +4445,24 @@ symtable_update_free_vars(struct symtable *st)
                                return -1;
                        }
                }
-/*
-               if (st->st_nested_scopes == 0 
-                   && list && PyList_GET_SIZE(list) > 0) {
-                       fprintf(stderr, "function %s has children with "
-                               "the following free vars:\n%s\n",
-                               PyString_AS_STRING(ste->ste_name),
-                               PyObject_REPR(list));
-                       continue; 
-               }
-*/
                for (j = 0; list && j < PyList_GET_SIZE(list); j++) {
+                       PyObject *v;
                        name = PyList_GET_ITEM(list, j);
+                       v = PyDict_GetItem(ste->ste_symbols, name);
+                       /* If a name N is declared global in scope A and
+                          referenced in scope B contained (perhaps
+                          indirectly) in A and there are no scopes
+                          with bindings for N between B and A, then N
+                          is global in B.
+                       */
+                       if (v) {
+                               int flags = PyInt_AS_LONG(v); 
+                               if (flags & DEF_GLOBAL) {
+                                       symtable_undo_free(st, child->ste_id,
+                                                          name);
+                                       continue;
+                               }
+                       }
                        if (ste->ste_nested) {
                                if (symtable_add_def_o(st, ste->ste_symbols,
                                                       name, def) < 0) {
@@ -4481,13 +4494,14 @@ symtable_check_global(struct symtable *st, PyObject *child, PyObject *name)
        PyObject *o;
        int v;
        PySymtableEntryObject *ste = st->st_cur;
-
+                       
        if (ste->ste_type == TYPE_CLASS)
                return symtable_undo_free(st, child, name);
        o = PyDict_GetItem(ste->ste_symbols, name);
        if (o == NULL)
                return symtable_undo_free(st, child, name);
        v = PyInt_AS_LONG(o);
+
        if (is_free(v) || (v & DEF_GLOBAL)) 
                return symtable_undo_free(st, child, name);
        else
@@ -4506,6 +4520,7 @@ symtable_undo_free(struct symtable *st, PyObject *id,
        ste = (PySymtableEntryObject *)PyDict_GetItem(st->st_symbols, id);
        if (ste == NULL)
                return -1;
+
        info = PyDict_GetItem(ste->ste_symbols, name);
        if (info == NULL)
                return 0;
@@ -4938,6 +4953,7 @@ symtable_global(struct symtable *st, node *n)
        int i;
 
        if (st->st_nscopes == 1) {
+               /* XXX must check that we are compiling file_input */
                if (symtable_warn(st, 
                  "global statement has no meaning at module level") < 0)
                        return;