Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overloaded operator support. #3796

Merged
merged 10 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ repos:
Exceptions. See /LICENSE for license information.
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- --custom_format
- '\.(carbon|proto|ypp)$'
- '\.(carbon|proto|ypp)(\.tmpl)?$'
- ''
- '// '
- ''
Expand Down
35 changes: 34 additions & 1 deletion toolchain/check/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ cc_library(
"decl_name_stack.cpp",
"eval.cpp",
"import_ref.cpp",
"import_ref.h",
"inst_block_stack.cpp",
"modifiers.cpp",
"return.cpp",
Expand All @@ -66,6 +65,7 @@ cc_library(
"decl_name_stack.h",
"decl_state.h",
"eval.h",
"import_ref.h",
"inst_block_stack.h",
"modifiers.h",
"param_and_arg_refs_stack.h",
Expand Down Expand Up @@ -101,12 +101,14 @@ cc_library(
]),
hdrs = ["check.h"],
deps = [
":call",
":context",
":function",
":impl",
":import",
":interface",
":member_access",
":operator",
":pointer_dereference",
"//common:check",
"//common:ostream",
Expand Down Expand Up @@ -138,6 +140,20 @@ cc_fuzz_test(
],
)

cc_library(
name = "call",
srcs = ["call.cpp"],
hdrs = ["call.h"],
deps = [
":context",
"//common:check",
"//toolchain/sem_ir:file",
"//toolchain/sem_ir:ids",
"//toolchain/sem_ir:inst",
"//toolchain/sem_ir:inst_kind",
],
)

cc_library(
name = "function",
srcs = ["function.cpp"],
Expand Down Expand Up @@ -213,6 +229,23 @@ cc_library(
],
)

cc_library(
name = "operator",
srcs = ["operator.cpp"],
hdrs = ["operator.h"],
deps = [
":call",
":context",
":member_access",
"//common:check",
"//toolchain/parse:node_kind",
"//toolchain/sem_ir:file",
"//toolchain/sem_ir:ids",
"//toolchain/sem_ir:inst",
"//toolchain/sem_ir:inst_kind",
],
)

cc_library(
name = "pointer_dereference",
srcs = ["pointer_dereference.cpp"],
Expand Down
77 changes: 77 additions & 0 deletions toolchain/check/call.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 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/call.h"

#include "toolchain/check/context.h"
#include "toolchain/check/convert.h"
#include "toolchain/sem_ir/inst.h"
#include "toolchain/sem_ir/typed_insts.h"

namespace Carbon::Check {

auto PerformCall(Context& context, Parse::NodeId node_id,
SemIR::InstId callee_id, llvm::ArrayRef<SemIR::InstId> arg_ids)
-> SemIR::InstId {
auto diagnose_not_callable = [&] {
auto callee_type_id = context.insts().Get(callee_id).type_id();
if (callee_type_id != SemIR::TypeId::Error) {
CARBON_DIAGNOSTIC(CallToNonCallable, Error,
"Value of type `{0}` is not callable.", SemIR::TypeId);
context.emitter().Emit(node_id, CallToNonCallable, callee_type_id);
}
return SemIR::InstId::BuiltinError;
};

// For a method call, pick out the `self` value.
auto function_callee_id = callee_id;
SemIR::InstId self_id = SemIR::InstId::Invalid;
if (auto bound_method =
context.insts().Get(callee_id).TryAs<SemIR::BoundMethod>()) {
self_id = bound_method->object_id;
function_callee_id = bound_method->function_id;
}

// Identify the function we're calling.
auto function_decl_id = context.constant_values().Get(function_callee_id);
if (!function_decl_id.is_constant()) {
return diagnose_not_callable();
}
auto function_decl = context.insts()
.Get(function_decl_id.inst_id())
.TryAs<SemIR::FunctionDecl>();
if (!function_decl) {
return diagnose_not_callable();
}
auto function_id = function_decl->function_id;
const auto& callable = context.functions().Get(function_id);

// For functions with an implicit return type, the return type is the empty
// tuple type.
SemIR::TypeId type_id = callable.return_type_id;
if (!type_id.is_valid()) {
type_id = context.GetTupleType({});
}

// If there is a return slot, build storage for the result.
SemIR::InstId return_storage_id = SemIR::InstId::Invalid;
if (callable.return_slot_id.is_valid()) {
// Tentatively put storage for a temporary in the function's return slot.
// This will be replaced if necessary when we perform initialization.
return_storage_id = context.AddInst(
{node_id, SemIR::TemporaryStorage{callable.return_type_id}});
}

// Convert the arguments to match the parameters.
auto converted_args_id =
ConvertCallArgs(context, node_id, self_id, arg_ids, return_storage_id,
function_decl_id.inst_id(),
callable.implicit_param_refs_id, callable.param_refs_id);
auto call_inst_id = context.AddInst(
{node_id, SemIR::Call{type_id, callee_id, converted_args_id}});

return call_inst_id;
}

} // namespace Carbon::Check
20 changes: 20 additions & 0 deletions toolchain/check/call.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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_CHECK_CALL_H_
#define CARBON_TOOLCHAIN_CHECK_CALL_H_

#include "toolchain/check/context.h"
#include "toolchain/sem_ir/ids.h"

namespace Carbon::Check {

// Checks and builds SemIR for a call to `callee_id` with arguments `args_id`.
auto PerformCall(Context& context, Parse::NodeId node_id,
SemIR::InstId callee_id, llvm::ArrayRef<SemIR::InstId> arg_ids)
-> SemIR::InstId;

} // namespace Carbon::Check

#endif // CARBON_TOOLCHAIN_CHECK_CALL_H_
2 changes: 1 addition & 1 deletion toolchain/check/eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ static auto RebuildAndValidateIfFieldsAreConstant(
if ((ReplaceFieldWithConstantValue(context, &typed_inst, each_field_id,
&phase) &&
...)) {
if (!validate_fn(typed_inst)) {
if (phase == Phase::UnknownDueToError || !validate_fn(typed_inst)) {
return SemIR::ConstantId::Error;
}
return MakeConstantResult(context, typed_inst, phase);
Expand Down
72 changes: 6 additions & 66 deletions toolchain/check/handle_call_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "llvm/ADT/ScopeExit.h"
#include "toolchain/check/call.h"
#include "toolchain/check/context.h"
#include "toolchain/check/convert.h"
#include "toolchain/sem_ir/inst.h"

namespace Carbon::Check {
Expand All @@ -27,74 +26,15 @@ auto HandleCallExpr(Context& context, Parse::CallExprId node_id) -> bool {
// Process the final explicit call argument now, but leave the arguments
// block on the stack until the end of this function.
context.param_and_arg_refs_stack().EndNoPop(Parse::NodeKind::CallExprStart);
auto discard_args_block = llvm::make_scope_exit(
[&] { context.param_and_arg_refs_stack().PopAndDiscard(); });

auto [call_expr_node_id, callee_id] =
context.node_stack().PopWithNodeId<Parse::NodeKind::CallExprStart>();

auto diagnose_not_callable = [&, call_expr_node_id = call_expr_node_id,
callee_id = callee_id] {
auto callee_type_id = context.insts().Get(callee_id).type_id();
if (callee_type_id != SemIR::TypeId::Error) {
CARBON_DIAGNOSTIC(CallToNonCallable, Error,
"Value of type `{0}` is not callable.", SemIR::TypeId);
context.emitter().Emit(call_expr_node_id, CallToNonCallable,
callee_type_id);
}
context.node_stack().Push(node_id, SemIR::InstId::BuiltinError);
return true;
};

// For a method call, pick out the `self` value.
auto function_callee_id = callee_id;
SemIR::InstId self_id = SemIR::InstId::Invalid;
if (auto bound_method =
context.insts().Get(callee_id).TryAs<SemIR::BoundMethod>()) {
self_id = bound_method->object_id;
function_callee_id = bound_method->function_id;
}

// Identify the function we're calling.
auto function_decl_id = context.constant_values().Get(function_callee_id);
if (!function_decl_id.is_constant()) {
return diagnose_not_callable();
}
auto function_decl = context.insts()
.Get(function_decl_id.inst_id())
.TryAs<SemIR::FunctionDecl>();
if (!function_decl) {
return diagnose_not_callable();
}
auto function_id = function_decl->function_id;
const auto& callable = context.functions().Get(function_id);

// For functions with an implicit return type, the return type is the empty
// tuple type.
SemIR::TypeId type_id = callable.return_type_id;
if (!type_id.is_valid()) {
type_id = context.GetTupleType({});
}

// If there is a return slot, build storage for the result.
SemIR::InstId return_storage_id = SemIR::InstId::Invalid;
if (callable.return_slot_id.is_valid()) {
// Tentatively put storage for a temporary in the function's return slot.
// This will be replaced if necessary when we perform initialization.
return_storage_id = context.AddInst(
{call_expr_node_id, SemIR::TemporaryStorage{callable.return_type_id}});
}

// Convert the arguments to match the parameters.
auto converted_args_id = ConvertCallArgs(
context, call_expr_node_id, self_id,
context.param_and_arg_refs_stack().PeekCurrentBlockContents(),
return_storage_id, function_decl_id.inst_id(),
callable.implicit_param_refs_id, callable.param_refs_id);
auto call_inst_id = context.AddInst(
{call_expr_node_id, SemIR::Call{type_id, callee_id, converted_args_id}});
auto call_id = PerformCall(
context, call_expr_node_id, callee_id,
context.param_and_arg_refs_stack().PeekCurrentBlockContents());

context.node_stack().Push(node_id, call_inst_id);
context.param_and_arg_refs_stack().PopAndDiscard();
context.node_stack().Push(node_id, call_id);
return true;
}

Expand Down
Loading
Loading