Files
carbon-lang/toolchain/sem_ir/function.cpp
T
Richard Smith 1a1bfd2eb2 Track and resolve the specific callee in a call to a generic function (#4395)
Add a new `specific_function` instruction that represents a generic
function plus its deduced argument list as a callee in a function call.
The new instruction can only appear as the immediate operand of a call
instruction, so we give it a builtin placeholder type.

At the end of each file, require definitions for all specific functions
used in that file. Resolve the generic with the argument list to produce
those specific function definitions as needed, and diagnose if the
generic doesn't have a definition available.

A few tests are updated in cases where they declared and used generic
functions but didn't previously provide a function definition.
2024-10-10 20:52:46 +00:00

87 lines
2.8 KiB
C++

// 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/sem_ir/function.h"
#include "toolchain/sem_ir/file.h"
#include "toolchain/sem_ir/generic.h"
#include "toolchain/sem_ir/ids.h"
namespace Carbon::SemIR {
auto GetCalleeFunction(const File& sem_ir, InstId callee_id) -> CalleeFunction {
CalleeFunction result = {.function_id = FunctionId::Invalid,
.enclosing_specific_id = SpecificId::Invalid,
.resolved_specific_id = SpecificId::Invalid,
.self_id = InstId::Invalid,
.is_error = false};
if (auto specific_function =
sem_ir.insts().TryGetAs<SpecificFunction>(callee_id)) {
result.resolved_specific_id = specific_function->specific_id;
callee_id = specific_function->callee_id;
}
if (auto bound_method = sem_ir.insts().TryGetAs<BoundMethod>(callee_id)) {
result.self_id = bound_method->object_id;
callee_id = bound_method->function_id;
}
// Identify the function we're calling.
auto val_id = sem_ir.constant_values().GetConstantInstId(callee_id);
if (!val_id.is_valid()) {
return result;
}
auto val_inst = sem_ir.insts().Get(val_id);
auto struct_val = val_inst.TryAs<StructValue>();
if (!struct_val) {
result.is_error = val_inst.type_id() == SemIR::TypeId::Error;
return result;
}
auto fn_type = sem_ir.types().TryGetAs<FunctionType>(struct_val->type_id);
if (!fn_type) {
return result;
}
result.function_id = fn_type->function_id;
result.enclosing_specific_id = fn_type->specific_id;
return result;
}
auto Function::GetParamFromParamRefId(const File& sem_ir, InstId param_ref_id)
-> ParamInfo {
auto ref = sem_ir.insts().Get(param_ref_id);
if (auto addr_pattern = ref.TryAs<AddrPattern>()) {
param_ref_id = addr_pattern->inner_id;
ref = sem_ir.insts().Get(param_ref_id);
}
auto bind_name = ref.TryAs<AnyBindName>();
if (bind_name) {
param_ref_id = bind_name->value_id;
ref = sem_ir.insts().Get(param_ref_id);
}
return {param_ref_id, ref.As<Param>(), bind_name};
}
auto Function::ParamInfo::GetNameId(const File& sem_ir) -> NameId {
if (bind_name) {
return sem_ir.entity_names().Get(bind_name->entity_name_id).name_id;
} else {
return NameId::Invalid;
}
}
auto Function::GetDeclaredReturnType(const File& file,
SpecificId specific_id) const -> TypeId {
if (!return_storage_id.is_valid()) {
return TypeId::Invalid;
}
return GetTypeInSpecific(file, specific_id,
file.insts().Get(return_storage_id).type_id());
}
} // namespace Carbon::SemIR