# Python code coverage for Lib/test/test_peepholer.py

# | count | content |
---|---|---|

1 | n/a | import dis |

2 | n/a | import unittest |

3 | n/a | |

4 | n/a | from test.bytecode_helper import BytecodeTestCase |

5 | n/a | |

6 | n/a | class TestTranforms(BytecodeTestCase): |

7 | n/a | |

8 | n/a | def test_unot(self): |

9 | n/a | # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE' |

10 | n/a | def unot(x): |

11 | n/a | if not x == 2: |

12 | n/a | del x |

13 | n/a | self.assertNotInBytecode(unot, 'UNARY_NOT') |

14 | n/a | self.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE') |

15 | n/a | self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE') |

16 | n/a | |

17 | n/a | def test_elim_inversion_of_is_or_in(self): |

18 | n/a | for line, cmp_op in ( |

19 | n/a | ('not a is b', 'is not',), |

20 | n/a | ('not a in b', 'not in',), |

21 | n/a | ('not a is not b', 'is',), |

22 | n/a | ('not a not in b', 'in',), |

23 | n/a | ): |

24 | n/a | code = compile(line, '', 'single') |

25 | n/a | self.assertInBytecode(code, 'COMPARE_OP', cmp_op) |

26 | n/a | |

27 | n/a | def test_global_as_constant(self): |

28 | n/a | # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False |

29 | n/a | def f(): |

30 | n/a | x = None |

31 | n/a | x = None |

32 | n/a | return x |

33 | n/a | def g(): |

34 | n/a | x = True |

35 | n/a | return x |

36 | n/a | def h(): |

37 | n/a | x = False |

38 | n/a | return x |

39 | n/a | |

40 | n/a | for func, elem in ((f, None), (g, True), (h, False)): |

41 | n/a | self.assertNotInBytecode(func, 'LOAD_GLOBAL') |

42 | n/a | self.assertInBytecode(func, 'LOAD_CONST', elem) |

43 | n/a | |

44 | n/a | def f(): |

45 | n/a | 'Adding a docstring made this test fail in Py2.5.0' |

46 | n/a | return None |

47 | n/a | |

48 | n/a | self.assertNotInBytecode(f, 'LOAD_GLOBAL') |

49 | n/a | self.assertInBytecode(f, 'LOAD_CONST', None) |

50 | n/a | |

51 | n/a | def test_while_one(self): |

52 | n/a | # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx |

53 | n/a | def f(): |

54 | n/a | while 1: |

55 | n/a | pass |

56 | n/a | return list |

57 | n/a | for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'): |

58 | n/a | self.assertNotInBytecode(f, elem) |

59 | n/a | for elem in ('JUMP_ABSOLUTE',): |

60 | n/a | self.assertInBytecode(f, elem) |

61 | n/a | |

62 | n/a | def test_pack_unpack(self): |

63 | n/a | for line, elem in ( |

64 | n/a | ('a, = a,', 'LOAD_CONST',), |

65 | n/a | ('a, b = a, b', 'ROT_TWO',), |

66 | n/a | ('a, b, c = a, b, c', 'ROT_THREE',), |

67 | n/a | ): |

68 | n/a | code = compile(line,'','single') |

69 | n/a | self.assertInBytecode(code, elem) |

70 | n/a | self.assertNotInBytecode(code, 'BUILD_TUPLE') |

71 | n/a | self.assertNotInBytecode(code, 'UNPACK_TUPLE') |

72 | n/a | |

73 | n/a | def test_folding_of_tuples_of_constants(self): |

74 | n/a | for line, elem in ( |

75 | n/a | ('a = 1,2,3', (1, 2, 3)), |

76 | n/a | ('("a","b","c")', ('a', 'b', 'c')), |

77 | n/a | ('a,b,c = 1,2,3', (1, 2, 3)), |

78 | n/a | ('(None, 1, None)', (None, 1, None)), |

79 | n/a | ('((1, 2), 3, 4)', ((1, 2), 3, 4)), |

80 | n/a | ): |

81 | n/a | code = compile(line,'','single') |

82 | n/a | self.assertInBytecode(code, 'LOAD_CONST', elem) |

83 | n/a | self.assertNotInBytecode(code, 'BUILD_TUPLE') |

84 | n/a | |

85 | n/a | # Long tuples should be folded too. |

86 | n/a | code = compile(repr(tuple(range(10000))),'','single') |

