handle_operator.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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 "toolchain/check/context.h"
  5. #include "toolchain/check/convert.h"
  6. namespace Carbon::Check {
  7. auto HandleInfixOperator(Context& context, Parse::NodeId parse_node) -> bool {
  8. auto [rhs_node, rhs_id] = context.node_stack().PopExprWithParseNode();
  9. auto [lhs_node, lhs_id] = context.node_stack().PopExprWithParseNode();
  10. // Figure out the operator for the token.
  11. auto token = context.parse_tree().node_token(parse_node);
  12. switch (auto token_kind = context.tokens().GetKind(token)) {
  13. case Lex::TokenKind::As: {
  14. auto rhs_type_id = ExprAsType(context, rhs_node, rhs_id);
  15. context.node_stack().Push(
  16. parse_node,
  17. ConvertForExplicitAs(context, parse_node, lhs_id, rhs_type_id));
  18. return true;
  19. }
  20. case Lex::TokenKind::Equal: {
  21. // TODO: handle complex assignment expression such as `a += 1`.
  22. if (auto lhs_cat = SemIR::GetExprCategory(context.sem_ir(), lhs_id);
  23. lhs_cat != SemIR::ExprCategory::DurableRef &&
  24. lhs_cat != SemIR::ExprCategory::Error) {
  25. CARBON_DIAGNOSTIC(AssignmentToNonAssignable, Error,
  26. "Expression is not assignable.");
  27. context.emitter().Emit(lhs_node, AssignmentToNonAssignable);
  28. }
  29. // TODO: Destroy the old value before reinitializing. This will require
  30. // building the destruction code before we build the RHS subexpression.
  31. rhs_id = Initialize(context, parse_node, lhs_id, rhs_id);
  32. context.AddInst(SemIR::Assign{parse_node, lhs_id, rhs_id});
  33. // We model assignment as an expression, so we need to push a value for
  34. // it, even though it doesn't produce a value.
  35. // TODO: Consider changing our parse tree to model assignment as a
  36. // different kind of statement than an expression statement.
  37. context.node_stack().Push(parse_node, lhs_id);
  38. return true;
  39. }
  40. default:
  41. return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
  42. }
  43. }
  44. auto HandlePostfixOperator(Context& context, Parse::NodeId parse_node) -> bool {
  45. auto value_id = context.node_stack().PopExpr();
  46. // Figure out the operator for the token.
  47. auto token = context.parse_tree().node_token(parse_node);
  48. switch (auto token_kind = context.tokens().GetKind(token)) {
  49. case Lex::TokenKind::Star: {
  50. auto inner_type_id = ExprAsType(context, parse_node, value_id);
  51. context.AddInstAndPush(
  52. parse_node, SemIR::PointerType{parse_node, SemIR::TypeId::TypeType,
  53. inner_type_id});
  54. return true;
  55. }
  56. default:
  57. CARBON_FATAL() << "Unexpected postfix operator " << token_kind;
  58. }
  59. }
  60. auto HandlePrefixOperator(Context& context, Parse::NodeId parse_node) -> bool {
  61. auto value_id = context.node_stack().PopExpr();
  62. // Figure out the operator for the token.
  63. auto token = context.parse_tree().node_token(parse_node);
  64. switch (auto token_kind = context.tokens().GetKind(token)) {
  65. case Lex::TokenKind::Amp: {
  66. // Only durable reference expressions can have their address taken.
  67. switch (SemIR::GetExprCategory(context.sem_ir(), value_id)) {
  68. case SemIR::ExprCategory::DurableRef:
  69. case SemIR::ExprCategory::Error:
  70. break;
  71. case SemIR::ExprCategory::EphemeralRef:
  72. CARBON_DIAGNOSTIC(AddressOfEphemeralRef, Error,
  73. "Cannot take the address of a temporary object.");
  74. context.emitter().Emit(parse_node, AddressOfEphemeralRef);
  75. break;
  76. default:
  77. CARBON_DIAGNOSTIC(
  78. AddressOfNonRef, Error,
  79. "Cannot take the address of non-reference expression.");
  80. context.emitter().Emit(parse_node, AddressOfNonRef);
  81. break;
  82. }
  83. context.AddInstAndPush(
  84. parse_node,
  85. SemIR::AddressOf{
  86. parse_node,
  87. context.GetPointerType(parse_node,
  88. context.insts().Get(value_id).type_id()),
  89. value_id});
  90. return true;
  91. }
  92. case Lex::TokenKind::Const: {
  93. // `const (const T)` is probably not what the developer intended.
  94. // TODO: Detect `const (const T)*` and suggest moving the `*` inside the
  95. // parentheses.
  96. if (context.insts().Get(value_id).kind() == SemIR::ConstType::Kind) {
  97. CARBON_DIAGNOSTIC(RepeatedConst, Warning,
  98. "`const` applied repeatedly to the same type has no "
  99. "additional effect.");
  100. context.emitter().Emit(parse_node, RepeatedConst);
  101. }
  102. auto inner_type_id = ExprAsType(context, parse_node, value_id);
  103. context.AddInstAndPush(
  104. parse_node,
  105. SemIR::ConstType{parse_node, SemIR::TypeId::TypeType, inner_type_id});
  106. return true;
  107. }
  108. case Lex::TokenKind::Not:
  109. value_id = ConvertToBoolValue(context, parse_node, value_id);
  110. context.AddInstAndPush(
  111. parse_node,
  112. SemIR::UnaryOperatorNot{
  113. parse_node, context.insts().Get(value_id).type_id(), value_id});
  114. return true;
  115. case Lex::TokenKind::Star: {
  116. value_id = ConvertToValueExpr(context, value_id);
  117. auto type_id =
  118. context.GetUnqualifiedType(context.insts().Get(value_id).type_id());
  119. auto result_type_id = SemIR::TypeId::Error;
  120. if (auto pointer_type =
  121. context.types().TryGetAs<SemIR::PointerType>(type_id)) {
  122. result_type_id = pointer_type->pointee_id;
  123. } else if (type_id != SemIR::TypeId::Error) {
  124. CARBON_DIAGNOSTIC(
  125. DerefOfNonPointer, Error,
  126. "Cannot dereference operand of non-pointer type `{0}`.",
  127. std::string);
  128. auto builder =
  129. context.emitter().Build(parse_node, DerefOfNonPointer,
  130. context.sem_ir().StringifyType(type_id));
  131. // TODO: Check for any facet here, rather than only a type.
  132. if (type_id == SemIR::TypeId::TypeType) {
  133. CARBON_DIAGNOSTIC(
  134. DerefOfType, Note,
  135. "To form a pointer type, write the `*` after the pointee type.");
  136. builder.Note(parse_node, DerefOfType);
  137. }
  138. builder.Emit();
  139. }
  140. context.AddInstAndPush(
  141. parse_node, SemIR::Deref{parse_node, result_type_id, value_id});
  142. return true;
  143. }
  144. default:
  145. return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
  146. }
  147. }
  148. // Adds the branch for a short circuit operand.
  149. static auto HandleShortCircuitOperand(Context& context,
  150. Parse::NodeId parse_node, bool is_or)
  151. -> bool {
  152. // Convert the condition to `bool`.
  153. auto cond_value_id = context.node_stack().PopExpr();
  154. cond_value_id = ConvertToBoolValue(context, parse_node, cond_value_id);
  155. auto bool_type_id = context.insts().Get(cond_value_id).type_id();
  156. // Compute the branch value: the condition for `and`, inverted for `or`.
  157. SemIR::InstId branch_value_id =
  158. is_or ? context.AddInst(SemIR::UnaryOperatorNot{parse_node, bool_type_id,
  159. cond_value_id})
  160. : cond_value_id;
  161. auto short_circuit_result_id = context.AddInst(SemIR::BoolLiteral{
  162. parse_node, bool_type_id,
  163. is_or ? SemIR::BoolValue::True : SemIR::BoolValue::False});
  164. // Create a block for the right-hand side and for the continuation.
  165. auto rhs_block_id =
  166. context.AddDominatedBlockAndBranchIf(parse_node, branch_value_id);
  167. auto end_block_id = context.AddDominatedBlockAndBranchWithArg(
  168. parse_node, short_circuit_result_id);
  169. // Push the resumption and the right-hand side blocks, and start emitting the
  170. // right-hand operand.
  171. context.inst_block_stack().Pop();
  172. context.inst_block_stack().Push(end_block_id);
  173. context.inst_block_stack().Push(rhs_block_id);
  174. context.AddCurrentCodeBlockToFunction();
  175. // HandleShortCircuitOperator will follow, and doesn't need the operand on the
  176. // node stack.
  177. return true;
  178. }
  179. auto HandleShortCircuitOperandAnd(Context& context, Parse::NodeId parse_node)
  180. -> bool {
  181. return HandleShortCircuitOperand(context, parse_node, /*is_or=*/false);
  182. }
  183. auto HandleShortCircuitOperandOr(Context& context, Parse::NodeId parse_node)
  184. -> bool {
  185. return HandleShortCircuitOperand(context, parse_node, /*is_or=*/true);
  186. }
  187. // Short circuit operator handling is uniform because the branching logic
  188. // occurs during operand handling.
  189. static auto HandleShortCircuitOperator(Context& context,
  190. Parse::NodeId parse_node) -> bool {
  191. auto [rhs_node, rhs_id] = context.node_stack().PopExprWithParseNode();
  192. // The first operand is wrapped in a ShortCircuitOperand, which we
  193. // already handled by creating a RHS block and a resumption block, which
  194. // are the current block and its enclosing block.
  195. rhs_id = ConvertToBoolValue(context, parse_node, rhs_id);
  196. // When the second operand is evaluated, the result of `and` and `or` is
  197. // its value.
  198. auto resume_block_id = context.inst_block_stack().PeekOrAdd(/*depth=*/1);
  199. context.AddInst(SemIR::BranchWithArg{parse_node, resume_block_id, rhs_id});
  200. context.inst_block_stack().Pop();
  201. context.AddCurrentCodeBlockToFunction();
  202. // Collect the result from either the first or second operand.
  203. context.AddInstAndPush(
  204. parse_node,
  205. SemIR::BlockArg{parse_node, context.insts().Get(rhs_id).type_id(),
  206. resume_block_id});
  207. return true;
  208. }
  209. auto HandleShortCircuitOperatorAnd(Context& context, Parse::NodeId parse_node)
  210. -> bool {
  211. return HandleShortCircuitOperator(context, parse_node);
  212. }
  213. auto HandleShortCircuitOperatorOr(Context& context, Parse::NodeId parse_node)
  214. -> bool {
  215. return HandleShortCircuitOperator(context, parse_node);
  216. }
  217. } // namespace Carbon::Check