diff options
Diffstat (limited to 'Cython/Compiler/PyrexTypes.py')
-rw-r--r-- | Cython/Compiler/PyrexTypes.py | 99 |
1 files changed, 49 insertions, 50 deletions
diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index c773f5c5a..da30809a3 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -13,6 +13,7 @@ try: except NameError: from functools import reduce from functools import partial +from itertools import product from Cython.Utils import cached_function from .Code import UtilityCode, LazyUtilityCode, TempitaUtilityCode @@ -205,6 +206,7 @@ class PyrexType(BaseType): # needs_cpp_construction boolean Needs C++ constructor and destructor when used in a cdef class # needs_refcounting boolean Needs code to be generated similar to incref/gotref/decref. # Largely used internally. + # equivalent_type type A C or Python type that is equivalent to this Python or C type. # default_value string Initial value that can be assigned before first user assignment. # declaration_value string The value statically assigned on declaration (if any). # entry Entry The Entry for this type @@ -277,6 +279,7 @@ class PyrexType(BaseType): has_attributes = 0 needs_cpp_construction = 0 needs_refcounting = 0 + equivalent_type = None default_value = "" declaration_value = "" @@ -1504,7 +1507,6 @@ class PyExtensionType(PyObjectType): # # name string # scope CClassScope Attribute namespace - # visibility string # typedef_flag boolean # base_type PyExtensionType or None # module_name string or None Qualified name of defining module @@ -1518,8 +1520,10 @@ class PyExtensionType(PyObjectType): # vtable_cname string Name of C method table definition # early_init boolean Whether to initialize early (as opposed to during module execution). # defered_declarations [thunk] Used to declare class hierarchies in order + # is_external boolean Defined in a extern block # check_size 'warn', 'error', 'ignore' What to do if tp_basicsize does not match # dataclass_fields OrderedDict nor None Used for inheriting from dataclasses + # multiple_bases boolean Does this class have multiple bases is_extension_type = 1 has_attributes = 1 @@ -1527,6 +1531,7 @@ class PyExtensionType(PyObjectType): objtypedef_cname = None dataclass_fields = None + multiple_bases = False def __init__(self, name, typedef_flag, base_type, is_external=0, check_size=None): self.name = name @@ -1833,7 +1838,27 @@ class FusedType(CType): for t in types: if t.is_fused: # recursively merge in subtypes - for subtype in t.types: + if isinstance(t, FusedType): + t_types = t.types + else: + # handle types that aren't a fused type themselves but contain fused types + # for example a C++ template where the template type is fused. + t_fused_types = t.get_fused_types() + t_types = [] + for substitution in product( + *[fused_type.types for fused_type in t_fused_types] + ): + t_types.append( + t.specialize( + { + fused_type: sub + for fused_type, sub in zip( + t_fused_types, substitution + ) + } + ) + ) + for subtype in t_types: if subtype not in flattened_types: flattened_types.append(subtype) elif t not in flattened_types: @@ -2788,6 +2813,8 @@ class CReferenceBaseType(BaseType): # Common base type for C reference and C++ rvalue reference types. + subtypes = ['ref_base_type'] + def __init__(self, base_type): self.ref_base_type = base_type @@ -3044,6 +3071,9 @@ class CFuncType(CType): # must catch C++ exceptions if we raise them return 0 if not other_type.exception_check or other_type.exception_value is not None: + # There's no problem if this type doesn't emit exceptions but the other type checks + if other_type.exception_check and not (self.exception_check or self.exception_value): + return 1 # if other does not *always* check exceptions, self must comply if not self._same_exception_value(other_type.exception_value): return 0 @@ -3129,8 +3159,10 @@ class CFuncType(CType): if (pyrex or for_display) and not self.return_type.is_pyobject: if self.exception_value and self.exception_check: trailer = " except? %s" % self.exception_value - elif self.exception_value: + elif self.exception_value and not self.exception_check: trailer = " except %s" % self.exception_value + elif not self.exception_value and not self.exception_check: + trailer = " noexcept" elif self.exception_check == '+': trailer = " except +" elif self.exception_check and for_display: @@ -4429,6 +4461,7 @@ class ErrorType(PyrexType): class PythonTypeConstructor(PyObjectType): """Used to help Cython interpret indexed types from the typing module (or similar) """ + modifier_name = None def __init__(self, name, base_type=None): self.python_type_constructor_name = name @@ -4457,69 +4490,35 @@ class PythonTupleTypeConstructor(PythonTypeConstructor): not any(v.is_pyobject for v in template_values)): entry = env.declare_tuple_type(pos, template_values) if entry: + entry.used = True return entry.type return super(PythonTupleTypeConstructor, self).specialize_here(pos, env, template_values) class SpecialPythonTypeConstructor(PythonTypeConstructor): """ - For things like ClassVar, Optional, etc, which have extra features on top of being - a "templated" type. + For things like ClassVar, Optional, etc, which are not types and disappear during type analysis. """ - def __init__(self, name, template_type=None): - super(SpecialPythonTypeConstructor, self).__init__(name, None) - if (name == "typing.ClassVar" and template_type - and not template_type.is_pyobject): - # because classvars end up essentially used as globals they have - # to be PyObjects. Try to find the nearest suitable type (although - # practically I doubt this matters). - py_type_name = template_type.py_type_name() - if py_type_name: - from .Builtin import builtin_scope - template_type = (builtin_scope.lookup_type(py_type_name) - or py_object_type) - else: - template_type = py_object_types - self.template_type = template_type + def __init__(self, name): + super(SpecialPythonTypeConstructor, self).__init__(name, base_type=None) + self.modifier_name = name def __repr__(self): - if self.template_type: - return "%s[%r]" % (self.name, self.template_type) - else: - return self.name - - def is_template_type(self): - return self.template_type is None + return self.name def resolve(self): - if self.template_type: - return self.template_type.resolve() - else: - return self + return self def specialize_here(self, pos, env, template_values=None): if len(template_values) != 1: error(pos, "'%s' takes exactly one template argument." % self.name) - # return a copy of the template type with python_type_constructor_name as an attribute - # so it can be identified, and a resolve function that gets back to - # the original type (since types are usually tested with "is") - new_type = template_values[0] - if self.python_type_constructor_name == "typing.ClassVar": - # classvar must remain a py_object_type - new_type = py_object_type - if (self.python_type_constructor_name == "typing.Optional" and - not new_type.is_pyobject): - # optional must be a py_object, but can be a specialized py_object - new_type = py_object_type - return SpecialPythonTypeConstructor( - self.python_type_constructor_name, - template_type = template_values[0]) - - def __getattr__(self, name): - if self.template_type: - return getattr(self.template_type, name) - return super(SpecialPythonTypeConstructor, self).__getattr__(name) + return error_type + if template_values[0] is None: + # FIXME: allowing unknown types for now since we don't recognise all Python types. + return None + # Replace this type with the actual 'template' argument. + return template_values[0].resolve() rank_to_type_name = ( |