| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- // Exceptions. See /LICENSE for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- #include "toolchain/check/function.h"
- #include "toolchain/check/merge.h"
- #include "toolchain/check/subst.h"
- #include "toolchain/sem_ir/ids.h"
- namespace Carbon::Check {
- auto CheckFunctionTypeMatches(Context& context,
- const SemIR::Function& new_function,
- const SemIR::Function& prev_function,
- Substitutions substitutions, bool check_syntax)
- -> bool {
- if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
- DeclParams(prev_function), substitutions,
- check_syntax)) {
- return false;
- }
- // TODO: Pass a specific ID for `prev_function` instead of substitutions and
- // use it here.
- auto new_return_type_id =
- new_function.GetDeclaredReturnType(context.sem_ir());
- auto prev_return_type_id = prev_function.GetDeclaredReturnType(
- context.sem_ir(), SemIR::SpecificId::Invalid);
- if (new_return_type_id == SemIR::TypeId::Error ||
- prev_return_type_id == SemIR::TypeId::Error) {
- return false;
- }
- if (prev_return_type_id.is_valid()) {
- prev_return_type_id =
- SubstType(context, prev_return_type_id, substitutions);
- }
- if (!context.types().AreEqualAcrossDeclarations(new_return_type_id,
- prev_return_type_id)) {
- CARBON_DIAGNOSTIC(
- FunctionRedeclReturnTypeDiffers, Error,
- "Function redeclaration differs because return type is `{0}`.",
- SemIR::TypeId);
- CARBON_DIAGNOSTIC(
- FunctionRedeclReturnTypeDiffersNoReturn, Error,
- "Function redeclaration differs because no return type is provided.");
- auto diag =
- new_return_type_id.is_valid()
- ? context.emitter().Build(new_function.decl_id,
- FunctionRedeclReturnTypeDiffers,
- new_return_type_id)
- : context.emitter().Build(new_function.decl_id,
- FunctionRedeclReturnTypeDiffersNoReturn);
- if (prev_return_type_id.is_valid()) {
- CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePrevious, Note,
- "Previously declared with return type `{0}`.",
- SemIR::TypeId);
- diag.Note(prev_function.decl_id, FunctionRedeclReturnTypePrevious,
- prev_return_type_id);
- } else {
- CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePreviousNoReturn, Note,
- "Previously declared with no return type.");
- diag.Note(prev_function.decl_id,
- FunctionRedeclReturnTypePreviousNoReturn);
- }
- diag.Emit();
- return false;
- }
- return true;
- }
- auto CheckFunctionReturnType(Context& context, SemIRLoc loc,
- SemIR::Function& function,
- SemIR::SpecificId specific_id)
- -> SemIR::Function::ReturnSlot {
- // If we have already checked the return type, we have nothing to do.
- if (function.return_slot != SemIR::Function::ReturnSlot::NotComputed &&
- !specific_id.is_valid()) {
- return function.return_slot;
- }
- if (!function.return_storage_id.is_valid()) {
- // Implicit `-> ()` has no return slot.
- function.return_slot = SemIR::Function::ReturnSlot::Absent;
- return function.return_slot;
- }
- auto return_type_id =
- function.GetDeclaredReturnType(context.sem_ir(), specific_id);
- CARBON_CHECK(return_type_id.is_valid())
- << "Have return storage but no return type.";
- // Check the return type is complete. Only diagnose incompleteness if we've
- // not already done so.
- auto diagnose_incomplete_return_type = [&] {
- CARBON_DIAGNOSTIC(IncompleteTypeInFunctionReturnType, Error,
- "Function returns incomplete type `{0}`.", SemIR::TypeId);
- return context.emitter().Build(loc, IncompleteTypeInFunctionReturnType,
- return_type_id);
- };
- SemIR::Function::ReturnSlot result;
- if (!context.TryToCompleteType(
- return_type_id,
- function.return_slot == SemIR::Function::ReturnSlot::Error
- ? std::nullopt
- : std::optional(diagnose_incomplete_return_type))) {
- result = SemIR::Function::ReturnSlot::Error;
- } else if (SemIR::GetInitRepr(context.sem_ir(), return_type_id)
- .has_return_slot()) {
- result = SemIR::Function::ReturnSlot::Present;
- } else {
- result = SemIR::Function::ReturnSlot::Absent;
- }
- if (!specific_id.is_valid()) {
- function.return_slot = result;
- }
- return result;
- }
- } // namespace Carbon::Check
|