function.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. // TODO: Pass a specific ID for `prev_function` instead of substitutions and
  20. // use it here.
  21. auto new_return_type_id =
  22. new_function.GetDeclaredReturnType(context.sem_ir());
  23. auto prev_return_type_id = prev_function.GetDeclaredReturnType(
  24. context.sem_ir(), SemIR::SpecificId::Invalid);
  25. if (new_return_type_id == SemIR::TypeId::Error ||
  26. prev_return_type_id == SemIR::TypeId::Error) {
  27. return false;
  28. }
  29. if (prev_return_type_id.is_valid()) {
  30. prev_return_type_id =
  31. SubstType(context, prev_return_type_id, substitutions);
  32. }
  33. if (!context.types().AreEqualAcrossDeclarations(new_return_type_id,
  34. prev_return_type_id)) {
  35. CARBON_DIAGNOSTIC(
  36. FunctionRedeclReturnTypeDiffers, Error,
  37. "Function redeclaration differs because return type is `{0}`.",
  38. SemIR::TypeId);
  39. CARBON_DIAGNOSTIC(
  40. FunctionRedeclReturnTypeDiffersNoReturn, Error,
  41. "Function redeclaration differs because no return type is provided.");
  42. auto diag =
  43. new_return_type_id.is_valid()
  44. ? context.emitter().Build(new_function.decl_id,
  45. FunctionRedeclReturnTypeDiffers,
  46. new_return_type_id)
  47. : context.emitter().Build(new_function.decl_id,
  48. FunctionRedeclReturnTypeDiffersNoReturn);
  49. if (prev_return_type_id.is_valid()) {
  50. CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePrevious, Note,
  51. "Previously declared with return type `{0}`.",
  52. SemIR::TypeId);
  53. diag.Note(prev_function.decl_id, FunctionRedeclReturnTypePrevious,
  54. prev_return_type_id);
  55. } else {
  56. CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePreviousNoReturn, Note,
  57. "Previously declared with no return type.");
  58. diag.Note(prev_function.decl_id,
  59. FunctionRedeclReturnTypePreviousNoReturn);
  60. }
  61. diag.Emit();
  62. return false;
  63. }
  64. return true;
  65. }
  66. auto CheckFunctionReturnType(Context& context, SemIRLoc loc,
  67. SemIR::Function& function,
  68. SemIR::SpecificId specific_id)
  69. -> SemIR::Function::ReturnSlot {
  70. // If we have already checked the return type, we have nothing to do.
  71. if (function.return_slot != SemIR::Function::ReturnSlot::NotComputed &&
  72. !specific_id.is_valid()) {
  73. return function.return_slot;
  74. }
  75. if (!function.return_storage_id.is_valid()) {
  76. // Implicit `-> ()` has no return slot.
  77. function.return_slot = SemIR::Function::ReturnSlot::Absent;
  78. return function.return_slot;
  79. }
  80. auto return_type_id =
  81. function.GetDeclaredReturnType(context.sem_ir(), specific_id);
  82. CARBON_CHECK(return_type_id.is_valid())
  83. << "Have return storage but no return type.";
  84. // Check the return type is complete. Only diagnose incompleteness if we've
  85. // not already done so.
  86. auto diagnose_incomplete_return_type = [&] {
  87. CARBON_DIAGNOSTIC(IncompleteTypeInFunctionReturnType, Error,
  88. "Function returns incomplete type `{0}`.", SemIR::TypeId);
  89. return context.emitter().Build(loc, IncompleteTypeInFunctionReturnType,
  90. return_type_id);
  91. };
  92. SemIR::Function::ReturnSlot result;
  93. if (!context.TryToCompleteType(
  94. return_type_id,
  95. function.return_slot == SemIR::Function::ReturnSlot::Error
  96. ? std::nullopt
  97. : std::optional(diagnose_incomplete_return_type))) {
  98. result = SemIR::Function::ReturnSlot::Error;
  99. } else if (SemIR::GetInitRepr(context.sem_ir(), return_type_id)
  100. .has_return_slot()) {
  101. result = SemIR::Function::ReturnSlot::Present;
  102. } else {
  103. result = SemIR::Function::ReturnSlot::Absent;
  104. }
  105. if (!specific_id.is_valid()) {
  106. function.return_slot = result;
  107. }
  108. return result;
  109. }
  110. } // namespace Carbon::Check