| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- // 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 "common/find.h"
- #include "toolchain/check/merge.h"
- #include "toolchain/check/type_completion.h"
- #include "toolchain/sem_ir/ids.h"
- #include "toolchain/sem_ir/pattern.h"
- namespace Carbon::Check {
- auto FindSelfPattern(Context& context,
- SemIR::InstBlockId implicit_param_patterns_id)
- -> SemIR::InstId {
- auto implicit_param_patterns =
- context.inst_blocks().GetOrEmpty(implicit_param_patterns_id);
- return FindIfOrNone(implicit_param_patterns, [&](auto implicit_param_id) {
- return SemIR::IsSelfPattern(context.sem_ir(), implicit_param_id);
- });
- }
- auto CheckFunctionReturnTypeMatches(Context& context,
- const SemIR::Function& new_function,
- const SemIR::Function& prev_function,
- SemIR::SpecificId prev_specific_id,
- bool diagnose) -> bool {
- // 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(), prev_specific_id);
- if (new_return_type_id == SemIR::ErrorInst::TypeId ||
- prev_return_type_id == SemIR::ErrorInst::TypeId) {
- return false;
- }
- if (!context.types().AreEqualAcrossDeclarations(new_return_type_id,
- prev_return_type_id)) {
- if (!diagnose) {
- return false;
- }
- 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.has_value()
- ? context.emitter().Build(new_function.latest_decl_id(),
- FunctionRedeclReturnTypeDiffers,
- new_return_type_id)
- : context.emitter().Build(new_function.latest_decl_id(),
- FunctionRedeclReturnTypeDiffersNoReturn);
- if (prev_return_type_id.has_value()) {
- CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePrevious, Note,
- "previously declared with return type {0}",
- SemIR::TypeId);
- diag.Note(prev_function.latest_decl_id(),
- FunctionRedeclReturnTypePrevious, prev_return_type_id);
- } else {
- CARBON_DIAGNOSTIC(FunctionRedeclReturnTypePreviousNoReturn, Note,
- "previously declared with no return type");
- diag.Note(prev_function.latest_decl_id(),
- FunctionRedeclReturnTypePreviousNoReturn);
- }
- diag.Emit();
- return false;
- }
- return true;
- }
- auto CheckFunctionTypeMatches(Context& context,
- const SemIR::Function& new_function,
- const SemIR::Function& prev_function,
- SemIR::SpecificId prev_specific_id,
- bool check_syntax, bool check_self, bool diagnose)
- -> bool {
- if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
- DeclParams(prev_function), prev_specific_id,
- diagnose, check_syntax, check_self)) {
- return false;
- }
- return CheckFunctionReturnTypeMatches(context, new_function, prev_function,
- prev_specific_id, diagnose);
- }
- auto CheckFunctionReturnType(Context& context, SemIR::LocId loc_id,
- const SemIR::Function& function,
- SemIR::SpecificId specific_id)
- -> SemIR::ReturnTypeInfo {
- auto return_info = SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(),
- function, specific_id);
- // If we couldn't determine the return information due to the return type
- // being incomplete, try to complete it now.
- if (return_info.init_repr.kind == SemIR::InitRepr::Incomplete) {
- auto diagnose_incomplete_return_type = [&] {
- CARBON_DIAGNOSTIC(IncompleteTypeInFunctionReturnType, Error,
- "function returns incomplete type {0}", SemIR::TypeId);
- return context.emitter().Build(loc_id, IncompleteTypeInFunctionReturnType,
- return_info.type_id);
- };
- auto diagnose_abstract_return_type = [&] {
- CARBON_DIAGNOSTIC(AbstractTypeInFunctionReturnType, Error,
- "function returns abstract type {0}", SemIR::TypeId);
- return context.emitter().Build(loc_id, AbstractTypeInFunctionReturnType,
- return_info.type_id);
- };
- // TODO: Consider suppressing the diagnostic if we've already diagnosed a
- // definition or call to this function.
- if (RequireConcreteType(context, return_info.type_id, loc_id,
- diagnose_incomplete_return_type,
- diagnose_abstract_return_type)) {
- return_info = SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(),
- function, specific_id);
- }
- }
- return return_info;
- }
- auto CheckFunctionDefinitionSignature(Context& context,
- SemIR::FunctionId function_id) -> void {
- auto& function = context.functions().Get(function_id);
- auto params_to_complete =
- context.inst_blocks().GetOrEmpty(function.call_params_id);
- // Check the return type is complete.
- if (function.return_slot_pattern_id.has_value()) {
- CheckFunctionReturnType(context,
- SemIR::LocId(function.return_slot_pattern_id),
- function, SemIR::SpecificId::None);
- // Don't re-check the return type below.
- params_to_complete.consume_back();
- }
- // Check the parameter types are complete.
- for (auto param_ref_id : params_to_complete) {
- if (param_ref_id == SemIR::ErrorInst::InstId) {
- continue;
- }
- // The parameter types need to be complete.
- RequireCompleteType(
- context, context.insts().GetAs<SemIR::AnyParam>(param_ref_id).type_id,
- SemIR::LocId(param_ref_id), [&] {
- CARBON_DIAGNOSTIC(
- IncompleteTypeInFunctionParam, Error,
- "parameter has incomplete type {0} in function definition",
- TypeOfInstId);
- return context.emitter().Build(
- param_ref_id, IncompleteTypeInFunctionParam, param_ref_id);
- });
- }
- }
- } // namespace Carbon::Check
|