From cf361a83f31ba94420c5f56aa339f3a4de5f9c3c Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 19 Mar 2024 12:47:29 -0700 Subject: [PATCH] Overloaded operator support. (#3796) Support is added for all overloaded operator interfaces in the current design apart from `Assign`, which is going to require some more work to properly handle, given that primitive assignment currently has a special implementation for quite a few builtin types. As we don't have support for generics yet -- in particular, generic interfaces -- there is no support for `*With` interfaces, but homogenous interfaces such as `Add` are supported instead. Factor out building of call expressions so that overloaded operators can generate calls. Switch a few places from using specific kinds of NodeId to a general NodeId. Because overloaded operators and other things like implicit conversions can result in member access and function calls, those operations can't require a specific kind of NodeId. Add import support for associated entities, and fix import support for interfaces and symbolic bindings. We now import interfaces in two steps, first importing a forward declaration then a definition, just like we do for classes. For symbolic bindings, we ensure that each BindSymbolicName is imported only once, because its ID is used as its symbolic identity. This is necessary because we (only) support operator interfaces that are defined in an imported Carbon package for now. The entire contents of `check/operator.cpp` should probably be rethought. In particular, doing a lot of name lookups on each operator is likely to be bad for performance. But this gets us to the point where overloaded operators are basically working, which seems like a good place to iterate from. For now, the tests that the individual operators map to the right interfaces are mostly generated by a script, but that's just because I'm expecting a fair bit of churn in how we define the prelude and the `impl`s -- in particular, when we add support for `AddWith`, we'll need to update all the tests. The plan is to remove the script once things settle down. --------- Co-authored-by: Jon Ross-Perkins Co-authored-by: Carbon Infra Bot --- .pre-commit-config.yaml | 2 +- toolchain/check/BUILD | 35 +- toolchain/check/call.cpp | 77 +++ toolchain/check/call.h | 20 + toolchain/check/eval.cpp | 2 +- toolchain/check/handle_call_expr.cpp | 72 +-- toolchain/check/handle_operator.cpp | 99 ++-- toolchain/check/impl.cpp | 6 +- toolchain/check/import_ref.cpp | 260 ++++++--- toolchain/check/member_access.cpp | 24 +- toolchain/check/member_access.h | 5 +- toolchain/check/operator.cpp | 148 +++++ toolchain/check/operator.h | 32 ++ toolchain/check/pointer_dereference.cpp | 5 + .../testdata/array/fail_bound_overflow.carbon | 11 +- .../index/fail_negative_indexing.carbon | 34 +- .../interface/fail_todo_import.carbon | 256 --------- .../check/testdata/interface/import.carbon | 64 ++- .../testdata/let/fail_generic_import.carbon | 4 +- .../check/testdata/let/generic_import.carbon | 6 +- toolchain/check/testdata/let/import.carbon | 4 +- .../operators/{ => builtin}/and.carbon | 0 .../operators/{ => builtin}/assignment.carbon | 0 .../fail_and_or_not_in_function.carbon | 0 .../fail_assignment_to_error.carbon | 0 .../fail_assignment_to_non_assignable.carbon | 0 .../fail_redundant_compound_access.carbon | 0 .../{ => builtin}/fail_type_mismatch.carbon | 0 .../fail_type_mismatch_assignment.carbon | 0 .../builtin/fail_type_mismatch_once.carbon | 42 ++ .../fail_unimplemented_op.carbon | 14 +- .../operators/{ => builtin}/or.carbon | 0 .../operators/{ => builtin}/unary_op.carbon | 0 .../operators/fail_type_mismatch_once.carbon | 28 - .../testdata/operators/overloaded/add.carbon | 290 ++++++++++ .../overloaded/binary_op.carbon.tmpl | 43 ++ .../operators/overloaded/bit_and.carbon | 290 ++++++++++ .../overloaded/bit_complement.carbon | 163 ++++++ .../operators/overloaded/bit_or.carbon | 290 ++++++++++ .../operators/overloaded/bit_xor.carbon | 290 ++++++++++ .../testdata/operators/overloaded/dec.carbon | 158 ++++++ .../testdata/operators/overloaded/div.carbon | 290 ++++++++++ .../testdata/operators/overloaded/eq.carbon | 494 +++++++++++++++++ .../overloaded/fail_assign_non_ref.carbon | 270 +++++++++ .../operators/overloaded/fail_no_impl.carbon | 328 +++++++++++ .../overloaded/fail_no_impl_for_arg.carbon | 301 ++++++++++ .../testdata/operators/overloaded/inc.carbon | 158 ++++++ .../operators/overloaded/left_shift.carbon | 290 ++++++++++ .../operators/overloaded/make_tests.sh | 43 ++ .../testdata/operators/overloaded/mod.carbon | 290 ++++++++++ .../testdata/operators/overloaded/mul.carbon | 290 ++++++++++ .../operators/overloaded/negate.carbon | 163 ++++++ .../operators/overloaded/ordered.carbon | 521 ++++++++++++++++++ .../operators/overloaded/right_shift.carbon | 290 ++++++++++ .../testdata/operators/overloaded/sub.carbon | 290 ++++++++++ .../operators/overloaded/unary_op.carbon.tmpl | 33 ++ .../overloaded/unary_stmt.carbon.tmpl | 32 ++ toolchain/parse/node_ids.h | 3 - toolchain/sem_ir/typed_insts.h | 9 +- 59 files changed, 6358 insertions(+), 511 deletions(-) create mode 100644 toolchain/check/call.cpp create mode 100644 toolchain/check/call.h create mode 100644 toolchain/check/operator.cpp create mode 100644 toolchain/check/operator.h delete mode 100644 toolchain/check/testdata/interface/fail_todo_import.carbon rename toolchain/check/testdata/operators/{ => builtin}/and.carbon (100%) rename toolchain/check/testdata/operators/{ => builtin}/assignment.carbon (100%) rename toolchain/check/testdata/operators/{ => builtin}/fail_and_or_not_in_function.carbon (100%) rename toolchain/check/testdata/operators/{ => builtin}/fail_assignment_to_error.carbon (100%) rename toolchain/check/testdata/operators/{ => builtin}/fail_assignment_to_non_assignable.carbon (100%) rename toolchain/check/testdata/operators/{ => builtin}/fail_redundant_compound_access.carbon (100%) rename toolchain/check/testdata/operators/{ => builtin}/fail_type_mismatch.carbon (100%) rename toolchain/check/testdata/operators/{ => builtin}/fail_type_mismatch_assignment.carbon (100%) create mode 100644 toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon rename toolchain/check/testdata/operators/{ => builtin}/fail_unimplemented_op.carbon (56%) rename toolchain/check/testdata/operators/{ => builtin}/or.carbon (100%) rename toolchain/check/testdata/operators/{ => builtin}/unary_op.carbon (100%) delete mode 100644 toolchain/check/testdata/operators/fail_type_mismatch_once.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/add.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/binary_op.carbon.tmpl create mode 100644 toolchain/check/testdata/operators/overloaded/bit_and.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/bit_complement.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/bit_or.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/bit_xor.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/dec.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/div.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/eq.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/inc.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/left_shift.carbon create mode 100755 toolchain/check/testdata/operators/overloaded/make_tests.sh create mode 100644 toolchain/check/testdata/operators/overloaded/mod.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/mul.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/negate.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/ordered.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/right_shift.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/sub.carbon create mode 100644 toolchain/check/testdata/operators/overloaded/unary_op.carbon.tmpl create mode 100644 toolchain/check/testdata/operators/overloaded/unary_stmt.carbon.tmpl diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aa3889f47484..18ec45ee0de4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -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)?$' - '' - '// ' - '' diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index 776f03076431..262d4277522e 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -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", @@ -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", @@ -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", @@ -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"], @@ -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"], diff --git a/toolchain/check/call.cpp b/toolchain/check/call.cpp new file mode 100644 index 000000000000..47f7e6a9bc75 --- /dev/null +++ b/toolchain/check/call.cpp @@ -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 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()) { + 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(); + 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 diff --git a/toolchain/check/call.h b/toolchain/check/call.h new file mode 100644 index 000000000000..ad0a2ea279bc --- /dev/null +++ b/toolchain/check/call.h @@ -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 arg_ids) + -> SemIR::InstId; + +} // namespace Carbon::Check + +#endif // CARBON_TOOLCHAIN_CHECK_CALL_H_ diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 7b1e9366303a..39036f6d3a4f 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -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); diff --git a/toolchain/check/handle_call_expr.cpp b/toolchain/check/handle_call_expr.cpp index 32aa8212fd8b..913a06522e53 100644 --- a/toolchain/check/handle_call_expr.cpp +++ b/toolchain/check/handle_call_expr.cpp @@ -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 { @@ -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(); - 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; - }; + auto call_id = PerformCall( + context, call_expr_node_id, callee_id, + context.param_and_arg_refs_stack().PeekCurrentBlockContents()); - // 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()) { - 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(); - 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}}); - - 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; } diff --git a/toolchain/check/handle_operator.cpp b/toolchain/check/handle_operator.cpp index 41435943243c..78b4aa10e3ee 100644 --- a/toolchain/check/handle_operator.cpp +++ b/toolchain/check/handle_operator.cpp @@ -4,20 +4,48 @@ #include "toolchain/check/context.h" #include "toolchain/check/convert.h" +#include "toolchain/check/operator.h" #include "toolchain/check/pointer_dereference.h" #include "toolchain/diagnostics/diagnostic_emitter.h" namespace Carbon::Check { +// Common logic for unary operator handlers. +static auto HandleUnaryOperator(Context& context, Parse::NodeId node_id, + Operator op) -> bool { + // TODO: Support implicit conversion from specific node IDs to node ID + // categories and change this function to take an `AnyExprId` directly. + auto expr_node_id = static_cast(node_id); + auto operand_id = context.node_stack().PopExpr(); + auto result_id = BuildUnaryOperator(context, expr_node_id, op, operand_id); + context.node_stack().Push(expr_node_id, result_id); + return true; +} + +// Common logic for binary operator handlers. +static auto HandleBinaryOperator(Context& context, Parse::NodeId node_id, + Operator op) -> bool { + // TODO: Support implicit conversion from specific node IDs to node ID + // categories and change this function to take an `AnyExprId` directly. + auto expr_node_id = static_cast(node_id); + auto rhs_id = context.node_stack().PopExpr(); + auto lhs_id = context.node_stack().PopExpr(); + auto result_id = + BuildBinaryOperator(context, expr_node_id, op, lhs_id, rhs_id); + context.node_stack().Push(expr_node_id, result_id); + return true; +} + auto HandleInfixOperatorAmp(Context& context, Parse::InfixOperatorAmpId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorAmp"); + // TODO: Facet type intersection may need to be handled directly. + return HandleBinaryOperator(context, node_id, {"BitAnd"}); } auto HandleInfixOperatorAmpEqual(Context& context, Parse::InfixOperatorAmpEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorAmpEqual"); + return HandleBinaryOperator(context, node_id, {"BitAndAssign"}); } auto HandleInfixOperatorAs(Context& context, Parse::InfixOperatorAsId node_id) @@ -33,21 +61,24 @@ auto HandleInfixOperatorAs(Context& context, Parse::InfixOperatorAsId node_id) auto HandleInfixOperatorCaret(Context& context, Parse::InfixOperatorCaretId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorCaret"); + return HandleBinaryOperator(context, node_id, {"BitXor"}); } auto HandleInfixOperatorCaretEqual(Context& context, Parse::InfixOperatorCaretEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorCaretEqual"); + return HandleBinaryOperator(context, node_id, {"BitXorAssign"}); } auto HandleInfixOperatorEqual(Context& context, Parse::InfixOperatorEqualId node_id) -> bool { + // TODO: Switch to using assignment interface for most assignment. Some cases + // may need to be handled directly. + // + // return HandleBinaryOperator(context, node_id, {"Assign"}); + auto [rhs_node, rhs_id] = context.node_stack().PopExprWithNodeId(); auto [lhs_node, lhs_id] = context.node_stack().PopExprWithNodeId(); - - // TODO: handle complex assignment expression such as `a += 1`. if (auto lhs_cat = SemIR::GetExprCategory(context.sem_ir(), lhs_id); lhs_cat != SemIR::ExprCategory::DurableRef && lhs_cat != SemIR::ExprCategory::Error) { @@ -70,128 +101,130 @@ auto HandleInfixOperatorEqual(Context& context, auto HandleInfixOperatorEqualEqual(Context& context, Parse::InfixOperatorEqualEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorEqualEqual"); + return HandleBinaryOperator(context, node_id, {"Eq", "Equal"}); } auto HandleInfixOperatorExclaimEqual(Context& context, Parse::InfixOperatorExclaimEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorExclaimEqual"); + return HandleBinaryOperator(context, node_id, {"Eq", "NotEqual"}); } auto HandleInfixOperatorGreater(Context& context, Parse::InfixOperatorGreaterId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorGreater"); + return HandleBinaryOperator(context, node_id, {"Ordered", "Greater"}); } auto HandleInfixOperatorGreaterEqual(Context& context, Parse::InfixOperatorGreaterEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorGreaterEqual"); + return HandleBinaryOperator(context, node_id, + {"Ordered", "GreaterOrEquivalent"}); } auto HandleInfixOperatorGreaterGreater( Context& context, Parse::InfixOperatorGreaterGreaterId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorGreaterGreater"); + return HandleBinaryOperator(context, node_id, {"RightShift"}); } auto HandleInfixOperatorGreaterGreaterEqual( Context& context, Parse::InfixOperatorGreaterGreaterEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorGreaterGreaterEqual"); + return HandleBinaryOperator(context, node_id, {"RightShiftAssign"}); } auto HandleInfixOperatorLess(Context& context, Parse::InfixOperatorLessId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorLess"); + return HandleBinaryOperator(context, node_id, {"Ordered", "Less"}); } auto HandleInfixOperatorLessEqual(Context& context, Parse::InfixOperatorLessEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorLessEqual"); + return HandleBinaryOperator(context, node_id, + {"Ordered", "LessOrEquivalent"}); } auto HandleInfixOperatorLessEqualGreater( Context& context, Parse::InfixOperatorLessEqualGreaterId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorLessEqualGreater"); + return context.TODO(node_id, "remove <=> operator that is not in the design"); } auto HandleInfixOperatorLessLess(Context& context, Parse::InfixOperatorLessLessId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorLessLess"); + return HandleBinaryOperator(context, node_id, {"LeftShift"}); } auto HandleInfixOperatorLessLessEqual( Context& context, Parse::InfixOperatorLessLessEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorLessLessEqual"); + return HandleBinaryOperator(context, node_id, {"LeftShiftAssign"}); } auto HandleInfixOperatorMinus(Context& context, Parse::InfixOperatorMinusId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorMinus"); + return HandleBinaryOperator(context, node_id, {"Sub"}); } auto HandleInfixOperatorMinusEqual(Context& context, Parse::InfixOperatorMinusEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorMinusEqual"); + return HandleBinaryOperator(context, node_id, {"SubAssign"}); } auto HandleInfixOperatorPercent(Context& context, Parse::InfixOperatorPercentId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorPercent"); + return HandleBinaryOperator(context, node_id, {"Mod"}); } auto HandleInfixOperatorPercentEqual(Context& context, Parse::InfixOperatorPercentEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorPercentEqual"); + return HandleBinaryOperator(context, node_id, {"ModAssign"}); } auto HandleInfixOperatorPipe(Context& context, Parse::InfixOperatorPipeId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorPipe"); + return HandleBinaryOperator(context, node_id, {"BitOr"}); } auto HandleInfixOperatorPipeEqual(Context& context, Parse::InfixOperatorPipeEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorPipeEqual"); + return HandleBinaryOperator(context, node_id, {"BitOrAssign"}); } auto HandleInfixOperatorPlus(Context& context, Parse::InfixOperatorPlusId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorPlus"); + return HandleBinaryOperator(context, node_id, {"Add"}); } auto HandleInfixOperatorPlusEqual(Context& context, Parse::InfixOperatorPlusEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorPlusEqual"); + return HandleBinaryOperator(context, node_id, {"AddAssign"}); } auto HandleInfixOperatorSlash(Context& context, Parse::InfixOperatorSlashId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorSlash"); + return HandleBinaryOperator(context, node_id, {"Div"}); } auto HandleInfixOperatorSlashEqual(Context& context, Parse::InfixOperatorSlashEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorSlashEqual"); + return HandleBinaryOperator(context, node_id, {"DivAssign"}); } auto HandleInfixOperatorStar(Context& context, Parse::InfixOperatorStarId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorStar"); + return HandleBinaryOperator(context, node_id, {"Mul"}); } auto HandleInfixOperatorStarEqual(Context& context, Parse::InfixOperatorStarEqualId node_id) -> bool { - return context.TODO(node_id, "HandleInfixOperatorStarEqual"); + return HandleBinaryOperator(context, node_id, {"MulAssign"}); } auto HandlePostfixOperatorStar(Context& context, @@ -232,7 +265,7 @@ auto HandlePrefixOperatorAmp(Context& context, auto HandlePrefixOperatorCaret(Context& context, Parse::PrefixOperatorCaretId node_id) -> bool { - return context.TODO(node_id, "HandlePrefixOperatorCaret"); + return HandleUnaryOperator(context, node_id, {"BitComplement"}); } auto HandlePrefixOperatorConst(Context& context, @@ -256,13 +289,13 @@ auto HandlePrefixOperatorConst(Context& context, auto HandlePrefixOperatorMinus(Context& context, Parse::PrefixOperatorMinusId node_id) -> bool { - return context.TODO(node_id, "HandlePrefixOperatorMinus"); + return HandleUnaryOperator(context, node_id, {"Negate"}); } auto HandlePrefixOperatorMinusMinus(Context& context, Parse::PrefixOperatorMinusMinusId node_id) -> bool { - return context.TODO(node_id, "HandlePrefixOperatorMinusMinus"); + return HandleUnaryOperator(context, node_id, {"Dec"}); } auto HandlePrefixOperatorNot(Context& context, @@ -278,7 +311,7 @@ auto HandlePrefixOperatorNot(Context& context, auto HandlePrefixOperatorPlusPlus(Context& context, Parse::PrefixOperatorPlusPlusId node_id) -> bool { - return context.TODO(node_id, "HandlePrefixOperatorPlusPlus"); + return HandleUnaryOperator(context, node_id, {"Inc"}); } auto HandlePrefixOperatorStar(Context& context, diff --git a/toolchain/check/impl.cpp b/toolchain/check/impl.cpp index 94a4e1aa6675..ae3d06caff24 100644 --- a/toolchain/check/impl.cpp +++ b/toolchain/check/impl.cpp @@ -6,6 +6,7 @@ #include "toolchain/check/context.h" #include "toolchain/check/function.h" +#include "toolchain/check/import_ref.h" #include "toolchain/check/subst.h" #include "toolchain/diagnostics/diagnostic_emitter.h" #include "toolchain/sem_ir/ids.h" @@ -86,7 +87,10 @@ static auto BuildInterfaceWitness( .replacement_id = context.types().GetConstantId(impl.self_id)}}; for (auto decl_id : assoc_entities) { - auto decl = context.insts().Get(decl_id); + TryResolveImportRefUnused(context, decl_id); + auto const_id = context.constant_values().Get(decl_id); + CARBON_CHECK(const_id.is_constant()) << "Non-constant associated entity"; + auto decl = context.insts().Get(const_id.inst_id()); if (auto fn_decl = decl.TryAs()) { auto& fn = context.functions().Get(fn_decl->function_id); auto impl_decl_id = diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 798837223c20..767e4a380f35 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -23,17 +23,19 @@ namespace Carbon::Check { // Work items on work_stack_. At a high level, the loop is: // // 1. If Work has received a constant, it's considered resolved. -// - If made_incomplete_type, resolve unconditionally. +// - If made_forward_decl, resolve unconditionally. // - The constant check avoids performance costs of deduplication on add. // 2. Resolve the instruction: (TryResolveInst/TryResolveTypedInst) // - For most cases: -// A. For types which _can_ be incomplete, when not made_incomplete_type: -// i. Start by making an incomplete type to address circular references. -// ii. If the imported type is incomplete, return the constant. -// iii. Otherwise, set made_incomplete_type and continue resolving. -// - Creating an incomplete type will have set the constant, which -// influences step (1); setting made_incomplete_type gets us a second -// resolve pass when needed. +// A. For types which _can_ be forward declared, when not +// made_forward_decl: +// i. Start by making a forward declared type to address circular +// references. +// ii. If the imported type is not defined, return the constant. +// iii. Otherwise, set made_forward_decl and continue resolving. +// - Creating a forward declaration of the type will have set the +// constant, which influences step (1); setting made_forward_decl +// gets us a second resolve pass when needed. // B. Gather all input constants. // - Gathering constants directly adds unresolved values to work_stack_. // C. If any need to be resolved (HasNewWork), return Invalid; this @@ -72,11 +74,11 @@ class ImportRefResolver { // This should typically be checked before adding it, but a given // instruction may be added multiple times before its constant is // evaluated. - if (!work.made_incomplete_type && + if (!work.made_forward_decl && import_ir_constant_values_.Get(work.inst_id).is_valid()) { work_stack_.pop_back(); } else if (auto new_const_id = - TryResolveInst(work.inst_id, work.made_incomplete_type); + TryResolveInst(work.inst_id, work.made_forward_decl); new_const_id.is_valid()) { import_ir_constant_values_.Set(work.inst_id, new_const_id); work_stack_.pop_back(); @@ -110,8 +112,8 @@ class ImportRefResolver { // The instruction to work on. SemIR::InstId inst_id; - // True if a first pass made an incomplete type. - bool made_incomplete_type = false; + // True if a first pass made a forward declaration. + bool made_forward_decl = false; }; // For imported entities, we use an invalid enclosing scope. This will be okay @@ -161,6 +163,15 @@ class ImportRefResolver { for (auto inst_id : param_refs) { const_ids.push_back( GetLocalConstantId(import_ir_.insts().Get(inst_id).type_id())); + + // If the parameter is a symbolic binding, build the BindSymbolicName + // constant. + auto bind_id = inst_id; + if (auto addr = + import_ir_.insts().TryGetAs(bind_id)) { + bind_id = addr->inner_id; + } + GetLocalConstantId(bind_id); } return const_ids; } @@ -182,8 +193,10 @@ class ImportRefResolver { // TODO: Consider a different parameter handling to simplify import logic. auto inst = import_ir_.insts().Get(ref_id); auto addr_inst = inst.TryAs(); + auto bind_id = ref_id; if (addr_inst) { - inst = import_ir_.insts().Get(addr_inst->inner_id); + bind_id = addr_inst->inner_id; + inst = import_ir_.insts().Get(bind_id); } auto bind_inst = inst.TryAs(); if (bind_inst) { @@ -198,23 +211,32 @@ class ImportRefResolver { auto new_param_id = context_.AddInstInNoBlock( {Parse::NodeId::Invalid, SemIR::Param{type_id, name_id}}); if (bind_inst) { - auto bind_name_id = context_.bind_names().Add( - {.name_id = name_id, - .enclosing_scope_id = SemIR::NameScopeId::Invalid}); switch (bind_inst->kind) { - case SemIR::InstKind::BindName: + case SemIR::InstKind::BindName: { + auto bind_name_id = context_.bind_names().Add( + {.name_id = name_id, + .enclosing_scope_id = SemIR::NameScopeId::Invalid}); new_param_id = context_.AddInstInNoBlock( {Parse::NodeId::Invalid, SemIR::BindName{type_id, bind_name_id, new_param_id}}); break; - case SemIR::InstKind::BindSymbolicName: - new_param_id = context_.AddInstInNoBlock( - {Parse::NodeId::Invalid, - SemIR::BindSymbolicName{type_id, bind_name_id, new_param_id}}); + } + case SemIR::InstKind::BindSymbolicName: { + // The symbolic name will be created on first reference, so might + // already exist. Update the value in it to refer to the parameter. + auto new_bind_inst = + context_.insts().GetAs( + GetLocalConstantId(bind_id).inst_id()); + new_bind_inst.value_id = new_param_id; + // This is not before constant use, but doesn't change the + // constant value of the instruction. + context_.ReplaceInstBeforeConstantUse( + bind_id, {Parse::NodeId::Invalid, new_bind_inst}); break; - - default: + } + default: { CARBON_FATAL() << "Unexpected kind: " << bind_inst->kind; + } } } if (addr_inst) { @@ -272,23 +294,30 @@ class ImportRefResolver { // following TryResolveTypedInst helper functions. // // TODO: Error is returned when support is missing, but that should go away. - auto TryResolveInst(SemIR::InstId inst_id, bool made_incomplete_type) + auto TryResolveInst(SemIR::InstId inst_id, bool made_forward_decl) -> SemIR::ConstantId { if (inst_id.is_builtin()) { - CARBON_CHECK(!made_incomplete_type); + CARBON_CHECK(!made_forward_decl); // Constants for builtins can be directly copied. return context_.constant_values().Get(inst_id); } auto inst = import_ir_.insts().Get(inst_id); - CARBON_CHECK(!made_incomplete_type || - inst.kind() == SemIR::InstKind::ClassDecl) - << "Currently only decls with incomplete types should need " - "made_incomplete_type states: " + CARBON_CHECK(!made_forward_decl || + inst.kind() == SemIR::InstKind::ClassDecl || + inst.kind() == SemIR::InstKind::InterfaceDecl) + << "Only types that can be involved in cycles should need " + "made_forward_decl state: " << inst.kind(); switch (inst.kind()) { + case SemIR::InstKind::AssociatedEntity: + return TryResolveTypedInst(inst.As()); + + case SemIR::InstKind::AssociatedEntityType: + return TryResolveTypedInst(inst.As()); + case SemIR::InstKind::BaseDecl: return TryResolveTypedInst(inst.As()); @@ -297,7 +326,7 @@ class ImportRefResolver { case SemIR::InstKind::ClassDecl: return TryResolveTypedInst(inst.As(), inst_id, - made_incomplete_type); + made_forward_decl); case SemIR::InstKind::ClassType: return TryResolveTypedInst(inst.As()); @@ -312,7 +341,8 @@ class ImportRefResolver { return TryResolveTypedInst(inst.As()); case SemIR::InstKind::InterfaceDecl: - return TryResolveTypedInst(inst.As()); + return TryResolveTypedInst(inst.As(), inst_id, + made_forward_decl); case SemIR::InstKind::InterfaceType: return TryResolveTypedInst(inst.As()); @@ -334,12 +364,7 @@ class ImportRefResolver { return TryEvalInst(context_, inst_id, inst); case SemIR::InstKind::BindSymbolicName: - // TODO: This will return a `ConstantId` referring to the `inst_id` from - // the import IR. But we need all references to the same - // `BindSymbolicName` in the imported IR to resolve to the same constant - // value in the local IR, so we can't just create a new local - // `BindSymbolicName` here. - return TryEvalInst(context_, inst_id, inst); + return TryResolveTypedInst(inst.As()); default: context_.TODO( @@ -349,6 +374,46 @@ class ImportRefResolver { } } + auto TryResolveTypedInst(SemIR::AssociatedEntity inst) -> SemIR::ConstantId { + auto initial_work = work_stack_.size(); + auto type_const_id = GetLocalConstantId(inst.type_id); + if (HasNewWork(initial_work)) { + return SemIR::ConstantId::Invalid; + } + + // Add a lazy reference to the target declaration. + auto decl_id = context_.AddPlaceholderInst( + SemIR::ImportRefUnused{import_ir_id_, inst.decl_id}); + + auto inst_id = context_.AddInstInNoBlock( + {Parse::NodeId::Invalid, + SemIR::AssociatedEntity{ + context_.GetTypeIdForTypeConstant(type_const_id), inst.index, + decl_id}}); + return context_.constant_values().Get(inst_id); + } + + auto TryResolveTypedInst(SemIR::AssociatedEntityType inst) + -> SemIR::ConstantId { + CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); + + auto initial_work = work_stack_.size(); + auto entity_type_const_id = GetLocalConstantId(inst.entity_type_id); + auto interface_const_id = GetLocalConstantId( + import_ir_.interfaces().Get(inst.interface_id).decl_id); + if (HasNewWork(initial_work)) { + return SemIR::ConstantId::Invalid; + } + + auto inst_id = context_.AddInstInNoBlock(SemIR::AssociatedEntityType{ + SemIR::TypeId::TypeType, + context_.insts() + .GetAs(interface_const_id.inst_id()) + .interface_id, + context_.GetTypeIdForTypeConstant(entity_type_const_id)}); + return context_.constant_values().Get(inst_id); + } + auto TryResolveTypedInst(SemIR::BaseDecl inst) -> SemIR::ConstantId { auto initial_work = work_stack_.size(); auto type_const_id = GetLocalConstantId(inst.type_id); @@ -375,6 +440,25 @@ class ImportRefResolver { return value_id; } + auto TryResolveTypedInst(SemIR::BindSymbolicName inst) -> SemIR::ConstantId { + auto initial_work = work_stack_.size(); + auto type_id = GetLocalConstantId(inst.type_id); + if (HasNewWork(initial_work)) { + return SemIR::ConstantId::Invalid; + } + + auto name_id = + GetLocalNameId(import_ir_.bind_names().Get(inst.bind_name_id).name_id); + auto bind_name_id = context_.bind_names().Add( + {.name_id = name_id, + .enclosing_scope_id = SemIR::NameScopeId::Invalid}); + auto new_bind_id = context_.AddInstInNoBlock( + {Parse::NodeId::Invalid, + SemIR::BindSymbolicName{context_.GetTypeIdForTypeConstant(type_id), + bind_name_id, SemIR::InstId::Invalid}}); + return context_.constant_values().Get(new_bind_id); + } + // Makes an incomplete class. This is necessary even with classes with a // complete declaration, because things such as `Self` may refer back to the // type. @@ -452,13 +536,13 @@ class ImportRefResolver { } auto TryResolveTypedInst(SemIR::ClassDecl inst, SemIR::InstId inst_id, - bool made_incomplete_type) -> SemIR::ConstantId { + bool made_forward_decl) -> SemIR::ConstantId { const auto& import_class = import_ir_.classes().Get(inst.class_id); SemIR::ConstantId class_const_id = SemIR::ConstantId::Invalid; // On the first pass, there's no incomplete type; start by adding one for // any recursive references. - if (!made_incomplete_type) { + if (!made_forward_decl) { class_const_id = MakeIncompleteClass(inst_id, import_class); // If there's only a forward declaration, we're done. if (!import_class.is_defined()) { @@ -467,7 +551,7 @@ class ImportRefResolver { // This may not be needed because all constants might be ready, but we do // it here so that we don't need to track which work item corresponds to // this instruction. - work_stack_.back().made_incomplete_type = true; + work_stack_.back().made_forward_decl = true; } CARBON_CHECK(import_class.is_defined()) @@ -488,7 +572,7 @@ class ImportRefResolver { // On the first pass, we build the incomplete type's constant above. If we // get here on a subsequent pass we need to fetch the one we built in the // first pass. - if (made_incomplete_type) { + if (made_forward_decl) { CARBON_CHECK(!class_const_id.is_valid()) << "Shouldn't have a const yet when resuming"; class_const_id = import_ir_constant_values_.Get(inst_id); @@ -588,10 +672,11 @@ class ImportRefResolver { return context_.constant_values().Get(function_decl_id); } - auto TryResolveTypedInst(SemIR::InterfaceDecl inst) -> SemIR::ConstantId { - const auto& import_interface = - import_ir_.interfaces().Get(inst.interface_id); - + // Make a declaration of an interface. This is done as a separate step from + // importing the interface definition in order to resolve cycles. + auto MakeInterfaceDecl(SemIR::InstId inst_id, + const SemIR::Interface& import_interface) + -> SemIR::ConstantId { auto interface_decl = SemIR::InterfaceDecl{SemIR::TypeId::Invalid, SemIR::InterfaceId::Invalid, SemIR::InstBlockId::Empty}; @@ -605,34 +690,73 @@ class ImportRefResolver { .decl_id = interface_decl_id, }; - // If the interface is defined, we can complete it immediately. No constants - // are required. Do this before adding it to interfaces. - if (import_interface.is_defined()) { - new_interface.scope_id = context_.name_scopes().Add( - new_interface.decl_id, SemIR::NameId::Invalid, - new_interface.enclosing_scope_id); - auto& new_scope = context_.name_scopes().Get(new_interface.scope_id); - const auto& import_scope = - import_ir_.name_scopes().Get(import_interface.scope_id); - - // Push a block so that we can add scoped instructions to it. - context_.inst_block_stack().Push(); - AddNameScopeImportRefs(import_scope, new_scope); - new_interface.associated_entities_id = - AddAssociatedEntities(import_interface.associated_entities_id); - new_interface.body_block_id = context_.inst_block_stack().Pop(); - // TODO: Import new_interface.self_param_id. - - CARBON_CHECK(import_scope.extended_scopes.empty()) - << "Interfaces don't currently have extended scopes to support."; - } - // Write the interface ID into the InterfaceDecl. interface_decl.interface_id = context_.interfaces().Add(new_interface); context_.ReplaceInstBeforeConstantUse( interface_decl_id, {Parse::NodeId::Invalid, interface_decl}); - return context_.constant_values().Get(interface_decl_id); + // Set the constant value for the imported interface. + auto interface_const_id = context_.constant_values().Get(interface_decl_id); + import_ir_constant_values_.Set(inst_id, interface_const_id); + return interface_const_id; + } + + // Imports the definition for an interface that has been imported as a forward + // declaration. + auto AddInterfaceDefinition(const SemIR::Interface& import_interface, + SemIR::ConstantId interface_const_id, + SemIR::ConstantId self_param_id) -> void { + auto& new_interface = context_.interfaces().Get( + context_.insts() + .GetAs(interface_const_id.inst_id()) + .interface_id); + new_interface.scope_id = context_.name_scopes().Add( + new_interface.decl_id, SemIR::NameId::Invalid, + new_interface.enclosing_scope_id); + auto& new_scope = context_.name_scopes().Get(new_interface.scope_id); + const auto& import_scope = + import_ir_.name_scopes().Get(import_interface.scope_id); + + // Push a block so that we can add scoped instructions to it. + context_.inst_block_stack().Push(); + AddNameScopeImportRefs(import_scope, new_scope); + new_interface.associated_entities_id = + AddAssociatedEntities(import_interface.associated_entities_id); + new_interface.body_block_id = context_.inst_block_stack().Pop(); + new_interface.self_param_id = self_param_id.inst_id(); + + CARBON_CHECK(import_scope.extended_scopes.empty()) + << "Interfaces don't currently have extended scopes to support."; + } + + auto TryResolveTypedInst(SemIR::InterfaceDecl inst, SemIR::InstId inst_id, + bool made_forward_decl) -> SemIR::ConstantId { + const auto& import_interface = + import_ir_.interfaces().Get(inst.interface_id); + + // On the first pass, create a forward declaration of the interface. + if (!made_forward_decl) { + auto interface_const_id = MakeInterfaceDecl(inst_id, import_interface); + if (!import_interface.is_defined()) { + return interface_const_id; + } + // Track that we need another pass. We always will, because the type of + // the `Self` binding refers to the interface. + work_stack_.back().made_forward_decl = true; + } + + auto initial_work = work_stack_.size(); + auto self_param_id = GetLocalConstantId(import_interface.self_param_id); + if (HasNewWork(initial_work)) { + return SemIR::ConstantId::Invalid; + } + + // Add the interface definition. + CARBON_CHECK(import_interface.is_defined()) + << "Should not need second pass for undefined interface."; + auto interface_const_id = import_ir_constant_values_.Get(inst_id); + AddInterfaceDefinition(import_interface, interface_const_id, self_param_id); + return interface_const_id; } auto TryResolveTypedInst(SemIR::InterfaceType inst) -> SemIR::ConstantId { diff --git a/toolchain/check/member_access.cpp b/toolchain/check/member_access.cpp index 57e3c321fc0b..172ba06f0a2f 100644 --- a/toolchain/check/member_access.cpp +++ b/toolchain/check/member_access.cpp @@ -149,7 +149,8 @@ static auto LookupInterfaceWitness(Context& context, // Performs impl lookup for a member name expression. This finds the relevant // impl witness and extracts the corresponding impl member. -static auto PerformImplLookup(Context& context, SemIR::ConstantId type_const_id, +static auto PerformImplLookup(Context& context, Parse::NodeId node_id, + SemIR::ConstantId type_const_id, SemIR::AssociatedEntityType assoc_type, SemIR::InstId member_id) -> SemIR::InstId { auto& interface = context.interfaces().Get(assoc_type.interface_id); @@ -161,7 +162,7 @@ static auto PerformImplLookup(Context& context, SemIR::ConstantId type_const_id, "that does not implement that interface.", SemIR::NameId, std::string); context.emitter().Emit( - member_id, MissingImplInMemberAccess, interface.name_id, + node_id, MissingImplInMemberAccess, interface.name_id, context.sem_ir().StringifyTypeExpr(type_const_id.inst_id())); return SemIR::InstId::BuiltinError; } @@ -194,8 +195,7 @@ static auto PerformImplLookup(Context& context, SemIR::ConstantId type_const_id, // Performs a member name lookup into the specified scope, including performing // impl lookup if necessary. If the scope is invalid, assume an error has // already been diagnosed, and return BuiltinError. -static auto LookupMemberNameInScope(Context& context, - Parse::AnyMemberAccessExprId node_id, +static auto LookupMemberNameInScope(Context& context, Parse::NodeId node_id, SemIR::InstId /*base_id*/, SemIR::NameId name_id, SemIR::ConstantId name_scope_const_id, @@ -219,8 +219,8 @@ static auto LookupMemberNameInScope(Context& context, if (auto assoc_type = context.types().TryGetAs( inst.type_id())) { if (ScopeNeedsImplLookup(context, name_scope_id)) { - member_id = PerformImplLookup(context, name_scope_const_id, *assoc_type, - member_id); + member_id = PerformImplLookup(context, node_id, name_scope_const_id, + *assoc_type, member_id); } } @@ -230,8 +230,7 @@ static auto LookupMemberNameInScope(Context& context, // Performs the instance binding step in member access. If the found member is a // field, forms a class member access. If the found member is an instance // method, forms a bound method. Otherwise, the member is returned unchanged. -static auto PerformInstanceBinding(Context& context, - Parse::AnyMemberAccessExprId node_id, +static auto PerformInstanceBinding(Context& context, Parse::NodeId node_id, SemIR::InstId base_id, SemIR::InstId member_id) -> SemIR::InstId { auto member_type_id = context.insts().Get(member_id).type_id(); @@ -295,7 +294,7 @@ static auto PerformInstanceBinding(Context& context, return member_id; } -auto PerformMemberAccess(Context& context, Parse::AnyMemberAccessExprId node_id, +auto PerformMemberAccess(Context& context, Parse::NodeId node_id, SemIR::InstId base_id, SemIR::NameId name_id) -> SemIR::InstId { // If the base is a name scope, such as a class or namespace, perform lookup @@ -370,8 +369,7 @@ auto PerformMemberAccess(Context& context, Parse::AnyMemberAccessExprId node_id, return member_id; } -auto PerformCompoundMemberAccess(Context& context, - Parse::AnyMemberAccessExprId node_id, +auto PerformCompoundMemberAccess(Context& context, Parse::NodeId node_id, SemIR::InstId base_id, SemIR::InstId member_expr_id) -> SemIR::InstId { @@ -387,8 +385,8 @@ auto PerformCompoundMemberAccess(Context& context, // performed using the type of the base expression. if (auto assoc_type = context.types().TryGetAs( member.type_id())) { - member_id = - PerformImplLookup(context, base_type_const_id, *assoc_type, member_id); + member_id = PerformImplLookup(context, node_id, base_type_const_id, + *assoc_type, member_id); } // Perform instance binding if we found an instance member. diff --git a/toolchain/check/member_access.h b/toolchain/check/member_access.h index f1f3594c92ab..562d3c3a14b8 100644 --- a/toolchain/check/member_access.h +++ b/toolchain/check/member_access.h @@ -12,15 +12,14 @@ namespace Carbon::Check { // Creates SemIR to perform a member access with base expression `base_id` and // member name `name_id`. Returns the result of the access. -auto PerformMemberAccess(Context& context, Parse::AnyMemberAccessExprId node_id, +auto PerformMemberAccess(Context& context, Parse::NodeId node_id, SemIR::InstId base_id, SemIR::NameId name_id) -> SemIR::InstId; // Creates SemIR to perform a compound member access with base expression // `base_id` and member name expression `member_expr_id`. Returns the result of // the access. -auto PerformCompoundMemberAccess(Context& context, - Parse::AnyMemberAccessExprId node_id, +auto PerformCompoundMemberAccess(Context& context, Parse::NodeId node_id, SemIR::InstId base_id, SemIR::InstId member_expr_id) -> SemIR::InstId; diff --git a/toolchain/check/operator.cpp b/toolchain/check/operator.cpp new file mode 100644 index 000000000000..291fef60b9b7 --- /dev/null +++ b/toolchain/check/operator.cpp @@ -0,0 +1,148 @@ +// 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/member_access.h" +#include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/typed_insts.h" + +namespace Carbon::Check { + +// Returns the scope of the Core package, or Invalid if it's not found. +// +// TODO: Consider tracking the Core package in SemIR so we don't need to use +// name lookup to find it. +static auto GetCorePackage(Context& context, Parse::AnyExprId node_id) + -> SemIR::NameScopeId { + // TODO: If the current package is the `Core` package, return + // `SemIR::InstId::Package`. + + auto ident_id = context.identifiers().Lookup("Core"); + if (!ident_id.is_valid()) { + return SemIR::NameScopeId::Invalid; + } + auto name_id = SemIR::NameId::ForIdentifier(ident_id); + + // Look up `package.Core`. + auto package_id = context.LookupQualifiedName( + node_id, name_id, SemIR::NameScopeId::Package, /*required=*/false); + if (!package_id.is_valid()) { + return SemIR::NameScopeId::Invalid; + } + + // Look through import_refs and aliases. + package_id = context.constant_values().Get(package_id).inst_id(); + + // We expect it to be a package, and fail if not. + if (auto package_inst = + context.insts().TryGetAs(package_id)) { + auto& name_scope = context.name_scopes().Get(package_inst->name_scope_id); + // Check that this is really the `Core` package and not an alias. + if (name_scope.is_closed_import && name_scope.name_id == name_id && + name_scope.enclosing_scope_id == SemIR::NameScopeId::Package) { + return package_inst->name_scope_id; + } + } + return SemIR::NameScopeId::Invalid; +} + +// 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 carbon_package_id = GetCorePackage(context, node_id); + if (!carbon_package_id.is_valid()) { + return SemIR::NameScopeId::Invalid; + } + + // Lookup `Core.InterfaceName`. + auto interface_ident_id = context.identifiers().Add(op.interface_name); + auto interface_id = context.LookupQualifiedName( + node_id, SemIR::NameId::ForIdentifier(interface_ident_id), + carbon_package_id, /*required=*/false); + if (!interface_id.is_valid()) { + return SemIR::NameScopeId::Invalid; + } + + // Look through import_refs and aliases. + interface_id = context.constant_values().Get(interface_id).inst_id(); + + // We expect it to be an interface. + if (auto interface_inst = + context.insts().TryGetAs(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; + } + + // Lookup `Interface.Op`. + auto op_ident_id = context.identifiers().Add(op.op_name); + auto op_id = context.LookupQualifiedName( + node_id, SemIR::NameId::ForIdentifier(op_ident_id), interface_scope_id, + /*required=*/false); + if (!op_id.is_valid()) { + return SemIR::InstId::Invalid; + } + + // Look through import_refs and aliases. + op_id = context.constant_values().Get(op_id).inst_id(); + + // We expect it to be an associated function. + if (context.insts().Is(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"); + 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 diff --git a/toolchain/check/operator.h b/toolchain/check/operator.h new file mode 100644 index 000000000000..77d79ae81801 --- /dev/null +++ b/toolchain/check/operator.h @@ -0,0 +1,32 @@ +// 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_OPERATOR_H_ +#define CARBON_TOOLCHAIN_CHECK_OPERATOR_H_ + +#include "toolchain/check/context.h" +#include "toolchain/parse/node_ids.h" +#include "toolchain/sem_ir/ids.h" + +namespace Carbon::Check { + +struct Operator { + llvm::StringLiteral interface_name; + llvm::StringLiteral op_name = "Op"; +}; + +// Checks and builds SemIR for a unary operator expression. For example, +// `$operand` or `operand$`. +auto BuildUnaryOperator(Context& context, Parse::AnyExprId node_id, Operator op, + SemIR::InstId operand_id) -> SemIR::InstId; + +// Checks and builds SemIR for a binary operator expression. For example, +// `lhs_id $ rhs_id`. +auto BuildBinaryOperator(Context& context, Parse::AnyExprId node_id, + Operator op, SemIR::InstId lhs_id, + SemIR::InstId rhs_id) -> SemIR::InstId; + +} // namespace Carbon::Check + +#endif // CARBON_TOOLCHAIN_CHECK_OPERATOR_H_ diff --git a/toolchain/check/pointer_dereference.cpp b/toolchain/check/pointer_dereference.cpp index 556ae5ee3741..e8371e17c14d 100644 --- a/toolchain/check/pointer_dereference.cpp +++ b/toolchain/check/pointer_dereference.cpp @@ -15,6 +15,11 @@ auto PerformPointerDereference( SemIR::InstId base_id, llvm::function_refvoid> diagnose_not_pointer) -> SemIR::InstId { + // TODO: Once we have a finalized design for a pointer interface, use + // + // HandleUnaryOperator(context, node_id, {"Pointer", "Dereference"}); + // + // to convert to a pointer value. base_id = ConvertToValueExpr(context, base_id); auto type_id = context.GetUnqualifiedType(context.insts().Get(base_id).type_id()); diff --git a/toolchain/check/testdata/array/fail_bound_overflow.carbon b/toolchain/check/testdata/array/fail_bound_overflow.carbon index 0e8a93bba4ee..bc94d859ae76 100644 --- a/toolchain/check/testdata/array/fail_bound_overflow.carbon +++ b/toolchain/check/testdata/array/fail_bound_overflow.carbon @@ -9,12 +9,9 @@ // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ var a: [i32; 39999999999999999993]; -// CHECK:STDERR: fail_bound_overflow.carbon:[[@LINE+6]]:9: ERROR: Cannot implicitly convert from `i32` to `type`. +// CHECK:STDERR: fail_bound_overflow.carbon:[[@LINE+3]]:9: ERROR: Cannot implicitly convert from `i32` to `type`. // CHECK:STDERR: var b: [1; 39999999999999999993]; // CHECK:STDERR: ^ -// CHECK:STDERR: fail_bound_overflow.carbon:[[@LINE+3]]:12: ERROR: Array bound of 39999999999999999993 is too large. -// CHECK:STDERR: var b: [1; 39999999999999999993]; -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ var b: [1; 39999999999999999993]; // CHECK:STDOUT: --- fail_bound_overflow.carbon @@ -33,9 +30,9 @@ var b: [1; 39999999999999999993]; // CHECK:STDOUT: %.loc10_34: type = array_type %.loc10_14, i32 [template = ] // CHECK:STDOUT: %a.var: ref = var a // CHECK:STDOUT: %a: ref = bind_name a, %a.var -// CHECK:STDOUT: %.loc18_9: i32 = int_literal 1 [template = constants.%.2] -// CHECK:STDOUT: %.loc18_12: i32 = int_literal 39999999999999999993 [template = constants.%.1] -// CHECK:STDOUT: %.loc18_32: type = array_type %.loc18_12, [template = ] +// CHECK:STDOUT: %.loc15_9: i32 = int_literal 1 [template = constants.%.2] +// CHECK:STDOUT: %.loc15_12: i32 = int_literal 39999999999999999993 [template = constants.%.1] +// CHECK:STDOUT: %.loc15_32: type = array_type %.loc15_12, [template = ] // CHECK:STDOUT: %b.var: ref = var b // CHECK:STDOUT: %b: ref = bind_name b, %b.var // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/index/fail_negative_indexing.carbon b/toolchain/check/testdata/index/fail_negative_indexing.carbon index 862f072049a1..4135c2334f8c 100644 --- a/toolchain/check/testdata/index/fail_negative_indexing.carbon +++ b/toolchain/check/testdata/index/fail_negative_indexing.carbon @@ -5,7 +5,7 @@ // AUTOUPDATE var a: (i32, i32) = (12, 6); -// CHECK:STDERR: fail_negative_indexing.carbon:[[@LINE+3]]:16: ERROR: Semantics TODO: `HandlePrefixOperatorMinus`. +// CHECK:STDERR: fail_negative_indexing.carbon:[[@LINE+3]]:16: ERROR: Semantics TODO: `missing or invalid operator interface`. // CHECK:STDERR: var b: i32 = a[-10]; // CHECK:STDERR: ^~~ var b: i32 = a[-10]; @@ -22,5 +22,35 @@ var b: i32 = a[-10]; // CHECK:STDOUT: %.7: i32 = int_literal 10 [template] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: file {} +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .a = %a +// CHECK:STDOUT: .b = %b +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc7_17.1: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.2: type = converted %.loc7_17.1, constants.%.2 [template = constants.%.2] +// CHECK:STDOUT: %a.var: ref (i32, i32) = var a +// CHECK:STDOUT: %a: ref (i32, i32) = bind_name a, %a.var +// CHECK:STDOUT: %b.var: ref i32 = var b +// CHECK:STDOUT: %b: ref i32 = bind_name b, %b.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc7_22: i32 = int_literal 12 [template = constants.%.4] +// CHECK:STDOUT: %.loc7_26: i32 = int_literal 6 [template = constants.%.5] +// CHECK:STDOUT: %.loc7_27.1: (i32, i32) = tuple_literal (%.loc7_22, %.loc7_26) +// CHECK:STDOUT: %.loc7_27.2: ref i32 = tuple_access file.%a.var, element0 +// CHECK:STDOUT: %.loc7_27.3: init i32 = initialize_from %.loc7_22 to %.loc7_27.2 [template = constants.%.4] +// CHECK:STDOUT: %.loc7_27.4: ref i32 = tuple_access file.%a.var, element1 +// CHECK:STDOUT: %.loc7_27.5: init i32 = initialize_from %.loc7_26 to %.loc7_27.4 [template = constants.%.5] +// CHECK:STDOUT: %.loc7_27.6: init (i32, i32) = tuple_init (%.loc7_27.3, %.loc7_27.5) to file.%a.var [template = constants.%.6] +// CHECK:STDOUT: %.loc7_27.7: init (i32, i32) = converted %.loc7_27.1, %.loc7_27.6 [template = constants.%.6] +// CHECK:STDOUT: assign file.%a.var, %.loc7_27.7 +// CHECK:STDOUT: %a.ref: ref (i32, i32) = name_ref a, file.%a +// CHECK:STDOUT: %.loc11_17: i32 = int_literal 10 [template = constants.%.7] +// CHECK:STDOUT: %.loc11_19: ref = tuple_index %a.ref, +// CHECK:STDOUT: assign file.%b.var, +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/fail_todo_import.carbon b/toolchain/check/testdata/interface/fail_todo_import.carbon deleted file mode 100644 index d717cd901cfa..000000000000 --- a/toolchain/check/testdata/interface/fail_todo_import.carbon +++ /dev/null @@ -1,256 +0,0 @@ -// 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 -// -// AUTOUPDATE -// CHECK:STDERR: fail_b.carbon: ERROR: Semantics TODO: `TryResolveInst on AssociatedEntityType`. -// CHECK:STDERR: fail_b.carbon: ERROR: Semantics TODO: `TryResolveInst on AssociatedEntity`. -// CHECK:STDERR: fail_b.carbon: ERROR: Semantics TODO: `TryResolveInst on AssociatedEntityType`. -// CHECK:STDERR: fail_b.carbon: ERROR: Semantics TODO: `TryResolveInst on AssociatedEntity`. -// CHECK:STDERR: fail_b.carbon: ERROR: Semantics TODO: `TryResolveInst on AssociatedEntityType`. -// CHECK:STDERR: fail_b.carbon: ERROR: Semantics TODO: `TryResolveInst on AssociatedEntity`. -// CHECK:STDERR: fail_b.carbon: ERROR: Semantics TODO: `TryResolveInst on AssociatedEntityType`. -// CHECK:STDERR: fail_b.carbon: ERROR: Semantics TODO: `TryResolveInst on AssociatedEntity`. - -// --- a.carbon - -library "a" api; - -interface Empty { -} - -interface Basic { - let T:! type; - fn F(); -} - -interface ForwardDeclared; - -interface ForwardDeclared { - let T:! type; - fn F(); -} - -var f_ref: {.f: ForwardDeclared}; - -// --- fail_b.carbon - -library "b" api; - -import library "a"; - -fn UseEmpty(e: Empty) {} -fn UseBasic(e: Basic) {} -fn UseForwardDeclared(f: ForwardDeclared) {} - -alias UseBasicT = Basic.T; -alias UseBasicF = Basic.F; - -alias UseForwardDeclaredT = ForwardDeclared.T; -alias UseForwardDeclaredF = ForwardDeclared.F; - -var f: ForwardDeclared* = &f_ref.f; - -// CHECK:STDOUT: --- a.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = interface_type @Empty [template] -// CHECK:STDOUT: %.2: type = interface_type @Basic [template] -// CHECK:STDOUT: %.3: type = assoc_entity_type @Basic, type [template] -// CHECK:STDOUT: %.4: = assoc_entity element0, @Basic.%T [template] -// CHECK:STDOUT: %.5: type = assoc_entity_type @Basic, [template] -// CHECK:STDOUT: %.6: in Basic> = assoc_entity element1, @Basic.%F [template] -// CHECK:STDOUT: %.7: type = interface_type @ForwardDeclared [template] -// CHECK:STDOUT: %.8: type = assoc_entity_type @ForwardDeclared, type [template] -// CHECK:STDOUT: %.9: = assoc_entity element0, @ForwardDeclared.%T [template] -// CHECK:STDOUT: %.10: type = assoc_entity_type @ForwardDeclared, [template] -// CHECK:STDOUT: %.11: in ForwardDeclared> = assoc_entity element1, @ForwardDeclared.%F [template] -// CHECK:STDOUT: %.12: type = struct_type {.f: ForwardDeclared} [template] -// CHECK:STDOUT: %.13: type = tuple_type () [template] -// CHECK:STDOUT: %.14: type = struct_type {.f: ()} [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace [template] { -// CHECK:STDOUT: .Empty = %Empty.decl -// CHECK:STDOUT: .Basic = %Basic.decl -// CHECK:STDOUT: .ForwardDeclared = %ForwardDeclared.decl.loc12 -// CHECK:STDOUT: .f_ref = %f_ref -// CHECK:STDOUT: } -// CHECK:STDOUT: %Empty.decl: type = interface_decl @Empty [template = constants.%.1] {} -// CHECK:STDOUT: %Basic.decl: type = interface_decl @Basic [template = constants.%.2] {} -// CHECK:STDOUT: %ForwardDeclared.decl.loc12: type = interface_decl @ForwardDeclared [template = constants.%.7] {} -// CHECK:STDOUT: %ForwardDeclared.decl.loc14: type = interface_decl @ForwardDeclared [template = constants.%.7] {} -// CHECK:STDOUT: %ForwardDeclared.ref: type = name_ref ForwardDeclared, %ForwardDeclared.decl.loc12 [template = constants.%.7] -// CHECK:STDOUT: %.loc19: type = struct_type {.f: ForwardDeclared} [template = constants.%.12] -// CHECK:STDOUT: %f_ref.var: ref {.f: ForwardDeclared} = var f_ref -// CHECK:STDOUT: %f_ref: ref {.f: ForwardDeclared} = bind_name f_ref, %f_ref.var -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: interface @Empty { -// CHECK:STDOUT: %Self: Empty = bind_symbolic_name Self [symbolic] -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = %Self -// CHECK:STDOUT: witness = () -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: interface @Basic { -// CHECK:STDOUT: %Self: Basic = bind_symbolic_name Self [symbolic] -// CHECK:STDOUT: %T: type = assoc_const_decl T [template] -// CHECK:STDOUT: %.loc8: = assoc_entity element0, %T [template = constants.%.4] -// CHECK:STDOUT: %F: = fn_decl @F.1 [template] {} -// CHECK:STDOUT: %.loc9: in Basic> = assoc_entity element1, %F [template = constants.%.6] -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = %Self -// CHECK:STDOUT: .T = %.loc8 -// CHECK:STDOUT: .F = %.loc9 -// CHECK:STDOUT: witness = (%T, %F) -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: interface @ForwardDeclared { -// CHECK:STDOUT: %Self: ForwardDeclared = bind_symbolic_name Self [symbolic] -// CHECK:STDOUT: %T: type = assoc_const_decl T [template] -// CHECK:STDOUT: %.loc15: = assoc_entity element0, %T [template = constants.%.9] -// CHECK:STDOUT: %F: = fn_decl @F.2 [template] {} -// CHECK:STDOUT: %.loc16: in ForwardDeclared> = assoc_entity element1, %F [template = constants.%.11] -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = %Self -// CHECK:STDOUT: .T = %.loc15 -// CHECK:STDOUT: .F = %.loc16 -// CHECK:STDOUT: witness = (%T, %F) -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(); -// CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2(); -// CHECK:STDOUT: -// CHECK:STDOUT: --- fail_b.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = interface_type @Empty [template] -// CHECK:STDOUT: %.2: type = tuple_type () [template] -// CHECK:STDOUT: %.3: type = interface_type @Basic [template] -// CHECK:STDOUT: %.4: type = interface_type @ForwardDeclared [template] -// CHECK:STDOUT: %.5: type = ptr_type ForwardDeclared [template] -// CHECK:STDOUT: %.6: type = struct_type {.f: ForwardDeclared} [template] -// CHECK:STDOUT: %.7: type = struct_type {.f: ()} [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace [template] { -// CHECK:STDOUT: .Empty = %import_ref.1 -// CHECK:STDOUT: .Basic = %import_ref.2 -// CHECK:STDOUT: .ForwardDeclared = %import_ref.3 -// CHECK:STDOUT: .f_ref = %import_ref.4 -// CHECK:STDOUT: .UseEmpty = %UseEmpty -// CHECK:STDOUT: .UseBasic = %UseBasic -// CHECK:STDOUT: .UseForwardDeclared = %UseForwardDeclared -// CHECK:STDOUT: .UseBasicT = %UseBasicT -// CHECK:STDOUT: .UseBasicF = %UseBasicF -// CHECK:STDOUT: .UseForwardDeclaredT = %UseForwardDeclaredT -// CHECK:STDOUT: .UseForwardDeclaredF = %UseForwardDeclaredF -// CHECK:STDOUT: .f = %f.loc16 -// CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.1] -// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+4, used [template = constants.%.3] -// CHECK:STDOUT: %import_ref.3: type = import_ref ir1, inst+15, used [template = constants.%.4] -// CHECK:STDOUT: %import_ref.4: ref {.f: ForwardDeclared} = import_ref ir1, inst+36, used -// CHECK:STDOUT: %UseEmpty: = fn_decl @UseEmpty [template] { -// CHECK:STDOUT: %Empty.decl: invalid = interface_decl @Empty [template = constants.%.1] {} -// CHECK:STDOUT: %Empty.ref: type = name_ref Empty, %import_ref.1 [template = constants.%.1] -// CHECK:STDOUT: %e.loc6_13.1: Empty = param e -// CHECK:STDOUT: @UseEmpty.%e: Empty = bind_name e, %e.loc6_13.1 -// CHECK:STDOUT: } -// CHECK:STDOUT: %UseBasic: = fn_decl @UseBasic [template] { -// CHECK:STDOUT: %Basic.decl: invalid = interface_decl @Basic [template = constants.%.3] {} -// CHECK:STDOUT: %Basic.ref.loc7: type = name_ref Basic, %import_ref.2 [template = constants.%.3] -// CHECK:STDOUT: %e.loc7_13.1: Basic = param e -// CHECK:STDOUT: @UseBasic.%e: Basic = bind_name e, %e.loc7_13.1 -// CHECK:STDOUT: } -// CHECK:STDOUT: %UseForwardDeclared: = fn_decl @UseForwardDeclared [template] { -// CHECK:STDOUT: %ForwardDeclared.decl: invalid = interface_decl @ForwardDeclared [template = constants.%.4] {} -// CHECK:STDOUT: %ForwardDeclared.ref.loc8: type = name_ref ForwardDeclared, %import_ref.3 [template = constants.%.4] -// CHECK:STDOUT: %f.loc8_23.1: ForwardDeclared = param f -// CHECK:STDOUT: @UseForwardDeclared.%f: ForwardDeclared = bind_name f, %f.loc8_23.1 -// CHECK:STDOUT: } -// CHECK:STDOUT: %Basic.ref.loc10: type = name_ref Basic, %import_ref.2 [template = constants.%.3] -// CHECK:STDOUT: %T.ref.loc10: = name_ref T, @Basic.%import_ref.3 [template = ] -// CHECK:STDOUT: %UseBasicT: = bind_alias UseBasicT, @Basic.%import_ref.3 [template = ] -// CHECK:STDOUT: %Basic.ref.loc11: type = name_ref Basic, %import_ref.2 [template = constants.%.3] -// CHECK:STDOUT: %F.ref.loc11: = name_ref F, @Basic.%import_ref.2 [template = ] -// CHECK:STDOUT: %UseBasicF: = bind_alias UseBasicF, @Basic.%import_ref.2 [template = ] -// CHECK:STDOUT: %ForwardDeclared.ref.loc13: type = name_ref ForwardDeclared, %import_ref.3 [template = constants.%.4] -// CHECK:STDOUT: %T.ref.loc13: = name_ref T, @ForwardDeclared.%import_ref.3 [template = ] -// CHECK:STDOUT: %UseForwardDeclaredT: = bind_alias UseForwardDeclaredT, @ForwardDeclared.%import_ref.3 [template = ] -// CHECK:STDOUT: %ForwardDeclared.ref.loc14: type = name_ref ForwardDeclared, %import_ref.3 [template = constants.%.4] -// CHECK:STDOUT: %F.ref.loc14: = name_ref F, @ForwardDeclared.%import_ref.2 [template = ] -// CHECK:STDOUT: %UseForwardDeclaredF: = bind_alias UseForwardDeclaredF, @ForwardDeclared.%import_ref.2 [template = ] -// CHECK:STDOUT: %ForwardDeclared.ref.loc16: type = name_ref ForwardDeclared, %import_ref.3 [template = constants.%.4] -// CHECK:STDOUT: %.loc16: type = ptr_type ForwardDeclared [template = constants.%.5] -// CHECK:STDOUT: %f.var: ref ForwardDeclared* = var f -// CHECK:STDOUT: %f.loc16: ref ForwardDeclared* = bind_name f, %f.var -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: interface @Empty { -// CHECK:STDOUT: %import_ref = import_ref ir1, inst+3, unused -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = %import_ref -// CHECK:STDOUT: witness = () -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: interface @Basic { -// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+6, unused -// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+13, used [template = ] -// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+9, used [template = ] -// CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+7, unused -// CHECK:STDOUT: %import_ref.5 = import_ref ir1, inst+11, unused -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = %import_ref.1 -// CHECK:STDOUT: .F = %import_ref.2 -// CHECK:STDOUT: .T = %import_ref.3 -// CHECK:STDOUT: witness = (%import_ref.4, %import_ref.5) -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: interface @ForwardDeclared { -// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+18, unused -// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+25, used [template = ] -// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+21, used [template = ] -// CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+19, unused -// CHECK:STDOUT: %import_ref.5 = import_ref ir1, inst+23, unused -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = %import_ref.1 -// CHECK:STDOUT: .F = %import_ref.2 -// CHECK:STDOUT: .T = %import_ref.3 -// CHECK:STDOUT: witness = (%import_ref.4, %import_ref.5) -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @UseEmpty(%e: Empty) { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: return -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @UseBasic(%e: Basic) { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: return -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @UseForwardDeclared(%f: ForwardDeclared) { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: return -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @__global_init() { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: %f_ref.ref: ref {.f: ForwardDeclared} = name_ref f_ref, file.%import_ref.4 -// CHECK:STDOUT: %.loc16_33: ref ForwardDeclared = struct_access %f_ref.ref, element0 -// CHECK:STDOUT: %.loc16_27: ForwardDeclared* = addr_of %.loc16_33 -// CHECK:STDOUT: assign file.%f.var, %.loc16_27 -// CHECK:STDOUT: return -// CHECK:STDOUT: } -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/import.carbon b/toolchain/check/testdata/interface/import.carbon index 1a363c63b7d2..475ee276f2b2 100644 --- a/toolchain/check/testdata/interface/import.carbon +++ b/toolchain/check/testdata/interface/import.carbon @@ -35,6 +35,12 @@ fn UseEmpty(e: Empty) {} fn UseBasic(e: Basic) {} fn UseForwardDeclared(f: ForwardDeclared) {} +alias UseBasicT = Basic.T; +alias UseBasicF = Basic.F; + +alias UseForwardDeclaredT = ForwardDeclared.T; +alias UseForwardDeclaredF = ForwardDeclared.F; + var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: --- a.carbon @@ -120,9 +126,17 @@ var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: %.2: type = tuple_type () [template] // CHECK:STDOUT: %.3: type = interface_type @Basic [template] // CHECK:STDOUT: %.4: type = interface_type @ForwardDeclared [template] -// CHECK:STDOUT: %.5: type = ptr_type ForwardDeclared [template] -// CHECK:STDOUT: %.6: type = struct_type {.f: ForwardDeclared} [template] -// CHECK:STDOUT: %.7: type = struct_type {.f: ()} [template] +// CHECK:STDOUT: %.5: type = assoc_entity_type @Basic, type [template] +// CHECK:STDOUT: %.6: = assoc_entity element0, file.%import_ref.5 [template] +// CHECK:STDOUT: %.7: type = assoc_entity_type @Basic, [template] +// CHECK:STDOUT: %.8: in Basic> = assoc_entity element1, file.%import_ref.6 [template] +// CHECK:STDOUT: %.9: type = assoc_entity_type @ForwardDeclared, type [template] +// CHECK:STDOUT: %.10: = assoc_entity element0, file.%import_ref.7 [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @ForwardDeclared, [template] +// CHECK:STDOUT: %.12: in ForwardDeclared> = assoc_entity element1, file.%import_ref.8 [template] +// CHECK:STDOUT: %.13: type = ptr_type ForwardDeclared [template] +// CHECK:STDOUT: %.14: type = struct_type {.f: ForwardDeclared} [template] +// CHECK:STDOUT: %.15: type = struct_type {.f: ()} [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -134,7 +148,11 @@ var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: .UseEmpty = %UseEmpty // CHECK:STDOUT: .UseBasic = %UseBasic // CHECK:STDOUT: .UseForwardDeclared = %UseForwardDeclared -// CHECK:STDOUT: .f = %f.loc10 +// CHECK:STDOUT: .UseBasicT = %UseBasicT +// CHECK:STDOUT: .UseBasicF = %UseBasicF +// CHECK:STDOUT: .UseForwardDeclaredT = %UseForwardDeclaredT +// CHECK:STDOUT: .UseForwardDeclaredF = %UseForwardDeclaredF +// CHECK:STDOUT: .f = %f.loc16 // CHECK:STDOUT: } // CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.1] // CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+4, used [template = constants.%.3] @@ -148,7 +166,7 @@ var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: } // CHECK:STDOUT: %UseBasic: = fn_decl @UseBasic [template] { // CHECK:STDOUT: %Basic.decl: invalid = interface_decl @Basic [template = constants.%.3] {} -// CHECK:STDOUT: %Basic.ref: type = name_ref Basic, %import_ref.2 [template = constants.%.3] +// CHECK:STDOUT: %Basic.ref.loc7: type = name_ref Basic, %import_ref.2 [template = constants.%.3] // CHECK:STDOUT: %e.loc7_13.1: Basic = param e // CHECK:STDOUT: @UseBasic.%e: Basic = bind_name e, %e.loc7_13.1 // CHECK:STDOUT: } @@ -158,10 +176,26 @@ var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: %f.loc8_23.1: ForwardDeclared = param f // CHECK:STDOUT: @UseForwardDeclared.%f: ForwardDeclared = bind_name f, %f.loc8_23.1 // CHECK:STDOUT: } -// CHECK:STDOUT: %ForwardDeclared.ref.loc10: type = name_ref ForwardDeclared, %import_ref.3 [template = constants.%.4] -// CHECK:STDOUT: %.loc10: type = ptr_type ForwardDeclared [template = constants.%.5] +// CHECK:STDOUT: %Basic.ref.loc10: type = name_ref Basic, %import_ref.2 [template = constants.%.3] +// CHECK:STDOUT: %import_ref.5 = import_ref ir1, inst+7, unused +// CHECK:STDOUT: %T.ref.loc10: = name_ref T, @Basic.%import_ref.3 [template = constants.%.6] +// CHECK:STDOUT: %UseBasicT: = bind_alias UseBasicT, @Basic.%import_ref.3 [template = constants.%.6] +// CHECK:STDOUT: %Basic.ref.loc11: type = name_ref Basic, %import_ref.2 [template = constants.%.3] +// CHECK:STDOUT: %import_ref.6 = import_ref ir1, inst+11, unused +// CHECK:STDOUT: %F.ref.loc11: in Basic> = name_ref F, @Basic.%import_ref.2 [template = constants.%.8] +// CHECK:STDOUT: %UseBasicF: in Basic> = bind_alias UseBasicF, @Basic.%import_ref.2 [template = constants.%.8] +// CHECK:STDOUT: %ForwardDeclared.ref.loc13: type = name_ref ForwardDeclared, %import_ref.3 [template = constants.%.4] +// CHECK:STDOUT: %import_ref.7 = import_ref ir1, inst+19, unused +// CHECK:STDOUT: %T.ref.loc13: = name_ref T, @ForwardDeclared.%import_ref.3 [template = constants.%.10] +// CHECK:STDOUT: %UseForwardDeclaredT: = bind_alias UseForwardDeclaredT, @ForwardDeclared.%import_ref.3 [template = constants.%.10] +// CHECK:STDOUT: %ForwardDeclared.ref.loc14: type = name_ref ForwardDeclared, %import_ref.3 [template = constants.%.4] +// CHECK:STDOUT: %import_ref.8 = import_ref ir1, inst+23, unused +// CHECK:STDOUT: %F.ref.loc14: in ForwardDeclared> = name_ref F, @ForwardDeclared.%import_ref.2 [template = constants.%.12] +// CHECK:STDOUT: %UseForwardDeclaredF: in ForwardDeclared> = bind_alias UseForwardDeclaredF, @ForwardDeclared.%import_ref.2 [template = constants.%.12] +// CHECK:STDOUT: %ForwardDeclared.ref.loc16: type = name_ref ForwardDeclared, %import_ref.3 [template = constants.%.4] +// CHECK:STDOUT: %.loc16: type = ptr_type ForwardDeclared [template = constants.%.13] // CHECK:STDOUT: %f.var: ref ForwardDeclared* = var f -// CHECK:STDOUT: %f.loc10: ref ForwardDeclared* = bind_name f, %f.var +// CHECK:STDOUT: %f.loc16: ref ForwardDeclared* = bind_name f, %f.var // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @Empty { @@ -174,8 +208,8 @@ var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: // CHECK:STDOUT: interface @Basic { // CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+6, unused -// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+13, unused -// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+9, unused +// CHECK:STDOUT: %import_ref.2: in Basic> = import_ref ir1, inst+13, used [template = constants.%.8] +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+9, used [template = constants.%.6] // CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+7, unused // CHECK:STDOUT: %import_ref.5 = import_ref ir1, inst+11, unused // CHECK:STDOUT: @@ -188,8 +222,8 @@ var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: // CHECK:STDOUT: interface @ForwardDeclared { // CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+18, unused -// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+25, unused -// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+21, unused +// CHECK:STDOUT: %import_ref.2: in ForwardDeclared> = import_ref ir1, inst+25, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+21, used [template = constants.%.10] // CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+19, unused // CHECK:STDOUT: %import_ref.5 = import_ref ir1, inst+23, unused // CHECK:STDOUT: @@ -218,9 +252,9 @@ var f: ForwardDeclared* = &f_ref.f; // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %f_ref.ref: ref {.f: ForwardDeclared} = name_ref f_ref, file.%import_ref.4 -// CHECK:STDOUT: %.loc10_33: ref ForwardDeclared = struct_access %f_ref.ref, element0 -// CHECK:STDOUT: %.loc10_27: ForwardDeclared* = addr_of %.loc10_33 -// CHECK:STDOUT: assign file.%f.var, %.loc10_27 +// CHECK:STDOUT: %.loc16_33: ref ForwardDeclared = struct_access %f_ref.ref, element0 +// CHECK:STDOUT: %.loc16_27: ForwardDeclared* = addr_of %.loc16_33 +// CHECK:STDOUT: assign file.%f.var, %.loc16_27 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/let/fail_generic_import.carbon b/toolchain/check/testdata/let/fail_generic_import.carbon index e58b751fde7f..97f7861922f3 100644 --- a/toolchain/check/testdata/let/fail_generic_import.carbon +++ b/toolchain/check/testdata/let/fail_generic_import.carbon @@ -37,8 +37,8 @@ let a: T = 0; // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .T = %import_ref // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [symbolic] -// CHECK:STDOUT: %T.ref: type = name_ref T, %import_ref [symbolic = %import_ref] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [symbolic = ] +// CHECK:STDOUT: %T.ref: type = name_ref T, %import_ref [symbolic = ] // CHECK:STDOUT: %.loc8: i32 = int_literal 0 [template = constants.%.1] // CHECK:STDOUT: %a: T = bind_name a, // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/let/generic_import.carbon b/toolchain/check/testdata/let/generic_import.carbon index e506f5d0aea2..360e482b5a40 100644 --- a/toolchain/check/testdata/let/generic_import.carbon +++ b/toolchain/check/testdata/let/generic_import.carbon @@ -36,12 +36,12 @@ var b: T = *a; // CHECK:STDOUT: .a = %a // CHECK:STDOUT: .b = %b // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [symbolic] -// CHECK:STDOUT: %T.ref.loc4: type = name_ref T, %import_ref [symbolic = %import_ref] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [symbolic = ] +// CHECK:STDOUT: %T.ref.loc4: type = name_ref T, %import_ref [symbolic = ] // CHECK:STDOUT: %.loc4: type = ptr_type T [symbolic = constants.%.1] // CHECK:STDOUT: %a.var: ref T* = var a // CHECK:STDOUT: %a: ref T* = bind_name a, %a.var -// CHECK:STDOUT: %T.ref.loc5: type = name_ref T, %import_ref [symbolic = %import_ref] +// CHECK:STDOUT: %T.ref.loc5: type = name_ref T, %import_ref [symbolic = ] // CHECK:STDOUT: %b.var: ref T = var b // CHECK:STDOUT: %b: ref T = bind_name b, %b.var // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/let/import.carbon b/toolchain/check/testdata/let/import.carbon index 1af3f96af7df..a081056b6460 100644 --- a/toolchain/check/testdata/let/import.carbon +++ b/toolchain/check/testdata/let/import.carbon @@ -34,8 +34,8 @@ let b:! bool = a; // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .a = %import_ref // CHECK:STDOUT: } -// CHECK:STDOUT: %import_ref: bool = import_ref ir1, inst+1, used [symbolic] -// CHECK:STDOUT: %a.ref: bool = name_ref a, %import_ref [symbolic = %import_ref] +// CHECK:STDOUT: %import_ref: bool = import_ref ir1, inst+1, used [symbolic = ] +// CHECK:STDOUT: %a.ref: bool = name_ref a, %import_ref [symbolic = ] // CHECK:STDOUT: %b: bool = bind_symbolic_name b, %a.ref [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/and.carbon b/toolchain/check/testdata/operators/builtin/and.carbon similarity index 100% rename from toolchain/check/testdata/operators/and.carbon rename to toolchain/check/testdata/operators/builtin/and.carbon diff --git a/toolchain/check/testdata/operators/assignment.carbon b/toolchain/check/testdata/operators/builtin/assignment.carbon similarity index 100% rename from toolchain/check/testdata/operators/assignment.carbon rename to toolchain/check/testdata/operators/builtin/assignment.carbon diff --git a/toolchain/check/testdata/operators/fail_and_or_not_in_function.carbon b/toolchain/check/testdata/operators/builtin/fail_and_or_not_in_function.carbon similarity index 100% rename from toolchain/check/testdata/operators/fail_and_or_not_in_function.carbon rename to toolchain/check/testdata/operators/builtin/fail_and_or_not_in_function.carbon diff --git a/toolchain/check/testdata/operators/fail_assignment_to_error.carbon b/toolchain/check/testdata/operators/builtin/fail_assignment_to_error.carbon similarity index 100% rename from toolchain/check/testdata/operators/fail_assignment_to_error.carbon rename to toolchain/check/testdata/operators/builtin/fail_assignment_to_error.carbon diff --git a/toolchain/check/testdata/operators/fail_assignment_to_non_assignable.carbon b/toolchain/check/testdata/operators/builtin/fail_assignment_to_non_assignable.carbon similarity index 100% rename from toolchain/check/testdata/operators/fail_assignment_to_non_assignable.carbon rename to toolchain/check/testdata/operators/builtin/fail_assignment_to_non_assignable.carbon diff --git a/toolchain/check/testdata/operators/fail_redundant_compound_access.carbon b/toolchain/check/testdata/operators/builtin/fail_redundant_compound_access.carbon similarity index 100% rename from toolchain/check/testdata/operators/fail_redundant_compound_access.carbon rename to toolchain/check/testdata/operators/builtin/fail_redundant_compound_access.carbon diff --git a/toolchain/check/testdata/operators/fail_type_mismatch.carbon b/toolchain/check/testdata/operators/builtin/fail_type_mismatch.carbon similarity index 100% rename from toolchain/check/testdata/operators/fail_type_mismatch.carbon rename to toolchain/check/testdata/operators/builtin/fail_type_mismatch.carbon diff --git a/toolchain/check/testdata/operators/fail_type_mismatch_assignment.carbon b/toolchain/check/testdata/operators/builtin/fail_type_mismatch_assignment.carbon similarity index 100% rename from toolchain/check/testdata/operators/fail_type_mismatch_assignment.carbon rename to toolchain/check/testdata/operators/builtin/fail_type_mismatch_assignment.carbon diff --git a/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon b/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon new file mode 100644 index 000000000000..09b26ec151ca --- /dev/null +++ b/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon @@ -0,0 +1,42 @@ +// 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 +// +// AUTOUPDATE + +fn Main() -> i32 { + // The following line has two mismatches, but after the first, it shouldn't + // keep erroring. + // CHECK:STDERR: fail_type_mismatch_once.carbon:[[@LINE+6]]:10: ERROR: Semantics TODO: `missing or invalid operator interface`. + // CHECK:STDERR: return 12 + 3.4 + 12; + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_type_mismatch_once.carbon:[[@LINE+3]]:10: ERROR: Semantics TODO: `missing or invalid operator interface`. + // CHECK:STDERR: return 12 + 3.4 + 12; + // CHECK:STDERR: ^~~~~~~~~~~~~ + return 12 + 3.4 + 12; +} + +// CHECK:STDOUT: --- fail_type_mismatch_once.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 12 [template] +// CHECK:STDOUT: %.2: f64 = real_literal 34e-1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Main = %Main +// CHECK:STDOUT: } +// CHECK:STDOUT: %Main: = fn_decl @Main [template] { +// CHECK:STDOUT: %return.var: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Main() -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc16_10: i32 = int_literal 12 [template = constants.%.1] +// CHECK:STDOUT: %.loc16_15: f64 = real_literal 34e-1 [template = constants.%.2] +// CHECK:STDOUT: %.loc16_21: i32 = int_literal 12 [template = constants.%.1] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/fail_unimplemented_op.carbon b/toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon similarity index 56% rename from toolchain/check/testdata/operators/fail_unimplemented_op.carbon rename to toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon index 0650514cca44..6236d5b6e311 100644 --- a/toolchain/check/testdata/operators/fail_unimplemented_op.carbon +++ b/toolchain/check/testdata/operators/builtin/fail_unimplemented_op.carbon @@ -5,7 +5,7 @@ // AUTOUPDATE fn Main() -> i32 { - // CHECK:STDERR: fail_unimplemented_op.carbon:[[@LINE+3]]:10: ERROR: Semantics TODO: `HandleInfixOperatorPlus`. + // CHECK:STDERR: fail_unimplemented_op.carbon:[[@LINE+3]]:10: ERROR: Semantics TODO: `missing or invalid operator interface`. // CHECK:STDERR: return 12 + 34; // CHECK:STDERR: ^~~~~~~ return 12 + 34; @@ -18,9 +18,19 @@ fn Main() -> i32 { // CHECK:STDOUT: %.2: i32 = int_literal 34 [template] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: file {} +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Main = %Main +// CHECK:STDOUT: } +// CHECK:STDOUT: %Main: = fn_decl @Main [template] { +// CHECK:STDOUT: %return.var: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Main() -> i32 { // CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc11_10: i32 = int_literal 12 [template = constants.%.1] +// CHECK:STDOUT: %.loc11_15: i32 = int_literal 34 [template = constants.%.2] +// CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/or.carbon b/toolchain/check/testdata/operators/builtin/or.carbon similarity index 100% rename from toolchain/check/testdata/operators/or.carbon rename to toolchain/check/testdata/operators/builtin/or.carbon diff --git a/toolchain/check/testdata/operators/unary_op.carbon b/toolchain/check/testdata/operators/builtin/unary_op.carbon similarity index 100% rename from toolchain/check/testdata/operators/unary_op.carbon rename to toolchain/check/testdata/operators/builtin/unary_op.carbon diff --git a/toolchain/check/testdata/operators/fail_type_mismatch_once.carbon b/toolchain/check/testdata/operators/fail_type_mismatch_once.carbon deleted file mode 100644 index 72c584999058..000000000000 --- a/toolchain/check/testdata/operators/fail_type_mismatch_once.carbon +++ /dev/null @@ -1,28 +0,0 @@ -// 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 -// -// AUTOUPDATE - -fn Main() -> i32 { - // The following line has two mismatches, but after the first, it shouldn't - // keep erroring. - // CHECK:STDERR: fail_type_mismatch_once.carbon:[[@LINE+3]]:10: ERROR: Semantics TODO: `HandleInfixOperatorPlus`. - // CHECK:STDERR: return 12 + 3.4 + 12; - // CHECK:STDERR: ^~~~~~~~ - return 12 + 3.4 + 12; -} - -// CHECK:STDOUT: --- fail_type_mismatch_once.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: i32 = int_literal 12 [template] -// CHECK:STDOUT: %.2: f64 = real_literal 34e-1 [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file {} -// CHECK:STDOUT: -// CHECK:STDOUT: fn @Main() -> i32 { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: } -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/add.carbon b/toolchain/check/testdata/operators/overloaded/add.carbon new file mode 100644 index 000000000000..21b1a7c61dd4 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/add.carbon @@ -0,0 +1,290 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from binary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface Add { + fn Op[self: Self](other: Self) -> Self; +} +interface AddAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Add { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.AddAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a + b; +} + +fn TestAssign(a: C*, b: C) { + *a += b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Add [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Add, [template] +// CHECK:STDOUT: %.3: in Add> = assoc_entity element0, @Add.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @AddAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @AddAssign, [template] +// CHECK:STDOUT: %.7: in AddAssign> = assoc_entity element0, @AddAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Add = %Add.decl +// CHECK:STDOUT: .AddAssign = %AddAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Add.decl: type = interface_decl @Add [template = constants.%.1] {} +// CHECK:STDOUT: %AddAssign.decl: type = interface_decl @AddAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Add { +// CHECK:STDOUT: %Self: Add = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: Add = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: Add = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: Add = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in Add> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @AddAssign { +// CHECK:STDOUT: %Self: AddAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: AddAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: AddAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in AddAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@Add.%self.loc5_9.2: Self](@Add.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @AddAssign.%self.loc8_14.3: Self*](@AddAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Add [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.7: type = interface_type @AddAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type C [template] +// CHECK:STDOUT: %.9: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @Add, [template] +// CHECK:STDOUT: %.12: in Add> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @AddAssign, [template] +// CHECK:STDOUT: %.14: in AddAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Add.decl: invalid = interface_decl @Add [template = constants.%.2] {} +// CHECK:STDOUT: %Add.ref: type = name_ref Add, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc13: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %AddAssign.decl: invalid = interface_decl @AddAssign [template = constants.%.7] {} +// CHECK:STDOUT: %AddAssign.ref: type = name_ref AddAssign, %import_ref.2 [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc17_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc17_11.1 +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_17.1: C = param b +// CHECK:STDOUT: @TestOp.%b: C = bind_name b, %b.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %C.ref.loc21_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %a.loc21_15.1: C* = param a +// CHECK:STDOUT: @TestAssign.%a: C* = bind_name a, %a.loc21_15.1 +// CHECK:STDOUT: %C.ref.loc21_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc21_22.1: C = param b +// CHECK:STDOUT: @TestAssign.%b: C = bind_name b, %b.loc21_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Add { +// CHECK:STDOUT: %import_ref.1: in Add> = import_ref ir1, inst+20, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @AddAssign { +// CHECK:STDOUT: %import_ref.1: in AddAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as Add { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_18.1: C = param other +// CHECK:STDOUT: %other.loc9_18.2: C = bind_name other, %other.loc9_18.1 +// CHECK:STDOUT: %C.ref.loc9_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as AddAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14_21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %self.loc14_14.1: C* = param self +// CHECK:STDOUT: %self.loc14_14.3: C* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: C* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: %C.ref.loc14_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc14_24.1: C = param other +// CHECK:STDOUT: %other.loc14_24.2: C = bind_name other, %other.loc14_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc9_9.2: C](@impl.1.%other.loc9_18.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.1.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc14_14.3: C*](@impl.2.%other.loc14_24.2: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc17: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc18_12.2: init C = call %.loc18_12.1(%a.ref, %b.ref) to %.loc17 +// CHECK:STDOUT: return %.loc18_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%a: C*, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C* = name_ref a, %a +// CHECK:STDOUT: %.loc22_3.1: ref C = deref %a.ref +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc22_6.1: = bound_method %.loc22_3.1, %.1 +// CHECK:STDOUT: %.loc22_3.2: C* = addr_of %.loc22_3.1 +// CHECK:STDOUT: %.loc22_6.2: init () = call %.loc22_6.1(%.loc22_3.2, %b.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/binary_op.carbon.tmpl b/toolchain/check/testdata/operators/overloaded/binary_op.carbon.tmpl new file mode 100644 index 000000000000..1dc84d32c2f8 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/binary_op.carbon.tmpl @@ -0,0 +1,43 @@ +// 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 +// +// AUTOUPDATE + +HEADER + +// --- prelude.carbon + +package Core api; + +interface INTERFACE { + fn Op[self: Self](other: Self) -> Self; +} +interface INTERFACEAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.INTERFACE { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.INTERFACEAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a OP b; +} + +fn TestAssign(a: C*, b: C) { + *a OP= b; +} diff --git a/toolchain/check/testdata/operators/overloaded/bit_and.carbon b/toolchain/check/testdata/operators/overloaded/bit_and.carbon new file mode 100644 index 000000000000..3f69e2d06a2a --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/bit_and.carbon @@ -0,0 +1,290 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from binary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface BitAnd { + fn Op[self: Self](other: Self) -> Self; +} +interface BitAndAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.BitAnd { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.BitAndAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a & b; +} + +fn TestAssign(a: C*, b: C) { + *a &= b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @BitAnd [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @BitAnd, [template] +// CHECK:STDOUT: %.3: in BitAnd> = assoc_entity element0, @BitAnd.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @BitAndAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @BitAndAssign, [template] +// CHECK:STDOUT: %.7: in BitAndAssign> = assoc_entity element0, @BitAndAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .BitAnd = %BitAnd.decl +// CHECK:STDOUT: .BitAndAssign = %BitAndAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %BitAnd.decl: type = interface_decl @BitAnd [template = constants.%.1] {} +// CHECK:STDOUT: %BitAndAssign.decl: type = interface_decl @BitAndAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitAnd { +// CHECK:STDOUT: %Self: BitAnd = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: BitAnd = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: BitAnd = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: BitAnd = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in BitAnd> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitAndAssign { +// CHECK:STDOUT: %Self: BitAndAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: BitAndAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: BitAndAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in BitAndAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@BitAnd.%self.loc5_9.2: Self](@BitAnd.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @BitAndAssign.%self.loc8_14.3: Self*](@BitAndAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @BitAnd [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.7: type = interface_type @BitAndAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type C [template] +// CHECK:STDOUT: %.9: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @BitAnd, [template] +// CHECK:STDOUT: %.12: in BitAnd> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @BitAndAssign, [template] +// CHECK:STDOUT: %.14: in BitAndAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %BitAnd.decl: invalid = interface_decl @BitAnd [template = constants.%.2] {} +// CHECK:STDOUT: %BitAnd.ref: type = name_ref BitAnd, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc13: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %BitAndAssign.decl: invalid = interface_decl @BitAndAssign [template = constants.%.7] {} +// CHECK:STDOUT: %BitAndAssign.ref: type = name_ref BitAndAssign, %import_ref.2 [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc17_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc17_11.1 +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_17.1: C = param b +// CHECK:STDOUT: @TestOp.%b: C = bind_name b, %b.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %C.ref.loc21_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %a.loc21_15.1: C* = param a +// CHECK:STDOUT: @TestAssign.%a: C* = bind_name a, %a.loc21_15.1 +// CHECK:STDOUT: %C.ref.loc21_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc21_22.1: C = param b +// CHECK:STDOUT: @TestAssign.%b: C = bind_name b, %b.loc21_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitAnd { +// CHECK:STDOUT: %import_ref.1: in BitAnd> = import_ref ir1, inst+20, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitAndAssign { +// CHECK:STDOUT: %import_ref.1: in BitAndAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as BitAnd { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_18.1: C = param other +// CHECK:STDOUT: %other.loc9_18.2: C = bind_name other, %other.loc9_18.1 +// CHECK:STDOUT: %C.ref.loc9_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as BitAndAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14_21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %self.loc14_14.1: C* = param self +// CHECK:STDOUT: %self.loc14_14.3: C* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: C* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: %C.ref.loc14_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc14_24.1: C = param other +// CHECK:STDOUT: %other.loc14_24.2: C = bind_name other, %other.loc14_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc9_9.2: C](@impl.1.%other.loc9_18.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.1.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc14_14.3: C*](@impl.2.%other.loc14_24.2: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc17: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc18_12.2: init C = call %.loc18_12.1(%a.ref, %b.ref) to %.loc17 +// CHECK:STDOUT: return %.loc18_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%a: C*, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C* = name_ref a, %a +// CHECK:STDOUT: %.loc22_3.1: ref C = deref %a.ref +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc22_6.1: = bound_method %.loc22_3.1, %.1 +// CHECK:STDOUT: %.loc22_3.2: C* = addr_of %.loc22_3.1 +// CHECK:STDOUT: %.loc22_6.2: init () = call %.loc22_6.1(%.loc22_3.2, %b.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/bit_complement.carbon b/toolchain/check/testdata/operators/overloaded/bit_complement.carbon new file mode 100644 index 000000000000..d4cf3720ee5c --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/bit_complement.carbon @@ -0,0 +1,163 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from unary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface BitComplement { + fn Op[self: Self]() -> Self; +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.BitComplement { + fn Op[self: C]() -> C { + return {}; + } +} + +fn TestOp(a: C) -> C { + return ^a; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @BitComplement [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @BitComplement, [template] +// CHECK:STDOUT: %.3: in BitComplement> = assoc_entity element0, @BitComplement.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .BitComplement = %BitComplement.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %BitComplement.decl: type = interface_decl @BitComplement [template = constants.%.1] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitComplement { +// CHECK:STDOUT: %Self: BitComplement = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: BitComplement = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_26: BitComplement = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_26.1: type = facet_type_access %Self.ref.loc5_26 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_26.2: type = converted %Self.ref.loc5_26, %.loc5_26.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_30: in BitComplement> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_30 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op[@BitComplement.%self.loc5_9.2: Self]() -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @BitComplement [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.%Op) [template] +// CHECK:STDOUT: %.7: type = assoc_entity_type @BitComplement, [template] +// CHECK:STDOUT: %.8: in BitComplement> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %BitComplement.decl: invalid = interface_decl @BitComplement [template = constants.%.2] {} +// CHECK:STDOUT: %BitComplement.ref: type = name_ref BitComplement, %import_ref [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc14_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc14_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc14_11.1 +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitComplement { +// CHECK:STDOUT: %import_ref.1: in BitComplement> = import_ref ir1, inst+15, used [template = constants.%.8] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+13, used [template = imports.%Op] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: C as BitComplement { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_23: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.%self.loc9_9.2: C]() -> @impl.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self]() -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+13, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element0 [template = @impl.%Op] +// CHECK:STDOUT: %.loc15_10.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc14: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc15_10.2: init C = call %.loc15_10.1(%a.ref) to %.loc14 +// CHECK:STDOUT: return %.loc15_10.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/bit_or.carbon b/toolchain/check/testdata/operators/overloaded/bit_or.carbon new file mode 100644 index 000000000000..9981e8d04910 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/bit_or.carbon @@ -0,0 +1,290 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from binary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface BitOr { + fn Op[self: Self](other: Self) -> Self; +} +interface BitOrAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.BitOr { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.BitOrAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a | b; +} + +fn TestAssign(a: C*, b: C) { + *a |= b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @BitOr [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @BitOr, [template] +// CHECK:STDOUT: %.3: in BitOr> = assoc_entity element0, @BitOr.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @BitOrAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @BitOrAssign, [template] +// CHECK:STDOUT: %.7: in BitOrAssign> = assoc_entity element0, @BitOrAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .BitOr = %BitOr.decl +// CHECK:STDOUT: .BitOrAssign = %BitOrAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %BitOr.decl: type = interface_decl @BitOr [template = constants.%.1] {} +// CHECK:STDOUT: %BitOrAssign.decl: type = interface_decl @BitOrAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitOr { +// CHECK:STDOUT: %Self: BitOr = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: BitOr = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: BitOr = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: BitOr = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in BitOr> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitOrAssign { +// CHECK:STDOUT: %Self: BitOrAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: BitOrAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: BitOrAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in BitOrAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@BitOr.%self.loc5_9.2: Self](@BitOr.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @BitOrAssign.%self.loc8_14.3: Self*](@BitOrAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @BitOr [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.7: type = interface_type @BitOrAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type C [template] +// CHECK:STDOUT: %.9: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @BitOr, [template] +// CHECK:STDOUT: %.12: in BitOr> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @BitOrAssign, [template] +// CHECK:STDOUT: %.14: in BitOrAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %BitOr.decl: invalid = interface_decl @BitOr [template = constants.%.2] {} +// CHECK:STDOUT: %BitOr.ref: type = name_ref BitOr, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc13: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %BitOrAssign.decl: invalid = interface_decl @BitOrAssign [template = constants.%.7] {} +// CHECK:STDOUT: %BitOrAssign.ref: type = name_ref BitOrAssign, %import_ref.2 [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc17_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc17_11.1 +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_17.1: C = param b +// CHECK:STDOUT: @TestOp.%b: C = bind_name b, %b.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %C.ref.loc21_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %a.loc21_15.1: C* = param a +// CHECK:STDOUT: @TestAssign.%a: C* = bind_name a, %a.loc21_15.1 +// CHECK:STDOUT: %C.ref.loc21_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc21_22.1: C = param b +// CHECK:STDOUT: @TestAssign.%b: C = bind_name b, %b.loc21_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitOr { +// CHECK:STDOUT: %import_ref.1: in BitOr> = import_ref ir1, inst+20, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitOrAssign { +// CHECK:STDOUT: %import_ref.1: in BitOrAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as BitOr { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_18.1: C = param other +// CHECK:STDOUT: %other.loc9_18.2: C = bind_name other, %other.loc9_18.1 +// CHECK:STDOUT: %C.ref.loc9_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as BitOrAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14_21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %self.loc14_14.1: C* = param self +// CHECK:STDOUT: %self.loc14_14.3: C* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: C* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: %C.ref.loc14_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc14_24.1: C = param other +// CHECK:STDOUT: %other.loc14_24.2: C = bind_name other, %other.loc14_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc9_9.2: C](@impl.1.%other.loc9_18.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.1.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc14_14.3: C*](@impl.2.%other.loc14_24.2: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc17: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc18_12.2: init C = call %.loc18_12.1(%a.ref, %b.ref) to %.loc17 +// CHECK:STDOUT: return %.loc18_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%a: C*, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C* = name_ref a, %a +// CHECK:STDOUT: %.loc22_3.1: ref C = deref %a.ref +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc22_6.1: = bound_method %.loc22_3.1, %.1 +// CHECK:STDOUT: %.loc22_3.2: C* = addr_of %.loc22_3.1 +// CHECK:STDOUT: %.loc22_6.2: init () = call %.loc22_6.1(%.loc22_3.2, %b.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/bit_xor.carbon b/toolchain/check/testdata/operators/overloaded/bit_xor.carbon new file mode 100644 index 000000000000..3dea50fb9052 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/bit_xor.carbon @@ -0,0 +1,290 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from binary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface BitXor { + fn Op[self: Self](other: Self) -> Self; +} +interface BitXorAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.BitXor { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.BitXorAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a ^ b; +} + +fn TestAssign(a: C*, b: C) { + *a ^= b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @BitXor [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @BitXor, [template] +// CHECK:STDOUT: %.3: in BitXor> = assoc_entity element0, @BitXor.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @BitXorAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @BitXorAssign, [template] +// CHECK:STDOUT: %.7: in BitXorAssign> = assoc_entity element0, @BitXorAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .BitXor = %BitXor.decl +// CHECK:STDOUT: .BitXorAssign = %BitXorAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %BitXor.decl: type = interface_decl @BitXor [template = constants.%.1] {} +// CHECK:STDOUT: %BitXorAssign.decl: type = interface_decl @BitXorAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitXor { +// CHECK:STDOUT: %Self: BitXor = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: BitXor = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: BitXor = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: BitXor = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in BitXor> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitXorAssign { +// CHECK:STDOUT: %Self: BitXorAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: BitXorAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: BitXorAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in BitXorAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@BitXor.%self.loc5_9.2: Self](@BitXor.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @BitXorAssign.%self.loc8_14.3: Self*](@BitXorAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @BitXor [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.7: type = interface_type @BitXorAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type C [template] +// CHECK:STDOUT: %.9: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @BitXor, [template] +// CHECK:STDOUT: %.12: in BitXor> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @BitXorAssign, [template] +// CHECK:STDOUT: %.14: in BitXorAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %BitXor.decl: invalid = interface_decl @BitXor [template = constants.%.2] {} +// CHECK:STDOUT: %BitXor.ref: type = name_ref BitXor, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc13: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %BitXorAssign.decl: invalid = interface_decl @BitXorAssign [template = constants.%.7] {} +// CHECK:STDOUT: %BitXorAssign.ref: type = name_ref BitXorAssign, %import_ref.2 [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc17_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc17_11.1 +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_17.1: C = param b +// CHECK:STDOUT: @TestOp.%b: C = bind_name b, %b.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %C.ref.loc21_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %a.loc21_15.1: C* = param a +// CHECK:STDOUT: @TestAssign.%a: C* = bind_name a, %a.loc21_15.1 +// CHECK:STDOUT: %C.ref.loc21_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc21_22.1: C = param b +// CHECK:STDOUT: @TestAssign.%b: C = bind_name b, %b.loc21_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitXor { +// CHECK:STDOUT: %import_ref.1: in BitXor> = import_ref ir1, inst+20, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @BitXorAssign { +// CHECK:STDOUT: %import_ref.1: in BitXorAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as BitXor { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_18.1: C = param other +// CHECK:STDOUT: %other.loc9_18.2: C = bind_name other, %other.loc9_18.1 +// CHECK:STDOUT: %C.ref.loc9_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as BitXorAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14_21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %self.loc14_14.1: C* = param self +// CHECK:STDOUT: %self.loc14_14.3: C* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: C* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: %C.ref.loc14_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc14_24.1: C = param other +// CHECK:STDOUT: %other.loc14_24.2: C = bind_name other, %other.loc14_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc9_9.2: C](@impl.1.%other.loc9_18.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.1.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc14_14.3: C*](@impl.2.%other.loc14_24.2: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc17: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc18_12.2: init C = call %.loc18_12.1(%a.ref, %b.ref) to %.loc17 +// CHECK:STDOUT: return %.loc18_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%a: C*, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C* = name_ref a, %a +// CHECK:STDOUT: %.loc22_3.1: ref C = deref %a.ref +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc22_6.1: = bound_method %.loc22_3.1, %.1 +// CHECK:STDOUT: %.loc22_3.2: C* = addr_of %.loc22_3.1 +// CHECK:STDOUT: %.loc22_6.2: init () = call %.loc22_6.1(%.loc22_3.2, %b.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/dec.carbon b/toolchain/check/testdata/operators/overloaded/dec.carbon new file mode 100644 index 000000000000..d09e17e1b15f --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/dec.carbon @@ -0,0 +1,158 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from unary_stmt.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface Dec { + fn Op[addr self: Self*](); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Dec { + fn Op[addr self: C*](); +} + +fn TestOp() { + var c: C = {}; + --c; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Dec [template] +// CHECK:STDOUT: %.2: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.3: type = assoc_entity_type @Dec, [template] +// CHECK:STDOUT: %.4: in Dec> = assoc_entity element0, @Dec.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Dec = %Dec.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Dec.decl: type = interface_decl @Dec [template = constants.%.1] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Dec { +// CHECK:STDOUT: %Self: Dec = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op [template] { +// CHECK:STDOUT: %Self.ref: Dec = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_24.1: type = facet_type_access %Self.ref [symbolic = %Self] +// CHECK:STDOUT: %.loc5_20: type = converted %Self.ref, %.loc5_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_24.2: type = ptr_type Self [symbolic = constants.%.2] +// CHECK:STDOUT: %self.loc5_14.1: Self* = param self +// CHECK:STDOUT: %self.loc5_14.3: Self* = bind_name self, %self.loc5_14.1 +// CHECK:STDOUT: %.loc5_9: Self* = addr_pattern %self.loc5_14.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_28: in Dec> = assoc_entity element0, %Op [template = constants.%.4] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_28 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op[addr @Dec.%self.loc5_14.3: Self*](); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Dec [template] +// CHECK:STDOUT: %.3: type = ptr_type C [template] +// CHECK:STDOUT: %.4: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.5: = interface_witness (@impl.%Op) [template] +// CHECK:STDOUT: %.6: type = tuple_type () [template] +// CHECK:STDOUT: %.7: type = ptr_type {} [template] +// CHECK:STDOUT: %.8: C = struct_value () [template] +// CHECK:STDOUT: %.9: type = assoc_entity_type @Dec, [template] +// CHECK:STDOUT: %.10: in Dec> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl { +// CHECK:STDOUT: %C.ref: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Dec.decl: invalid = interface_decl @Dec [template = constants.%.2] {} +// CHECK:STDOUT: %Dec.ref: type = name_ref Dec, %import_ref [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Dec { +// CHECK:STDOUT: %import_ref.1: in Dec> = import_ref ir1, inst+14, used [template = constants.%.10] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+12, used [template = imports.%Op] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: C as Dec { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc9_21: type = ptr_type C [template = constants.%.3] +// CHECK:STDOUT: %self.loc9_14.1: C* = param self +// CHECK:STDOUT: %self.loc9_14.3: C* = bind_name self, %self.loc9_14.1 +// CHECK:STDOUT: %.loc9_9: C* = addr_pattern %self.loc9_14.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.5] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[addr @impl.%self.loc9_14.3: C*](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr %self: Self*](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %c.var: ref C = var c +// CHECK:STDOUT: %c: ref C = bind_name c, %c.var +// CHECK:STDOUT: %.loc13_15.1: {} = struct_literal () +// CHECK:STDOUT: %.loc13_15.2: init C = class_init (), %c.var [template = constants.%.8] +// CHECK:STDOUT: %.loc13_15.3: init C = converted %.loc13_15.1, %.loc13_15.2 [template = constants.%.8] +// CHECK:STDOUT: assign %c.var, %.loc13_15.3 +// CHECK:STDOUT: %c.ref: ref C = name_ref c, %c +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+12, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element0 [template = @impl.%Op] +// CHECK:STDOUT: %.loc14_3.1: = bound_method %c.ref, %.1 +// CHECK:STDOUT: %.loc14_5: C* = addr_of %c.ref +// CHECK:STDOUT: %.loc14_3.2: init () = call %.loc14_3.1(%.loc14_5) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/div.carbon b/toolchain/check/testdata/operators/overloaded/div.carbon new file mode 100644 index 000000000000..1de680612d5b --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/div.carbon @@ -0,0 +1,290 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from binary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface Div { + fn Op[self: Self](other: Self) -> Self; +} +interface DivAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Div { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.DivAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a / b; +} + +fn TestAssign(a: C*, b: C) { + *a /= b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Div [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Div, [template] +// CHECK:STDOUT: %.3: in Div> = assoc_entity element0, @Div.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @DivAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @DivAssign, [template] +// CHECK:STDOUT: %.7: in DivAssign> = assoc_entity element0, @DivAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Div = %Div.decl +// CHECK:STDOUT: .DivAssign = %DivAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Div.decl: type = interface_decl @Div [template = constants.%.1] {} +// CHECK:STDOUT: %DivAssign.decl: type = interface_decl @DivAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Div { +// CHECK:STDOUT: %Self: Div = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: Div = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: Div = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: Div = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in Div> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @DivAssign { +// CHECK:STDOUT: %Self: DivAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: DivAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: DivAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in DivAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@Div.%self.loc5_9.2: Self](@Div.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @DivAssign.%self.loc8_14.3: Self*](@DivAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Div [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.7: type = interface_type @DivAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type C [template] +// CHECK:STDOUT: %.9: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @Div, [template] +// CHECK:STDOUT: %.12: in Div> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @DivAssign, [template] +// CHECK:STDOUT: %.14: in DivAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Div.decl: invalid = interface_decl @Div [template = constants.%.2] {} +// CHECK:STDOUT: %Div.ref: type = name_ref Div, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc13: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %DivAssign.decl: invalid = interface_decl @DivAssign [template = constants.%.7] {} +// CHECK:STDOUT: %DivAssign.ref: type = name_ref DivAssign, %import_ref.2 [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc17_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc17_11.1 +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_17.1: C = param b +// CHECK:STDOUT: @TestOp.%b: C = bind_name b, %b.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %C.ref.loc21_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %a.loc21_15.1: C* = param a +// CHECK:STDOUT: @TestAssign.%a: C* = bind_name a, %a.loc21_15.1 +// CHECK:STDOUT: %C.ref.loc21_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc21_22.1: C = param b +// CHECK:STDOUT: @TestAssign.%b: C = bind_name b, %b.loc21_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Div { +// CHECK:STDOUT: %import_ref.1: in Div> = import_ref ir1, inst+20, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @DivAssign { +// CHECK:STDOUT: %import_ref.1: in DivAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as Div { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_18.1: C = param other +// CHECK:STDOUT: %other.loc9_18.2: C = bind_name other, %other.loc9_18.1 +// CHECK:STDOUT: %C.ref.loc9_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as DivAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14_21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %self.loc14_14.1: C* = param self +// CHECK:STDOUT: %self.loc14_14.3: C* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: C* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: %C.ref.loc14_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc14_24.1: C = param other +// CHECK:STDOUT: %other.loc14_24.2: C = bind_name other, %other.loc14_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc9_9.2: C](@impl.1.%other.loc9_18.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.1.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc14_14.3: C*](@impl.2.%other.loc14_24.2: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc17: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc18_12.2: init C = call %.loc18_12.1(%a.ref, %b.ref) to %.loc17 +// CHECK:STDOUT: return %.loc18_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%a: C*, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C* = name_ref a, %a +// CHECK:STDOUT: %.loc22_3.1: ref C = deref %a.ref +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc22_6.1: = bound_method %.loc22_3.1, %.1 +// CHECK:STDOUT: %.loc22_3.2: C* = addr_of %.loc22_3.1 +// CHECK:STDOUT: %.loc22_6.2: init () = call %.loc22_6.1(%.loc22_3.2, %b.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/eq.carbon b/toolchain/check/testdata/operators/overloaded/eq.carbon new file mode 100644 index 000000000000..bcc55e90a6fa --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/eq.carbon @@ -0,0 +1,494 @@ +// 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 +// +// AUTOUPDATE + +// --- prelude.carbon + +package Core api; + +interface Eq { + fn Equal[self: Self](other: Self) -> bool; + fn NotEqual[self: Self](other: Self) -> bool; +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Eq { + fn Equal[self: C](other: C) -> bool; + fn NotEqual[self: C](other: C) -> bool; +} + +fn TestEqual(a: C, b: C) -> bool { + return a == b; +} + +fn TestNotEqual(a: C, b: C) -> bool { + return a != b; +} + +// --- fail_no_impl.carbon + +package FailNoImpl api; + +import Core; + +class D {}; + +fn TestEqual(a: D, b: D) -> bool { + // CHECK:STDERR: fail_no_impl.carbon:[[@LINE+3]]:10: ERROR: Cannot access member of interface Eq in type D that does not implement that interface. + // CHECK:STDERR: return a == b; + // CHECK:STDERR: ^~~~~~ + return a == b; +} + +fn TestNotEqual(a: D, b: D) -> bool { + // CHECK:STDERR: fail_no_impl.carbon:[[@LINE+3]]:10: ERROR: Cannot access member of interface Eq in type D that does not implement that interface. + // CHECK:STDERR: return a != b; + // CHECK:STDERR: ^~~~~~ + return a != b; +} + +// --- fail_no_impl_for_args.carbon + +package FailNoImplForArgs api; + +import Core; + +class C {}; +class D {}; + +impl C as Core.Eq { + fn Equal[self: C](other: C) -> bool; + fn NotEqual[self: C](other: C) -> bool; +} + +fn TestRhsBad(a: C, b: D) -> bool { + // CHECK:STDERR: fail_no_impl_for_args.carbon:[[@LINE+6]]:10: ERROR: Cannot implicitly convert from `D` to `C`. + // CHECK:STDERR: return a == b; + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_no_impl_for_args.carbon:[[@LINE-8]]:3: Initializing parameter 1 of function declared here. + // CHECK:STDERR: fn Equal[self: C](other: C) -> bool; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + return a == b; +} + +fn TestLhsBad(a: D, b: C) -> bool { + // CHECK:STDERR: fail_no_impl_for_args.carbon:[[@LINE+3]]:10: ERROR: Cannot access member of interface Eq in type D that does not implement that interface. + // CHECK:STDERR: return a != b; + // CHECK:STDERR: ^~~~~~ + return a != b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Eq [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Eq, [template] +// CHECK:STDOUT: %.3: in Eq> = assoc_entity element0, @Eq.%Equal [template] +// CHECK:STDOUT: %.4: in Eq> = assoc_entity element1, @Eq.%NotEqual [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Eq = %Eq.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Eq.decl: type = interface_decl @Eq [template = constants.%.1] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Eq { +// CHECK:STDOUT: %Self: Eq = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Equal: = fn_decl @Equal [template] { +// CHECK:STDOUT: %Self.ref.loc5_18: Eq = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_18.1: type = facet_type_access %Self.ref.loc5_18 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_18.2: type = converted %Self.ref.loc5_18, %.loc5_18.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_12.1: Self = param self +// CHECK:STDOUT: %self.loc5_12.2: Self = bind_name self, %self.loc5_12.1 +// CHECK:STDOUT: %Self.ref.loc5_31: Eq = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_31.1: type = facet_type_access %Self.ref.loc5_31 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_31.2: type = converted %Self.ref.loc5_31, %.loc5_31.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_24.1: Self = param other +// CHECK:STDOUT: %other.loc5_24.2: Self = bind_name other, %other.loc5_24.1 +// CHECK:STDOUT: %return.var.loc5: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_44: in Eq> = assoc_entity element0, %Equal [template = constants.%.3] +// CHECK:STDOUT: %NotEqual: = fn_decl @NotEqual [template] { +// CHECK:STDOUT: %Self.ref.loc6_21: Eq = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc6_21.1: type = facet_type_access %Self.ref.loc6_21 [symbolic = %Self] +// CHECK:STDOUT: %.loc6_21.2: type = converted %Self.ref.loc6_21, %.loc6_21.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc6_15.1: Self = param self +// CHECK:STDOUT: %self.loc6_15.2: Self = bind_name self, %self.loc6_15.1 +// CHECK:STDOUT: %Self.ref.loc6_34: Eq = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc6_34.1: type = facet_type_access %Self.ref.loc6_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc6_34.2: type = converted %Self.ref.loc6_34, %.loc6_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc6_27.1: Self = param other +// CHECK:STDOUT: %other.loc6_27.2: Self = bind_name other, %other.loc6_27.1 +// CHECK:STDOUT: %return.var.loc6: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc6_47: in Eq> = assoc_entity element1, %NotEqual [template = constants.%.4] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Equal = %.loc5_44 +// CHECK:STDOUT: .NotEqual = %.loc6_47 +// CHECK:STDOUT: witness = (%Equal, %NotEqual) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Equal[@Eq.%self.loc5_12.2: Self](@Eq.%other.loc5_24.2: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @NotEqual[@Eq.%self.loc6_15.2: Self](@Eq.%other.loc6_27.2: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Eq [template] +// CHECK:STDOUT: %.3: = interface_witness (@impl.%Equal, @impl.%NotEqual) [template] +// CHECK:STDOUT: %.4: type = tuple_type () [template] +// CHECK:STDOUT: %.5: type = ptr_type {} [template] +// CHECK:STDOUT: %.6: type = assoc_entity_type @Eq, [template] +// CHECK:STDOUT: %.7: in Eq> = assoc_entity element0, @TestEqual.%import_ref.2 [template] +// CHECK:STDOUT: %.8: in Eq> = assoc_entity element1, @TestNotEqual.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestEqual = %TestEqual +// CHECK:STDOUT: .TestNotEqual = %TestNotEqual +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Eq.decl: invalid = interface_decl @Eq [template = constants.%.2] {} +// CHECK:STDOUT: %Eq.ref: type = name_ref Eq, %import_ref [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestEqual: = fn_decl @TestEqual [template] { +// CHECK:STDOUT: %C.ref.loc13_17: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc13_14.1: C = param a +// CHECK:STDOUT: @TestEqual.%a: C = bind_name a, %a.loc13_14.1 +// CHECK:STDOUT: %C.ref.loc13_23: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc13_20.1: C = param b +// CHECK:STDOUT: @TestEqual.%b: C = bind_name b, %b.loc13_20.1 +// CHECK:STDOUT: %return.var.loc13: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestNotEqual: = fn_decl @TestNotEqual [template] { +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_17.1: C = param a +// CHECK:STDOUT: @TestNotEqual.%a: C = bind_name a, %a.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_23.1: C = param b +// CHECK:STDOUT: @TestNotEqual.%b: C = bind_name b, %b.loc17_23.1 +// CHECK:STDOUT: %return.var.loc17: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Eq { +// CHECK:STDOUT: %import_ref.1: in Eq> = import_ref ir1, inst+17, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: in Eq> = import_ref ir1, inst+31, used [template = constants.%.8] +// CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+15, used [template = imports.%Equal] +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+30, used [template = imports.%NotEqual] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Equal = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: .NotEqual = %import_ref.3 +// CHECK:STDOUT: witness = (%import_ref.4, %import_ref.5) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: C as Eq { +// CHECK:STDOUT: %Equal: = fn_decl @Equal.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_18: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_12.1: C = param self +// CHECK:STDOUT: %self.loc9_12.2: C = bind_name self, %self.loc9_12.1 +// CHECK:STDOUT: %C.ref.loc9_28: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_21.1: C = param other +// CHECK:STDOUT: %other.loc9_21.2: C = bind_name other, %other.loc9_21.1 +// CHECK:STDOUT: %return.var.loc9: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %NotEqual: = fn_decl @NotEqual.1 [template] { +// CHECK:STDOUT: %C.ref.loc10_21: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc10_15.1: C = param self +// CHECK:STDOUT: %self.loc10_15.2: C = bind_name self, %self.loc10_15.1 +// CHECK:STDOUT: %C.ref.loc10_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc10_24.1: C = param other +// CHECK:STDOUT: %other.loc10_24.2: C = bind_name other, %other.loc10_24.1 +// CHECK:STDOUT: %return.var.loc10: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Equal, %NotEqual) [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Equal = %Equal +// CHECK:STDOUT: .NotEqual = %NotEqual +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Equal.1[@impl.%self.loc9_12.2: C](@impl.%other.loc9_21.2: C) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @NotEqual.1[@impl.%self.loc10_15.2: C](@impl.%other.loc10_24.2: C) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Equal.2[%self: Self](%other: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @NotEqual.2[%self: Self](%other: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestEqual(%a: C, %b: C) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+15, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element0 [template = @impl.%Equal] +// CHECK:STDOUT: %.loc14_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc14_12.2: init bool = call %.loc14_12.1(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc14_16: bool = value_of_initializer %.loc14_12.2 +// CHECK:STDOUT: %.loc14_12.3: bool = converted %.loc14_12.2, %.loc14_16 +// CHECK:STDOUT: return %.loc14_12.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestNotEqual(%a: C, %b: C) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+30, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element1 [template = @impl.%NotEqual] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc18_12.2: init bool = call %.loc18_12.1(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc18_16: bool = value_of_initializer %.loc18_12.2 +// CHECK:STDOUT: %.loc18_12.3: bool = converted %.loc18_12.2, %.loc18_16 +// CHECK:STDOUT: return %.loc18_12.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_no_impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %D: type = class_type @D [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: %.4: type = interface_type @Eq [template] +// CHECK:STDOUT: %.5: type = assoc_entity_type @Eq, [template] +// CHECK:STDOUT: %.6: in Eq> = assoc_entity element0, @TestEqual.%import_ref.2 [template] +// CHECK:STDOUT: %.7: in Eq> = assoc_entity element1, @TestNotEqual.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .D = %D.decl +// CHECK:STDOUT: .TestEqual = %TestEqual +// CHECK:STDOUT: .TestNotEqual = %TestNotEqual +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %D.decl: type = class_decl @D [template = constants.%D] {} +// CHECK:STDOUT: %TestEqual: = fn_decl @TestEqual [template] { +// CHECK:STDOUT: %D.ref.loc8_17: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %a.loc8_14.1: D = param a +// CHECK:STDOUT: @TestEqual.%a: D = bind_name a, %a.loc8_14.1 +// CHECK:STDOUT: %D.ref.loc8_23: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %b.loc8_20.1: D = param b +// CHECK:STDOUT: @TestEqual.%b: D = bind_name b, %b.loc8_20.1 +// CHECK:STDOUT: %return.var.loc8: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestNotEqual: = fn_decl @TestNotEqual [template] { +// CHECK:STDOUT: %D.ref.loc15_20: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %a.loc15_17.1: D = param a +// CHECK:STDOUT: @TestNotEqual.%a: D = bind_name a, %a.loc15_17.1 +// CHECK:STDOUT: %D.ref.loc15_26: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %b.loc15_23.1: D = param b +// CHECK:STDOUT: @TestNotEqual.%b: D = bind_name b, %b.loc15_23.1 +// CHECK:STDOUT: %return.var.loc15: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Eq { +// CHECK:STDOUT: %import_ref.1: in Eq> = import_ref ir1, inst+17, used [template = constants.%.6] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: in Eq> = import_ref ir1, inst+31, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+15, unused +// CHECK:STDOUT: %import_ref.5 = import_ref ir1, inst+30, unused +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Equal = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: .NotEqual = %import_ref.3 +// CHECK:STDOUT: witness = (%import_ref.4, %import_ref.5) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @D { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%D +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestEqual(%a: D, %b: D) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: D = name_ref a, %a +// CHECK:STDOUT: %b.ref: D = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.4] +// CHECK:STDOUT: %Eq.decl: invalid = interface_decl @Eq [template = constants.%.4] {} +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+15, unused +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestNotEqual(%a: D, %b: D) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: D = name_ref a, %a +// CHECK:STDOUT: %b.ref: D = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.4] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+30, unused +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_no_impl_for_args.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %D: type = class_type @D [template] +// CHECK:STDOUT: %.2: type = interface_type @Eq [template] +// CHECK:STDOUT: %.3: = interface_witness (@impl.%Equal, @impl.%NotEqual) [template] +// CHECK:STDOUT: %.4: type = tuple_type () [template] +// CHECK:STDOUT: %.5: type = ptr_type {} [template] +// CHECK:STDOUT: %.6: type = assoc_entity_type @Eq, [template] +// CHECK:STDOUT: %.7: in Eq> = assoc_entity element0, @TestRhsBad.%import_ref.2 [template] +// CHECK:STDOUT: %.8: in Eq> = assoc_entity element1, @TestLhsBad.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .D = %D.decl +// CHECK:STDOUT: .TestRhsBad = %TestRhsBad +// CHECK:STDOUT: .TestLhsBad = %TestLhsBad +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: %D.decl: type = class_decl @D [template = constants.%D] {} +// CHECK:STDOUT: impl_decl @impl { +// CHECK:STDOUT: %C.ref.loc9: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Eq.decl: invalid = interface_decl @Eq [template = constants.%.2] {} +// CHECK:STDOUT: %Eq.ref: type = name_ref Eq, %import_ref [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestRhsBad: = fn_decl @TestRhsBad [template] { +// CHECK:STDOUT: %C.ref.loc14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc14_15.1: C = param a +// CHECK:STDOUT: @TestRhsBad.%a: C = bind_name a, %a.loc14_15.1 +// CHECK:STDOUT: %D.ref.loc14: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %b.loc14_21.1: D = param b +// CHECK:STDOUT: @TestRhsBad.%b: D = bind_name b, %b.loc14_21.1 +// CHECK:STDOUT: %return.var.loc14: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestLhsBad: = fn_decl @TestLhsBad [template] { +// CHECK:STDOUT: %D.ref.loc24: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %a.loc24_15.1: D = param a +// CHECK:STDOUT: @TestLhsBad.%a: D = bind_name a, %a.loc24_15.1 +// CHECK:STDOUT: %C.ref.loc24: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc24_21.1: C = param b +// CHECK:STDOUT: @TestLhsBad.%b: C = bind_name b, %b.loc24_21.1 +// CHECK:STDOUT: %return.var.loc24: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Eq { +// CHECK:STDOUT: %import_ref.1: in Eq> = import_ref ir1, inst+17, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: in Eq> = import_ref ir1, inst+31, used [template = constants.%.8] +// CHECK:STDOUT: %import_ref.4: = import_ref ir1, inst+15, used [template = imports.%Equal] +// CHECK:STDOUT: %import_ref.5: = import_ref ir1, inst+30, used [template = imports.%NotEqual] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Equal = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: .NotEqual = %import_ref.3 +// CHECK:STDOUT: witness = (%import_ref.4, %import_ref.5) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: C as Eq { +// CHECK:STDOUT: %Equal: = fn_decl @Equal.1 [template] { +// CHECK:STDOUT: %C.ref.loc10_18: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc10_12.1: C = param self +// CHECK:STDOUT: %self.loc10_12.2: C = bind_name self, %self.loc10_12.1 +// CHECK:STDOUT: %C.ref.loc10_28: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc10_21.1: C = param other +// CHECK:STDOUT: %other.loc10_21.2: C = bind_name other, %other.loc10_21.1 +// CHECK:STDOUT: %return.var.loc10: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %NotEqual: = fn_decl @NotEqual.1 [template] { +// CHECK:STDOUT: %C.ref.loc11_21: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc11_15.1: C = param self +// CHECK:STDOUT: %self.loc11_15.2: C = bind_name self, %self.loc11_15.1 +// CHECK:STDOUT: %C.ref.loc11_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc11_24.1: C = param other +// CHECK:STDOUT: %other.loc11_24.2: C = bind_name other, %other.loc11_24.1 +// CHECK:STDOUT: %return.var.loc11: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Equal, %NotEqual) [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Equal = %Equal +// CHECK:STDOUT: .NotEqual = %NotEqual +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @D { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%D +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Equal.1[@impl.%self.loc10_12.2: C](@impl.%other.loc10_21.2: C) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @NotEqual.1[@impl.%self.loc11_15.2: C](@impl.%other.loc11_24.2: C) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Equal.2[%self: Self](%other: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @NotEqual.2[%self: Self](%other: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestRhsBad(%a: C, %b: D) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: D = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+15, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element0 [template = @impl.%Equal] +// CHECK:STDOUT: %.loc21_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc21_12.2: init bool = call %.loc21_12.1() +// CHECK:STDOUT: %.loc21_16: bool = value_of_initializer %.loc21_12.2 +// CHECK:STDOUT: %.loc21_12.3: bool = converted %.loc21_12.2, %.loc21_16 +// CHECK:STDOUT: return %.loc21_12.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestLhsBad(%a: D, %b: C) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: D = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+30, unused +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon b/toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon new file mode 100644 index 000000000000..6def544f25c1 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/fail_assign_non_ref.carbon @@ -0,0 +1,270 @@ +// 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 +// +// AUTOUPDATE + +// --- prelude.carbon + +package Core api; + +interface Inc { + fn Op[addr self: Self*](); +} +interface AddAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- fail_assign_non_ref.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Inc { + fn Op[addr self: C*](); +} +impl C as Core.AddAssign { + fn Op[addr self: C*](other: C); +} + +fn TestIncNonRef(a: C) { + // CHECK:STDERR: fail_assign_non_ref.carbon:[[@LINE+6]]:3: ERROR: `addr self` method cannot be invoked on a value. + // CHECK:STDERR: ++a; + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_assign_non_ref.carbon:[[@LINE-10]]:14: Initializing `addr self` parameter of method declared here. + // CHECK:STDERR: fn Op[addr self: C*](); + // CHECK:STDERR: ^~~~ + ++a; +} + +fn TestAddAssignNonRef(a: C, b: C) { + // CHECK:STDERR: fail_assign_non_ref.carbon:[[@LINE+6]]:5: ERROR: `addr self` method cannot be invoked on a value. + // CHECK:STDERR: a += b; + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_assign_non_ref.carbon:[[@LINE-17]]:14: Initializing `addr self` parameter of method declared here. + // CHECK:STDERR: fn Op[addr self: C*](other: C); + // CHECK:STDERR: ^~~~ + a += b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Inc [template] +// CHECK:STDOUT: %.2: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.3: type = assoc_entity_type @Inc, [template] +// CHECK:STDOUT: %.4: in Inc> = assoc_entity element0, @Inc.%Op [template] +// CHECK:STDOUT: %.5: type = interface_type @AddAssign [template] +// CHECK:STDOUT: %.6: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.7: type = assoc_entity_type @AddAssign, [template] +// CHECK:STDOUT: %.8: in AddAssign> = assoc_entity element0, @AddAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Inc = %Inc.decl +// CHECK:STDOUT: .AddAssign = %AddAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Inc.decl: type = interface_decl @Inc [template = constants.%.1] {} +// CHECK:STDOUT: %AddAssign.decl: type = interface_decl @AddAssign [template = constants.%.5] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Inc { +// CHECK:STDOUT: %Self: Inc = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref: Inc = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_24.1: type = facet_type_access %Self.ref [symbolic = %Self] +// CHECK:STDOUT: %.loc5_20: type = converted %Self.ref, %.loc5_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_24.2: type = ptr_type Self [symbolic = constants.%.2] +// CHECK:STDOUT: %self.loc5_14.1: Self* = param self +// CHECK:STDOUT: %self.loc5_14.3: Self* = bind_name self, %self.loc5_14.1 +// CHECK:STDOUT: %.loc5_9: Self* = addr_pattern %self.loc5_14.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_28: in Inc> = assoc_entity element0, %Op [template = constants.%.4] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_28 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @AddAssign { +// CHECK:STDOUT: %Self: AddAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: AddAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.6] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: AddAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in AddAssign> = assoc_entity element0, %Op [template = constants.%.8] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[addr @Inc.%self.loc5_14.3: Self*](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @AddAssign.%self.loc8_14.3: Self*](@AddAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_assign_non_ref.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Inc [template] +// CHECK:STDOUT: %.3: type = ptr_type C [template] +// CHECK:STDOUT: %.4: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.5: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.6: type = interface_type @AddAssign [template] +// CHECK:STDOUT: %.7: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.8: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.9: type = tuple_type () [template] +// CHECK:STDOUT: %.10: type = ptr_type {} [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @Inc, [template] +// CHECK:STDOUT: %.12: in Inc> = assoc_entity element0, @TestIncNonRef.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @AddAssign, [template] +// CHECK:STDOUT: %.14: in AddAssign> = assoc_entity element0, @TestAddAssignNonRef.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestIncNonRef = %TestIncNonRef +// CHECK:STDOUT: .TestAddAssignNonRef = %TestAddAssignNonRef +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Inc.decl: invalid = interface_decl @Inc [template = constants.%.2] {} +// CHECK:STDOUT: %Inc.ref: type = name_ref Inc, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc11: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc11: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+16, used [template = constants.%.6] +// CHECK:STDOUT: %AddAssign.decl: invalid = interface_decl @AddAssign [template = constants.%.6] {} +// CHECK:STDOUT: %AddAssign.ref: type = name_ref AddAssign, %import_ref.2 [template = constants.%.6] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestIncNonRef: = fn_decl @TestIncNonRef [template] { +// CHECK:STDOUT: %C.ref.loc15: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc15_18.1: C = param a +// CHECK:STDOUT: @TestIncNonRef.%a: C = bind_name a, %a.loc15_18.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAddAssignNonRef: = fn_decl @TestAddAssignNonRef [template] { +// CHECK:STDOUT: %C.ref.loc25_27: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc25_24.1: C = param a +// CHECK:STDOUT: @TestAddAssignNonRef.%a: C = bind_name a, %a.loc25_24.1 +// CHECK:STDOUT: %C.ref.loc25_33: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc25_30.1: C = param b +// CHECK:STDOUT: @TestAddAssignNonRef.%b: C = bind_name b, %b.loc25_30.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Inc { +// CHECK:STDOUT: %import_ref.1: in Inc> = import_ref ir1, inst+14, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+12, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @AddAssign { +// CHECK:STDOUT: %import_ref.1: in AddAssign> = import_ref ir1, inst+34, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+32, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as Inc { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc9_21: type = ptr_type C [template = constants.%.3] +// CHECK:STDOUT: %self.loc9_14.1: C* = param self +// CHECK:STDOUT: %self.loc9_14.3: C* = bind_name self, %self.loc9_14.1 +// CHECK:STDOUT: %.loc9_9: C* = addr_pattern %self.loc9_14.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.5] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as AddAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc12_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc12_21: type = ptr_type C [template = constants.%.3] +// CHECK:STDOUT: %self.loc12_14.1: C* = param self +// CHECK:STDOUT: %self.loc12_14.3: C* = bind_name self, %self.loc12_14.1 +// CHECK:STDOUT: %.loc12_9: C* = addr_pattern %self.loc12_14.3 +// CHECK:STDOUT: %C.ref.loc12_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc12_24.1: C = param other +// CHECK:STDOUT: %other.loc12_24.2: C = bind_name other, %other.loc12_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.8] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[addr @impl.1.%self.loc9_14.3: C*](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr %self: Self*](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc12_14.3: C*](@impl.2.%other.loc12_24.2: C); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestIncNonRef(%a: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+12, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc22_3.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc22_3.2: init () = call %.loc22_3.1() +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAddAssignNonRef(%a: C, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+16, used [template = constants.%.6] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+32, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc32_5.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc32_5.2: init () = call %.loc32_5.1() +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon b/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon new file mode 100644 index 000000000000..e6ed439945fa --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/fail_no_impl.carbon @@ -0,0 +1,328 @@ +// 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 +// +// AUTOUPDATE + +// --- prelude.carbon + +package Core api; + +interface Negate { + fn Op[self: Self](); +} +interface Add { + fn Op[self: Self](other: Self) -> Self; +} +interface AddAssign { + fn Op[addr self: Self*](other: Self); +} +interface Inc { + fn Op[addr self: Self*](); +} + +// --- fail_no_impl.carbon + +package User api; + +import Core; + +class C {}; + +fn TestUnary(a: C) -> C { + // CHECK:STDERR: fail_no_impl.carbon:[[@LINE+3]]:10: ERROR: Cannot access member of interface Negate in type C that does not implement that interface. + // CHECK:STDERR: return -a; + // CHECK:STDERR: ^~ + return -a; +} + +fn TestBinary(a: C, b: C) -> C { + // CHECK:STDERR: fail_no_impl.carbon:[[@LINE+3]]:10: ERROR: Cannot access member of interface Add in type C that does not implement that interface. + // CHECK:STDERR: return a + b; + // CHECK:STDERR: ^~~~~ + return a + b; +} + +fn TestRef(b: C) { + var a: C = {}; + // CHECK:STDERR: fail_no_impl.carbon:[[@LINE+3]]:3: ERROR: Cannot access member of interface AddAssign in type C that does not implement that interface. + // CHECK:STDERR: a += b; + // CHECK:STDERR: ^~~~~~ + a += b; + // CHECK:STDERR: fail_no_impl.carbon:[[@LINE+3]]:3: ERROR: Cannot access member of interface Inc in type C that does not implement that interface. + // CHECK:STDERR: ++a; + // CHECK:STDERR: ^~~ + ++a; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Negate [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Negate, [template] +// CHECK:STDOUT: %.3: in Negate> = assoc_entity element0, @Negate.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @Add [template] +// CHECK:STDOUT: %.5: type = assoc_entity_type @Add, [template] +// CHECK:STDOUT: %.6: in Add> = assoc_entity element0, @Add.%Op [template] +// CHECK:STDOUT: %.7: type = interface_type @AddAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.9: type = assoc_entity_type @AddAssign, [template] +// CHECK:STDOUT: %.10: in AddAssign> = assoc_entity element0, @AddAssign.%Op [template] +// CHECK:STDOUT: %.11: type = interface_type @Inc [template] +// CHECK:STDOUT: %.12: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.13: type = assoc_entity_type @Inc, [template] +// CHECK:STDOUT: %.14: in Inc> = assoc_entity element0, @Inc.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Negate = %Negate.decl +// CHECK:STDOUT: .Add = %Add.decl +// CHECK:STDOUT: .AddAssign = %AddAssign.decl +// CHECK:STDOUT: .Inc = %Inc.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate.decl: type = interface_decl @Negate [template = constants.%.1] {} +// CHECK:STDOUT: %Add.decl: type = interface_decl @Add [template = constants.%.4] {} +// CHECK:STDOUT: %AddAssign.decl: type = interface_decl @AddAssign [template = constants.%.7] {} +// CHECK:STDOUT: %Inc.decl: type = interface_decl @Inc [template = constants.%.11] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Negate { +// CHECK:STDOUT: %Self: Negate = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref: Negate = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_22: in Negate> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_22 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Add { +// CHECK:STDOUT: %Self: Add = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_15: Add = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_15.1: type = facet_type_access %Self.ref.loc8_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_15.2: type = converted %Self.ref.loc8_15, %.loc8_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc8_9.1: Self = param self +// CHECK:STDOUT: %self.loc8_9.2: Self = bind_name self, %self.loc8_9.1 +// CHECK:STDOUT: %Self.ref.loc8_28: Add = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_28.1: type = facet_type_access %Self.ref.loc8_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_28.2: type = converted %Self.ref.loc8_28, %.loc8_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_21.1: Self = param other +// CHECK:STDOUT: %other.loc8_21.2: Self = bind_name other, %other.loc8_21.1 +// CHECK:STDOUT: %Self.ref.loc8_37: Add = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_37.1: type = facet_type_access %Self.ref.loc8_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_37.2: type = converted %Self.ref.loc8_37, %.loc8_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_41: in Add> = assoc_entity element0, %Op [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @AddAssign { +// CHECK:STDOUT: %Self: AddAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %Self.ref.loc11_20: AddAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc11_24.1: type = facet_type_access %Self.ref.loc11_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc11_20: type = converted %Self.ref.loc11_20, %.loc11_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc11_24.2: type = ptr_type Self [symbolic = constants.%.8] +// CHECK:STDOUT: %self.loc11_14.1: Self* = param self +// CHECK:STDOUT: %self.loc11_14.3: Self* = bind_name self, %self.loc11_14.1 +// CHECK:STDOUT: %.loc11_9: Self* = addr_pattern %self.loc11_14.3 +// CHECK:STDOUT: %Self.ref.loc11_34: AddAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc11_34.1: type = facet_type_access %Self.ref.loc11_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc11_34.2: type = converted %Self.ref.loc11_34, %.loc11_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc11_27.1: Self = param other +// CHECK:STDOUT: %other.loc11_27.2: Self = bind_name other, %other.loc11_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc11_39: in AddAssign> = assoc_entity element0, %Op [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc11_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Inc { +// CHECK:STDOUT: %Self: Inc = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.4 [template] { +// CHECK:STDOUT: %Self.ref: Inc = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc14_24.1: type = facet_type_access %Self.ref [symbolic = %Self] +// CHECK:STDOUT: %.loc14_20: type = converted %Self.ref, %.loc14_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc14_24.2: type = ptr_type Self [symbolic = constants.%.12] +// CHECK:STDOUT: %self.loc14_14.1: Self* = param self +// CHECK:STDOUT: %self.loc14_14.3: Self* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: Self* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc14_28: in Inc> = assoc_entity element0, %Op [template = constants.%.14] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc14_28 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@Negate.%self.loc5_9.2: Self](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[@Add.%self.loc8_9.2: Self](@Add.%other.loc8_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @AddAssign.%self.loc11_14.3: Self*](@AddAssign.%other.loc11_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr @Inc.%self.loc14_14.3: Self*](); +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_no_impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: %.4: type = interface_type @Negate [template] +// CHECK:STDOUT: %.5: type = assoc_entity_type @Negate, [template] +// CHECK:STDOUT: %.6: in Negate> = assoc_entity element0, @TestUnary.%import_ref.2 [template] +// CHECK:STDOUT: %.7: type = interface_type @Add [template] +// CHECK:STDOUT: %.8: type = assoc_entity_type @Add, [template] +// CHECK:STDOUT: %.9: in Add> = assoc_entity element0, @TestBinary.%import_ref.2 [template] +// CHECK:STDOUT: %.10: C = struct_value () [template] +// CHECK:STDOUT: %.11: type = interface_type @AddAssign [template] +// CHECK:STDOUT: %.12: type = assoc_entity_type @AddAssign, [template] +// CHECK:STDOUT: %.13: in AddAssign> = assoc_entity element0, @TestRef.%import_ref.2 [template] +// CHECK:STDOUT: %.14: type = interface_type @Inc [template] +// CHECK:STDOUT: %.15: type = assoc_entity_type @Inc, [template] +// CHECK:STDOUT: %.16: in Inc> = assoc_entity element0, @TestRef.%import_ref.4 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestUnary = %TestUnary +// CHECK:STDOUT: .TestBinary = %TestBinary +// CHECK:STDOUT: .TestRef = %TestRef +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: %TestUnary: = fn_decl @TestUnary [template] { +// CHECK:STDOUT: %C.ref.loc8_17: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc8_14.1: C = param a +// CHECK:STDOUT: @TestUnary.%a: C = bind_name a, %a.loc8_14.1 +// CHECK:STDOUT: %C.ref.loc8_23: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestUnary.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestBinary: = fn_decl @TestBinary [template] { +// CHECK:STDOUT: %C.ref.loc15_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc15_15.1: C = param a +// CHECK:STDOUT: @TestBinary.%a: C = bind_name a, %a.loc15_15.1 +// CHECK:STDOUT: %C.ref.loc15_24: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc15_21.1: C = param b +// CHECK:STDOUT: @TestBinary.%b: C = bind_name b, %b.loc15_21.1 +// CHECK:STDOUT: %C.ref.loc15_30: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestBinary.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestRef: = fn_decl @TestRef [template] { +// CHECK:STDOUT: %C.ref.loc22: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc22_12.1: C = param b +// CHECK:STDOUT: @TestRef.%b: C = bind_name b, %b.loc22_12.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Negate { +// CHECK:STDOUT: %import_ref.1: in Negate> = import_ref ir1, inst+11, used [template = constants.%.6] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+9, unused +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Add { +// CHECK:STDOUT: %import_ref.1: in Add> = import_ref ir1, inst+32, used [template = constants.%.9] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+15, unused +// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+30, unused +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @AddAssign { +// CHECK:STDOUT: %import_ref.1: in AddAssign> = import_ref ir1, inst+52, used [template = constants.%.13] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+36, unused +// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+50, unused +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Inc { +// CHECK:STDOUT: %import_ref.1: in Inc> = import_ref ir1, inst+67, used [template = constants.%.16] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+56, unused +// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+65, unused +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestUnary(%a: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.4] +// CHECK:STDOUT: %Negate.decl: invalid = interface_decl @Negate [template = constants.%.4] {} +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+9, unused +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestBinary(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+13, used [template = constants.%.7] +// CHECK:STDOUT: %Add.decl: invalid = interface_decl @Add [template = constants.%.7] {} +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+30, unused +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestRef(%b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %a.var: ref C = var a +// CHECK:STDOUT: %a: ref C = bind_name a, %a.var +// CHECK:STDOUT: %.loc23_15.1: {} = struct_literal () +// CHECK:STDOUT: %.loc23_15.2: init C = class_init (), %a.var [template = constants.%.10] +// CHECK:STDOUT: %.loc23_15.3: init C = converted %.loc23_15.1, %.loc23_15.2 [template = constants.%.10] +// CHECK:STDOUT: assign %a.var, %.loc23_15.3 +// CHECK:STDOUT: %a.ref.loc27: ref C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+34, used [template = constants.%.11] +// CHECK:STDOUT: %AddAssign.decl: invalid = interface_decl @AddAssign [template = constants.%.11] {} +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+50, unused +// CHECK:STDOUT: %a.ref.loc31: ref C = name_ref a, %a +// CHECK:STDOUT: %import_ref.3: type = import_ref ir1, inst+54, used [template = constants.%.14] +// CHECK:STDOUT: %Inc.decl: invalid = interface_decl @Inc [template = constants.%.14] {} +// CHECK:STDOUT: %import_ref.4 = import_ref ir1, inst+65, unused +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon b/toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon new file mode 100644 index 000000000000..3e98a04b48ce --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/fail_no_impl_for_arg.carbon @@ -0,0 +1,301 @@ +// 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 +// +// AUTOUPDATE + +// --- prelude.carbon + +package Core api; + +interface Add { + fn Op[self: Self](other: Self) -> Self; +} +interface AddAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- fail_no_impl_for_arg.carbon + +package User api; + +import Core; + +class C {}; +class D {}; + +impl C as Core.Add { + fn Op[self: C](other: C) -> C; +} +impl C as Core.AddAssign { + fn Op[addr self: C*](other: C); +} + +fn Test(a: C, b: D) -> C { + // CHECK:STDERR: fail_no_impl_for_arg.carbon:[[@LINE+6]]:10: ERROR: Cannot implicitly convert from `D` to `C`. + // CHECK:STDERR: return a + b; + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: fail_no_impl_for_arg.carbon:[[@LINE-10]]:3: Initializing parameter 1 of function declared here. + // CHECK:STDERR: fn Op[self: C](other: C) -> C; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + return a + b; +} + +fn TestAssign(b: D) { + var a: C = {}; + // CHECK:STDERR: fail_no_impl_for_arg.carbon:[[@LINE+6]]:3: ERROR: Cannot implicitly convert from `D` to `C`. + // CHECK:STDERR: a += b; + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_no_impl_for_arg.carbon:[[@LINE-18]]:3: Initializing parameter 1 of function declared here. + // CHECK:STDERR: fn Op[addr self: C*](other: C); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + a += b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Add [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Add, [template] +// CHECK:STDOUT: %.3: in Add> = assoc_entity element0, @Add.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @AddAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @AddAssign, [template] +// CHECK:STDOUT: %.7: in AddAssign> = assoc_entity element0, @AddAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Add = %Add.decl +// CHECK:STDOUT: .AddAssign = %AddAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Add.decl: type = interface_decl @Add [template = constants.%.1] {} +// CHECK:STDOUT: %AddAssign.decl: type = interface_decl @AddAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Add { +// CHECK:STDOUT: %Self: Add = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: Add = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: Add = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: Add = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in Add> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @AddAssign { +// CHECK:STDOUT: %Self: AddAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: AddAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: AddAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in AddAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@Add.%self.loc5_9.2: Self](@Add.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @AddAssign.%self.loc8_14.3: Self*](@AddAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_no_impl_for_arg.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %D: type = class_type @D [template] +// CHECK:STDOUT: %.2: type = interface_type @Add [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.6: type = interface_type @AddAssign [template] +// CHECK:STDOUT: %.7: type = ptr_type C [template] +// CHECK:STDOUT: %.8: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.9: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.10: type = assoc_entity_type @Add, [template] +// CHECK:STDOUT: %.11: in Add> = assoc_entity element0, @Test.%import_ref.2 [template] +// CHECK:STDOUT: %.12: C = struct_value () [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @AddAssign, [template] +// CHECK:STDOUT: %.14: in AddAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .D = %D.decl +// CHECK:STDOUT: .Test = %Test +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: %D.decl: type = class_decl @D [template = constants.%D] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc9: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc9: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Add.decl: invalid = interface_decl @Add [template = constants.%.2] {} +// CHECK:STDOUT: %Add.ref: type = name_ref Add, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc12: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc12: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.6] +// CHECK:STDOUT: %AddAssign.decl: invalid = interface_decl @AddAssign [template = constants.%.6] {} +// CHECK:STDOUT: %AddAssign.ref: type = name_ref AddAssign, %import_ref.2 [template = constants.%.6] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Test: = fn_decl @Test [template] { +// CHECK:STDOUT: %C.ref.loc16_12: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc16_9.1: C = param a +// CHECK:STDOUT: @Test.%a: C = bind_name a, %a.loc16_9.1 +// CHECK:STDOUT: %D.ref.loc16: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %b.loc16_15.1: D = param b +// CHECK:STDOUT: @Test.%b: D = bind_name b, %b.loc16_15.1 +// CHECK:STDOUT: %C.ref.loc16_24: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @Test.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %D.ref.loc26: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %b.loc26_15.1: D = param b +// CHECK:STDOUT: @TestAssign.%b: D = bind_name b, %b.loc26_15.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Add { +// CHECK:STDOUT: %import_ref.1: in Add> = import_ref ir1, inst+20, used [template = constants.%.11] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @AddAssign { +// CHECK:STDOUT: %import_ref.1: in AddAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as Add { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc10_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc10_9.1: C = param self +// CHECK:STDOUT: %self.loc10_9.2: C = bind_name self, %self.loc10_9.1 +// CHECK:STDOUT: %C.ref.loc10_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc10_18.1: C = param other +// CHECK:STDOUT: %other.loc10_18.2: C = bind_name other, %other.loc10_18.1 +// CHECK:STDOUT: %C.ref.loc10_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.5] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as AddAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc13_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc13_21: type = ptr_type C [template = constants.%.7] +// CHECK:STDOUT: %self.loc13_14.1: C* = param self +// CHECK:STDOUT: %self.loc13_14.3: C* = bind_name self, %self.loc13_14.1 +// CHECK:STDOUT: %.loc13_9: C* = addr_pattern %self.loc13_14.3 +// CHECK:STDOUT: %C.ref.loc13_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc13_24.1: C = param other +// CHECK:STDOUT: %other.loc13_24.2: C = bind_name other, %other.loc13_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.9] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @D { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%D +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc10_9.2: C](@impl.1.%other.loc10_18.2: C) -> @impl.1.%return.var: C; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc13_14.3: C*](@impl.2.%other.loc13_24.2: C); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Test(%a: C, %b: D) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: D = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc23_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc23_12.2: ref C = temporary_storage +// CHECK:STDOUT: %.loc23_12.3: init C = call %.loc23_12.1() +// CHECK:STDOUT: return %.loc23_12.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%b: D) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %a.var: ref C = var a +// CHECK:STDOUT: %a: ref C = bind_name a, %a.var +// CHECK:STDOUT: %.loc27_15.1: {} = struct_literal () +// CHECK:STDOUT: %.loc27_15.2: init C = class_init (), %a.var [template = constants.%.12] +// CHECK:STDOUT: %.loc27_15.3: init C = converted %.loc27_15.1, %.loc27_15.2 [template = constants.%.12] +// CHECK:STDOUT: assign %a.var, %.loc27_15.3 +// CHECK:STDOUT: %a.ref: ref C = name_ref a, %a +// CHECK:STDOUT: %b.ref: D = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.6] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc34_5.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc34_3: C* = addr_of %a.ref +// CHECK:STDOUT: %.loc34_5.2: init () = call %.loc34_5.1() +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/inc.carbon b/toolchain/check/testdata/operators/overloaded/inc.carbon new file mode 100644 index 000000000000..bf6df03b2ab6 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/inc.carbon @@ -0,0 +1,158 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from unary_stmt.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface Inc { + fn Op[addr self: Self*](); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Inc { + fn Op[addr self: C*](); +} + +fn TestOp() { + var c: C = {}; + ++c; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Inc [template] +// CHECK:STDOUT: %.2: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.3: type = assoc_entity_type @Inc, [template] +// CHECK:STDOUT: %.4: in Inc> = assoc_entity element0, @Inc.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Inc = %Inc.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Inc.decl: type = interface_decl @Inc [template = constants.%.1] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Inc { +// CHECK:STDOUT: %Self: Inc = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op [template] { +// CHECK:STDOUT: %Self.ref: Inc = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_24.1: type = facet_type_access %Self.ref [symbolic = %Self] +// CHECK:STDOUT: %.loc5_20: type = converted %Self.ref, %.loc5_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_24.2: type = ptr_type Self [symbolic = constants.%.2] +// CHECK:STDOUT: %self.loc5_14.1: Self* = param self +// CHECK:STDOUT: %self.loc5_14.3: Self* = bind_name self, %self.loc5_14.1 +// CHECK:STDOUT: %.loc5_9: Self* = addr_pattern %self.loc5_14.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_28: in Inc> = assoc_entity element0, %Op [template = constants.%.4] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_28 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op[addr @Inc.%self.loc5_14.3: Self*](); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Inc [template] +// CHECK:STDOUT: %.3: type = ptr_type C [template] +// CHECK:STDOUT: %.4: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.5: = interface_witness (@impl.%Op) [template] +// CHECK:STDOUT: %.6: type = tuple_type () [template] +// CHECK:STDOUT: %.7: type = ptr_type {} [template] +// CHECK:STDOUT: %.8: C = struct_value () [template] +// CHECK:STDOUT: %.9: type = assoc_entity_type @Inc, [template] +// CHECK:STDOUT: %.10: in Inc> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl { +// CHECK:STDOUT: %C.ref: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Inc.decl: invalid = interface_decl @Inc [template = constants.%.2] {} +// CHECK:STDOUT: %Inc.ref: type = name_ref Inc, %import_ref [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Inc { +// CHECK:STDOUT: %import_ref.1: in Inc> = import_ref ir1, inst+14, used [template = constants.%.10] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+12, used [template = imports.%Op] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: C as Inc { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc9_21: type = ptr_type C [template = constants.%.3] +// CHECK:STDOUT: %self.loc9_14.1: C* = param self +// CHECK:STDOUT: %self.loc9_14.3: C* = bind_name self, %self.loc9_14.1 +// CHECK:STDOUT: %.loc9_9: C* = addr_pattern %self.loc9_14.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.5] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[addr @impl.%self.loc9_14.3: C*](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr %self: Self*](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %c.var: ref C = var c +// CHECK:STDOUT: %c: ref C = bind_name c, %c.var +// CHECK:STDOUT: %.loc13_15.1: {} = struct_literal () +// CHECK:STDOUT: %.loc13_15.2: init C = class_init (), %c.var [template = constants.%.8] +// CHECK:STDOUT: %.loc13_15.3: init C = converted %.loc13_15.1, %.loc13_15.2 [template = constants.%.8] +// CHECK:STDOUT: assign %c.var, %.loc13_15.3 +// CHECK:STDOUT: %c.ref: ref C = name_ref c, %c +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+12, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element0 [template = @impl.%Op] +// CHECK:STDOUT: %.loc14_3.1: = bound_method %c.ref, %.1 +// CHECK:STDOUT: %.loc14_5: C* = addr_of %c.ref +// CHECK:STDOUT: %.loc14_3.2: init () = call %.loc14_3.1(%.loc14_5) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/left_shift.carbon b/toolchain/check/testdata/operators/overloaded/left_shift.carbon new file mode 100644 index 000000000000..2071d61155ac --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/left_shift.carbon @@ -0,0 +1,290 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from binary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface LeftShift { + fn Op[self: Self](other: Self) -> Self; +} +interface LeftShiftAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.LeftShift { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.LeftShiftAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a << b; +} + +fn TestAssign(a: C*, b: C) { + *a <<= b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @LeftShift [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @LeftShift, [template] +// CHECK:STDOUT: %.3: in LeftShift> = assoc_entity element0, @LeftShift.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @LeftShiftAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @LeftShiftAssign, [template] +// CHECK:STDOUT: %.7: in LeftShiftAssign> = assoc_entity element0, @LeftShiftAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .LeftShift = %LeftShift.decl +// CHECK:STDOUT: .LeftShiftAssign = %LeftShiftAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %LeftShift.decl: type = interface_decl @LeftShift [template = constants.%.1] {} +// CHECK:STDOUT: %LeftShiftAssign.decl: type = interface_decl @LeftShiftAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @LeftShift { +// CHECK:STDOUT: %Self: LeftShift = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: LeftShift = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: LeftShift = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: LeftShift = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in LeftShift> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @LeftShiftAssign { +// CHECK:STDOUT: %Self: LeftShiftAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: LeftShiftAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: LeftShiftAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in LeftShiftAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@LeftShift.%self.loc5_9.2: Self](@LeftShift.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @LeftShiftAssign.%self.loc8_14.3: Self*](@LeftShiftAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @LeftShift [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.7: type = interface_type @LeftShiftAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type C [template] +// CHECK:STDOUT: %.9: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @LeftShift, [template] +// CHECK:STDOUT: %.12: in LeftShift> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @LeftShiftAssign, [template] +// CHECK:STDOUT: %.14: in LeftShiftAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %LeftShift.decl: invalid = interface_decl @LeftShift [template = constants.%.2] {} +// CHECK:STDOUT: %LeftShift.ref: type = name_ref LeftShift, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc13: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %LeftShiftAssign.decl: invalid = interface_decl @LeftShiftAssign [template = constants.%.7] {} +// CHECK:STDOUT: %LeftShiftAssign.ref: type = name_ref LeftShiftAssign, %import_ref.2 [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc17_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc17_11.1 +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_17.1: C = param b +// CHECK:STDOUT: @TestOp.%b: C = bind_name b, %b.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %C.ref.loc21_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %a.loc21_15.1: C* = param a +// CHECK:STDOUT: @TestAssign.%a: C* = bind_name a, %a.loc21_15.1 +// CHECK:STDOUT: %C.ref.loc21_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc21_22.1: C = param b +// CHECK:STDOUT: @TestAssign.%b: C = bind_name b, %b.loc21_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @LeftShift { +// CHECK:STDOUT: %import_ref.1: in LeftShift> = import_ref ir1, inst+20, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @LeftShiftAssign { +// CHECK:STDOUT: %import_ref.1: in LeftShiftAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as LeftShift { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_18.1: C = param other +// CHECK:STDOUT: %other.loc9_18.2: C = bind_name other, %other.loc9_18.1 +// CHECK:STDOUT: %C.ref.loc9_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as LeftShiftAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14_21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %self.loc14_14.1: C* = param self +// CHECK:STDOUT: %self.loc14_14.3: C* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: C* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: %C.ref.loc14_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc14_24.1: C = param other +// CHECK:STDOUT: %other.loc14_24.2: C = bind_name other, %other.loc14_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc9_9.2: C](@impl.1.%other.loc9_18.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.1.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc14_14.3: C*](@impl.2.%other.loc14_24.2: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc17: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc18_12.2: init C = call %.loc18_12.1(%a.ref, %b.ref) to %.loc17 +// CHECK:STDOUT: return %.loc18_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%a: C*, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C* = name_ref a, %a +// CHECK:STDOUT: %.loc22_3.1: ref C = deref %a.ref +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc22_6.1: = bound_method %.loc22_3.1, %.1 +// CHECK:STDOUT: %.loc22_3.2: C* = addr_of %.loc22_3.1 +// CHECK:STDOUT: %.loc22_6.2: init () = call %.loc22_6.1(%.loc22_3.2, %b.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/make_tests.sh b/toolchain/check/testdata/operators/overloaded/make_tests.sh new file mode 100755 index 000000000000..5f8e2d7669cd --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/make_tests.sh @@ -0,0 +1,43 @@ +#! /bin/bash +# 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 + +# TODO: This is a short-term script to regenerate the test files for operators +# while we're in a period where we expect the tests to have substantial churn. +# Once the implementation of overloaded operators has stabilized, this script +# and its template files should be removed. + +make_test() { + HEADER="// This file was generated from $4. Run make_tests.sh to regenerate." + sed "s,INTERFACE,$1,g; s,OP,$2,g; s,HEADER,$HEADER," "$4" > "$3.carbon" +} + +make_unary_op_test() { + make_test "$1" "$2" "$3" unary_op.carbon.tmpl +} + +make_unary_stmt_test() { + make_test "$1" "$2" "$3" unary_stmt.carbon.tmpl +} + +make_binary_op_test() { + make_test "$1" "$2" "$3" binary_op.carbon.tmpl +} + +make_unary_op_test BitComplement '^' bit_complement +make_unary_op_test Negate '-' negate + +make_unary_stmt_test Dec '--' dec +make_unary_stmt_test Inc '++' inc + +make_binary_op_test Add '+' add +make_binary_op_test BitAnd '\&' bit_and +make_binary_op_test BitOr '|' bit_or +make_binary_op_test BitXor '^' bit_xor +make_binary_op_test Div '/' div +make_binary_op_test LeftShift '<<' left_shift +make_binary_op_test Mod '%' mod +make_binary_op_test Mul '*' mul +make_binary_op_test RightShift '>>' right_shift +make_binary_op_test Sub '-' sub diff --git a/toolchain/check/testdata/operators/overloaded/mod.carbon b/toolchain/check/testdata/operators/overloaded/mod.carbon new file mode 100644 index 000000000000..c08914276c26 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/mod.carbon @@ -0,0 +1,290 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from binary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface Mod { + fn Op[self: Self](other: Self) -> Self; +} +interface ModAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Mod { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.ModAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a % b; +} + +fn TestAssign(a: C*, b: C) { + *a %= b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Mod [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Mod, [template] +// CHECK:STDOUT: %.3: in Mod> = assoc_entity element0, @Mod.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @ModAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @ModAssign, [template] +// CHECK:STDOUT: %.7: in ModAssign> = assoc_entity element0, @ModAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Mod = %Mod.decl +// CHECK:STDOUT: .ModAssign = %ModAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Mod.decl: type = interface_decl @Mod [template = constants.%.1] {} +// CHECK:STDOUT: %ModAssign.decl: type = interface_decl @ModAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Mod { +// CHECK:STDOUT: %Self: Mod = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: Mod = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: Mod = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: Mod = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in Mod> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @ModAssign { +// CHECK:STDOUT: %Self: ModAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: ModAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: ModAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in ModAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@Mod.%self.loc5_9.2: Self](@Mod.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @ModAssign.%self.loc8_14.3: Self*](@ModAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Mod [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.7: type = interface_type @ModAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type C [template] +// CHECK:STDOUT: %.9: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @Mod, [template] +// CHECK:STDOUT: %.12: in Mod> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @ModAssign, [template] +// CHECK:STDOUT: %.14: in ModAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Mod.decl: invalid = interface_decl @Mod [template = constants.%.2] {} +// CHECK:STDOUT: %Mod.ref: type = name_ref Mod, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc13: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %ModAssign.decl: invalid = interface_decl @ModAssign [template = constants.%.7] {} +// CHECK:STDOUT: %ModAssign.ref: type = name_ref ModAssign, %import_ref.2 [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc17_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc17_11.1 +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_17.1: C = param b +// CHECK:STDOUT: @TestOp.%b: C = bind_name b, %b.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %C.ref.loc21_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %a.loc21_15.1: C* = param a +// CHECK:STDOUT: @TestAssign.%a: C* = bind_name a, %a.loc21_15.1 +// CHECK:STDOUT: %C.ref.loc21_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc21_22.1: C = param b +// CHECK:STDOUT: @TestAssign.%b: C = bind_name b, %b.loc21_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Mod { +// CHECK:STDOUT: %import_ref.1: in Mod> = import_ref ir1, inst+20, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @ModAssign { +// CHECK:STDOUT: %import_ref.1: in ModAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as Mod { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_18.1: C = param other +// CHECK:STDOUT: %other.loc9_18.2: C = bind_name other, %other.loc9_18.1 +// CHECK:STDOUT: %C.ref.loc9_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as ModAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14_21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %self.loc14_14.1: C* = param self +// CHECK:STDOUT: %self.loc14_14.3: C* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: C* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: %C.ref.loc14_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc14_24.1: C = param other +// CHECK:STDOUT: %other.loc14_24.2: C = bind_name other, %other.loc14_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc9_9.2: C](@impl.1.%other.loc9_18.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.1.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc14_14.3: C*](@impl.2.%other.loc14_24.2: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc17: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc18_12.2: init C = call %.loc18_12.1(%a.ref, %b.ref) to %.loc17 +// CHECK:STDOUT: return %.loc18_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%a: C*, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C* = name_ref a, %a +// CHECK:STDOUT: %.loc22_3.1: ref C = deref %a.ref +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc22_6.1: = bound_method %.loc22_3.1, %.1 +// CHECK:STDOUT: %.loc22_3.2: C* = addr_of %.loc22_3.1 +// CHECK:STDOUT: %.loc22_6.2: init () = call %.loc22_6.1(%.loc22_3.2, %b.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/mul.carbon b/toolchain/check/testdata/operators/overloaded/mul.carbon new file mode 100644 index 000000000000..c5018912cba0 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/mul.carbon @@ -0,0 +1,290 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from binary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface Mul { + fn Op[self: Self](other: Self) -> Self; +} +interface MulAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Mul { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.MulAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a * b; +} + +fn TestAssign(a: C*, b: C) { + *a *= b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Mul [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Mul, [template] +// CHECK:STDOUT: %.3: in Mul> = assoc_entity element0, @Mul.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @MulAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @MulAssign, [template] +// CHECK:STDOUT: %.7: in MulAssign> = assoc_entity element0, @MulAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Mul = %Mul.decl +// CHECK:STDOUT: .MulAssign = %MulAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Mul.decl: type = interface_decl @Mul [template = constants.%.1] {} +// CHECK:STDOUT: %MulAssign.decl: type = interface_decl @MulAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Mul { +// CHECK:STDOUT: %Self: Mul = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: Mul = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: Mul = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: Mul = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in Mul> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @MulAssign { +// CHECK:STDOUT: %Self: MulAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: MulAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: MulAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in MulAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@Mul.%self.loc5_9.2: Self](@Mul.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @MulAssign.%self.loc8_14.3: Self*](@MulAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Mul [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.7: type = interface_type @MulAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type C [template] +// CHECK:STDOUT: %.9: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @Mul, [template] +// CHECK:STDOUT: %.12: in Mul> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @MulAssign, [template] +// CHECK:STDOUT: %.14: in MulAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Mul.decl: invalid = interface_decl @Mul [template = constants.%.2] {} +// CHECK:STDOUT: %Mul.ref: type = name_ref Mul, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc13: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %MulAssign.decl: invalid = interface_decl @MulAssign [template = constants.%.7] {} +// CHECK:STDOUT: %MulAssign.ref: type = name_ref MulAssign, %import_ref.2 [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc17_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc17_11.1 +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_17.1: C = param b +// CHECK:STDOUT: @TestOp.%b: C = bind_name b, %b.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %C.ref.loc21_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %a.loc21_15.1: C* = param a +// CHECK:STDOUT: @TestAssign.%a: C* = bind_name a, %a.loc21_15.1 +// CHECK:STDOUT: %C.ref.loc21_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc21_22.1: C = param b +// CHECK:STDOUT: @TestAssign.%b: C = bind_name b, %b.loc21_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Mul { +// CHECK:STDOUT: %import_ref.1: in Mul> = import_ref ir1, inst+20, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @MulAssign { +// CHECK:STDOUT: %import_ref.1: in MulAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as Mul { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_18.1: C = param other +// CHECK:STDOUT: %other.loc9_18.2: C = bind_name other, %other.loc9_18.1 +// CHECK:STDOUT: %C.ref.loc9_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as MulAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14_21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %self.loc14_14.1: C* = param self +// CHECK:STDOUT: %self.loc14_14.3: C* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: C* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: %C.ref.loc14_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc14_24.1: C = param other +// CHECK:STDOUT: %other.loc14_24.2: C = bind_name other, %other.loc14_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc9_9.2: C](@impl.1.%other.loc9_18.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.1.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc14_14.3: C*](@impl.2.%other.loc14_24.2: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc17: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc18_12.2: init C = call %.loc18_12.1(%a.ref, %b.ref) to %.loc17 +// CHECK:STDOUT: return %.loc18_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%a: C*, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C* = name_ref a, %a +// CHECK:STDOUT: %.loc22_3.1: ref C = deref %a.ref +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc22_6.1: = bound_method %.loc22_3.1, %.1 +// CHECK:STDOUT: %.loc22_3.2: C* = addr_of %.loc22_3.1 +// CHECK:STDOUT: %.loc22_6.2: init () = call %.loc22_6.1(%.loc22_3.2, %b.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/negate.carbon b/toolchain/check/testdata/operators/overloaded/negate.carbon new file mode 100644 index 000000000000..4301e8a96d32 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/negate.carbon @@ -0,0 +1,163 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from unary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface Negate { + fn Op[self: Self]() -> Self; +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Negate { + fn Op[self: C]() -> C { + return {}; + } +} + +fn TestOp(a: C) -> C { + return -a; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Negate [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Negate, [template] +// CHECK:STDOUT: %.3: in Negate> = assoc_entity element0, @Negate.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Negate = %Negate.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate.decl: type = interface_decl @Negate [template = constants.%.1] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Negate { +// CHECK:STDOUT: %Self: Negate = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: Negate = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_26: Negate = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_26.1: type = facet_type_access %Self.ref.loc5_26 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_26.2: type = converted %Self.ref.loc5_26, %.loc5_26.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_30: in Negate> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_30 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op[@Negate.%self.loc5_9.2: Self]() -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Negate [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.%Op) [template] +// CHECK:STDOUT: %.7: type = assoc_entity_type @Negate, [template] +// CHECK:STDOUT: %.8: in Negate> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Negate.decl: invalid = interface_decl @Negate [template = constants.%.2] {} +// CHECK:STDOUT: %Negate.ref: type = name_ref Negate, %import_ref [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc14_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc14_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc14_11.1 +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Negate { +// CHECK:STDOUT: %import_ref.1: in Negate> = import_ref ir1, inst+15, used [template = constants.%.8] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+13, used [template = imports.%Op] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: C as Negate { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_23: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.%self.loc9_9.2: C]() -> @impl.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self]() -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+13, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element0 [template = @impl.%Op] +// CHECK:STDOUT: %.loc15_10.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc14: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc15_10.2: init C = call %.loc15_10.1(%a.ref) to %.loc14 +// CHECK:STDOUT: return %.loc15_10.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/ordered.carbon b/toolchain/check/testdata/operators/overloaded/ordered.carbon new file mode 100644 index 000000000000..e158a533ab4c --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/ordered.carbon @@ -0,0 +1,521 @@ +// 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 +// +// AUTOUPDATE + +// --- prelude.carbon + +package Core api; + +interface Ordered { + // TODO: fn Compare + fn Less[self: Self](other: Self) -> bool; + fn LessOrEquivalent[self: Self](other: Self) -> bool; + fn Greater[self: Self](other: Self) -> bool; + fn GreaterOrEquivalent[self: Self](other: Self) -> bool; +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Ordered { + fn Less[self: C](other: C) -> bool; + fn LessOrEquivalent[self: C](other: C) -> bool; + fn Greater[self: C](other: C) -> bool; + fn GreaterOrEquivalent[self: C](other: C) -> bool; +} + +fn TestLess(a: C, b: C) -> bool { + return a < b; +} + +fn TestLessEqual(a: C, b: C) -> bool { + return a <= b; +} + +fn TestGreater(a: C, b: C) -> bool { + return a > b; +} + +fn TestGreaterEqual(a: C, b: C) -> bool { + return a >= b; +} + +// --- fail_no_impl.carbon + +package FailNoImpl api; + +import Core; + +class D {}; + +fn TestLess(a: D, b: D) -> bool { + // CHECK:STDERR: fail_no_impl.carbon:[[@LINE+3]]:10: ERROR: Cannot access member of interface Ordered in type D that does not implement that interface. + // CHECK:STDERR: return a < b; + // CHECK:STDERR: ^~~~~ + return a < b; +} + +fn TestLessEqual(a: D, b: D) -> bool { + // CHECK:STDERR: fail_no_impl.carbon:[[@LINE+3]]:10: ERROR: Cannot access member of interface Ordered in type D that does not implement that interface. + // CHECK:STDERR: return a <= b; + // CHECK:STDERR: ^~~~~~ + return a <= b; +} + +fn TestGreater(a: D, b: D) -> bool { + // CHECK:STDERR: fail_no_impl.carbon:[[@LINE+3]]:10: ERROR: Cannot access member of interface Ordered in type D that does not implement that interface. + // CHECK:STDERR: return a > b; + // CHECK:STDERR: ^~~~~ + return a > b; +} + +fn TestGreaterEqual(a: D, b: D) -> bool { + // CHECK:STDERR: fail_no_impl.carbon:[[@LINE+3]]:10: ERROR: Cannot access member of interface Ordered in type D that does not implement that interface. + // CHECK:STDERR: return a >= b; + // CHECK:STDERR: ^~~~~~ + return a >= b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Ordered [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Ordered, [template] +// CHECK:STDOUT: %.3: in Ordered> = assoc_entity element0, @Ordered.%Less [template] +// CHECK:STDOUT: %.4: in Ordered> = assoc_entity element1, @Ordered.%LessOrEquivalent [template] +// CHECK:STDOUT: %.5: in Ordered> = assoc_entity element2, @Ordered.%Greater [template] +// CHECK:STDOUT: %.6: in Ordered> = assoc_entity element3, @Ordered.%GreaterOrEquivalent [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Ordered = %Ordered.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Ordered.decl: type = interface_decl @Ordered [template = constants.%.1] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Ordered { +// CHECK:STDOUT: %Self: Ordered = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Less: = fn_decl @Less [template] { +// CHECK:STDOUT: %Self.ref.loc6_17: Ordered = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc6_17.1: type = facet_type_access %Self.ref.loc6_17 [symbolic = %Self] +// CHECK:STDOUT: %.loc6_17.2: type = converted %Self.ref.loc6_17, %.loc6_17.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc6_11.1: Self = param self +// CHECK:STDOUT: %self.loc6_11.2: Self = bind_name self, %self.loc6_11.1 +// CHECK:STDOUT: %Self.ref.loc6_30: Ordered = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc6_30.1: type = facet_type_access %Self.ref.loc6_30 [symbolic = %Self] +// CHECK:STDOUT: %.loc6_30.2: type = converted %Self.ref.loc6_30, %.loc6_30.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc6_23.1: Self = param other +// CHECK:STDOUT: %other.loc6_23.2: Self = bind_name other, %other.loc6_23.1 +// CHECK:STDOUT: %return.var.loc6: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc6_43: in Ordered> = assoc_entity element0, %Less [template = constants.%.3] +// CHECK:STDOUT: %LessOrEquivalent: = fn_decl @LessOrEquivalent [template] { +// CHECK:STDOUT: %Self.ref.loc7_29: Ordered = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc7_29.1: type = facet_type_access %Self.ref.loc7_29 [symbolic = %Self] +// CHECK:STDOUT: %.loc7_29.2: type = converted %Self.ref.loc7_29, %.loc7_29.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc7_23.1: Self = param self +// CHECK:STDOUT: %self.loc7_23.2: Self = bind_name self, %self.loc7_23.1 +// CHECK:STDOUT: %Self.ref.loc7_42: Ordered = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc7_42.1: type = facet_type_access %Self.ref.loc7_42 [symbolic = %Self] +// CHECK:STDOUT: %.loc7_42.2: type = converted %Self.ref.loc7_42, %.loc7_42.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc7_35.1: Self = param other +// CHECK:STDOUT: %other.loc7_35.2: Self = bind_name other, %other.loc7_35.1 +// CHECK:STDOUT: %return.var.loc7: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc7_55: in Ordered> = assoc_entity element1, %LessOrEquivalent [template = constants.%.4] +// CHECK:STDOUT: %Greater: = fn_decl @Greater [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: Ordered = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20.2: type = converted %Self.ref.loc8_20, %.loc8_20.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc8_14.1: Self = param self +// CHECK:STDOUT: %self.loc8_14.2: Self = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %Self.ref.loc8_33: Ordered = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_33.1: type = facet_type_access %Self.ref.loc8_33 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_33.2: type = converted %Self.ref.loc8_33, %.loc8_33.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_26.1: Self = param other +// CHECK:STDOUT: %other.loc8_26.2: Self = bind_name other, %other.loc8_26.1 +// CHECK:STDOUT: %return.var.loc8: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_46: in Ordered> = assoc_entity element2, %Greater [template = constants.%.5] +// CHECK:STDOUT: %GreaterOrEquivalent: = fn_decl @GreaterOrEquivalent [template] { +// CHECK:STDOUT: %Self.ref.loc9_32: Ordered = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc9_32.1: type = facet_type_access %Self.ref.loc9_32 [symbolic = %Self] +// CHECK:STDOUT: %.loc9_32.2: type = converted %Self.ref.loc9_32, %.loc9_32.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc9_26.1: Self = param self +// CHECK:STDOUT: %self.loc9_26.2: Self = bind_name self, %self.loc9_26.1 +// CHECK:STDOUT: %Self.ref.loc9_45: Ordered = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc9_45.1: type = facet_type_access %Self.ref.loc9_45 [symbolic = %Self] +// CHECK:STDOUT: %.loc9_45.2: type = converted %Self.ref.loc9_45, %.loc9_45.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc9_38.1: Self = param other +// CHECK:STDOUT: %other.loc9_38.2: Self = bind_name other, %other.loc9_38.1 +// CHECK:STDOUT: %return.var.loc9: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc9_58: in Ordered> = assoc_entity element3, %GreaterOrEquivalent [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Less = %.loc6_43 +// CHECK:STDOUT: .LessOrEquivalent = %.loc7_55 +// CHECK:STDOUT: .Greater = %.loc8_46 +// CHECK:STDOUT: .GreaterOrEquivalent = %.loc9_58 +// CHECK:STDOUT: witness = (%Less, %LessOrEquivalent, %Greater, %GreaterOrEquivalent) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Less[@Ordered.%self.loc6_11.2: Self](@Ordered.%other.loc6_23.2: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @LessOrEquivalent[@Ordered.%self.loc7_23.2: Self](@Ordered.%other.loc7_35.2: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Greater[@Ordered.%self.loc8_14.2: Self](@Ordered.%other.loc8_26.2: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @GreaterOrEquivalent[@Ordered.%self.loc9_26.2: Self](@Ordered.%other.loc9_38.2: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Ordered [template] +// CHECK:STDOUT: %.3: = interface_witness (@impl.%Less, @impl.%LessOrEquivalent, @impl.%Greater, @impl.%GreaterOrEquivalent) [template] +// CHECK:STDOUT: %.4: type = tuple_type () [template] +// CHECK:STDOUT: %.5: type = ptr_type {} [template] +// CHECK:STDOUT: %.6: type = assoc_entity_type @Ordered, [template] +// CHECK:STDOUT: %.7: in Ordered> = assoc_entity element0, @TestLess.%import_ref.2 [template] +// CHECK:STDOUT: %.8: in Ordered> = assoc_entity element1, @TestLessEqual.%import_ref.2 [template] +// CHECK:STDOUT: %.9: in Ordered> = assoc_entity element2, @TestGreater.%import_ref.2 [template] +// CHECK:STDOUT: %.10: in Ordered> = assoc_entity element3, @TestGreaterEqual.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestLess = %TestLess +// CHECK:STDOUT: .TestLessEqual = %TestLessEqual +// CHECK:STDOUT: .TestGreater = %TestGreater +// CHECK:STDOUT: .TestGreaterEqual = %TestGreaterEqual +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Ordered.decl: invalid = interface_decl @Ordered [template = constants.%.2] {} +// CHECK:STDOUT: %Ordered.ref: type = name_ref Ordered, %import_ref [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestLess: = fn_decl @TestLess [template] { +// CHECK:STDOUT: %C.ref.loc15_16: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc15_13.1: C = param a +// CHECK:STDOUT: @TestLess.%a: C = bind_name a, %a.loc15_13.1 +// CHECK:STDOUT: %C.ref.loc15_22: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc15_19.1: C = param b +// CHECK:STDOUT: @TestLess.%b: C = bind_name b, %b.loc15_19.1 +// CHECK:STDOUT: %return.var.loc15: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestLessEqual: = fn_decl @TestLessEqual [template] { +// CHECK:STDOUT: %C.ref.loc19_21: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc19_18.1: C = param a +// CHECK:STDOUT: @TestLessEqual.%a: C = bind_name a, %a.loc19_18.1 +// CHECK:STDOUT: %C.ref.loc19_27: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc19_24.1: C = param b +// CHECK:STDOUT: @TestLessEqual.%b: C = bind_name b, %b.loc19_24.1 +// CHECK:STDOUT: %return.var.loc19: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestGreater: = fn_decl @TestGreater [template] { +// CHECK:STDOUT: %C.ref.loc23_19: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc23_16.1: C = param a +// CHECK:STDOUT: @TestGreater.%a: C = bind_name a, %a.loc23_16.1 +// CHECK:STDOUT: %C.ref.loc23_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc23_22.1: C = param b +// CHECK:STDOUT: @TestGreater.%b: C = bind_name b, %b.loc23_22.1 +// CHECK:STDOUT: %return.var.loc23: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestGreaterEqual: = fn_decl @TestGreaterEqual [template] { +// CHECK:STDOUT: %C.ref.loc27_24: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc27_21.1: C = param a +// CHECK:STDOUT: @TestGreaterEqual.%a: C = bind_name a, %a.loc27_21.1 +// CHECK:STDOUT: %C.ref.loc27_30: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc27_27.1: C = param b +// CHECK:STDOUT: @TestGreaterEqual.%b: C = bind_name b, %b.loc27_27.1 +// CHECK:STDOUT: %return.var.loc27: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Ordered { +// CHECK:STDOUT: %import_ref.1: in Ordered> = import_ref ir1, inst+17, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: in Ordered> = import_ref ir1, inst+31, used [template = constants.%.8] +// CHECK:STDOUT: %import_ref.4: in Ordered> = import_ref ir1, inst+59, used [template = constants.%.10] +// CHECK:STDOUT: %import_ref.5: in Ordered> = import_ref ir1, inst+45, used [template = constants.%.9] +// CHECK:STDOUT: %import_ref.6: = import_ref ir1, inst+15, used [template = imports.%Less] +// CHECK:STDOUT: %import_ref.7: = import_ref ir1, inst+30, used [template = imports.%LessOrEquivalent] +// CHECK:STDOUT: %import_ref.8: = import_ref ir1, inst+44, used [template = imports.%Greater] +// CHECK:STDOUT: %import_ref.9: = import_ref ir1, inst+58, used [template = imports.%GreaterOrEquivalent] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Less = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: .LessOrEquivalent = %import_ref.3 +// CHECK:STDOUT: .GreaterOrEquivalent = %import_ref.4 +// CHECK:STDOUT: .Greater = %import_ref.5 +// CHECK:STDOUT: witness = (%import_ref.6, %import_ref.7, %import_ref.8, %import_ref.9) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: C as Ordered { +// CHECK:STDOUT: %Less: = fn_decl @Less.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_17: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_11.1: C = param self +// CHECK:STDOUT: %self.loc9_11.2: C = bind_name self, %self.loc9_11.1 +// CHECK:STDOUT: %C.ref.loc9_27: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_20.1: C = param other +// CHECK:STDOUT: %other.loc9_20.2: C = bind_name other, %other.loc9_20.1 +// CHECK:STDOUT: %return.var.loc9: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %LessOrEquivalent: = fn_decl @LessOrEquivalent.1 [template] { +// CHECK:STDOUT: %C.ref.loc10_29: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc10_23.1: C = param self +// CHECK:STDOUT: %self.loc10_23.2: C = bind_name self, %self.loc10_23.1 +// CHECK:STDOUT: %C.ref.loc10_39: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc10_32.1: C = param other +// CHECK:STDOUT: %other.loc10_32.2: C = bind_name other, %other.loc10_32.1 +// CHECK:STDOUT: %return.var.loc10: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Greater: = fn_decl @Greater.1 [template] { +// CHECK:STDOUT: %C.ref.loc11_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc11_14.1: C = param self +// CHECK:STDOUT: %self.loc11_14.2: C = bind_name self, %self.loc11_14.1 +// CHECK:STDOUT: %C.ref.loc11_30: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc11_23.1: C = param other +// CHECK:STDOUT: %other.loc11_23.2: C = bind_name other, %other.loc11_23.1 +// CHECK:STDOUT: %return.var.loc11: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %GreaterOrEquivalent: = fn_decl @GreaterOrEquivalent.1 [template] { +// CHECK:STDOUT: %C.ref.loc12_32: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc12_26.1: C = param self +// CHECK:STDOUT: %self.loc12_26.2: C = bind_name self, %self.loc12_26.1 +// CHECK:STDOUT: %C.ref.loc12_42: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc12_35.1: C = param other +// CHECK:STDOUT: %other.loc12_35.2: C = bind_name other, %other.loc12_35.1 +// CHECK:STDOUT: %return.var.loc12: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Less, %LessOrEquivalent, %Greater, %GreaterOrEquivalent) [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Less = %Less +// CHECK:STDOUT: .LessOrEquivalent = %LessOrEquivalent +// CHECK:STDOUT: .Greater = %Greater +// CHECK:STDOUT: .GreaterOrEquivalent = %GreaterOrEquivalent +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Less.1[@impl.%self.loc9_11.2: C](@impl.%other.loc9_20.2: C) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @LessOrEquivalent.1[@impl.%self.loc10_23.2: C](@impl.%other.loc10_32.2: C) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Greater.1[@impl.%self.loc11_14.2: C](@impl.%other.loc11_23.2: C) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @GreaterOrEquivalent.1[@impl.%self.loc12_26.2: C](@impl.%other.loc12_35.2: C) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Less.2[%self: Self](%other: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @LessOrEquivalent.2[%self: Self](%other: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Greater.2[%self: Self](%other: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @GreaterOrEquivalent.2[%self: Self](%other: Self) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestLess(%a: C, %b: C) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+15, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element0 [template = @impl.%Less] +// CHECK:STDOUT: %.loc16_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc16_12.2: init bool = call %.loc16_12.1(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc16_15: bool = value_of_initializer %.loc16_12.2 +// CHECK:STDOUT: %.loc16_12.3: bool = converted %.loc16_12.2, %.loc16_15 +// CHECK:STDOUT: return %.loc16_12.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestLessEqual(%a: C, %b: C) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+30, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element1 [template = @impl.%LessOrEquivalent] +// CHECK:STDOUT: %.loc20_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc20_12.2: init bool = call %.loc20_12.1(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc20_16: bool = value_of_initializer %.loc20_12.2 +// CHECK:STDOUT: %.loc20_12.3: bool = converted %.loc20_12.2, %.loc20_16 +// CHECK:STDOUT: return %.loc20_12.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestGreater(%a: C, %b: C) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+44, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element2 [template = @impl.%Greater] +// CHECK:STDOUT: %.loc24_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc24_12.2: init bool = call %.loc24_12.1(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc24_15: bool = value_of_initializer %.loc24_12.2 +// CHECK:STDOUT: %.loc24_12.3: bool = converted %.loc24_12.2, %.loc24_15 +// CHECK:STDOUT: return %.loc24_12.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestGreaterEqual(%a: C, %b: C) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+58, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.%.1, element3 [template = @impl.%GreaterOrEquivalent] +// CHECK:STDOUT: %.loc28_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc28_12.2: init bool = call %.loc28_12.1(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc28_16: bool = value_of_initializer %.loc28_12.2 +// CHECK:STDOUT: %.loc28_12.3: bool = converted %.loc28_12.2, %.loc28_16 +// CHECK:STDOUT: return %.loc28_12.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_no_impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %D: type = class_type @D [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: %.4: type = interface_type @Ordered [template] +// CHECK:STDOUT: %.5: type = assoc_entity_type @Ordered, [template] +// CHECK:STDOUT: %.6: in Ordered> = assoc_entity element0, @TestLess.%import_ref.2 [template] +// CHECK:STDOUT: %.7: in Ordered> = assoc_entity element1, @TestLessEqual.%import_ref.2 [template] +// CHECK:STDOUT: %.8: in Ordered> = assoc_entity element2, @TestGreater.%import_ref.2 [template] +// CHECK:STDOUT: %.9: in Ordered> = assoc_entity element3, @TestGreaterEqual.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .D = %D.decl +// CHECK:STDOUT: .TestLess = %TestLess +// CHECK:STDOUT: .TestLessEqual = %TestLessEqual +// CHECK:STDOUT: .TestGreater = %TestGreater +// CHECK:STDOUT: .TestGreaterEqual = %TestGreaterEqual +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %D.decl: type = class_decl @D [template = constants.%D] {} +// CHECK:STDOUT: %TestLess: = fn_decl @TestLess [template] { +// CHECK:STDOUT: %D.ref.loc8_16: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %a.loc8_13.1: D = param a +// CHECK:STDOUT: @TestLess.%a: D = bind_name a, %a.loc8_13.1 +// CHECK:STDOUT: %D.ref.loc8_22: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %b.loc8_19.1: D = param b +// CHECK:STDOUT: @TestLess.%b: D = bind_name b, %b.loc8_19.1 +// CHECK:STDOUT: %return.var.loc8: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestLessEqual: = fn_decl @TestLessEqual [template] { +// CHECK:STDOUT: %D.ref.loc15_21: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %a.loc15_18.1: D = param a +// CHECK:STDOUT: @TestLessEqual.%a: D = bind_name a, %a.loc15_18.1 +// CHECK:STDOUT: %D.ref.loc15_27: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %b.loc15_24.1: D = param b +// CHECK:STDOUT: @TestLessEqual.%b: D = bind_name b, %b.loc15_24.1 +// CHECK:STDOUT: %return.var.loc15: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestGreater: = fn_decl @TestGreater [template] { +// CHECK:STDOUT: %D.ref.loc22_19: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %a.loc22_16.1: D = param a +// CHECK:STDOUT: @TestGreater.%a: D = bind_name a, %a.loc22_16.1 +// CHECK:STDOUT: %D.ref.loc22_25: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %b.loc22_22.1: D = param b +// CHECK:STDOUT: @TestGreater.%b: D = bind_name b, %b.loc22_22.1 +// CHECK:STDOUT: %return.var.loc22: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestGreaterEqual: = fn_decl @TestGreaterEqual [template] { +// CHECK:STDOUT: %D.ref.loc29_24: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %a.loc29_21.1: D = param a +// CHECK:STDOUT: @TestGreaterEqual.%a: D = bind_name a, %a.loc29_21.1 +// CHECK:STDOUT: %D.ref.loc29_30: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %b.loc29_27.1: D = param b +// CHECK:STDOUT: @TestGreaterEqual.%b: D = bind_name b, %b.loc29_27.1 +// CHECK:STDOUT: %return.var.loc29: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Ordered { +// CHECK:STDOUT: %import_ref.1: in Ordered> = import_ref ir1, inst+17, used [template = constants.%.6] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: in Ordered> = import_ref ir1, inst+31, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.4: in Ordered> = import_ref ir1, inst+59, used [template = constants.%.9] +// CHECK:STDOUT: %import_ref.5: in Ordered> = import_ref ir1, inst+45, used [template = constants.%.8] +// CHECK:STDOUT: %import_ref.6 = import_ref ir1, inst+15, unused +// CHECK:STDOUT: %import_ref.7 = import_ref ir1, inst+30, unused +// CHECK:STDOUT: %import_ref.8 = import_ref ir1, inst+44, unused +// CHECK:STDOUT: %import_ref.9 = import_ref ir1, inst+58, unused +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Less = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: .LessOrEquivalent = %import_ref.3 +// CHECK:STDOUT: .GreaterOrEquivalent = %import_ref.4 +// CHECK:STDOUT: .Greater = %import_ref.5 +// CHECK:STDOUT: witness = (%import_ref.6, %import_ref.7, %import_ref.8, %import_ref.9) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @D { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%D +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestLess(%a: D, %b: D) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: D = name_ref a, %a +// CHECK:STDOUT: %b.ref: D = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.4] +// CHECK:STDOUT: %Ordered.decl: invalid = interface_decl @Ordered [template = constants.%.4] {} +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+15, unused +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestLessEqual(%a: D, %b: D) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: D = name_ref a, %a +// CHECK:STDOUT: %b.ref: D = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.4] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+30, unused +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestGreater(%a: D, %b: D) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: D = name_ref a, %a +// CHECK:STDOUT: %b.ref: D = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.4] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+44, unused +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestGreaterEqual(%a: D, %b: D) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: D = name_ref a, %a +// CHECK:STDOUT: %b.ref: D = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.4] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+58, unused +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/right_shift.carbon b/toolchain/check/testdata/operators/overloaded/right_shift.carbon new file mode 100644 index 000000000000..33a161daa6b1 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/right_shift.carbon @@ -0,0 +1,290 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from binary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface RightShift { + fn Op[self: Self](other: Self) -> Self; +} +interface RightShiftAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.RightShift { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.RightShiftAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a >> b; +} + +fn TestAssign(a: C*, b: C) { + *a >>= b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @RightShift [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @RightShift, [template] +// CHECK:STDOUT: %.3: in RightShift> = assoc_entity element0, @RightShift.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @RightShiftAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @RightShiftAssign, [template] +// CHECK:STDOUT: %.7: in RightShiftAssign> = assoc_entity element0, @RightShiftAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .RightShift = %RightShift.decl +// CHECK:STDOUT: .RightShiftAssign = %RightShiftAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %RightShift.decl: type = interface_decl @RightShift [template = constants.%.1] {} +// CHECK:STDOUT: %RightShiftAssign.decl: type = interface_decl @RightShiftAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @RightShift { +// CHECK:STDOUT: %Self: RightShift = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: RightShift = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: RightShift = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: RightShift = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in RightShift> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @RightShiftAssign { +// CHECK:STDOUT: %Self: RightShiftAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: RightShiftAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: RightShiftAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in RightShiftAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@RightShift.%self.loc5_9.2: Self](@RightShift.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @RightShiftAssign.%self.loc8_14.3: Self*](@RightShiftAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @RightShift [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.7: type = interface_type @RightShiftAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type C [template] +// CHECK:STDOUT: %.9: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @RightShift, [template] +// CHECK:STDOUT: %.12: in RightShift> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @RightShiftAssign, [template] +// CHECK:STDOUT: %.14: in RightShiftAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %RightShift.decl: invalid = interface_decl @RightShift [template = constants.%.2] {} +// CHECK:STDOUT: %RightShift.ref: type = name_ref RightShift, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc13: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %RightShiftAssign.decl: invalid = interface_decl @RightShiftAssign [template = constants.%.7] {} +// CHECK:STDOUT: %RightShiftAssign.ref: type = name_ref RightShiftAssign, %import_ref.2 [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc17_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc17_11.1 +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_17.1: C = param b +// CHECK:STDOUT: @TestOp.%b: C = bind_name b, %b.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %C.ref.loc21_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %a.loc21_15.1: C* = param a +// CHECK:STDOUT: @TestAssign.%a: C* = bind_name a, %a.loc21_15.1 +// CHECK:STDOUT: %C.ref.loc21_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc21_22.1: C = param b +// CHECK:STDOUT: @TestAssign.%b: C = bind_name b, %b.loc21_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @RightShift { +// CHECK:STDOUT: %import_ref.1: in RightShift> = import_ref ir1, inst+20, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @RightShiftAssign { +// CHECK:STDOUT: %import_ref.1: in RightShiftAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as RightShift { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_18.1: C = param other +// CHECK:STDOUT: %other.loc9_18.2: C = bind_name other, %other.loc9_18.1 +// CHECK:STDOUT: %C.ref.loc9_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as RightShiftAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14_21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %self.loc14_14.1: C* = param self +// CHECK:STDOUT: %self.loc14_14.3: C* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: C* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: %C.ref.loc14_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc14_24.1: C = param other +// CHECK:STDOUT: %other.loc14_24.2: C = bind_name other, %other.loc14_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc9_9.2: C](@impl.1.%other.loc9_18.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.1.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc14_14.3: C*](@impl.2.%other.loc14_24.2: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc17: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc18_12.2: init C = call %.loc18_12.1(%a.ref, %b.ref) to %.loc17 +// CHECK:STDOUT: return %.loc18_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%a: C*, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C* = name_ref a, %a +// CHECK:STDOUT: %.loc22_3.1: ref C = deref %a.ref +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc22_6.1: = bound_method %.loc22_3.1, %.1 +// CHECK:STDOUT: %.loc22_3.2: C* = addr_of %.loc22_3.1 +// CHECK:STDOUT: %.loc22_6.2: init () = call %.loc22_6.1(%.loc22_3.2, %b.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/sub.carbon b/toolchain/check/testdata/operators/overloaded/sub.carbon new file mode 100644 index 000000000000..a9bf34490889 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/sub.carbon @@ -0,0 +1,290 @@ +// 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 +// +// AUTOUPDATE + +// This file was generated from binary_op.carbon.tmpl. Run make_tests.sh to regenerate. + +// --- prelude.carbon + +package Core api; + +interface Sub { + fn Op[self: Self](other: Self) -> Self; +} +interface SubAssign { + fn Op[addr self: Self*](other: Self); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.Sub { + fn Op[self: C](other: C) -> C { + return {}; + } +} +impl C as Core.SubAssign { + fn Op[addr self: C*](other: C) {} +} + +fn TestOp(a: C, b: C) -> C { + return a - b; +} + +fn TestAssign(a: C*, b: C) { + *a -= b; +} + +// CHECK:STDOUT: --- prelude.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @Sub [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @Sub, [template] +// CHECK:STDOUT: %.3: in Sub> = assoc_entity element0, @Sub.%Op [template] +// CHECK:STDOUT: %.4: type = interface_type @SubAssign [template] +// CHECK:STDOUT: %.5: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.6: type = assoc_entity_type @SubAssign, [template] +// CHECK:STDOUT: %.7: in SubAssign> = assoc_entity element0, @SubAssign.%Op [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Sub = %Sub.decl +// CHECK:STDOUT: .SubAssign = %SubAssign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Sub.decl: type = interface_decl @Sub [template = constants.%.1] {} +// CHECK:STDOUT: %SubAssign.decl: type = interface_decl @SubAssign [template = constants.%.4] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Sub { +// CHECK:STDOUT: %Self: Sub = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc5_15: Sub = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.1: type = facet_type_access %Self.ref.loc5_15 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_15.2: type = converted %Self.ref.loc5_15, %.loc5_15.1 [symbolic = %Self] +// CHECK:STDOUT: %self.loc5_9.1: Self = param self +// CHECK:STDOUT: %self.loc5_9.2: Self = bind_name self, %self.loc5_9.1 +// CHECK:STDOUT: %Self.ref.loc5_28: Sub = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.1: type = facet_type_access %Self.ref.loc5_28 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_28.2: type = converted %Self.ref.loc5_28, %.loc5_28.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc5_21.1: Self = param other +// CHECK:STDOUT: %other.loc5_21.2: Self = bind_name other, %other.loc5_21.1 +// CHECK:STDOUT: %Self.ref.loc5_37: Sub = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.1: type = facet_type_access %Self.ref.loc5_37 [symbolic = %Self] +// CHECK:STDOUT: %.loc5_37.2: type = converted %Self.ref.loc5_37, %.loc5_37.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc5_41: in Sub> = assoc_entity element0, %Op [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc5_41 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @SubAssign { +// CHECK:STDOUT: %Self: SubAssign = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Op: = fn_decl @Op.2 [template] { +// CHECK:STDOUT: %Self.ref.loc8_20: SubAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.1: type = facet_type_access %Self.ref.loc8_20 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_20: type = converted %Self.ref.loc8_20, %.loc8_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type Self [symbolic = constants.%.5] +// CHECK:STDOUT: %self.loc8_14.1: Self* = param self +// CHECK:STDOUT: %self.loc8_14.3: Self* = bind_name self, %self.loc8_14.1 +// CHECK:STDOUT: %.loc8_9: Self* = addr_pattern %self.loc8_14.3 +// CHECK:STDOUT: %Self.ref.loc8_34: SubAssign = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.1: type = facet_type_access %Self.ref.loc8_34 [symbolic = %Self] +// CHECK:STDOUT: %.loc8_34.2: type = converted %Self.ref.loc8_34, %.loc8_34.1 [symbolic = %Self] +// CHECK:STDOUT: %other.loc8_27.1: Self = param other +// CHECK:STDOUT: %other.loc8_27.2: Self = bind_name other, %other.loc8_27.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_39: in SubAssign> = assoc_entity element0, %Op [template = constants.%.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Op = %.loc8_39 +// CHECK:STDOUT: witness = (%Op) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@Sub.%self.loc5_9.2: Self](@Sub.%other.loc5_21.2: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[addr @SubAssign.%self.loc8_14.3: Self*](@SubAssign.%other.loc8_27.2: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: --- user.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: type = interface_type @Sub [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: %.5: C = struct_value () [template] +// CHECK:STDOUT: %.6: = interface_witness (@impl.1.%Op) [template] +// CHECK:STDOUT: %.7: type = interface_type @SubAssign [template] +// CHECK:STDOUT: %.8: type = ptr_type C [template] +// CHECK:STDOUT: %.9: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%Op) [template] +// CHECK:STDOUT: %.11: type = assoc_entity_type @Sub, [template] +// CHECK:STDOUT: %.12: in Sub> = assoc_entity element0, @TestOp.%import_ref.2 [template] +// CHECK:STDOUT: %.13: type = assoc_entity_type @SubAssign, [template] +// CHECK:STDOUT: %.14: in SubAssign> = assoc_entity element0, @TestAssign.%import_ref.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .TestOp = %TestOp +// CHECK:STDOUT: .TestAssign = %TestAssign +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: impl_decl @impl.1 { +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc8: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %Sub.decl: invalid = interface_decl @Sub [template = constants.%.2] {} +// CHECK:STDOUT: %Sub.ref: type = name_ref Sub, %import_ref.1 [template = constants.%.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.2 { +// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %Core.ref.loc13: = name_ref Core, %Core [template = %Core] +// CHECK:STDOUT: %import_ref.2: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %SubAssign.decl: invalid = interface_decl @SubAssign [template = constants.%.7] {} +// CHECK:STDOUT: %SubAssign.ref: type = name_ref SubAssign, %import_ref.2 [template = constants.%.7] +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestOp: = fn_decl @TestOp [template] { +// CHECK:STDOUT: %C.ref.loc17_14: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %a.loc17_11.1: C = param a +// CHECK:STDOUT: @TestOp.%a: C = bind_name a, %a.loc17_11.1 +// CHECK:STDOUT: %C.ref.loc17_20: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc17_17.1: C = param b +// CHECK:STDOUT: @TestOp.%b: C = bind_name b, %b.loc17_17.1 +// CHECK:STDOUT: %C.ref.loc17_26: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: @TestOp.%return: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TestAssign: = fn_decl @TestAssign [template] { +// CHECK:STDOUT: %C.ref.loc21_18: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %a.loc21_15.1: C* = param a +// CHECK:STDOUT: @TestAssign.%a: C* = bind_name a, %a.loc21_15.1 +// CHECK:STDOUT: %C.ref.loc21_25: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %b.loc21_22.1: C = param b +// CHECK:STDOUT: @TestAssign.%b: C = bind_name b, %b.loc21_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Sub { +// CHECK:STDOUT: %import_ref.1: in Sub> = import_ref ir1, inst+20, used [template = constants.%.12] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+3, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+18, used [template = imports.%Op.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @SubAssign { +// CHECK:STDOUT: %import_ref.1: in SubAssign> = import_ref ir1, inst+40, used [template = constants.%.14] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+24, unused +// CHECK:STDOUT: %import_ref.3: = import_ref ir1, inst+38, used [template = imports.%Op.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %import_ref.1 +// CHECK:STDOUT: .Self = %import_ref.2 +// CHECK:STDOUT: witness = (%import_ref.3) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.1: C as Sub { +// CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %C.ref.loc9_15: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc9_9.1: C = param self +// CHECK:STDOUT: %self.loc9_9.2: C = bind_name self, %self.loc9_9.1 +// CHECK:STDOUT: %C.ref.loc9_25: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc9_18.1: C = param other +// CHECK:STDOUT: %other.loc9_18.2: C = bind_name other, %other.loc9_18.1 +// CHECK:STDOUT: %C.ref.loc9_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %return.var: ref C = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: C as SubAssign { +// CHECK:STDOUT: %Op: = fn_decl @Op.3 [template] { +// CHECK:STDOUT: %C.ref.loc14_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc14_21: type = ptr_type C [template = constants.%.8] +// CHECK:STDOUT: %self.loc14_14.1: C* = param self +// CHECK:STDOUT: %self.loc14_14.3: C* = bind_name self, %self.loc14_14.1 +// CHECK:STDOUT: %.loc14_9: C* = addr_pattern %self.loc14_14.3 +// CHECK:STDOUT: %C.ref.loc14_31: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %other.loc14_24.1: C = param other +// CHECK:STDOUT: %other.loc14_24.2: C = bind_name other, %other.loc14_24.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Op = %Op +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.1[@impl.1.%self.loc9_9.2: C](@impl.1.%other.loc9_18.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_13.1: {} = struct_literal () +// CHECK:STDOUT: %.loc10_13.2: init C = class_init (), @impl.1.%return.var [template = constants.%.5] +// CHECK:STDOUT: %.loc10_13.3: init C = converted %.loc10_13.1, %.loc10_13.2 [template = constants.%.5] +// CHECK:STDOUT: return %.loc10_13.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.3[addr @impl.2.%self.loc14_14.3: C*](@impl.2.%other.loc14_24.2: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Op.4[addr %self: Self*](%other: Self); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestOp(%a: C, %b: C) -> %return: C { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C = name_ref a, %a +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+1, used [template = constants.%.2] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+18, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.1.%.1, element0 [template = @impl.1.%Op] +// CHECK:STDOUT: %.loc18_12.1: = bound_method %a.ref, %.1 +// CHECK:STDOUT: %.loc17: ref C = splice_block %return {} +// CHECK:STDOUT: %.loc18_12.2: init C = call %.loc18_12.1(%a.ref, %b.ref) to %.loc17 +// CHECK:STDOUT: return %.loc18_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestAssign(%a: C*, %b: C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: C* = name_ref a, %a +// CHECK:STDOUT: %.loc22_3.1: ref C = deref %a.ref +// CHECK:STDOUT: %b.ref: C = name_ref b, %b +// CHECK:STDOUT: %import_ref.1: type = import_ref ir1, inst+22, used [template = constants.%.7] +// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+38, unused +// CHECK:STDOUT: %.1: = interface_witness_access @impl.2.%.1, element0 [template = @impl.2.%Op] +// CHECK:STDOUT: %.loc22_6.1: = bound_method %.loc22_3.1, %.1 +// CHECK:STDOUT: %.loc22_3.2: C* = addr_of %.loc22_3.1 +// CHECK:STDOUT: %.loc22_6.2: init () = call %.loc22_6.1(%.loc22_3.2, %b.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/operators/overloaded/unary_op.carbon.tmpl b/toolchain/check/testdata/operators/overloaded/unary_op.carbon.tmpl new file mode 100644 index 000000000000..6730d3c7e63f --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/unary_op.carbon.tmpl @@ -0,0 +1,33 @@ +// 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 +// +// AUTOUPDATE + +HEADER + +// --- prelude.carbon + +package Core api; + +interface INTERFACE { + fn Op[self: Self]() -> Self; +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.INTERFACE { + fn Op[self: C]() -> C { + return {}; + } +} + +fn TestOp(a: C) -> C { + return OPa; +} diff --git a/toolchain/check/testdata/operators/overloaded/unary_stmt.carbon.tmpl b/toolchain/check/testdata/operators/overloaded/unary_stmt.carbon.tmpl new file mode 100644 index 000000000000..34daef335465 --- /dev/null +++ b/toolchain/check/testdata/operators/overloaded/unary_stmt.carbon.tmpl @@ -0,0 +1,32 @@ +// 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 +// +// AUTOUPDATE + +HEADER + +// --- prelude.carbon + +package Core api; + +interface INTERFACE { + fn Op[addr self: Self*](); +} + +// --- user.carbon + +package User api; + +import Core; + +class C {}; + +impl C as Core.INTERFACE { + fn Op[addr self: C*](); +} + +fn TestOp() { + var c: C = {}; + OPc; +} diff --git a/toolchain/parse/node_ids.h b/toolchain/parse/node_ids.h index 6fa15b152bd9..93824d5cb25d 100644 --- a/toolchain/parse/node_ids.h +++ b/toolchain/parse/node_ids.h @@ -65,7 +65,6 @@ struct NodeIdInCategory : public NodeId { using AnyDeclId = NodeIdInCategory; using AnyExprId = NodeIdInCategory; using AnyImplAsId = NodeIdInCategory; -using AnyMemberNameId = NodeIdInCategory; using AnyMemberNameOrMemberExprId = NodeIdInCategory; using AnyModifierId = NodeIdInCategory; @@ -94,8 +93,6 @@ using AnyImplDeclId = NodeIdOneOf; using AnyInterfaceDeclId = NodeIdOneOf; using AnyNamespaceId = NodeIdOneOf; -using AnyMemberAccessExprId = - NodeIdOneOf; using AnyPointerDeferenceExprId = NodeIdOneOf; diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index 728d0b2ce3f1..755fc4b7fe33 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -273,8 +273,7 @@ struct BoolLiteral { // `self` parameter, such as `object.MethodName`. struct BoundMethod { static constexpr auto Kind = - InstKind::BoundMethod.Define( - "bound_method"); + InstKind::BoundMethod.Define("bound_method"); TypeId type_id; // The object argument in the bound method, which will be used to initialize @@ -335,8 +334,10 @@ struct Builtin { }; struct Call { - static constexpr auto Kind = - InstKind::Call.Define("call"); + // For a syntactic call, the parse node will be a CallExprStartId. However, + // calls can arise from other syntaxes, such as operators and implicit + // conversions. + static constexpr auto Kind = InstKind::Call.Define("call"); TypeId type_id; InstId callee_id;