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):
else:
type = py_object_type
else:
scope = env
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
scope = env.find_imported_module(self.module_path, self.pos)
if scope:
if scope.is_c_class_scope:
scope = scope.global_scope()
......@@ -1230,6 +1221,8 @@ class DefNode(FuncDefNode):
self.num_required_kw_args = rk
self.num_required_args = r
entry = None
def analyse_declarations(self, env):
for arg in self.args:
base_type = arg.base_type.analyse(env)
......@@ -2010,7 +2003,14 @@ class CClassDefNode(StatNode, BlockNode):
else:
self.base_type = base_class_entry.type
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,
pos = self.pos,
defining = has_body and self.in_pxd,
......@@ -2022,6 +2022,8 @@ class CClassDefNode(StatNode, BlockNode):
visibility = self.visibility,
typedef_flag = self.typedef_flag,
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
if self.doc and Options.docstrings:
......
......@@ -420,6 +420,21 @@ class Scope:
else:
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):
# Look up name in this scope or an enclosing one.
# 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