Files
carbon-lang/toolchain/check/operator.cpp
T
Richard SmithandJon Ross-Perkins 187a3608df Use As and ImplicitAs interfaces for conversions. (#4209)
Add these interfaces to the core library. For now, they're two separate
interfaces because we don't yet support one interface extending another.

This collapses a lot of the layering in check: for example, the call
building logic depends on implicit conversions, conversions now depend
on the overloaded operator machinery, and that machinery depends on
building calls.

In passing, improve the diagnostics for failing to find a name required
from the prelude. Also convert all the transitively-called code from
`NodeId` to `LocId` given the latter is what the conversion machinery
has available.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2024-09-05 23:39:58 +00:00

71 lines
2.5 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/check/operator.h"
#include "toolchain/check/call.h"
#include "toolchain/check/context.h"
#include "toolchain/check/generic.h"
#include "toolchain/check/member_access.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/typed_insts.h"
namespace Carbon::Check {
// Returns the `Op` function for the specified operator.
static auto GetOperatorOpFunction(Context& context, SemIR::LocId loc_id,
Operator op) -> SemIR::InstId {
// Look up the interface, and pass it any generic arguments.
auto interface_id = context.LookupNameInCore(loc_id, op.interface_name);
if (!op.interface_args_ref.empty()) {
interface_id =
PerformCall(context, loc_id, interface_id, op.interface_args_ref);
}
// Look up the interface member.
auto op_name_id =
SemIR::NameId::ForIdentifier(context.identifiers().Add(op.op_name));
return PerformMemberAccess(context, loc_id, interface_id, op_name_id);
}
auto BuildUnaryOperator(
Context& context, SemIR::LocId loc_id, Operator op,
SemIR::InstId operand_id,
std::optional<Context::BuildDiagnosticFn> missing_impl_diagnoser)
-> SemIR::InstId {
// Look up the operator function.
auto op_fn = GetOperatorOpFunction(context, loc_id, op);
// Form `operand.(Op)`.
auto bound_op_id = PerformCompoundMemberAccess(context, loc_id, operand_id,
op_fn, missing_impl_diagnoser);
if (bound_op_id == SemIR::InstId::BuiltinError) {
return SemIR::InstId::BuiltinError;
}
// Form `bound_op()`.
return PerformCall(context, loc_id, bound_op_id, {});
}
auto BuildBinaryOperator(
Context& context, SemIR::LocId loc_id, Operator op, SemIR::InstId lhs_id,
SemIR::InstId rhs_id,
std::optional<Context::BuildDiagnosticFn> missing_impl_diagnoser)
-> SemIR::InstId {
// Look up the operator function.
auto op_fn = GetOperatorOpFunction(context, loc_id, op);
// Form `lhs.(Op)`.
auto bound_op_id = PerformCompoundMemberAccess(context, loc_id, lhs_id, op_fn,
missing_impl_diagnoser);
if (bound_op_id == SemIR::InstId::BuiltinError) {
return SemIR::InstId::BuiltinError;
}
// Form `bound_op(rhs)`.
return PerformCall(context, loc_id, bound_op_id, {rhs_id});
}
} // namespace Carbon::Check