87 | n/a | self.assertNotInBytecode(code, 'BUILD_TUPLE') |

88 | n/a | # One LOAD_CONST for the tuple, one for the None return value |

89 | n/a | load_consts = [instr for instr in dis.get_instructions(code) |

90 | n/a | if instr.opname == 'LOAD_CONST'] |

91 | n/a | self.assertEqual(len(load_consts), 2) |

92 | n/a | |

93 | n/a | # Bug 1053819: Tuple of constants misidentified when presented with: |

94 | n/a | # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . . |

95 | n/a | # The following would segfault upon compilation |

96 | n/a | def crater(): |

97 | n/a | (~[ |

98 | n/a | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |

99 | n/a | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |

100 | n/a | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |

101 | n/a | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |

102 | n/a | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |

103 | n/a | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |

104 | n/a | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |

105 | n/a | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |

106 | n/a | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |

107 | n/a | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |

108 | n/a | ],) |

109 | n/a | |

110 | n/a | def test_folding_of_lists_of_constants(self): |

111 | n/a | for line, elem in ( |

112 | n/a | # in/not in constants with BUILD_LIST should be folded to a tuple: |

113 | n/a | ('a in [1,2,3]', (1, 2, 3)), |

114 | n/a | ('a not in ["a","b","c"]', ('a', 'b', 'c')), |

115 | n/a | ('a in [None, 1, None]', (None, 1, None)), |

116 | n/a | ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)), |

117 | n/a | ): |

118 | n/a | code = compile(line, '', 'single') |

119 | n/a | self.assertInBytecode(code, 'LOAD_CONST', elem) |

120 | n/a | self.assertNotInBytecode(code, 'BUILD_LIST') |

121 | n/a | |

122 | n/a | def test_folding_of_sets_of_constants(self): |

123 | n/a | for line, elem in ( |

124 | n/a | # in/not in constants with BUILD_SET should be folded to a frozenset: |

125 | n/a | ('a in {1,2,3}', frozenset({1, 2, 3})), |

126 | n/a | ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})), |

127 | n/a | ('a in {None, 1, None}', frozenset({1, None})), |

128 | n/a | ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})), |

129 | n/a | ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})), |

130 | n/a | ): |

131 | n/a | code = compile(line, '', 'single') |

132 | n/a | self.assertNotInBytecode(code, 'BUILD_SET') |

133 | n/a | self.assertInBytecode(code, 'LOAD_CONST', elem) |

134 | n/a | |

135 | n/a | # Ensure that the resulting code actually works: |

136 | n/a | def f(a): |

137 | n/a | return a in {1, 2, 3} |

138 | n/a | |

139 | n/a | def g(a): |

140 | n/a | return a not in {1, 2, 3} |

141 | n/a | |

142 | n/a | self.assertTrue(f(3)) |

143 | n/a | self.assertTrue(not f(4)) |

144 | n/a | |

145 | n/a | self.assertTrue(not g(3)) |

146 | n/a | self.assertTrue(g(4)) |

147 | n/a | |

148 | n/a | |

149 | n/a | def test_folding_of_binops_on_constants(self): |

150 | n/a | for line, elem in ( |

151 | n/a | ('a = 2+3+4', 9), # chained fold |

152 | n/a | ('"@"*4', '@@@@'), # check string ops |

153 | n/a | ('a="abc" + "def"', 'abcdef'), # check string ops |

154 | n/a | ('a = 3**4', 81), # binary power |

155 | n/a | ('a = 3*4', 12), # binary multiply |

156 | n/a | ('a = 13//4', 3), # binary floor divide |

157 | n/a | ('a = 14%4', 2), # binary modulo |

158 | n/a | ('a = 2+3', 5), # binary add |

159 | n/a | ('a = 13-4', 9), # binary subtract |

160 | n/a | ('a = (12,13)[1]', 13), # binary subscr |

161 | n/a | ('a = 13 << 2', 52), # binary lshift |

162 | n/a | ('a = 13 >> 2', 3), # binary rshift |

163 | n/a | ('a = 13 & 7', 5), # binary and |

164 | n/a | ('a = 13 ^ 7', 10), # binary xor |

165 | n/a | ('a = 13 | 7', 15), # binary or |

166 | n/a | ): |

167 | n/a | code = compile(line, '', 'single') |

168 | n/a | self.assertInBytecode(code, 'LOAD_CONST', elem) |

