handle_statement.cpp 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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. #include "toolchain/sem_ir/inst.h"
  7. namespace Carbon::Check {
  8. // TODO: Find a better home for this. We'll likely need it for more than just
  9. // expression statements.
  10. static auto HandleDiscardedExpression(Context& context, SemIR::InstId expr_id)
  11. -> void {
  12. // If we discard an initializing expression, convert it to a value or
  13. // reference so that it has something to initialize.
  14. auto expr = context.insts().Get(expr_id);
  15. Convert(context, expr.parse_node(), expr_id,
  16. {.kind = ConversionTarget::Discarded, .type_id = expr.type_id()});
  17. // TODO: This will eventually need to do some "do not discard" analysis.
  18. }
  19. auto HandleExpressionStatement(Context& context, Parse::Node /*parse_node*/)
  20. -> bool {
  21. HandleDiscardedExpression(context, context.node_stack().PopExpression());
  22. return true;
  23. }
  24. auto HandleReturnStatement(Context& context, Parse::Node parse_node) -> bool {
  25. CARBON_CHECK(!context.return_scope_stack().empty());
  26. auto fn_inst = context.insts().GetAs<SemIR::FunctionDeclaration>(
  27. context.return_scope_stack().back());
  28. const auto& callable = context.functions().Get(fn_inst.function_id);
  29. if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) ==
  30. Parse::NodeKind::ReturnStatementStart) {
  31. context.node_stack()
  32. .PopAndDiscardSoloParseNode<Parse::NodeKind::ReturnStatementStart>();
  33. if (callable.return_type_id.is_valid()) {
  34. // TODO: Add a note pointing at the return type's parse node.
  35. CARBON_DIAGNOSTIC(ReturnStatementMissingExpression, Error,
  36. "Must return a {0}.", std::string);
  37. context.emitter()
  38. .Build(parse_node, ReturnStatementMissingExpression,
  39. context.sem_ir().StringifyType(callable.return_type_id))
  40. .Emit();
  41. }
  42. context.AddInst(SemIR::Return{parse_node});
  43. } else {
  44. auto arg = context.node_stack().PopExpression();
  45. context.node_stack()
  46. .PopAndDiscardSoloParseNode<Parse::NodeKind::ReturnStatementStart>();
  47. if (!callable.return_type_id.is_valid()) {
  48. CARBON_DIAGNOSTIC(
  49. ReturnStatementDisallowExpression, Error,
  50. "No return expression should be provided in this context.");
  51. CARBON_DIAGNOSTIC(ReturnStatementImplicitNote, Note,
  52. "There was no return type provided.");
  53. context.emitter()
  54. .Build(parse_node, ReturnStatementDisallowExpression)
  55. .Note(fn_inst.parse_node, ReturnStatementImplicitNote)
  56. .Emit();
  57. } else if (callable.return_slot_id.is_valid()) {
  58. arg = Initialize(context, parse_node, callable.return_slot_id, arg);
  59. } else {
  60. arg = ConvertToValueOfType(context, parse_node, arg,
  61. callable.return_type_id);
  62. }
  63. context.AddInst(SemIR::ReturnExpression{parse_node, arg});
  64. }
  65. // Switch to a new, unreachable, empty instruction block. This typically won't
  66. // contain any semantics IR, but it can do if there are statements following
  67. // the `return` statement.
  68. context.inst_block_stack().Pop();
  69. context.inst_block_stack().PushUnreachable();
  70. return true;
  71. }
  72. auto HandleReturnStatementStart(Context& context, Parse::Node parse_node)
  73. -> bool {
  74. // No action, just a bracketing node.
  75. context.node_stack().Push(parse_node);
  76. return true;
  77. }
  78. } // namespace Carbon::Check