mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
teaches arithmetic interfaces about C++ operators (#7123)
This commit is contained in:
@@ -6,8 +6,10 @@
|
||||
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "toolchain/base/kind_switch.h"
|
||||
#include "toolchain/check/core_identifier.h"
|
||||
#include "toolchain/check/cpp/import.h"
|
||||
#include "toolchain/check/cpp/location.h"
|
||||
#include "toolchain/check/cpp/operators.h"
|
||||
#include "toolchain/check/cpp/overload_resolution.h"
|
||||
#include "toolchain/check/custom_witness.h"
|
||||
#include "toolchain/check/impl.h"
|
||||
@@ -231,6 +233,74 @@ static auto BuildDestroyWitness(
|
||||
query_specific_interface_id, {fn_id});
|
||||
}
|
||||
|
||||
// Attempts to build a witness table entry for a C++ unary operator.
|
||||
static auto BuildCppUnaryOperatorWitness(
|
||||
Context& context, SemIR::LocId loc_id, SemIR::CoreInterface core_interface,
|
||||
bool has_associated_result_type, SemIR::ConstantId query_self_const_id,
|
||||
SemIR::SpecificInterfaceId query_specific_interface_id) -> SemIR::InstId {
|
||||
auto self_type_id =
|
||||
context.types().GetTypeIdForTypeConstantId(query_self_const_id);
|
||||
auto fn_id = LookupCppOperator(
|
||||
context, loc_id, {.interface_name = AsCoreIdentifier(core_interface)},
|
||||
{self_type_id});
|
||||
if (fn_id == SemIR::ErrorInst::InstId || fn_id == SemIR::InstId::None) {
|
||||
return fn_id;
|
||||
}
|
||||
|
||||
if (has_associated_result_type) {
|
||||
auto result_type_id =
|
||||
context.functions()
|
||||
.Get(context.insts().GetAs<SemIR::FunctionDecl>(fn_id).function_id)
|
||||
.return_type_inst_id;
|
||||
if (result_type_id == SemIR::ErrorInst::InstId) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
return BuildCustomWitness(context, loc_id, query_self_const_id,
|
||||
query_specific_interface_id,
|
||||
{result_type_id, fn_id});
|
||||
}
|
||||
return BuildCustomWitness(context, loc_id, query_self_const_id,
|
||||
query_specific_interface_id, {fn_id});
|
||||
}
|
||||
|
||||
// Attempts to build a witness table entry for a C++ binary operator.
|
||||
static auto BuildCppBinaryOperatorWitness(
|
||||
Context& context, SemIR::LocId loc_id, SemIR::CoreInterface core_interface,
|
||||
bool has_associated_result_type, SemIR::ConstantId query_self_const_id,
|
||||
SemIR::SpecificInterfaceId query_specific_interface_id) -> SemIR::InstId {
|
||||
auto self_type_id =
|
||||
context.types().GetTypeIdForTypeConstantId(query_self_const_id);
|
||||
auto args =
|
||||
context.inst_blocks().Get(context.specifics()
|
||||
.Get(context.specific_interfaces()
|
||||
.Get(query_specific_interface_id)
|
||||
.specific_id)
|
||||
.args_id);
|
||||
CARBON_CHECK(args.size() == 1, "Binary operator missing an argument");
|
||||
auto arg_type_id = context.types().GetTypeIdForTypeInstId(args.front());
|
||||
auto fn_id = LookupCppOperator(
|
||||
context, loc_id, {.interface_name = AsCoreIdentifier(core_interface)},
|
||||
{self_type_id, arg_type_id});
|
||||
if (fn_id == SemIR::ErrorInst::InstId || fn_id == SemIR::InstId::None) {
|
||||
return fn_id;
|
||||
}
|
||||
if (has_associated_result_type) {
|
||||
auto result_type_id =
|
||||
context.functions()
|
||||
.Get(context.insts().GetAs<SemIR::FunctionDecl>(fn_id).function_id)
|
||||
.return_type_inst_id;
|
||||
if (result_type_id == SemIR::ErrorInst::InstId) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
return BuildCustomWitness(context, loc_id, query_self_const_id,
|
||||
query_specific_interface_id,
|
||||
{result_type_id, fn_id});
|
||||
}
|
||||
return BuildCustomWitness(context, loc_id, query_self_const_id,
|
||||
query_specific_interface_id, {fn_id});
|
||||
}
|
||||
|
||||
auto LookupCppImpl(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::CoreInterface core_interface,
|
||||
SemIR::ConstantId query_self_const_id,
|
||||
@@ -243,6 +313,34 @@ auto LookupCppImpl(Context& context, SemIR::LocId loc_id,
|
||||
static_cast<void>(best_impl_loc_id);
|
||||
|
||||
switch (core_interface) {
|
||||
case SemIR::CoreInterface::Inc:
|
||||
case SemIR::CoreInterface::Dec:
|
||||
return BuildCppUnaryOperatorWitness(context, loc_id, core_interface,
|
||||
/*has_associated_result_type=*/false,
|
||||
query_self_const_id,
|
||||
query_specific_interface_id);
|
||||
case SemIR::CoreInterface::Negate:
|
||||
return BuildCppUnaryOperatorWitness(
|
||||
context, loc_id, core_interface, /*has_associated_result_type=*/true,
|
||||
query_self_const_id, query_specific_interface_id);
|
||||
case SemIR::CoreInterface::AddWith:
|
||||
case SemIR::CoreInterface::SubWith:
|
||||
case SemIR::CoreInterface::MulWith:
|
||||
case SemIR::CoreInterface::DivWith:
|
||||
case SemIR::CoreInterface::ModWith:
|
||||
return BuildCppBinaryOperatorWitness(context, loc_id, core_interface,
|
||||
/*has_associated_result_type=*/true,
|
||||
query_self_const_id,
|
||||
query_specific_interface_id);
|
||||
case SemIR::CoreInterface::AddAssignWith:
|
||||
case SemIR::CoreInterface::SubAssignWith:
|
||||
case SemIR::CoreInterface::MulAssignWith:
|
||||
case SemIR::CoreInterface::DivAssignWith:
|
||||
case SemIR::CoreInterface::ModAssignWith:
|
||||
return BuildCppBinaryOperatorWitness(context, loc_id, core_interface,
|
||||
/*has_associated_result_type=*/false,
|
||||
query_self_const_id,
|
||||
query_specific_interface_id);
|
||||
case SemIR::CoreInterface::Copy:
|
||||
return BuildCopyWitness(context, loc_id, query_self_const_id,
|
||||
query_specific_interface_id);
|
||||
|
||||
@@ -453,6 +453,90 @@ static auto LookupCppConversion(Context& context, SemIR::LocId loc_id,
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
|
||||
static auto FindClangOperator(Context& context, SemIR::LocId loc_id,
|
||||
clang::OverloadedOperatorKind op_kind,
|
||||
llvm::ArrayRef<clang::Expr*> arg_exprs)
|
||||
-> SemIR::InstId;
|
||||
|
||||
namespace {
|
||||
struct DiagnoseIncompleteOperandTypeInCppOperatorLookup {
|
||||
Context& context;
|
||||
SemIR::TypeId arg_type_id;
|
||||
SemIR::LocId loc_id;
|
||||
|
||||
void operator()(auto& builder) const {
|
||||
CARBON_DIAGNOSTIC(
|
||||
IncompleteOperandTypeInCppOperatorLookup, Context,
|
||||
"looking up a C++ operator with incomplete operand type {0}",
|
||||
SemIR::TypeId);
|
||||
builder.Context(loc_id, IncompleteOperandTypeInCppOperatorLookup,
|
||||
arg_type_id);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
llvm::ArrayRef<SemIR::TypeId> arg_type_ids)
|
||||
-> SemIR::InstId {
|
||||
// Register an annotation scope to flush any Clang diagnostics when we return.
|
||||
// This is important to ensure that Clang diagnostics are properly interleaved
|
||||
// with Carbon diagnostics.
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(&context.emitter(),
|
||||
[](auto& /*builder*/) {});
|
||||
|
||||
if (op.interface_name == CoreIdentifier::ImplicitAs ||
|
||||
op.interface_name == CoreIdentifier::As) {
|
||||
context.TODO(loc_id, "handle `as` operator when passed a type");
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
auto op_kind =
|
||||
GetClangOperatorKind(context, loc_id, op.interface_name, op.op_name);
|
||||
if (!op_kind) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
for (SemIR::TypeId arg_type_id : arg_type_ids) {
|
||||
if (!RequireCompleteType(context, arg_type_id, loc_id,
|
||||
DiagnoseIncompleteOperandTypeInCppOperatorLookup{
|
||||
.context = context,
|
||||
.arg_type_id = arg_type_id,
|
||||
.loc_id = loc_id})) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
}
|
||||
|
||||
struct Operand {
|
||||
using enum clang::ExprValueKind;
|
||||
explicit Operand(clang::QualType type)
|
||||
: type(type),
|
||||
expression({}, type,
|
||||
type->isLValueReferenceType() ? VK_LValue
|
||||
: type->isRValueReferenceType() ? VK_XValue
|
||||
: VK_PRValue) {}
|
||||
clang::QualType type;
|
||||
clang::OpaqueValueExpr expression;
|
||||
};
|
||||
|
||||
auto cpp_type = MapToCppType(context, arg_type_ids[0]);
|
||||
if (cpp_type.isNull()) {
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
auto arg0 = Operand(cpp_type);
|
||||
if (arg_type_ids.size() == 1) {
|
||||
return FindClangOperator(context, loc_id, *op_kind, {&arg0.expression});
|
||||
}
|
||||
|
||||
CARBON_CHECK(arg_type_ids.size() == 2);
|
||||
cpp_type = MapToCppType(context, arg_type_ids[1]);
|
||||
if (cpp_type.isNull()) {
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
auto arg1 = Operand(cpp_type);
|
||||
return FindClangOperator(context, loc_id, *op_kind,
|
||||
{&arg0.expression, &arg1.expression});
|
||||
}
|
||||
|
||||
auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId {
|
||||
// Register an annotation scope to flush any Clang diagnostics when we return.
|
||||
@@ -461,6 +545,14 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(&context.emitter(),
|
||||
[](auto& /*builder*/) {});
|
||||
|
||||
// We can only handle concrete types in LookupCppOperator.
|
||||
for (auto arg_id : arg_ids) {
|
||||
auto type_id = context.insts().Get(arg_id).type_id();
|
||||
if (type_id.is_symbolic()) {
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle `ImplicitAs` and `As`.
|
||||
if (op.interface_name == CoreIdentifier::ImplicitAs ||
|
||||
op.interface_name == CoreIdentifier::As) {
|
||||
@@ -490,14 +582,11 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
// Make sure all operands are complete before lookup.
|
||||
for (SemIR::InstId arg_id : arg_ids) {
|
||||
SemIR::TypeId arg_type_id = context.insts().Get(arg_id).type_id();
|
||||
if (!RequireCompleteType(context, arg_type_id, loc_id, [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
IncompleteOperandTypeInCppOperatorLookup, Context,
|
||||
"looking up a C++ operator with incomplete operand type {0}",
|
||||
SemIR::TypeId);
|
||||
builder.Context(loc_id, IncompleteOperandTypeInCppOperatorLookup,
|
||||
arg_type_id);
|
||||
})) {
|
||||
if (!RequireCompleteType(context, arg_type_id, loc_id,
|
||||
DiagnoseIncompleteOperandTypeInCppOperatorLookup{
|
||||
.context = context,
|
||||
.arg_type_id = arg_type_id,
|
||||
.loc_id = loc_id})) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
}
|
||||
@@ -506,18 +595,24 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
if (!maybe_arg_exprs.has_value()) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
auto& arg_exprs = *maybe_arg_exprs;
|
||||
|
||||
return FindClangOperator(context, loc_id, *op_kind, *maybe_arg_exprs);
|
||||
}
|
||||
|
||||
static auto FindClangOperator(Context& context, SemIR::LocId loc_id,
|
||||
clang::OverloadedOperatorKind op_kind,
|
||||
llvm::ArrayRef<clang::Expr*> arg_exprs)
|
||||
-> SemIR::InstId {
|
||||
clang::SourceLocation loc = GetCppLocation(context, loc_id);
|
||||
clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info(
|
||||
*op_kind, loc, /*AllowRewritten=*/true);
|
||||
op_kind, loc, /*AllowRewritten=*/true);
|
||||
clang::OverloadCandidateSet candidate_set(
|
||||
loc, clang::OverloadCandidateSet::CSK_Operator, operator_rewrite_info);
|
||||
|
||||
clang::Sema& sema = context.clang_sema();
|
||||
|
||||
// This works for both unary and binary operators.
|
||||
sema.LookupOverloadedBinOp(candidate_set, *op_kind, clang::UnresolvedSet<0>{},
|
||||
sema.LookupOverloadedBinOp(candidate_set, op_kind, clang::UnresolvedSet<0>{},
|
||||
arg_exprs);
|
||||
|
||||
clang::OverloadCandidateSet::iterator best_viable_fn;
|
||||
@@ -540,7 +635,7 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
sema.MarkFunctionReferenced(loc, best_viable_fn->Function);
|
||||
|
||||
// If this is an operator method, the first arg will be used as self.
|
||||
int32_t num_params = arg_ids.size();
|
||||
int32_t num_params = arg_exprs.size();
|
||||
if (isa<clang::CXXMethodDecl>(best_viable_fn->Function)) {
|
||||
--num_params;
|
||||
}
|
||||
@@ -561,7 +656,7 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
case clang::OverloadingResult::OR_Ambiguous: {
|
||||
const char* spelling = clang::getOperatorSpelling(*op_kind);
|
||||
const char* spelling = clang::getOperatorSpelling(op_kind);
|
||||
candidate_set.NoteCandidates(
|
||||
clang::PartialDiagnosticAt(
|
||||
loc, sema.PDiag(clang::diag::err_ovl_ambiguous_oper_binary)
|
||||
@@ -571,7 +666,7 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
case clang::OverloadingResult::OR_Deleted:
|
||||
const char* spelling = clang::getOperatorSpelling(*op_kind);
|
||||
const char* spelling = clang::getOperatorSpelling(op_kind);
|
||||
auto* message = best_viable_fn->Function->getDeletedMessage();
|
||||
// The best viable function might be a different operator if the best
|
||||
// candidate is a rewritten candidate, so use the operator kind of the
|
||||
|
||||
@@ -17,6 +17,16 @@ namespace Carbon::Check {
|
||||
auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId;
|
||||
|
||||
// Looks up the given operator in the Clang AST generated when importing C++
|
||||
// code using argument dependent lookup (ADL) and return overload set
|
||||
// instruction.
|
||||
//
|
||||
// This overload synthesises objects in an unevaluated context within the Clang
|
||||
// AST based on the types it is provided.
|
||||
auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
llvm::ArrayRef<SemIR::TypeId> arg_type_ids)
|
||||
-> SemIR::InstId;
|
||||
|
||||
// Returns whether the decl is an operator member function.
|
||||
auto IsCppOperatorMethodDecl(clang::Decl* decl) -> bool;
|
||||
|
||||
|
||||
@@ -527,6 +527,51 @@ auto BuildCustomWitness(Context& context, SemIR::LocId loc_id,
|
||||
context.inst_blocks().Add(entries));
|
||||
}
|
||||
|
||||
auto AsCoreIdentifier(SemIR::CoreInterface core_interface) -> CoreIdentifier {
|
||||
using SemIR::CoreInterface;
|
||||
switch (core_interface) {
|
||||
case CoreInterface::AddAssignWith:
|
||||
return CoreIdentifier::AddAssignWith;
|
||||
case CoreInterface::AddWith:
|
||||
return CoreIdentifier::AddWith;
|
||||
case CoreInterface::Copy:
|
||||
return CoreIdentifier::Copy;
|
||||
case CoreInterface::CppUnsafeDeref:
|
||||
return CoreIdentifier::CppUnsafeDeref;
|
||||
case CoreInterface::Dec:
|
||||
return CoreIdentifier::Dec;
|
||||
case CoreInterface::Default:
|
||||
return CoreIdentifier::Default;
|
||||
case CoreInterface::Destroy:
|
||||
return CoreIdentifier::Destroy;
|
||||
case CoreInterface::DivAssignWith:
|
||||
return CoreIdentifier::DivAssignWith;
|
||||
case CoreInterface::DivWith:
|
||||
return CoreIdentifier::DivWith;
|
||||
case CoreInterface::Inc:
|
||||
return CoreIdentifier::Inc;
|
||||
case CoreInterface::IntFitsIn:
|
||||
return CoreIdentifier::IntFitsIn;
|
||||
case CoreInterface::ModAssignWith:
|
||||
return CoreIdentifier::ModAssignWith;
|
||||
case CoreInterface::ModWith:
|
||||
return CoreIdentifier::ModWith;
|
||||
case CoreInterface::MulAssignWith:
|
||||
return CoreIdentifier::MulAssignWith;
|
||||
case CoreInterface::MulWith:
|
||||
return CoreIdentifier::MulWith;
|
||||
case CoreInterface::Negate:
|
||||
return CoreIdentifier::Negate;
|
||||
case CoreInterface::SubAssignWith:
|
||||
return CoreIdentifier::SubAssignWith;
|
||||
case CoreInterface::SubWith:
|
||||
return CoreIdentifier::SubWith;
|
||||
case CoreInterface::Unknown:
|
||||
CARBON_FATAL("{0} doesn't have a `CoreIdentifier` mapping",
|
||||
core_interface);
|
||||
}
|
||||
}
|
||||
|
||||
auto GetCoreInterface(Context& context, SemIR::InterfaceId interface_id)
|
||||
-> SemIR::CoreInterface {
|
||||
const auto& interface = context.interfaces().Get(interface_id);
|
||||
@@ -665,9 +710,22 @@ auto LookupCustomWitness(Context& context, SemIR::LocId loc_id,
|
||||
case SemIR::CoreInterface::IntFitsIn:
|
||||
return MakeIntFitsInWitness(context, loc_id, query_self_const_id,
|
||||
query_specific_interface_id, build_witness);
|
||||
case SemIR::CoreInterface::AddAssignWith:
|
||||
case SemIR::CoreInterface::AddWith:
|
||||
case SemIR::CoreInterface::Copy:
|
||||
case SemIR::CoreInterface::CppUnsafeDeref:
|
||||
case SemIR::CoreInterface::Dec:
|
||||
case SemIR::CoreInterface::Default:
|
||||
case SemIR::CoreInterface::DivAssignWith:
|
||||
case SemIR::CoreInterface::DivWith:
|
||||
case SemIR::CoreInterface::Inc:
|
||||
case SemIR::CoreInterface::ModAssignWith:
|
||||
case SemIR::CoreInterface::ModWith:
|
||||
case SemIR::CoreInterface::MulAssignWith:
|
||||
case SemIR::CoreInterface::MulWith:
|
||||
case SemIR::CoreInterface::Negate:
|
||||
case SemIR::CoreInterface::SubAssignWith:
|
||||
case SemIR::CoreInterface::SubWith:
|
||||
case SemIR::CoreInterface::Unknown:
|
||||
// TODO: Handle more interfaces, particularly copy, move, and conversion.
|
||||
return std::nullopt;
|
||||
|
||||
@@ -30,6 +30,9 @@ auto BuildPrimitiveCopyWitness(
|
||||
auto GetCoreInterface(Context& context, SemIR::InterfaceId interface_id)
|
||||
-> SemIR::CoreInterface;
|
||||
|
||||
// Maps a `CoreInterface` to its `CoreIdentifier` equivalent.
|
||||
auto AsCoreIdentifier(SemIR::CoreInterface core_interface) -> CoreIdentifier;
|
||||
|
||||
// Returns a witness for a `CoreInterface` `CustomWitness`. A return value of
|
||||
// `None` indicates a non-final witness should be produced, while `std::nullopt`
|
||||
// indicates the query is final and no witness can be produced.
|
||||
|
||||
@@ -250,6 +250,10 @@ auto CheckFunctionReturnTypeMatches(Context& context,
|
||||
}
|
||||
if (!context.types().AreEqualAcrossDeclarations(new_return_type_id,
|
||||
prev_return_type_id)) {
|
||||
if (new_function.name_id == SemIR::NameId::CppOperator &&
|
||||
!prev_return_type_id.has_value()) {
|
||||
return true;
|
||||
}
|
||||
if (!diagnose) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "toolchain/check/name_component.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/sem_ir/core_interface.h"
|
||||
#include "toolchain/sem_ir/entity_with_params_base.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/interface.h"
|
||||
@@ -92,11 +93,24 @@ static auto BuildInterfaceDecl(Context& context,
|
||||
auto name = context.names().GetIRBaseName(interface_info.name_id);
|
||||
interface_info.core_interface =
|
||||
llvm::StringSwitch<SemIR::CoreInterface>(name)
|
||||
.Case("AddAssignWith", SemIR::CoreInterface::AddAssignWith)
|
||||
.Case("AddWith", SemIR::CoreInterface::AddWith)
|
||||
.Case("Copy", SemIR::CoreInterface::Copy)
|
||||
.Case("CppUnsafeDeref", SemIR::CoreInterface::CppUnsafeDeref)
|
||||
.Case("Dec", SemIR::CoreInterface::Dec)
|
||||
.Case("Default", SemIR::CoreInterface::Default)
|
||||
.Case("Destroy", SemIR::CoreInterface::Destroy)
|
||||
.Case("DivAssignWith", SemIR::CoreInterface::DivAssignWith)
|
||||
.Case("DivWith", SemIR::CoreInterface::DivWith)
|
||||
.Case("Inc", SemIR::CoreInterface::Inc)
|
||||
.Case("IntFitsIn", SemIR::CoreInterface::IntFitsIn)
|
||||
.Case("ModAssignWith", SemIR::CoreInterface::ModAssignWith)
|
||||
.Case("ModWith", SemIR::CoreInterface::ModWith)
|
||||
.Case("MulAssignWith", SemIR::CoreInterface::MulAssignWith)
|
||||
.Case("MulWith", SemIR::CoreInterface::MulWith)
|
||||
.Case("Negate", SemIR::CoreInterface::Negate)
|
||||
.Case("SubAssignWith", SemIR::CoreInterface::SubAssignWith)
|
||||
.Case("SubWith", SemIR::CoreInterface::SubWith)
|
||||
.Default(SemIR::CoreInterface::Unknown);
|
||||
}
|
||||
interface_decl.interface_id = context.interfaces().Add(interface_info);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -822,35 +822,6 @@ fn F() {
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Satisfying constraints
|
||||
// ============================================================================
|
||||
|
||||
// --- fail_todo_constraints.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp inline '''
|
||||
class X {};
|
||||
X operator+(X, X);
|
||||
''';
|
||||
|
||||
// TODO: Use Core.Add() when it is available.
|
||||
// TODO: `Sum()` should be declared this way when generics implementation is ready for that:
|
||||
// fn Sum[T:! Core.AddWith(.Self) where .Result = .Self](a: T, b: T) -> T
|
||||
fn Sum[U:! type, T:! Core.AddWith(U) where .Result = U](a: T, b: U) -> U {
|
||||
return a + b;
|
||||
}
|
||||
fn Call(x: Cpp.X) -> Cpp.X {
|
||||
// CHECK:STDERR: fail_todo_constraints.carbon:[[@LINE+7]]:10: error: cannot convert type `Cpp.X` into type implementing `Core.AddWith(Cpp.X) where .(Core.AddWith(Cpp.X).Result) = Cpp.X` [ConversionFailureTypeToFacet]
|
||||
// CHECK:STDERR: return Sum(x, x);
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_constraints.carbon:[[@LINE-7]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
|
||||
// CHECK:STDERR: fn Sum[U:! type, T:! Core.AddWith(U) where .Result = U](a: T, b: U) -> U {
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
return Sum(x, x);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Operator not found
|
||||
|
||||
@@ -472,7 +472,9 @@ auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
|
||||
// TODO: For virtual functions, we want different rules for checking `self`.
|
||||
// TODO: This is too strict; for example, we should not compare parameter
|
||||
// names here.
|
||||
if (CheckFunctionTypeMatches(
|
||||
if (context.functions().Get(callee.function_id).special_function_kind !=
|
||||
SemIR::Function::SpecialFunctionKind::HasCppThunk &&
|
||||
CheckFunctionTypeMatches(
|
||||
context, context.functions().Get(callee.function_id),
|
||||
context.functions().Get(signature_id), signature_specific_id,
|
||||
/*check_syntax=*/false, /*check_self=*/true, /*diagnose=*/false)) {
|
||||
@@ -489,7 +491,9 @@ auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
|
||||
// thunk, and always convert the result of the wrapped call to the return type
|
||||
// of the thunk.
|
||||
if (!HasDeclaredReturnType(context, signature_id) &&
|
||||
HasDeclaredReturnType(context, callee.function_id)) {
|
||||
HasDeclaredReturnType(context, callee.function_id) &&
|
||||
context.functions().Get(callee.function_id).name_id !=
|
||||
SemIR::NameId::CppOperator) {
|
||||
bool success = CheckFunctionReturnTypeMatches(
|
||||
context, context.functions().Get(callee.function_id),
|
||||
context.functions().Get(signature_id), signature_specific_id);
|
||||
|
||||
@@ -16,11 +16,24 @@
|
||||
#define CARBON_SEM_IR_CORE_INTERFACE_KIND(Name)
|
||||
#endif
|
||||
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(AddAssignWith)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(AddWith)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(Copy)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(CppUnsafeDeref)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(Dec)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(Default)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(Destroy)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(DivAssignWith)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(DivWith)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(Inc)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(IntFitsIn)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(ModAssignWith)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(ModWith)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(MulAssignWith)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(MulWith)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(Negate)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(SubAssignWith)
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(SubWith)
|
||||
|
||||
CARBON_SEM_IR_CORE_INTERFACE_KIND(Unknown)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user