function.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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. auto CheckFunctionTypeMatches(Context& context,
  10. const SemIR::Function& new_function,
  11. const SemIR::Function& prev_function,
  12. Substitutions substitutions, bool check_syntax)
  13. -> bool {
  14. if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
  15. DeclParams(prev_function), substitutions,
  16. check_syntax)) {
  17. return false;
  18. }
  19. auto new_return_type_id = new_function.declared_return_type(context.sem_ir());
  20. auto prev_return_type_id =
  21. prev_function.declared_return_type(context.sem_ir());
  22. if (new_return_type_id == SemIR::TypeId::Error ||
  23. prev_return_type_id == SemIR::TypeId::Error) {
  24. return false;
  25. }
  26. if (prev_return_type_id.is_valid()) {
  27. prev_return_type_id =
  28. SubstType(context, prev_return_type_id, substitutions);
  29. }
  30. if (!context.types().AreEqualAcrossDeclarations(new_return_type_id,
  31. prev_return_type_id)) {
  32. CARBON_DIAGNOSTIC(
  33. FunctionRedeclReturnTypeDiffers, Error,
  34. "Function redeclaration differs because return type is `{0}`.",
  35. SemIR::TypeId);
  36. CARBON_DIAGNOSTIC(
  37. FunctionRedeclReturnTypeDiffersNoReturn, Error,
  38. "Function redeclaration differs because no return type is provided.");
  39. auto diag =
  40. new_return_type_id.is_valid()
  41. ? context.emitter().Build(new_function.decl_id,
  42. FunctionRedeclReturnTypeDiffers,
  43. new_return_type_id)
  44. : context.emitter().Build(new_function.decl_id,
  45. FunctionRedeclReturnTypeDiffersNoReturn);
  46. if (prev_return_type_id.is_valid()) {
  47. CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePrevious, Note,
  48. "Previously declared with return type `{0}`.",
  49. SemIR::TypeId);
  50. diag.Note(prev_function.decl_id, FunctionRedeclReturnTypePrevious,
  51. prev_return_type_id);
  52. } else {
  53. CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePreviousNoReturn, Note,
  54. "Previously declared with no return type.");
  55. diag.Note(prev_function.decl_id,
  56. FunctionRedeclReturnTypePreviousNoReturn);
  57. }
  58. diag.Emit();
  59. return false;
  60. }
  61. return true;
  62. }
  63. auto CheckFunctionReturnType(Context& context, SemIRLoc loc,
  64. SemIR::Function& function) -> void {
  65. // If we have already checked the return type, we have nothing to do.
  66. if (function.return_slot != SemIR::Function::ReturnSlot::NotComputed) {
  67. return;
  68. }
  69. if (!function.return_storage_id.is_valid()) {
  70. // Implicit `-> ()` has no return slot.
  71. function.return_slot = SemIR::Function::ReturnSlot::Absent;
  72. return;
  73. }
  74. auto return_type_id = function.declared_return_type(context.sem_ir());
  75. CARBON_CHECK(return_type_id.is_valid())
  76. << "Have return storage but no return type.";
  77. // Check the return type is complete. Only diagnose incompleteness if we've
  78. // not already done so.
  79. auto diagnose_incomplete_return_type = [&] {
  80. CARBON_DIAGNOSTIC(IncompleteTypeInFunctionReturnType, Error,
  81. "Function returns incomplete type `{0}`.", SemIR::TypeId);
  82. return context.emitter().Build(loc, IncompleteTypeInFunctionReturnType,
  83. return_type_id);
  84. };
  85. if (!context.TryToCompleteType(
  86. return_type_id,
  87. function.return_slot == SemIR::Function::ReturnSlot::Error
  88. ? std::nullopt
  89. : std::optional(diagnose_incomplete_return_type))) {
  90. function.return_slot = SemIR::Function::ReturnSlot::Error;
  91. } else if (SemIR::GetInitRepr(context.sem_ir(), return_type_id)
  92. .has_return_slot()) {
  93. function.return_slot = SemIR::Function::ReturnSlot::Present;
  94. } else {
  95. function.return_slot = SemIR::Function::ReturnSlot::Absent;
  96. }
  97. }
  98. } // namespace Carbon::Check