semantics_handle_operator.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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/semantics/semantics_context.h"
  5. namespace Carbon::Check {
  6. auto HandleInfixOperator(Context& context, ParseTree::Node parse_node) -> bool {
  7. auto rhs_id = context.node_stack().PopExpression();
  8. auto [lhs_node, lhs_id] = context.node_stack().PopExpressionWithParseNode();
  9. // Figure out the operator for the token.
  10. auto token = context.parse_tree().node_token(parse_node);
  11. switch (auto token_kind = context.tokens().GetKind(token)) {
  12. case TokenKind::Plus:
  13. // TODO: This should search for a compatible interface. For now, it's a
  14. // very trivial check of validity on the operation.
  15. lhs_id = context.ImplicitAsRequired(
  16. parse_node, lhs_id, context.semantics_ir().GetNode(rhs_id).type_id());
  17. context.AddNodeAndPush(
  18. parse_node,
  19. SemIR::Node::BinaryOperatorAdd::Make(
  20. parse_node, context.semantics_ir().GetNode(lhs_id).type_id(),
  21. lhs_id, rhs_id));
  22. return true;
  23. case TokenKind::And:
  24. case TokenKind::Or: {
  25. // The first operand is wrapped in a ShortCircuitOperand, which we
  26. // already handled by creating a RHS block and a resumption block, which
  27. // are the current block and its enclosing block.
  28. rhs_id = context.ImplicitAsBool(parse_node, rhs_id);
  29. // When the second operand is evaluated, the result of `and` and `or` is
  30. // its value.
  31. auto rhs_block_id = context.node_block_stack().PopForAdd();
  32. auto resume_block_id = context.node_block_stack().PeekForAdd();
  33. context.AddNodeToBlock(rhs_block_id,
  34. SemIR::Node::BranchWithArg::Make(
  35. parse_node, resume_block_id, rhs_id));
  36. context.AddCurrentCodeBlockToFunction();
  37. // Collect the result from either the first or second operand.
  38. context.AddNodeAndPush(
  39. parse_node,
  40. SemIR::Node::BlockArg::Make(
  41. parse_node, context.semantics_ir().GetNode(rhs_id).type_id(),
  42. resume_block_id));
  43. return true;
  44. }
  45. case TokenKind::Equal: {
  46. // TODO: handle complex assignment expression such as `a += 1`.
  47. if (SemIR::GetExpressionCategory(context.semantics_ir(), lhs_id) !=
  48. SemIR::ExpressionCategory::DurableReference) {
  49. CARBON_DIAGNOSTIC(AssignmentToNonAssignable, Error,
  50. "Expression is not assignable.");
  51. context.emitter().Emit(lhs_node, AssignmentToNonAssignable);
  52. }
  53. context.ImplicitAsRequired(
  54. parse_node, rhs_id, context.semantics_ir().GetNode(lhs_id).type_id());
  55. context.AddNodeAndPush(
  56. parse_node, SemIR::Node::Assign::Make(parse_node, lhs_id, rhs_id));
  57. return true;
  58. }
  59. default:
  60. return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
  61. }
  62. }
  63. auto HandlePostfixOperator(Context& context, ParseTree::Node parse_node)
  64. -> bool {
  65. auto value_id = context.node_stack().PopExpression();
  66. // Figure out the operator for the token.
  67. auto token = context.parse_tree().node_token(parse_node);
  68. switch (auto token_kind = context.tokens().GetKind(token)) {
  69. case TokenKind::Star: {
  70. auto inner_type_id = context.ExpressionAsType(parse_node, value_id);
  71. context.AddNodeAndPush(
  72. parse_node, SemIR::Node::PointerType::Make(
  73. parse_node, SemIR::TypeId::TypeType, inner_type_id));
  74. return true;
  75. }
  76. default:
  77. CARBON_FATAL() << "Unexpected postfix operator " << token_kind;
  78. }
  79. }
  80. auto HandlePrefixOperator(Context& context, ParseTree::Node parse_node)
  81. -> bool {
  82. auto value_id = context.node_stack().PopExpression();
  83. // Figure out the operator for the token.
  84. auto token = context.parse_tree().node_token(parse_node);
  85. switch (auto token_kind = context.tokens().GetKind(token)) {
  86. case TokenKind::Amp: {
  87. // Only durable reference expressions can have their address taken.
  88. switch (SemIR::GetExpressionCategory(context.semantics_ir(), value_id)) {
  89. case SemIR::ExpressionCategory::DurableReference:
  90. break;
  91. case SemIR::ExpressionCategory::EphemeralReference:
  92. CARBON_DIAGNOSTIC(AddressOfEphemeralReference, Error,
  93. "Cannot take the address of a temporary object.");
  94. context.emitter().Emit(parse_node, AddressOfEphemeralReference);
  95. break;
  96. default:
  97. CARBON_DIAGNOSTIC(
  98. AddressOfNonReference, Error,
  99. "Cannot take the address of non-reference expression.");
  100. context.emitter().Emit(parse_node, AddressOfNonReference);
  101. break;
  102. }
  103. context.AddNodeAndPush(
  104. parse_node,
  105. SemIR::Node::AddressOf::Make(
  106. parse_node,
  107. context.GetPointerType(
  108. parse_node,
  109. context.semantics_ir().GetNode(value_id).type_id()),
  110. value_id));
  111. return true;
  112. }
  113. case TokenKind::Const: {
  114. // `const (const T)` is probably not what the developer intended.
  115. // TODO: Detect `const (const T)*` and suggest moving the `*` inside the
  116. // parentheses.
  117. if (context.semantics_ir().GetNode(value_id).kind() ==
  118. SemIR::NodeKind::ConstType) {
  119. CARBON_DIAGNOSTIC(RepeatedConst, Warning,
  120. "`const` applied repeatedly to the same type has no "
  121. "additional effect.");
  122. context.emitter().Emit(parse_node, RepeatedConst);
  123. }
  124. auto inner_type_id = context.ExpressionAsType(parse_node, value_id);
  125. context.AddNodeAndPush(
  126. parse_node, SemIR::Node::ConstType::Make(
  127. parse_node, SemIR::TypeId::TypeType, inner_type_id));
  128. return true;
  129. }
  130. case TokenKind::Not:
  131. value_id = context.ImplicitAsBool(parse_node, value_id);
  132. context.AddNodeAndPush(
  133. parse_node,
  134. SemIR::Node::UnaryOperatorNot::Make(
  135. parse_node, context.semantics_ir().GetNode(value_id).type_id(),
  136. value_id));
  137. return true;
  138. case TokenKind::Star: {
  139. auto type_id = context.GetUnqualifiedType(
  140. context.semantics_ir().GetNode(value_id).type_id());
  141. auto type_node = context.semantics_ir().GetNode(
  142. context.semantics_ir().GetTypeAllowBuiltinTypes(type_id));
  143. auto result_type_id = SemIR::TypeId::Error;
  144. if (type_node.kind() == SemIR::NodeKind::PointerType) {
  145. result_type_id = type_node.GetAsPointerType();
  146. } else {
  147. CARBON_DIAGNOSTIC(
  148. DereferenceOfNonPointer, Error,
  149. "Cannot dereference operand of non-pointer type `{0}`.",
  150. std::string);
  151. auto builder = context.emitter().Build(
  152. parse_node, DereferenceOfNonPointer,
  153. context.semantics_ir().StringifyType(type_id));
  154. // TODO: Check for any facet here, rather than only a type.
  155. if (type_id == SemIR::TypeId::TypeType) {
  156. CARBON_DIAGNOSTIC(
  157. DereferenceOfType, Note,
  158. "To form a pointer type, write the `*` after the pointee type.");
  159. builder.Note(parse_node, DereferenceOfType);
  160. }
  161. builder.Emit();
  162. }
  163. context.AddNodeAndPush(
  164. parse_node,
  165. SemIR::Node::Dereference::Make(parse_node, result_type_id, value_id));
  166. return true;
  167. }
  168. default:
  169. return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
  170. }
  171. }
  172. auto HandleShortCircuitOperand(Context& context, ParseTree::Node parse_node)
  173. -> bool {
  174. // Convert the condition to `bool`.
  175. auto cond_value_id = context.node_stack().PopExpression();
  176. cond_value_id = context.ImplicitAsBool(parse_node, cond_value_id);
  177. auto bool_type_id = context.semantics_ir().GetNode(cond_value_id).type_id();
  178. // Compute the branch value: the condition for `and`, inverted for `or`.
  179. auto token = context.parse_tree().node_token(parse_node);
  180. SemIR::NodeId branch_value_id = SemIR::NodeId::Invalid;
  181. auto short_circuit_result_id = SemIR::NodeId::Invalid;
  182. switch (auto token_kind = context.tokens().GetKind(token)) {
  183. case TokenKind::And:
  184. branch_value_id = cond_value_id;
  185. short_circuit_result_id = context.AddNode(SemIR::Node::BoolLiteral::Make(
  186. parse_node, bool_type_id, SemIR::BoolValue::False));
  187. break;
  188. case TokenKind::Or:
  189. branch_value_id = context.AddNode(SemIR::Node::UnaryOperatorNot::Make(
  190. parse_node, bool_type_id, cond_value_id));
  191. short_circuit_result_id = context.AddNode(SemIR::Node::BoolLiteral::Make(
  192. parse_node, bool_type_id, SemIR::BoolValue::True));
  193. break;
  194. default:
  195. CARBON_FATAL() << "Unexpected short-circuiting operator " << token_kind;
  196. }
  197. // Create a block for the right-hand side and for the continuation.
  198. auto rhs_block_id =
  199. context.AddDominatedBlockAndBranchIf(parse_node, branch_value_id);
  200. auto end_block_id = context.AddDominatedBlockAndBranchWithArg(
  201. parse_node, short_circuit_result_id);
  202. // Push the resumption and the right-hand side blocks, and start emitting the
  203. // right-hand operand.
  204. context.node_block_stack().Pop();
  205. context.node_block_stack().Push(end_block_id);
  206. context.node_block_stack().Push(rhs_block_id);
  207. context.AddCurrentCodeBlockToFunction();
  208. // Put the condition back on the stack for HandleInfixOperator.
  209. context.node_stack().Push(parse_node, cond_value_id);
  210. return true;
  211. }
  212. } // namespace Carbon::Check