function.cpp 10 KB

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