8000 [mypyc] Fix some nondeterminism caused by iterating over sets/dicts (… · python/mypy@bd0271b · GitHub
[go: up one dir, main page]

Skip to content

Commit bd0271b

Browse files
authored
[mypyc] Fix some nondeterminism caused by iterating over sets/dicts (#7594)
Tested by compiling mypy and comparing outputs on Python 3.5.
1 parent 8b86349 commit bd0271b

File tree

4 files changed

+10
-7
lines changed

4 files changed

+10
-7
lines changed

mypyc/emitclass.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ def wrapper_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
6969

7070
def generate_slots(cl: ClassIR, table: SlotTable, emitter: Emitter) -> Dict[str, str]:
7171
fields = OrderedDict() # type: Dict[str, str]
72-
for name, (slot, generator) in table.items():
72+
# Sort for determinism on Python 3.5
73+
for name, (slot, generator) in sorted(table.items()):
7374
method = cl.get_method(name)
7475
if method:
7576
fields[slot] = generator(cl, method, emitter)

mypyc/emitwrapper.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ def generate_dunder_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
127127

128128
def generate_richcompare_wrapper(cl: ClassIR, emitter: Emitter) -> Optional[str]:
129129
"""Generates a wrapper for richcompare dunder methods."""
130-
matches = [name for name in RICHCOMPARE_OPS if cl.has_method(name)]
130+
# Sort for determinism on Python 3.5
131+
matches = sorted([name for name in RICHCOMPARE_OPS if cl.has_method(name)])
131132
if not matches:
132133
return None
133134

mypyc/genops.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ def __init__(self) -> None:
361361
self.type_to_ir = {} # type: Dict[TypeInfo, ClassIR]
362362
self.func_to_decl = {} # type: Dict[SymbolNode, FuncDecl]
363363
# Maps integer, float, and unicode literals to a static name
364-
self.literals = {} # type: LiteralsMap
364+
self.literals = OrderedDict() # type: LiteralsMap
365365

366366
def type_to_rtype(self, typ: Optional[Type]) -> RType:
367367
if typ is None:
@@ -1873,7 +1873,8 @@ def c() -> None:
18731873
env_for_func = self.fn_info.callable_class
18741874

18751875
if self.fn_info.fitem in self.free_variables:
1876-
for var in self.free_variables[self.fn_info.fitem]:
1876+
# Sort the variables to keep things deterministic
1877+
for var in sorted(self.free_variables[self.fn_info.fitem], key=lambda x: x.name()):
18771878
if isinstance(var, Var):
18781879
rtype = self.type_to_rtype(var.type)
18791880
self.add_var_to_env_class(var, rtype, env_for_func, reassign=False)

mypyc/prebuildvisitor.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ def __init__(self) -> None:
2727
self.prop_setters = set() # type: Set[FuncDef]
2828
# A map from any function that contains nested functions to
2929
# a set of all the functions that are nested within it.
30-
self.encapsulating_funcs = dict() # type: Dict[FuncItem, Set[FuncItem]]
30+
self.encapsulating_funcs = {} # type: Dict[FuncItem, List[FuncItem]]
3131
# A map from a nested func to it's parent/encapsulating func.
32-
self.nested_funcs = dict() # type: Dict[FuncItem, FuncItem]
32+
self.nested_funcs = {} # type: Dict[FuncItem, FuncItem]
3333
self.funcs_to_decorators = {} # type: Dict[FuncDef, List[Expression]]
3434

3535
def add_free_variable(self, symbol: SymbolNode) -> None:
@@ -57,7 +57,7 @@ def visit_func(self, func: FuncItem) -> None:
5757
# being a nested function.
5858
if self.funcs:
5959
# Add the new func to the set of nested funcs within the func at top of the func stack.
60-
self.encapsulating_funcs.setdefault(self.funcs[-1], set()).add(func)
60+
self.encapsulating_funcs.setdefault(self.funcs[-1], []).append(func)
6161
# Add the func at top of the func stack as the parent of new func.
6262
self.nested_funcs[func] = self.funcs[-1]
6363

0 commit comments

Comments
 (0)
0