Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
11915abb
Commit
11915abb
authored
Dec 04, 2020
by
Xavier Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Introduce 'iso' qualifier and 'consume' keyword
parent
b24fad38
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
198 additions
and
12 deletions
+198
-12
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+85
-9
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+10
-1
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+44
-2
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+57
-0
Cython/Compiler/TypeInference.py
Cython/Compiler/TypeInference.py
+2
-0
No files found.
Cython/Compiler/ExprNodes.py
View file @
11915abb
...
...
@@ -1048,11 +1048,15 @@ class ExprNode(Node):
src
=
CoerceToComplexNode
(
src
,
dst_type
,
env
)
else
:
# neither src nor dst are py types
# Qualified cypclass types can have nontrivial aliasing rules
# meaning type equality may not imply the coercion is valid.
if
src_type
.
is_qualified_cyp_class
and
not
dst_type
.
assignable_from
(
src_type
):
self
.
fail_assignment
(
dst_type
)
# Added the string comparison, since for c types that
# is enough, but Cython gets confused when the types are
# in different pxi files.
# TODO: Remove this hack and require shared declarations.
if
not
(
src
.
type
==
dst_type
or
str
(
src
.
type
)
==
str
(
dst_type
)
or
dst_type
.
assignable_from
(
src_type
)):
el
if
not
(
src
.
type
==
dst_type
or
str
(
src
.
type
)
==
str
(
dst_type
)
or
dst_type
.
assignable_from
(
src_type
)):
self
.
fail_assignment
(
dst_type
)
return
src
...
...
@@ -3945,8 +3949,8 @@ class IndexNode(_IndexingBaseNode):
elif
self
.
exception_check
==
'~'
:
self
.
is_temp
=
True
self
.
index
=
self
.
index
.
coerce_to
(
func_type
.
args
[
0
].
type
,
env
)
self
.
type
=
func_type
.
return_type
if
setting
and
not
func_type
.
return_
type
.
is_reference
:
self
.
type
=
func_type
.
return_type
.
as_returned_type
()
if
setting
and
not
self
.
type
.
is_reference
:
error
(
self
.
pos
,
"Can't set non-reference result '%s'"
%
self
.
type
)
return
self
...
...
@@ -3979,7 +3983,7 @@ class IndexNode(_IndexingBaseNode):
self
.
is_temp
=
True
self
.
index
=
self
.
index
.
coerce_to
(
function
.
type
.
args
[
0
].
type
,
env
)
self
.
type
=
func_type
.
return_type
self
.
type
=
func_type
.
return_type
.
as_returned_type
()
return
self
def
analyse_cyp_class_setitem
(
self
,
env
):
...
...
@@ -4019,7 +4023,7 @@ class IndexNode(_IndexingBaseNode):
env
.
use_utility_code
(
UtilityCode
.
load_cached
(
"CppExceptionConversion"
,
"CppSupport.cpp"
))
self
.
index
=
self
.
index
.
coerce_to
(
function
.
type
.
args
[
0
].
type
,
env
)
self
.
type
=
func_type
.
return_type
self
.
type
=
func_type
.
return_type
.
as_returned_type
()
return
self
def
analyse_as_c_function
(
self
,
env
):
...
...
@@ -6234,7 +6238,7 @@ class SimpleCallNode(CallNode):
else
:
self
.
type
=
PyrexTypes
.
CPtrType
(
self
.
function
.
class_type
)
else
:
self
.
type
=
func_type
.
return_type
self
.
type
=
func_type
.
return_type
.
as_returned_type
()
if
self
.
function
.
is_name
or
self
.
function
.
is_attribute
:
func_entry
=
self
.
function
.
entry
...
...
@@ -6723,7 +6727,7 @@ class PythonCapiCallNode(SimpleCallNode):
def
__init__
(
self
,
pos
,
function_name
,
func_type
,
utility_code
=
None
,
py_name
=
None
,
**
kwargs
):
self
.
type
=
func_type
.
return_type
self
.
type
=
func_type
.
return_type
.
as_returned_type
()
self
.
result_ctype
=
self
.
type
self
.
function
=
PythonCapiFunctionNode
(
pos
,
py_name
,
function_name
,
func_type
,
...
...
@@ -11346,6 +11350,78 @@ class SizeofVarNode(SizeofNode):
pass
class
ConsumeNode
(
ExprNode
):
# Consume expression
#
# operand ExprNode
subexprs
=
[
'operand'
]
generate_runtime_check
=
True
operand_is_named
=
True
def
infer_type
(
self
,
env
):
operand_type
=
self
.
operand
.
infer_type
(
env
)
if
operand_type
.
is_cyp_class
:
return
PyrexTypes
.
cyp_class_qualified_type
(
operand_type
,
'iso~'
)
else
:
return
operand_type
def
analyse_types
(
self
,
env
):
self
.
operand
=
self
.
operand
.
analyse_types
(
env
)
operand_type
=
self
.
operand
.
type
if
not
operand_type
.
is_cyp_class
:
error
(
self
.
pos
,
"Can only consume cypclass"
)
self
.
type
=
PyrexTypes
.
error_type
return
self
if
self
.
operand
.
is_name
or
self
.
operand
.
is_attribute
:
self
.
is_temp
=
self
.
operand_is_named
=
True
# We steal the reference of the operand.
self
.
use_managed_ref
=
False
if
operand_type
.
is_qualified_cyp_class
:
if
operand_type
.
qualifier
==
'iso!'
:
error
(
self
.
pos
,
"Cannot consume iso!"
)
self
.
type
=
PyrexTypes
.
error_type
return
self
self
.
generate_runtime_check
=
operand_type
.
qualifier
not
in
(
'iso'
,
'iso~'
)
if
operand_type
.
qualifier
==
'iso~'
:
self
.
type
=
operand_type
else
:
self
.
type
=
PyrexTypes
.
cyp_class_qualified_type
(
operand_type
.
qual_base_type
,
'iso~'
)
else
:
self
.
type
=
PyrexTypes
.
cyp_class_qualified_type
(
operand_type
,
'iso~'
)
return
self
def
may_be_none
(
self
):
return
self
.
operand
.
may_be_none
()
def
is_simple
(
self
):
return
self
.
operand
.
is_simple
()
def
make_owned_reference
(
self
,
code
):
# We steal the reference of the consumed operand.
pass
def
calculate_result_code
(
self
):
if
self
.
generate_runtime_check
:
# TODO: generate runtime check for isolation
return
self
.
operand
.
result
()
else
:
return
self
.
operand
.
result
()
def
generate_result_code
(
self
,
code
):
if
self
.
is_temp
:
operand_result
=
self
.
operand
.
result
()
code
.
putln
(
"%s = %s;"
%
(
self
.
result
(),
operand_result
))
if
self
.
generate_runtime_check
:
# TODO: generate runtime check for isolation
pass
# We steal the reference of the operand.
code
.
putln
(
"%s = NULL;"
%
operand_result
)
if
self
.
operand
.
is_temp
:
# TODO: steal the reference of the operand instead
code
.
put_incref
(
self
.
result
(),
self
.
type
)
class
TypeidNode
(
ExprNode
):
# C++ typeid operator applied to a type or variable
#
...
...
@@ -11634,7 +11710,7 @@ class BinopNode(ExprNode):
else
:
self
.
operand1
=
self
.
operand1
.
coerce_to
(
func_type
.
args
[
0
].
type
,
env
)
self
.
operand2
=
self
.
operand2
.
coerce_to
(
func_type
.
args
[
1
].
type
,
env
)
self
.
type
=
func_type
.
return_type
self
.
type
=
func_type
.
return_type
.
as_returned_type
()
def
result_type
(
self
,
type1
,
type2
,
env
):
if
self
.
is_pythran_operation_types
(
type1
,
type2
,
env
):
...
...
@@ -13330,7 +13406,7 @@ class PrimaryCmpNode(ExprNode, CmpNode):
else
:
self
.
operand1
=
self
.
operand1
.
coerce_to
(
func_type
.
args
[
0
].
type
,
env
)
self
.
operand2
=
self
.
operand2
.
coerce_to
(
func_type
.
args
[
1
].
type
,
env
)
self
.
type
=
func_type
.
return_type
self
.
type
=
func_type
.
return_type
.
as_returned_type
()
def
analyse_memoryviewslice_comparison
(
self
,
env
):
have_none
=
self
.
operand1
.
is_none
or
self
.
operand2
.
is_none
...
...
Cython/Compiler/Parsing.py
View file @
11915abb
...
...
@@ -309,6 +309,8 @@ def _p_factor(s):
return
p_typecast
(
s
)
elif
sy
==
'IDENT'
and
s
.
systring
==
"sizeof"
:
return
p_sizeof
(
s
)
elif
sy
==
'IDENT'
and
s
.
systring
==
"consume"
:
return
p_consume
(
s
)
return
p_power
(
s
)
def
p_typecast
(
s
):
...
...
@@ -357,6 +359,13 @@ def p_sizeof(s):
s
.
expect
(
')'
)
return
node
def
p_consume
(
s
):
# s.sy == ident "consume"
pos
=
s
.
position
()
s
.
next
()
operand
=
p_factor
(
s
)
return
ExprNodes
.
ConsumeNode
(
pos
,
operand
=
operand
)
def
p_yield_expression
(
s
):
# s.sy == "yield"
...
...
@@ -2535,7 +2544,7 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
base_type
=
base_type
,
is_const
=
is_const
,
is_volatile
=
is_volatile
)
# Handle cypclass qualifiers
if
s
.
sy
==
'IDENT'
and
s
.
systring
in
(
'active'
,):
if
s
.
sy
==
'IDENT'
and
s
.
systring
in
(
'active'
,
'iso'
):
qualifier
=
s
.
systring
s
.
next
()
base_type
=
p_c_base_type
(
s
,
self_flag
=
self_flag
,
nonempty
=
nonempty
,
templates
=
templates
)
...
...
Cython/Compiler/PyrexTypes.py
View file @
11915abb
...
...
@@ -228,6 +228,9 @@ class PyrexType(BaseType):
# Coerces array and C function types into pointer type for use as
# a formal argument type.
#
# as_returned_type():
# Potentially annotates function call return types as pure rvalues.
#
is_pyobject
=
0
is_unspecified
=
0
...
...
@@ -316,6 +319,9 @@ class PyrexType(BaseType):
def
as_argument_type
(
self
):
return
self
def
as_returned_type
(
self
):
return
self
def
is_complete
(
self
):
# A type is incomplete if it is an unsized array,
# a struct whose attributes are not defined, etc.
...
...
@@ -648,6 +654,12 @@ class CheckedResultType(BaseType):
def
as_argument_type
(
self
):
return
self
.
checked_base_type
.
as_argument_type
()
def
as_returned_type
(
self
):
returned_base_type
=
self
.
checked_base_type
.
as_returned_type
()
if
returned_base_type
.
same_as
(
self
.
checked_base_type
):
return
self
return
CheckedResultType
(
self
.
pos
,
returned_base_type
)
def
cast_code
(
self
,
expr_code
):
return
self
.
checked_base_type
.
cast_code
(
expr_code
)
...
...
@@ -1265,6 +1277,9 @@ class BufferType(BaseType):
def
as_argument_type
(
self
):
return
self
def
as_returned_type
(
self
):
return
self
def
specialize
(
self
,
values
):
dtype
=
self
.
dtype
.
specialize
(
values
)
if
dtype
is
not
self
.
dtype
:
...
...
@@ -1956,6 +1971,9 @@ class QualifiedMethodType(BaseType):
def
as_argument_type
(
self
):
return
c_ptr_type
(
self
)
def
as_returned_type
(
self
):
return
self
# All that follows is just to behave exactly like the underlying function type
def
__getattr__
(
self
,
name
):
...
...
@@ -3000,6 +3018,13 @@ class CReferenceType(BaseType):
else
:
return
type
(
self
)(
base_type
)
def
as_returned_type
(
self
):
returned_base_type
=
self
.
ref_base_type
.
as_returned_type
()
if
returned_base_type
==
self
.
ref_base_type
:
return
self
else
:
return
CReferenceType
(
returned_base_type
)
def
deduce_template_params
(
self
,
actual
):
return
self
.
ref_base_type
.
deduce_template_params
(
actual
)
...
...
@@ -4618,6 +4643,8 @@ class CypClassType(CppClassType):
def
assignable_from_resolved_type
(
self
,
other_type
):
if
other_type
.
is_const_cyp_class
:
return
0
if
other_type
.
is_qualified_cyp_class
and
other_type
.
qualifier
!=
'iso~'
:
return
0
if
other_type
.
is_ptr
and
other_type
.
base_type
.
is_cpp_class
and
other_type
.
base_type
.
is_subclass
(
self
)
or
other_type
.
is_null_ptr
:
return
1
return
super
(
CypClassType
,
self
).
assignable_from_resolved_type
(
other_type
)
...
...
@@ -4733,6 +4760,9 @@ class ConstCypclassType(BaseType):
def
as_argument_type
(
self
):
return
self
def
as_returned_type
(
self
):
return
self
def
deduce_template_params
(
self
,
actual
):
return
self
.
const_base_type
.
deduce_template_params
(
actual
)
...
...
@@ -4772,13 +4802,20 @@ class ConstCypclassType(BaseType):
class
QualifiedCypclassType
(
BaseType
):
"A qualified cypclass reference"
# qualifier string the qualifier keyword
# qualifier string the qualifier keyword
: ('active' | 'iso' | 'iso~' | 'iso!' )
subtypes
=
[
'qual_base_type'
]
is_cyp_class
=
1
is_qualified_cyp_class
=
1
assignable_to
=
{
'active'
:
(
'active'
,
'iso~'
),
'iso'
:
(
'iso~'
,),
'iso~'
:
(),
'iso!'
:
(),
}
def
__init__
(
self
,
base_type
,
qualifier
):
assert
base_type
.
is_cyp_class
self
.
qual_base_type
=
base_type
...
...
@@ -4830,6 +4867,11 @@ class QualifiedCypclassType(BaseType):
def
as_argument_type
(
self
):
return
self
def
as_returned_type
(
self
):
if
self
.
qualifier
==
'iso'
:
return
QualifiedCypclassType
(
self
.
qual_base_type
,
'iso~'
)
return
self
def
deduce_template_params
(
self
,
actual
):
return
self
.
qual_base_type
.
deduce_template_params
(
actual
)
...
...
@@ -4848,7 +4890,7 @@ class QualifiedCypclassType(BaseType):
return
self
.
assignable_from_resolved_type
(
src_type
.
resolve
())
def
assignable_from_resolved_type
(
self
,
src_type
):
if
src_type
.
is_qualified_cyp_class
and
s
elf
.
qualifier
==
src_type
.
qualifier
:
if
src_type
.
is_qualified_cyp_class
and
s
rc_type
.
qualifier
in
self
.
assignable_to
[
self
.
qualifier
]
:
return
self
.
qual_base_type
.
assignable_from_resolved_type
(
src_type
.
qual_base_type
)
return
0
...
...
Cython/Compiler/Symtab.py
View file @
11915abb
...
...
@@ -3272,6 +3272,8 @@ class QualifiedCypclassScope(Scope):
def
qualified_cypclass_scope
(
base_type_scope
,
qualifier
):
if
qualifier
==
'active'
:
return
ActiveCypclassScope
(
base_type_scope
)
elif
qualifier
.
startswith
(
'iso'
):
return
IsoCypclassScope
(
base_type_scope
)
else
:
return
QualifiedCypclassScope
(
base_type_scope
,
qualifier
)
...
...
@@ -3293,6 +3295,61 @@ class ActiveCypclassScope(QualifiedCypclassScope):
return
base_entry
.
active_entry
class
IsoCypclassScope
(
QualifiedCypclassScope
):
def
__init__
(
self
,
base_type_scope
):
QualifiedCypclassScope
.
__init__
(
self
,
base_type_scope
,
'iso'
)
def
adapt
(
self
,
fieldtype
,
qualifier
=
'iso'
):
if
fieldtype
.
is_qualified_cyp_class
:
# attribute is sendable (either 'iso' or 'active')
return
fieldtype
elif
fieldtype
.
is_cyp_class
:
# viewpoint adaptation
return
PyrexTypes
.
cyp_class_qualified_type
(
fieldtype
,
qualifier
)
else
:
return
fieldtype
def
adapt_arg_type
(
self
,
arg
):
arg
=
copy
.
copy
(
arg
)
arg
.
type
=
self
.
adapt
(
arg
.
type
)
return
arg
def
adapt_method_entry
(
self
,
base_entry
):
iso_method_type
=
copy
.
copy
(
base_entry
.
type
)
# The return type should be treated as 'iso' but cannot be consumed
return_type
=
self
.
adapt
(
base_entry
.
type
.
return_type
,
qualifier
=
'iso!'
)
iso_method_type
.
return_type
=
return_type
iso_method_type
.
args
=
[
self
.
adapt_arg_type
(
arg
)
for
arg
in
base_entry
.
type
.
args
]
if
hasattr
(
base_entry
.
type
,
'op_arg_struct'
):
iso_method_type
.
op_arg_struct
=
entry
.
type
.
op_arg_struct
entry
=
copy
.
copy
(
base_entry
)
entry
.
type
=
iso_method_type
return
entry
def
resolve
(
self
,
name
):
base_entry
=
self
.
base_type_scope
.
lookup_here
(
name
)
if
base_entry
is
None
:
return
None
if
base_entry
.
is_type
:
return
base_entry
if
base_entry
.
is_cfunction
:
iso_alternatives
=
[]
for
e
in
base_entry
.
all_alternatives
():
iso_entry
=
self
.
adapt_method_entry
(
e
)
iso_alternatives
.
append
(
iso_entry
)
iso_entry
.
overloaded_alternatives
=
iso_alternatives
return
iso_alternatives
[
0
]
else
:
base_entry_type
=
base_entry
.
type
adapted_type
=
self
.
adapt
(
base_entry_type
)
if
adapted_type
is
base_entry_type
:
return
base_entry
else
:
entry
=
copy
.
copy
(
base_entry
)
entry
.
type
=
adapted_type
return
entry
class
TemplateScope
(
Scope
):
def
__init__
(
self
,
name
,
outer_scope
):
Scope
.
__init__
(
self
,
name
,
outer_scope
,
None
)
...
...
Cython/Compiler/TypeInference.py
View file @
11915abb
...
...
@@ -538,6 +538,8 @@ def simply_type(result_type, pos):
result_type
=
result_type
.
ref_base_type
if
result_type
.
is_cv_qualified
:
result_type
=
result_type
.
cv_base_type
if
result_type
.
is_qualified_cyp_class
and
result_type
.
qualifier
==
'iso~'
:
result_type
=
PyrexTypes
.
cyp_class_qualified_type
(
result_type
.
qual_base_type
,
'iso'
)
if
result_type
.
is_cpp_class
:
result_type
.
check_nullary_constructor
(
pos
)
if
result_type
.
is_array
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment