function.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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/merge.h"
  6. #include "toolchain/check/subst.h"
  7. #include "toolchain/sem_ir/ids.h"
  8. namespace Carbon::Check {
  9. CARBON_DIAGNOSTIC(FunctionPreviousDecl, Note, "Previously declared here.");
  10. // Returns true if there was an error in declaring the function, which will have
  11. // previously been diagnosed.
  12. static auto FunctionDeclHasError(Context& context, const SemIR::Function& fn)
  13. -> bool {
  14. if (fn.return_type_id == SemIR::TypeId::Error) {
  15. return true;
  16. }
  17. for (auto param_refs_id : {fn.implicit_param_refs_id, fn.param_refs_id}) {
  18. if (param_refs_id != SemIR::InstBlockId::Empty) {
  19. for (auto param_id : context.inst_blocks().Get(param_refs_id)) {
  20. if (context.insts().Get(param_id).type_id() == SemIR::TypeId::Error) {
  21. return true;
  22. }
  23. }
  24. }
  25. }
  26. return false;
  27. }
  28. // Returns false if a param differs for a redeclaration. The caller is expected
  29. // to provide a diagnostic.
  30. static auto CheckRedeclParam(Context& context,
  31. llvm::StringLiteral param_diag_label,
  32. int32_t param_index,
  33. SemIR::InstId new_param_ref_id,
  34. SemIR::InstId prev_param_ref_id,
  35. Substitutions substitutions) -> bool {
  36. // TODO: Consider differentiating between type and name mistakes. For now,
  37. // taking the simpler approach because I also think we may want to refactor
  38. // params.
  39. auto diagnose = [&]() {
  40. CARBON_DIAGNOSTIC(FunctionRedeclParamDiffers, Error,
  41. "Function redeclaration differs at {0}parameter {1}.",
  42. llvm::StringLiteral, int32_t);
  43. CARBON_DIAGNOSTIC(FunctionRedeclParamPrevious, Note,
  44. "Previous declaration's corresponding {0}parameter here.",
  45. llvm::StringLiteral);
  46. context.emitter()
  47. .Build(new_param_ref_id, FunctionRedeclParamDiffers, param_diag_label,
  48. param_index + 1)
  49. .Note(prev_param_ref_id, FunctionRedeclParamPrevious, param_diag_label)
  50. .Emit();
  51. };
  52. auto new_param_ref = context.insts().Get(new_param_ref_id);
  53. auto prev_param_ref = context.insts().Get(prev_param_ref_id);
  54. if (new_param_ref.kind() != prev_param_ref.kind() ||
  55. new_param_ref.type_id() !=
  56. SubstType(context, prev_param_ref.type_id(), substitutions)) {
  57. diagnose();
  58. return false;
  59. }
  60. if (new_param_ref.Is<SemIR::AddrPattern>()) {
  61. new_param_ref =
  62. context.insts().Get(new_param_ref.As<SemIR::AddrPattern>().inner_id);
  63. prev_param_ref =
  64. context.insts().Get(prev_param_ref.As<SemIR::AddrPattern>().inner_id);
  65. if (new_param_ref.kind() != prev_param_ref.kind()) {
  66. diagnose();
  67. return false;
  68. }
  69. }
  70. if (new_param_ref.Is<SemIR::AnyBindName>()) {
  71. new_param_ref =
  72. context.insts().Get(new_param_ref.As<SemIR::AnyBindName>().value_id);
  73. prev_param_ref =
  74. context.insts().Get(prev_param_ref.As<SemIR::AnyBindName>().value_id);
  75. }
  76. auto new_param = new_param_ref.As<SemIR::Param>();
  77. auto prev_param = prev_param_ref.As<SemIR::Param>();
  78. if (new_param.name_id != prev_param.name_id) {
  79. diagnose();
  80. return false;
  81. }
  82. return true;
  83. }
  84. // Returns false if the param refs differ for a redeclaration.
  85. static auto CheckRedeclParams(Context& context, SemIR::InstId new_decl_id,
  86. SemIR::InstBlockId new_param_refs_id,
  87. SemIR::InstId prev_decl_id,
  88. SemIR::InstBlockId prev_param_refs_id,
  89. llvm::StringLiteral param_diag_label,
  90. Substitutions substitutions) -> bool {
  91. // This will often occur for empty params.
  92. if (new_param_refs_id == prev_param_refs_id) {
  93. return true;
  94. }
  95. const auto new_param_ref_ids = context.inst_blocks().Get(new_param_refs_id);
  96. const auto prev_param_ref_ids = context.inst_blocks().Get(prev_param_refs_id);
  97. if (new_param_ref_ids.size() != prev_param_ref_ids.size()) {
  98. CARBON_DIAGNOSTIC(
  99. FunctionRedeclParamCountDiffers, Error,
  100. "Function redeclaration differs because of {0}parameter count of {1}.",
  101. llvm::StringLiteral, int32_t);
  102. CARBON_DIAGNOSTIC(FunctionRedeclParamCountPrevious, Note,
  103. "Previously declared with {0}parameter count of {1}.",
  104. llvm::StringLiteral, int32_t);
  105. context.emitter()
  106. .Build(new_decl_id, FunctionRedeclParamCountDiffers, param_diag_label,
  107. new_param_ref_ids.size())
  108. .Note(prev_decl_id, FunctionRedeclParamCountPrevious, param_diag_label,
  109. prev_param_ref_ids.size())
  110. .Emit();
  111. return false;
  112. }
  113. for (auto [index, new_param_ref_id, prev_param_ref_id] :
  114. llvm::enumerate(new_param_ref_ids, prev_param_ref_ids)) {
  115. if (!CheckRedeclParam(context, param_diag_label, index, new_param_ref_id,
  116. prev_param_ref_id, substitutions)) {
  117. return false;
  118. }
  119. }
  120. return true;
  121. }
  122. // Returns false if the provided function declarations differ.
  123. static auto CheckRedecl(Context& context, const SemIR::Function& new_function,
  124. const SemIR::Function& prev_function,
  125. Substitutions substitutions) -> bool {
  126. if (FunctionDeclHasError(context, new_function) ||
  127. FunctionDeclHasError(context, prev_function)) {
  128. return false;
  129. }
  130. if (!CheckRedeclParams(
  131. context, new_function.decl_id, new_function.implicit_param_refs_id,
  132. prev_function.decl_id, prev_function.implicit_param_refs_id,
  133. "implicit ", substitutions) ||
  134. !CheckRedeclParams(context, new_function.decl_id,
  135. new_function.param_refs_id, prev_function.decl_id,
  136. prev_function.param_refs_id, "", substitutions)) {
  137. return false;
  138. }
  139. auto prev_return_type_id =
  140. prev_function.return_type_id.is_valid()
  141. ? SubstType(context, prev_function.return_type_id, substitutions)
  142. : SemIR::TypeId::Invalid;
  143. if (new_function.return_type_id != prev_return_type_id) {
  144. CARBON_DIAGNOSTIC(
  145. FunctionRedeclReturnTypeDiffers, Error,
  146. "Function redeclaration differs because return type is `{0}`.",
  147. SemIR::TypeId);
  148. CARBON_DIAGNOSTIC(
  149. FunctionRedeclReturnTypeDiffersNoReturn, Error,
  150. "Function redeclaration differs because no return type is provided.");
  151. auto diag =
  152. new_function.return_type_id.is_valid()
  153. ? context.emitter().Build(new_function.decl_id,
  154. FunctionRedeclReturnTypeDiffers,
  155. new_function.return_type_id)
  156. : context.emitter().Build(new_function.decl_id,
  157. FunctionRedeclReturnTypeDiffersNoReturn);
  158. if (prev_return_type_id.is_valid()) {
  159. CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePrevious, Note,
  160. "Previously declared with return type `{0}`.",
  161. SemIR::TypeId);
  162. diag.Note(prev_function.decl_id, FunctionRedeclReturnTypePrevious,
  163. prev_return_type_id);
  164. } else {
  165. CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePreviousNoReturn, Note,
  166. "Previously declared with no return type.");
  167. diag.Note(prev_function.decl_id,
  168. FunctionRedeclReturnTypePreviousNoReturn);
  169. }
  170. diag.Emit();
  171. return false;
  172. }
  173. return true;
  174. }
  175. auto CheckFunctionTypeMatches(Context& context,
  176. SemIR::FunctionId new_function_id,
  177. SemIR::FunctionId prev_function_id,
  178. Substitutions substitutions) -> bool {
  179. return CheckRedecl(context, context.functions().Get(new_function_id),
  180. context.functions().Get(prev_function_id), substitutions);
  181. }
  182. // Emits a redundant redeclaration diagnostic.
  183. static auto EmitRedundantRedecl(Context& context, SemIR::LocId loc_id,
  184. const SemIR::Function& prev_function) {
  185. CARBON_DIAGNOSTIC(FunctionRedecl, Error,
  186. "Redundant redeclaration of function {0}.", SemIR::NameId);
  187. context.emitter()
  188. .Build(loc_id, FunctionRedecl, prev_function.name_id)
  189. .Note(prev_function.decl_id, FunctionPreviousDecl)
  190. .Emit();
  191. }
  192. // Emits a redefinition diagnostic.
  193. static auto EmitRedefinition(Context& context, SemIR::LocId loc_id,
  194. const SemIR::Function& prev_function) {
  195. CARBON_DIAGNOSTIC(FunctionRedefinition, Error,
  196. "Redefinition of function {0}.", SemIR::NameId);
  197. CARBON_DIAGNOSTIC(FunctionPreviousDefinition, Note,
  198. "Previously defined here.");
  199. context.emitter()
  200. .Build(loc_id, FunctionRedefinition, prev_function.name_id)
  201. .Note(prev_function.definition_id, FunctionPreviousDefinition)
  202. .Emit();
  203. }
  204. // Checks to see if a structurally valid redeclaration is allowed in context.
  205. // These all still merge.
  206. static auto CheckIsAllowedRedecl(Context& context, SemIR::LocId loc_id,
  207. const SemIR::Function& new_function,
  208. bool new_is_definition,
  209. const SemIR::Function& prev_function,
  210. SemIR::ImportIRInstId prev_import_ir_inst_id)
  211. -> void {
  212. if (!prev_import_ir_inst_id.is_valid()) {
  213. // Check for disallowed redeclarations in the same file.
  214. if (!new_is_definition) {
  215. EmitRedundantRedecl(context, loc_id, prev_function);
  216. return;
  217. }
  218. if (prev_function.definition_id.is_valid()) {
  219. EmitRedefinition(context, loc_id, prev_function);
  220. return;
  221. }
  222. // `extern` definitions are prevented in handle_function.cpp; this is only
  223. // checking for a non-`extern` definition after an `extern` declaration.
  224. if (prev_function.is_extern) {
  225. CARBON_DIAGNOSTIC(FunctionDefiningExtern, Error,
  226. "Redeclaring `extern` function `{0}` as non-`extern`.",
  227. SemIR::NameId);
  228. CARBON_DIAGNOSTIC(FunctionPreviousExternDecl, Note,
  229. "Previously declared `extern` here.");
  230. context.emitter()
  231. .Build(loc_id, FunctionDefiningExtern, prev_function.name_id)
  232. .Note(prev_function.decl_id, FunctionPreviousExternDecl)
  233. .Emit();
  234. return;
  235. }
  236. return;
  237. }
  238. auto import_ir_id =
  239. context.import_ir_insts().Get(prev_import_ir_inst_id).ir_id;
  240. if (import_ir_id == SemIR::ImportIRId::ApiForImpl) {
  241. // Check for disallowed redeclarations in the same library. Note that a
  242. // forward declaration in the impl is allowed.
  243. if (prev_function.definition_id.is_valid()) {
  244. if (new_function.definition_id.is_valid()) {
  245. EmitRedefinition(context, loc_id, prev_function);
  246. } else {
  247. EmitRedundantRedecl(context, loc_id, prev_function);
  248. }
  249. return;
  250. }
  251. if (prev_function.is_extern != new_function.is_extern) {
  252. CARBON_DIAGNOSTIC(
  253. FunctionExternMismatch, Error,
  254. "Redeclarations in the same library must match use of `extern`.");
  255. context.emitter()
  256. .Build(loc_id, FunctionExternMismatch)
  257. .Note(prev_function.decl_id, FunctionPreviousDecl)
  258. .Emit();
  259. return;
  260. }
  261. return;
  262. }
  263. // Check for disallowed redeclarations cross-library.
  264. if (!new_function.is_extern && !prev_function.is_extern) {
  265. CARBON_DIAGNOSTIC(
  266. FunctionNonExternRedecl, Error,
  267. "Only one library can declare function {0} without `extern`.",
  268. SemIR::NameId);
  269. context.emitter()
  270. .Build(loc_id, FunctionNonExternRedecl, prev_function.name_id)
  271. .Note(prev_function.decl_id, FunctionPreviousDecl)
  272. .Emit();
  273. return;
  274. }
  275. }
  276. auto MergeFunctionRedecl(Context& context, SemIR::LocId loc_id,
  277. SemIR::Function& new_function, bool new_is_import,
  278. bool new_is_definition,
  279. SemIR::FunctionId prev_function_id,
  280. SemIR::ImportIRInstId prev_import_ir_inst_id) -> bool {
  281. auto& prev_function = context.functions().Get(prev_function_id);
  282. if (!CheckRedecl(context, new_function, prev_function, {})) {
  283. return false;
  284. }
  285. CheckIsAllowedRedecl(context, loc_id, new_function, new_is_definition,
  286. prev_function, prev_import_ir_inst_id);
  287. if (new_is_definition) {
  288. // Track the signature from the definition, so that IDs in the body
  289. // match IDs in the signature.
  290. prev_function.definition_id = new_function.definition_id;
  291. prev_function.implicit_param_refs_id = new_function.implicit_param_refs_id;
  292. prev_function.param_refs_id = new_function.param_refs_id;
  293. prev_function.return_type_id = new_function.return_type_id;
  294. prev_function.return_slot_id = new_function.return_slot_id;
  295. }
  296. if ((prev_import_ir_inst_id.is_valid() && !new_is_import) ||
  297. (prev_function.is_extern && !new_function.is_extern)) {
  298. prev_function.is_extern = new_function.is_extern;
  299. prev_function.decl_id = new_function.decl_id;
  300. ReplacePrevInstForMerge(context, prev_function.enclosing_scope_id,
  301. prev_function.name_id, new_function.decl_id);
  302. }
  303. return true;
  304. }
  305. } // namespace Carbon::Check