Skip to content

Commit bd207f5

Browse files
committed
Simplify the implementation with certain compromises
Namely the inability to handle 1.2 transformations, and perhaps performance
1 parent fbd0602 commit bd207f5

File tree

2 files changed

+128
-187
lines changed

2 files changed

+128
-187
lines changed

py/dml/structure.py

Lines changed: 99 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -812,26 +812,6 @@ def report_poverride(sup, inf, obj_specs):
812812
else:
813813
report(POVERRIDE_IMPORT(sup_obj.site, inf.desc.text))
814814

815-
def sort_method_declarations(declarations, obj_specs):
816-
if dml.globals.dml_version == (1, 2):
817-
# Backward compatibility: If there is exactly one default and
818-
# one non-default implementation, then disregard template
819-
# instantiation relations.
820-
implementations = [impl for impl in declarations if not impl.abstract]
821-
if len(implementations) == 2:
822-
[m1, m2] = implementations
823-
# create fake ranks to make sure methods end up in the right order
824-
if m1.overridable and not m2.overridable:
825-
if logging.show_porting:
826-
report_poverride(m2.obj_spec.rank, m1.obj_spec.rank,
827-
obj_specs)
828-
m2.rank = Rank({m1.rank}, m2.rank.desc)
829-
elif not m1.overridable and m2.overridable:
830-
if logging.show_porting:
831-
report_poverride(m1.rank, m2.rank, obj_specs)
832-
m1.rank = Rank({m2.rank}, m1.rank.desc)
833-
return traits.sort_method_declarations(declarations)
834-
835815
def merge_subobj_defs(def1, def2, parent):
836816
(objtype, name, arrayinfo, obj_specs1) = def1
837817
(objtype2, name2, arrayinfo2, obj_specs2) = def2
@@ -1460,14 +1440,12 @@ def __init__(self, name, vtable_trait):
14601440
super(AbstractTraitMethodHandle, self).__init__(
14611441
site, name, obj_spec, True, True, None, *sig)
14621442

1463-
1464-
14651443
def process_method_declarations(obj, name, declarations,
14661444
shared_impl_traits, shared_absdecl_traits,
14671445
obj_specs, vtable_nothrow_dml14):
14681446
# A method can have both shared and non-shared declarations.
14691447
# We will create a MethodHandle object for either, which
1470-
# sort_method_declarations() uses to resolve override order.
1448+
# sort_method_implementations() uses to resolve override order.
14711449
unshared_methods = [
14721450
ObjMethodHandle(method_ast, obj_spec)
14731451
for (obj_spec, method_ast) in declarations]
@@ -1480,9 +1458,55 @@ def process_method_declarations(obj, name, declarations,
14801458
AbstractTraitMethodHandle(name, vtable_trait)
14811459
for vtable_trait in shared_absdecl_traits]
14821460