169 | n/a | for instr in dis.get_instructions(code): |

170 | n/a | self.assertFalse(instr.opname.startswith('BINARY_')) |

171 | n/a | |

172 | n/a | # Verify that unfoldables are skipped |

173 | n/a | code = compile('a=2+"b"', '', 'single') |

174 | n/a | self.assertInBytecode(code, 'LOAD_CONST', 2) |

175 | n/a | self.assertInBytecode(code, 'LOAD_CONST', 'b') |

176 | n/a | |

177 | n/a | # Verify that large sequences do not result from folding |

178 | n/a | code = compile('a="x"*1000', '', 'single') |

179 | n/a | self.assertInBytecode(code, 'LOAD_CONST', 1000) |

180 | n/a | |

181 | n/a | def test_binary_subscr_on_unicode(self): |

182 | n/a | # valid code get optimized |

183 | n/a | code = compile('"foo"[0]', '', 'single') |

184 | n/a | self.assertInBytecode(code, 'LOAD_CONST', 'f') |

185 | n/a | self.assertNotInBytecode(code, 'BINARY_SUBSCR') |

186 | n/a | code = compile('"\u0061\uffff"[1]', '', 'single') |

187 | n/a | self.assertInBytecode(code, 'LOAD_CONST', '\uffff') |

188 | n/a | self.assertNotInBytecode(code,'BINARY_SUBSCR') |

189 | n/a | |

190 | n/a | # With PEP 393, non-BMP char get optimized |

191 | n/a | code = compile('"\U00012345"[0]', '', 'single') |

192 | n/a | self.assertInBytecode(code, 'LOAD_CONST', '\U00012345') |

193 | n/a | self.assertNotInBytecode(code, 'BINARY_SUBSCR') |

194 | n/a | |

195 | n/a | # invalid code doesn't get optimized |

196 | n/a | # out of range |

197 | n/a | code = compile('"fuu"[10]', '', 'single') |

198 | n/a | self.assertInBytecode(code, 'BINARY_SUBSCR') |

199 | n/a | |

200 | n/a | def test_folding_of_unaryops_on_constants(self): |

201 | n/a | for line, elem in ( |

202 | n/a | ('-0.5', -0.5), # unary negative |

203 | n/a | ('-0.0', -0.0), # -0.0 |

204 | n/a | ('-(1.0-1.0)', -0.0), # -0.0 after folding |

205 | n/a | ('-0', 0), # -0 |

206 | n/a | ('~-2', 1), # unary invert |

207 | n/a | ('+1', 1), # unary positive |

208 | n/a | ): |

209 | n/a | code = compile(line, '', 'single') |

210 | n/a | self.assertInBytecode(code, 'LOAD_CONST', elem) |

211 | n/a | for instr in dis.get_instructions(code): |

212 | n/a | self.assertFalse(instr.opname.startswith('UNARY_')) |

213 | n/a | |

214 | n/a | # Check that -0.0 works after marshaling |

215 | n/a | def negzero(): |

216 | n/a | return -(1.0-1.0) |

217 | n/a | |

218 | n/a | for instr in dis.get_instructions(code): |

219 | n/a | self.assertFalse(instr.opname.startswith('UNARY_')) |

220 | n/a | |

221 | n/a | # Verify that unfoldables are skipped |

222 | n/a | for line, elem, opname in ( |

223 | n/a | ('-"abc"', 'abc', 'UNARY_NEGATIVE'), |

224 | n/a | ('~"abc"', 'abc', 'UNARY_INVERT'), |

225 | n/a | ): |

226 | n/a | code = compile(line, '', 'single') |

227 | n/a | self.assertInBytecode(code, 'LOAD_CONST', elem) |

228 | n/a | self.assertInBytecode(code, opname) |

229 | n/a | |

230 | n/a | def test_elim_extra_return(self): |

231 | n/a | # RETURN LOAD_CONST None RETURN --> RETURN |

232 | n/a | def f(x): |

233 | n/a | return x |

234 | n/a | self.assertNotInBytecode(f, 'LOAD_CONST', None) |

235 | n/a | returns = [instr for instr in dis.get_instructions(f) |

236 | n/a | if instr.opname == 'RETURN_VALUE'] |

237 | n/a | self.assertEqual(len(returns), 1) |

238 | n/a | |

239 | n/a | def test_elim_jump_to_return(self): |

240 | n/a | # JUMP_FORWARD to RETURN --> RETURN |

