Promote FunctionType to a standard instruction. (#3931)

This removes the builtin FunctionType, replacing it with a FunctionType
instruction. The constant for a FunctionDecl is now a StructValue with
type of FunctionType.

Note this means a function declaration produces _both_ a type, and a
value of the type. This has some consequences in terms of circularity,
and makes the importing of function declarations a little more complex.

It'll get particularly peculiar for imports because of the behavior of
the reference, but that's a known issue due to other things such as
`alias`. The impact will hopefully be contained to
ResolvePrevInstForMerge (and ImportRefs).

To note a small formatting change in diagnostics:

```
-  // CHECK:STDERR: fail_member_lookup.carbon:[[@LINE+4]]:3: ERROR: Value of type `<associated <function> in Interface>` is not callable.
+  // CHECK:STDERR: fail_member_lookup.carbon:[[@LINE+4]]:3: ERROR: Value of type `<associated F in Interface>` is not callable.

-  // CHECK:STDERR: fail_todo_facet_lookup.carbon:[[@LINE+4]]:3: ERROR: Value of type `<associated <function> in Interface>` is not callable.
+  // CHECK:STDERR: fail_todo_facet_lookup.carbon:[[@LINE+4]]:3: ERROR: Value of type `<associated F in Interface>` is not callable.
```

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
Jon Ross-Perkins
2024-05-03 15:18:04 +00:00
committed by GitHub
co-authored by Richard Smith
parent e6061f6910
commit 76ed3c73cb
405 changed files with 9799 additions and 6579 deletions
+30 -13
View File
@@ -8,6 +8,7 @@
#include "toolchain/check/diagnostic_helpers.h"
#include "toolchain/diagnostics/diagnostic_emitter.h"
#include "toolchain/sem_ir/builtin_function_kind.h"
#include "toolchain/sem_ir/function.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/typed_insts.h"
@@ -687,10 +688,12 @@ static auto PerformBuiltinFloatComparison(
return MakeBoolResult(context, bool_type_id, result);
}
static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call,
SemIR::BuiltinFunctionKind builtin_kind,
llvm::ArrayRef<SemIR::InstId> arg_ids,
Phase phase) -> SemIR::ConstantId {
// Returns a constant for a call to a builtin function.
static auto MakeConstantForBuiltinCall(Context& context, SemIRLoc loc,
SemIR::Call call,
SemIR::BuiltinFunctionKind builtin_kind,
llvm::ArrayRef<SemIR::InstId> arg_ids,
Phase phase) -> SemIR::ConstantId {
switch (builtin_kind) {
case SemIR::BuiltinFunctionKind::None:
CARBON_FATAL() << "Not a builtin function.";
@@ -810,8 +813,9 @@ static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call,
return SemIR::ConstantId::NotConstant;
}
static auto PerformCall(Context& context, SemIRLoc loc, SemIR::Call call)
-> SemIR::ConstantId {
// Makes a constant for a call instruction.
static auto MakeConstantForCall(Context& context, SemIRLoc loc,
SemIR::Call call) -> SemIR::ConstantId {
Phase phase = Phase::Template;
// A call with an invalid argument list is used to represent an erroneous
@@ -828,10 +832,15 @@ static auto PerformCall(Context& context, SemIRLoc loc, SemIR::Call call)
return SemIR::ConstantId::NotConstant;
}
auto callee_function =
SemIR::GetCalleeFunction(context.sem_ir(), call.callee_id);
if (!callee_function.function_id.is_valid()) {
return SemIR::ConstantId::Error;
}
const auto& function = context.functions().Get(callee_function.function_id);
// Handle calls to builtins.
if (auto builtin_function_kind = SemIR::BuiltinFunctionKind::ForCallee(
context.sem_ir(), call.callee_id);
builtin_function_kind != SemIR::BuiltinFunctionKind::None) {
if (function.builtin_kind != SemIR::BuiltinFunctionKind::None) {
if (!ReplaceFieldWithConstantValue(context, &call, &SemIR::Call::args_id,
&phase)) {
return SemIR::ConstantId::NotConstant;
@@ -839,8 +848,9 @@ static auto PerformCall(Context& context, SemIRLoc loc, SemIR::Call call)
if (phase == Phase::UnknownDueToError) {
return SemIR::ConstantId::Error;
}
return PerformBuiltinCall(context, loc, call, builtin_function_kind,
context.inst_blocks().Get(call.args_id), phase);
return MakeConstantForBuiltinCall(context, loc, call, function.builtin_kind,
context.inst_blocks().Get(call.args_id),
phase);
}
return SemIR::ConstantId::NotConstant;
}
@@ -955,9 +965,17 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
case SemIR::AssociatedEntity::Kind:
case SemIR::Builtin::Kind:
case SemIR::FunctionType::Kind:
// Builtins are always template constants.
return MakeConstantResult(context, inst, Phase::Template);
case CARBON_KIND(SemIR::FunctionDecl fn_decl): {
return MakeConstantResult(
context,
SemIR::StructValue{fn_decl.type_id, SemIR::InstBlockId::Empty},
Phase::Template);
}
case CARBON_KIND(SemIR::ClassDecl class_decl): {
// TODO: Once classes have generic arguments, handle them.
return MakeConstantResult(
@@ -986,7 +1004,6 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
case SemIR::AssociatedConstantDecl::Kind:
case SemIR::BaseDecl::Kind:
case SemIR::FieldDecl::Kind:
case SemIR::FunctionDecl::Kind:
case SemIR::Namespace::Kind:
return SemIR::ConstantId::ForTemplateConstant(inst_id);
@@ -1012,7 +1029,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
return PerformAggregateIndex(context, inst);
case CARBON_KIND(SemIR::Call call): {
return PerformCall(context, inst_id, call);
return MakeConstantForCall(context, inst_id, call);
}
// TODO: These need special handling.