resolve_unformed.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "explorer/interpreter/resolve_unformed.h"
  5. #include <unordered_map>
  6. #include "common/check.h"
  7. #include "explorer/ast/ast.h"
  8. #include "explorer/ast/expression.h"
  9. #include "explorer/ast/pattern.h"
  10. #include "explorer/common/error_builders.h"
  11. #include "explorer/common/nonnull.h"
  12. using llvm::cast;
  13. namespace Carbon {
  14. // Aggregate information about a AstNode being analyzed.
  15. struct FlowFact {
  16. bool may_be_formed;
  17. };
  18. // Traverses the sub-AST rooted at the given node, resolving the formed/unformed
  19. // states of local variables within it and updating the flow facts.
  20. static auto ResolveUnformed(
  21. Nonnull<const Expression*> expression,
  22. std::unordered_map<Nonnull<const AstNode*>, FlowFact>& flow_facts,
  23. bool set_formed) -> ErrorOr<Success>;
  24. static auto ResolveUnformed(
  25. Nonnull<const Pattern*> pattern,
  26. std::unordered_map<Nonnull<const AstNode*>, FlowFact>& flow_facts,
  27. bool has_init) -> ErrorOr<Success>;
  28. static auto ResolveUnformed(
  29. Nonnull<const Statement*> statement,
  30. std::unordered_map<Nonnull<const AstNode*>, FlowFact>& flow_facts)
  31. -> ErrorOr<Success>;
  32. static auto ResolveUnformed(Nonnull<const Declaration*> declaration)
  33. -> ErrorOr<Success>;
  34. static auto ResolveUnformed(
  35. Nonnull<const Expression*> expression,
  36. std::unordered_map<Nonnull<const AstNode*>, FlowFact>& flow_facts,
  37. const bool set_formed) -> ErrorOr<Success> {
  38. switch (expression->kind()) {
  39. case ExpressionKind::IdentifierExpression: {
  40. auto& identifier = cast<IdentifierExpression>(*expression);
  41. auto fact = flow_facts.find(&identifier.value_node().base());
  42. // TODO: @slaterlatiao add all available value nodes to flow facts and use
  43. // CARBON_CHECK on the following line.
  44. if (fact == flow_facts.end()) {
  45. break;
  46. }
  47. if (set_formed) {
  48. fact->second.may_be_formed = true;
  49. } else if (!fact->second.may_be_formed) {
  50. return CompilationError(identifier.source_loc())
  51. << "use of uninitialized variable " << identifier.name();
  52. }
  53. break;
  54. }
  55. case ExpressionKind::CallExpression: {
  56. auto& call = cast<CallExpression>(*expression);
  57. CARBON_RETURN_IF_ERROR(
  58. ResolveUnformed(&call.argument(), flow_facts, /*set_formed=*/false));
  59. break;
  60. }
  61. case ExpressionKind::TupleLiteral:
  62. for (Nonnull<const Expression*> field :
  63. cast<TupleLiteral>(*expression).fields()) {
  64. CARBON_RETURN_IF_ERROR(
  65. ResolveUnformed(field, flow_facts, /*set_formed=*/false));
  66. }
  67. break;
  68. case ExpressionKind::OperatorExpression: {
  69. auto& opt_exp = cast<OperatorExpression>(*expression);
  70. if (opt_exp.op() == Operator::AddressOf) {
  71. CARBON_CHECK(opt_exp.arguments().size() == 1)
  72. << "OperatorExpression with op & can only have 1 argument";
  73. CARBON_RETURN_IF_ERROR(
  74. // When a variable is taken address of, defer the unformed check to
  75. // runtime. A more sound analysis can be implemented when a
  76. // points-to analysis is available.
  77. ResolveUnformed(opt_exp.arguments().front(), flow_facts,
  78. /*set_formed=*/true));
  79. } else {
  80. for (Nonnull<const Expression*> operand : opt_exp.arguments()) {
  81. CARBON_RETURN_IF_ERROR(
  82. ResolveUnformed(operand, flow_facts, /*set_formed=*/false));
  83. }
  84. }
  85. break;
  86. }
  87. case ExpressionKind::DotSelfExpression:
  88. case ExpressionKind::IntLiteral:
  89. case ExpressionKind::BoolLiteral:
  90. case ExpressionKind::BoolTypeLiteral:
  91. case ExpressionKind::IntTypeLiteral:
  92. case ExpressionKind::StringLiteral:
  93. case ExpressionKind::StringTypeLiteral:
  94. case ExpressionKind::TypeTypeLiteral:
  95. case ExpressionKind::ContinuationTypeLiteral:
  96. case ExpressionKind::ValueLiteral:
  97. case ExpressionKind::IndexExpression:
  98. case ExpressionKind::SimpleMemberAccessExpression:
  99. case ExpressionKind::CompoundMemberAccessExpression:
  100. case ExpressionKind::IfExpression:
  101. case ExpressionKind::WhereExpression:
  102. case ExpressionKind::StructLiteral:
  103. case ExpressionKind::StructTypeLiteral:
  104. case ExpressionKind::IntrinsicExpression:
  105. case ExpressionKind::UnimplementedExpression:
  106. case ExpressionKind::FunctionTypeLiteral:
  107. case ExpressionKind::ArrayTypeLiteral:
  108. case ExpressionKind::InstantiateImpl:
  109. break;
  110. }
  111. return Success();
  112. }
  113. static auto ResolveUnformed(
  114. Nonnull<const Pattern*> pattern,
  115. std::unordered_map<Nonnull<const AstNode*>, FlowFact>& flow_facts,
  116. const bool has_init) -> ErrorOr<Success> {
  117. switch (pattern->kind()) {
  118. case PatternKind::BindingPattern:
  119. flow_facts.insert(
  120. {Nonnull<const AstNode*>(&cast<BindingPattern>(*pattern)),
  121. {has_init}});
  122. break;
  123. case PatternKind::TuplePattern:
  124. for (Nonnull<const Pattern*> field :
  125. cast<TuplePattern>(*pattern).fields()) {
  126. CARBON_RETURN_IF_ERROR(ResolveUnformed(field, flow_facts, has_init));
  127. }
  128. break;
  129. case PatternKind::GenericBinding:
  130. case PatternKind::AlternativePattern:
  131. case PatternKind::ExpressionPattern:
  132. case PatternKind::AutoPattern:
  133. case PatternKind::VarPattern:
  134. case PatternKind::AddrPattern:
  135. // do nothing
  136. break;
  137. }
  138. return Success();
  139. }
  140. static auto ResolveUnformed(
  141. Nonnull<const Statement*> statement,
  142. std::unordered_map<Nonnull<const AstNode*>, FlowFact>& flow_facts)
  143. -> ErrorOr<Success> {
  144. switch (statement->kind()) {
  145. case StatementKind::Block: {
  146. auto& block = cast<Block>(*statement);
  147. for (auto* block_statement : block.statements()) {
  148. CARBON_RETURN_IF_ERROR(ResolveUnformed(block_statement, flow_facts));
  149. }
  150. break;
  151. }
  152. case StatementKind::VariableDefinition: {
  153. auto& def = cast<VariableDefinition>(*statement);
  154. CARBON_RETURN_IF_ERROR(ResolveUnformed(&def.pattern(), flow_facts,
  155. /*has_init=*/def.has_init()));
  156. break;
  157. }
  158. case StatementKind::ReturnVar:
  159. // TODO: @slaterlatiao: Implement this flow.
  160. break;
  161. case StatementKind::ReturnExpression: {
  162. auto& ret_exp_stmt = cast<ReturnExpression>(*statement);
  163. CARBON_RETURN_IF_ERROR(ResolveUnformed(&ret_exp_stmt.expression(),
  164. flow_facts, /*set_formed=*/false));
  165. break;
  166. }
  167. case StatementKind::Assign: {
  168. auto& assign = cast<Assign>(*statement);
  169. CARBON_RETURN_IF_ERROR(
  170. ResolveUnformed(&assign.lhs(), flow_facts, /*set_formed=*/true));
  171. CARBON_RETURN_IF_ERROR(
  172. ResolveUnformed(&assign.rhs(), flow_facts, /*set_formed=*/false));
  173. break;
  174. }
  175. case StatementKind::ExpressionStatement: {
  176. auto& exp_stmt = cast<ExpressionStatement>(*statement);
  177. CARBON_RETURN_IF_ERROR(ResolveUnformed(&exp_stmt.expression(), flow_facts,
  178. /*set_formed=*/false));
  179. break;
  180. }
  181. case StatementKind::Break:
  182. case StatementKind::Continue:
  183. case StatementKind::If:
  184. case StatementKind::While:
  185. case StatementKind::Match:
  186. case StatementKind::Continuation:
  187. case StatementKind::Run:
  188. case StatementKind::Await:
  189. // do nothing
  190. break;
  191. }
  192. return Success();
  193. }
  194. static auto ResolveUnformed(Nonnull<const Declaration*> declaration)
  195. -> ErrorOr<Success> {
  196. switch (declaration->kind()) {
  197. // Checks formed/unformed state intraprocedurally.
  198. // Can be extended to an interprocedural analysis when a call graph is
  199. // available.
  200. case DeclarationKind::FunctionDeclaration: {
  201. auto& function = cast<FunctionDeclaration>(*declaration);
  202. if (function.body().has_value()) {
  203. std::unordered_map<Nonnull<const AstNode*>, FlowFact> flow_facts;
  204. CARBON_RETURN_IF_ERROR(ResolveUnformed(*function.body(), flow_facts));
  205. }
  206. break;
  207. }
  208. case DeclarationKind::ClassDeclaration:
  209. case DeclarationKind::InterfaceDeclaration:
  210. case DeclarationKind::ImplDeclaration:
  211. case DeclarationKind::ChoiceDeclaration:
  212. case DeclarationKind::VariableDeclaration:
  213. case DeclarationKind::AssociatedConstantDeclaration:
  214. case DeclarationKind::SelfDeclaration:
  215. case DeclarationKind::AliasDeclaration:
  216. // do nothing
  217. break;
  218. }
  219. return Success();
  220. }
  221. auto ResolveUnformed(const AST& ast) -> ErrorOr<Success> {
  222. for (auto declaration : ast.declarations) {
  223. CARBON_RETURN_IF_ERROR(ResolveUnformed(declaration));
  224. }
  225. return Success();
  226. }
  227. } // namespace Carbon