Commit f73108cc authored by Stefan Behnel's avatar Stefan Behnel

Check for "Optional[ctype]" earlier because we need to make sure that...

Check for "Optional[ctype]" earlier because we need to make sure that "Optional[int]" etc. interprets "int" as (valid) Python int type and not (invalid) C int type.

See https://github.com/cython/cython/issues/3883
parent aaba1229
...@@ -969,9 +969,6 @@ class CArgDeclNode(Node): ...@@ -969,9 +969,6 @@ class CArgDeclNode(Node):
if arg_type and arg_type.python_type_constructor_name == "typing.Optional": if arg_type and arg_type.python_type_constructor_name == "typing.Optional":
# "x: Optional[...]" => explicitly allow 'None' # "x: Optional[...]" => explicitly allow 'None'
arg_type = arg_type.resolve() arg_type = arg_type.resolve()
if arg_type and not arg_type.is_pyobject:
error(annotation.pos, "Only Python type arguments can use typing.Optional[...]")
else:
self.or_none = True self.or_none = True
elif arg_type and arg_type.is_pyobject and self.default and self.default.is_none: elif arg_type and arg_type.is_pyobject and self.default and self.default.is_none:
# "x: ... = None" => implicitly allow 'None' # "x: ... = None" => implicitly allow 'None'
...@@ -1225,6 +1222,16 @@ class TemplatedTypeNode(CBaseTypeNode): ...@@ -1225,6 +1222,16 @@ class TemplatedTypeNode(CBaseTypeNode):
if type is None and base_type.is_cpp_class: if type is None and base_type.is_cpp_class:
error(template_node.pos, "unknown type in template argument") error(template_node.pos, "unknown type in template argument")
type = error_type type = error_type
elif type and base_type.python_type_constructor_name and not (type.is_pyobject or type.is_memoryviewslice):
if type.is_numeric and template_node.is_name and template_node.name in ('int', 'long', 'float', 'complex'):
# int, long, float, complex => make sure we use the Python types
type = env.builtin_scope().lookup_here(template_node.name).type
else:
error(template_node.pos, "%s[...] cannot be applied to non-Python type %s" % (
base_type.python_type_constructor_name,
type,
))
type = error_type
# for indexed_pytype we can be a bit more flexible and pass None # for indexed_pytype we can be a bit more flexible and pass None
template_types.append(type) template_types.append(type)
self.type = base_type.specialize_here(self.pos, env, template_types) self.type = base_type.specialize_here(self.pos, env, template_types)
...@@ -3155,7 +3162,7 @@ class DefNode(FuncDefNode): ...@@ -3155,7 +3162,7 @@ class DefNode(FuncDefNode):
else: else:
# probably just a plain 'object' # probably just a plain 'object'
arg.accept_none = True arg.accept_none = True
else: elif not arg.type.is_error:
arg.accept_none = True # won't be used, but must be there arg.accept_none = True # won't be used, but must be there
if arg.not_none: if arg.not_none:
error(arg.pos, "Only Python type arguments can have 'not None'") error(arg.pos, "Only Python type arguments can have 'not None'")
......
...@@ -4482,17 +4482,9 @@ class SpecialPythonTypeConstructor(PythonTypeConstructor): ...@@ -4482,17 +4482,9 @@ class SpecialPythonTypeConstructor(PythonTypeConstructor):
# return a copy of the template type with python_type_constructor_name as an attribute # 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 # so it can be identified, and a resolve function that gets back to
# the original type (since types are usually tested with "is") # 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( return SpecialPythonTypeConstructor(
self.python_type_constructor_name, self.python_type_constructor_name,
template_type=new_type) template_type=template_values[0])
def __getattr__(self, name): def __getattr__(self, name):
if self.template_type: if self.template_type:
......
...@@ -8,11 +8,10 @@ except ImportError: ...@@ -8,11 +8,10 @@ except ImportError:
pass pass
def optional_pytypes(i: Optional[int], f: Optional[float]): # not OK
pass
def optional_cython_types(i: Optional[cython.int], d: Optional[cython.double], f: Optional[cython.float]): def optional_cython_types(i: Optional[cython.int], d: Optional[cython.double], f: Optional[cython.float],
c: Optional[cython.complex], l: Optional[cython.long], ll: Optional[cython.longlong]):
pass pass
...@@ -22,13 +21,23 @@ def optional_cstruct(x: Optional[MyStruct]): ...@@ -22,13 +21,23 @@ def optional_cstruct(x: Optional[MyStruct]):
pass pass
# OK
def optional_pytypes(i: Optional[int], f: Optional[float], c: Optional[complex], l: Optional[long]):
pass
def optional_memoryview(d: double[:], o: Optional[double[:]]):
pass
_ERRORS = """ _ERRORS = """
15:29: Only Python type arguments can use typing.Optional[...] 13:44: typing.Optional[...] cannot be applied to non-Python type int
15:54: Only Python type arguments can use typing.Optional[...] 13:69: typing.Optional[...] cannot be applied to non-Python type double
15:82: Only Python type arguments can use typing.Optional[...] 13:97: typing.Optional[...] cannot be applied to non-Python type float
21:24: Only Python type arguments can use typing.Optional[...] 14:44: typing.Optional[...] cannot be applied to non-Python type double complex
14:73: typing.Optional[...] cannot be applied to non-Python type long
# FIXME: these should be allowed! 14:100: typing.Optional[...] cannot be applied to non-Python type long long
11:24: Only Python type arguments can use typing.Optional[...]
11:42: Only Python type arguments can use typing.Optional[...] 20:33: typing.Optional[...] cannot be applied to non-Python type MyStruct
""" """
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