1483-
(default_map, decl_ancestry_map, method_order,
1484-
abstract_decls) = sort_method_declarations(
1485-
unshared_methods + shared_methods + shared_abstract_methods, obj_specs)
1461+
methods = unshared_methods + shared_methods + shared_abstract_methods
1462+
impls = [meth for meth in methods if not meth.abstract]
1463+
1464+
if dml.globals.dml_version == (1, 2) and len(impls) == 2:
1465+
# Backward compatibility: If there is exactly one default and
1466+
# one non-default implementation, then disregard template
1467+
# instantiation relations.
1468+
[m1, m2] = impls
1469+
# create fake ranks to make sure methods end up in the right order
1470+
if m1.overridable and not m2.overridable:
1471+
if logging.show_porting:
1472+
report_poverride(m2.obj_spec.rank, m1.obj_spec.rank, obj_specs)
1473+
m2.rank = Rank({m1.rank}, m2.rank.desc)
1474+
elif not m1.overridable and m2.overridable:
1475+
if logging.show_porting:
1476+
report_poverride(m1.rank, m2.rank, obj_specs)
1477+
m1.rank = Rank({m2.rank}, m1.rank.desc)
1478+
1479+
rank_to_methods = {}
1480+
for meth in methods:
1481+
rank_to_methods.setdefault(meth.rank, []).append(meth)
1482+
1483+
minimal_ancestry = traits.calc_minimal_ancestry(frozenset(rank_to_methods))
1484+
1485+
for (r, meths) in rank_to_methods.items():
1486+
[impl, *others] = sorted(meths, key=lambda meth: meth.abstract)
1487+
if impl.abstract:
1488+
continue
1489+
1490+
for other in others:
1491+
if not other.abstract:
1492+
# two conflicting method definitions in the same block
1493+
raise ENAMECOLL(other.site, impl.site, other.name)
1494+
1495+
if (not impl.shared # Handled separately
1496+
and impl.site.provisional_enabled(
1497+
provisional.explicit_method_decls)):
1498+
existing = others or [m for anc in minimal_ancestry[r]
1499+
for m in rank_to_methods[anc]]
1500+
if impl.explicit_decl:
1501+
if existing:
1502+
report(EOVERRIDEMETH(impl.site, existing[0].site,
1503+
impl.name,
1504+
'default ' * impl.overridable))
1505+
elif not existing:
1506+
report(ENOVERRIDEMETH(impl.site, impl.name,
1507+
'default ' * impl.overridable))
1508+
1509+
(default_map, method_order) = traits.sort_method_implementations(impls)
14861510

14871511
location = Location(obj, static_indices(obj))
14881512