241 | n/a | def f(cond, true_value, false_value): |

242 | n/a | return true_value if cond else false_value |

243 | n/a | self.assertNotInBytecode(f, 'JUMP_FORWARD') |

244 | n/a | self.assertNotInBytecode(f, 'JUMP_ABSOLUTE') |

245 | n/a | returns = [instr for instr in dis.get_instructions(f) |

246 | n/a | if instr.opname == 'RETURN_VALUE'] |

247 | n/a | self.assertEqual(len(returns), 2) |

248 | n/a | |

249 | n/a | def test_elim_jump_after_return1(self): |

250 | n/a | # Eliminate dead code: jumps immediately after returns can't be reached |

251 | n/a | def f(cond1, cond2): |

252 | n/a | if cond1: return 1 |

253 | n/a | if cond2: return 2 |

254 | n/a | while 1: |

255 | n/a | return 3 |

256 | n/a | while 1: |

257 | n/a | if cond1: return 4 |

258 | n/a | return 5 |

259 | n/a | return 6 |

260 | n/a | self.assertNotInBytecode(f, 'JUMP_FORWARD') |

261 | n/a | self.assertNotInBytecode(f, 'JUMP_ABSOLUTE') |

262 | n/a | returns = [instr for instr in dis.get_instructions(f) |

263 | n/a | if instr.opname == 'RETURN_VALUE'] |

264 | n/a | self.assertEqual(len(returns), 6) |

265 | n/a | |

266 | n/a | def test_elim_jump_after_return2(self): |

267 | n/a | # Eliminate dead code: jumps immediately after returns can't be reached |

268 | n/a | def f(cond1, cond2): |

269 | n/a | while 1: |

270 | n/a | if cond1: return 4 |

271 | n/a | self.assertNotInBytecode(f, 'JUMP_FORWARD') |

272 | n/a | # There should be one jump for the while loop. |

273 | n/a | returns = [instr for instr in dis.get_instructions(f) |

274 | n/a | if instr.opname == 'JUMP_ABSOLUTE'] |

275 | n/a | self.assertEqual(len(returns), 1) |

276 | n/a | returns = [instr for instr in dis.get_instructions(f) |

277 | n/a | if instr.opname == 'RETURN_VALUE'] |

278 | n/a | self.assertEqual(len(returns), 2) |

279 | n/a | |

280 | n/a | def test_make_function_doesnt_bail(self): |

281 | n/a | def f(): |

282 | n/a | def g()->1+1: |

283 | n/a | pass |

284 | n/a | return g |

285 | n/a | self.assertNotInBytecode(f, 'BINARY_ADD') |

286 | n/a | |

287 | n/a | def test_constant_folding(self): |

288 | n/a | # Issue #11244: aggressive constant folding. |

289 | n/a | exprs = [ |

290 | n/a | '3 * -5', |

291 | n/a | '-3 * 5', |

292 | n/a | '2 * (3 * 4)', |

293 | n/a | '(2 * 3) * 4', |

294 | n/a | '(-1, 2, 3)', |

295 | n/a | '(1, -2, 3)', |

296 | n/a | '(1, 2, -3)', |

297 | n/a | '(1, 2, -3) * 6', |

298 | n/a | 'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}', |

299 | n/a | ] |

300 | n/a | for e in exprs: |

301 | n/a | code = compile(e, '', 'single') |

302 | n/a | for instr in dis.get_instructions(code): |

303 | n/a | self.assertFalse(instr.opname.startswith('UNARY_')) |

304 | n/a | self.assertFalse(instr.opname.startswith('BINARY_')) |

305 | n/a | self.assertFalse(instr.opname.startswith('BUILD_')) |

306 | n/a | |

307 | n/a | |

308 | n/a | class TestBuglets(unittest.TestCase): |

309 | n/a | |

310 | n/a | def test_bug_11510(self): |

311 | n/a | # folded constant set optimization was commingled with the tuple |

312 | n/a | # unpacking optimization which would fail if the set had duplicate |

313 | n/a | # elements so that the set length was unexpected |

314 | n/a | def f(): |

315 | n/a | x, y = {1, 1} |

316 | n/a | return x, y |

317 | n/a | with self.assertRaises(ValueError): |

318 | n/a | f() |

319 | n/a | |

320 | n/a | |

321 | n/a | if __name__ == "__main__": |

322 | n/a | unittest.main() |