return.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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/return.h"
  5. #include "toolchain/check/context.h"
  6. #include "toolchain/check/convert.h"
  7. namespace Carbon::Check {
  8. // Gets the function that lexically encloses the current location.
  9. static auto GetCurrentFunction(Context& context) -> SemIR::Function& {
  10. CARBON_CHECK(!context.return_scope_stack().empty(),
  11. "Handling return but not in a function");
  12. auto function_id = context.insts()
  13. .GetAs<SemIR::FunctionDecl>(
  14. context.return_scope_stack().back().decl_id)
  15. .function_id;
  16. return context.functions().Get(function_id);
  17. }
  18. // Gets the currently in scope `returned var`, if any, that would be returned
  19. // by a `return var;`.
  20. static auto GetCurrentReturnedVar(Context& context) -> SemIR::InstId {
  21. CARBON_CHECK(!context.return_scope_stack().empty(),
  22. "Handling return but not in a function");
  23. return context.return_scope_stack().back().returned_var;
  24. }
  25. // Produces a note that the given function has no explicit return type.
  26. static auto NoteNoReturnTypeProvided(Context::DiagnosticBuilder& diag,
  27. const SemIR::Function& function) {
  28. CARBON_DIAGNOSTIC(ReturnTypeOmittedNote, Note,
  29. "there was no return type provided");
  30. diag.Note(function.latest_decl_id(), ReturnTypeOmittedNote);
  31. }
  32. // Produces a note describing the return type of the given function, which
  33. // must be a function whose definition is currently being checked.
  34. static auto NoteReturnType(Context& context, Context::DiagnosticBuilder& diag,
  35. const SemIR::Function& function) {
  36. auto return_type_inst_id =
  37. context.insts()
  38. .GetAs<SemIR::ReturnSlot>(function.return_slot_id)
  39. .type_inst_id;
  40. CARBON_DIAGNOSTIC(ReturnTypeHereNote, Note, "return type of function is {0}",
  41. InstIdAsType);
  42. diag.Note(function.return_slot_id, ReturnTypeHereNote, return_type_inst_id);
  43. }
  44. // Produces a note pointing at the currently in scope `returned var`.
  45. static auto NoteReturnedVar(Context::DiagnosticBuilder& diag,
  46. SemIR::InstId returned_var_id) {
  47. CARBON_DIAGNOSTIC(ReturnedVarHere, Note, "`returned var` was declared here");
  48. diag.Note(returned_var_id, ReturnedVarHere);
  49. }
  50. auto CheckReturnedVar(Context& context, Parse::NodeId returned_node,
  51. Parse::NodeId name_node, SemIR::NameId name_id,
  52. Parse::NodeId type_node, SemIR::TypeId type_id)
  53. -> SemIR::InstId {
  54. auto& function = GetCurrentFunction(context);
  55. auto return_info =
  56. SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function);
  57. if (!return_info.is_valid()) {
  58. // We already diagnosed this when we started defining the function. Create a
  59. // placeholder for error recovery.
  60. return context.AddInst<SemIR::VarStorage>(
  61. name_node, {.type_id = type_id, .name_id = name_id});
  62. }
  63. // A `returned var` requires an explicit return type.
  64. if (!return_info.type_id.is_valid()) {
  65. CARBON_DIAGNOSTIC(ReturnedVarWithNoReturnType, Error,
  66. "cannot declare a `returned var` in this function");
  67. auto diag =
  68. context.emitter().Build(returned_node, ReturnedVarWithNoReturnType);
  69. NoteNoReturnTypeProvided(diag, function);
  70. diag.Emit();
  71. return SemIR::InstId::BuiltinErrorInst;
  72. }
  73. // The declared type of the var must match the return type of the function.
  74. if (return_info.type_id != type_id) {
  75. CARBON_DIAGNOSTIC(ReturnedVarWrongType, Error,
  76. "type {0} of `returned var` does not match "
  77. "return type of enclosing function",
  78. SemIR::TypeId);
  79. auto diag =
  80. context.emitter().Build(type_node, ReturnedVarWrongType, type_id);
  81. NoteReturnType(context, diag, function);
  82. diag.Emit();
  83. return SemIR::InstId::BuiltinErrorInst;
  84. }
  85. // The variable aliases the return slot if there is one. If not, it has its
  86. // own storage.
  87. if (return_info.has_return_slot()) {
  88. return function.return_slot_id;
  89. }
  90. return context.AddInst<SemIR::VarStorage>(
  91. name_node, {.type_id = type_id, .name_id = name_id});
  92. }
  93. auto RegisterReturnedVar(Context& context, SemIR::InstId bind_id) -> void {
  94. auto existing_id = context.scope_stack().SetReturnedVarOrGetExisting(bind_id);
  95. if (existing_id.is_valid()) {
  96. CARBON_DIAGNOSTIC(ReturnedVarShadowed, Error,
  97. "cannot declare a `returned var` in the scope of "
  98. "another `returned var`");
  99. auto diag = context.emitter().Build(bind_id, ReturnedVarShadowed);
  100. NoteReturnedVar(diag, existing_id);
  101. diag.Emit();
  102. }
  103. }
  104. auto BuildReturnWithNoExpr(Context& context, Parse::ReturnStatementId node_id)
  105. -> void {
  106. const auto& function = GetCurrentFunction(context);
  107. auto return_type_id = function.GetDeclaredReturnType(context.sem_ir());
  108. if (return_type_id.is_valid()) {
  109. CARBON_DIAGNOSTIC(ReturnStatementMissingExpr, Error,
  110. "missing return value");
  111. auto diag = context.emitter().Build(node_id, ReturnStatementMissingExpr);
  112. NoteReturnType(context, diag, function);
  113. diag.Emit();
  114. }
  115. context.AddInst<SemIR::Return>(node_id, {});
  116. }
  117. auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
  118. SemIR::InstId expr_id) -> void {
  119. const auto& function = GetCurrentFunction(context);
  120. auto returned_var_id = GetCurrentReturnedVar(context);
  121. auto return_slot_id = SemIR::InstId::Invalid;
  122. auto return_info =
  123. SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function);
  124. if (!return_info.type_id.is_valid()) {
  125. CARBON_DIAGNOSTIC(
  126. ReturnStatementDisallowExpr, Error,
  127. "no return expression should be provided in this context");
  128. auto diag = context.emitter().Build(node_id, ReturnStatementDisallowExpr);
  129. NoteNoReturnTypeProvided(diag, function);
  130. diag.Emit();
  131. expr_id = SemIR::InstId::BuiltinErrorInst;
  132. } else if (returned_var_id.is_valid()) {
  133. CARBON_DIAGNOSTIC(
  134. ReturnExprWithReturnedVar, Error,
  135. "can only `return var;` in the scope of a `returned var`");
  136. auto diag = context.emitter().Build(node_id, ReturnExprWithReturnedVar);
  137. NoteReturnedVar(diag, returned_var_id);
  138. diag.Emit();
  139. expr_id = SemIR::InstId::BuiltinErrorInst;
  140. } else if (!return_info.is_valid()) {
  141. // We already diagnosed that the return type is invalid. Don't try to
  142. // convert to it.
  143. expr_id = SemIR::InstId::BuiltinErrorInst;
  144. } else if (return_info.has_return_slot()) {
  145. return_slot_id = function.return_slot_id;
  146. // Note that this can import a function and invalidate `function`.
  147. expr_id = Initialize(context, node_id, return_slot_id, expr_id);
  148. } else {
  149. expr_id =
  150. ConvertToValueOfType(context, node_id, expr_id, return_info.type_id);
  151. }
  152. context.AddInst<SemIR::ReturnExpr>(
  153. node_id, {.expr_id = expr_id, .dest_id = return_slot_id});
  154. }
  155. auto BuildReturnVar(Context& context, Parse::ReturnStatementId node_id)
  156. -> void {
  157. const auto& function = GetCurrentFunction(context);
  158. auto returned_var_id = GetCurrentReturnedVar(context);
  159. if (!returned_var_id.is_valid()) {
  160. CARBON_DIAGNOSTIC(ReturnVarWithNoReturnedVar, Error,
  161. "`return var;` with no `returned var` in scope");
  162. context.emitter().Emit(node_id, ReturnVarWithNoReturnedVar);
  163. returned_var_id = SemIR::InstId::BuiltinErrorInst;
  164. }
  165. auto return_slot_id = function.return_slot_id;
  166. if (!SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function)
  167. .has_return_slot()) {
  168. // If we don't have a return slot, we're returning by value. Convert to a
  169. // value expression.
  170. returned_var_id = ConvertToValueExpr(context, returned_var_id);
  171. return_slot_id = SemIR::InstId::Invalid;
  172. }
  173. context.AddInst<SemIR::ReturnExpr>(
  174. node_id, {.expr_id = returned_var_id, .dest_id = return_slot_id});
  175. }
  176. } // namespace Carbon::Check