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
109e1ace
Commit
109e1ace
authored
Jun 13, 2020
by
Xavier Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Emulate Python MRO by adding virtual methods in derived cypclasses forwarding to correct method
parent
174755c6
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
54 additions
and
10 deletions
+54
-10
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+0
-2
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+42
-0
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+6
-5
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+6
-3
No files found.
Cython/Compiler/ExprNodes.py
View file @
109e1ace
...
@@ -7424,8 +7424,6 @@ class AttributeNode(ExprNode):
...
@@ -7424,8 +7424,6 @@ class AttributeNode(ExprNode):
if
obj
.
type
.
is_cpp_class
and
self
.
entry
and
self
.
entry
.
is_cfunction
:
if
obj
.
type
.
is_cpp_class
and
self
.
entry
and
self
.
entry
.
is_cfunction
:
# the entry might have been resolved to an overladed alternative in the meantime
# the entry might have been resolved to an overladed alternative in the meantime
self
.
member
=
self
.
entry
.
cname
self
.
member
=
self
.
entry
.
cname
if
obj
.
type
.
is_cyp_class
and
self
.
entry
and
self
.
entry
.
from_type
:
self
.
member
=
"%s::%s"
%
(
self
.
entry
.
from_type
.
empty_declaration_code
(),
self
.
member
)
return
"%s%s%s"
%
(
obj_code
,
self
.
op
,
self
.
member
)
return
"%s%s%s"
%
(
obj_code
,
self
.
op
,
self
.
member
)
def
generate_result_code
(
self
,
code
):
def
generate_result_code
(
self
,
code
):
...
...
Cython/Compiler/ModuleNode.py
View file @
109e1ace
...
@@ -992,6 +992,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -992,6 +992,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
constructor
=
scope
.
lookup_here
(
"<constructor>"
)
constructor
=
scope
.
lookup_here
(
"<constructor>"
)
for
constructor_alternative
in
constructor
.
all_alternatives
():
for
constructor_alternative
in
constructor
.
all_alternatives
():
code
.
putln
(
"static %s;"
%
constructor_alternative
.
type
.
declaration_code
(
constructor_alternative
.
cname
))
code
.
putln
(
"static %s;"
%
constructor_alternative
.
type
.
declaration_code
(
constructor_alternative
.
cname
))
self
.
generate_cyp_class_mro_method_resolution
(
scope
,
code
)
elif
constructor
or
py_attrs
:
elif
constructor
or
py_attrs
:
if
constructor
:
if
constructor
:
for
constructor_alternative
in
constructor
.
all_alternatives
():
for
constructor_alternative
in
constructor
.
all_alternatives
():
...
@@ -1081,6 +1082,47 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -1081,6 +1082,47 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code
.
globalstate
.
use_utility_code
(
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load
(
"CyObjects"
,
"CyObjects.cpp"
,
proto_block
=
"utility_code_proto_before_types"
))
UtilityCode
.
load
(
"CyObjects"
,
"CyObjects.cpp"
,
proto_block
=
"utility_code_proto_before_types"
))
def
generate_cyp_class_mro_method_resolution
(
self
,
scope
,
code
):
"""
Generate overriding methods in derived cypclasses to forward calls to the correct method according
to the MRO, regardless of the type of the pointer to the object through which the call is made.
In other words: emulate Python MRO lookup rules using only C++ virtual methods.
"""
inherited_methods
=
[
e
for
entry
in
scope
.
entries
.
values
()
for
e
in
entry
.
all_alternatives
()
if
e
.
is_cfunction
and
e
.
from_type
and
e
.
mro_index
>
0
and
not
e
.
type
.
is_static_method
# avoid dealing with static methods for now
and
e
.
name
not
in
(
"<init>"
,
"<del>"
)
and
not
e
.
type
.
has_varargs
# avoid dealing with varargs for now (is this ever required anyway ?)
]
if
inherited_methods
:
code
.
putln
(
""
)
code
.
putln
(
"/* make all inherited (non overriden) methods resolve correctly according to the MRO */"
)
for
e
in
inherited_methods
:
modifiers
=
code
.
build_function_modifiers
(
e
.
func_modifiers
)
arg_decls
=
[
arg
.
declaration_code
()
for
arg
in
e
.
type
.
args
]
arg_names
=
[
arg
.
cname
for
arg
in
e
.
type
.
args
]
if
e
.
type
.
optional_arg_count
:
opt_name
=
Naming
.
optional_args_cname
arg_decls
.
append
(
e
.
type
.
op_arg_struct
.
declaration_code
(
opt_name
))
arg_names
.
append
(
opt_name
)
header
=
e
.
type
.
function_header_code
(
e
.
cname
,
", "
.
join
(
arg_decls
))
if
not
e
.
name
.
startswith
(
"operator "
):
header
=
e
.
type
.
return_type
.
declaration_code
(
header
)
return_code
=
""
if
e
.
type
.
return_type
.
is_void
else
"return "
resolution
=
e
.
from_type
.
empty_declaration_code
()
body
=
"%s%s::%s(%s);"
%
(
return_code
,
resolution
,
e
.
cname
,
", "
.
join
(
arg_names
))
code
.
putln
(
"virtual %s%s {%s}"
%
(
modifiers
,
header
,
body
))
if
inherited_methods
:
code
.
putln
(
""
)
def
generate_cyp_class_attrs_destructor_definition
(
self
,
entry
,
code
):
def
generate_cyp_class_attrs_destructor_definition
(
self
,
entry
,
code
):
scope
=
entry
.
type
.
scope
scope
=
entry
.
type
.
scope
cypclass_attrs
=
[
e
for
e
in
scope
.
var_entries
cypclass_attrs
=
[
e
for
e
in
scope
.
var_entries
...
...
Cython/Compiler/PyrexTypes.py
View file @
109e1ace
...
@@ -2804,10 +2804,10 @@ class CFuncType(CType):
...
@@ -2804,10 +2804,10 @@ class CFuncType(CType):
return
0
return
0
return
1
return
1
def
compatible_signature_with
(
self
,
other_type
,
as_cmethod
=
0
):
def
compatible_signature_with
(
self
,
other_type
,
as_cmethod
=
0
,
ignore_return_type
=
0
):
return
self
.
compatible_signature_with_resolved_type
(
other_type
.
resolve
(),
as_cmethod
)
return
self
.
compatible_signature_with_resolved_type
(
other_type
.
resolve
(),
as_cmethod
,
ignore_return_type
)
def
compatible_signature_with_resolved_type
(
self
,
other_type
,
as_cmethod
):
def
compatible_signature_with_resolved_type
(
self
,
other_type
,
as_cmethod
,
ignore_return_type
=
0
):
#print "CFuncType.same_c_signature_as_resolved_type:", \
#print "CFuncType.same_c_signature_as_resolved_type:", \
# self, other_type, "as_cmethod =", as_cmethod ###
# self, other_type, "as_cmethod =", as_cmethod ###
if
other_type
is
error_type
:
if
other_type
is
error_type
:
...
@@ -2830,8 +2830,9 @@ class CFuncType(CType):
...
@@ -2830,8 +2830,9 @@ class CFuncType(CType):
return
0
return
0
if
self
.
has_varargs
!=
other_type
.
has_varargs
:
if
self
.
has_varargs
!=
other_type
.
has_varargs
:
return
0
return
0
if
not
self
.
return_type
.
subtype_of_resolved_type
(
other_type
.
return_type
):
if
not
ignore_return_type
:
return
0
if
not
self
.
return_type
.
subtype_of_resolved_type
(
other_type
.
return_type
):
return
0
if
not
self
.
same_calling_convention_as
(
other_type
):
if
not
self
.
same_calling_convention_as
(
other_type
):
return
0
return
0
if
self
.
nogil
!=
other_type
.
nogil
:
if
self
.
nogil
!=
other_type
.
nogil
:
...
...
Cython/Compiler/Symtab.py
View file @
109e1ace
...
@@ -506,7 +506,12 @@ class Scope(object):
...
@@ -506,7 +506,12 @@ class Scope(object):
if
type
.
is_cfunction
and
old_entry
.
type
.
is_cfunction
and
self
.
is_cpp
():
if
type
.
is_cfunction
and
old_entry
.
type
.
is_cfunction
and
self
.
is_cpp
():
cpp_override_allowed
=
True
cpp_override_allowed
=
True
for
index
,
alt_entry
in
enumerate
(
old_entry
.
all_alternatives
()):
for
index
,
alt_entry
in
enumerate
(
old_entry
.
all_alternatives
()):
if
type
.
compatible_signature_with
(
alt_entry
.
type
):
# in a cypclass, a method can hide a method inherited from a different class
# regardless of their return types
ignore_return_type
=
(
self
.
is_cyp_class_scope
and
alt_entry
.
is_inherited
and
alt_entry
.
from_type
is
not
from_type
)
if
type
.
compatible_signature_with
(
alt_entry
.
type
,
ignore_return_type
=
ignore_return_type
):
ccp_override_allowed
=
False
ccp_override_allowed
=
False
...
@@ -2927,7 +2932,6 @@ class CppClassScope(Scope):
...
@@ -2927,7 +2932,6 @@ class CppClassScope(Scope):
entry
.
is_cfunction
=
base_entry
.
is_cfunction
entry
.
is_cfunction
=
base_entry
.
is_cfunction
if
entry
.
is_cfunction
:
if
entry
.
is_cfunction
:
entry
.
func_cname
=
base_entry
.
func_cname
entry
.
func_cname
=
base_entry
.
func_cname
self
.
inherited_var_entries
.
append
(
entry
)
for
base_entry
in
base_scope
.
type_entries
:
for
base_entry
in
base_scope
.
type_entries
:
if
base_entry
.
name
not
in
base_templates
:
if
base_entry
.
name
not
in
base_templates
:
...
@@ -2935,7 +2939,6 @@ class CppClassScope(Scope):
...
@@ -2935,7 +2939,6 @@ class CppClassScope(Scope):
base_entry
.
pos
,
base_entry
.
cname
,
base_entry
.
pos
,
base_entry
.
cname
,
base_entry
.
visibility
,
defining
=
0
)
base_entry
.
visibility
,
defining
=
0
)
entry
.
is_inherited
=
1
entry
.
is_inherited
=
1
self
.
inherited_type_entries
.
append
(
entry
)
def
specialize
(
self
,
values
,
type_entry
):
def
specialize
(
self
,
values
,
type_entry
):
scope
=
CppClassScope
(
self
.
name
,
self
.
outer_scope
)
scope
=
CppClassScope
(
self
.
name
,
self
.
outer_scope
)
...
...
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