# Commits

committed 6bf8c42

Remove invalid optimization: x in tuple => x in set

# NOTES

`    shadowed at runtime.`
`  - x in [a, b, c] => x in {a, b, c}.`
`    A list can contain non-hashable objects, a set cannot.`
`+   x can be non-hashable, whereas x in set() would fail.`
`  - [x*2 for x in "abc"] => (x*2 for x in "abc").`
`    The generator expression doesn't set the local variable x, and generators`
`    are slower than list comprehensions.`

`  * Replace list with tuple (need "builtin_funcs" feature). Examples:`
` `
`    - ``for x in [1, 2, 3]: pass`` => ``for x in (1, 2, 3): pass```
`+   - ``x in [1, 2, 3]`` => ``x in (1, 2, 3)```
`    - ``list([x, y, z])`` => ``[x, y, z]```
`    - ``set([1, 2, 3])`` => ``{1, 2, 3}`` (Python 2.7+)`
` `

# astoptimizer/optimizer.py

`         return self.compare_cst(node, op, left_cst, right_cst)`
` `
`     def compare_in(self, data):`
`+        if isinstance(data, ast.List):`
`+            # x in [1, 2] => x in (1, 2)`
`+            return self.list_to_tuple(data)`
`+`
`         if sys.version_info >= (3, 2):`
`+            constant = self.get_constant(data, frozenset)`
`+            if constant is UNSET:`
`+                return`
`+            # x in frozenset((1, 2)) => x in {1, 2}`
`             # Python 3.2+ bytecode peepholer replaces x in {1, 2} with x in`
`             # frozenset({1, 2}), where frozenset({1, 2}) is a constant.`
`-            if isinstance(data, ast.List):`
`-                return new_set_elts(data, data.elts)`
`-`
`-            constant = self.get_constant(data, (tuple, frozenset))`
`-            if constant is UNSET:`
`-                return`
`-            # x in (1, 2) => x in {1, 2}`
`-            # x in frozenset((1, 2)) => x in {1, 2}`
`             return new_set(data, constant)`
`-        else:`
`-            if isinstance(data, ast.List):`
`-                # x in [1, 2] => x in (1, 2)`
`-                return self.list_to_tuple(data)`
` `
`     def visit_Compare(self, node):`
`         # FIXME: implement 1 < 2 < 3`

# astoptimizer/tests.py

`         self.check("not(x not in y)", self.text_ast("x in y"))`
` `
`     def test_Compare_in(self):`
`+        config = self.create_config('builtin_funcs')`
`+`
`+        # constant`
`         self.check('"xxx" in "abcdef"', self.text_bool(False))`
`         self.check('"xxx" not in "abcdef"', self.text_bool(True))`
`         self.check('"bcd" in "abcdef"', self.text_bool(True))`
`         self.check('0 in (1, 2, 3)', self.text_bool(False))`
`         self.check('2 in (1, 2, 3)', self.text_bool(True))`
` `
`+        # generic`
`+        self.check_not_optimized("x in (1, 2, 3)")`
`+        self.check("x in [1, 2, 3]", self.text_ast('x in (1, 2, 3)'))`
`+        self.check("x not in [1, 2, 3]", self.text_ast('x not in (1, 2, 3)'))`
`+`
`         if sys.version_info >= (3, 2):`
`-            config = self.create_config('builtin_funcs')`
`+            self.check("x in frozenset((1, 2, 3))", self.text_ast('x in {1, 2, 3}'), config)`
`+        else:`
`+            self.check_not_optimized("x in frozenset((1, 2, 3))", config)`
` `
`-            self.check("x in (1, 2, 3)", self.text_ast('x in {1, 2, 3}'))`
`-            self.check("x in [1, 2, 3]", self.text_ast('x in {1, 2, 3}'))`
`-            self.check("x in frozenset((1, 2, 3))", self.text_ast('x in {1, 2, 3}'), config)`
`+        if sys.version_info >= (2, 7):`
`+            self.check("x in set((1, 2, 3))",`
`+                       self.text_ast("x in {1, 2, 3}"),`
`+                       config)`
`             self.check_not_optimized("x in {1, 2, 3}")`
`+        else:`
`+            self.check_not_optimized("x in set((1, 2, 3))", config)`
` `
`-            self.check("x not in (1, 2, 3)", self.text_ast('x not in {1, 2, 3}'))`
`-        else:`
`-            self.check_not_optimized("x in (1, 2, 3)")`
`-            self.check("x in [1, 2, 3]", self.text_ast("x in (1, 2, 3)"))`
`-            self.check_not_optimized("x in set((1, 2, 3))")`
`-            self.check_not_optimized("x in frozenset((1, 2, 3))")`
`-`
`-            self.check("x not in [1, 2, 3]", self.text_ast('x not in (1, 2, 3)'))`
`         self.check("not(x in y)", self.text_ast("x not in y"))`
`         self.check("not(x not in y)", self.text_ast("x in y"))`
` `