Files
carbon-lang/toolchain/sem_ir/function.h
T
Jon Ross-Perkins a65f4b89e2 Make ValueStore require a ValueT parameter (#5757)
This is reducing ValueStore inference of types from `using`, and removes
`using ValueType = ...` from affected id types.

I'm adding a number of `using FooStore = ValueStore<FooId, Foo>` because
I think it's a little repetitive otherwise; often 4 cases where I'm
doing this: getter, const getter, member, and getter on `Context`. Note
we also have a number of `-> decltype(auto)` that were added I think
mainly to avoid repeating the type, but I'm not sure whether there'll be
agreement on replacing those and so am not changing them here.

I'm placing these aliases with the value type in general, because I
think it's probably easier to view that way. An alternative would be to
put all the types on `File`, but:

- That would be inconsistent with things like `InstStore`, which are
very `ValueStore`-adjacent and put with their value type.
- `File` would have a _lot_ of using's, and the accessors are already
noisy -- I think it would just make the file harder to skim.

Note this is the heart of what I'd brought up [on
Discord](https://discord.com/channels/655572317891461132/655578254970716160/1388199282250613019).
This PR still leaves CanonicalValueStore and BlockValueStore as things
to also add parameters to, but I thought it best to try breaking the set
of changes apart by type. Both of those rely on ValueStore, so
ValueStore needs to change first.
2025-07-02 18:07:55 +00:00

197 lines
7.9 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
#ifndef CARBON_TOOLCHAIN_SEM_IR_FUNCTION_H_
#define CARBON_TOOLCHAIN_SEM_IR_FUNCTION_H_
#include "clang/AST/Decl.h"
#include "toolchain/base/value_store.h"
#include "toolchain/sem_ir/builtin_function_kind.h"
#include "toolchain/sem_ir/clang_decl.h"
#include "toolchain/sem_ir/entity_with_params_base.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/inst_categories.h"
#include "toolchain/sem_ir/typed_insts.h"
namespace Carbon::SemIR {
// Function-specific fields.
struct FunctionFields {
// Kinds of special functions.
enum class SpecialFunctionKind : uint8_t { None, Builtin, Thunk };
// Kinds of virtual modifiers that can apply to functions.
enum class VirtualModifier : uint8_t { None, Virtual, Abstract, Impl };
// The following members always have values, and do not change throughout the
// lifetime of the function.
// This block consists of references to the `AnyParam` insts that represent
// the function's `Call` parameters. The "`Call` parameters" are the
// parameters corresponding to the arguments that are passed to a `Call`
// inst, so they do not include compile-time parameters, but they do include
// the return slot.
//
// The parameters appear in declaration order: `self` (if present), then the
// explicit runtime parameters, then the return slot (which is "declared" by
// the function's return type declaration). This is not populated on imported
// functions, because it is relevant only for a function definition.
InstBlockId call_params_id;
// A reference to the instruction in the entity's pattern block that depends
// on all other pattern insts pertaining to the return slot pattern. This may
// or may not be used by the function, depending on whether the return type
// needs a return slot, but is always present if the function has a declared
// return type.
InstId return_slot_pattern_id;
// Which kind of special function this is, if any. This is used in cases where
// a special function would otherwise be indistinguishable from a normal
// function.
SpecialFunctionKind special_function_kind = SpecialFunctionKind::None;
// Which, if any, virtual modifier (virtual, abstract, or impl) is applied to
// this function.
VirtualModifier virtual_modifier;
// The index of the vtable slot for this virtual function. -1 if the function
// is not virtual (ie: (virtual_modifier == None) == (virtual_index == -1)).
int32_t virtual_index = -1;
// The implicit self parameter pattern, if any, in
// implicit_param_patterns_id from EntityWithParamsBase.
InstId self_param_id = InstId::None;
// Data that is specific to the special function kind. Use
// `builtin_function_kind()` or `thunk_decl_id()` to access this.
AnyRawId special_function_kind_data = AnyRawId(AnyRawId::NoneIndex);
// The following members are accumulated throughout the function definition.
// A list of the statically reachable code blocks in the body of the
// function, in lexical order. The first block is the entry block. This will
// be empty for declarations that don't have a visible definition.
llvm::SmallVector<InstBlockId> body_block_ids = {};
// If the function is imported from C++, the Clang function declaration. Used
// for mangling and inline function definition code generation. The AST is
// owned by `CompileSubcommand` so we expect it to be live from `Function`
// creation to mangling.
ClangDeclId clang_decl_id = ClangDeclId::None;
};
// A function. See EntityWithParamsBase regarding the inheritance here.
struct Function : public EntityWithParamsBase,
public FunctionFields,
public Printable<Function> {
struct ParamPatternInfo {
InstId inst_id;
AnyParamPattern inst;
EntityNameId entity_name_id;
};
auto Print(llvm::raw_ostream& out) const -> void {
out << "{";
PrintBaseFields(out);
if (call_params_id.has_value()) {
out << ", call_params_id: " << call_params_id;
}
if (return_slot_pattern_id.has_value()) {
out << ", return_slot_pattern: " << return_slot_pattern_id;
}
if (!body_block_ids.empty()) {
out << llvm::formatv(
", body: [{0}]",
llvm::make_range(body_block_ids.begin(), body_block_ids.end()));
}
out << "}";
}
// Returns the builtin function kind for this function, or None if this is not
// a builtin function.
auto builtin_function_kind() const -> BuiltinFunctionKind {
return special_function_kind == SpecialFunctionKind::Builtin
? BuiltinFunctionKind::FromInt(special_function_kind_data.index)
: BuiltinFunctionKind::None;
}
// Returns the declaration that this is a thunk for, or None if this function
// is not a thunk.
auto thunk_decl_id() const -> InstId {
return special_function_kind == SpecialFunctionKind::Thunk
? InstId(special_function_kind_data.index)
: InstId::None;
}
// Given the ID of an instruction from `param_patterns_id` or
// `implicit_param_patterns_id`, returns a `ParamPatternInfo` value with the
// corresponding `Call` parameter pattern, its ID, and the entity_name_id of
// the underlying binding pattern, or std::nullopt if there is no
// corresponding `Call` parameter.
// TODO: Remove this, by exposing `Call` parameter patterns instead of `Call`
// parameters in EntityWithParams.
static auto GetParamPatternInfoFromPatternId(const File& sem_ir,
InstId param_pattern_id)
-> std::optional<ParamPatternInfo>;
// Gets the declared return type for a specific version of this function, or
// the canonical return type for the original declaration no specific is
// specified. Returns `None` if no return type was specified, in which
// case the effective return type is an empty tuple.
auto GetDeclaredReturnType(const File& file,
SpecificId specific_id = SpecificId::None) const
-> TypeId;
// Sets that this function is a builtin function.
auto SetBuiltinFunction(BuiltinFunctionKind kind) -> void {
CARBON_CHECK(special_function_kind == SpecialFunctionKind::None);
special_function_kind = SpecialFunctionKind::Builtin;
special_function_kind_data = AnyRawId(kind.AsInt());
}
// Sets that this function is a thunk.
auto SetThunk(InstId decl_id) -> void {
CARBON_CHECK(special_function_kind == SpecialFunctionKind::None);
special_function_kind = SpecialFunctionKind::Thunk;
special_function_kind_data = AnyRawId(decl_id.index);
}
};
using FunctionStore = ValueStore<FunctionId, Function>;
class File;
struct CalleeFunction : public Printable<CalleeFunction> {
// The function. `None` if not a function.
FunctionId function_id;
// The specific that contains the function.
SpecificId enclosing_specific_id;
// The specific for the callee itself, in a resolved call.
SpecificId resolved_specific_id;
// The bound `Self` type or facet value. `None` if not a bound interface
// member.
InstId self_type_id;
// The bound `self` parameter. `None` if not a method.
InstId self_id;
// True if an error instruction was found.
bool is_error;
auto Print(llvm::raw_ostream& out) const -> void {
out << "{function_id: " << function_id
<< ", enclosing_specific_id: " << enclosing_specific_id
<< ", resolved_specific_id: " << resolved_specific_id
<< ", self_type_id: " << self_type_id << ", self_id: " << self_id
<< ", is_error: " << is_error << "}";
}
};
// Returns information for the function corresponding to callee_id.
auto GetCalleeFunction(const File& sem_ir, InstId callee_id,
SpecificId specific_id = SpecificId::None)
-> CalleeFunction;
} // namespace Carbon::SemIR
#endif // CARBON_TOOLCHAIN_SEM_IR_FUNCTION_H_