summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Bradshaw <robertwb@gmail.com>2014-01-16 00:05:44 -0800
committerRobert Bradshaw <robertwb@gmail.com>2014-01-16 00:05:44 -0800
commit2108d1aa6f586445f00961bc3de1947349f7ca2b (patch)
treefb34a596e93b429e73732337a8c24b8e306422d5
parentd929ac0889b93703b704460bcff7433a93b8f0f4 (diff)
downloadcython-2108d1aa6f586445f00961bc3de1947349f7ca2b.tar.gz
Completely re-do out-of-order class declarations.
-rw-r--r--Cython/Compiler/Nodes.py42
-rw-r--r--Cython/Compiler/PyrexTypes.py2
2 files changed, 12 insertions, 32 deletions
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index 448530fd9..1cde9cbee 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -379,38 +379,7 @@ class StatListNode(Node):
def analyse_declarations(self, env):
#print "StatListNode.analyse_declarations" ###
- base_classes = {}
- def flatten(stats):
- # Common case is trivial flatten.
- if not [stat for stat in stats if isinstance(stat, StatListNode)]:
- return stats
- else:
- all = []
- for stat in stats:
- if isinstance(stat, StatListNode):
- all.extend(flatten(stat.stats))
- else:
- all.append(stat)
- return all
- flattened = flatten(self.stats)
- for stat in flattened:
- if isinstance(stat, CClassDefNode) and not stat.base_class_module:
- base_classes[stat.class_name] = stat.base_class_name
- @cached_function
- def depth(class_name):
- base_class = base_classes.get(class_name)
- if class_name is None:
- return 0
- else:
- return depth(base_class) + 1
- keyed_stats = []
- for ix, stat in enumerate(flattened):
- if isinstance(stat, CClassDefNode):
- key = 20, depth(stat.class_name), ix
- else:
- key = 10, ix
- keyed_stats.append((key, stat))
- for key, stat in sorted(keyed_stats):
+ for stat in self.stats:
stat.analyse_declarations(env)
def analyse_expressions(self, env):
@@ -4337,6 +4306,12 @@ class CClassDefNode(ClassDefNode):
warning(self.pos, "freelists cannot be used on subtypes, only the base class can manage them", 1)
has_body = self.body is not None
+ if has_body and self.base_type and not self.base_type.scope:
+ # To properly initialize inherited attributes, the base type must
+ # be analysed before this type.
+ self.base_type.defered_declarations.append(lambda : self.analyse_declarations(env))
+ return
+
if self.module_name and self.visibility != 'extern':
module_path = self.module_name.split(".")
home_scope = env.find_imported_module(module_path, self.pos)
@@ -4385,6 +4360,9 @@ class CClassDefNode(ClassDefNode):
scope.implemented = 1
env.allocate_vtable_names(self.entry)
+ for thunk in self.entry.type.defered_declarations:
+ thunk()
+
def analyse_expressions(self, env):
if self.body:
scope = self.entry.type.scope
diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py
index d388a90b2..3f8e85fb5 100644
--- a/Cython/Compiler/PyrexTypes.py
+++ b/Cython/Compiler/PyrexTypes.py
@@ -1070,6 +1070,7 @@ class PyExtensionType(PyObjectType):
# vtabstruct_cname string Name of C method table struct
# vtabptr_cname string Name of pointer to C method table
# vtable_cname string Name of C method table definition
+ # defered_declarations [thunk] Used to declare class hierarchies in order
is_extension_type = 1
has_attributes = 1
@@ -1092,6 +1093,7 @@ class PyExtensionType(PyObjectType):
self.vtabptr_cname = None
self.vtable_cname = None
self.is_external = is_external
+ self.defered_declarations = []
def set_scope(self, scope):
self.scope = scope