From e81d171226c91f81f220f54d3122a9db7972af79 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 13 Sep 2023 17:49:55 -0700 Subject: [PATCH] Switch to modeling array initialization analogously to a function call. (#3205) Instead of modeling array initialization as a thin wrapper around tuple initialization, handle it like a function call, with a return slot as part of its input. This better matches how initialization via a call to `ImplicitAs::Convert` will eventually work, and in particular lets us do in-place initialization of arrays rather than always creating a temporary. --- toolchain/check/context.cpp | 166 ++++++++++++++++-- toolchain/check/context.h | 9 + .../testdata/array/assign_return_value.carbon | 11 +- .../check/testdata/array/assign_var.carbon | 21 ++- toolchain/check/testdata/array/base.carbon | 34 +++- .../testdata/array/fail_out_of_bound.carbon | 4 +- .../testdata/array/fail_type_mismatch.carbon | 83 +++++++-- .../testdata/array/function_param.carbon | 57 ++++++ .../check/testdata/array/nine_elements.carbon | 32 +++- .../testdata/basics/numeric_literals.carbon | 46 ++++- .../index/array_element_access.carbon | 11 +- .../index/fail_array_large_index.carbon | 8 +- .../index/fail_array_non_int_indexing.carbon | 8 +- .../fail_array_out_of_bound_access.carbon | 8 +- toolchain/diagnostics/diagnostic_kind.def | 2 + toolchain/lower/handle.cpp | 42 ++--- .../testdata/array/assign_return_value.carbon | 17 +- toolchain/lower/testdata/array/base.carbon | 133 ++++++-------- .../testdata/array/function_param.carbon | 44 +++++ .../testdata/basics/numeric_literals.carbon | 86 ++++----- .../index/array_element_access.carbon | 58 +++--- toolchain/sem_ir/file.cpp | 12 +- toolchain/sem_ir/formatter.cpp | 35 +++- toolchain/sem_ir/node.h | 17 +- toolchain/sem_ir/node_kind.def | 4 +- 25 files changed, 686 insertions(+), 262 deletions(-) create mode 100644 toolchain/check/testdata/array/function_param.carbon create mode 100644 toolchain/lower/testdata/array/function_param.carbon diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 17790f0db3d2..8af78abc7fa6 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -293,6 +293,23 @@ auto Context::Initialize(Parse::Node parse_node, SemIR::NodeId target_id, } } +auto Context::InitializeAndFinalize(Parse::Node parse_node, + SemIR::NodeId target_id, + SemIR::NodeId value_id) -> SemIR::NodeId { + auto init_id = Initialize(parse_node, target_id, value_id); + if (init_id == SemIR::NodeId::BuiltinError) { + return init_id; + } + auto target_type_id = semantics_ir().GetNode(target_id).type_id(); + if (auto init_rep = + SemIR::GetInitializingRepresentation(semantics_ir(), target_type_id); + init_rep.kind == SemIR::InitializingRepresentation::ByCopy) { + init_id = AddNode(SemIR::Node::InitializeFrom::Make( + parse_node, target_type_id, init_id, target_id)); + } + return init_id; +} + auto Context::ConvertToValueExpression(SemIR::NodeId expr_id) -> SemIR::NodeId { if (expr_id == SemIR::NodeId::BuiltinError) { return expr_id; @@ -376,6 +393,19 @@ auto Context::FinalizeTemporary(SemIR::NodeId init_id, bool discarded) return AddNode(SemIR::Node::Temporary::Make( init.parse_node(), init.type_id(), temporary_id, init_id)); } + + case SemIR::NodeKind::ArrayInit: { + auto [src_id, refs_id] = init.GetAsArrayInit(); + // The return slot should have a materialized temporary in it. + auto temporary_id = semantics_ir().GetNodeBlock(refs_id).back(); + CARBON_CHECK(semantics_ir().GetNode(temporary_id).kind() == + SemIR::NodeKind::TemporaryStorage) + << "Return slot for array init does not contain a temporary; " + << "initialized multiple times? Have " + << semantics_ir().GetNode(temporary_id); + return AddNode(SemIR::Node::Temporary::Make( + init.parse_node(), init.type_id(), temporary_id, orig_init_id)); + } } } } @@ -416,6 +446,26 @@ auto Context::MarkInitializerFor(SemIR::NodeId init_id, SemIR::NodeId target_id) } return; } + + case SemIR::NodeKind::ArrayInit: { + // Rewrite the return slot as a reference to our target. We can't just + // update the index in `refs_id`, like we do for a Call, because there + // will be other references to the return slot for the individual array + // element initializers. + auto [src_id, refs_id] = init.GetAsArrayInit(); + auto temporary_id = semantics_ir().GetNodeBlock(refs_id).back(); + CARBON_CHECK(semantics_ir().GetNode(temporary_id).kind() == + SemIR::NodeKind::TemporaryStorage) + << "Return slot for array init does not contain a temporary; " + << "initialized multiple times? Have " + << semantics_ir().GetNode(temporary_id); + semantics_ir().ReplaceNode( + temporary_id, + SemIR::Node::StubReference::Make( + init.parse_node(), semantics_ir().GetNode(target_id).type_id(), + target_id)); + return; + } } } } @@ -499,6 +549,97 @@ auto Context::ImplicitAsForArgs(Parse::Node call_parse_node, return true; } +// Performs a conversion from a tuple to an array type. +static auto ConvertTupleToArray(Context& context, SemIR::Node tuple_type, + SemIR::Node array_type, + SemIR::TypeId array_type_id, + SemIR::NodeId value_id) -> SemIR::NodeId { + auto [array_bound_id, element_type_id] = array_type.GetAsArrayType(); + auto tuple_elem_types_id = tuple_type.GetAsTupleType(); + const auto& tuple_elem_types = + context.semantics_ir().GetTypeBlock(tuple_elem_types_id); + + // Skip back over StubReferences to find if we're being initialized from a + // tuple literal. + auto value = context.semantics_ir().GetNode(value_id); + while (value.kind() == SemIR::NodeKind::StubReference) { + value_id = value.GetAsStubReference(); + value = context.semantics_ir().GetNode(value_id); + } + + llvm::ArrayRef literal_elems; + if (value.kind() == SemIR::NodeKind::TupleLiteral) { + literal_elems = + context.semantics_ir().GetNodeBlock(value.GetAsTupleLiteral()); + } + + // Check that the tuple is the right size. + uint64_t array_bound = + context.semantics_ir().GetArrayBoundValue(array_bound_id); + if (tuple_elem_types.size() != array_bound) { + CARBON_DIAGNOSTIC( + ArrayInitFromLiteralArgCountMismatch, Error, + "Cannot initialize array of {0} element(s) from {1} initializer(s).", + uint64_t, size_t); + CARBON_DIAGNOSTIC(ArrayInitFromExpressionArgCountMismatch, Error, + "Cannot initialize array of {0} element(s) from tuple " + "with {1} element(s).", + uint64_t, size_t); + context.emitter().Emit( + context.semantics_ir().GetNode(value_id).parse_node(), + literal_elems.empty() ? ArrayInitFromExpressionArgCountMismatch + : ArrayInitFromLiteralArgCountMismatch, + array_bound, tuple_elem_types.size()); + return SemIR::NodeId::BuiltinError; + } + + // If we're initializing from a tuple literal, we will use its elements + // directly. Otherwise, materialize a temporary if needed and index into the + // result. + if (literal_elems.empty()) { + value_id = context.MaterializeIfInitializing(value_id); + } + + // Arrays are always initialized in-place. Tentatively allocate a temporary + // as the destination for the array initialization. + auto return_slot_id = context.AddNode( + SemIR::Node::TemporaryStorage::Make(value.parse_node(), array_type_id)); + + // Initialize each element of the array from the corresponding element of the + // tuple. + llvm::SmallVector inits; + inits.reserve(array_bound + 1); + for (auto [i, src_type_id] : llvm::enumerate(tuple_elem_types)) { + // TODO: Add a new node kind for indexing an array at a constant index + // so that we don't need an integer literal node here. + auto index_id = context.AddNode(SemIR::Node::IntegerLiteral::Make( + value.parse_node(), + context.CanonicalizeType(SemIR::NodeId::BuiltinIntegerType), + context.semantics_ir().AddIntegerLiteral(llvm::APInt(32, i)))); + auto target_id = context.AddNode(SemIR::Node::ArrayIndex::Make( + value.parse_node(), element_type_id, return_slot_id, index_id)); + auto src_id = + !literal_elems.empty() + ? literal_elems[i] + : context.AddNode(SemIR::Node::TupleIndex::Make( + value.parse_node(), src_type_id, value_id, index_id)); + auto init_id = + context.InitializeAndFinalize(value.parse_node(), target_id, src_id); + if (init_id == SemIR::NodeId::BuiltinError) { + return SemIR::NodeId::BuiltinError; + } + inits.push_back(init_id); + } + + // The last element of the refs block contains the return slot for the array + // initialization. + inits.push_back(return_slot_id); + + return context.AddNode( + SemIR::Node::ArrayInit::Make(value.parse_node(), array_type_id, value_id, + context.semantics_ir().AddNodeBlock(inits))); +} + auto Context::ImplicitAs(Parse::Node parse_node, SemIR::NodeId value_id, SemIR::TypeId as_type_id) -> SemIR::NodeId { // Start by making sure both sides are valid. If any part is invalid, the @@ -520,29 +661,22 @@ auto Context::ImplicitAs(Parse::Node parse_node, SemIR::NodeId value_id, auto as_type = semantics_ir_->GetTypeAllowBuiltinTypes(as_type_id); auto as_type_node = semantics_ir_->GetNode(as_type); + + // A tuple (T1, T2, ..., Tn) converts to [T; n] if each Ti converts to T. if (as_type_node.kind() == SemIR::NodeKind::ArrayType) { - auto [bound_node_id, element_type_id] = as_type_node.GetAsArrayType(); - // To resolve lambda issue. - auto element_type = element_type_id; auto value_type_node = semantics_ir_->GetNode( semantics_ir_->GetTypeAllowBuiltinTypes(value_type_id)); if (value_type_node.kind() == SemIR::NodeKind::TupleType) { - auto tuple_type_block_id = value_type_node.GetAsTupleType(); - const auto& type_block = semantics_ir_->GetTypeBlock(tuple_type_block_id); - if (type_block.size() == - semantics_ir_->GetArrayBoundValue(bound_node_id) && - std::all_of(type_block.begin(), type_block.end(), - [&](auto type) { return type == element_type; })) { - // TODO: We should convert an initializing expression of tuple type - // to an initializing expression of array type. - value_id = ConvertToValueExpression(value_id); - return AddNode(SemIR::Node::ArrayValue::Make(value.parse_node(), - as_type_id, value_id)); - } + // The conversion from tuple to array is `final`, so we don't need a + // fallback path here. + return ConvertTupleToArray(*this, value_type_node, as_type_node, + as_type_id, value_id); } } if (as_type_id == SemIR::TypeId::TypeType) { + // A tuple of types converts to type `type`. + // TODO: This should apply even for non-literal tuples. if (value.kind() == SemIR::NodeKind::TupleLiteral) { auto tuple_block_id = value.GetAsTupleLiteral(); llvm::SmallVector type_ids; @@ -561,7 +695,7 @@ auto Context::ImplicitAs(Parse::Node parse_node, SemIR::NodeId value_id, CanonicalizeTupleType(value.parse_node(), std::move(type_ids)); return semantics_ir_->GetTypeAllowBuiltinTypes(tuple_type_id); } - // When converting `{}` to a type, the result is `{} as Type`. + // When converting `{}` to a type, the result is `{} as type`. if (value.kind() == SemIR::NodeKind::StructLiteral && value.GetAsStructLiteral() == SemIR::NodeBlockId::Empty) { return semantics_ir_->GetType(value_type_id); diff --git a/toolchain/check/context.h b/toolchain/check/context.h index e7dc352b5d98..f4a9c699862b 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -124,6 +124,15 @@ class Context { auto Initialize(Parse::Node parse_node, SemIR::NodeId target_id, SemIR::NodeId value_id) -> SemIR::NodeId; + // Performs and finalizes initialization of `target_id` from `value_id`. This + // is the same as `Initialize`, except that it also performs the final store + // from the initializer to the target if the initialization is not in-place. + // That final store is often undesirable as it is performed by the consumer + // of the initializer, such as an `Assign` or `ReturnExpression` node. The + // resulting node describes the initialization operation that was performed. + auto InitializeAndFinalize(Parse::Node parse_node, SemIR::NodeId target_id, + SemIR::NodeId value_id) -> SemIR::NodeId; + // Converts `value_id` to a value expression of type `type_id`. auto ConvertToValueOfType(Parse::Node parse_node, SemIR::NodeId value_id, SemIR::TypeId type_id) -> SemIR::NodeId { diff --git a/toolchain/check/testdata/array/assign_return_value.carbon b/toolchain/check/testdata/array/assign_return_value.carbon index 1ba6a2d54d11..7bc344bf529f 100644 --- a/toolchain/check/testdata/array/assign_return_value.carbon +++ b/toolchain/check/testdata/array/assign_return_value.carbon @@ -31,8 +31,13 @@ fn Run() { // CHECK:STDOUT: %.loc10_22.1: init (i32,) = call @F() // CHECK:STDOUT: %.loc10_22.2: ref (i32,) = temporary_storage // CHECK:STDOUT: %.loc10_22.3: ref (i32,) = temporary %.loc10_22.2, %.loc10_22.1 -// CHECK:STDOUT: %.loc10_22.4: (i32,) = bind_value %.loc10_22.3 -// CHECK:STDOUT: %.loc10_22.5: [i32; 1] = array_value %.loc10_22.4 -// CHECK:STDOUT: assign %t, %.loc10_22.5 +// CHECK:STDOUT: %.loc10_22.4: ref [i32; 1] = stub_reference %t +// CHECK:STDOUT: %.loc10_22.5: i32 = int_literal 0 +// CHECK:STDOUT: %.loc10_22.6: ref i32 = array_index %.loc10_22.4, %.loc10_22.5 +// CHECK:STDOUT: %.loc10_22.7: ref i32 = tuple_index %.loc10_22.3, %.loc10_22.5 +// CHECK:STDOUT: %.loc10_22.8: i32 = bind_value %.loc10_22.7 +// CHECK:STDOUT: %.loc10_22.9: init i32 = initialize_from %.loc10_22.8 to %.loc10_22.6 +// CHECK:STDOUT: %.loc10_22.10: init [i32; 1] = array_init %.loc10_22.3, (%.loc10_22.9) to %.loc10_22.4 +// CHECK:STDOUT: assign %t, %.loc10_22.10 // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/array/assign_var.carbon b/toolchain/check/testdata/array/assign_var.carbon index 91d193666efe..2bff509752f6 100644 --- a/toolchain/check/testdata/array/assign_var.carbon +++ b/toolchain/check/testdata/array/assign_var.carbon @@ -26,7 +26,22 @@ var b: [i32; 3] = a; // CHECK:STDOUT: %.loc8_14: i32 = int_literal 3 // CHECK:STDOUT: %.loc8_15: type = array_type %.loc8_14, i32 // CHECK:STDOUT: %b: ref [i32; 3] = var "b" -// CHECK:STDOUT: %.loc7_5.1: (i32, i32, i32) = bind_value %a -// CHECK:STDOUT: %.loc7_5.2: [i32; 3] = array_value %.loc7_5.1 -// CHECK:STDOUT: assign %b, %.loc7_5.2 +// CHECK:STDOUT: %.loc7_5.1: ref [i32; 3] = stub_reference %b +// CHECK:STDOUT: %.loc7_5.2: i32 = int_literal 0 +// CHECK:STDOUT: %.loc7_5.3: ref i32 = array_index %.loc7_5.1, %.loc7_5.2 +// CHECK:STDOUT: %.loc7_5.4: ref i32 = tuple_index %a, %.loc7_5.2 +// CHECK:STDOUT: %.loc7_5.5: i32 = bind_value %.loc7_5.4 +// CHECK:STDOUT: %.loc7_5.6: init i32 = initialize_from %.loc7_5.5 to %.loc7_5.3 +// CHECK:STDOUT: %.loc7_5.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc7_5.8: ref i32 = array_index %.loc7_5.1, %.loc7_5.7 +// CHECK:STDOUT: %.loc7_5.9: ref i32 = tuple_index %a, %.loc7_5.7 +// CHECK:STDOUT: %.loc7_5.10: i32 = bind_value %.loc7_5.9 +// CHECK:STDOUT: %.loc7_5.11: init i32 = initialize_from %.loc7_5.10 to %.loc7_5.8 +// CHECK:STDOUT: %.loc7_5.12: i32 = int_literal 2 +// CHECK:STDOUT: %.loc7_5.13: ref i32 = array_index %.loc7_5.1, %.loc7_5.12 +// CHECK:STDOUT: %.loc7_5.14: ref i32 = tuple_index %a, %.loc7_5.12 +// CHECK:STDOUT: %.loc7_5.15: i32 = bind_value %.loc7_5.14 +// CHECK:STDOUT: %.loc7_5.16: init i32 = initialize_from %.loc7_5.15 to %.loc7_5.13 +// CHECK:STDOUT: %.loc7_5.17: init [i32; 3] = array_init %a, (%.loc7_5.6, %.loc7_5.11, %.loc7_5.16) to %.loc7_5.1 +// CHECK:STDOUT: assign %b, %.loc7_5.17 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/array/base.carbon b/toolchain/check/testdata/array/base.carbon index ccd6cb750783..f0201edc9daf 100644 --- a/toolchain/check/testdata/array/base.carbon +++ b/toolchain/check/testdata/array/base.carbon @@ -16,8 +16,12 @@ var c: [(); 5] = ((), (), (), (), (),); // CHECK:STDOUT: %.loc7_20.2: i32 = stub_reference %.loc7_20.1 // CHECK:STDOUT: %.loc7_22.1: type = tuple_type (i32) // CHECK:STDOUT: %.loc7_22.2: (i32,) = tuple_literal (%.loc7_20.2) -// CHECK:STDOUT: %.loc7_22.3: [i32; 1] = array_value %.loc7_22.2 -// CHECK:STDOUT: assign %a, %.loc7_22.3 +// CHECK:STDOUT: %.loc7_22.3: ref [i32; 1] = stub_reference %a +// CHECK:STDOUT: %.loc7_22.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc7_22.5: ref i32 = array_index %.loc7_22.3, %.loc7_22.4 +// CHECK:STDOUT: %.loc7_22.6: init i32 = initialize_from %.loc7_20.2 to %.loc7_22.5 +// CHECK:STDOUT: %.loc7_22.7: init [i32; 1] = array_init %.loc7_22.2, (%.loc7_22.6) to %.loc7_22.3 +// CHECK:STDOUT: assign %a, %.loc7_22.7 // CHECK:STDOUT: %.loc8_14: i32 = int_literal 2 // CHECK:STDOUT: %.loc8_15: type = array_type %.loc8_14, f64 // CHECK:STDOUT: %b: ref [f64; 2] = var "b" @@ -27,8 +31,15 @@ var c: [(); 5] = ((), (), (), (), (),); // CHECK:STDOUT: %.loc8_26.2: f64 = stub_reference %.loc8_26.1 // CHECK:STDOUT: %.loc8_30.1: type = tuple_type (f64, f64) // CHECK:STDOUT: %.loc8_30.2: (f64, f64) = tuple_literal (%.loc8_20.2, %.loc8_26.2) -// CHECK:STDOUT: %.loc8_30.3: [f64; 2] = array_value %.loc8_30.2 -// CHECK:STDOUT: assign %b, %.loc8_30.3 +// CHECK:STDOUT: %.loc8_30.3: ref [f64; 2] = stub_reference %b +// CHECK:STDOUT: %.loc8_30.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc8_30.5: ref f64 = array_index %.loc8_30.3, %.loc8_30.4 +// CHECK:STDOUT: %.loc8_30.6: init f64 = initialize_from %.loc8_20.2 to %.loc8_30.5 +// CHECK:STDOUT: %.loc8_30.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc8_30.8: ref f64 = array_index %.loc8_30.3, %.loc8_30.7 +// CHECK:STDOUT: %.loc8_30.9: init f64 = initialize_from %.loc8_26.2 to %.loc8_30.8 +// CHECK:STDOUT: %.loc8_30.10: init [f64; 2] = array_init %.loc8_30.2, (%.loc8_30.6, %.loc8_30.9) to %.loc8_30.3 +// CHECK:STDOUT: assign %b, %.loc8_30.10 // CHECK:STDOUT: %.loc9_10.1: type = tuple_type () // CHECK:STDOUT: %.loc9_10.2: () = tuple_literal () // CHECK:STDOUT: %.loc9_13: i32 = int_literal 5 @@ -46,6 +57,17 @@ var c: [(); 5] = ((), (), (), (), (),); // CHECK:STDOUT: %.loc9_36.2: () = stub_reference %.loc9_36.1 // CHECK:STDOUT: %.loc9_38.1: type = tuple_type ((), (), (), (), ()) // CHECK:STDOUT: %.loc9_38.2: ((), (), (), (), ()) = tuple_literal (%.loc9_20.2, %.loc9_24.2, %.loc9_28.2, %.loc9_32.2, %.loc9_36.2) -// CHECK:STDOUT: %.loc9_38.3: [(); 5] = array_value %.loc9_38.2 -// CHECK:STDOUT: assign %c, %.loc9_38.3 +// CHECK:STDOUT: %.loc9_38.3: ref [(); 5] = stub_reference %c +// CHECK:STDOUT: %.loc9_38.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc9_38.5: ref () = array_index %.loc9_38.3, %.loc9_38.4 +// CHECK:STDOUT: %.loc9_38.6: i32 = int_literal 1 +// CHECK:STDOUT: %.loc9_38.7: ref () = array_index %.loc9_38.3, %.loc9_38.6 +// CHECK:STDOUT: %.loc9_38.8: i32 = int_literal 2 +// CHECK:STDOUT: %.loc9_38.9: ref () = array_index %.loc9_38.3, %.loc9_38.8 +// CHECK:STDOUT: %.loc9_38.10: i32 = int_literal 3 +// CHECK:STDOUT: %.loc9_38.11: ref () = array_index %.loc9_38.3, %.loc9_38.10 +// CHECK:STDOUT: %.loc9_38.12: i32 = int_literal 4 +// CHECK:STDOUT: %.loc9_38.13: ref () = array_index %.loc9_38.3, %.loc9_38.12 +// CHECK:STDOUT: %.loc9_38.14: init [(); 5] = array_init %.loc9_38.2, (%.loc9_20.2, %.loc9_24.2, %.loc9_28.2, %.loc9_32.2, %.loc9_36.2) to %.loc9_38.3 +// CHECK:STDOUT: assign %c, %.loc9_38.14 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/array/fail_out_of_bound.carbon b/toolchain/check/testdata/array/fail_out_of_bound.carbon index e8c55b0bac1d..701b32b712c4 100644 --- a/toolchain/check/testdata/array/fail_out_of_bound.carbon +++ b/toolchain/check/testdata/array/fail_out_of_bound.carbon @@ -4,9 +4,9 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_out_of_bound.carbon:[[@LINE+3]]:28: Cannot implicitly convert from `(i32, i32, i32) as type` to `[i32; 1]`. +// CHECK:STDERR: fail_out_of_bound.carbon:[[@LINE+3]]:27: Cannot initialize array of 1 element(s) from 3 initializer(s). // CHECK:STDERR: var a: [i32; 1] = (1, 2, 3); -// CHECK:STDERR: ^ +// CHECK:STDERR: ^ var a: [i32; 1] = (1, 2, 3); // CHECK:STDOUT: file "fail_out_of_bound.carbon" { diff --git a/toolchain/check/testdata/array/fail_type_mismatch.carbon b/toolchain/check/testdata/array/fail_type_mismatch.carbon index 6101c30c4870..b76ab6c6a59e 100644 --- a/toolchain/check/testdata/array/fail_type_mismatch.carbon +++ b/toolchain/check/testdata/array/fail_type_mismatch.carbon @@ -4,20 +4,83 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE+3]]:27: Cannot implicitly convert from `(i32, f64) as type` to `[i32; 2]`. -// CHECK:STDERR: var a: [i32; 2] = (1, 2.5); -// CHECK:STDERR: ^ -var a: [i32; 2] = (1, 2.5); +// CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE+3]]:39: Cannot implicitly convert from `String` to `i32`. +// CHECK:STDERR: var a: [i32; 3] = (1, "Hello", "World"); +// CHECK:STDERR: ^ +var a: [i32; 3] = (1, "Hello", "World"); + +// CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE+3]]:5: Cannot implicitly convert from `String` to `i32`. +// CHECK:STDERR: var t1: (i32, String, String); +// CHECK:STDERR: ^ +var t1: (i32, String, String); +var b: [i32; 3] = t1; + +// CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE+3]]:24: Cannot initialize array of 3 element(s) from 2 initializer(s). +// CHECK:STDERR: var c: [i32; 3] = (1, 2); +// CHECK:STDERR: ^ +var c: [i32; 3] = (1, 2); + +// CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE+3]]:5: Cannot initialize array of 3 element(s) from tuple with 2 element(s). +// CHECK:STDERR: var t2: (i32, i32); +// CHECK:STDERR: ^ +var t2: (i32, i32); +var d: [i32; 3] = t2; // CHECK:STDOUT: file "fail_type_mismatch.carbon" { -// CHECK:STDOUT: %.loc10_14: i32 = int_literal 2 +// CHECK:STDOUT: %.loc10_14: i32 = int_literal 3 // CHECK:STDOUT: %.loc10_15: type = array_type %.loc10_14, i32 -// CHECK:STDOUT: %a: ref [i32; 2] = var "a" +// CHECK:STDOUT: %a: ref [i32; 3] = var "a" // CHECK:STDOUT: %.loc10_20.1: i32 = int_literal 1 // CHECK:STDOUT: %.loc10_20.2: i32 = stub_reference %.loc10_20.1 -// CHECK:STDOUT: %.loc10_23.1: f64 = real_literal 25e-1 -// CHECK:STDOUT: %.loc10_23.2: f64 = stub_reference %.loc10_23.1 -// CHECK:STDOUT: %.loc10_26.1: type = tuple_type (i32, f64) -// CHECK:STDOUT: %.loc10_26.2: (i32, f64) = tuple_literal (%.loc10_20.2, %.loc10_23.2) +// CHECK:STDOUT: %.loc10_23.1: String = string_literal "Hello" +// CHECK:STDOUT: %.loc10_23.2: String = stub_reference %.loc10_23.1 +// CHECK:STDOUT: %.loc10_32.1: String = string_literal "World" +// CHECK:STDOUT: %.loc10_32.2: String = stub_reference %.loc10_32.1 +// CHECK:STDOUT: %.loc10_39.1: type = tuple_type (i32, String, String) +// CHECK:STDOUT: %.loc10_39.2: (i32, String, String) = tuple_literal (%.loc10_20.2, %.loc10_23.2, %.loc10_32.2) +// CHECK:STDOUT: %.loc10_39.3: ref [i32; 3] = temporary_storage +// CHECK:STDOUT: %.loc10_39.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc10_39.5: ref i32 = array_index %.loc10_39.3, %.loc10_39.4 +// CHECK:STDOUT: %.loc10_39.6: init i32 = initialize_from %.loc10_20.2 to %.loc10_39.5 +// CHECK:STDOUT: %.loc10_39.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc10_39.8: ref i32 = array_index %.loc10_39.3, %.loc10_39.7 // CHECK:STDOUT: assign %a, +// CHECK:STDOUT: %.loc15_10: type = stub_reference i32 +// CHECK:STDOUT: %.loc15_15: type = stub_reference String +// CHECK:STDOUT: %.loc15_23: type = stub_reference String +// CHECK:STDOUT: %.loc15_29.1: type = tuple_type (type, type, type) +// CHECK:STDOUT: %.loc15_29.2: (type, type, type) = tuple_literal (%.loc15_10, %.loc15_15, %.loc15_23) +// CHECK:STDOUT: %t1: ref (i32, String, String) = var "t1" +// CHECK:STDOUT: %.loc16_14: i32 = int_literal 3 +// CHECK:STDOUT: %.loc16_15: type = array_type %.loc16_14, i32 +// CHECK:STDOUT: %b: ref [i32; 3] = var "b" +// CHECK:STDOUT: %.loc15_5.1: ref [i32; 3] = temporary_storage +// CHECK:STDOUT: %.loc15_5.2: i32 = int_literal 0 +// CHECK:STDOUT: %.loc15_5.3: ref i32 = array_index %.loc15_5.1, %.loc15_5.2 +// CHECK:STDOUT: %.loc15_5.4: ref i32 = tuple_index %t1, %.loc15_5.2 +// CHECK:STDOUT: %.loc15_5.5: i32 = bind_value %.loc15_5.4 +// CHECK:STDOUT: %.loc15_5.6: init i32 = initialize_from %.loc15_5.5 to %.loc15_5.3 +// CHECK:STDOUT: %.loc15_5.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc15_5.8: ref i32 = array_index %.loc15_5.1, %.loc15_5.7 +// CHECK:STDOUT: %.loc15_5.9: ref String = tuple_index %t1, %.loc15_5.7 +// CHECK:STDOUT: assign %b, +// CHECK:STDOUT: %.loc21_14: i32 = int_literal 3 +// CHECK:STDOUT: %.loc21_15: type = array_type %.loc21_14, i32 +// CHECK:STDOUT: %c: ref [i32; 3] = var "c" +// CHECK:STDOUT: %.loc21_20.1: i32 = int_literal 1 +// CHECK:STDOUT: %.loc21_20.2: i32 = stub_reference %.loc21_20.1 +// CHECK:STDOUT: %.loc21_23.1: i32 = int_literal 2 +// CHECK:STDOUT: %.loc21_23.2: i32 = stub_reference %.loc21_23.1 +// CHECK:STDOUT: %.loc21_24.1: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc21_24.2: (i32, i32) = tuple_literal (%.loc21_20.2, %.loc21_23.2) +// CHECK:STDOUT: assign %c, +// CHECK:STDOUT: %.loc26_10: type = stub_reference i32 +// CHECK:STDOUT: %.loc26_15: type = stub_reference i32 +// CHECK:STDOUT: %.loc26_18.1: type = tuple_type (type, type) +// CHECK:STDOUT: %.loc26_18.2: (type, type) = tuple_literal (%.loc26_10, %.loc26_15) +// CHECK:STDOUT: %t2: ref (i32, i32) = var "t2" +// CHECK:STDOUT: %.loc27_14: i32 = int_literal 3 +// CHECK:STDOUT: %.loc27_15: type = array_type %.loc27_14, i32 +// CHECK:STDOUT: %d: ref [i32; 3] = var "d" +// CHECK:STDOUT: assign %d, // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/array/function_param.carbon b/toolchain/check/testdata/array/function_param.carbon new file mode 100644 index 000000000000..f88dfdea8091 --- /dev/null +++ b/toolchain/check/testdata/array/function_param.carbon @@ -0,0 +1,57 @@ +// 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 F(arr: [i32; 3], i: i32) -> i32 { + return arr[i]; +} + +fn G() -> i32 { + return F((1, 2, 3), 1); +} + +// CHECK:STDOUT: file "function_param.carbon" { +// CHECK:STDOUT: %.loc7 = fn_decl @F +// CHECK:STDOUT: %.loc11 = fn_decl @G +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%arr: [i32; 3], %i: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc8: i32 = array_index %arr, %i +// CHECK:STDOUT: return %.loc8 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G() -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc12_13.1: i32 = int_literal 1 +// CHECK:STDOUT: %.loc12_13.2: i32 = stub_reference %.loc12_13.1 +// CHECK:STDOUT: %.loc12_16.1: i32 = int_literal 2 +// CHECK:STDOUT: %.loc12_16.2: i32 = stub_reference %.loc12_16.1 +// CHECK:STDOUT: %.loc12_19.1: i32 = int_literal 3 +// CHECK:STDOUT: %.loc12_19.2: i32 = stub_reference %.loc12_19.1 +// CHECK:STDOUT: %.loc12_20.1: type = tuple_type (i32, i32, i32) +// CHECK:STDOUT: %.loc12_20.2: (i32, i32, i32) = tuple_literal (%.loc12_13.2, %.loc12_16.2, %.loc12_19.2) +// CHECK:STDOUT: %.loc12_20.3: (i32, i32, i32) = stub_reference %.loc12_20.2 +// CHECK:STDOUT: %.loc12_23.1: i32 = int_literal 1 +// CHECK:STDOUT: %.loc12_23.2: i32 = stub_reference %.loc12_23.1 +// CHECK:STDOUT: %.loc12_20.4: ref [i32; 3] = temporary_storage +// CHECK:STDOUT: %.loc12_20.5: i32 = int_literal 0 +// CHECK:STDOUT: %.loc12_20.6: ref i32 = array_index %.loc12_20.4, %.loc12_20.5 +// CHECK:STDOUT: %.loc12_20.7: init i32 = initialize_from %.loc12_13.2 to %.loc12_20.6 +// CHECK:STDOUT: %.loc12_20.8: i32 = int_literal 1 +// CHECK:STDOUT: %.loc12_20.9: ref i32 = array_index %.loc12_20.4, %.loc12_20.8 +// CHECK:STDOUT: %.loc12_20.10: init i32 = initialize_from %.loc12_16.2 to %.loc12_20.9 +// CHECK:STDOUT: %.loc12_20.11: i32 = int_literal 2 +// CHECK:STDOUT: %.loc12_20.12: ref i32 = array_index %.loc12_20.4, %.loc12_20.11 +// CHECK:STDOUT: %.loc12_20.13: init i32 = initialize_from %.loc12_19.2 to %.loc12_20.12 +// CHECK:STDOUT: %.loc12_20.14: init [i32; 3] = array_init %.loc12_20.2, (%.loc12_20.7, %.loc12_20.10, %.loc12_20.13) to %.loc12_20.4 +// CHECK:STDOUT: %.loc12_20.15: ref [i32; 3] = temporary %.loc12_20.4, %.loc12_20.14 +// CHECK:STDOUT: %.loc12_20.16: [i32; 3] = bind_value %.loc12_20.15 +// CHECK:STDOUT: %.loc12_11.1: init i32 = call @F(%.loc12_20.16, %.loc12_23.2) +// CHECK:STDOUT: %.loc12_11.2: ref i32 = temporary_storage +// CHECK:STDOUT: %.loc12_11.3: ref i32 = temporary %.loc12_11.2, %.loc12_11.1 +// CHECK:STDOUT: %.loc12_11.4: i32 = bind_value %.loc12_11.3 +// CHECK:STDOUT: return %.loc12_11.4 +// CHECK:STDOUT: } diff --git a/toolchain/check/testdata/array/nine_elements.carbon b/toolchain/check/testdata/array/nine_elements.carbon index 48c86e3255c7..54a2c6c26459 100644 --- a/toolchain/check/testdata/array/nine_elements.carbon +++ b/toolchain/check/testdata/array/nine_elements.carbon @@ -30,6 +30,34 @@ var a: [i32; 9] = (1, 2, 3, 4, 5, 6, 7, 8, 9); // CHECK:STDOUT: %.loc7_44.2: i32 = stub_reference %.loc7_44.1 // CHECK:STDOUT: %.loc7_45.1: type = tuple_type (i32, i32, i32, i32, i32, i32, i32, i32, i32) // CHECK:STDOUT: %.loc7_45.2: (i32, i32, i32, i32, i32, i32, i32, i32, i32) = tuple_literal (%.loc7_20.2, %.loc7_23.2, %.loc7_26.2, %.loc7_29.2, %.loc7_32.2, %.loc7_35.2, %.loc7_38.2, %.loc7_41.2, %.loc7_44.2) -// CHECK:STDOUT: %.loc7_45.3: [i32; 9] = array_value %.loc7_45.2 -// CHECK:STDOUT: assign %a, %.loc7_45.3 +// CHECK:STDOUT: %.loc7_45.3: ref [i32; 9] = stub_reference %a +// CHECK:STDOUT: %.loc7_45.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc7_45.5: ref i32 = array_index %.loc7_45.3, %.loc7_45.4 +// CHECK:STDOUT: %.loc7_45.6: init i32 = initialize_from %.loc7_20.2 to %.loc7_45.5 +// CHECK:STDOUT: %.loc7_45.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc7_45.8: ref i32 = array_index %.loc7_45.3, %.loc7_45.7 +// CHECK:STDOUT: %.loc7_45.9: init i32 = initialize_from %.loc7_23.2 to %.loc7_45.8 +// CHECK:STDOUT: %.loc7_45.10: i32 = int_literal 2 +// CHECK:STDOUT: %.loc7_45.11: ref i32 = array_index %.loc7_45.3, %.loc7_45.10 +// CHECK:STDOUT: %.loc7_45.12: init i32 = initialize_from %.loc7_26.2 to %.loc7_45.11 +// CHECK:STDOUT: %.loc7_45.13: i32 = int_literal 3 +// CHECK:STDOUT: %.loc7_45.14: ref i32 = array_index %.loc7_45.3, %.loc7_45.13 +// CHECK:STDOUT: %.loc7_45.15: init i32 = initialize_from %.loc7_29.2 to %.loc7_45.14 +// CHECK:STDOUT: %.loc7_45.16: i32 = int_literal 4 +// CHECK:STDOUT: %.loc7_45.17: ref i32 = array_index %.loc7_45.3, %.loc7_45.16 +// CHECK:STDOUT: %.loc7_45.18: init i32 = initialize_from %.loc7_32.2 to %.loc7_45.17 +// CHECK:STDOUT: %.loc7_45.19: i32 = int_literal 5 +// CHECK:STDOUT: %.loc7_45.20: ref i32 = array_index %.loc7_45.3, %.loc7_45.19 +// CHECK:STDOUT: %.loc7_45.21: init i32 = initialize_from %.loc7_35.2 to %.loc7_45.20 +// CHECK:STDOUT: %.loc7_45.22: i32 = int_literal 6 +// CHECK:STDOUT: %.loc7_45.23: ref i32 = array_index %.loc7_45.3, %.loc7_45.22 +// CHECK:STDOUT: %.loc7_45.24: init i32 = initialize_from %.loc7_38.2 to %.loc7_45.23 +// CHECK:STDOUT: %.loc7_45.25: i32 = int_literal 7 +// CHECK:STDOUT: %.loc7_45.26: ref i32 = array_index %.loc7_45.3, %.loc7_45.25 +// CHECK:STDOUT: %.loc7_45.27: init i32 = initialize_from %.loc7_41.2 to %.loc7_45.26 +// CHECK:STDOUT: %.loc7_45.28: i32 = int_literal 8 +// CHECK:STDOUT: %.loc7_45.29: ref i32 = array_index %.loc7_45.3, %.loc7_45.28 +// CHECK:STDOUT: %.loc7_45.30: init i32 = initialize_from %.loc7_44.2 to %.loc7_45.29 +// CHECK:STDOUT: %.loc7_45.31: init [i32; 9] = array_init %.loc7_45.2, (%.loc7_45.6, %.loc7_45.9, %.loc7_45.12, %.loc7_45.15, %.loc7_45.18, %.loc7_45.21, %.loc7_45.24, %.loc7_45.27, %.loc7_45.30) to %.loc7_45.3 +// CHECK:STDOUT: assign %a, %.loc7_45.31 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/basics/numeric_literals.carbon b/toolchain/check/testdata/basics/numeric_literals.carbon index d7b19682b935..ca29ff512f1c 100644 --- a/toolchain/check/testdata/basics/numeric_literals.carbon +++ b/toolchain/check/testdata/basics/numeric_literals.carbon @@ -46,8 +46,24 @@ fn F() { // CHECK:STDOUT: %.loc15_5.2: i32 = stub_reference %.loc15_5.1 // CHECK:STDOUT: %.loc16_3.1: type = tuple_type (i32, i32, i32, i32, i32) // CHECK:STDOUT: %.loc16_3.2: (i32, i32, i32, i32, i32) = tuple_literal (%.loc11_5.2, %.loc12_5.2, %.loc13_5.2, %.loc14_5.2, %.loc15_5.2) -// CHECK:STDOUT: %.loc16_3.3: [i32; 5] = array_value %.loc16_3.2 -// CHECK:STDOUT: assign %ints, %.loc16_3.3 +// CHECK:STDOUT: %.loc16_3.3: ref [i32; 5] = stub_reference %ints +// CHECK:STDOUT: %.loc16_3.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc16_3.5: ref i32 = array_index %.loc16_3.3, %.loc16_3.4 +// CHECK:STDOUT: %.loc16_3.6: init i32 = initialize_from %.loc11_5.2 to %.loc16_3.5 +// CHECK:STDOUT: %.loc16_3.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc16_3.8: ref i32 = array_index %.loc16_3.3, %.loc16_3.7 +// CHECK:STDOUT: %.loc16_3.9: init i32 = initialize_from %.loc12_5.2 to %.loc16_3.8 +// CHECK:STDOUT: %.loc16_3.10: i32 = int_literal 2 +// CHECK:STDOUT: %.loc16_3.11: ref i32 = array_index %.loc16_3.3, %.loc16_3.10 +// CHECK:STDOUT: %.loc16_3.12: init i32 = initialize_from %.loc13_5.2 to %.loc16_3.11 +// CHECK:STDOUT: %.loc16_3.13: i32 = int_literal 3 +// CHECK:STDOUT: %.loc16_3.14: ref i32 = array_index %.loc16_3.3, %.loc16_3.13 +// CHECK:STDOUT: %.loc16_3.15: init i32 = initialize_from %.loc14_5.2 to %.loc16_3.14 +// CHECK:STDOUT: %.loc16_3.16: i32 = int_literal 4 +// CHECK:STDOUT: %.loc16_3.17: ref i32 = array_index %.loc16_3.3, %.loc16_3.16 +// CHECK:STDOUT: %.loc16_3.18: init i32 = initialize_from %.loc15_5.2 to %.loc16_3.17 +// CHECK:STDOUT: %.loc16_3.19: init [i32; 5] = array_init %.loc16_3.2, (%.loc16_3.6, %.loc16_3.9, %.loc16_3.12, %.loc16_3.15, %.loc16_3.18) to %.loc16_3.3 +// CHECK:STDOUT: assign %ints, %.loc16_3.19 // CHECK:STDOUT: %.loc17_21: i32 = int_literal 7 // CHECK:STDOUT: %.loc17_22: type = array_type %.loc17_21, f64 // CHECK:STDOUT: %floats: ref [f64; 7] = var "floats" @@ -67,7 +83,29 @@ fn F() { // CHECK:STDOUT: %.loc24_5.2: f64 = stub_reference %.loc24_5.1 // CHECK:STDOUT: %.loc25_3.1: type = tuple_type (f64, f64, f64, f64, f64, f64, f64) // CHECK:STDOUT: %.loc25_3.2: (f64, f64, f64, f64, f64, f64, f64) = tuple_literal (%.loc18_5.2, %.loc19_5.2, %.loc20_5.2, %.loc21_5.2, %.loc22_5.2, %.loc23_5.2, %.loc24_5.2) -// CHECK:STDOUT: %.loc25_3.3: [f64; 7] = array_value %.loc25_3.2 -// CHECK:STDOUT: assign %floats, %.loc25_3.3 +// CHECK:STDOUT: %.loc25_3.3: ref [f64; 7] = stub_reference %floats +// CHECK:STDOUT: %.loc25_3.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc25_3.5: ref f64 = array_index %.loc25_3.3, %.loc25_3.4 +// CHECK:STDOUT: %.loc25_3.6: init f64 = initialize_from %.loc18_5.2 to %.loc25_3.5 +// CHECK:STDOUT: %.loc25_3.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc25_3.8: ref f64 = array_index %.loc25_3.3, %.loc25_3.7 +// CHECK:STDOUT: %.loc25_3.9: init f64 = initialize_from %.loc19_5.2 to %.loc25_3.8 +// CHECK:STDOUT: %.loc25_3.10: i32 = int_literal 2 +// CHECK:STDOUT: %.loc25_3.11: ref f64 = array_index %.loc25_3.3, %.loc25_3.10 +// CHECK:STDOUT: %.loc25_3.12: init f64 = initialize_from %.loc20_5.2 to %.loc25_3.11 +// CHECK:STDOUT: %.loc25_3.13: i32 = int_literal 3 +// CHECK:STDOUT: %.loc25_3.14: ref f64 = array_index %.loc25_3.3, %.loc25_3.13 +// CHECK:STDOUT: %.loc25_3.15: init f64 = initialize_from %.loc21_5.2 to %.loc25_3.14 +// CHECK:STDOUT: %.loc25_3.16: i32 = int_literal 4 +// CHECK:STDOUT: %.loc25_3.17: ref f64 = array_index %.loc25_3.3, %.loc25_3.16 +// CHECK:STDOUT: %.loc25_3.18: init f64 = initialize_from %.loc22_5.2 to %.loc25_3.17 +// CHECK:STDOUT: %.loc25_3.19: i32 = int_literal 5 +// CHECK:STDOUT: %.loc25_3.20: ref f64 = array_index %.loc25_3.3, %.loc25_3.19 +// CHECK:STDOUT: %.loc25_3.21: init f64 = initialize_from %.loc23_5.2 to %.loc25_3.20 +// CHECK:STDOUT: %.loc25_3.22: i32 = int_literal 6 +// CHECK:STDOUT: %.loc25_3.23: ref f64 = array_index %.loc25_3.3, %.loc25_3.22 +// CHECK:STDOUT: %.loc25_3.24: init f64 = initialize_from %.loc24_5.2 to %.loc25_3.23 +// CHECK:STDOUT: %.loc25_3.25: init [f64; 7] = array_init %.loc25_3.2, (%.loc25_3.6, %.loc25_3.9, %.loc25_3.12, %.loc25_3.15, %.loc25_3.18, %.loc25_3.21, %.loc25_3.24) to %.loc25_3.3 +// CHECK:STDOUT: assign %floats, %.loc25_3.25 // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/index/array_element_access.carbon b/toolchain/check/testdata/index/array_element_access.carbon index 14ec89abde26..5c4ddf3fb4a2 100644 --- a/toolchain/check/testdata/index/array_element_access.carbon +++ b/toolchain/check/testdata/index/array_element_access.carbon @@ -19,8 +19,15 @@ var d: i32 = a[b]; // CHECK:STDOUT: %.loc7_24.2: i32 = stub_reference %.loc7_24.1 // CHECK:STDOUT: %.loc7_26.1: type = tuple_type (i32, i32) // CHECK:STDOUT: %.loc7_26.2: (i32, i32) = tuple_literal (%.loc7_20.2, %.loc7_24.2) -// CHECK:STDOUT: %.loc7_26.3: [i32; 2] = array_value %.loc7_26.2 -// CHECK:STDOUT: assign %a, %.loc7_26.3 +// CHECK:STDOUT: %.loc7_26.3: ref [i32; 2] = stub_reference %a +// CHECK:STDOUT: %.loc7_26.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc7_26.5: ref i32 = array_index %.loc7_26.3, %.loc7_26.4 +// CHECK:STDOUT: %.loc7_26.6: init i32 = initialize_from %.loc7_20.2 to %.loc7_26.5 +// CHECK:STDOUT: %.loc7_26.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc7_26.8: ref i32 = array_index %.loc7_26.3, %.loc7_26.7 +// CHECK:STDOUT: %.loc7_26.9: init i32 = initialize_from %.loc7_24.2 to %.loc7_26.8 +// CHECK:STDOUT: %.loc7_26.10: init [i32; 2] = array_init %.loc7_26.2, (%.loc7_26.6, %.loc7_26.9) to %.loc7_26.3 +// CHECK:STDOUT: assign %a, %.loc7_26.10 // CHECK:STDOUT: %b: ref i32 = var "b" // CHECK:STDOUT: %.loc8_14: i32 = int_literal 1 // CHECK:STDOUT: assign %b, %.loc8_14 diff --git a/toolchain/check/testdata/index/fail_array_large_index.carbon b/toolchain/check/testdata/index/fail_array_large_index.carbon index f22db61107c2..724cc1c3ed96 100644 --- a/toolchain/check/testdata/index/fail_array_large_index.carbon +++ b/toolchain/check/testdata/index/fail_array_large_index.carbon @@ -18,8 +18,12 @@ var b: i32 = a[0xFFFFFFFFFFFFFFFFF]; // CHECK:STDOUT: %.loc7_20.2: i32 = stub_reference %.loc7_20.1 // CHECK:STDOUT: %.loc7_23.1: type = tuple_type (i32) // CHECK:STDOUT: %.loc7_23.2: (i32,) = tuple_literal (%.loc7_20.2) -// CHECK:STDOUT: %.loc7_23.3: [i32; 1] = array_value %.loc7_23.2 -// CHECK:STDOUT: assign %a, %.loc7_23.3 +// CHECK:STDOUT: %.loc7_23.3: ref [i32; 1] = stub_reference %a +// CHECK:STDOUT: %.loc7_23.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc7_23.5: ref i32 = array_index %.loc7_23.3, %.loc7_23.4 +// CHECK:STDOUT: %.loc7_23.6: init i32 = initialize_from %.loc7_20.2 to %.loc7_23.5 +// CHECK:STDOUT: %.loc7_23.7: init [i32; 1] = array_init %.loc7_23.2, (%.loc7_23.6) to %.loc7_23.3 +// CHECK:STDOUT: assign %a, %.loc7_23.7 // CHECK:STDOUT: %b: ref i32 = var "b" // CHECK:STDOUT: %.loc11_16: i32 = int_literal 295147905179352825855 // CHECK:STDOUT: %.loc11_35.1: ref i32 = array_index %a, diff --git a/toolchain/check/testdata/index/fail_array_non_int_indexing.carbon b/toolchain/check/testdata/index/fail_array_non_int_indexing.carbon index 1531b1185377..bae62520678b 100644 --- a/toolchain/check/testdata/index/fail_array_non_int_indexing.carbon +++ b/toolchain/check/testdata/index/fail_array_non_int_indexing.carbon @@ -18,8 +18,12 @@ var b: i32 = a[2.6]; // CHECK:STDOUT: %.loc7_20.2: i32 = stub_reference %.loc7_20.1 // CHECK:STDOUT: %.loc7_23.1: type = tuple_type (i32) // CHECK:STDOUT: %.loc7_23.2: (i32,) = tuple_literal (%.loc7_20.2) -// CHECK:STDOUT: %.loc7_23.3: [i32; 1] = array_value %.loc7_23.2 -// CHECK:STDOUT: assign %a, %.loc7_23.3 +// CHECK:STDOUT: %.loc7_23.3: ref [i32; 1] = stub_reference %a +// CHECK:STDOUT: %.loc7_23.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc7_23.5: ref i32 = array_index %.loc7_23.3, %.loc7_23.4 +// CHECK:STDOUT: %.loc7_23.6: init i32 = initialize_from %.loc7_20.2 to %.loc7_23.5 +// CHECK:STDOUT: %.loc7_23.7: init [i32; 1] = array_init %.loc7_23.2, (%.loc7_23.6) to %.loc7_23.3 +// CHECK:STDOUT: assign %a, %.loc7_23.7 // CHECK:STDOUT: %b: ref i32 = var "b" // CHECK:STDOUT: %.loc11_16: f64 = real_literal 26e-1 // CHECK:STDOUT: %.loc11_19.1: ref i32 = array_index %a, diff --git a/toolchain/check/testdata/index/fail_array_out_of_bound_access.carbon b/toolchain/check/testdata/index/fail_array_out_of_bound_access.carbon index 6f4086a04fa6..cd7bc3ee87fb 100644 --- a/toolchain/check/testdata/index/fail_array_out_of_bound_access.carbon +++ b/toolchain/check/testdata/index/fail_array_out_of_bound_access.carbon @@ -18,8 +18,12 @@ var b: i32 = a[2]; // CHECK:STDOUT: %.loc7_20.2: i32 = stub_reference %.loc7_20.1 // CHECK:STDOUT: %.loc7_23.1: type = tuple_type (i32) // CHECK:STDOUT: %.loc7_23.2: (i32,) = tuple_literal (%.loc7_20.2) -// CHECK:STDOUT: %.loc7_23.3: [i32; 1] = array_value %.loc7_23.2 -// CHECK:STDOUT: assign %a, %.loc7_23.3 +// CHECK:STDOUT: %.loc7_23.3: ref [i32; 1] = stub_reference %a +// CHECK:STDOUT: %.loc7_23.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc7_23.5: ref i32 = array_index %.loc7_23.3, %.loc7_23.4 +// CHECK:STDOUT: %.loc7_23.6: init i32 = initialize_from %.loc7_20.2 to %.loc7_23.5 +// CHECK:STDOUT: %.loc7_23.7: init [i32; 1] = array_init %.loc7_23.2, (%.loc7_23.6) to %.loc7_23.3 +// CHECK:STDOUT: assign %a, %.loc7_23.7 // CHECK:STDOUT: %b: ref i32 = var "b" // CHECK:STDOUT: %.loc11_16: i32 = int_literal 2 // CHECK:STDOUT: %.loc11_17.1: ref i32 = array_index %a, diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 7b7797fdcdad..29b5ca65e743 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -109,6 +109,8 @@ CARBON_DIAGNOSTIC_KIND(SemanticsTodo) CARBON_DIAGNOSTIC_KIND(AddressOfEphemeralReference) CARBON_DIAGNOSTIC_KIND(AddressOfNonReference) +CARBON_DIAGNOSTIC_KIND(ArrayInitFromLiteralArgCountMismatch) +CARBON_DIAGNOSTIC_KIND(ArrayInitFromExpressionArgCountMismatch) CARBON_DIAGNOSTIC_KIND(AssignmentToNonAssignable) CARBON_DIAGNOSTIC_KIND(DereferenceOfNonPointer) CARBON_DIAGNOSTIC_KIND(DereferenceOfType) diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index c6140c2031ec..414aae531446 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -42,36 +42,21 @@ auto HandleArrayIndex(FunctionContext& context, SemIR::NodeId node_id, } else { auto* index = context.GetLocalLoaded(index_node_id); // TODO: Handle return value or call such as `F()[a]`. - // TODO: The GEP indexes here are wrong; we should pass {0, index}. + auto* zero = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(context.llvm_context()), 0); array_element_value = context.builder().CreateInBoundsGEP( - llvm_type, array_value, index, "array.index"); + llvm_type, array_value, {zero, index}, "array.index"); } context.SetLocal(node_id, array_element_value); } -auto HandleArrayValue(FunctionContext& context, SemIR::NodeId node_id, - SemIR::Node node) -> void { - auto* llvm_type = context.GetType(node.type_id()); - auto* alloca = - context.builder().CreateAlloca(llvm_type, /*ArraySize=*/nullptr, "array"); - context.SetLocal(node_id, alloca); - auto tuple_node_id = node.GetAsArrayValue(); - auto* tuple_value = context.GetLocal(tuple_node_id); - auto* tuple_type = - context.GetType(context.semantics_ir().GetNode(tuple_node_id).type_id()); - - for (auto i : llvm::seq(llvm_type->getArrayNumElements())) { - llvm::Value* array_element_value = context.GetIndexFromStructOrArray( - tuple_type, tuple_value, i, "array.element"); - if (tuple_value->getType()->isPointerTy()) { - array_element_value = context.builder().CreateLoad( - llvm_type->getArrayElementType(), array_element_value); - } - // Initializing the array with values. - context.builder().CreateStore( - array_element_value, - context.builder().CreateStructGEP(llvm_type, alloca, i)); - } +auto HandleArrayInit(FunctionContext& context, SemIR::NodeId node_id, + SemIR::Node node) -> void { + auto [src_id, refs_id] = node.GetAsArrayInit(); + // The result of initialization is the return slot of the initializer. + context.SetLocal( + node_id, + context.GetLocal(context.semantics_ir().GetNodeBlock(refs_id).back())); } auto HandleAssign(FunctionContext& context, SemIR::NodeId /*node_id*/, @@ -220,6 +205,13 @@ auto HandleFunctionDeclaration(FunctionContext& /*context*/, << node; } +auto HandleInitializeFrom(FunctionContext& context, SemIR::NodeId /*node_id*/, + SemIR::Node node) -> void { + auto [init_id, storage_id] = node.GetAsInitializeFrom(); + auto storage_type_id = context.semantics_ir().GetNode(storage_id).type_id(); + context.FinishInitialization(storage_type_id, storage_id, init_id); +} + auto HandleIntegerLiteral(FunctionContext& context, SemIR::NodeId node_id, SemIR::Node node) -> void { llvm::APInt i = diff --git a/toolchain/lower/testdata/array/assign_return_value.carbon b/toolchain/lower/testdata/array/assign_return_value.carbon index a8ec18c6a2a7..9f32b1ee450b 100644 --- a/toolchain/lower/testdata/array/assign_return_value.carbon +++ b/toolchain/lower/testdata/array/assign_return_value.carbon @@ -26,14 +26,13 @@ fn Run() { // CHECK:STDOUT: %t = alloca [2 x i32], align 4 // CHECK:STDOUT: %temp = alloca { i32, i32 }, align 8 // CHECK:STDOUT: call void @F(ptr %temp) -// CHECK:STDOUT: %array = alloca [2 x i32], align 4 -// CHECK:STDOUT: %array.element = getelementptr inbounds { i32, i32 }, ptr %temp, i32 0, i32 0 -// CHECK:STDOUT: %1 = load i32, ptr %array.element, align 4 -// CHECK:STDOUT: %2 = getelementptr inbounds [2 x i32], ptr %array, i32 0, i32 0 -// CHECK:STDOUT: store i32 %1, ptr %2, align 4 -// CHECK:STDOUT: %array.element1 = getelementptr inbounds { i32, i32 }, ptr %temp, i32 0, i32 1 -// CHECK:STDOUT: %3 = load i32, ptr %array.element1, align 4 -// CHECK:STDOUT: %4 = getelementptr inbounds [2 x i32], ptr %array, i32 0, i32 1 -// CHECK:STDOUT: store i32 %3, ptr %4, align 4 +// CHECK:STDOUT: %array.index = getelementptr inbounds [2 x i32], ptr %t, i32 0, i32 0 +// CHECK:STDOUT: %tuple.index = getelementptr inbounds { i32, i32 }, ptr %temp, i32 0, i32 0 +// CHECK:STDOUT: %1 = load i32, ptr %tuple.index, align 4 +// CHECK:STDOUT: store i32 %1, ptr %array.index, align 4 +// CHECK:STDOUT: %array.index1 = getelementptr inbounds [2 x i32], ptr %t, i32 0, i32 1 +// CHECK:STDOUT: %tuple.index2 = getelementptr inbounds { i32, i32 }, ptr %temp, i32 0, i32 1 +// CHECK:STDOUT: %2 = load i32, ptr %tuple.index2, align 4 +// CHECK:STDOUT: store i32 %2, ptr %array.index1, align 4 // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/array/base.carbon b/toolchain/lower/testdata/array/base.carbon index 5ae8e7273a3e..c0fcbca893b8 100644 --- a/toolchain/lower/testdata/array/base.carbon +++ b/toolchain/lower/testdata/array/base.carbon @@ -22,93 +22,68 @@ fn Run() { // CHECK:STDOUT: %tuple = alloca { i32 }, align 8 // CHECK:STDOUT: %1 = getelementptr inbounds { i32 }, ptr %tuple, i32 0, i32 0 // CHECK:STDOUT: store i32 1, ptr %1, align 4 -// CHECK:STDOUT: %array = alloca [1 x i32], align 4 -// CHECK:STDOUT: %array.element = getelementptr inbounds { i32 }, ptr %tuple, i32 0, i32 0 -// CHECK:STDOUT: %2 = load i32, ptr %array.element, align 4 -// CHECK:STDOUT: %3 = getelementptr inbounds [1 x i32], ptr %array, i32 0, i32 0 -// CHECK:STDOUT: store i32 %2, ptr %3, align 4 +// CHECK:STDOUT: %array.index = getelementptr inbounds [1 x i32], ptr %a, i32 0, i32 0 +// CHECK:STDOUT: store i32 1, ptr %array.index, align 4 // CHECK:STDOUT: %b = alloca [2 x double], align 8 // CHECK:STDOUT: %tuple1 = alloca { double, double }, align 8 -// CHECK:STDOUT: %4 = getelementptr inbounds { double, double }, ptr %tuple1, i32 0, i32 0 -// CHECK:STDOUT: store double 0x4026333333333334, ptr %4, align 8 -// CHECK:STDOUT: %5 = getelementptr inbounds { double, double }, ptr %tuple1, i32 0, i32 1 -// CHECK:STDOUT: store double 2.200000e+00, ptr %5, align 8 -// CHECK:STDOUT: %array2 = alloca [2 x double], align 8 -// CHECK:STDOUT: %array.element3 = getelementptr inbounds { double, double }, ptr %tuple1, i32 0, i32 0 -// CHECK:STDOUT: %6 = load double, ptr %array.element3, align 8 -// CHECK:STDOUT: %7 = getelementptr inbounds [2 x double], ptr %array2, i32 0, i32 0 -// CHECK:STDOUT: store double %6, ptr %7, align 8 -// CHECK:STDOUT: %array.element4 = getelementptr inbounds { double, double }, ptr %tuple1, i32 0, i32 1 -// CHECK:STDOUT: %8 = load double, ptr %array.element4, align 8 -// CHECK:STDOUT: %9 = getelementptr inbounds [2 x double], ptr %array2, i32 0, i32 1 -// CHECK:STDOUT: store double %8, ptr %9, align 8 -// CHECK:STDOUT: %tuple5 = alloca {}, align 8 +// CHECK:STDOUT: %2 = getelementptr inbounds { double, double }, ptr %tuple1, i32 0, i32 0 +// CHECK:STDOUT: store double 0x4026333333333334, ptr %2, align 8 +// CHECK:STDOUT: %3 = getelementptr inbounds { double, double }, ptr %tuple1, i32 0, i32 1 +// CHECK:STDOUT: store double 2.200000e+00, ptr %3, align 8 +// CHECK:STDOUT: %array.index2 = getelementptr inbounds [2 x double], ptr %b, i32 0, i32 0 +// CHECK:STDOUT: store double 0x4026333333333334, ptr %array.index2, align 8 +// CHECK:STDOUT: %array.index3 = getelementptr inbounds [2 x double], ptr %b, i32 0, i32 1 +// CHECK:STDOUT: store double 2.200000e+00, ptr %array.index3, align 8 +// CHECK:STDOUT: %tuple4 = alloca {}, align 8 // CHECK:STDOUT: %c = alloca [5 x {}], align 8 +// CHECK:STDOUT: %tuple5 = alloca {}, align 8 // CHECK:STDOUT: %tuple6 = alloca {}, align 8 // CHECK:STDOUT: %tuple7 = alloca {}, align 8 // CHECK:STDOUT: %tuple8 = alloca {}, align 8 // CHECK:STDOUT: %tuple9 = alloca {}, align 8 -// CHECK:STDOUT: %tuple10 = alloca {}, align 8 -// CHECK:STDOUT: %tuple11 = alloca { {}, {}, {}, {}, {} }, align 8 -// CHECK:STDOUT: %10 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple11, i32 0, i32 0 -// CHECK:STDOUT: store ptr %tuple6, ptr %10, align 8 -// CHECK:STDOUT: %11 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple11, i32 0, i32 1 -// CHECK:STDOUT: store ptr %tuple7, ptr %11, align 8 -// CHECK:STDOUT: %12 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple11, i32 0, i32 2 -// CHECK:STDOUT: store ptr %tuple8, ptr %12, align 8 -// CHECK:STDOUT: %13 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple11, i32 0, i32 3 -// CHECK:STDOUT: store ptr %tuple9, ptr %13, align 8 -// CHECK:STDOUT: %14 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple11, i32 0, i32 4 -// CHECK:STDOUT: store ptr %tuple10, ptr %14, align 8 -// CHECK:STDOUT: %array12 = alloca [5 x {}], align 8 -// CHECK:STDOUT: %array.element13 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple11, i32 0, i32 0 -// CHECK:STDOUT: %15 = load {}, ptr %array.element13, align 1 -// CHECK:STDOUT: %16 = getelementptr inbounds [5 x {}], ptr %array12, i32 0, i32 0 -// CHECK:STDOUT: store {} %15, ptr %16, align 1 -// CHECK:STDOUT: %array.element14 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple11, i32 0, i32 1 -// CHECK:STDOUT: %17 = load {}, ptr %array.element14, align 1 -// CHECK:STDOUT: %18 = getelementptr inbounds [5 x {}], ptr %array12, i32 0, i32 1 -// CHECK:STDOUT: store {} %17, ptr %18, align 1 -// CHECK:STDOUT: %array.element15 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple11, i32 0, i32 2 -// CHECK:STDOUT: %19 = load {}, ptr %array.element15, align 1 -// CHECK:STDOUT: %20 = getelementptr inbounds [5 x {}], ptr %array12, i32 0, i32 2 -// CHECK:STDOUT: store {} %19, ptr %20, align 1 -// CHECK:STDOUT: %array.element16 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple11, i32 0, i32 3 -// CHECK:STDOUT: %21 = load {}, ptr %array.element16, align 1 -// CHECK:STDOUT: %22 = getelementptr inbounds [5 x {}], ptr %array12, i32 0, i32 3 -// CHECK:STDOUT: store {} %21, ptr %22, align 1 -// CHECK:STDOUT: %array.element17 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple11, i32 0, i32 4 -// CHECK:STDOUT: %23 = load {}, ptr %array.element17, align 1 -// CHECK:STDOUT: %24 = getelementptr inbounds [5 x {}], ptr %array12, i32 0, i32 4 -// CHECK:STDOUT: store {} %23, ptr %24, align 1 -// CHECK:STDOUT: %tuple18 = alloca { %type, %type, %type }, align 8 -// CHECK:STDOUT: %25 = getelementptr inbounds { %type, %type, %type }, ptr %tuple18, i32 0, i32 0 -// CHECK:STDOUT: store %type zeroinitializer, ptr %25, align 1 -// CHECK:STDOUT: %26 = getelementptr inbounds { %type, %type, %type }, ptr %tuple18, i32 0, i32 1 -// CHECK:STDOUT: store %type zeroinitializer, ptr %26, align 1 -// CHECK:STDOUT: %27 = getelementptr inbounds { %type, %type, %type }, ptr %tuple18, i32 0, i32 2 -// CHECK:STDOUT: store %type zeroinitializer, ptr %27, align 1 +// CHECK:STDOUT: %tuple10 = alloca { {}, {}, {}, {}, {} }, align 8 +// CHECK:STDOUT: %4 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple10, i32 0, i32 0 +// CHECK:STDOUT: store ptr %tuple5, ptr %4, align 8 +// CHECK:STDOUT: %5 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple10, i32 0, i32 1 +// CHECK:STDOUT: store ptr %tuple6, ptr %5, align 8 +// CHECK:STDOUT: %6 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple10, i32 0, i32 2 +// CHECK:STDOUT: store ptr %tuple7, ptr %6, align 8 +// CHECK:STDOUT: %7 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple10, i32 0, i32 3 +// CHECK:STDOUT: store ptr %tuple8, ptr %7, align 8 +// CHECK:STDOUT: %8 = getelementptr inbounds { {}, {}, {}, {}, {} }, ptr %tuple10, i32 0, i32 4 +// CHECK:STDOUT: store ptr %tuple9, ptr %8, align 8 +// CHECK:STDOUT: %array.index11 = getelementptr inbounds [5 x {}], ptr %c, i32 0, i32 0 +// CHECK:STDOUT: %array.index12 = getelementptr inbounds [5 x {}], ptr %c, i32 0, i32 1 +// CHECK:STDOUT: %array.index13 = getelementptr inbounds [5 x {}], ptr %c, i32 0, i32 2 +// CHECK:STDOUT: %array.index14 = getelementptr inbounds [5 x {}], ptr %c, i32 0, i32 3 +// CHECK:STDOUT: %array.index15 = getelementptr inbounds [5 x {}], ptr %c, i32 0, i32 4 +// CHECK:STDOUT: %tuple16 = alloca { %type, %type, %type }, align 8 +// CHECK:STDOUT: %9 = getelementptr inbounds { %type, %type, %type }, ptr %tuple16, i32 0, i32 0 +// CHECK:STDOUT: store %type zeroinitializer, ptr %9, align 1 +// CHECK:STDOUT: %10 = getelementptr inbounds { %type, %type, %type }, ptr %tuple16, i32 0, i32 1 +// CHECK:STDOUT: store %type zeroinitializer, ptr %10, align 1 +// CHECK:STDOUT: %11 = getelementptr inbounds { %type, %type, %type }, ptr %tuple16, i32 0, i32 2 +// CHECK:STDOUT: store %type zeroinitializer, ptr %11, align 1 // CHECK:STDOUT: %d = alloca { i32, i32, i32 }, align 8 -// CHECK:STDOUT: %tuple19 = alloca { i32, i32, i32 }, align 8 -// CHECK:STDOUT: %28 = getelementptr inbounds { i32, i32, i32 }, ptr %tuple19, i32 0, i32 0 -// CHECK:STDOUT: store i32 1, ptr %28, align 4 -// CHECK:STDOUT: %29 = getelementptr inbounds { i32, i32, i32 }, ptr %tuple19, i32 0, i32 1 -// CHECK:STDOUT: store i32 2, ptr %29, align 4 -// CHECK:STDOUT: %30 = getelementptr inbounds { i32, i32, i32 }, ptr %tuple19, i32 0, i32 2 -// CHECK:STDOUT: store i32 3, ptr %30, align 4 +// CHECK:STDOUT: %tuple17 = alloca { i32, i32, i32 }, align 8 +// CHECK:STDOUT: %12 = getelementptr inbounds { i32, i32, i32 }, ptr %tuple17, i32 0, i32 0 +// CHECK:STDOUT: store i32 1, ptr %12, align 4 +// CHECK:STDOUT: %13 = getelementptr inbounds { i32, i32, i32 }, ptr %tuple17, i32 0, i32 1 +// CHECK:STDOUT: store i32 2, ptr %13, align 4 +// CHECK:STDOUT: %14 = getelementptr inbounds { i32, i32, i32 }, ptr %tuple17, i32 0, i32 2 +// CHECK:STDOUT: store i32 3, ptr %14, align 4 // CHECK:STDOUT: %e = alloca [3 x i32], align 4 -// CHECK:STDOUT: %array20 = alloca [3 x i32], align 4 -// CHECK:STDOUT: %array.element21 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 0 -// CHECK:STDOUT: %31 = load i32, ptr %array.element21, align 4 -// CHECK:STDOUT: %32 = getelementptr inbounds [3 x i32], ptr %array20, i32 0, i32 0 -// CHECK:STDOUT: store i32 %31, ptr %32, align 4 -// CHECK:STDOUT: %array.element22 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 1 -// CHECK:STDOUT: %33 = load i32, ptr %array.element22, align 4 -// CHECK:STDOUT: %34 = getelementptr inbounds [3 x i32], ptr %array20, i32 0, i32 1 -// CHECK:STDOUT: store i32 %33, ptr %34, align 4 -// CHECK:STDOUT: %array.element23 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 2 -// CHECK:STDOUT: %35 = load i32, ptr %array.element23, align 4 -// CHECK:STDOUT: %36 = getelementptr inbounds [3 x i32], ptr %array20, i32 0, i32 2 -// CHECK:STDOUT: store i32 %35, ptr %36, align 4 +// CHECK:STDOUT: %array.index18 = getelementptr inbounds [3 x i32], ptr %e, i32 0, i32 0 +// CHECK:STDOUT: %tuple.index = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 0 +// CHECK:STDOUT: %15 = load i32, ptr %tuple.index, align 4 +// CHECK:STDOUT: store i32 %15, ptr %array.index18, align 4 +// CHECK:STDOUT: %array.index19 = getelementptr inbounds [3 x i32], ptr %e, i32 0, i32 1 +// CHECK:STDOUT: %tuple.index20 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 1 +// CHECK:STDOUT: %16 = load i32, ptr %tuple.index20, align 4 +// CHECK:STDOUT: store i32 %16, ptr %array.index19, align 4 +// CHECK:STDOUT: %array.index21 = getelementptr inbounds [3 x i32], ptr %e, i32 0, i32 2 +// CHECK:STDOUT: %tuple.index22 = getelementptr inbounds { i32, i32, i32 }, ptr %d, i32 0, i32 2 +// CHECK:STDOUT: %17 = load i32, ptr %tuple.index22, align 4 +// CHECK:STDOUT: store i32 %17, ptr %array.index21, align 4 // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/array/function_param.carbon b/toolchain/lower/testdata/array/function_param.carbon new file mode 100644 index 000000000000..4f116f3add03 --- /dev/null +++ b/toolchain/lower/testdata/array/function_param.carbon @@ -0,0 +1,44 @@ +// 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 F(arr: [i32; 3], i: i32) -> i32 { + return arr[i]; +} + +fn G() -> i32 { + return F((1, 2, 3), 1); +} + +// CHECK:STDOUT: ; ModuleID = 'function_param.carbon' +// CHECK:STDOUT: source_filename = "function_param.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @F(ptr %arr, i32 %i) { +// CHECK:STDOUT: %array.index = getelementptr inbounds [3 x i32], ptr %arr, i32 0, i32 %i +// CHECK:STDOUT: %1 = load i32, ptr %array.index, align 4 +// CHECK:STDOUT: ret i32 %1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @G() { +// CHECK:STDOUT: %tuple = alloca { i32, i32, i32 }, align 8 +// CHECK:STDOUT: %1 = getelementptr inbounds { i32, i32, i32 }, ptr %tuple, i32 0, i32 0 +// CHECK:STDOUT: store i32 1, ptr %1, align 4 +// CHECK:STDOUT: %2 = getelementptr inbounds { i32, i32, i32 }, ptr %tuple, i32 0, i32 1 +// CHECK:STDOUT: store i32 2, ptr %2, align 4 +// CHECK:STDOUT: %3 = getelementptr inbounds { i32, i32, i32 }, ptr %tuple, i32 0, i32 2 +// CHECK:STDOUT: store i32 3, ptr %3, align 4 +// CHECK:STDOUT: %temp = alloca [3 x i32], align 4 +// CHECK:STDOUT: %array.index = getelementptr inbounds [3 x i32], ptr %temp, i32 0, i32 0 +// CHECK:STDOUT: store i32 1, ptr %array.index, align 4 +// CHECK:STDOUT: %array.index1 = getelementptr inbounds [3 x i32], ptr %temp, i32 0, i32 1 +// CHECK:STDOUT: store i32 2, ptr %array.index1, align 4 +// CHECK:STDOUT: %array.index2 = getelementptr inbounds [3 x i32], ptr %temp, i32 0, i32 2 +// CHECK:STDOUT: store i32 3, ptr %array.index2, align 4 +// CHECK:STDOUT: %F = call i32 @F(ptr %temp, i32 1) +// CHECK:STDOUT: %temp3 = alloca i32, align 4 +// CHECK:STDOUT: store i32 %F, ptr %temp3, align 4 +// CHECK:STDOUT: %4 = load i32, ptr %temp3, align 4 +// CHECK:STDOUT: ret i32 %4 +// CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/basics/numeric_literals.carbon b/toolchain/lower/testdata/basics/numeric_literals.carbon index ce89100de345..cec19e63c715 100644 --- a/toolchain/lower/testdata/basics/numeric_literals.carbon +++ b/toolchain/lower/testdata/basics/numeric_literals.carbon @@ -37,61 +37,39 @@ fn F() { // CHECK:STDOUT: store i32 8, ptr %3, align 4 // CHECK:STDOUT: %4 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 3 // CHECK:STDOUT: store i32 8, ptr %4, align 4 -// CHECK:STDOUT: %array = alloca [4 x i32], align 4 -// CHECK:STDOUT: %array.element = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 0 -// CHECK:STDOUT: %5 = load i32, ptr %array.element, align 4 -// CHECK:STDOUT: %6 = getelementptr inbounds [4 x i32], ptr %array, i32 0, i32 0 -// CHECK:STDOUT: store i32 %5, ptr %6, align 4 -// CHECK:STDOUT: %array.element1 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 1 -// CHECK:STDOUT: %7 = load i32, ptr %array.element1, align 4 -// CHECK:STDOUT: %8 = getelementptr inbounds [4 x i32], ptr %array, i32 0, i32 1 -// CHECK:STDOUT: store i32 %7, ptr %8, align 4 -// CHECK:STDOUT: %array.element2 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 2 -// CHECK:STDOUT: %9 = load i32, ptr %array.element2, align 4 -// CHECK:STDOUT: %10 = getelementptr inbounds [4 x i32], ptr %array, i32 0, i32 2 -// CHECK:STDOUT: store i32 %9, ptr %10, align 4 -// CHECK:STDOUT: %array.element3 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 3 -// CHECK:STDOUT: %11 = load i32, ptr %array.element3, align 4 -// CHECK:STDOUT: %12 = getelementptr inbounds [4 x i32], ptr %array, i32 0, i32 3 -// CHECK:STDOUT: store i32 %11, ptr %12, align 4 +// CHECK:STDOUT: %array.index = getelementptr inbounds [4 x i32], ptr %ints, i32 0, i32 0 +// CHECK:STDOUT: store i32 8, ptr %array.index, align 4 +// CHECK:STDOUT: %array.index1 = getelementptr inbounds [4 x i32], ptr %ints, i32 0, i32 1 +// CHECK:STDOUT: store i32 9, ptr %array.index1, align 4 +// CHECK:STDOUT: %array.index2 = getelementptr inbounds [4 x i32], ptr %ints, i32 0, i32 2 +// CHECK:STDOUT: store i32 8, ptr %array.index2, align 4 +// CHECK:STDOUT: %array.index3 = getelementptr inbounds [4 x i32], ptr %ints, i32 0, i32 3 +// CHECK:STDOUT: store i32 8, ptr %array.index3, align 4 // CHECK:STDOUT: %floats = alloca [6 x double], align 8 // CHECK:STDOUT: %tuple4 = alloca { double, double, double, double, double, double }, align 8 -// CHECK:STDOUT: %13 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 0 -// CHECK:STDOUT: store double 9.000000e-01, ptr %13, align 8 -// CHECK:STDOUT: %14 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 1 -// CHECK:STDOUT: store double 8.000000e+00, ptr %14, align 8 -// CHECK:STDOUT: %15 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 2 -// CHECK:STDOUT: store double 8.000000e+01, ptr %15, align 8 -// CHECK:STDOUT: %16 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 3 -// CHECK:STDOUT: store double 1.000000e+07, ptr %16, align 8 -// CHECK:STDOUT: %17 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 4 -// CHECK:STDOUT: store double 1.000000e+08, ptr %17, align 8 -// CHECK:STDOUT: %18 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 5 -// CHECK:STDOUT: store double 1.000000e-08, ptr %18, align 8 -// CHECK:STDOUT: %array5 = alloca [6 x double], align 8 -// CHECK:STDOUT: %array.element6 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 0 -// CHECK:STDOUT: %19 = load double, ptr %array.element6, align 8 -// CHECK:STDOUT: %20 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 0 -// CHECK:STDOUT: store double %19, ptr %20, align 8 -// CHECK:STDOUT: %array.element7 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 1 -// CHECK:STDOUT: %21 = load double, ptr %array.element7, align 8 -// CHECK:STDOUT: %22 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 1 -// CHECK:STDOUT: store double %21, ptr %22, align 8 -// CHECK:STDOUT: %array.element8 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 2 -// CHECK:STDOUT: %23 = load double, ptr %array.element8, align 8 -// CHECK:STDOUT: %24 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 2 -// CHECK:STDOUT: store double %23, ptr %24, align 8 -// CHECK:STDOUT: %array.element9 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 3 -// CHECK:STDOUT: %25 = load double, ptr %array.element9, align 8 -// CHECK:STDOUT: %26 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 3 -// CHECK:STDOUT: store double %25, ptr %26, align 8 -// CHECK:STDOUT: %array.element10 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 4 -// CHECK:STDOUT: %27 = load double, ptr %array.element10, align 8 -// CHECK:STDOUT: %28 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 4 -// CHECK:STDOUT: store double %27, ptr %28, align 8 -// CHECK:STDOUT: %array.element11 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 5 -// CHECK:STDOUT: %29 = load double, ptr %array.element11, align 8 -// CHECK:STDOUT: %30 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 5 -// CHECK:STDOUT: store double %29, ptr %30, align 8 +// CHECK:STDOUT: %5 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 0 +// CHECK:STDOUT: store double 9.000000e-01, ptr %5, align 8 +// CHECK:STDOUT: %6 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 1 +// CHECK:STDOUT: store double 8.000000e+00, ptr %6, align 8 +// CHECK:STDOUT: %7 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 2 +// CHECK:STDOUT: store double 8.000000e+01, ptr %7, align 8 +// CHECK:STDOUT: %8 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 3 +// CHECK:STDOUT: store double 1.000000e+07, ptr %8, align 8 +// CHECK:STDOUT: %9 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 4 +// CHECK:STDOUT: store double 1.000000e+08, ptr %9, align 8 +// CHECK:STDOUT: %10 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 5 +// CHECK:STDOUT: store double 1.000000e-08, ptr %10, align 8 +// CHECK:STDOUT: %array.index5 = getelementptr inbounds [6 x double], ptr %floats, i32 0, i32 0 +// CHECK:STDOUT: store double 9.000000e-01, ptr %array.index5, align 8 +// CHECK:STDOUT: %array.index6 = getelementptr inbounds [6 x double], ptr %floats, i32 0, i32 1 +// CHECK:STDOUT: store double 8.000000e+00, ptr %array.index6, align 8 +// CHECK:STDOUT: %array.index7 = getelementptr inbounds [6 x double], ptr %floats, i32 0, i32 2 +// CHECK:STDOUT: store double 8.000000e+01, ptr %array.index7, align 8 +// CHECK:STDOUT: %array.index8 = getelementptr inbounds [6 x double], ptr %floats, i32 0, i32 3 +// CHECK:STDOUT: store double 1.000000e+07, ptr %array.index8, align 8 +// CHECK:STDOUT: %array.index9 = getelementptr inbounds [6 x double], ptr %floats, i32 0, i32 4 +// CHECK:STDOUT: store double 1.000000e+08, ptr %array.index9, align 8 +// CHECK:STDOUT: %array.index10 = getelementptr inbounds [6 x double], ptr %floats, i32 0, i32 5 +// CHECK:STDOUT: store double 1.000000e-08, ptr %array.index10, align 8 // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/index/array_element_access.carbon b/toolchain/lower/testdata/index/array_element_access.carbon index 8f00da733ea8..81ae68247481 100644 --- a/toolchain/lower/testdata/index/array_element_access.carbon +++ b/toolchain/lower/testdata/index/array_element_access.carbon @@ -32,15 +32,10 @@ fn Run() { // CHECK:STDOUT: store i32 1, ptr %1, align 4 // CHECK:STDOUT: %2 = getelementptr inbounds { i32, i32 }, ptr %tuple, i32 0, i32 1 // CHECK:STDOUT: store i32 2, ptr %2, align 4 -// CHECK:STDOUT: %array = alloca [2 x i32], align 4 -// CHECK:STDOUT: %array.element = getelementptr inbounds { i32, i32 }, ptr %tuple, i32 0, i32 0 -// CHECK:STDOUT: %3 = load i32, ptr %array.element, align 4 -// CHECK:STDOUT: %4 = getelementptr inbounds [2 x i32], ptr %array, i32 0, i32 0 -// CHECK:STDOUT: store i32 %3, ptr %4, align 4 -// CHECK:STDOUT: %array.element1 = getelementptr inbounds { i32, i32 }, ptr %tuple, i32 0, i32 1 -// CHECK:STDOUT: %5 = load i32, ptr %array.element1, align 4 -// CHECK:STDOUT: %6 = getelementptr inbounds [2 x i32], ptr %array, i32 0, i32 1 -// CHECK:STDOUT: store i32 %5, ptr %6, align 4 +// CHECK:STDOUT: %array.index = getelementptr inbounds [2 x i32], ptr %return, i32 0, i32 0 +// CHECK:STDOUT: store i32 1, ptr %array.index, align 4 +// CHECK:STDOUT: %array.index1 = getelementptr inbounds [2 x i32], ptr %return, i32 0, i32 1 +// CHECK:STDOUT: store i32 2, ptr %array.index1, align 4 // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: @@ -48,31 +43,30 @@ fn Run() { // CHECK:STDOUT: %a = alloca [2 x i32], align 4 // CHECK:STDOUT: %temp = alloca { i32, i32 }, align 8 // CHECK:STDOUT: call void @A(ptr %temp) -// CHECK:STDOUT: %array = alloca [2 x i32], align 4 -// CHECK:STDOUT: %array.element = getelementptr inbounds { i32, i32 }, ptr %temp, i32 0, i32 0 -// CHECK:STDOUT: %1 = load i32, ptr %array.element, align 4 -// CHECK:STDOUT: %2 = getelementptr inbounds [2 x i32], ptr %array, i32 0, i32 0 -// CHECK:STDOUT: store i32 %1, ptr %2, align 4 -// CHECK:STDOUT: %array.element1 = getelementptr inbounds { i32, i32 }, ptr %temp, i32 0, i32 1 -// CHECK:STDOUT: %3 = load i32, ptr %array.element1, align 4 -// CHECK:STDOUT: %4 = getelementptr inbounds [2 x i32], ptr %array, i32 0, i32 1 -// CHECK:STDOUT: store i32 %3, ptr %4, align 4 +// CHECK:STDOUT: %array.index = getelementptr inbounds [2 x i32], ptr %a, i32 0, i32 0 +// CHECK:STDOUT: %tuple.index = getelementptr inbounds { i32, i32 }, ptr %temp, i32 0, i32 0 +// CHECK:STDOUT: %1 = load i32, ptr %tuple.index, align 4 +// CHECK:STDOUT: store i32 %1, ptr %array.index, align 4 +// CHECK:STDOUT: %array.index1 = getelementptr inbounds [2 x i32], ptr %a, i32 0, i32 1 +// CHECK:STDOUT: %tuple.index2 = getelementptr inbounds { i32, i32 }, ptr %temp, i32 0, i32 1 +// CHECK:STDOUT: %2 = load i32, ptr %tuple.index2, align 4 +// CHECK:STDOUT: store i32 %2, ptr %array.index1, align 4 // CHECK:STDOUT: %b = alloca i32, align 4 -// CHECK:STDOUT: %temp2 = alloca { i32, i32 }, align 8 -// CHECK:STDOUT: call void @A(ptr %temp2) -// CHECK:STDOUT: %tuple.index = getelementptr inbounds { i32, i32 }, ptr %temp2, i32 0, i32 0 -// CHECK:STDOUT: %5 = load i32, ptr %tuple.index, align 4 -// CHECK:STDOUT: store i32 %5, ptr %b, align 4 +// CHECK:STDOUT: %temp3 = alloca { i32, i32 }, align 8 +// CHECK:STDOUT: call void @A(ptr %temp3) +// CHECK:STDOUT: %tuple.index4 = getelementptr inbounds { i32, i32 }, ptr %temp3, i32 0, i32 0 +// CHECK:STDOUT: %3 = load i32, ptr %tuple.index4, align 4 +// CHECK:STDOUT: store i32 %3, ptr %b, align 4 // CHECK:STDOUT: %c = alloca i32, align 4 -// CHECK:STDOUT: %6 = load i32, ptr %b, align 4 -// CHECK:STDOUT: %array.index = getelementptr inbounds [2 x i32], ptr %a, i32 %6 -// CHECK:STDOUT: %7 = load i32, ptr %array.index, align 4 -// CHECK:STDOUT: store i32 %7, ptr %c, align 4 +// CHECK:STDOUT: %4 = load i32, ptr %b, align 4 +// CHECK:STDOUT: %array.index5 = getelementptr inbounds [2 x i32], ptr %a, i32 0, i32 %4 +// CHECK:STDOUT: %5 = load i32, ptr %array.index5, align 4 +// CHECK:STDOUT: store i32 %5, ptr %c, align 4 // CHECK:STDOUT: %d = alloca i32, align 4 -// CHECK:STDOUT: %temp3 = alloca [2 x i32], align 4 -// CHECK:STDOUT: call void @B(ptr %temp3) -// CHECK:STDOUT: %array.index4 = getelementptr inbounds [2 x i32], ptr %temp3, i32 0, i32 1 -// CHECK:STDOUT: %8 = load i32, ptr %array.index4, align 4 -// CHECK:STDOUT: store i32 %8, ptr %d, align 4 +// CHECK:STDOUT: %temp6 = alloca [2 x i32], align 4 +// CHECK:STDOUT: call void @B(ptr %temp6) +// CHECK:STDOUT: %array.index7 = getelementptr inbounds [2 x i32], ptr %temp6, i32 0, i32 1 +// CHECK:STDOUT: %6 = load i32, ptr %array.index7, align 4 +// CHECK:STDOUT: store i32 %6, ptr %d, align 4 // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 9e5456ac9977..c297edcfdc5f 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -195,7 +195,7 @@ static auto GetTypePrecedence(NodeKind kind) -> int { case NodeKind::AddressOf: case NodeKind::ArrayIndex: - case NodeKind::ArrayValue: + case NodeKind::ArrayInit: case NodeKind::Assign: case NodeKind::BinaryOperatorAdd: case NodeKind::BindValue: @@ -207,6 +207,7 @@ static auto GetTypePrecedence(NodeKind kind) -> int { case NodeKind::Call: case NodeKind::Dereference: case NodeKind::FunctionDeclaration: + case NodeKind::InitializeFrom: case NodeKind::IntegerLiteral: case NodeKind::Invalid: case NodeKind::Namespace: @@ -356,7 +357,7 @@ auto File::StringifyType(TypeId type_id, bool in_type_context) const } case NodeKind::AddressOf: case NodeKind::ArrayIndex: - case NodeKind::ArrayValue: + case NodeKind::ArrayInit: case NodeKind::Assign: case NodeKind::BinaryOperatorAdd: case NodeKind::BindValue: @@ -370,6 +371,7 @@ auto File::StringifyType(TypeId type_id, bool in_type_context) const case NodeKind::CrossReference: case NodeKind::Dereference: case NodeKind::FunctionDeclaration: + case NodeKind::InitializeFrom: case NodeKind::IntegerLiteral: case NodeKind::Namespace: case NodeKind::NoOp: @@ -480,7 +482,6 @@ auto GetExpressionCategory(const File& file, NodeId node_id) continue; } - case NodeKind::ArrayValue: case NodeKind::StructLiteral: case NodeKind::TupleLiteral: // TODO: Eventually these will depend on the context in which the value @@ -489,7 +490,9 @@ auto GetExpressionCategory(const File& file, NodeId node_id) // struct/tuple value construction. return ExpressionCategory::Value; + case NodeKind::ArrayInit: case NodeKind::Call: + case NodeKind::InitializeFrom: return ExpressionCategory::Initializing; case NodeKind::Dereference: @@ -514,7 +517,7 @@ auto GetValueRepresentation(const File& file, TypeId type_id) switch (node.kind()) { case NodeKind::AddressOf: case NodeKind::ArrayIndex: - case NodeKind::ArrayValue: + case NodeKind::ArrayInit: case NodeKind::Assign: case NodeKind::BinaryOperatorAdd: case NodeKind::BindValue: @@ -526,6 +529,7 @@ auto GetValueRepresentation(const File& file, TypeId type_id) case NodeKind::Call: case NodeKind::Dereference: case NodeKind::FunctionDeclaration: + case NodeKind::InitializeFrom: case NodeKind::IntegerLiteral: case NodeKind::Invalid: case NodeKind::Namespace: diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 2b2fa140916e..cd0f3ebb094c 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -593,6 +593,26 @@ class Formatter { in_terminator_sequence = false; } + template <> + auto FormatInstructionRHS(Node node) -> void { + out_ << " "; + auto [src_id, refs_id] = node.GetAsArrayInit(); + FormatArg(src_id); + + llvm::ArrayRef refs = semantics_ir_.GetNodeBlock(refs_id); + auto inits = refs.drop_back(1); + auto return_slot_id = refs.back(); + + out_ << ", ("; + llvm::ListSeparator sep; + for (auto node_id : inits) { + out_ << sep; + FormatArg(node_id); + } + out_ << ')'; + FormatReturnSlot(return_slot_id); + } + template <> auto FormatInstructionRHS(Node node) -> void { out_ << " "; @@ -618,11 +638,17 @@ class Formatter { out_ << ')'; if (has_return_slot) { - out_ << " to "; - FormatArg(return_slot_id); + FormatReturnSlot(return_slot_id); } } + template <> + auto FormatInstructionRHS(Node node) -> void { + auto [src_id, dest_id] = node.GetAsInitializeFrom(); + FormatArgs(src_id); + FormatReturnSlot(dest_id); + } + template <> auto FormatInstructionRHS(Node node) -> void { // TODO: Figure out a way to make this meaningful. We'll need some way to @@ -739,6 +765,11 @@ class Formatter { out_ << ')'; } + auto FormatReturnSlot(NodeId dest_id) -> void { + out_ << " to "; + FormatArg(dest_id); + } + auto FormatNodeName(NodeId id) -> void { out_ << node_namer_.GetNameFor(scope_, id); } diff --git a/toolchain/sem_ir/node.h b/toolchain/sem_ir/node.h index a783c867b22f..b4e13070eb69 100644 --- a/toolchain/sem_ir/node.h +++ b/toolchain/sem_ir/node.h @@ -304,11 +304,18 @@ class Node : public Printable { using ArrayIndex = Factory; + // Initializes an array from a tuple. `tuple_id` is the source tuple + // expression. `refs_id` contains one initializer per array element, plus a + // final element that is the return slot for the initialization. + using ArrayInit = Factory; + using ArrayType = Node::Factory; - using ArrayValue = Factory; - + // Performs a source-level initialization or assignment of `lhs_id` from + // `rhs_id`. This finishes initialization of `lhs_id` in the same way as + // `InitializeFrom`. using Assign = Node::FactoryNoType; @@ -369,6 +376,12 @@ class Node : public Printable { using FunctionDeclaration = FactoryNoType; + // Finalizes the initialization of `dest_id` from the initializer expression + // `src_id`, by performing a final copy from source to destination, for types + // whose initialization is not in-place. + using InitializeFrom = + Factory; + using IntegerLiteral = Factory; diff --git a/toolchain/sem_ir/node_kind.def b/toolchain/sem_ir/node_kind.def index e6665ecd7491..614264f57a78 100644 --- a/toolchain/sem_ir/node_kind.def +++ b/toolchain/sem_ir/node_kind.def @@ -47,8 +47,8 @@ CARBON_SEMANTICS_NODE_KIND_IMPL(CrossReference, "xref", Typed, NotTerminator) CARBON_SEMANTICS_NODE_KIND_IMPL(AddressOf, "address_of", Typed, NotTerminator) CARBON_SEMANTICS_NODE_KIND_IMPL(ArrayIndex, "array_index", Typed, NotTerminator) +CARBON_SEMANTICS_NODE_KIND_IMPL(ArrayInit, "array_init", Typed, NotTerminator) CARBON_SEMANTICS_NODE_KIND_IMPL(ArrayType, "array_type", Typed, NotTerminator) -CARBON_SEMANTICS_NODE_KIND_IMPL(ArrayValue, "array_value", Typed, NotTerminator) CARBON_SEMANTICS_NODE_KIND_IMPL(Assign, "assign", None, NotTerminator) CARBON_SEMANTICS_NODE_KIND_IMPL(BinaryOperatorAdd, "add", Typed, NotTerminator) CARBON_SEMANTICS_NODE_KIND_IMPL(BindValue, "bind_value", Typed, NotTerminator) @@ -65,6 +65,8 @@ CARBON_SEMANTICS_NODE_KIND_IMPL(Dereference, "dereference", Typed, NotTerminator) CARBON_SEMANTICS_NODE_KIND_IMPL(FunctionDeclaration, "fn_decl", Untyped, NotTerminator) +CARBON_SEMANTICS_NODE_KIND_IMPL(InitializeFrom, "initialize_from", Typed, + NotTerminator) CARBON_SEMANTICS_NODE_KIND_IMPL(IntegerLiteral, "int_literal", Typed, NotTerminator) CARBON_SEMANTICS_NODE_KIND_IMPL(Namespace, "namespace", Untyped, NotTerminator)