function.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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/function.h"
  5. namespace Carbon::Check {
  6. // Returns true if there was an error in declaring the function, which will have
  7. // previously been diagnosed.
  8. static auto FunctionDeclHasError(Context& context, const SemIR::Function& fn)
  9. -> bool {
  10. if (fn.return_type_id == SemIR::TypeId::Error) {
  11. return true;
  12. }
  13. for (auto param_refs_id : {fn.implicit_param_refs_id, fn.param_refs_id}) {
  14. if (param_refs_id != SemIR::InstBlockId::Empty) {
  15. for (auto param_id : context.inst_blocks().Get(param_refs_id)) {
  16. if (context.insts().Get(param_id).type_id() == SemIR::TypeId::Error) {
  17. return true;
  18. }
  19. }
  20. }
  21. }
  22. return false;
  23. }
  24. // Returns false if a param differs for a redeclaration. The caller is expected
  25. // to provide a diagnostic.
  26. static auto CheckRedeclParam(Context& context,
  27. llvm::StringLiteral param_diag_label,
  28. int32_t param_index,
  29. SemIR::InstId new_param_ref_id,
  30. SemIR::InstId prev_param_ref_id) -> bool {
  31. // TODO: Consider differentiating between type and name mistakes. For now,
  32. // taking the simpler approach because I also think we may want to refactor
  33. // params.
  34. auto diagnose = [&]() {
  35. CARBON_DIAGNOSTIC(FunctionRedeclParamDiffers, Error,
  36. "Function redeclaration differs at {0}parameter {1}.",
  37. llvm::StringLiteral, int32_t);
  38. CARBON_DIAGNOSTIC(FunctionRedeclParamPrevious, Note,
  39. "Previous declaration's corresponding {0}parameter here.",
  40. llvm::StringLiteral);
  41. context.emitter()
  42. .Build(new_param_ref_id, FunctionRedeclParamDiffers, param_diag_label,
  43. param_index + 1)
  44. .Note(prev_param_ref_id, FunctionRedeclParamPrevious, param_diag_label)
  45. .Emit();
  46. };
  47. auto new_param_ref = context.insts().Get(new_param_ref_id);
  48. auto prev_param_ref = context.insts().Get(prev_param_ref_id);
  49. if (new_param_ref.kind() != prev_param_ref.kind() ||
  50. new_param_ref.type_id() != prev_param_ref.type_id()) {
  51. diagnose();
  52. return false;
  53. }
  54. if (new_param_ref.Is<SemIR::AddrPattern>()) {
  55. new_param_ref =
  56. context.insts().Get(new_param_ref.As<SemIR::AddrPattern>().inner_id);
  57. prev_param_ref =
  58. context.insts().Get(prev_param_ref.As<SemIR::AddrPattern>().inner_id);
  59. if (new_param_ref.kind() != prev_param_ref.kind()) {
  60. diagnose();
  61. return false;
  62. }
  63. }
  64. if (new_param_ref.Is<SemIR::AnyBindName>()) {
  65. new_param_ref =
  66. context.insts().Get(new_param_ref.As<SemIR::AnyBindName>().value_id);
  67. prev_param_ref =
  68. context.insts().Get(prev_param_ref.As<SemIR::AnyBindName>().value_id);
  69. }
  70. auto new_param = new_param_ref.As<SemIR::Param>();
  71. auto prev_param = prev_param_ref.As<SemIR::Param>();
  72. if (new_param.name_id != prev_param.name_id) {
  73. diagnose();
  74. return false;
  75. }
  76. return true;
  77. }
  78. // Returns false if the param refs differ for a redeclaration.
  79. static auto CheckRedeclParams(Context& context, SemIR::InstId new_decl_id,
  80. SemIR::InstBlockId new_param_refs_id,
  81. SemIR::InstId prev_decl_id,
  82. SemIR::InstBlockId prev_param_refs_id,
  83. llvm::StringLiteral param_diag_label) -> bool {
  84. // This will often occur for empty params.
  85. if (new_param_refs_id == prev_param_refs_id) {
  86. return true;
  87. }
  88. const auto new_param_ref_ids = context.inst_blocks().Get(new_param_refs_id);
  89. const auto prev_param_ref_ids = context.inst_blocks().Get(prev_param_refs_id);
  90. if (new_param_ref_ids.size() != prev_param_ref_ids.size()) {
  91. CARBON_DIAGNOSTIC(
  92. FunctionRedeclParamCountDiffers, Error,
  93. "Function redeclaration differs because of {0}parameter count of {1}.",
  94. llvm::StringLiteral, int32_t);
  95. CARBON_DIAGNOSTIC(FunctionRedeclParamCountPrevious, Note,
  96. "Previously declared with {0}parameter count of {1}.",
  97. llvm::StringLiteral, int32_t);
  98. context.emitter()
  99. .Build(new_decl_id, FunctionRedeclParamCountDiffers, param_diag_label,
  100. new_param_ref_ids.size())
  101. .Note(prev_decl_id, FunctionRedeclParamCountPrevious, param_diag_label,
  102. prev_param_ref_ids.size())
  103. .Emit();
  104. return false;
  105. }
  106. for (auto [index, new_param_ref_id, prev_param_ref_id] :
  107. llvm::enumerate(new_param_ref_ids, prev_param_ref_ids)) {
  108. if (!CheckRedeclParam(context, param_diag_label, index, new_param_ref_id,
  109. prev_param_ref_id)) {
  110. return false;
  111. }
  112. }
  113. return true;
  114. }
  115. // Returns false if the provided function declarations differ.
  116. static auto CheckRedecl(Context& context, const SemIR::Function& new_function,
  117. const SemIR::Function& prev_function) -> bool {
  118. if (FunctionDeclHasError(context, new_function) ||
  119. FunctionDeclHasError(context, prev_function)) {
  120. return false;
  121. }
  122. if (!CheckRedeclParams(context, new_function.decl_id,
  123. new_function.implicit_param_refs_id,
  124. prev_function.decl_id,
  125. prev_function.implicit_param_refs_id, "implicit ") ||
  126. !CheckRedeclParams(context, new_function.decl_id,
  127. new_function.param_refs_id, prev_function.decl_id,
  128. prev_function.param_refs_id, "")) {
  129. return false;
  130. }
  131. if (new_function.return_type_id != prev_function.return_type_id) {
  132. CARBON_DIAGNOSTIC(
  133. FunctionRedeclReturnTypeDiffers, Error,
  134. "Function redeclaration differs because return type is `{0}`.",
  135. SemIR::TypeId);
  136. CARBON_DIAGNOSTIC(
  137. FunctionRedeclReturnTypeDiffersNoReturn, Error,
  138. "Function redeclaration differs because no return type is provided.");
  139. auto diag =
  140. new_function.return_type_id.is_valid()
  141. ? context.emitter().Build(new_function.decl_id,
  142. FunctionRedeclReturnTypeDiffers,
  143. new_function.return_type_id)
  144. : context.emitter().Build(new_function.decl_id,
  145. FunctionRedeclReturnTypeDiffersNoReturn);
  146. if (prev_function.return_type_id.is_valid()) {
  147. CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePrevious, Note,
  148. "Previously declared with return type `{0}`.",
  149. SemIR::TypeId);
  150. diag.Note(prev_function.decl_id, FunctionRedeclReturnTypePrevious,
  151. prev_function.return_type_id);
  152. } else {
  153. CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePreviousNoReturn, Note,
  154. "Previously declared with no return type.");
  155. diag.Note(prev_function.decl_id,
  156. FunctionRedeclReturnTypePreviousNoReturn);
  157. }
  158. diag.Emit();
  159. return false;
  160. }
  161. return true;
  162. }
  163. auto CheckFunctionRedecl(Context& context, SemIR::FunctionId new_function_id,
  164. SemIR::FunctionId prev_function_id) -> bool {
  165. return CheckRedecl(context, context.functions().Get(new_function_id),
  166. context.functions().Get(prev_function_id));
  167. }
  168. auto MergeFunctionRedecl(Context& context, Parse::NodeId node_id,
  169. SemIR::Function& new_function,
  170. SemIR::FunctionId prev_function_id, bool is_definition)
  171. -> bool {
  172. auto& prev_function = context.functions().Get(prev_function_id);
  173. // TODO: Disallow redeclarations within classes?
  174. if (!CheckRedecl(context, new_function, prev_function)) {
  175. return false;
  176. }
  177. if (!is_definition) {
  178. CARBON_DIAGNOSTIC(FunctionRedecl, Error,
  179. "Redundant redeclaration of function {0}.",
  180. SemIR::NameId);
  181. CARBON_DIAGNOSTIC(FunctionPreviousDecl, Note, "Previously declared here.");
  182. context.emitter()
  183. .Build(node_id, FunctionRedecl, prev_function.name_id)
  184. .Note(prev_function.decl_id, FunctionPreviousDecl)
  185. .Emit();
  186. // The diagnostic doesn't prevent a merge.
  187. return true;
  188. } else if (prev_function.definition_id.is_valid()) {
  189. CARBON_DIAGNOSTIC(FunctionRedefinition, Error,
  190. "Redefinition of function {0}.", SemIR::NameId);
  191. CARBON_DIAGNOSTIC(FunctionPreviousDefinition, Note,
  192. "Previously defined here.");
  193. context.emitter()
  194. .Build(node_id, FunctionRedefinition, prev_function.name_id)
  195. .Note(prev_function.definition_id, FunctionPreviousDefinition)
  196. .Emit();
  197. // The second definition will be unused as a consequence of the error.
  198. return true;
  199. }
  200. // Track the signature from the definition, so that IDs in the body
  201. // match IDs in the signature.
  202. prev_function.definition_id = new_function.definition_id;
  203. prev_function.implicit_param_refs_id = new_function.implicit_param_refs_id;
  204. prev_function.param_refs_id = new_function.param_refs_id;
  205. prev_function.return_type_id = new_function.return_type_id;
  206. prev_function.return_slot_id = new_function.return_slot_id;
  207. return true;
  208. }
  209. } // namespace Carbon::Check