Commit 4c4f6bdb authored by Gregory Ewing's avatar Gregory Ewing

Forward declaration of extension class in another module


+
+    - There is now a way of forward-declaring an extension type into
+      another module. This allows two .pxd files to define extension types
+      that refer to each other without running into circular import problems.
+      For example:
+
+        cimport blarg
+        cdef class blarg.Blarg # Forward declaration
+
+        cdef class Foo:
+          cdef blarg.Blarg blg
parent 6194c79e
...@@ -571,16 +571,7 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -571,16 +571,7 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
else: else:
type = py_object_type type = py_object_type
else: else:
scope = env scope = env.find_imported_module(self.module_path, self.pos)
for name in self.module_path:
entry = scope.find(name, self.pos)
if entry and entry.as_module:
scope = entry.as_module
else:
if entry:
error(self.pos, "'%s' is not a cimported module" % name)
scope = None
break
if scope: if scope:
if scope.is_c_class_scope: if scope.is_c_class_scope:
scope = scope.global_scope() scope = scope.global_scope()
...@@ -1230,6 +1221,8 @@ class DefNode(FuncDefNode): ...@@ -1230,6 +1221,8 @@ class DefNode(FuncDefNode):
self.num_required_kw_args = rk self.num_required_kw_args = rk
self.num_required_args = r self.num_required_args = r
entry = None
def analyse_declarations(self, env): def analyse_declarations(self, env):
for arg in self.args: for arg in self.args:
base_type = arg.base_type.analyse(env) base_type = arg.base_type.analyse(env)
...@@ -2010,7 +2003,14 @@ class CClassDefNode(StatNode, BlockNode): ...@@ -2010,7 +2003,14 @@ class CClassDefNode(StatNode, BlockNode):
else: else:
self.base_type = base_class_entry.type self.base_type = base_class_entry.type
has_body = self.body is not None has_body = self.body is not None
self.entry = env.declare_c_class( if self.module_name:
module_path = self.module_name.split(".")
home_scope = env.find_imported_module(module_path, self.pos)
if not home_scope:
return
else:
home_scope = env
self.entry = home_scope.declare_c_class(
name = self.class_name, name = self.class_name,
pos = self.pos, pos = self.pos,
defining = has_body and self.in_pxd, defining = has_body and self.in_pxd,
...@@ -2022,6 +2022,8 @@ class CClassDefNode(StatNode, BlockNode): ...@@ -2022,6 +2022,8 @@ class CClassDefNode(StatNode, BlockNode):
visibility = self.visibility, visibility = self.visibility,
typedef_flag = self.typedef_flag, typedef_flag = self.typedef_flag,
api = self.api) api = self.api)
if home_scope is not env and self.visibility == 'extern':
env.add_imported_entry(self.class_name, self.entry, pos)
scope = self.entry.type.scope scope = self.entry.type.scope
if self.doc and Options.docstrings: if self.doc and Options.docstrings:
......
...@@ -420,6 +420,21 @@ class Scope: ...@@ -420,6 +420,21 @@ class Scope:
else: else:
error(pos, "'%s' is not declared" % name) error(pos, "'%s' is not declared" % name)
def find_imported_module(self, path, pos):
# Look up qualified name, must be a module, report error if not found.
# Path is a list of names.
scope = self
for name in path:
entry = scope.find(name, pos)
if not entry:
return None
if entry.as_module:
scope = entry.as_module
else:
error(pos, "'%s' is not a cimported module" % scope.qualified_name)
return None
return scope
def lookup(self, name): def lookup(self, name):
# Look up name in this scope or an enclosing one. # Look up name in this scope or an enclosing one.
# Return None if not found. # Return None if not found.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment