Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'bugs'

Conflicts:
	Cython/Compiler/Optimize.py
	Cython/Compiler/TypeInference.py
  • Loading branch information...
commit d7a2258c30ec8f91ae4079d4418d9e193304d93d 2 parents a7707eb + 15dce27
@robertwb robertwb authored
View
8 CHANGES.rst
@@ -25,6 +25,14 @@ Bugs fixed
* C++ class nesting was broken.
+* Better checking for required nullary constructors for stack-allocated C++ instances.
+
+* Remove module docstring in no-docstring mode.
+
+* Fix specialization for varargs function signatures.
+
+* Fix several compiler crashes.
+
Other changes
-------------
View
7 Cython/Compiler/FusedNode.py
@@ -211,7 +211,7 @@ def specialize_copied_def(self, node, cname, py_entry, f2s, fused_types):
for fused_type in fused_types
]
- node.specialized_signature_string = ', '.join(type_strings)
+ node.specialized_signature_string = '|'.join(type_strings)
node.entry.pymethdef_cname = PyrexTypes.get_fused_cname(
cname, node.entry.pymethdef_cname)
@@ -322,7 +322,8 @@ def _buffer_check_numpy_dtype(self, pyx_code, specialized_buffer_types):
for dtype_category, codewriter in dtypes:
if dtype_category:
- cond = '{{itemsize_match}}'
+ cond = '{{itemsize_match}} and arg.ndim == %d' % (
+ specialized_type.ndim,)
if dtype.is_int:
cond += ' and {{signed_match}}'
@@ -587,7 +588,7 @@ def __pyx_fused_cpdef(signatures, args, kwargs, defaults):
candidates = []
for sig in signatures:
match_found = False
- for src_type, dst_type in zip(sig.strip('()').split(', '), dest_sig):
+ for src_type, dst_type in zip(sig.strip('()').split('|'), dest_sig):
if dst_type is not None:
if src_type == dst_type:
match_found = True
View
4 Cython/Compiler/ModuleNode.py
@@ -86,7 +86,9 @@ def extend_if_not_in(L1, L2):
self.scope.merge_in(scope)
def analyse_declarations(self, env):
- if Options.embed_pos_in_docstring:
+ if not Options.docstrings:
+ env.doc = self.doc = None
+ elif Options.embed_pos_in_docstring:
env.doc = EncodedString(u'File: %s (starting at line %s)' % Nodes.relative_position(self.pos))
if not self.doc is None:
env.doc = EncodedString(env.doc + u'\n' + self.doc)
View
9 Cython/Compiler/Nodes.py
@@ -1239,7 +1239,12 @@ def analyse_declarations(self, env):
scope = None
if self.attributes is not None:
scope = CppClassScope(self.name, env, templates = self.templates)
- base_class_types = [b.analyse(scope or env) for b in self.base_classes]
+ def base_ok(base_class):
+ if base_class.is_cpp_class or base_class.is_struct:
+ return True
+ else:
+ error(self.pos, "Base class '%s' not a struct or class." % base_class)
+ base_class_types = filter(base_ok, [b.analyse(scope or env) for b in self.base_classes])
if self.templates is None:
template_types = None
else:
@@ -2084,6 +2089,8 @@ def analyse_declarations(self, env):
if self.return_type.is_array and self.visibility != 'extern':
error(self.pos,
"Function cannot return an array")
+ if self.return_type.is_cpp_class:
+ self.return_type.check_nullary_constructor(self.pos, "used as a return value")
if self.overridable and not env.is_module_scope:
if len(self.args) < 1 or not self.args[0].type.is_pyobject:
View
5 Cython/Compiler/PyrexTypes.py
@@ -3314,6 +3314,11 @@ def find_cpp_operation_type(self, operator, operand_type=None):
func_type = func_type.base_type
return func_type.return_type
+ def check_nullary_constructor(self, pos, msg="stack allocated"):
+ constructor = self.scope.lookup(u'<init>')
+ if constructor is not None and best_match([], constructor.all_alternatives()) is None:
+ error(pos, "C++ class must have a nullary constructor to be %s" % msg)
+
class TemplatePlaceholderType(CType):
View
9 Cython/Compiler/Symtab.py
@@ -570,9 +570,7 @@ def declare_var(self, name, type, pos,
else:
cname = self.mangle(Naming.var_prefix, name)
if type.is_cpp_class and visibility != 'extern':
- constructor = type.scope.lookup(u'<init>')
- if constructor is not None and PyrexTypes.best_match([], constructor.all_alternatives()) is None:
- error(pos, "C++ class must have a no-arg constructor to be stack allocated")
+ type.check_nullary_constructor(pos)
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
if in_pxd and visibility != 'extern':
@@ -1783,10 +1781,7 @@ def declare_var(self, name, type, pos,
if visibility == 'private':
cname = c_safe_identifier(cname)
if type.is_cpp_class and visibility != 'extern':
- constructor = type.scope.lookup(u'<init>')
- if constructor is not None and \
- PyrexTypes.best_match([], constructor.all_alternatives()) is None:
- error(pos, "C++ class must have a no-arg constructor to be a member of an extension type; use a pointer instead")
+ type.check_nullary_constructor(pos)
self.use_utility_code(Code.UtilityCode("#include <new>"))
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
View
14 Cython/Compiler/TypeInference.py
@@ -390,7 +390,7 @@ def resolve_dependancy(dep):
types = [assmt.rhs.infer_type(scope)
for assmt in entry.cf_assignments]
if types and Utils.all(types):
- entry.type = spanning_type(types, entry.might_overflow)
+ entry.type = spanning_type(types, entry.might_overflow, entry.pos)
else:
# FIXME: raise a warning?
# print "No assignments", entry.pos, entry
@@ -405,10 +405,10 @@ def resolve_dependancy(dep):
for assmt in entry.cf_assignments
if assmt.type_dependencies(scope) == ()]
if types:
- entry.type = spanning_type(types, entry.might_overflow)
+ entry.type = spanning_type(types, entry.might_overflow, entry.pos)
types = [assmt.infer_type(scope)
for assmt in entry.cf_assignments]
- entry.type = spanning_type(types, entry.might_overflow) # might be wider...
+ entry.type = spanning_type(types, entry.might_overflow, entry.pos) # might be wider...
resolve_dependancy(entry)
del dependancies_by_entry[entry]
if ready_to_infer:
@@ -438,20 +438,24 @@ def find_spanning_type(type1, type2):
return PyrexTypes.c_double_type
return result_type
-def aggressive_spanning_type(types, might_overflow):
+def aggressive_spanning_type(types, might_overflow, pos):
result_type = reduce(find_spanning_type, types)
if result_type.is_reference:
result_type = result_type.ref_base_type
if result_type.is_const:
result_type = result_type.const_base_type
+ if result_type.is_cpp_class:
+ result_type.check_nullary_constructor(pos)
return result_type
-def safe_spanning_type(types, might_overflow):
+def safe_spanning_type(types, might_overflow, pos):
result_type = reduce(find_spanning_type, types)
if result_type.is_const:
result_type = result_type.const_base_type
if result_type.is_reference:
result_type = result_type.ref_base_type
+ if result_type.is_cpp_class:
+ result_type.check_nullary_constructor(pos)
if result_type.is_pyobject:
# In theory, any specific Python type is always safe to
# infer. However, inferring str can cause some existing code
View
62 Cython/Shadow.py
@@ -1,6 +1,66 @@
# cython.* namespace for pure mode.
__version__ = "0.18-pre"
+# Shamelessly copied from Cython/minivect/minitypes.py
+
+class _ArrayType(object):
+
+ is_array = True
+ subtypes = ['dtype']
+
+ def __init__(self, dtype, ndim, is_c_contig=False, is_f_contig=False,
+ inner_contig=False, broadcasting=None):
+ self.dtype = dtype
+ self.ndim = ndim
+ self.is_c_contig = is_c_contig
+ self.is_f_contig = is_f_contig
+ self.inner_contig = inner_contig or is_c_contig or is_f_contig
+ self.broadcasting = broadcasting
+
+ def __repr__(self):
+ axes = [":"] * self.ndim
+ if self.is_c_contig:
+ axes[-1] = "::1"
+ elif self.is_f_contig:
+ axes[0] = "::1"
+
+ return "%s[%s]" % (self.dtype, ", ".join(axes))
+
+def index_type(base_type, item):
+ """
+ Support array type creation by slicing, e.g. double[:, :] specifies
+ a 2D strided array of doubles. The syntax is the same as for
+ Cython memoryviews.
+ """
+ assert isinstance(item, (tuple, slice))
+
+ def verify_slice(s):
+ if s.start or s.stop or s.step not in (None, 1):
+ raise minierror.InvalidTypeSpecification(
+ "Only a step of 1 may be provided to indicate C or "
+ "Fortran contiguity")
+
+ if isinstance(item, tuple):
+ step_idx = None
+ for idx, s in enumerate(item):
+ verify_slice(s)
+ if s.step and (step_idx or idx not in (0, len(item) - 1)):
+ raise minierror.InvalidTypeSpecification(
+ "Step may only be provided once, and only in the "
+ "first or last dimension.")
+
+ if s.step == 1:
+ step_idx = idx
+
+ return _ArrayType(base_type, len(item),
+ is_c_contig=step_idx == len(item) - 1,
+ is_f_contig=step_idx == 0)
+ else:
+ verify_slice(item)
+ return _ArrayType(base_type, 1, is_c_contig=bool(item.step))
+
+# END shameless copy
+
compiled = False
_Unspecified = object()
@@ -241,6 +301,8 @@ def __call__(self, *arg):
def __repr__(self):
return self.name or str(self._basetype)
+ __getitem__ = index_type
+
class _FusedType(CythonType):
pass
View
2  Cython/Utility/CppConvert.pyx
@@ -5,6 +5,7 @@
cdef extern from *:
cdef cppclass string "std::string":
+ string()
string(char* c_str, size_t size)
@cname("{{cname}}")
@@ -147,6 +148,7 @@ cdef object {{cname}}(const_cpp_set[X]& s):
cdef extern from *:
cdef cppclass pair "std::pair" [T, U]:
+ pair()
pair(T&, U&)
@cname("{{cname}}")
View
2  Cython/Utility/CythonFunction.c
@@ -700,7 +700,7 @@ __pyx_FusedFunction_getitem(__pyx_FusedFunctionObject *self, PyObject *idx)
Py_DECREF(string);
}
- sep = PyUnicode_FromString(", ");
+ sep = PyUnicode_FromString("|");
if (sep)
signature = PyUnicode_Join(sep, list);
__pyx_err:
View
10 docs/src/userguide/fusedtypes.rst
@@ -230,9 +230,10 @@ __signatures__
Finally, function objects from ``def`` or ``cpdef`` functions have an attribute
__signatures__, which maps the signature strings to the actual specialized
functions. This may be useful for inspection. Listed signature strings may also
-be used as indices to the fused function::
+be used as indices to the fused function, but the index format may change between
+Cython versions::
- specialized_function = fused_function["MyExtensionClass, int, float"]
+ specialized_function = fused_function["MyExtensionClass|int|float"]
It would usually be preferred to index like this, however::
@@ -242,8 +243,7 @@ Although the latter will select the biggest types for ``int`` and ``float`` from
Python space, as they are not type identifiers but builtin types there. Passing
``cython.int`` and ``cython.float`` would resolve that, however.
-For memoryview indexing from python space you have to use strings instead of
-types::
+For memoryview indexing from python space we can do the following:
ctypedef fused my_fused_type:
int[:, ::1]
@@ -252,6 +252,6 @@ types::
def func(my_fused_type array):
...
- my_fused_type['int[:, ::1]'](myarray)
+ my_fused_type[cython.int[:, ::1]](myarray)
The same goes for when using e.g. ``cython.numeric[:, :]``.
View
4 tests/run/fused_def.pyx
@@ -48,7 +48,7 @@ def opt_func(fused_t obj, cython.floating myf = 1.2, cython.integral myi = 7):
>>> opt_func[str, float, int]("spam", f, i)
str object float int
spam 5.60 9 5.60 9
- >>> opt_func["str, double, long"]("spam", f, i)
+ >>> opt_func[str, cy.double, cy.long]("spam", f, i)
str object double long
spam 5.60 9 5.60 9
>>> opt_func[str, float, cy.int]("spam", f, i)
@@ -62,7 +62,7 @@ def opt_func(fused_t obj, cython.floating myf = 1.2, cython.integral myi = 7):
>>> opt_func[ExtClassA, float, int](ExtClassA(), f, i)
ExtClassA float int
ExtClassA 5.60 9 5.60 9
- >>> opt_func["ExtClassA, double, long"](ExtClassA(), f, i)
+ >>> opt_func[ExtClassA, cy.double, cy.long](ExtClassA(), f, i)
ExtClassA double long
ExtClassA 5.60 9 5.60 9
View
24 tests/run/numpy_test.pyx
@@ -849,4 +849,28 @@ def test_dispatch_memoryview_object():
cdef int[:] m3 = <object> m
test_fused_memslice(m3)
+cdef fused ndim_t:
+ double[:]
+ double[:, :]
+ double[:, :, :]
+
+@testcase
+def test_dispatch_ndim(ndim_t array):
+ """
+ >>> test_dispatch_ndim(np.empty(5, dtype=np.double))
+ double[:] 1
+ >>> test_dispatch_ndim(np.empty((5, 5), dtype=np.double))
+ double[:, :] 2
+ >>> test_dispatch_ndim(np.empty((5, 5, 5), dtype=np.double))
+ double[:, :, :] 3
+
+ Test indexing using Cython.Shadow
+ >>> import cython
+ >>> test_dispatch_ndim[cython.double[:]](np.empty(5, dtype=np.double))
+ double[:] 1
+ >>> test_dispatch_ndim[cython.double[:, :]](np.empty((5, 5), dtype=np.double))
+ double[:, :] 2
+ """
+ print cython.typeof(array), np.asarray(array).ndim
+
include "numpy_common.pxi"
View
1  tests/run/public_fused_types.srctree
@@ -201,7 +201,6 @@ def ae(result, expected):
assert result == expected
-ae(a_mod.public_cpdef["int, float, list"](5, 6, [7]), ("int", "float", "list object"))
ae(a_mod.public_cpdef[int, float, list](5, 6, [7]), ("int", "float", "list object"))
idx = cy.typeof(0), cy.typeof(0.0), cy.typeof([])
Please sign in to comment.
Something went wrong with that request. Please try again.