Files
carbon-lang/toolchain/check/operator.cpp
T
Richard Smith 3cb769a053 Rename "generic instance" to "specific" throughout the toolchain. (#4165)
As discussed in toolchain meeting, we want to avoid overloading the
meaning of "instance", and "specific" was the best name we found. It's a
little unorthodox and inventive, but hopefully over time will become as
unsurprising as the term "generic" is.
2024-07-25 16:42:01 +00:00

108 lines
3.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/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 name scope of the operator interface for the specified operator
// from the Core package.
static auto GetOperatorInterface(Context& context, Parse::AnyExprId node_id,
Operator op) -> SemIR::NameScopeId {
auto interface_id = context.LookupNameInCore(node_id, op.interface_name);
if (interface_id == SemIR::InstId::BuiltinError) {
return SemIR::NameScopeId::Invalid;
}
// We expect it to be an interface.
if (auto interface_inst =
context.insts().TryGetAs<SemIR::InterfaceType>(interface_id)) {
return context.interfaces().Get(interface_inst->interface_id).scope_id;
}
return SemIR::NameScopeId::Invalid;
}
// Returns the `Op` function for the specified operator.
static auto GetOperatorOpFunction(Context& context, Parse::AnyExprId node_id,
Operator op) -> SemIR::InstId {
auto interface_scope_id = GetOperatorInterface(context, node_id, op);
if (!interface_scope_id.is_valid()) {
return SemIR::InstId::Invalid;
}
// TODO: For a parameterized interface, find the corresponding specific.
LookupScope scope = {.name_scope_id = interface_scope_id,
.specific_id = SemIR::SpecificId::Invalid};
// Lookup `Interface.Op`.
auto op_ident_id = context.identifiers().Add(op.op_name);
auto op_result = context.LookupQualifiedName(
node_id, SemIR::NameId::ForIdentifier(op_ident_id), scope,
/*required=*/false);
if (!op_result.inst_id.is_valid()) {
return SemIR::InstId::Invalid;
}
// Look through import_refs and aliases.
auto op_const_id = GetConstantValueInSpecific(
context.sem_ir(), op_result.specific_id, op_result.inst_id);
auto op_id = context.constant_values().GetInstId(op_const_id);
// We expect it to be an associated function.
if (context.insts().Is<SemIR::AssociatedEntity>(op_id)) {
return op_id;
}
return SemIR::InstId::Invalid;
}
auto BuildUnaryOperator(Context& context, Parse::AnyExprId node_id, Operator op,
SemIR::InstId operand_id) -> SemIR::InstId {
auto op_fn = GetOperatorOpFunction(context, node_id, op);
if (!op_fn.is_valid()) {
context.TODO(node_id,
"missing or invalid operator interface, also avoid duplicate "
"diagnostic if prelude is unavailable");
return SemIR::InstId::BuiltinError;
}
// Form `operand.(Op)`.
auto bound_op_id =
PerformCompoundMemberAccess(context, node_id, operand_id, op_fn);
if (bound_op_id == SemIR::InstId::BuiltinError) {
return SemIR::InstId::BuiltinError;
}
// Form `bound_op()`.
return PerformCall(context, node_id, bound_op_id, {});
}
auto BuildBinaryOperator(Context& context, Parse::AnyExprId node_id,
Operator op, SemIR::InstId lhs_id,
SemIR::InstId rhs_id) -> SemIR::InstId {
auto op_fn = GetOperatorOpFunction(context, node_id, op);
if (!op_fn.is_valid()) {
context.TODO(node_id, "missing or invalid operator interface");
return SemIR::InstId::BuiltinError;
}
// Form `lhs.(Op)`.
auto bound_op_id =
PerformCompoundMemberAccess(context, node_id, lhs_id, op_fn);
if (bound_op_id == SemIR::InstId::BuiltinError) {
return SemIR::InstId::BuiltinError;
}
// Form `bound_op(rhs)`.
return PerformCall(context, node_id, bound_op_id, {rhs_id});
}
} // namespace Carbon::Check