@@ -1497,29 +1521,39 @@ def process_method_declarations(obj, name, declarations,
14971521
else:
14981522
nonshared_impls.append(impl)
14991523

1500-
if not nonshared_impls:
1501-
if shared_methods:
1502-
shared_impl_sig = shared_methods[0].signature
1503-
for decl in abstract_decls:
1504-
if decl.shared:
1505-
# handled separately
1506-
continue
1507-
1508-
try:
1509-
traits.typecheck_method_override(shared_impl_sig,
1510-
decl.signature)
1511-
except DMLError as e:
1512-
report(e)
1513-
return None
1524+
abstract_decls = [meth for meth in methods
1525+
if meth.abstract and not meth.shared]
1526+
1527+
# Typecheck nonshared abstract decls against each other
1528+
for (meth0, meth1) in itertools.pairwise(abstract_decls):
1529+
typecheck_method_override(meth0.method_ast, meth1.method_ast,
1530+
location)
1531+
1532+
# Then typecheck any shared abstract declaration -- or, failing that,
1533+
# the highest ranking implementation -- against some arbitrary abstract
1534+
# decl
1535+
# This prioritization is because we consider the trait authorative for what
1536+
# the type should be.
1537+
if abstract_decls:
1538+
if shared_abstract_methods:
1539+
traits.typecheck_method_override(
1540+
abstract_decls[0].signature,
1541+
shared_abstract_methods[0].signature)
1542+
elif method_order:
1543+
impl = method_order[0]
1544+
if impl.shared:
1545+
traits.typecheck_method_override(
1546+
impl.signature, abstract_decls[0].signature)
1547+
else:
1548+
typecheck_method_override(
1549+
impl.method_ast, abstract_decls[0].method_ast, location)
15141550
else:
1515-
assert abstract_decls
1516-
for decl in abstract_decls:
1517-
# We favor reporting EABSTEMPLATE (done by the caller)
1518-
# over EABSMETH
1519-
if not decl.shared:
1520-
report(EABSMETH(decl.site, name))
1551+
# This only done in this path because we favor reporting
1552+
# EABSTEMPLATE (done by the caller) over EABSMETH
1553+
report(EABSMETH(abstract_decls[0].site, name))
15211554

1522-
return None
1555+
if not nonshared_impls:
1556+
return None
15231557

15241558
impl_to_method = {}
15251559
for (default_level, impl) in reversed(list(enumerate(nonshared_impls))):
@@ -1553,11 +1587,20 @@ def process_method_declarations(obj, name, declarations,
15531587
impl.site, vtable_nothrow_dml14,
15541588
obj, name, body, rbrace_site)
15551589
throws = False
1556-
1557-
for ancestor_decl in decl_ancestry_map[impl]:
1590+
for overridden in default_map[impl]:
1591+
if not overridden.overridable:
1592+
raise EDMETH(impl.site, overridden.site, name)
1593+
# the override of trait ASTs is checked later, by
1594+
# traits.typecheck_method_override
1595+
if not overridden.shared:
1596+
# captured with ETMETH above
1597+
assert not impl.shared
1598+
typecheck_method_override(impl.method_ast,
1599+
overridden.method_ast,
1600+
location)
15581601
if (impl.site.dml_version() == (1, 2) and throws
1559-
and not ancestor_decl.throws
1560-
and ancestor_decl.site.dml_version() == (1, 4)):
1602+
and not overridden.throws
1603+
and overridden.site.dml_version() == (1, 4)):
15611604
# If a 1.4 library file defines an overrideable
15621605
# non-throwing method, and a 1.2 device overrides
15631606
# this, then assume that the method was never
@@ -1566,11 +1609,12 @@ def process_method_declarations(obj, name, declarations,
15661609
# We modify the override to nothrow, and patch it
15671610
# to catch any exceptions.
15681611
body = wrap_method_body_in_try(
1569-
impl.site, ancestor_decl.site,
1612+
impl.site, overridden.site,
15701613
obj, name, body, rbrace_site)
15711614
throws = False
1572-
elif throws != ancestor_decl.throws:
1573-
if dml.globals.dml_version == (1, 2) and not throws:
1615+
elif throws != overridden.throws:
1616+
if (dml.globals.dml_version == (1, 2)
1617+
and not throws):
15741618
# Permit a nonthrowing method to override
15751619
# a throwing 1.2 method, with no warning.
15761620
# This is needed for some common standard
@@ -1581,45 +1625,12 @@ def process_method_declarations(obj, name, declarations,
15811625
else:
15821626
annotation = ("no"*(dml.globals.dml_version != (1, 4))
15831627
+ "throw")
1584-
raise EMETH(impl.site, ancestor_decl.site,
1628+
raise EMETH(impl.site, overridden.site,
15851629
f"different {annotation} annotations")
15861630

1587-
for overridden in default_map[impl]:
1588-
if not overridden.overridable:
1589-
raise EDMETH(impl.site, overridden.site, name)
1590-
# the override of trait ASTs is checked later, by
1591-
# traits.typecheck_method_override
1592-
if not overridden.shared:
1593-
# captured with ETMETH above
1594-
assert not impl.shared
1595-
typecheck_method_override(impl.method_ast,
1596-
overridden.method_ast,
1597-
location)
1598-
1599-
# Check compatibility with all non-shared abstract declarations against
1600-
# the highest-ranked implementation
1601-
if default_level == 0:
1602-
for decl in abstract_decls:
1603-
if decl.shared:
1604-
# handled separately
1605-
continue
1606-
1607-
typecheck_method_override(impl.method_ast,
1608-
decl.method_ast,
1609-
location)
1610-
1611-
if (not decl.throws and throws
1612-
and impl.dml_version() != (1, 4)):
1613-
1614-
body = wrap_method_body_in_try(
1615-
impl.site, decl.site, obj, name, body, rbrace_site)
1616-
throws = False
1617-
16181631
template = (impl.obj_spec.parent_template
16191632
if isinstance(impl.obj_spec, InstantiatedTemplateSpec)
16201633
else None)
1621-
if isinstance(body, bool):
1622-
report(ICE(impl.site, f"wut: {repr(impl)}"))
16231634
method = mkmethod(impl.site, rbrace_site,
16241635
location,
16251636
obj, name, inp_ast,

0 commit comments

Comments
 (0)