semantics_visitor.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. import hutnparser as hp
  2. import symbol_table as st
  3. import sys
  4. import types_mv
  5. from declare_functions_visitor import DeclareFunctionsVisitor
  6. from visitor import Visitor
  7. class SemanticsVisitor(Visitor):
  8. def __init__(self, args):
  9. Visitor.__init__(self, args)
  10. self.symbol_table = st.SymbolTable()
  11. # there is only one input file, list is for sharing it among visitors
  12. self.inputfiles = []
  13. # inherited attribute, set in funcdecl and used in return,
  14. # to ensure that (returned type == declared type)
  15. self.current_funcdecl = None
  16. self.declare_functions_visitor =\
  17. DeclareFunctionsVisitor(self.symbol_table, self.inputfiles)
  18. @staticmethod
  19. def incompatible_types(l_type, r_type):
  20. if type(l_type) != type(r_type):
  21. if types_mv.Void in (type(l_type), type(r_type)):
  22. return True
  23. if types_mv.Element in (type(l_type), type(r_type)):
  24. return False
  25. if l_type.isNotNumber() or r_type.isNotNumber():
  26. return True
  27. return False
  28. def do_check_binary_ops_arithmetic(self, l, r):
  29. l_type, r_type = self.get_type(l), self.get_type(r)
  30. if SemanticsVisitor.incompatible_types(l_type, r_type):
  31. raise RuntimeError(
  32. "{}:{}:{}: error: invalid operands to binary operator "
  33. "(have {} and {})".format(self.inputfiles[0],
  34. l.startpos['line'],
  35. l.startpos['column'],
  36. str(l_type),
  37. str(r_type)))
  38. def check_binary_ops_arithmetic(self, tree):
  39. l, r = tree.get_tail()[0], tree.get_tail()[2]
  40. self.do_check_binary_ops_arithmetic(l, r)
  41. def generalize_binary_ops_arithmetic(self, tree):
  42. l, r = tree.get_tail()[0], tree.get_tail()[2]
  43. l_type, r_type = self.get_type(l), self.get_type(r)
  44. return types_mv.generalize_arithmetic(l_type, r_type)
  45. def check_unary_ops_arithmetic(self, tree, operator_name):
  46. l = tree.get_tail()[1]
  47. l_type = self.get_type(l)
  48. if l_type.isNotNumber():
  49. raise RuntimeError(
  50. "{}:{}:{}: error: wrong type argument to unary {} "
  51. "({})".format(self.inputfiles[0],
  52. l.startpos['line'],
  53. l.startpos['column'],
  54. operator_name,
  55. str(l_type)))
  56. def promote_unary_ops_arithmetic(self, tree):
  57. l = tree.get_tail()[1]
  58. l_type = self.get_type(l)
  59. try:
  60. return types_mv.promote_arithmetic(l_type)
  61. except RuntimeError:
  62. raise RuntimeError(
  63. "Pathological situation in promote_unary_ops_arithmetic: "
  64. "check_unary_ops_arithmetic has not been executed")
  65. # if r_type is provided, r is not used
  66. def do_check_assignment(self, l, r, r_type = None):
  67. if r_type is not None:
  68. l_type = self.get_type(l)
  69. else:
  70. l_type, r_type = self.get_type(l), self.get_type(r)
  71. if SemanticsVisitor.incompatible_types(l_type, r_type):
  72. raise RuntimeError("{}:{}:{}: error: cannot assign a value of "
  73. "type '{}' to a variable of type '{}'"
  74. .format(self.inputfiles[0],
  75. l.startpos['line'],
  76. l.startpos['column'],
  77. str(r_type),
  78. str(l_type)))
  79. def check_assignment(self, tree):
  80. l, r = tree.get_tail()[0], tree.get_tail()[2]
  81. self.do_check_assignment(l, r)
  82. def check_return(self, tree):
  83. l = self.current_funcdecl
  84. if len(tree.get_tail()) > 2:
  85. r = tree.get_tail()[1]
  86. r_type = None
  87. else:
  88. r = None
  89. r_type = types_mv.Void()
  90. if l:
  91. self.do_check_assignment(l, r, r_type)
  92. else:
  93. raise RuntimeError(
  94. "{}:{}:{}: error: 'return' is used outside of a function"
  95. .format(self.inputfiles[0],
  96. tree.startpos['line'],
  97. tree.startpos['column']))
  98. def check_predicate(self, tree):
  99. if isinstance(self.get_type(tree), types_mv.Element):
  100. return
  101. if self.get_type(tree).isNotNumber():
  102. raise RuntimeError(
  103. "{}:{}:{}: error: predicates of type '{}' are not allowed"
  104. .format(self.inputfiles[0],
  105. tree.startpos['line'],
  106. tree.startpos['column'],
  107. self.get_type(tree)))
  108. def replace_child_binary_op_with_call(self, tree, i=0):
  109. child = tree.get_tail()[i]
  110. if len(child.get_tail()) > 1:
  111. l, op, r = child.get_tail()
  112. l_type, r_type = self.get_type(l), self.get_type(r)
  113. if type(l_type) != type(r_type):
  114. print("Error: " + str(l_type) + " <-> " + str(r_type))
  115. raise RuntimeError(
  116. "{}:{}:{}: error: children were not casted".format(
  117. self.inputfiles[0],
  118. tree.startpos['line'],
  119. tree.startpos['column']
  120. ))
  121. call_name = SemanticsVisitor.call_name_binary(l_type, op)
  122. call_tree = SemanticsVisitor.func_call(call_name, [l, r])
  123. try:
  124. self.visit(call_tree)
  125. except RuntimeError:
  126. call_signature = "{0} function {1}({2}, {2})".format(
  127. str(types_mv.Boolean()), call_name, l_type)
  128. raise RuntimeError(
  129. "{}:{}:{}: error: cannot perform {}: function '{}' is "
  130. "not found".format(
  131. self.inputfiles[0],
  132. tree.startpos['line'],
  133. tree.startpos['column'],
  134. child.head,
  135. call_signature))
  136. tree.replace_child(child, call_tree)
  137. self.set_type(tree, self.get_type(tree.get_tail()[i]))
  138. def replace_child_unary_op_with_call(self, tree):
  139. child = tree.get_tail()[0]
  140. if child.head == "keep_sign":
  141. tree.replace_child(child, child.get_tail()[1])
  142. else:
  143. op, l = child.get_tail()
  144. l_type = self.get_type(l)
  145. call_name = SemanticsVisitor.call_name_unary(l_type, op)
  146. call_tree = SemanticsVisitor.func_call(call_name, [l])
  147. try:
  148. self.visit(call_tree)
  149. except RuntimeError:
  150. call_signature = "{0} function {1}({2})".format(
  151. str(types_mv.Boolean()), call_name, l_type)
  152. raise RuntimeError(
  153. "{}:{}:{}: error: cannot perform {}: function '{}' is "
  154. "not found".format(
  155. self.inputfiles[0],
  156. tree.startpos['line'],
  157. tree.startpos['column'],
  158. child.head,
  159. call_signature))
  160. tree.replace_child(child, call_tree)
  161. self.set_type(tree, self.get_type(tree.get_tail()[0]))
  162. def cast_binary_ops_arithmetic(self, tree):
  163. l, op, r = tree.get_tail()
  164. l_type, r_type = self.get_type(l), self.get_type(r)
  165. if type(l_type) != type(r_type): # if two different numeric types
  166. g_type = types_mv.generalize_arithmetic(l_type, r_type)
  167. self.perform_implicit_cast(tree, l, l_type, g_type)
  168. self.perform_implicit_cast(tree, r, r_type, g_type)
  169. def cast_binary_ops_logical(self, tree):
  170. l, op, r = tree.get_tail()
  171. l_type, r_type = self.get_type(l), self.get_type(r)
  172. self.perform_implicit_cast(tree, l, l_type, types_mv.Boolean())
  173. self.perform_implicit_cast(tree, r, r_type, types_mv.Boolean())
  174. def cast_unary_ops_arithmetic(self, tree):
  175. l = tree.get_tail()[1]
  176. l_type = self.get_type(l)
  177. p_type = self.promote_unary_ops_arithmetic(tree)
  178. self.perform_implicit_cast(tree, l, l_type, p_type)
  179. @staticmethod
  180. def func_call(name, params):
  181. zero = {'line': 0, 'column': 0}
  182. tree = hp.Tree(
  183. "func_call",
  184. [
  185. hp.Tree("rvalue",
  186. [
  187. hp.Tree("ID", [name], zero, zero)
  188. ],
  189. zero, zero),
  190. # Tokens have no impact on visit_func_call. So leave them out.
  191. # hp.Tree("LPAREN", ["("], zero, zero),
  192. # hp.Tree("COMMA", [","], zero, zero),
  193. # hp.Tree("RPAREN", [")"], zero, zero),
  194. ],
  195. zero, zero)
  196. params = [hp.Tree("expression", [p], zero, zero) for p in params]
  197. tree.tail.extend(params)
  198. return hp.Tree("expression", [tree], zero, zero)
  199. @staticmethod
  200. def cast_name(from_type, to_type):
  201. from_t = str(from_type)[0].lower()
  202. to_t = str(to_type)[0].lower()
  203. cast_name = "cast_{}2{}".format(from_t, to_t)
  204. return cast_name
  205. def raise_implicit_cast_error(self, from_type, to_type, tree):
  206. cast_name = SemanticsVisitor.cast_name(from_type, to_type)
  207. cast_signature = "{} function {}({})".format(
  208. str(to_type), cast_name, str(from_type))
  209. raise RuntimeError(
  210. "{}:{}:{}: error: cannot perform implicit cast from '{}'"
  211. " to '{}': function '{}' is not found".format(
  212. self.inputfiles[0],
  213. tree.startpos['line'],
  214. tree.startpos['column'],
  215. str(to_type), str(from_type),
  216. cast_signature))
  217. def perform_implicit_cast(self, tree, child, from_type, to_type):
  218. if types_mv.Element in (type(from_type), type(to_type)):
  219. return
  220. if type(from_type) == type(to_type):
  221. return
  222. cast_name = SemanticsVisitor.cast_name(from_type, to_type)
  223. cast_tree = \
  224. SemanticsVisitor.func_call(cast_name, [child])
  225. try:
  226. self.visit(cast_tree)
  227. except RuntimeError:
  228. self.raise_implicit_cast_error(from_type, to_type, child)
  229. tree.replace_child(child, cast_tree)
  230. types = {
  231. "Integer": "integer",
  232. "Float": "float",
  233. "Boolean": "bool",
  234. "String": "string",
  235. "Action": "action",
  236. "Element": "element",
  237. "Type": "type"
  238. }
  239. binary_ops = {
  240. "OR": "or",
  241. "AND": "and",
  242. "EQ": "eq",
  243. "NEQ": "neq",
  244. "LT": "lt",
  245. "GT": "gt",
  246. "LE": "lte",
  247. "GE": "gte",
  248. "PLUS": "addition",
  249. "MINUS": "subtraction",
  250. "STAR": "multiplication",
  251. "SLASH": "division"
  252. }
  253. unary_ops = {
  254. "NOT": "not",
  255. "MINUS": "neg"
  256. }
  257. @staticmethod
  258. def call_name_binary(operand_type, operator):
  259. # String joins should also be possible
  260. if str(operand_type) == "String":
  261. if operator.head == "PLUS":
  262. return "string_join"
  263. if operator.head == "EQ":
  264. return "value_eq"
  265. elif operator.head == "NEQ":
  266. return "value_neq"
  267. call_name = "{}_{}".format(SemanticsVisitor.types[str(operand_type)],
  268. SemanticsVisitor.binary_ops[operator.head])
  269. return call_name
  270. @staticmethod
  271. def call_name_unary(operand_type, operator):
  272. call_name = "{}_{}".format(SemanticsVisitor.types[str(operand_type)],
  273. SemanticsVisitor.unary_ops[operator.head])
  274. return call_name
  275. def dump(self):
  276. return self.tree.get_text(with_implicit=True)
  277. # return "No code generation here"
  278. # a visit_* method for each non-terminal in the grammar
  279. def visit_start(self, tree):
  280. self.symbol_table.open_scope()
  281. self.inputfiles.append(tree.inputfile)
  282. for child in tree.get_tail():
  283. self.inputfiles[0] = child.inputfile
  284. self.declare_functions_visitor.visit(child)
  285. for child in tree.get_tail():
  286. self.inputfiles[0] = child.inputfile
  287. self.visit(child)
  288. self.inputfiles.pop()
  289. self.symbol_table.close_scope()
  290. self.tree = tree
  291. def visit_statement(self, tree):
  292. self.visit_children(tree)
  293. def visit_definition(self, tree):
  294. self.visit_vardecl(tree)
  295. def visit_vardecl(self, tree):
  296. type_spec = tree.get_child("type_specifier")
  297. var_id = tree.get_child("ID")
  298. var_type = types_mv.string_to_type(type_spec.get_text())
  299. var_name = var_id.get_text()
  300. symbol = st.Symbol(var_name, var_type,
  301. is_global=self.current_funcdecl is None)
  302. try:
  303. self.symbol_table.add(symbol)
  304. except Exception:
  305. raise RuntimeError(
  306. "{}:{}:{}: error: redeclaration of '{}'".format(
  307. self.inputfiles[0], tree.startpos['line'],
  308. tree.startpos['column'], var_name))
  309. self.set_symbol(tree, symbol)
  310. def visit_assignment(self, tree):
  311. self.visit_children(tree)
  312. self.check_assignment(tree)
  313. def visit_expression(self, tree):
  314. self.visit_children(tree)
  315. self.set_type(tree, self.get_type(tree.get_tail()[0]))
  316. def visit_binary_operation(self, tree):
  317. self.visit_children(tree)
  318. self.replace_child_binary_op_with_call(tree)
  319. def visit_disjunction(self, tree):
  320. self.visit_children(tree)
  321. if len(tree.get_tail()) == 1:
  322. self.replace_child_binary_op_with_call(tree)
  323. else:
  324. self.replace_child_binary_op_with_call(tree, 2)
  325. self.cast_binary_ops_logical(tree)
  326. self.set_type(tree, types_mv.Boolean())
  327. def visit_conjunction(self, tree):
  328. self.visit_children(tree)
  329. if len(tree.get_tail()) == 1:
  330. self.replace_child_binary_op_with_call(tree)
  331. else:
  332. self.replace_child_binary_op_with_call(tree, 2)
  333. self.cast_binary_ops_logical(tree)
  334. self.set_type(tree, types_mv.Boolean())
  335. def visit_comparison(self, tree):
  336. self.visit_children(tree)
  337. if len(tree.get_tail()) == 1:
  338. self.replace_child_binary_op_with_call(tree)
  339. else:
  340. self.replace_child_binary_op_with_call(tree, 2)
  341. self.check_binary_ops_arithmetic(tree)
  342. self.cast_binary_ops_arithmetic(tree)
  343. self.set_type(tree, types_mv.Boolean())
  344. def visit_relation(self, tree):
  345. self.visit_children(tree)
  346. if len(tree.get_tail()) == 1:
  347. self.replace_child_binary_op_with_call(tree)
  348. else:
  349. self.replace_child_binary_op_with_call(tree, 2)
  350. self.check_binary_ops_arithmetic(tree)
  351. self.cast_binary_ops_arithmetic(tree)
  352. self.set_type(tree, types_mv.Boolean())
  353. def visit_sum(self, tree):
  354. self.visit_children(tree)
  355. if len(tree.get_tail()) == 1:
  356. self.replace_child_binary_op_with_call(tree)
  357. else:
  358. self.replace_child_binary_op_with_call(tree, 2)
  359. self.check_binary_ops_arithmetic(tree)
  360. self.cast_binary_ops_arithmetic(tree)
  361. # after the cast both parameters have the same (generalized) type:
  362. self.set_type(tree, self.get_type(tree.get_tail()[0]))
  363. def visit_term(self, tree):
  364. self.visit_children(tree)
  365. if len(tree.get_tail()) == 1:
  366. self.set_type(tree, self.get_type(tree.get_tail()[0]))
  367. else:
  368. self.check_binary_ops_arithmetic(tree)
  369. self.cast_binary_ops_arithmetic(tree)
  370. # after the cast both parameters have the same (generalized) type:
  371. self.set_type(tree, self.get_type(tree.get_tail()[0]))
  372. def visit_factor(self, tree):
  373. self.visit_children(tree)
  374. if tree.get_child("primary") is not None:
  375. self.set_type(tree, self.get_type(tree.get_tail()[0]))
  376. else:
  377. self.replace_child_unary_op_with_call(tree)
  378. def visit_logical_not(self, tree):
  379. self.visit_children(tree)
  380. l = tree.get_tail()[1]
  381. l_type = self.get_type(l)
  382. self.perform_implicit_cast(tree, l, l_type, types_mv.Boolean())
  383. self.set_type(tree, self.get_type(tree.get_tail()[1]))
  384. def visit_invert_sign(self, tree):
  385. self.visit_children(tree)
  386. self.check_unary_ops_arithmetic(tree, "minus")
  387. self.cast_unary_ops_arithmetic(tree)
  388. self.set_type(tree, self.get_type(tree.get_tail()[1]))
  389. def visit_keep_sign(self, tree):
  390. self.visit_children(tree)
  391. self.check_unary_ops_arithmetic(tree, "plus")
  392. self.cast_unary_ops_arithmetic(tree)
  393. self.set_type(tree, self.get_type(tree.get_tail()[1]))
  394. def visit_primary(self, tree):
  395. self.visit_children(tree)
  396. self.set_type(tree, self.get_type(tree.get_tail()[0]))
  397. def visit_parenthesized(self, tree):
  398. self.visit_children(tree)
  399. self.set_type(tree, self.get_type(tree.get_tail()[1]))
  400. def visit_atomvalue(self, tree):
  401. self.visit_children(tree)
  402. self.set_type(tree, self.get_type(tree.get_tail()[0]))
  403. def visit_type_specifier(self, tree):
  404. self.set_type(tree, types_mv.Type())
  405. def visit_actionname(self, tree):
  406. self.set_type(tree, types_mv.Action())
  407. def visit_string(self, tree):
  408. self.set_type(tree, types_mv.String())
  409. def visit_integer(self, tree):
  410. self.set_type(tree, types_mv.Integer())
  411. def visit_float(self, tree):
  412. self.set_type(tree, types_mv.Float())
  413. # there is no such rule in the grammar, we just avoid code duplicates
  414. def visit_id(self, tree):
  415. name = tree.get_text()
  416. try:
  417. symbol = self.symbol_table.get(name)
  418. except KeyError:
  419. raise RuntimeError("{}:{}:{}: error: '{}' is not declared".format(
  420. self.inputfiles[0], tree.startpos['line'],
  421. tree.startpos['column'], name))
  422. self.set_type(tree, symbol.type)
  423. self.set_symbol(tree, symbol)
  424. def visit_rvalue(self, tree):
  425. if len(tree.get_tail()) > 1:
  426. # Complex: dict_read operation needed
  427. child = tree.get_tail()[0]
  428. node = tree.get_child("rvalue")
  429. expression = tree.get_child("expression")
  430. operation = "dict_read"
  431. call_tree = SemanticsVisitor.func_call(operation, [node, expression])
  432. self.visit(call_tree)
  433. tree.head = call_tree.head
  434. tree._tail = call_tree.tail
  435. tree.tail = call_tree.tail
  436. self.set_type(tree, self.get_type(node))
  437. else:
  438. # Simple
  439. self.visit_id(tree)
  440. def visit_lvalue(self, tree):
  441. self.visit_id(tree)
  442. def visit_func_call(self, tree):
  443. self.visit_children(tree)
  444. symbol = self.get_symbol(tree.get_tail()[0])
  445. self.set_type(tree, symbol.type)
  446. if not symbol.is_func():
  447. if isinstance(symbol.type, types_mv.Element):
  448. sys.stderr.write("{}:{}:{}: warning: calling a variable of type "
  449. "'Element'\n".format(self.inputfiles[0],
  450. tree.startpos['line'],
  451. tree.startpos['column'],
  452. symbol.name))
  453. return # allow the call without knowing the declaration
  454. raise RuntimeError(
  455. "{}:{}:{}: error: '{}' is a variable of type '{}', not a "
  456. "function".format(self.inputfiles[0],
  457. tree.startpos['line'],
  458. tree.startpos['column'],
  459. symbol.name,
  460. symbol.type))
  461. expressions = tree.get_children("expression")
  462. if len(expressions) != len(symbol.params):
  463. raise RuntimeError(
  464. "{}:{}:{}: error: wrong number of arguments to "
  465. "function '{}'".format(self.inputfiles[0],
  466. tree.startpos['line'],
  467. tree.startpos['column'],
  468. symbol.signature()))
  469. for i in range(len(expressions)):
  470. arg_type = self.get_type(expressions[i])
  471. param_type = symbol.params[i]
  472. if SemanticsVisitor.incompatible_types(arg_type, param_type):
  473. raise RuntimeError(
  474. "{}:{}:{}: error: argument {} has type '{}' instead of "
  475. "'{}', calling function '{}'".format(
  476. self.inputfiles[0],
  477. tree.startpos['line'],
  478. tree.startpos['column'],
  479. i + 1,
  480. str(arg_type),
  481. str(param_type),
  482. symbol.signature()))
  483. if type(arg_type) != type(param_type):
  484. self.perform_implicit_cast(tree, expressions[i], arg_type,
  485. param_type)
  486. if symbol.name in ["input", "output"]:
  487. tree.head = symbol.name
  488. def visit_input(self, tree):
  489. pass # no need to visit it again
  490. def visit_output(self, tree):
  491. pass # no need to visit it again
  492. def visit_dictionary(self, tree):
  493. self.set_type(tree, types_mv.Element)
  494. def visit_list(self, tree):
  495. self.set_type(tree, types_mv.Element)
  496. def visit_dict_item(self, tree):
  497. pass
  498. def visit_ifelse(self, tree):
  499. self.visit_children(tree)
  500. expressions = tree.get_children("expression")
  501. for expression in expressions:
  502. self.check_predicate(expression)
  503. def visit_while(self, tree):
  504. self.visit_children(tree)
  505. expression = tree.get_child("expression")
  506. self.check_predicate(expression)
  507. def visit_block(self, tree):
  508. self.symbol_table.open_scope()
  509. self.visit_children(tree)
  510. self.symbol_table.close_scope()
  511. def visit_func_body(self, tree):
  512. self.visit_children(tree)
  513. def visit_funcdecl(self, tree):
  514. # here we only visit the body cause the declaration is already done
  515. # by declare_functions_visitor
  516. if tree.get_child('func_body') is not None:
  517. self.current_funcdecl = tree
  518. self.symbol_table.open_scope()
  519. self.visit_children(tree)
  520. self.symbol_table.close_scope()
  521. self.current_funcdecl = None
  522. def visit_parameter(self, tree):
  523. param_id = tree.get_child("ID")
  524. type_spec = tree.get_child("type_specifier")
  525. param_type = types_mv.string_to_type(type_spec.get_text())
  526. param_name = param_id.get_text()
  527. symbol = st.Symbol(param_name, param_type, is_global=False)
  528. try:
  529. self.symbol_table.add(symbol)
  530. except Exception:
  531. raise RuntimeError(
  532. "{}:{}:{}: error: redeclaration of '{}'".format(
  533. self.inputfiles[0], tree.startpos['line'],
  534. tree.startpos['column'], param_name))
  535. self.set_symbol(tree, symbol)
  536. def visit_return(self, tree):
  537. self.visit_children(tree)
  538. self.check_return(tree)
  539. def visit_bool(self, tree):
  540. self.set_type(tree, types_mv.Boolean())