From e4caf7d604b288796d7e1b92b0d55535846f43c8 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 13 Oct 2023 15:27:02 -0700 Subject: [PATCH] Compute and cache the value representation of a type when it becomes complete. (#3271) Using the computed value representation, fix lowering of struct and tuple values to use the value representation rather than the object representation. Fixes an issue found in the review of #3257. This currently causes us to compute value representations of all types as they are created, which generates substantially more SemIR to represent types. We can get some of that back by deferring computation of the value representation until the type is required to be complete, but some of the additional cost here will persist with this approach. I also considered making the computation of the value representation type be something that lives entirely within the lowering phase, but I think that's not the right approach in the longer term, because the value representation will be semantically visible and relevant once we start allowing it to be customized. We should consider moving the nodes that exist to compute canonical non-local types, including value representations, out into a separate global block. That will clean up the SemIR representation substantially, and make the SemIR produced for a function not depend on which types we happen to have encountered beforehand. But that's not being done in this PR. --------- Co-authored-by: Chandler Carruth --- toolchain/check/context.cpp | 239 ++++++++++++++++++ toolchain/check/context.h | 7 +- .../testdata/array/array_in_place.carbon | 11 +- .../testdata/array/assign_return_value.carbon | 3 +- .../check/testdata/array/assign_var.carbon | 9 +- toolchain/check/testdata/array/base.carbon | 35 +-- .../testdata/array/fail_invalid_type.carbon | 3 +- .../testdata/array/fail_out_of_bound.carbon | 6 +- .../testdata/array/fail_type_mismatch.carbon | 23 +- .../testdata/array/function_param.carbon | 31 +-- .../check/testdata/array/nine_elements.carbon | 64 ++--- .../testdata/basics/builtin_types.carbon | 1 + .../multifile_raw_and_textual_ir.carbon | 4 +- .../testdata/basics/multifile_raw_ir.carbon | 4 +- .../testdata/basics/numeric_literals.carbon | 92 +++---- .../testdata/basics/raw_and_textual_ir.carbon | 54 ++-- toolchain/check/testdata/basics/raw_ir.carbon | 54 ++-- .../function/call/fail_not_callable.carbon | 1 + .../index/array_element_access.carbon | 22 +- .../testdata/index/expression_category.carbon | 25 +- .../index/fail_array_large_index.carbon | 3 +- .../index/fail_array_non_int_indexing.carbon | 3 +- .../fail_array_out_of_bound_access.carbon | 3 +- .../testdata/index/fail_invalid_base.carbon | 5 +- .../index/fail_non_deterministic_type.carbon | 6 +- .../index/fail_tuple_index_error.carbon | 6 +- .../index/fail_tuple_non_int_indexing.carbon | 6 +- .../fail_tuple_out_of_bound_access.carbon | 6 +- toolchain/check/testdata/let/convert.carbon | 6 +- .../testdata/operators/assignment.carbon | 9 +- .../fail_assigment_to_non_assignable.carbon | 22 +- .../testdata/pointer/address_of_lvalue.carbon | 9 +- .../pointer/fail_address_of_value.carbon | 10 +- toolchain/check/testdata/struct/empty.carbon | 3 +- .../testdata/struct/fail_assign_empty.carbon | 3 +- .../testdata/struct/fail_assign_nested.carbon | 9 +- .../struct/fail_assign_to_empty.carbon | 3 +- .../struct/fail_too_few_values.carbon | 3 +- .../struct/literal_member_access.carbon | 8 +- .../testdata/struct/member_access.carbon | 3 +- .../struct/nested_struct_in_place.carbon | 4 +- .../testdata/struct/tuple_as_element.carbon | 3 +- .../check/testdata/struct/two_entries.carbon | 3 +- .../testdata/tuples/fail_assign_nested.carbon | 21 +- .../tuples/fail_element_type_mismatch.carbon | 13 +- .../tuples/fail_too_few_element.carbon | 6 +- .../check/testdata/tuples/nested_tuple.carbon | 14 +- .../tuples/nested_tuple_in_place.carbon | 16 +- .../check/testdata/tuples/two_elements.carbon | 6 +- .../testdata/while/fail_bad_condition.carbon | 1 + toolchain/lower/file_context.cpp | 10 +- toolchain/lower/function_context.cpp | 2 + toolchain/lower/handle.cpp | 104 +++++--- .../lower/handle_expression_category.cpp | 3 + .../lower/testdata/basics/type_values.carbon | 13 +- toolchain/lower/testdata/let/tuple.carbon | 15 +- .../testdata/tuple/value_formation.carbon | 6 +- .../testdata/tuple/value_forwarding.carbon | 6 +- toolchain/sem_ir/file.cpp | 168 +++--------- toolchain/sem_ir/file.h | 113 ++++++--- toolchain/sem_ir/yaml_test.cpp | 4 +- 61 files changed, 837 insertions(+), 508 deletions(-) diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 58269a92a731..50fdad22bb8d 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -279,6 +279,235 @@ auto Context::ParamOrArgEnd(Parse::NodeKind start_kind) -> SemIR::NodeBlockId { return ParamOrArgPop(); } +// Attempts to complete the given type. +auto Context::TryToCompleteType(SemIR::TypeId type_id) -> bool { + auto node_id = semantics_ir().GetTypeAllowBuiltinTypes(type_id); + auto node = semantics_ir().GetNode(node_id); + + auto set_empty_representation = [&]() { + semantics_ir().CompleteType( + type_id, {.kind = SemIR::ValueRepresentation::None, + .type_id = CanonicalizeTupleType(node.parse_node(), {})}); + return true; + }; + + auto set_copy_representation = [&](SemIR::TypeId rep_id) { + semantics_ir().CompleteType( + type_id, {.kind = SemIR::ValueRepresentation::Copy, .type_id = rep_id}); + return true; + }; + + auto set_pointer_representation = [&](SemIR::TypeId pointee_id) { + // TODO: Should we add `const` qualification to `pointee_id`? + semantics_ir().CompleteType( + type_id, {.kind = SemIR::ValueRepresentation::Pointer, + .type_id = GetPointerType(node.parse_node(), pointee_id)}); + return true; + }; + + // clang warns on unhandled enum values; clang-tidy is incorrect here. + // NOLINTNEXTLINE(bugprone-switch-missing-default-case) + switch (node.kind()) { + case SemIR::AddressOf::Kind: + case SemIR::ArrayIndex::Kind: + case SemIR::ArrayInit::Kind: + case SemIR::Assign::Kind: + case SemIR::BinaryOperatorAdd::Kind: + case SemIR::BindName::Kind: + case SemIR::BindValue::Kind: + case SemIR::BlockArg::Kind: + case SemIR::BoolLiteral::Kind: + case SemIR::Branch::Kind: + case SemIR::BranchIf::Kind: + case SemIR::BranchWithArg::Kind: + case SemIR::Call::Kind: + case SemIR::Dereference::Kind: + case SemIR::FunctionDeclaration::Kind: + case SemIR::InitializeFrom::Kind: + case SemIR::IntegerLiteral::Kind: + case SemIR::NameReference::Kind: + case SemIR::Namespace::Kind: + case SemIR::NoOp::Kind: + case SemIR::Parameter::Kind: + case SemIR::RealLiteral::Kind: + case SemIR::Return::Kind: + case SemIR::ReturnExpression::Kind: + case SemIR::SpliceBlock::Kind: + case SemIR::StringLiteral::Kind: + case SemIR::StructAccess::Kind: + case SemIR::StructTypeField::Kind: + case SemIR::StructLiteral::Kind: + case SemIR::StructInit::Kind: + case SemIR::StructValue::Kind: + case SemIR::Temporary::Kind: + case SemIR::TemporaryStorage::Kind: + case SemIR::TupleAccess::Kind: + case SemIR::TupleIndex::Kind: + case SemIR::TupleLiteral::Kind: + case SemIR::TupleInit::Kind: + case SemIR::TupleValue::Kind: + case SemIR::UnaryOperatorNot::Kind: + case SemIR::ValueAsReference::Kind: + case SemIR::VarStorage::Kind: + CARBON_FATAL() << "Type refers to non-type node " << node; + + case SemIR::CrossReference::Kind: { + auto xref = node.As(); + auto xref_node = + semantics_ir().GetCrossReferenceIR(xref.ir_id).GetNode(xref.node_id); + + // The canonical description of a type should only have cross-references + // for entities owned by another File, such as builtins, which are owned + // by the prelude, and named entities like classes and interfaces, which + // we don't support yet. + CARBON_CHECK(xref_node.kind() == SemIR::Builtin::Kind) + << "TODO: Handle other kinds of node cross-references"; + + // clang warns on unhandled enum values; clang-tidy is incorrect here. + // NOLINTNEXTLINE(bugprone-switch-missing-default-case) + switch (xref_node.As().builtin_kind) { + case SemIR::BuiltinKind::TypeType: + case SemIR::BuiltinKind::Error: + case SemIR::BuiltinKind::Invalid: + case SemIR::BuiltinKind::BoolType: + case SemIR::BuiltinKind::IntegerType: + case SemIR::BuiltinKind::FloatingPointType: + case SemIR::BuiltinKind::NamespaceType: + case SemIR::BuiltinKind::FunctionType: + return set_copy_representation(type_id); + + case SemIR::BuiltinKind::StringType: + // TODO: Decide on string value semantics. This should probably be a + // custom value representation carrying a pointer and size or + // similar. + return set_pointer_representation(type_id); + } + llvm_unreachable("All builtin kinds were handled above"); + } + + case SemIR::ArrayType::Kind: + // For arrays, it's convenient to always use a pointer representation, + // even when the array has zero or one element, in order to support + // indexing. + return set_pointer_representation(type_id); + + case SemIR::StructType::Kind: { + auto fields = + semantics_ir().GetNodeBlock(node.As().fields_id); + if (fields.empty()) { + return set_empty_representation(); + } + + // Find the value representation for each field, and construct a struct + // of value representations. + llvm::SmallVector value_rep_fields; + value_rep_fields.reserve(fields.size()); + bool same_as_object_rep = true; + for (auto field_id : fields) { + auto field = semantics_ir().GetNodeAs(field_id); + + // A struct is complete if and only if all its fields are complete. + auto field_value_rep = + semantics_ir().GetValueRepresentation(field.type_id); + if (field_value_rep.kind == SemIR::ValueRepresentation::Unknown) { + // TODO: If the field type might have become complete after we formed + // it, we should attempt to complete its type. + return false; + } + if (field_value_rep.type_id != field.type_id) { + same_as_object_rep = false; + field.type_id = field_value_rep.type_id; + field_id = AddNode(field); + } + value_rep_fields.push_back(field_id); + } + + auto value_rep = same_as_object_rep + ? type_id + : CanonicalizeStructType( + node.parse_node(), + semantics_ir().AddNodeBlock(value_rep_fields)); + if (fields.size() == 1) { + // The value representation for a struct with a single field is a struct + // containing the value representation of the field. + // TODO: Consider doing the same for structs with multiple small fields. + return set_copy_representation(value_rep); + } + // For a struct with multiple fields, we use a pointer representation. + return set_pointer_representation(value_rep); + } + + case SemIR::TupleType::Kind: { + // TODO: Extract and share code with structs and maybe arrays. + auto elements = + semantics_ir().GetTypeBlock(node.As().elements_id); + if (elements.empty()) { + return set_empty_representation(); + } + + // Find the value representation for each element, and construct a tuple + // of value representations. + llvm::SmallVector value_rep_elements; + value_rep_elements.reserve(elements.size()); + bool same_as_object_rep = true; + for (auto element_type_id : elements) { + // A tuple is complete if and only if all its elements are complete. + auto element_value_rep = + semantics_ir().GetValueRepresentation(element_type_id); + if (element_value_rep.kind == SemIR::ValueRepresentation::Unknown) { + // TODO: If the element type might have become complete after we + // formed it, we should attempt to complete its type. + return false; + } + if (element_value_rep.type_id != element_type_id) { + same_as_object_rep = false; + } + value_rep_elements.push_back(element_value_rep.type_id); + } + + auto value_rep = + same_as_object_rep + ? type_id + : CanonicalizeTupleType(node.parse_node(), value_rep_elements); + if (elements.size() == 1) { + // The value representation for a tuple with a single element is a tuple + // containing the value representation of that element. + // TODO: Consider doing the same for tuples with multiple small + // elements. + return set_copy_representation(value_rep); + } + // For a tuple with multiple elements, we use a pointer representation. + return set_pointer_representation(value_rep); + } + + case SemIR::ClassDeclaration::Kind: { + // TODO: Pick the default value representation in a smarter way. + // TODO: Allow the value representation for a class to be customized. + return set_pointer_representation(type_id); + } + + case SemIR::Builtin::Kind: + CARBON_FATAL() << "Builtins should be named as cross-references"; + + case SemIR::PointerType::Kind: + return set_copy_representation(type_id); + + case SemIR::ConstType::Kind: { + // The value representation of `const T` is the same as that of `T`. + // Objects are not modifiable through their value representations. + auto inner_value_rep = semantics_ir().GetValueRepresentation( + node.As().inner_id); + if (inner_value_rep.kind == SemIR::ValueRepresentation::Unknown) { + return false; + } + semantics_ir().CompleteType(type_id, inner_value_rep); + return true; + } + } + + llvm_unreachable("All node kinds were handled above"); +} + auto Context::CanonicalizeTypeImpl( SemIR::NodeKind kind, llvm::function_ref profile_type, @@ -310,6 +539,16 @@ auto Context::CanonicalizeTypeImpl( }()) << "Type was created recursively during canonicalization"; canonical_type_nodes_.InsertNode(type_node_storage_.back().get(), insert_pos); + + // Now we've formed the type, try to complete it and build its value + // representation. + // TODO: Delay doing this until a complete type is required, and issue a + // diagnostic if it fails. + // TODO: Consider emitting this into the file's global node block + // (or somewhere else that better reflects the definition of the type + // rather than the coincidental first use). + bool complete = TryToCompleteType(type_id); + CARBON_CHECK(complete) << "Incomplete types should not exist yet"; return type_id; } diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 3f6f099d3306..b9ac682e2b07 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -115,7 +115,6 @@ class Context { auto is_current_position_reachable() -> bool; // Canonicalizes a type which is tracked as a single node. - // TODO: This should eventually return a type ID. auto CanonicalizeType(SemIR::NodeId node_id) -> SemIR::TypeId; // Handles canonicalization of struct types. This may create a new struct type @@ -134,6 +133,12 @@ class Context { llvm::ArrayRef type_ids) -> SemIR::TypeId; + // Attempts to complete the type `type_id`. Returns `true` if the type is + // complete, or `false` if it could not be completed. A complete type has + // known object and value representations. + // TODO: For now, all types are always complete. + auto TryToCompleteType(SemIR::TypeId type_id) -> bool; + // Returns a pointer type whose pointee type is `pointee_type_id`. auto GetPointerType(Parse::Node parse_node, SemIR::TypeId pointee_type_id) -> SemIR::TypeId; diff --git a/toolchain/check/testdata/array/array_in_place.carbon b/toolchain/check/testdata/array/array_in_place.carbon index f57b6c707278..2c8ad5d5b8d8 100644 --- a/toolchain/check/testdata/array/array_in_place.carbon +++ b/toolchain/check/testdata/array/array_in_place.carbon @@ -21,7 +21,8 @@ fn G() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc10_25: (type, type, type) = tuple_literal (i32, i32, i32) // CHECK:STDOUT: %.loc10_28: i32 = int_literal 2 -// CHECK:STDOUT: %.loc10_29: type = array_type %.loc10_28, (i32, i32, i32) +// CHECK:STDOUT: %.loc10_29.1: type = array_type %.loc10_28, (i32, i32, i32) +// CHECK:STDOUT: %.loc10_29.2: type = ptr_type [(i32, i32, i32); 2] // CHECK:STDOUT: %v: ref [(i32, i32, i32); 2] = var "v" // CHECK:STDOUT: %F.ref.loc10_34: = name_reference "F", package.%F // CHECK:STDOUT: %.loc10_42.3: ref (i32, i32, i32) = splice_block %.loc10_42.2 { @@ -36,8 +37,10 @@ fn G() { // CHECK:STDOUT: } // CHECK:STDOUT: %.loc10_40: init (i32, i32, i32) = call %F.ref.loc10_39() to %.loc10_42.6 // CHECK:STDOUT: %.loc10_42.7: type = tuple_type ((i32, i32, i32), (i32, i32, i32)) -// CHECK:STDOUT: %.loc10_42.8: ((i32, i32, i32), (i32, i32, i32)) = tuple_literal (%.loc10_35, %.loc10_40) -// CHECK:STDOUT: %.loc10_42.9: init [(i32, i32, i32); 2] = array_init %.loc10_42.8, (%.loc10_35, %.loc10_40) to %v -// CHECK:STDOUT: assign %v, %.loc10_42.9 +// CHECK:STDOUT: %.loc10_42.8: type = tuple_type ((i32, i32, i32)*, (i32, i32, i32)*) +// CHECK:STDOUT: %.loc10_42.9: type = ptr_type ((i32, i32, i32)*, (i32, i32, i32)*) +// CHECK:STDOUT: %.loc10_42.10: ((i32, i32, i32), (i32, i32, i32)) = tuple_literal (%.loc10_35, %.loc10_40) +// CHECK:STDOUT: %.loc10_42.11: init [(i32, i32, i32); 2] = array_init %.loc10_42.10, (%.loc10_35, %.loc10_40) to %v +// CHECK:STDOUT: assign %v, %.loc10_42.11 // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/array/assign_return_value.carbon b/toolchain/check/testdata/array/assign_return_value.carbon index 7e5fa3da19b0..f10b054e314e 100644 --- a/toolchain/check/testdata/array/assign_return_value.carbon +++ b/toolchain/check/testdata/array/assign_return_value.carbon @@ -26,7 +26,8 @@ fn Run() { // CHECK:STDOUT: fn @Run() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc10_16: i32 = int_literal 1 -// CHECK:STDOUT: %.loc10_17: type = array_type %.loc10_16, i32 +// CHECK:STDOUT: %.loc10_17.1: type = array_type %.loc10_16, i32 +// CHECK:STDOUT: %.loc10_17.2: type = ptr_type [i32; 1] // CHECK:STDOUT: %t: ref [i32; 1] = var "t" // CHECK:STDOUT: %F.ref: = name_reference "F", package.%F // CHECK:STDOUT: %.loc10_22.1: init (i32,) = call %F.ref() diff --git a/toolchain/check/testdata/array/assign_var.carbon b/toolchain/check/testdata/array/assign_var.carbon index e205b7fd155d..ad76a5c9d088 100644 --- a/toolchain/check/testdata/array/assign_var.carbon +++ b/toolchain/check/testdata/array/assign_var.carbon @@ -9,8 +9,10 @@ var b: [i32; 3] = a; // CHECK:STDOUT: file "assign_var.carbon" { // CHECK:STDOUT: %.loc7_22.1: type = tuple_type (type, type, type) -// CHECK:STDOUT: %.loc7_22.2: (type, type, type) = tuple_literal (i32, i32, i32) -// CHECK:STDOUT: %.loc7_22.3: type = tuple_type (i32, i32, i32) +// CHECK:STDOUT: %.loc7_22.2: type = ptr_type (type, type, type) +// CHECK:STDOUT: %.loc7_22.3: (type, type, type) = tuple_literal (i32, i32, i32) +// CHECK:STDOUT: %.loc7_22.4: type = tuple_type (i32, i32, i32) +// CHECK:STDOUT: %.loc7_22.5: type = ptr_type (i32, i32, i32) // CHECK:STDOUT: %a: ref (i32, i32, i32) = var "a" // CHECK:STDOUT: %.loc7_27: i32 = int_literal 1 // CHECK:STDOUT: %.loc7_30: i32 = int_literal 2 @@ -25,7 +27,8 @@ var b: [i32; 3] = a; // CHECK:STDOUT: %.loc7_34.8: init (i32, i32, i32) = tuple_init %.loc7_34.1, (%.loc7_34.3, %.loc7_34.5, %.loc7_34.7) // CHECK:STDOUT: assign %a, %.loc7_34.8 // CHECK:STDOUT: %.loc8_14: i32 = int_literal 3 -// CHECK:STDOUT: %.loc8_15: type = array_type %.loc8_14, i32 +// CHECK:STDOUT: %.loc8_15.1: type = array_type %.loc8_14, i32 +// CHECK:STDOUT: %.loc8_15.2: type = ptr_type [i32; 3] // CHECK:STDOUT: %b: ref [i32; 3] = var "b" // CHECK:STDOUT: %a.ref: ref (i32, i32, i32) = name_reference "a", %a // CHECK:STDOUT: %.loc8_19.1: ref i32 = tuple_access %a.ref, member0 diff --git a/toolchain/check/testdata/array/base.carbon b/toolchain/check/testdata/array/base.carbon index 70cdd5f25261..a7669ac8c89f 100644 --- a/toolchain/check/testdata/array/base.carbon +++ b/toolchain/check/testdata/array/base.carbon @@ -10,7 +10,8 @@ var c: [(); 5] = ((), (), (), (), (),); // CHECK:STDOUT: file "base.carbon" { // CHECK:STDOUT: %.loc7_14: i32 = int_literal 1 -// CHECK:STDOUT: %.loc7_15: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.1: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.2: type = ptr_type [i32; 1] // CHECK:STDOUT: %a: ref [i32; 1] = var "a" // CHECK:STDOUT: %.loc7_20: i32 = int_literal 1 // CHECK:STDOUT: %.loc7_22.1: type = tuple_type (i32) @@ -21,24 +22,27 @@ var c: [(); 5] = ((), (), (), (), (),); // CHECK:STDOUT: %.loc7_22.6: init [i32; 1] = array_init %.loc7_22.2, (%.loc7_22.5) to %a // CHECK:STDOUT: assign %a, %.loc7_22.6 // CHECK:STDOUT: %.loc8_14: i32 = int_literal 2 -// CHECK:STDOUT: %.loc8_15: type = array_type %.loc8_14, f64 +// CHECK:STDOUT: %.loc8_15.1: type = array_type %.loc8_14, f64 +// CHECK:STDOUT: %.loc8_15.2: type = ptr_type [f64; 2] // CHECK:STDOUT: %b: ref [f64; 2] = var "b" // CHECK:STDOUT: %.loc8_20: f64 = real_literal 111e-1 // CHECK:STDOUT: %.loc8_26: f64 = real_literal 22e-1 // CHECK:STDOUT: %.loc8_30.1: type = tuple_type (f64, f64) -// CHECK:STDOUT: %.loc8_30.2: (f64, f64) = tuple_literal (%.loc8_20, %.loc8_26) -// CHECK:STDOUT: %.loc8_30.3: i32 = int_literal 0 -// CHECK:STDOUT: %.loc8_30.4: ref f64 = array_index %b, %.loc8_30.3 -// CHECK:STDOUT: %.loc8_30.5: init f64 = initialize_from %.loc8_20 to %.loc8_30.4 -// CHECK:STDOUT: %.loc8_30.6: i32 = int_literal 1 -// CHECK:STDOUT: %.loc8_30.7: ref f64 = array_index %b, %.loc8_30.6 -// CHECK:STDOUT: %.loc8_30.8: init f64 = initialize_from %.loc8_26 to %.loc8_30.7 -// CHECK:STDOUT: %.loc8_30.9: init [f64; 2] = array_init %.loc8_30.2, (%.loc8_30.5, %.loc8_30.8) to %b -// CHECK:STDOUT: assign %b, %.loc8_30.9 +// CHECK:STDOUT: %.loc8_30.2: type = ptr_type (f64, f64) +// CHECK:STDOUT: %.loc8_30.3: (f64, f64) = tuple_literal (%.loc8_20, %.loc8_26) +// CHECK:STDOUT: %.loc8_30.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc8_30.5: ref f64 = array_index %b, %.loc8_30.4 +// CHECK:STDOUT: %.loc8_30.6: init f64 = initialize_from %.loc8_20 to %.loc8_30.5 +// CHECK:STDOUT: %.loc8_30.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc8_30.8: ref f64 = array_index %b, %.loc8_30.7 +// CHECK:STDOUT: %.loc8_30.9: init f64 = initialize_from %.loc8_26 to %.loc8_30.8 +// CHECK:STDOUT: %.loc8_30.10: init [f64; 2] = array_init %.loc8_30.3, (%.loc8_30.6, %.loc8_30.9) to %b +// 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 -// CHECK:STDOUT: %.loc9_14: type = array_type %.loc9_13, () +// CHECK:STDOUT: %.loc9_14.1: type = array_type %.loc9_13, () +// CHECK:STDOUT: %.loc9_14.2: type = ptr_type [(); 5] // CHECK:STDOUT: %c: ref [(); 5] = var "c" // CHECK:STDOUT: %.loc9_20.1: () = tuple_literal () // CHECK:STDOUT: %.loc9_24.1: () = tuple_literal () @@ -46,12 +50,13 @@ var c: [(); 5] = ((), (), (), (), (),); // CHECK:STDOUT: %.loc9_32.1: () = tuple_literal () // CHECK:STDOUT: %.loc9_36.1: () = tuple_literal () // CHECK:STDOUT: %.loc9_38.1: type = tuple_type ((), (), (), (), ()) -// CHECK:STDOUT: %.loc9_38.2: ((), (), (), (), ()) = tuple_literal (%.loc9_20.1, %.loc9_24.1, %.loc9_28.1, %.loc9_32.1, %.loc9_36.1) +// CHECK:STDOUT: %.loc9_38.2: type = ptr_type ((), (), (), (), ()) +// CHECK:STDOUT: %.loc9_38.3: ((), (), (), (), ()) = tuple_literal (%.loc9_20.1, %.loc9_24.1, %.loc9_28.1, %.loc9_32.1, %.loc9_36.1) // CHECK:STDOUT: %.loc9_20.2: init () = tuple_init %.loc9_20.1, () // CHECK:STDOUT: %.loc9_24.2: init () = tuple_init %.loc9_24.1, () // CHECK:STDOUT: %.loc9_28.2: init () = tuple_init %.loc9_28.1, () // CHECK:STDOUT: %.loc9_32.2: init () = tuple_init %.loc9_32.1, () // CHECK:STDOUT: %.loc9_36.2: init () = tuple_init %.loc9_36.1, () -// CHECK:STDOUT: %.loc9_38.3: init [(); 5] = array_init %.loc9_38.2, (%.loc9_20.2, %.loc9_24.2, %.loc9_28.2, %.loc9_32.2, %.loc9_36.2) to %c -// CHECK:STDOUT: assign %c, %.loc9_38.3 +// CHECK:STDOUT: %.loc9_38.4: init [(); 5] = array_init %.loc9_38.3, (%.loc9_20.2, %.loc9_24.2, %.loc9_28.2, %.loc9_32.2, %.loc9_36.2) to %c +// CHECK:STDOUT: assign %c, %.loc9_38.4 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/array/fail_invalid_type.carbon b/toolchain/check/testdata/array/fail_invalid_type.carbon index c4c905e32776..4c3135f349cf 100644 --- a/toolchain/check/testdata/array/fail_invalid_type.carbon +++ b/toolchain/check/testdata/array/fail_invalid_type.carbon @@ -12,6 +12,7 @@ var a: [1; 1]; // CHECK:STDOUT: file "fail_invalid_type.carbon" { // CHECK:STDOUT: %.loc10_9: i32 = int_literal 1 // CHECK:STDOUT: %.loc10_12: i32 = int_literal 1 -// CHECK:STDOUT: %.loc10_13: type = array_type %.loc10_12, +// CHECK:STDOUT: %.loc10_13.1: type = array_type %.loc10_12, +// CHECK:STDOUT: %.loc10_13.2: type = ptr_type [; 1] // CHECK:STDOUT: %a: ref [; 1] = var "a" // 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 538d6f8381ca..9b4e674d2eed 100644 --- a/toolchain/check/testdata/array/fail_out_of_bound.carbon +++ b/toolchain/check/testdata/array/fail_out_of_bound.carbon @@ -11,12 +11,14 @@ var a: [i32; 1] = (1, 2, 3); // CHECK:STDOUT: file "fail_out_of_bound.carbon" { // CHECK:STDOUT: %.loc10_14: i32 = int_literal 1 -// CHECK:STDOUT: %.loc10_15: type = array_type %.loc10_14, i32 +// CHECK:STDOUT: %.loc10_15.1: type = array_type %.loc10_14, i32 +// CHECK:STDOUT: %.loc10_15.2: type = ptr_type [i32; 1] // CHECK:STDOUT: %a: ref [i32; 1] = var "a" // CHECK:STDOUT: %.loc10_20: i32 = int_literal 1 // CHECK:STDOUT: %.loc10_23: i32 = int_literal 2 // CHECK:STDOUT: %.loc10_26: i32 = int_literal 3 // CHECK:STDOUT: %.loc10_27.1: type = tuple_type (i32, i32, i32) -// CHECK:STDOUT: %.loc10_27.2: (i32, i32, i32) = tuple_literal (%.loc10_20, %.loc10_23, %.loc10_26) +// CHECK:STDOUT: %.loc10_27.2: type = ptr_type (i32, i32, i32) +// CHECK:STDOUT: %.loc10_27.3: (i32, i32, i32) = tuple_literal (%.loc10_20, %.loc10_23, %.loc10_26) // CHECK:STDOUT: assign %a, // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/array/fail_type_mismatch.carbon b/toolchain/check/testdata/array/fail_type_mismatch.carbon index 483628d9332b..6e400a66e3f5 100644 --- a/toolchain/check/testdata/array/fail_type_mismatch.carbon +++ b/toolchain/check/testdata/array/fail_type_mismatch.carbon @@ -28,19 +28,24 @@ var d: [i32; 3] = t2; // CHECK:STDOUT: file "fail_type_mismatch.carbon" { // CHECK:STDOUT: %.loc10_14: i32 = int_literal 3 -// CHECK:STDOUT: %.loc10_15: type = array_type %.loc10_14, i32 +// CHECK:STDOUT: %.loc10_15.1: type = array_type %.loc10_14, i32 +// CHECK:STDOUT: %.loc10_15.2: type = ptr_type [i32; 3] // CHECK:STDOUT: %a: ref [i32; 3] = var "a" // CHECK:STDOUT: %.loc10_20: i32 = int_literal 1 +// CHECK:STDOUT: %.1: type = ptr_type String // CHECK:STDOUT: %.loc10_23: String = string_literal "Hello" // CHECK:STDOUT: %.loc10_32: String = string_literal "World" // CHECK:STDOUT: %.loc10_39.1: type = tuple_type (i32, String, String) -// CHECK:STDOUT: %.loc10_39.2: (i32, String, String) = tuple_literal (%.loc10_20, %.loc10_23, %.loc10_32) -// CHECK:STDOUT: %.loc10_39.3: i32 = int_literal 0 -// CHECK:STDOUT: %.loc10_39.4: ref i32 = array_index %a, %.loc10_39.3 -// CHECK:STDOUT: %.loc10_39.5: init i32 = initialize_from %.loc10_20 to %.loc10_39.4 +// CHECK:STDOUT: %.loc10_39.2: type = tuple_type (i32, String*, String*) +// CHECK:STDOUT: %.loc10_39.3: type = ptr_type (i32, String*, String*) +// CHECK:STDOUT: %.loc10_39.4: (i32, String, String) = tuple_literal (%.loc10_20, %.loc10_23, %.loc10_32) +// CHECK:STDOUT: %.loc10_39.5: i32 = int_literal 0 +// CHECK:STDOUT: %.loc10_39.6: ref i32 = array_index %a, %.loc10_39.5 +// CHECK:STDOUT: %.loc10_39.7: init i32 = initialize_from %.loc10_20 to %.loc10_39.6 // CHECK:STDOUT: assign %a, // CHECK:STDOUT: %.loc12_29.1: type = tuple_type (type, type, type) -// CHECK:STDOUT: %.loc12_29.2: (type, type, type) = tuple_literal (i32, String, String) +// CHECK:STDOUT: %.loc12_29.2: type = ptr_type (type, type, type) +// CHECK:STDOUT: %.loc12_29.3: (type, type, type) = tuple_literal (i32, String, String) // 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 @@ -59,10 +64,12 @@ var d: [i32; 3] = t2; // CHECK:STDOUT: %.loc21_20: i32 = int_literal 1 // CHECK:STDOUT: %.loc21_23: i32 = int_literal 2 // CHECK:STDOUT: %.loc21_24.1: type = tuple_type (i32, i32) -// CHECK:STDOUT: %.loc21_24.2: (i32, i32) = tuple_literal (%.loc21_20, %.loc21_23) +// CHECK:STDOUT: %.loc21_24.2: type = ptr_type (i32, i32) +// CHECK:STDOUT: %.loc21_24.3: (i32, i32) = tuple_literal (%.loc21_20, %.loc21_23) // CHECK:STDOUT: assign %c, // CHECK:STDOUT: %.loc23_18.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc23_18.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc23_18.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc23_18.3: (type, type) = tuple_literal (i32, i32) // 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 diff --git a/toolchain/check/testdata/array/function_param.carbon b/toolchain/check/testdata/array/function_param.carbon index c0f6a1715048..b83e7bd936a6 100644 --- a/toolchain/check/testdata/array/function_param.carbon +++ b/toolchain/check/testdata/array/function_param.carbon @@ -34,22 +34,23 @@ fn G() -> i32 { // CHECK:STDOUT: %.loc12_16: i32 = int_literal 2 // CHECK:STDOUT: %.loc12_19: i32 = int_literal 3 // CHECK:STDOUT: %.loc12_20.1: type = tuple_type (i32, i32, i32) -// CHECK:STDOUT: %.loc12_20.2: (i32, i32, i32) = tuple_literal (%.loc12_13, %.loc12_16, %.loc12_19) +// CHECK:STDOUT: %.loc12_20.2: type = ptr_type (i32, i32, i32) +// CHECK:STDOUT: %.loc12_20.3: (i32, i32, i32) = tuple_literal (%.loc12_13, %.loc12_16, %.loc12_19) // CHECK:STDOUT: %.loc12_23: i32 = int_literal 1 -// CHECK:STDOUT: %.loc12_20.3: ref [i32; 3] = temporary_storage -// CHECK:STDOUT: %.loc12_20.4: i32 = int_literal 0 -// CHECK:STDOUT: %.loc12_20.5: ref i32 = array_index %.loc12_20.3, %.loc12_20.4 -// CHECK:STDOUT: %.loc12_20.6: init i32 = initialize_from %.loc12_13 to %.loc12_20.5 -// CHECK:STDOUT: %.loc12_20.7: i32 = int_literal 1 -// CHECK:STDOUT: %.loc12_20.8: ref i32 = array_index %.loc12_20.3, %.loc12_20.7 -// CHECK:STDOUT: %.loc12_20.9: init i32 = initialize_from %.loc12_16 to %.loc12_20.8 -// CHECK:STDOUT: %.loc12_20.10: i32 = int_literal 2 -// CHECK:STDOUT: %.loc12_20.11: ref i32 = array_index %.loc12_20.3, %.loc12_20.10 -// CHECK:STDOUT: %.loc12_20.12: init i32 = initialize_from %.loc12_19 to %.loc12_20.11 -// CHECK:STDOUT: %.loc12_20.13: init [i32; 3] = array_init %.loc12_20.2, (%.loc12_20.6, %.loc12_20.9, %.loc12_20.12) to %.loc12_20.3 -// CHECK:STDOUT: %.loc12_20.14: ref [i32; 3] = temporary %.loc12_20.3, %.loc12_20.13 -// CHECK:STDOUT: %.loc12_20.15: [i32; 3] = bind_value %.loc12_20.14 -// CHECK:STDOUT: %.loc12_11.1: init i32 = call %F.ref(%.loc12_20.15, %.loc12_23) +// 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 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 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 to %.loc12_20.12 +// CHECK:STDOUT: %.loc12_20.14: init [i32; 3] = array_init %.loc12_20.3, (%.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.ref(%.loc12_20.16, %.loc12_23) // 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 diff --git a/toolchain/check/testdata/array/nine_elements.carbon b/toolchain/check/testdata/array/nine_elements.carbon index 020f9ee0b236..3e18e7c54c36 100644 --- a/toolchain/check/testdata/array/nine_elements.carbon +++ b/toolchain/check/testdata/array/nine_elements.carbon @@ -8,7 +8,8 @@ var a: [i32; 9] = (1, 2, 3, 4, 5, 6, 7, 8, 9); // CHECK:STDOUT: file "nine_elements.carbon" { // CHECK:STDOUT: %.loc7_14: i32 = int_literal 9 -// CHECK:STDOUT: %.loc7_15: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.1: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.2: type = ptr_type [i32; 9] // CHECK:STDOUT: %a: ref [i32; 9] = var "a" // CHECK:STDOUT: %.loc7_20: i32 = int_literal 1 // CHECK:STDOUT: %.loc7_23: i32 = int_literal 2 @@ -20,34 +21,35 @@ var a: [i32; 9] = (1, 2, 3, 4, 5, 6, 7, 8, 9); // CHECK:STDOUT: %.loc7_41: i32 = int_literal 8 // CHECK:STDOUT: %.loc7_44: i32 = int_literal 9 // 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, %.loc7_23, %.loc7_26, %.loc7_29, %.loc7_32, %.loc7_35, %.loc7_38, %.loc7_41, %.loc7_44) -// CHECK:STDOUT: %.loc7_45.3: i32 = int_literal 0 -// CHECK:STDOUT: %.loc7_45.4: ref i32 = array_index %a, %.loc7_45.3 -// CHECK:STDOUT: %.loc7_45.5: init i32 = initialize_from %.loc7_20 to %.loc7_45.4 -// CHECK:STDOUT: %.loc7_45.6: i32 = int_literal 1 -// CHECK:STDOUT: %.loc7_45.7: ref i32 = array_index %a, %.loc7_45.6 -// CHECK:STDOUT: %.loc7_45.8: init i32 = initialize_from %.loc7_23 to %.loc7_45.7 -// CHECK:STDOUT: %.loc7_45.9: i32 = int_literal 2 -// CHECK:STDOUT: %.loc7_45.10: ref i32 = array_index %a, %.loc7_45.9 -// CHECK:STDOUT: %.loc7_45.11: init i32 = initialize_from %.loc7_26 to %.loc7_45.10 -// CHECK:STDOUT: %.loc7_45.12: i32 = int_literal 3 -// CHECK:STDOUT: %.loc7_45.13: ref i32 = array_index %a, %.loc7_45.12 -// CHECK:STDOUT: %.loc7_45.14: init i32 = initialize_from %.loc7_29 to %.loc7_45.13 -// CHECK:STDOUT: %.loc7_45.15: i32 = int_literal 4 -// CHECK:STDOUT: %.loc7_45.16: ref i32 = array_index %a, %.loc7_45.15 -// CHECK:STDOUT: %.loc7_45.17: init i32 = initialize_from %.loc7_32 to %.loc7_45.16 -// CHECK:STDOUT: %.loc7_45.18: i32 = int_literal 5 -// CHECK:STDOUT: %.loc7_45.19: ref i32 = array_index %a, %.loc7_45.18 -// CHECK:STDOUT: %.loc7_45.20: init i32 = initialize_from %.loc7_35 to %.loc7_45.19 -// CHECK:STDOUT: %.loc7_45.21: i32 = int_literal 6 -// CHECK:STDOUT: %.loc7_45.22: ref i32 = array_index %a, %.loc7_45.21 -// CHECK:STDOUT: %.loc7_45.23: init i32 = initialize_from %.loc7_38 to %.loc7_45.22 -// CHECK:STDOUT: %.loc7_45.24: i32 = int_literal 7 -// CHECK:STDOUT: %.loc7_45.25: ref i32 = array_index %a, %.loc7_45.24 -// CHECK:STDOUT: %.loc7_45.26: init i32 = initialize_from %.loc7_41 to %.loc7_45.25 -// CHECK:STDOUT: %.loc7_45.27: i32 = int_literal 8 -// CHECK:STDOUT: %.loc7_45.28: ref i32 = array_index %a, %.loc7_45.27 -// CHECK:STDOUT: %.loc7_45.29: init i32 = initialize_from %.loc7_44 to %.loc7_45.28 -// CHECK:STDOUT: %.loc7_45.30: init [i32; 9] = array_init %.loc7_45.2, (%.loc7_45.5, %.loc7_45.8, %.loc7_45.11, %.loc7_45.14, %.loc7_45.17, %.loc7_45.20, %.loc7_45.23, %.loc7_45.26, %.loc7_45.29) to %a -// CHECK:STDOUT: assign %a, %.loc7_45.30 +// CHECK:STDOUT: %.loc7_45.2: type = ptr_type (i32, i32, i32, i32, i32, i32, i32, i32, i32) +// CHECK:STDOUT: %.loc7_45.3: (i32, i32, i32, i32, i32, i32, i32, i32, i32) = tuple_literal (%.loc7_20, %.loc7_23, %.loc7_26, %.loc7_29, %.loc7_32, %.loc7_35, %.loc7_38, %.loc7_41, %.loc7_44) +// CHECK:STDOUT: %.loc7_45.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc7_45.5: ref i32 = array_index %a, %.loc7_45.4 +// CHECK:STDOUT: %.loc7_45.6: init i32 = initialize_from %.loc7_20 to %.loc7_45.5 +// CHECK:STDOUT: %.loc7_45.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc7_45.8: ref i32 = array_index %a, %.loc7_45.7 +// CHECK:STDOUT: %.loc7_45.9: init i32 = initialize_from %.loc7_23 to %.loc7_45.8 +// CHECK:STDOUT: %.loc7_45.10: i32 = int_literal 2 +// CHECK:STDOUT: %.loc7_45.11: ref i32 = array_index %a, %.loc7_45.10 +// CHECK:STDOUT: %.loc7_45.12: init i32 = initialize_from %.loc7_26 to %.loc7_45.11 +// CHECK:STDOUT: %.loc7_45.13: i32 = int_literal 3 +// CHECK:STDOUT: %.loc7_45.14: ref i32 = array_index %a, %.loc7_45.13 +// CHECK:STDOUT: %.loc7_45.15: init i32 = initialize_from %.loc7_29 to %.loc7_45.14 +// CHECK:STDOUT: %.loc7_45.16: i32 = int_literal 4 +// CHECK:STDOUT: %.loc7_45.17: ref i32 = array_index %a, %.loc7_45.16 +// CHECK:STDOUT: %.loc7_45.18: init i32 = initialize_from %.loc7_32 to %.loc7_45.17 +// CHECK:STDOUT: %.loc7_45.19: i32 = int_literal 5 +// CHECK:STDOUT: %.loc7_45.20: ref i32 = array_index %a, %.loc7_45.19 +// CHECK:STDOUT: %.loc7_45.21: init i32 = initialize_from %.loc7_35 to %.loc7_45.20 +// CHECK:STDOUT: %.loc7_45.22: i32 = int_literal 6 +// CHECK:STDOUT: %.loc7_45.23: ref i32 = array_index %a, %.loc7_45.22 +// CHECK:STDOUT: %.loc7_45.24: init i32 = initialize_from %.loc7_38 to %.loc7_45.23 +// CHECK:STDOUT: %.loc7_45.25: i32 = int_literal 7 +// CHECK:STDOUT: %.loc7_45.26: ref i32 = array_index %a, %.loc7_45.25 +// CHECK:STDOUT: %.loc7_45.27: init i32 = initialize_from %.loc7_41 to %.loc7_45.26 +// CHECK:STDOUT: %.loc7_45.28: i32 = int_literal 8 +// CHECK:STDOUT: %.loc7_45.29: ref i32 = array_index %a, %.loc7_45.28 +// CHECK:STDOUT: %.loc7_45.30: init i32 = initialize_from %.loc7_44 to %.loc7_45.29 +// CHECK:STDOUT: %.loc7_45.31: init [i32; 9] = array_init %.loc7_45.3, (%.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 %a +// CHECK:STDOUT: assign %a, %.loc7_45.31 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/basics/builtin_types.carbon b/toolchain/check/testdata/basics/builtin_types.carbon index cf5496b47c93..9ec71e92f0fe 100644 --- a/toolchain/check/testdata/basics/builtin_types.carbon +++ b/toolchain/check/testdata/basics/builtin_types.carbon @@ -16,6 +16,7 @@ var test_type: type = i32; // CHECK:STDOUT: %test_f64: ref f64 = var "test_f64" // CHECK:STDOUT: %.loc8: f64 = real_literal 1e-1 // CHECK:STDOUT: assign %test_f64, %.loc8 +// CHECK:STDOUT: %.1: type = ptr_type String // CHECK:STDOUT: %test_str: ref String = var "test_str" // CHECK:STDOUT: %.loc9: String = string_literal "Test" // CHECK:STDOUT: assign %test_str, %.loc9 diff --git a/toolchain/check/testdata/basics/multifile_raw_and_textual_ir.carbon b/toolchain/check/testdata/basics/multifile_raw_and_textual_ir.carbon index ae2acb188164..bbe6c6756c0f 100644 --- a/toolchain/check/testdata/basics/multifile_raw_and_textual_ir.carbon +++ b/toolchain/check/testdata/basics/multifile_raw_and_textual_ir.carbon @@ -30,7 +30,7 @@ fn B() {} // CHECK:STDOUT: A, // CHECK:STDOUT: ] // CHECK:STDOUT: types: [ -// CHECK:STDOUT: nodeFunctionType, +// CHECK:STDOUT: {node: nodeFunctionType, value_rep: {kind: copy, type: type0}}, // CHECK:STDOUT: ] // CHECK:STDOUT: type_blocks: [ // CHECK:STDOUT: ] @@ -73,7 +73,7 @@ fn B() {} // CHECK:STDOUT: B, // CHECK:STDOUT: ] // CHECK:STDOUT: types: [ -// CHECK:STDOUT: nodeFunctionType, +// CHECK:STDOUT: {node: nodeFunctionType, value_rep: {kind: copy, type: type0}}, // CHECK:STDOUT: ] // CHECK:STDOUT: type_blocks: [ // CHECK:STDOUT: ] diff --git a/toolchain/check/testdata/basics/multifile_raw_ir.carbon b/toolchain/check/testdata/basics/multifile_raw_ir.carbon index afaaf0788130..8fa0e785ef25 100644 --- a/toolchain/check/testdata/basics/multifile_raw_ir.carbon +++ b/toolchain/check/testdata/basics/multifile_raw_ir.carbon @@ -30,7 +30,7 @@ fn B() {} // CHECK:STDOUT: A, // CHECK:STDOUT: ] // CHECK:STDOUT: types: [ -// CHECK:STDOUT: nodeFunctionType, +// CHECK:STDOUT: {node: nodeFunctionType, value_rep: {kind: copy, type: type0}}, // CHECK:STDOUT: ] // CHECK:STDOUT: type_blocks: [ // CHECK:STDOUT: ] @@ -64,7 +64,7 @@ fn B() {} // CHECK:STDOUT: B, // CHECK:STDOUT: ] // CHECK:STDOUT: types: [ -// CHECK:STDOUT: nodeFunctionType, +// CHECK:STDOUT: {node: nodeFunctionType, value_rep: {kind: copy, type: type0}}, // CHECK:STDOUT: ] // CHECK:STDOUT: type_blocks: [ // CHECK:STDOUT: ] diff --git a/toolchain/check/testdata/basics/numeric_literals.carbon b/toolchain/check/testdata/basics/numeric_literals.carbon index c20c4eb84e77..2bd90e385749 100644 --- a/toolchain/check/testdata/basics/numeric_literals.carbon +++ b/toolchain/check/testdata/basics/numeric_literals.carbon @@ -32,7 +32,8 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc10_19: i32 = int_literal 5 -// CHECK:STDOUT: %.loc10_20: type = array_type %.loc10_19, i32 +// CHECK:STDOUT: %.loc10_20.1: type = array_type %.loc10_19, i32 +// CHECK:STDOUT: %.loc10_20.2: type = ptr_type [i32; 5] // CHECK:STDOUT: %ints: ref [i32; 5] = var "ints" // CHECK:STDOUT: %.loc11: i32 = int_literal 8 // CHECK:STDOUT: %.loc12: i32 = int_literal 9 @@ -40,26 +41,28 @@ fn F() { // CHECK:STDOUT: %.loc14: i32 = int_literal 8 // CHECK:STDOUT: %.loc15: i32 = int_literal 39999999999999999993 // 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, %.loc12, %.loc13, %.loc14, %.loc15) -// CHECK:STDOUT: %.loc16_3.3: i32 = int_literal 0 -// CHECK:STDOUT: %.loc16_3.4: ref i32 = array_index %ints, %.loc16_3.3 -// CHECK:STDOUT: %.loc16_3.5: init i32 = initialize_from %.loc11 to %.loc16_3.4 -// CHECK:STDOUT: %.loc16_3.6: i32 = int_literal 1 -// CHECK:STDOUT: %.loc16_3.7: ref i32 = array_index %ints, %.loc16_3.6 -// CHECK:STDOUT: %.loc16_3.8: init i32 = initialize_from %.loc12 to %.loc16_3.7 -// CHECK:STDOUT: %.loc16_3.9: i32 = int_literal 2 -// CHECK:STDOUT: %.loc16_3.10: ref i32 = array_index %ints, %.loc16_3.9 -// CHECK:STDOUT: %.loc16_3.11: init i32 = initialize_from %.loc13 to %.loc16_3.10 -// CHECK:STDOUT: %.loc16_3.12: i32 = int_literal 3 -// CHECK:STDOUT: %.loc16_3.13: ref i32 = array_index %ints, %.loc16_3.12 -// CHECK:STDOUT: %.loc16_3.14: init i32 = initialize_from %.loc14 to %.loc16_3.13 -// CHECK:STDOUT: %.loc16_3.15: i32 = int_literal 4 -// CHECK:STDOUT: %.loc16_3.16: ref i32 = array_index %ints, %.loc16_3.15 -// CHECK:STDOUT: %.loc16_3.17: init i32 = initialize_from %.loc15 to %.loc16_3.16 -// CHECK:STDOUT: %.loc16_3.18: init [i32; 5] = array_init %.loc16_3.2, (%.loc16_3.5, %.loc16_3.8, %.loc16_3.11, %.loc16_3.14, %.loc16_3.17) to %ints -// CHECK:STDOUT: assign %ints, %.loc16_3.18 +// CHECK:STDOUT: %.loc16_3.2: type = ptr_type (i32, i32, i32, i32, i32) +// CHECK:STDOUT: %.loc16_3.3: (i32, i32, i32, i32, i32) = tuple_literal (%.loc11, %.loc12, %.loc13, %.loc14, %.loc15) +// CHECK:STDOUT: %.loc16_3.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc16_3.5: ref i32 = array_index %ints, %.loc16_3.4 +// CHECK:STDOUT: %.loc16_3.6: init i32 = initialize_from %.loc11 to %.loc16_3.5 +// CHECK:STDOUT: %.loc16_3.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc16_3.8: ref i32 = array_index %ints, %.loc16_3.7 +// CHECK:STDOUT: %.loc16_3.9: init i32 = initialize_from %.loc12 to %.loc16_3.8 +// CHECK:STDOUT: %.loc16_3.10: i32 = int_literal 2 +// CHECK:STDOUT: %.loc16_3.11: ref i32 = array_index %ints, %.loc16_3.10 +// CHECK:STDOUT: %.loc16_3.12: init i32 = initialize_from %.loc13 to %.loc16_3.11 +// CHECK:STDOUT: %.loc16_3.13: i32 = int_literal 3 +// CHECK:STDOUT: %.loc16_3.14: ref i32 = array_index %ints, %.loc16_3.13 +// CHECK:STDOUT: %.loc16_3.15: init i32 = initialize_from %.loc14 to %.loc16_3.14 +// CHECK:STDOUT: %.loc16_3.16: i32 = int_literal 4 +// CHECK:STDOUT: %.loc16_3.17: ref i32 = array_index %ints, %.loc16_3.16 +// CHECK:STDOUT: %.loc16_3.18: init i32 = initialize_from %.loc15 to %.loc16_3.17 +// CHECK:STDOUT: %.loc16_3.19: init [i32; 5] = array_init %.loc16_3.3, (%.loc16_3.6, %.loc16_3.9, %.loc16_3.12, %.loc16_3.15, %.loc16_3.18) to %ints +// 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: %.loc17_22.1: type = array_type %.loc17_21, f64 +// CHECK:STDOUT: %.loc17_22.2: type = ptr_type [f64; 7] // CHECK:STDOUT: %floats: ref [f64; 7] = var "floats" // CHECK:STDOUT: %.loc18: f64 = real_literal 9e-1 // CHECK:STDOUT: %.loc19: f64 = real_literal 80e-1 @@ -69,29 +72,30 @@ fn F() { // CHECK:STDOUT: %.loc23: f64 = real_literal 10e-9 // CHECK:STDOUT: %.loc24: f64 = real_literal 399999999999999999930e39999999999999999992 // 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, %.loc19, %.loc20, %.loc21, %.loc22, %.loc23, %.loc24) -// CHECK:STDOUT: %.loc25_3.3: i32 = int_literal 0 -// CHECK:STDOUT: %.loc25_3.4: ref f64 = array_index %floats, %.loc25_3.3 -// CHECK:STDOUT: %.loc25_3.5: init f64 = initialize_from %.loc18 to %.loc25_3.4 -// CHECK:STDOUT: %.loc25_3.6: i32 = int_literal 1 -// CHECK:STDOUT: %.loc25_3.7: ref f64 = array_index %floats, %.loc25_3.6 -// CHECK:STDOUT: %.loc25_3.8: init f64 = initialize_from %.loc19 to %.loc25_3.7 -// CHECK:STDOUT: %.loc25_3.9: i32 = int_literal 2 -// CHECK:STDOUT: %.loc25_3.10: ref f64 = array_index %floats, %.loc25_3.9 -// CHECK:STDOUT: %.loc25_3.11: init f64 = initialize_from %.loc20 to %.loc25_3.10 -// CHECK:STDOUT: %.loc25_3.12: i32 = int_literal 3 -// CHECK:STDOUT: %.loc25_3.13: ref f64 = array_index %floats, %.loc25_3.12 -// CHECK:STDOUT: %.loc25_3.14: init f64 = initialize_from %.loc21 to %.loc25_3.13 -// CHECK:STDOUT: %.loc25_3.15: i32 = int_literal 4 -// CHECK:STDOUT: %.loc25_3.16: ref f64 = array_index %floats, %.loc25_3.15 -// CHECK:STDOUT: %.loc25_3.17: init f64 = initialize_from %.loc22 to %.loc25_3.16 -// CHECK:STDOUT: %.loc25_3.18: i32 = int_literal 5 -// CHECK:STDOUT: %.loc25_3.19: ref f64 = array_index %floats, %.loc25_3.18 -// CHECK:STDOUT: %.loc25_3.20: init f64 = initialize_from %.loc23 to %.loc25_3.19 -// CHECK:STDOUT: %.loc25_3.21: i32 = int_literal 6 -// CHECK:STDOUT: %.loc25_3.22: ref f64 = array_index %floats, %.loc25_3.21 -// CHECK:STDOUT: %.loc25_3.23: init f64 = initialize_from %.loc24 to %.loc25_3.22 -// CHECK:STDOUT: %.loc25_3.24: init [f64; 7] = array_init %.loc25_3.2, (%.loc25_3.5, %.loc25_3.8, %.loc25_3.11, %.loc25_3.14, %.loc25_3.17, %.loc25_3.20, %.loc25_3.23) to %floats -// CHECK:STDOUT: assign %floats, %.loc25_3.24 +// CHECK:STDOUT: %.loc25_3.2: type = ptr_type (f64, f64, f64, f64, f64, f64, f64) +// CHECK:STDOUT: %.loc25_3.3: (f64, f64, f64, f64, f64, f64, f64) = tuple_literal (%.loc18, %.loc19, %.loc20, %.loc21, %.loc22, %.loc23, %.loc24) +// CHECK:STDOUT: %.loc25_3.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc25_3.5: ref f64 = array_index %floats, %.loc25_3.4 +// CHECK:STDOUT: %.loc25_3.6: init f64 = initialize_from %.loc18 to %.loc25_3.5 +// CHECK:STDOUT: %.loc25_3.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc25_3.8: ref f64 = array_index %floats, %.loc25_3.7 +// CHECK:STDOUT: %.loc25_3.9: init f64 = initialize_from %.loc19 to %.loc25_3.8 +// CHECK:STDOUT: %.loc25_3.10: i32 = int_literal 2 +// CHECK:STDOUT: %.loc25_3.11: ref f64 = array_index %floats, %.loc25_3.10 +// CHECK:STDOUT: %.loc25_3.12: init f64 = initialize_from %.loc20 to %.loc25_3.11 +// CHECK:STDOUT: %.loc25_3.13: i32 = int_literal 3 +// CHECK:STDOUT: %.loc25_3.14: ref f64 = array_index %floats, %.loc25_3.13 +// CHECK:STDOUT: %.loc25_3.15: init f64 = initialize_from %.loc21 to %.loc25_3.14 +// CHECK:STDOUT: %.loc25_3.16: i32 = int_literal 4 +// CHECK:STDOUT: %.loc25_3.17: ref f64 = array_index %floats, %.loc25_3.16 +// CHECK:STDOUT: %.loc25_3.18: init f64 = initialize_from %.loc22 to %.loc25_3.17 +// CHECK:STDOUT: %.loc25_3.19: i32 = int_literal 5 +// CHECK:STDOUT: %.loc25_3.20: ref f64 = array_index %floats, %.loc25_3.19 +// CHECK:STDOUT: %.loc25_3.21: init f64 = initialize_from %.loc23 to %.loc25_3.20 +// CHECK:STDOUT: %.loc25_3.22: i32 = int_literal 6 +// CHECK:STDOUT: %.loc25_3.23: ref f64 = array_index %floats, %.loc25_3.22 +// CHECK:STDOUT: %.loc25_3.24: init f64 = initialize_from %.loc24 to %.loc25_3.23 +// CHECK:STDOUT: %.loc25_3.25: init [f64; 7] = array_init %.loc25_3.3, (%.loc25_3.6, %.loc25_3.9, %.loc25_3.12, %.loc25_3.15, %.loc25_3.18, %.loc25_3.21, %.loc25_3.24) to %floats +// CHECK:STDOUT: assign %floats, %.loc25_3.25 // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/basics/raw_and_textual_ir.carbon b/toolchain/check/testdata/basics/raw_and_textual_ir.carbon index 1ca55903e988..3ea7b5f1e16b 100644 --- a/toolchain/check/testdata/basics/raw_and_textual_ir.carbon +++ b/toolchain/check/testdata/basics/raw_and_textual_ir.carbon @@ -16,7 +16,7 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: sem_ir: // CHECK:STDOUT: - cross_reference_irs_size: 1 // CHECK:STDOUT: functions: [ -// CHECK:STDOUT: {name: str0, param_refs: block1, return_type: type3, return_slot: node+4, body: [block4]}, +// CHECK:STDOUT: {name: str0, param_refs: block1, return_type: type4, return_slot: node+6, body: [block4]}, // CHECK:STDOUT: ] // CHECK:STDOUT: classes: [ // CHECK:STDOUT: ] @@ -32,11 +32,13 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: return, // CHECK:STDOUT: ] // CHECK:STDOUT: types: [ -// CHECK:STDOUT: nodeIntegerType, -// CHECK:STDOUT: node+1, -// CHECK:STDOUT: nodeFloatingPointType, -// CHECK:STDOUT: node+3, -// CHECK:STDOUT: nodeFunctionType, +// CHECK:STDOUT: {node: nodeIntegerType, value_rep: {kind: copy, type: type0}}, +// CHECK:STDOUT: {node: node+1, value_rep: {kind: pointer, type: type2}}, +// CHECK:STDOUT: {node: node+2, value_rep: {kind: copy, type: type2}}, +// CHECK:STDOUT: {node: nodeFloatingPointType, value_rep: {kind: copy, type: type3}}, +// CHECK:STDOUT: {node: node+4, value_rep: {kind: pointer, type: type5}}, +// CHECK:STDOUT: {node: node+5, value_rep: {kind: copy, type: type5}}, +// CHECK:STDOUT: {node: nodeFunctionType, value_rep: {kind: copy, type: type6}}, // CHECK:STDOUT: ] // CHECK:STDOUT: type_blocks: [ // CHECK:STDOUT: [ @@ -45,27 +47,29 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: type0, -// CHECK:STDOUT: type2, +// CHECK:STDOUT: type3, // CHECK:STDOUT: ], // CHECK:STDOUT: ] // CHECK:STDOUT: nodes: [ // CHECK:STDOUT: {kind: Parameter, arg0: str1, type: type0}, // CHECK:STDOUT: {kind: TupleType, arg0: typeBlock0, type: typeTypeType}, +// CHECK:STDOUT: {kind: PointerType, arg0: type1, type: typeTypeType}, // CHECK:STDOUT: {kind: TupleLiteral, arg0: block2, type: type1}, // CHECK:STDOUT: {kind: TupleType, arg0: typeBlock1, type: typeTypeType}, -// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type3}, -// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0, type: type4}, +// CHECK:STDOUT: {kind: PointerType, arg0: type4, type: typeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type4}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0, type: type6}, // CHECK:STDOUT: {kind: NameReference, arg0: str1, arg1: node+0, type: type0}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0}, -// CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+6, arg1: node+7, type: type0}, -// CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: type2}, -// CHECK:STDOUT: {kind: TupleLiteral, arg0: block5, type: type3}, -// CHECK:STDOUT: {kind: TupleAccess, arg0: node+4, arg1: member0, type: type0}, -// CHECK:STDOUT: {kind: InitializeFrom, arg0: node+8, arg1: node+11, type: type0}, -// CHECK:STDOUT: {kind: TupleAccess, arg0: node+4, arg1: member1, type: type2}, -// CHECK:STDOUT: {kind: InitializeFrom, arg0: node+9, arg1: node+13, type: type2}, -// CHECK:STDOUT: {kind: TupleInit, arg0: node+10, arg1: block6, type: type3}, -// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+15}, +// CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+8, arg1: node+9, type: type0}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: type3}, +// CHECK:STDOUT: {kind: TupleLiteral, arg0: block5, type: type4}, +// CHECK:STDOUT: {kind: TupleAccess, arg0: node+6, arg1: member0, type: type0}, +// CHECK:STDOUT: {kind: InitializeFrom, arg0: node+10, arg1: node+13, type: type0}, +// CHECK:STDOUT: {kind: TupleAccess, arg0: node+6, arg1: member1, type: type3}, +// CHECK:STDOUT: {kind: InitializeFrom, arg0: node+11, arg1: node+15, type: type3}, +// CHECK:STDOUT: {kind: TupleInit, arg0: node+12, arg1: block6, type: type4}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+17}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ // CHECK:STDOUT: [ @@ -83,10 +87,10 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: node+2, // CHECK:STDOUT: node+3, // CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+6, -// CHECK:STDOUT: node+7, // CHECK:STDOUT: node+8, // CHECK:STDOUT: node+9, // CHECK:STDOUT: node+10, @@ -96,17 +100,19 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: node+14, // CHECK:STDOUT: node+15, // CHECK:STDOUT: node+16, +// CHECK:STDOUT: node+17, +// CHECK:STDOUT: node+18, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+8, -// CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: node+11, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+12, // CHECK:STDOUT: node+14, +// CHECK:STDOUT: node+16, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+7, // CHECK:STDOUT: ], // CHECK:STDOUT: ] // CHECK:STDOUT: diff --git a/toolchain/check/testdata/basics/raw_ir.carbon b/toolchain/check/testdata/basics/raw_ir.carbon index aecf8ec13a0c..b0a2ef371f7c 100644 --- a/toolchain/check/testdata/basics/raw_ir.carbon +++ b/toolchain/check/testdata/basics/raw_ir.carbon @@ -16,7 +16,7 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: sem_ir: // CHECK:STDOUT: - cross_reference_irs_size: 1 // CHECK:STDOUT: functions: [ -// CHECK:STDOUT: {name: str0, param_refs: block1, return_type: type3, return_slot: node+4, body: [block4]}, +// CHECK:STDOUT: {name: str0, param_refs: block1, return_type: type4, return_slot: node+6, body: [block4]}, // CHECK:STDOUT: ] // CHECK:STDOUT: classes: [ // CHECK:STDOUT: ] @@ -32,11 +32,13 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: return, // CHECK:STDOUT: ] // CHECK:STDOUT: types: [ -// CHECK:STDOUT: nodeIntegerType, -// CHECK:STDOUT: node+1, -// CHECK:STDOUT: nodeFloatingPointType, -// CHECK:STDOUT: node+3, -// CHECK:STDOUT: nodeFunctionType, +// CHECK:STDOUT: {node: nodeIntegerType, value_rep: {kind: copy, type: type0}}, +// CHECK:STDOUT: {node: node+1, value_rep: {kind: pointer, type: type2}}, +// CHECK:STDOUT: {node: node+2, value_rep: {kind: copy, type: type2}}, +// CHECK:STDOUT: {node: nodeFloatingPointType, value_rep: {kind: copy, type: type3}}, +// CHECK:STDOUT: {node: node+4, value_rep: {kind: pointer, type: type5}}, +// CHECK:STDOUT: {node: node+5, value_rep: {kind: copy, type: type5}}, +// CHECK:STDOUT: {node: nodeFunctionType, value_rep: {kind: copy, type: type6}}, // CHECK:STDOUT: ] // CHECK:STDOUT: type_blocks: [ // CHECK:STDOUT: [ @@ -45,27 +47,29 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: type0, -// CHECK:STDOUT: type2, +// CHECK:STDOUT: type3, // CHECK:STDOUT: ], // CHECK:STDOUT: ] // CHECK:STDOUT: nodes: [ // CHECK:STDOUT: {kind: Parameter, arg0: str1, type: type0}, // CHECK:STDOUT: {kind: TupleType, arg0: typeBlock0, type: typeTypeType}, +// CHECK:STDOUT: {kind: PointerType, arg0: type1, type: typeTypeType}, // CHECK:STDOUT: {kind: TupleLiteral, arg0: block2, type: type1}, // CHECK:STDOUT: {kind: TupleType, arg0: typeBlock1, type: typeTypeType}, -// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type3}, -// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0, type: type4}, +// CHECK:STDOUT: {kind: PointerType, arg0: type4, type: typeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type4}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0, type: type6}, // CHECK:STDOUT: {kind: NameReference, arg0: str1, arg1: node+0, type: type0}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0}, -// CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+6, arg1: node+7, type: type0}, -// CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: type2}, -// CHECK:STDOUT: {kind: TupleLiteral, arg0: block5, type: type3}, -// CHECK:STDOUT: {kind: TupleAccess, arg0: node+4, arg1: member0, type: type0}, -// CHECK:STDOUT: {kind: InitializeFrom, arg0: node+8, arg1: node+11, type: type0}, -// CHECK:STDOUT: {kind: TupleAccess, arg0: node+4, arg1: member1, type: type2}, -// CHECK:STDOUT: {kind: InitializeFrom, arg0: node+9, arg1: node+13, type: type2}, -// CHECK:STDOUT: {kind: TupleInit, arg0: node+10, arg1: block6, type: type3}, -// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+15}, +// CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+8, arg1: node+9, type: type0}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: type3}, +// CHECK:STDOUT: {kind: TupleLiteral, arg0: block5, type: type4}, +// CHECK:STDOUT: {kind: TupleAccess, arg0: node+6, arg1: member0, type: type0}, +// CHECK:STDOUT: {kind: InitializeFrom, arg0: node+10, arg1: node+13, type: type0}, +// CHECK:STDOUT: {kind: TupleAccess, arg0: node+6, arg1: member1, type: type3}, +// CHECK:STDOUT: {kind: InitializeFrom, arg0: node+11, arg1: node+15, type: type3}, +// CHECK:STDOUT: {kind: TupleInit, arg0: node+12, arg1: block6, type: type4}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+17}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ // CHECK:STDOUT: [ @@ -83,10 +87,10 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: node+2, // CHECK:STDOUT: node+3, // CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+6, -// CHECK:STDOUT: node+7, // CHECK:STDOUT: node+8, // CHECK:STDOUT: node+9, // CHECK:STDOUT: node+10, @@ -96,16 +100,18 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: node+14, // CHECK:STDOUT: node+15, // CHECK:STDOUT: node+16, +// CHECK:STDOUT: node+17, +// CHECK:STDOUT: node+18, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+8, -// CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: node+11, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+12, // CHECK:STDOUT: node+14, +// CHECK:STDOUT: node+16, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+7, // CHECK:STDOUT: ], // CHECK:STDOUT: ] diff --git a/toolchain/check/testdata/function/call/fail_not_callable.carbon b/toolchain/check/testdata/function/call/fail_not_callable.carbon index 7c40c9c10220..ab4ee32c733d 100644 --- a/toolchain/check/testdata/function/call/fail_not_callable.carbon +++ b/toolchain/check/testdata/function/call/fail_not_callable.carbon @@ -21,6 +21,7 @@ fn Run() { // CHECK:STDOUT: fn @Run() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %x: ref i32 = var "x" +// CHECK:STDOUT: %.1: type = ptr_type String // CHECK:STDOUT: %.loc14: String = string_literal "hello" // CHECK:STDOUT: assign %x, // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/index/array_element_access.carbon b/toolchain/check/testdata/index/array_element_access.carbon index a4c6e08a2ede..d37996d573cb 100644 --- a/toolchain/check/testdata/index/array_element_access.carbon +++ b/toolchain/check/testdata/index/array_element_access.carbon @@ -11,20 +11,22 @@ var d: i32 = a[b]; // CHECK:STDOUT: file "array_element_access.carbon" { // CHECK:STDOUT: %.loc7_14: i32 = int_literal 2 -// CHECK:STDOUT: %.loc7_15: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.1: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.2: type = ptr_type [i32; 2] // CHECK:STDOUT: %a: ref [i32; 2] = var "a" // CHECK:STDOUT: %.loc7_20: i32 = int_literal 12 // CHECK:STDOUT: %.loc7_24: i32 = int_literal 24 // CHECK:STDOUT: %.loc7_26.1: type = tuple_type (i32, i32) -// CHECK:STDOUT: %.loc7_26.2: (i32, i32) = tuple_literal (%.loc7_20, %.loc7_24) -// CHECK:STDOUT: %.loc7_26.3: i32 = int_literal 0 -// CHECK:STDOUT: %.loc7_26.4: ref i32 = array_index %a, %.loc7_26.3 -// CHECK:STDOUT: %.loc7_26.5: init i32 = initialize_from %.loc7_20 to %.loc7_26.4 -// CHECK:STDOUT: %.loc7_26.6: i32 = int_literal 1 -// CHECK:STDOUT: %.loc7_26.7: ref i32 = array_index %a, %.loc7_26.6 -// CHECK:STDOUT: %.loc7_26.8: init i32 = initialize_from %.loc7_24 to %.loc7_26.7 -// CHECK:STDOUT: %.loc7_26.9: init [i32; 2] = array_init %.loc7_26.2, (%.loc7_26.5, %.loc7_26.8) to %a -// CHECK:STDOUT: assign %a, %.loc7_26.9 +// CHECK:STDOUT: %.loc7_26.2: type = ptr_type (i32, i32) +// CHECK:STDOUT: %.loc7_26.3: (i32, i32) = tuple_literal (%.loc7_20, %.loc7_24) +// CHECK:STDOUT: %.loc7_26.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc7_26.5: ref i32 = array_index %a, %.loc7_26.4 +// CHECK:STDOUT: %.loc7_26.6: init i32 = initialize_from %.loc7_20 to %.loc7_26.5 +// CHECK:STDOUT: %.loc7_26.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc7_26.8: ref i32 = array_index %a, %.loc7_26.7 +// CHECK:STDOUT: %.loc7_26.9: init i32 = initialize_from %.loc7_24 to %.loc7_26.8 +// CHECK:STDOUT: %.loc7_26.10: init [i32; 2] = array_init %.loc7_26.3, (%.loc7_26.6, %.loc7_26.9) to %a +// CHECK:STDOUT: assign %a, %.loc7_26.10 // CHECK:STDOUT: %b: ref i32 = var "b" // CHECK:STDOUT: %.loc8: i32 = int_literal 1 // CHECK:STDOUT: assign %b, %.loc8 diff --git a/toolchain/check/testdata/index/expression_category.carbon b/toolchain/check/testdata/index/expression_category.carbon index 1a47867e8912..8527dcc06dbb 100644 --- a/toolchain/check/testdata/index/expression_category.carbon +++ b/toolchain/check/testdata/index/expression_category.carbon @@ -41,18 +41,19 @@ fn ValueBinding(b: [i32; 3]) { // CHECK:STDOUT: %.loc10_25: i32 = int_literal 2 // CHECK:STDOUT: %.loc10_28: i32 = int_literal 3 // CHECK:STDOUT: %.loc10_29.1: type = tuple_type (i32, i32, i32) -// CHECK:STDOUT: %.loc10_29.2: (i32, i32, i32) = tuple_literal (%.loc10_22, %.loc10_25, %.loc10_28) -// CHECK:STDOUT: %.loc10_29.3: i32 = int_literal 0 -// CHECK:STDOUT: %.loc10_29.4: ref i32 = array_index %a, %.loc10_29.3 -// CHECK:STDOUT: %.loc10_29.5: init i32 = initialize_from %.loc10_22 to %.loc10_29.4 -// CHECK:STDOUT: %.loc10_29.6: i32 = int_literal 1 -// CHECK:STDOUT: %.loc10_29.7: ref i32 = array_index %a, %.loc10_29.6 -// CHECK:STDOUT: %.loc10_29.8: init i32 = initialize_from %.loc10_25 to %.loc10_29.7 -// CHECK:STDOUT: %.loc10_29.9: i32 = int_literal 2 -// CHECK:STDOUT: %.loc10_29.10: ref i32 = array_index %a, %.loc10_29.9 -// CHECK:STDOUT: %.loc10_29.11: init i32 = initialize_from %.loc10_28 to %.loc10_29.10 -// CHECK:STDOUT: %.loc10_29.12: init [i32; 3] = array_init %.loc10_29.2, (%.loc10_29.5, %.loc10_29.8, %.loc10_29.11) to %a -// CHECK:STDOUT: assign %a, %.loc10_29.12 +// CHECK:STDOUT: %.loc10_29.2: type = ptr_type (i32, i32, i32) +// CHECK:STDOUT: %.loc10_29.3: (i32, i32, i32) = tuple_literal (%.loc10_22, %.loc10_25, %.loc10_28) +// CHECK:STDOUT: %.loc10_29.4: i32 = int_literal 0 +// CHECK:STDOUT: %.loc10_29.5: ref i32 = array_index %a, %.loc10_29.4 +// CHECK:STDOUT: %.loc10_29.6: init i32 = initialize_from %.loc10_22 to %.loc10_29.5 +// CHECK:STDOUT: %.loc10_29.7: i32 = int_literal 1 +// CHECK:STDOUT: %.loc10_29.8: ref i32 = array_index %a, %.loc10_29.7 +// CHECK:STDOUT: %.loc10_29.9: init i32 = initialize_from %.loc10_25 to %.loc10_29.8 +// CHECK:STDOUT: %.loc10_29.10: i32 = int_literal 2 +// CHECK:STDOUT: %.loc10_29.11: ref i32 = array_index %a, %.loc10_29.10 +// CHECK:STDOUT: %.loc10_29.12: init i32 = initialize_from %.loc10_28 to %.loc10_29.11 +// CHECK:STDOUT: %.loc10_29.13: init [i32; 3] = array_init %.loc10_29.3, (%.loc10_29.6, %.loc10_29.9, %.loc10_29.12) to %a +// CHECK:STDOUT: assign %a, %.loc10_29.13 // CHECK:STDOUT: %.loc13_14: type = ptr_type i32 // CHECK:STDOUT: %pa: ref i32* = var "pa" // CHECK:STDOUT: %a.ref.loc13: ref [i32; 3] = name_reference "a", %a diff --git a/toolchain/check/testdata/index/fail_array_large_index.carbon b/toolchain/check/testdata/index/fail_array_large_index.carbon index 1b975e54956b..519ce15bd7c8 100644 --- a/toolchain/check/testdata/index/fail_array_large_index.carbon +++ b/toolchain/check/testdata/index/fail_array_large_index.carbon @@ -12,7 +12,8 @@ var b: i32 = a[0xFFFFFFFFFFFFFFFFF]; // CHECK:STDOUT: file "fail_array_large_index.carbon" { // CHECK:STDOUT: %.loc7_14: i32 = int_literal 1 -// CHECK:STDOUT: %.loc7_15: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.1: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.2: type = ptr_type [i32; 1] // CHECK:STDOUT: %a: ref [i32; 1] = var "a" // CHECK:STDOUT: %.loc7_20: i32 = int_literal 12 // CHECK:STDOUT: %.loc7_23.1: type = tuple_type (i32) 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 c74b4d79f48d..29d85bbfc654 100644 --- a/toolchain/check/testdata/index/fail_array_non_int_indexing.carbon +++ b/toolchain/check/testdata/index/fail_array_non_int_indexing.carbon @@ -12,7 +12,8 @@ var b: i32 = a[2.6]; // CHECK:STDOUT: file "fail_array_non_int_indexing.carbon" { // CHECK:STDOUT: %.loc7_14: i32 = int_literal 1 -// CHECK:STDOUT: %.loc7_15: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.1: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.2: type = ptr_type [i32; 1] // CHECK:STDOUT: %a: ref [i32; 1] = var "a" // CHECK:STDOUT: %.loc7_20: i32 = int_literal 12 // CHECK:STDOUT: %.loc7_23.1: type = tuple_type (i32) 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 fd0af5a9df71..a9b3db0a456a 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 @@ -12,7 +12,8 @@ var b: i32 = a[2]; // CHECK:STDOUT: file "fail_array_out_of_bound_access.carbon" { // CHECK:STDOUT: %.loc7_14: i32 = int_literal 1 -// CHECK:STDOUT: %.loc7_15: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.1: type = array_type %.loc7_14, i32 +// CHECK:STDOUT: %.loc7_15.2: type = ptr_type [i32; 1] // CHECK:STDOUT: %a: ref [i32; 1] = var "a" // CHECK:STDOUT: %.loc7_20: i32 = int_literal 12 // CHECK:STDOUT: %.loc7_23.1: type = tuple_type (i32) diff --git a/toolchain/check/testdata/index/fail_invalid_base.carbon b/toolchain/check/testdata/index/fail_invalid_base.carbon index 461458d1e003..b530f6543ec8 100644 --- a/toolchain/check/testdata/index/fail_invalid_base.carbon +++ b/toolchain/check/testdata/index/fail_invalid_base.carbon @@ -45,9 +45,10 @@ var d: i32 = {.a: i32, .b: i32}[0]; // CHECK:STDOUT: %.loc26_20: i32 = int_literal 1 // CHECK:STDOUT: %.loc26_28: i32 = int_literal 2 // CHECK:STDOUT: %.loc26_29.1: type = struct_type {.a: i32, .b: i32} -// CHECK:STDOUT: %.loc26_29.2: {.a: i32, .b: i32} = struct_literal (%.loc26_20, %.loc26_28) +// CHECK:STDOUT: %.loc26_29.2: type = ptr_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc26_29.3: {.a: i32, .b: i32} = struct_literal (%.loc26_20, %.loc26_28) // CHECK:STDOUT: %.loc26_31: i32 = int_literal 0 -// CHECK:STDOUT: %.loc26_29.3: {.a: i32, .b: i32} = struct_value %.loc26_29.2, (%.loc26_20, %.loc26_28) +// CHECK:STDOUT: %.loc26_29.4: {.a: i32, .b: i32} = struct_value %.loc26_29.3, (%.loc26_20, %.loc26_28) // CHECK:STDOUT: assign %c, // CHECK:STDOUT: %d: ref i32 = var "d" // CHECK:STDOUT: %.loc31_31: type = struct_type {.a: i32, .b: i32} diff --git a/toolchain/check/testdata/index/fail_non_deterministic_type.carbon b/toolchain/check/testdata/index/fail_non_deterministic_type.carbon index b1ca51f3040c..78dd1bbc4014 100644 --- a/toolchain/check/testdata/index/fail_non_deterministic_type.carbon +++ b/toolchain/check/testdata/index/fail_non_deterministic_type.carbon @@ -13,8 +13,10 @@ var c: i32 = a[b]; // CHECK:STDOUT: file "fail_non_deterministic_type.carbon" { // CHECK:STDOUT: %.loc7_17.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc7_17.2: (type, type) = tuple_literal (i32, i32) -// CHECK:STDOUT: %.loc7_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc7_17.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.4: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.5: type = ptr_type (i32, i32) // CHECK:STDOUT: %a: ref (i32, i32) = var "a" // CHECK:STDOUT: %.loc7_22: i32 = int_literal 2 // CHECK:STDOUT: %.loc7_25: i32 = int_literal 3 diff --git a/toolchain/check/testdata/index/fail_tuple_index_error.carbon b/toolchain/check/testdata/index/fail_tuple_index_error.carbon index 54e3cb20b84b..b07ff69582a6 100644 --- a/toolchain/check/testdata/index/fail_tuple_index_error.carbon +++ b/toolchain/check/testdata/index/fail_tuple_index_error.carbon @@ -12,8 +12,10 @@ var b: i32 = a[oops]; // CHECK:STDOUT: file "fail_tuple_index_error.carbon" { // CHECK:STDOUT: %.loc7_17.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc7_17.2: (type, type) = tuple_literal (i32, i32) -// CHECK:STDOUT: %.loc7_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc7_17.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.4: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.5: type = ptr_type (i32, i32) // CHECK:STDOUT: %a: ref (i32, i32) = var "a" // CHECK:STDOUT: %.loc7_22: i32 = int_literal 12 // CHECK:STDOUT: %.loc7_26: i32 = int_literal 6 diff --git a/toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon b/toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon index 4241cffed3b1..8548c3cc46af 100644 --- a/toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon +++ b/toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon @@ -12,8 +12,10 @@ var b: i32 = a[2.6]; // CHECK:STDOUT: file "fail_tuple_non_int_indexing.carbon" { // CHECK:STDOUT: %.loc7_17.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc7_17.2: (type, type) = tuple_literal (i32, i32) -// CHECK:STDOUT: %.loc7_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc7_17.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.4: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.5: type = ptr_type (i32, i32) // CHECK:STDOUT: %a: ref (i32, i32) = var "a" // CHECK:STDOUT: %.loc7_22: i32 = int_literal 12 // CHECK:STDOUT: %.loc7_26: i32 = int_literal 6 diff --git a/toolchain/check/testdata/index/fail_tuple_out_of_bound_access.carbon b/toolchain/check/testdata/index/fail_tuple_out_of_bound_access.carbon index 8e106fd160bc..42cc31300bae 100644 --- a/toolchain/check/testdata/index/fail_tuple_out_of_bound_access.carbon +++ b/toolchain/check/testdata/index/fail_tuple_out_of_bound_access.carbon @@ -12,8 +12,10 @@ var b: i32 = a[2]; // CHECK:STDOUT: file "fail_tuple_out_of_bound_access.carbon" { // CHECK:STDOUT: %.loc7_17.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc7_17.2: (type, type) = tuple_literal (i32, i32) -// CHECK:STDOUT: %.loc7_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc7_17.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.4: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.5: type = ptr_type (i32, i32) // CHECK:STDOUT: %a: ref (i32, i32) = var "a" // CHECK:STDOUT: %.loc7_22: i32 = int_literal 12 // CHECK:STDOUT: %.loc7_26: i32 = int_literal 6 diff --git a/toolchain/check/testdata/let/convert.carbon b/toolchain/check/testdata/let/convert.carbon index be8d408a89aa..75c60c60ff07 100644 --- a/toolchain/check/testdata/let/convert.carbon +++ b/toolchain/check/testdata/let/convert.carbon @@ -18,8 +18,10 @@ fn F() -> i32 { // CHECK:STDOUT: fn @F() -> i32 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc8_24.1: type = tuple_type (type, type, type) -// CHECK:STDOUT: %.loc8_24.2: (type, type, type) = tuple_literal (i32, i32, i32) -// CHECK:STDOUT: %.loc8_24.3: type = tuple_type (i32, i32, i32) +// CHECK:STDOUT: %.loc8_24.2: type = ptr_type (type, type, type) +// CHECK:STDOUT: %.loc8_24.3: (type, type, type) = tuple_literal (i32, i32, i32) +// CHECK:STDOUT: %.loc8_24.4: type = tuple_type (i32, i32, i32) +// CHECK:STDOUT: %.loc8_24.5: type = ptr_type (i32, i32, i32) // CHECK:STDOUT: %v: ref (i32, i32, i32) = var "v" // CHECK:STDOUT: %.loc8_29: i32 = int_literal 1 // CHECK:STDOUT: %.loc8_32: i32 = int_literal 2 diff --git a/toolchain/check/testdata/operators/assignment.carbon b/toolchain/check/testdata/operators/assignment.carbon index 60ac1f40f216..819571ddfcae 100644 --- a/toolchain/check/testdata/operators/assignment.carbon +++ b/toolchain/check/testdata/operators/assignment.carbon @@ -35,8 +35,10 @@ fn Main() { // CHECK:STDOUT: %.loc9: i32 = int_literal 9 // CHECK:STDOUT: assign %a.ref.loc9, %.loc9 // CHECK:STDOUT: %.loc11_19.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc11_19.2: (type, type) = tuple_literal (i32, i32) -// CHECK:STDOUT: %.loc11_19.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc11_19.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc11_19.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc11_19.4: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc11_19.5: type = ptr_type (i32, i32) // CHECK:STDOUT: %b: ref (i32, i32) = var "b" // CHECK:STDOUT: %.loc11_24: i32 = int_literal 1 // CHECK:STDOUT: %.loc11_27: i32 = int_literal 2 @@ -57,7 +59,8 @@ fn Main() { // CHECK:STDOUT: %.loc13_6: ref i32 = tuple_index %b.ref.loc13, %.loc13_5 // CHECK:STDOUT: %.loc13_10: i32 = int_literal 4 // CHECK:STDOUT: assign %.loc13_6, %.loc13_10 -// CHECK:STDOUT: %.loc15_27: type = struct_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc15_27.1: type = struct_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc15_27.2: type = ptr_type {.a: i32, .b: i32} // CHECK:STDOUT: %c: ref {.a: i32, .b: i32} = var "c" // CHECK:STDOUT: %.loc15_37: i32 = int_literal 1 // CHECK:STDOUT: %.loc15_45: i32 = int_literal 2 diff --git a/toolchain/check/testdata/operators/fail_assigment_to_non_assignable.carbon b/toolchain/check/testdata/operators/fail_assigment_to_non_assignable.carbon index b2f7edecee10..5acce19a42b2 100644 --- a/toolchain/check/testdata/operators/fail_assigment_to_non_assignable.carbon +++ b/toolchain/check/testdata/operators/fail_assigment_to_non_assignable.carbon @@ -64,17 +64,18 @@ fn Main() { // CHECK:STDOUT: %.loc21_4: i32 = int_literal 1 // CHECK:STDOUT: %.loc21_7: i32 = int_literal 2 // CHECK:STDOUT: %.loc21_8.1: type = tuple_type (i32, i32) -// CHECK:STDOUT: %.loc21_8.2: (i32, i32) = tuple_literal (%.loc21_4, %.loc21_7) +// CHECK:STDOUT: %.loc21_8.2: type = ptr_type (i32, i32) +// CHECK:STDOUT: %.loc21_8.3: (i32, i32) = tuple_literal (%.loc21_4, %.loc21_7) // CHECK:STDOUT: %.loc21_13: i32 = int_literal 3 // CHECK:STDOUT: %.loc21_16: i32 = int_literal 4 // CHECK:STDOUT: %.loc21_17.1: (i32, i32) = tuple_literal (%.loc21_13, %.loc21_16) -// CHECK:STDOUT: %.loc21_17.2: i32 = tuple_access %.loc21_8.2, member0 +// CHECK:STDOUT: %.loc21_17.2: i32 = tuple_access %.loc21_8.3, member0 // CHECK:STDOUT: %.loc21_17.3: init i32 = initialize_from %.loc21_13 to %.loc21_17.2 -// CHECK:STDOUT: %.loc21_17.4: i32 = tuple_access %.loc21_8.2, member1 +// CHECK:STDOUT: %.loc21_17.4: i32 = tuple_access %.loc21_8.3, member1 // CHECK:STDOUT: %.loc21_17.5: init i32 = initialize_from %.loc21_16 to %.loc21_17.4 // CHECK:STDOUT: %.loc21_17.6: init (i32, i32) = tuple_init %.loc21_17.1, (%.loc21_17.3, %.loc21_17.5) -// CHECK:STDOUT: assign %.loc21_8.2, %.loc21_17.6 -// CHECK:STDOUT: %.loc21_8.3: (i32, i32) = tuple_value %.loc21_8.2, (%.loc21_4, %.loc21_7) +// CHECK:STDOUT: assign %.loc21_8.3, %.loc21_17.6 +// CHECK:STDOUT: %.loc21_8.4: (i32, i32) = tuple_value %.loc21_8.3, (%.loc21_4, %.loc21_7) // CHECK:STDOUT: %n: ref i32 = var "n" // CHECK:STDOUT: %.loc22: i32 = int_literal 0 // CHECK:STDOUT: assign %n, %.loc22 @@ -98,17 +99,18 @@ fn Main() { // CHECK:STDOUT: %.loc34_9: i32 = int_literal 1 // CHECK:STDOUT: %.loc34_17: i32 = int_literal 2 // CHECK:STDOUT: %.loc34_18.1: type = struct_type {.x: i32, .y: i32} -// CHECK:STDOUT: %.loc34_18.2: {.x: i32, .y: i32} = struct_literal (%.loc34_9, %.loc34_17) +// CHECK:STDOUT: %.loc34_18.2: type = ptr_type {.x: i32, .y: i32} +// CHECK:STDOUT: %.loc34_18.3: {.x: i32, .y: i32} = struct_literal (%.loc34_9, %.loc34_17) // CHECK:STDOUT: %.loc34_28: i32 = int_literal 3 // CHECK:STDOUT: %.loc34_36: i32 = int_literal 4 // CHECK:STDOUT: %.loc34_37.1: {.x: i32, .y: i32} = struct_literal (%.loc34_28, %.loc34_36) -// CHECK:STDOUT: %.loc34_37.2: i32 = struct_access %.loc34_18.2, member0 +// CHECK:STDOUT: %.loc34_37.2: i32 = struct_access %.loc34_18.3, member0 // CHECK:STDOUT: %.loc34_37.3: init i32 = initialize_from %.loc34_28 to %.loc34_37.2 -// CHECK:STDOUT: %.loc34_37.4: i32 = struct_access %.loc34_18.2, member1 +// CHECK:STDOUT: %.loc34_37.4: i32 = struct_access %.loc34_18.3, member1 // CHECK:STDOUT: %.loc34_37.5: init i32 = initialize_from %.loc34_36 to %.loc34_37.4 // CHECK:STDOUT: %.loc34_37.6: init {.x: i32, .y: i32} = struct_init %.loc34_37.1, (%.loc34_37.3, %.loc34_37.5) -// CHECK:STDOUT: assign %.loc34_18.2, %.loc34_37.6 -// CHECK:STDOUT: %.loc34_18.3: {.x: i32, .y: i32} = struct_value %.loc34_18.2, (%.loc34_9, %.loc34_17) +// CHECK:STDOUT: assign %.loc34_18.3, %.loc34_37.6 +// CHECK:STDOUT: %.loc34_18.4: {.x: i32, .y: i32} = struct_value %.loc34_18.3, (%.loc34_9, %.loc34_17) // CHECK:STDOUT: %.loc38_7: bool = bool_literal true // CHECK:STDOUT: if %.loc38_7 br !if.expr.then.loc38 else br !if.expr.else.loc38 // CHECK:STDOUT: diff --git a/toolchain/check/testdata/pointer/address_of_lvalue.carbon b/toolchain/check/testdata/pointer/address_of_lvalue.carbon index 9bda01208c88..e98aaf7e548f 100644 --- a/toolchain/check/testdata/pointer/address_of_lvalue.carbon +++ b/toolchain/check/testdata/pointer/address_of_lvalue.carbon @@ -22,7 +22,8 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc8_27: type = struct_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc8_27.1: type = struct_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc8_27.2: type = ptr_type {.a: i32, .b: i32} // CHECK:STDOUT: %s: ref {.a: i32, .b: i32} = var "s" // CHECK:STDOUT: %.loc8_37: i32 = int_literal 1 // CHECK:STDOUT: %.loc8_45: i32 = int_literal 2 @@ -52,8 +53,10 @@ fn F() { // CHECK:STDOUT: %.loc12_17: i32* = address_of %.loc12_19 // CHECK:STDOUT: assign %r, %.loc12_17 // CHECK:STDOUT: %.loc14_19.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc14_19.2: (type, type) = tuple_literal (i32, i32) -// CHECK:STDOUT: %.loc14_19.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc14_19.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc14_19.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc14_19.4: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc14_19.5: type = ptr_type (i32, i32) // CHECK:STDOUT: %t: ref (i32, i32) = var "t" // CHECK:STDOUT: %.loc14_24: i32 = int_literal 1 // CHECK:STDOUT: %.loc14_27: i32 = int_literal 2 diff --git a/toolchain/check/testdata/pointer/fail_address_of_value.carbon b/toolchain/check/testdata/pointer/fail_address_of_value.carbon index a8126bd12557..94c86ab7bfb4 100644 --- a/toolchain/check/testdata/pointer/fail_address_of_value.carbon +++ b/toolchain/check/testdata/pointer/fail_address_of_value.carbon @@ -108,15 +108,15 @@ fn AddressOfParameter(param: i32) { // CHECK:STDOUT: %.loc23_4: f64 = real_literal 10e-1 // CHECK:STDOUT: %.loc23_3.1: type = ptr_type f64 // CHECK:STDOUT: %.loc23_3.2: f64* = address_of %.loc23_4 +// CHECK:STDOUT: %.1: type = ptr_type String // CHECK:STDOUT: %.loc27_4: String = string_literal "Hello" -// CHECK:STDOUT: %.loc27_3.1: type = ptr_type String -// CHECK:STDOUT: %.loc27_3.2: String* = address_of %.loc27_4 +// CHECK:STDOUT: %.loc27_3: String* = address_of %.loc27_4 // CHECK:STDOUT: %.loc31_5: i32 = int_literal 1 // CHECK:STDOUT: %.loc31_8: i32 = int_literal 2 // CHECK:STDOUT: %.loc31_9.1: type = tuple_type (i32, i32) -// CHECK:STDOUT: %.loc31_9.2: (i32, i32) = tuple_literal (%.loc31_5, %.loc31_8) -// CHECK:STDOUT: %.loc31_3.1: type = ptr_type (i32, i32) -// CHECK:STDOUT: %.loc31_3.2: (i32, i32)* = address_of %.loc31_9.2 +// CHECK:STDOUT: %.loc31_9.2: type = ptr_type (i32, i32) +// CHECK:STDOUT: %.loc31_9.3: (i32, i32) = tuple_literal (%.loc31_5, %.loc31_8) +// CHECK:STDOUT: %.loc31_3: (i32, i32)* = address_of %.loc31_9.3 // CHECK:STDOUT: %.loc35_10: i32 = int_literal 5 // CHECK:STDOUT: %.loc35_11: {.a: i32} = struct_literal (%.loc35_10) // CHECK:STDOUT: %.loc35_3.1: type = ptr_type {.a: i32} diff --git a/toolchain/check/testdata/struct/empty.carbon b/toolchain/check/testdata/struct/empty.carbon index 9c4134360813..9a6d03265964 100644 --- a/toolchain/check/testdata/struct/empty.carbon +++ b/toolchain/check/testdata/struct/empty.carbon @@ -9,7 +9,8 @@ var y: {} = x; // CHECK:STDOUT: file "empty.carbon" { // CHECK:STDOUT: %.loc7_9.1: type = struct_type {} -// CHECK:STDOUT: %.loc7_9.2: {} = struct_literal () +// CHECK:STDOUT: %.loc7_9.2: type = tuple_type () +// CHECK:STDOUT: %.loc7_9.3: {} = struct_literal () // CHECK:STDOUT: %x: ref {} = var "x" // CHECK:STDOUT: %.loc7_14.1: {} = struct_literal () // CHECK:STDOUT: %.loc7_14.2: init {} = struct_init %.loc7_14.1, () diff --git a/toolchain/check/testdata/struct/fail_assign_empty.carbon b/toolchain/check/testdata/struct/fail_assign_empty.carbon index 8bb50da638f8..7b5afbd5017f 100644 --- a/toolchain/check/testdata/struct/fail_assign_empty.carbon +++ b/toolchain/check/testdata/struct/fail_assign_empty.carbon @@ -13,6 +13,7 @@ var x: {.a: i32} = {}; // CHECK:STDOUT: %.loc10_16: type = struct_type {.a: i32} // CHECK:STDOUT: %x: ref {.a: i32} = var "x" // CHECK:STDOUT: %.loc10_21.1: type = struct_type {} -// CHECK:STDOUT: %.loc10_21.2: {} = struct_literal () +// CHECK:STDOUT: %.loc10_21.2: type = tuple_type () +// CHECK:STDOUT: %.loc10_21.3: {} = struct_literal () // CHECK:STDOUT: assign %x, // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/struct/fail_assign_nested.carbon b/toolchain/check/testdata/struct/fail_assign_nested.carbon index 173e6d51bf13..9831b1fd20b0 100644 --- a/toolchain/check/testdata/struct/fail_assign_nested.carbon +++ b/toolchain/check/testdata/struct/fail_assign_nested.carbon @@ -11,11 +11,14 @@ var x: {.a: {}} = {.b = {}}; // CHECK:STDOUT: file "fail_assign_nested.carbon" { // CHECK:STDOUT: %.loc10_14.1: type = struct_type {} -// CHECK:STDOUT: %.loc10_14.2: {} = struct_literal () -// CHECK:STDOUT: %.loc10_15: type = struct_type {.a: {}} +// CHECK:STDOUT: %.loc10_14.2: type = tuple_type () +// CHECK:STDOUT: %.loc10_14.3: {} = struct_literal () +// CHECK:STDOUT: %.loc10_15.1: type = struct_type {.a: {}} +// CHECK:STDOUT: %.loc10_15.2: type = struct_type {.a: ()} // CHECK:STDOUT: %x: ref {.a: {}} = var "x" // CHECK:STDOUT: %.loc10_26: {} = struct_literal () // CHECK:STDOUT: %.loc10_27.1: type = struct_type {.b: {}} -// CHECK:STDOUT: %.loc10_27.2: {.b: {}} = struct_literal (%.loc10_26) +// CHECK:STDOUT: %.loc10_27.2: type = struct_type {.b: ()} +// CHECK:STDOUT: %.loc10_27.3: {.b: {}} = struct_literal (%.loc10_26) // CHECK:STDOUT: assign %x, // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/struct/fail_assign_to_empty.carbon b/toolchain/check/testdata/struct/fail_assign_to_empty.carbon index 0cfde402398b..5e92a7baa626 100644 --- a/toolchain/check/testdata/struct/fail_assign_to_empty.carbon +++ b/toolchain/check/testdata/struct/fail_assign_to_empty.carbon @@ -11,7 +11,8 @@ var x: {} = {.a = 1}; // CHECK:STDOUT: file "fail_assign_to_empty.carbon" { // CHECK:STDOUT: %.loc10_9.1: type = struct_type {} -// CHECK:STDOUT: %.loc10_9.2: {} = struct_literal () +// CHECK:STDOUT: %.loc10_9.2: type = tuple_type () +// CHECK:STDOUT: %.loc10_9.3: {} = struct_literal () // CHECK:STDOUT: %x: ref {} = var "x" // CHECK:STDOUT: %.loc10_19: i32 = int_literal 1 // CHECK:STDOUT: %.loc10_20.1: type = struct_type {.a: i32} diff --git a/toolchain/check/testdata/struct/fail_too_few_values.carbon b/toolchain/check/testdata/struct/fail_too_few_values.carbon index 3b95f37778b8..10ef90d301a4 100644 --- a/toolchain/check/testdata/struct/fail_too_few_values.carbon +++ b/toolchain/check/testdata/struct/fail_too_few_values.carbon @@ -10,7 +10,8 @@ var x: {.a: i32, .b: i32} = {.a = 1}; // CHECK:STDOUT: file "fail_too_few_values.carbon" { -// CHECK:STDOUT: %.loc10_25: type = struct_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc10_25.1: type = struct_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc10_25.2: type = ptr_type {.a: i32, .b: i32} // CHECK:STDOUT: %x: ref {.a: i32, .b: i32} = var "x" // CHECK:STDOUT: %.loc10_35: i32 = int_literal 1 // CHECK:STDOUT: %.loc10_36.1: type = struct_type {.a: i32} diff --git a/toolchain/check/testdata/struct/literal_member_access.carbon b/toolchain/check/testdata/struct/literal_member_access.carbon index 423f67fb6c4c..d096aab76b91 100644 --- a/toolchain/check/testdata/struct/literal_member_access.carbon +++ b/toolchain/check/testdata/struct/literal_member_access.carbon @@ -25,7 +25,9 @@ fn F() -> i32 { // CHECK:STDOUT: %.loc10_25.2: init {.x: i32, .y: i32, .z: i32} = call %G.ref() to %.loc10_25.1 // CHECK:STDOUT: %.loc10_34: i32 = int_literal 3 // CHECK:STDOUT: %.loc10_35.1: type = struct_type {.a: i32, .b: {.x: i32, .y: i32, .z: i32}, .c: i32} -// CHECK:STDOUT: %.loc10_35.2: {.a: i32, .b: {.x: i32, .y: i32, .z: i32}, .c: i32} = struct_literal (%.loc10_16, %.loc10_25.2, %.loc10_34) +// CHECK:STDOUT: %.loc10_35.2: type = struct_type {.a: i32, .b: {.x: i32, .y: i32, .z: i32}*, .c: i32} +// CHECK:STDOUT: %.loc10_35.3: type = ptr_type {.a: i32, .b: {.x: i32, .y: i32, .z: i32}*, .c: i32} +// CHECK:STDOUT: %.loc10_35.4: {.a: i32, .b: {.x: i32, .y: i32, .z: i32}, .c: i32} = struct_literal (%.loc10_16, %.loc10_25.2, %.loc10_34) // CHECK:STDOUT: %.loc10_25.3: ref {.x: i32, .y: i32, .z: i32} = temporary %.loc10_25.1, %.loc10_25.2 // CHECK:STDOUT: %.loc10_25.4: ref i32 = struct_access %.loc10_25.3, member0 // CHECK:STDOUT: %.loc10_25.5: i32 = bind_value %.loc10_25.4 @@ -34,8 +36,8 @@ fn F() -> i32 { // CHECK:STDOUT: %.loc10_25.8: ref i32 = struct_access %.loc10_25.3, member2 // CHECK:STDOUT: %.loc10_25.9: i32 = bind_value %.loc10_25.8 // CHECK:STDOUT: %.loc10_25.10: {.x: i32, .y: i32, .z: i32} = struct_value %.loc10_25.3, (%.loc10_25.5, %.loc10_25.7, %.loc10_25.9) -// CHECK:STDOUT: %.loc10_35.3: {.a: i32, .b: {.x: i32, .y: i32, .z: i32}, .c: i32} = struct_value %.loc10_35.2, (%.loc10_16, %.loc10_25.10, %.loc10_34) -// CHECK:STDOUT: %.loc10_36: {.x: i32, .y: i32, .z: i32} = struct_access %.loc10_35.3, member1 +// CHECK:STDOUT: %.loc10_35.5: {.a: i32, .b: {.x: i32, .y: i32, .z: i32}, .c: i32} = struct_value %.loc10_35.4, (%.loc10_16, %.loc10_25.10, %.loc10_34) +// CHECK:STDOUT: %.loc10_36: {.x: i32, .y: i32, .z: i32} = struct_access %.loc10_35.5, member1 // CHECK:STDOUT: %.loc10_38: i32 = struct_access %.loc10_36, member1 // CHECK:STDOUT: return %.loc10_38 // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/struct/member_access.carbon b/toolchain/check/testdata/struct/member_access.carbon index b06a5e36915b..2da174bec0a9 100644 --- a/toolchain/check/testdata/struct/member_access.carbon +++ b/toolchain/check/testdata/struct/member_access.carbon @@ -9,7 +9,8 @@ var y: i32 = x.b; var z: i32 = y; // CHECK:STDOUT: file "member_access.carbon" { -// CHECK:STDOUT: %.loc7_25: type = struct_type {.a: f64, .b: i32} +// CHECK:STDOUT: %.loc7_25.1: type = struct_type {.a: f64, .b: i32} +// CHECK:STDOUT: %.loc7_25.2: type = ptr_type {.a: f64, .b: i32} // CHECK:STDOUT: %x: ref {.a: f64, .b: i32} = var "x" // CHECK:STDOUT: %.loc7_35: f64 = real_literal 0e-1 // CHECK:STDOUT: %.loc7_45: i32 = int_literal 1 diff --git a/toolchain/check/testdata/struct/nested_struct_in_place.carbon b/toolchain/check/testdata/struct/nested_struct_in_place.carbon index aa6191eea00b..ecbefc3dfef9 100644 --- a/toolchain/check/testdata/struct/nested_struct_in_place.carbon +++ b/toolchain/check/testdata/struct/nested_struct_in_place.carbon @@ -21,7 +21,9 @@ fn G() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc10_29: (type, type, type) = tuple_literal (i32, i32, i32) // CHECK:STDOUT: %.loc10_50: (type, type, type) = tuple_literal (i32, i32, i32) -// CHECK:STDOUT: %.loc10_51: type = struct_type {.a: (i32, i32, i32), .b: (i32, i32, i32)} +// CHECK:STDOUT: %.loc10_51.1: type = struct_type {.a: (i32, i32, i32), .b: (i32, i32, i32)} +// CHECK:STDOUT: %.loc10_51.2: type = struct_type {.a: (i32, i32, i32)*, .b: (i32, i32, i32)*} +// CHECK:STDOUT: %.loc10_51.3: type = ptr_type {.a: (i32, i32, i32)*, .b: (i32, i32, i32)*} // CHECK:STDOUT: %v: ref {.a: (i32, i32, i32), .b: (i32, i32, i32)} = var "v" // CHECK:STDOUT: %F.ref.loc10_61: = name_reference "F", package.%F // CHECK:STDOUT: %.loc10_74.1: ref (i32, i32, i32) = struct_access %v, member0 diff --git a/toolchain/check/testdata/struct/tuple_as_element.carbon b/toolchain/check/testdata/struct/tuple_as_element.carbon index 41b12abafc10..cca201661b8c 100644 --- a/toolchain/check/testdata/struct/tuple_as_element.carbon +++ b/toolchain/check/testdata/struct/tuple_as_element.carbon @@ -11,7 +11,8 @@ var y: {.a: i32, .b: (i32,)} = x; // CHECK:STDOUT: %.loc7_27.1: type = tuple_type (type) // CHECK:STDOUT: %.loc7_27.2: (type,) = tuple_literal (i32) // CHECK:STDOUT: %.loc7_27.3: type = tuple_type (i32) -// CHECK:STDOUT: %.loc7_28: type = struct_type {.a: i32, .b: (i32,)} +// CHECK:STDOUT: %.loc7_28.1: type = struct_type {.a: i32, .b: (i32,)} +// CHECK:STDOUT: %.loc7_28.2: type = ptr_type {.a: i32, .b: (i32,)} // CHECK:STDOUT: %x: ref {.a: i32, .b: (i32,)} = var "x" // CHECK:STDOUT: %.loc7_38: i32 = int_literal 1 // CHECK:STDOUT: %.loc7_47: i32 = int_literal 2 diff --git a/toolchain/check/testdata/struct/two_entries.carbon b/toolchain/check/testdata/struct/two_entries.carbon index 8c2995a52da5..751b44b35edd 100644 --- a/toolchain/check/testdata/struct/two_entries.carbon +++ b/toolchain/check/testdata/struct/two_entries.carbon @@ -8,7 +8,8 @@ var x: {.a: i32, .b: i32} = {.a = 1, .b = 2}; var y: {.a: i32, .b: i32} = x; // CHECK:STDOUT: file "two_entries.carbon" { -// CHECK:STDOUT: %.loc7_25: type = struct_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc7_25.1: type = struct_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc7_25.2: type = ptr_type {.a: i32, .b: i32} // CHECK:STDOUT: %x: ref {.a: i32, .b: i32} = var "x" // CHECK:STDOUT: %.loc7_35: i32 = int_literal 1 // CHECK:STDOUT: %.loc7_43: i32 = int_literal 2 diff --git a/toolchain/check/testdata/tuples/fail_assign_nested.carbon b/toolchain/check/testdata/tuples/fail_assign_nested.carbon index 6f567f1a448d..06f0918ee5e8 100644 --- a/toolchain/check/testdata/tuples/fail_assign_nested.carbon +++ b/toolchain/check/testdata/tuples/fail_assign_nested.carbon @@ -11,23 +11,32 @@ var x: ((i32, i32), (i32, i32)) = ((1, 2, 3), (4, 5, 6)); // CHECK:STDOUT: file "fail_assign_nested.carbon" { // CHECK:STDOUT: %.loc10_18.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc10_18.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc10_18.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc10_18.3: (type, type) = tuple_literal (i32, i32) // CHECK:STDOUT: %.loc10_30: (type, type) = tuple_literal (i32, i32) // CHECK:STDOUT: %.loc10_31.1: type = tuple_type ((type, type), (type, type)) -// CHECK:STDOUT: %.loc10_31.2: ((type, type), (type, type)) = tuple_literal (%.loc10_18.2, %.loc10_30) -// CHECK:STDOUT: %.loc10_31.3: type = tuple_type (i32, i32) -// CHECK:STDOUT: %.loc10_31.4: type = tuple_type ((i32, i32), (i32, i32)) +// CHECK:STDOUT: %.loc10_31.2: type = tuple_type ((type, type)*, (type, type)*) +// CHECK:STDOUT: %.loc10_31.3: type = ptr_type ((type, type)*, (type, type)*) +// CHECK:STDOUT: %.loc10_31.4: ((type, type), (type, type)) = tuple_literal (%.loc10_18.3, %.loc10_30) +// CHECK:STDOUT: %.loc10_31.5: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc10_31.6: type = ptr_type (i32, i32) +// CHECK:STDOUT: %.loc10_31.7: type = tuple_type ((i32, i32), (i32, i32)) +// CHECK:STDOUT: %.loc10_31.8: type = tuple_type ((i32, i32)*, (i32, i32)*) +// CHECK:STDOUT: %.loc10_31.9: type = ptr_type ((i32, i32)*, (i32, i32)*) // CHECK:STDOUT: %x: ref ((i32, i32), (i32, i32)) = var "x" // CHECK:STDOUT: %.loc10_37: i32 = int_literal 1 // CHECK:STDOUT: %.loc10_40: i32 = int_literal 2 // CHECK:STDOUT: %.loc10_43: i32 = int_literal 3 // CHECK:STDOUT: %.loc10_44.1: type = tuple_type (i32, i32, i32) -// CHECK:STDOUT: %.loc10_44.2: (i32, i32, i32) = tuple_literal (%.loc10_37, %.loc10_40, %.loc10_43) +// CHECK:STDOUT: %.loc10_44.2: type = ptr_type (i32, i32, i32) +// CHECK:STDOUT: %.loc10_44.3: (i32, i32, i32) = tuple_literal (%.loc10_37, %.loc10_40, %.loc10_43) // CHECK:STDOUT: %.loc10_48: i32 = int_literal 4 // CHECK:STDOUT: %.loc10_51: i32 = int_literal 5 // CHECK:STDOUT: %.loc10_54: i32 = int_literal 6 // CHECK:STDOUT: %.loc10_55: (i32, i32, i32) = tuple_literal (%.loc10_48, %.loc10_51, %.loc10_54) // CHECK:STDOUT: %.loc10_56.1: type = tuple_type ((i32, i32, i32), (i32, i32, i32)) -// CHECK:STDOUT: %.loc10_56.2: ((i32, i32, i32), (i32, i32, i32)) = tuple_literal (%.loc10_44.2, %.loc10_55) +// CHECK:STDOUT: %.loc10_56.2: type = tuple_type ((i32, i32, i32)*, (i32, i32, i32)*) +// CHECK:STDOUT: %.loc10_56.3: type = ptr_type ((i32, i32, i32)*, (i32, i32, i32)*) +// CHECK:STDOUT: %.loc10_56.4: ((i32, i32, i32), (i32, i32, i32)) = tuple_literal (%.loc10_44.3, %.loc10_55) // CHECK:STDOUT: assign %x, // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon b/toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon index 28d1b9b0c8cc..123dda82778f 100644 --- a/toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon +++ b/toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon @@ -11,14 +11,17 @@ var x: (i32, i32) = (2, 65.89); // CHECK:STDOUT: file "fail_element_type_mismatch.carbon" { // CHECK:STDOUT: %.loc10_17.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc10_17.2: (type, type) = tuple_literal (i32, i32) -// CHECK:STDOUT: %.loc10_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc10_17.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc10_17.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc10_17.4: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc10_17.5: type = ptr_type (i32, i32) // CHECK:STDOUT: %x: ref (i32, i32) = var "x" // CHECK:STDOUT: %.loc10_22: i32 = int_literal 2 // CHECK:STDOUT: %.loc10_25: f64 = real_literal 6589e-2 // CHECK:STDOUT: %.loc10_30.1: type = tuple_type (i32, f64) -// CHECK:STDOUT: %.loc10_30.2: (i32, f64) = tuple_literal (%.loc10_22, %.loc10_25) -// CHECK:STDOUT: %.loc10_30.3: ref i32 = tuple_access %x, member0 -// CHECK:STDOUT: %.loc10_30.4: init i32 = initialize_from %.loc10_22 to %.loc10_30.3 +// CHECK:STDOUT: %.loc10_30.2: type = ptr_type (i32, f64) +// CHECK:STDOUT: %.loc10_30.3: (i32, f64) = tuple_literal (%.loc10_22, %.loc10_25) +// CHECK:STDOUT: %.loc10_30.4: ref i32 = tuple_access %x, member0 +// CHECK:STDOUT: %.loc10_30.5: init i32 = initialize_from %.loc10_22 to %.loc10_30.4 // CHECK:STDOUT: assign %x, // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/tuples/fail_too_few_element.carbon b/toolchain/check/testdata/tuples/fail_too_few_element.carbon index bc2f73669c3f..e0c7b28486fc 100644 --- a/toolchain/check/testdata/tuples/fail_too_few_element.carbon +++ b/toolchain/check/testdata/tuples/fail_too_few_element.carbon @@ -11,8 +11,10 @@ var x: (i32, i32) = (2, ); // CHECK:STDOUT: file "fail_too_few_element.carbon" { // CHECK:STDOUT: %.loc10_17.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc10_17.2: (type, type) = tuple_literal (i32, i32) -// CHECK:STDOUT: %.loc10_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc10_17.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc10_17.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc10_17.4: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc10_17.5: type = ptr_type (i32, i32) // CHECK:STDOUT: %x: ref (i32, i32) = var "x" // CHECK:STDOUT: %.loc10_22: i32 = int_literal 2 // CHECK:STDOUT: %.loc10_25.1: type = tuple_type (i32) diff --git a/toolchain/check/testdata/tuples/nested_tuple.carbon b/toolchain/check/testdata/tuples/nested_tuple.carbon index bf57a4c57cdc..a5f72a0edc2d 100644 --- a/toolchain/check/testdata/tuples/nested_tuple.carbon +++ b/toolchain/check/testdata/tuples/nested_tuple.carbon @@ -8,11 +8,17 @@ var x: ((i32, i32), i32) = ((12, 76), 6); // CHECK:STDOUT: file "nested_tuple.carbon" { // CHECK:STDOUT: %.loc7_18.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc7_18.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_18.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc7_18.3: (type, type) = tuple_literal (i32, i32) // CHECK:STDOUT: %.loc7_24.1: type = tuple_type ((type, type), type) -// CHECK:STDOUT: %.loc7_24.2: ((type, type), type) = tuple_literal (%.loc7_18.2, i32) -// CHECK:STDOUT: %.loc7_24.3: type = tuple_type (i32, i32) -// CHECK:STDOUT: %.loc7_24.4: type = tuple_type ((i32, i32), i32) +// CHECK:STDOUT: %.loc7_24.2: type = tuple_type ((type, type)*, type) +// CHECK:STDOUT: %.loc7_24.3: type = ptr_type ((type, type)*, type) +// CHECK:STDOUT: %.loc7_24.4: ((type, type), type) = tuple_literal (%.loc7_18.3, i32) +// CHECK:STDOUT: %.loc7_24.5: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_24.6: type = ptr_type (i32, i32) +// CHECK:STDOUT: %.loc7_24.7: type = tuple_type ((i32, i32), i32) +// CHECK:STDOUT: %.loc7_24.8: type = tuple_type ((i32, i32)*, i32) +// CHECK:STDOUT: %.loc7_24.9: type = ptr_type ((i32, i32)*, i32) // CHECK:STDOUT: %x: ref ((i32, i32), i32) = var "x" // CHECK:STDOUT: %.loc7_30: i32 = int_literal 12 // CHECK:STDOUT: %.loc7_34: i32 = int_literal 76 diff --git a/toolchain/check/testdata/tuples/nested_tuple_in_place.carbon b/toolchain/check/testdata/tuples/nested_tuple_in_place.carbon index d777016776d1..052fda770897 100644 --- a/toolchain/check/testdata/tuples/nested_tuple_in_place.carbon +++ b/toolchain/check/testdata/tuples/nested_tuple_in_place.carbon @@ -27,8 +27,12 @@ fn H() { // CHECK:STDOUT: %.loc10_25: (type, type, type) = tuple_literal (i32, i32, i32) // CHECK:STDOUT: %.loc10_42: (type, type, type) = tuple_literal (i32, i32, i32) // CHECK:STDOUT: %.loc10_43.1: type = tuple_type ((type, type, type), (type, type, type)) -// CHECK:STDOUT: %.loc10_43.2: ((type, type, type), (type, type, type)) = tuple_literal (%.loc10_25, %.loc10_42) -// CHECK:STDOUT: %.loc10_43.3: type = tuple_type ((i32, i32, i32), (i32, i32, i32)) +// CHECK:STDOUT: %.loc10_43.2: type = tuple_type ((type, type, type)*, (type, type, type)*) +// CHECK:STDOUT: %.loc10_43.3: type = ptr_type ((type, type, type)*, (type, type, type)*) +// CHECK:STDOUT: %.loc10_43.4: ((type, type, type), (type, type, type)) = tuple_literal (%.loc10_25, %.loc10_42) +// CHECK:STDOUT: %.loc10_43.5: type = tuple_type ((i32, i32, i32), (i32, i32, i32)) +// CHECK:STDOUT: %.loc10_43.6: type = tuple_type ((i32, i32, i32)*, (i32, i32, i32)*) +// CHECK:STDOUT: %.loc10_43.7: type = ptr_type ((i32, i32, i32)*, (i32, i32, i32)*) // CHECK:STDOUT: %v: ref ((i32, i32, i32), (i32, i32, i32)) = var "v" // CHECK:STDOUT: %F.ref.loc10_48: = name_reference "F", package.%F // CHECK:STDOUT: %.loc10_56.1: ref (i32, i32, i32) = tuple_access %v, member0 @@ -46,8 +50,12 @@ fn H() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc14_30: (type, type, type) = tuple_literal (i32, i32, i32) // CHECK:STDOUT: %.loc14_36.1: type = tuple_type (type, (type, type, type), type) -// CHECK:STDOUT: %.loc14_36.2: (type, (type, type, type), type) = tuple_literal (i32, %.loc14_30, i32) -// CHECK:STDOUT: %.loc14_36.3: type = tuple_type (i32, (i32, i32, i32), i32) +// CHECK:STDOUT: %.loc14_36.2: type = tuple_type (type, (type, type, type)*, type) +// CHECK:STDOUT: %.loc14_36.3: type = ptr_type (type, (type, type, type)*, type) +// CHECK:STDOUT: %.loc14_36.4: (type, (type, type, type), type) = tuple_literal (i32, %.loc14_30, i32) +// CHECK:STDOUT: %.loc14_36.5: type = tuple_type (i32, (i32, i32, i32), i32) +// CHECK:STDOUT: %.loc14_36.6: type = tuple_type (i32, (i32, i32, i32)*, i32) +// CHECK:STDOUT: %.loc14_36.7: type = ptr_type (i32, (i32, i32, i32)*, i32) // CHECK:STDOUT: %v: ref (i32, (i32, i32, i32), i32) = var "v" // CHECK:STDOUT: %.loc14_41: i32 = int_literal 1 // CHECK:STDOUT: %F.ref: = name_reference "F", package.%F diff --git a/toolchain/check/testdata/tuples/two_elements.carbon b/toolchain/check/testdata/tuples/two_elements.carbon index ea92de611cf8..ef71ba7c5cb4 100644 --- a/toolchain/check/testdata/tuples/two_elements.carbon +++ b/toolchain/check/testdata/tuples/two_elements.carbon @@ -9,8 +9,10 @@ var y: (i32, i32) = x; // CHECK:STDOUT: file "two_elements.carbon" { // CHECK:STDOUT: %.loc7_17.1: type = tuple_type (type, type) -// CHECK:STDOUT: %.loc7_17.2: (type, type) = tuple_literal (i32, i32) -// CHECK:STDOUT: %.loc7_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.2: type = ptr_type (type, type) +// CHECK:STDOUT: %.loc7_17.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.4: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.5: type = ptr_type (i32, i32) // CHECK:STDOUT: %x: ref (i32, i32) = var "x" // CHECK:STDOUT: %.loc7_22: i32 = int_literal 4 // CHECK:STDOUT: %.loc7_25: i32 = int_literal 102 diff --git a/toolchain/check/testdata/while/fail_bad_condition.carbon b/toolchain/check/testdata/while/fail_bad_condition.carbon index 19a6fb28bebb..afbec5013c16 100644 --- a/toolchain/check/testdata/while/fail_bad_condition.carbon +++ b/toolchain/check/testdata/while/fail_bad_condition.carbon @@ -20,6 +20,7 @@ fn While() { // CHECK:STDOUT: br !while.cond // CHECK:STDOUT: // CHECK:STDOUT: !while.cond: +// CHECK:STDOUT: %.1: type = ptr_type String // CHECK:STDOUT: %.loc11: String = string_literal "Hello" // CHECK:STDOUT: if br !while.body else br !while.done // CHECK:STDOUT: diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index 98d976daf1a6..138c77288e18 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -35,7 +35,7 @@ auto FileContext::Run() -> std::unique_ptr { auto types = semantics_ir_->types(); types_.resize_for_overwrite(types.size()); for (auto [i, type] : llvm::enumerate(types)) { - types_[i] = BuildType(type); + types_[i] = BuildType(type.node_id); } // Lower function declarations. @@ -87,15 +87,15 @@ auto FileContext::BuildFunctionDeclaration(SemIR::FunctionId function_id) switch (auto value_rep = SemIR::GetValueRepresentation(semantics_ir(), param_type_id); value_rep.kind) { + case SemIR::ValueRepresentation::Unknown: + CARBON_FATAL() + << "Incomplete parameter type lowering function declaration"; case SemIR::ValueRepresentation::None: break; case SemIR::ValueRepresentation::Copy: case SemIR::ValueRepresentation::Custom: - param_types.push_back(GetType(value_rep.type)); - param_node_ids.push_back(param_ref_id); - break; case SemIR::ValueRepresentation::Pointer: - param_types.push_back(GetType(value_rep.type)->getPointerTo()); + param_types.push_back(GetType(value_rep.type_id)); param_node_ids.push_back(param_ref_id); break; } diff --git a/toolchain/lower/function_context.cpp b/toolchain/lower/function_context.cpp index 547b78e2ad6c..2ed46ec4ac3c 100644 --- a/toolchain/lower/function_context.cpp +++ b/toolchain/lower/function_context.cpp @@ -95,6 +95,8 @@ auto FunctionContext::CopyValue(SemIR::TypeId type_id, SemIR::NodeId source_id, SemIR::NodeId dest_id) -> void { switch (auto rep = SemIR::GetValueRepresentation(semantics_ir(), type_id); rep.kind) { + case SemIR::ValueRepresentation::Unknown: + CARBON_FATAL() << "Attempt to copy incomplete type"; case SemIR::ValueRepresentation::None: break; case SemIR::ValueRepresentation::Copy: diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index 653139fdcd60..1f329d6115a7 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -286,39 +286,53 @@ static auto GetStructOrTupleElement(FunctionContext& context, auto aggr_node = context.semantics_ir().GetNode(aggr_node_id); auto* aggr_value = context.GetLocal(aggr_node_id); - auto aggr_cat = - SemIR::GetExpressionCategory(context.semantics_ir(), aggr_node_id); - if (aggr_cat == SemIR::ExpressionCategory::Value && - SemIR::GetValueRepresentation(context.semantics_ir(), aggr_node.type_id()) - .kind == SemIR::ValueRepresentation::Copy) { - // We are holding the values of the aggregate directly, elementwise. - return context.builder().CreateExtractValue(aggr_value, idx, name); - } + switch (SemIR::GetExpressionCategory(context.semantics_ir(), aggr_node_id)) { + case SemIR::ExpressionCategory::Error: + case SemIR::ExpressionCategory::NotExpression: + case SemIR::ExpressionCategory::Initializing: + case SemIR::ExpressionCategory::Mixed: + CARBON_FATAL() << "Unexpected expression category for aggregate access"; - // Either we're accessing an element of a reference and producing a reference, - // or we're accessing an element of a value that is held by pointer and we're - // producing a value. - auto* aggr_type = context.GetType(aggr_node.type_id()); - auto* elem_ptr = - context.builder().CreateStructGEP(aggr_type, aggr_value, idx, name); + case SemIR::ExpressionCategory::Value: { + auto value_rep = SemIR::GetValueRepresentation(context.semantics_ir(), + aggr_node.type_id()); + switch (value_rep.kind) { + case SemIR::ValueRepresentation::Unknown: + CARBON_FATAL() << "Lowering access to incomplete aggregate type"; + case SemIR::ValueRepresentation::None: + return aggr_value; + case SemIR::ValueRepresentation::Copy: + // We are holding the values of the aggregate directly, elementwise. + return context.builder().CreateExtractValue(aggr_value, idx, name); + case SemIR::ValueRepresentation::Pointer: { + // The value representation is a pointer to an aggregate that we want + // to index into. + auto pointee_type_id = + context.semantics_ir().GetPointeeType(value_rep.type_id); + auto* value_type = context.GetType(pointee_type_id); + auto* elem_ptr = context.builder().CreateStructGEP( + value_type, aggr_value, idx, name); + auto result_value_type_id = + SemIR::GetValueRepresentation(context.semantics_ir(), + result_type_id) + .type_id; + return context.builder().CreateLoad( + context.GetType(result_value_type_id), elem_ptr, name + ".load"); + } + case SemIR::ValueRepresentation::Custom: + CARBON_FATAL() + << "Aggregate should never have custom value representation"; + } + } - // If this is a value access, load the element if necessary. - if (aggr_cat == SemIR::ExpressionCategory::Value) { - switch ( - SemIR::GetValueRepresentation(context.semantics_ir(), result_type_id) - .kind) { - case SemIR::ValueRepresentation::None: - return llvm::PoisonValue::get(context.GetType(result_type_id)); - case SemIR::ValueRepresentation::Copy: - return context.builder().CreateLoad(context.GetType(result_type_id), - elem_ptr, name + ".load"); - case SemIR::ValueRepresentation::Pointer: - return elem_ptr; - case SemIR::ValueRepresentation::Custom: - CARBON_FATAL() << "TODO: Add support for custom value representation"; + case SemIR::ExpressionCategory::DurableReference: + case SemIR::ExpressionCategory::EphemeralReference: { + // Just locate the aggregate element. + auto* aggr_type = context.GetType(aggr_node.type_id()); + return context.builder().CreateStructGEP(aggr_type, aggr_value, idx, + name); } } - return elem_ptr; } auto HandleStructAccess(FunctionContext& context, SemIR::NodeId node_id, @@ -355,12 +369,15 @@ auto EmitStructOrTupleValueRepresentation(FunctionContext& context, SemIR::TypeId type_id, SemIR::NodeBlockId refs_id, llvm::Twine name) -> llvm::Value* { - auto* llvm_type = context.GetType(type_id); + auto value_rep = + SemIR::GetValueRepresentation(context.semantics_ir(), type_id); + switch (value_rep.kind) { + case SemIR::ValueRepresentation::Unknown: + CARBON_FATAL() << "Incomplete aggregate type in lowering"; - switch (SemIR::GetValueRepresentation(context.semantics_ir(), type_id).kind) { case SemIR::ValueRepresentation::None: // TODO: Add a helper to get a "no value representation" value. - return llvm::PoisonValue::get(llvm_type); + return llvm::PoisonValue::get(context.GetType(value_rep.type_id)); case SemIR::ValueRepresentation::Copy: { auto refs = context.semantics_ir().GetNodeBlock(refs_id); @@ -369,20 +386,25 @@ auto EmitStructOrTupleValueRepresentation(FunctionContext& context, // TODO: Remove the LLVM StructType wrapper in this case, so we don't // need this `insert_value` wrapping. return context.builder().CreateInsertValue( - llvm::PoisonValue::get(llvm_type), context.GetLocal(refs[0]), {0}); + llvm::PoisonValue::get(context.GetType(value_rep.type_id)), + context.GetLocal(refs[0]), {0}); } case SemIR::ValueRepresentation::Pointer: { - // Write the object representation to a local alloca so we can produce a - // pointer to it as the value representation. - auto* alloca = context.builder().CreateAlloca( - llvm_type, /*ArraySize=*/nullptr, name); + auto pointee_type_id = + context.semantics_ir().GetPointeeType(value_rep.type_id); + auto* llvm_value_rep_type = context.GetType(pointee_type_id); + + // Write the value representation to a local alloca so we can produce a + // pointer to it as the value representation of the struct or tuple. + auto* alloca = + context.builder().CreateAlloca(llvm_value_rep_type, + /*ArraySize=*/nullptr, name); for (auto [i, ref] : llvm::enumerate(context.semantics_ir().GetNodeBlock(refs_id))) { - auto* gep = context.builder().CreateStructGEP(llvm_type, alloca, i); - // TODO: We are loading a value representation here and storing an - // object representation! - context.builder().CreateStore(context.GetLocal(ref), gep); + context.builder().CreateStore( + context.GetLocal(ref), + context.builder().CreateStructGEP(llvm_value_rep_type, alloca, i)); } return alloca; } diff --git a/toolchain/lower/handle_expression_category.cpp b/toolchain/lower/handle_expression_category.cpp index c7e645edbbe0..01c0c9668cc5 100644 --- a/toolchain/lower/handle_expression_category.cpp +++ b/toolchain/lower/handle_expression_category.cpp @@ -12,6 +12,9 @@ auto HandleBindValue(FunctionContext& context, SemIR::NodeId node_id, switch (auto rep = SemIR::GetValueRepresentation(context.semantics_ir(), node.type_id); rep.kind) { + case SemIR::ValueRepresentation::Unknown: + CARBON_FATAL() + << "Value binding for type with incomplete value representation"; case SemIR::ValueRepresentation::None: // Nothing should use this value, but StubReference needs a value to // propagate. diff --git a/toolchain/lower/testdata/basics/type_values.carbon b/toolchain/lower/testdata/basics/type_values.carbon index 7b2b8d014db7..6e93c667792b 100644 --- a/toolchain/lower/testdata/basics/type_values.carbon +++ b/toolchain/lower/testdata/basics/type_values.carbon @@ -4,6 +4,9 @@ // // AUTOUPDATE +// TODO: It would be nice to treat these functions as returning `void` instead +// of `{}`. + fn I32() -> type { return i32; } @@ -15,10 +18,12 @@ fn F64() -> type { // CHECK:STDOUT: ; ModuleID = 'type_values.carbon' // CHECK:STDOUT: source_filename = "type_values.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: define void @I32() { -// CHECK:STDOUT: ret void +// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: +// CHECK:STDOUT: define %type @I32() { +// CHECK:STDOUT: ret %type zeroinitializer // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: define void @F64() { -// CHECK:STDOUT: ret void +// CHECK:STDOUT: define %type @F64() { +// CHECK:STDOUT: ret %type zeroinitializer // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/let/tuple.carbon b/toolchain/lower/testdata/let/tuple.carbon index 5facd2e9e893..a359e2ea3318 100644 --- a/toolchain/lower/testdata/let/tuple.carbon +++ b/toolchain/lower/testdata/let/tuple.carbon @@ -49,13 +49,14 @@ fn F() -> i32 { // CHECK:STDOUT: store i32 %7, ptr %9, align 4 // CHECK:STDOUT: %10 = getelementptr inbounds { i32, i32 }, ptr %tuple10, i32 0, i32 1 // CHECK:STDOUT: store i32 %8, ptr %10, align 4 -// CHECK:STDOUT: %tuple11 = alloca { { i32, i32, i32 }, { i32, i32 } }, align 8 -// CHECK:STDOUT: %11 = getelementptr inbounds { { i32, i32, i32 }, { i32, i32 } }, ptr %tuple11, i32 0, i32 0 +// CHECK:STDOUT: %tuple11 = alloca { ptr, ptr }, align 8 +// CHECK:STDOUT: %11 = getelementptr inbounds { ptr, ptr }, ptr %tuple11, i32 0, i32 0 // CHECK:STDOUT: store ptr %tuple, ptr %11, align 8 -// CHECK:STDOUT: %12 = getelementptr inbounds { { i32, i32, i32 }, { i32, i32 } }, ptr %tuple11, i32 0, i32 1 +// CHECK:STDOUT: %12 = getelementptr inbounds { ptr, ptr }, ptr %tuple11, i32 0, i32 1 // CHECK:STDOUT: store ptr %tuple10, ptr %12, align 8 -// CHECK:STDOUT: %tuple.index = getelementptr inbounds { { i32, i32, i32 }, { i32, i32 } }, ptr %tuple11, i32 0, i32 1 -// CHECK:STDOUT: %tuple.index12 = getelementptr inbounds { i32, i32 }, ptr %tuple.index, i32 0, i32 1 -// CHECK:STDOUT: %tuple.index.load = load i32, ptr %tuple.index12, align 4 -// CHECK:STDOUT: ret i32 %tuple.index.load +// CHECK:STDOUT: %tuple.index = getelementptr inbounds { ptr, ptr }, ptr %tuple11, i32 0, i32 1 +// CHECK:STDOUT: %tuple.index.load = load ptr, ptr %tuple.index, align 8 +// CHECK:STDOUT: %tuple.index12 = getelementptr inbounds { i32, i32 }, ptr %tuple.index.load, i32 0, i32 1 +// CHECK:STDOUT: %tuple.index.load13 = load i32, ptr %tuple.index12, align 4 +// CHECK:STDOUT: ret i32 %tuple.index.load13 // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/tuple/value_formation.carbon b/toolchain/lower/testdata/tuple/value_formation.carbon index 9e12e7e1e859..78c4a40da120 100644 --- a/toolchain/lower/testdata/tuple/value_formation.carbon +++ b/toolchain/lower/testdata/tuple/value_formation.carbon @@ -46,10 +46,10 @@ fn F() { // CHECK:STDOUT: store i32 %8, ptr %11, align 4 // CHECK:STDOUT: %12 = getelementptr inbounds { i32, i32, i32 }, ptr %tuple6, i32 0, i32 2 // CHECK:STDOUT: store i32 %9, ptr %12, align 4 -// CHECK:STDOUT: %tuple7 = alloca { { i32, i32, i32 }, { i32, i32, i32 } }, align 8 -// CHECK:STDOUT: %13 = getelementptr inbounds { { i32, i32, i32 }, { i32, i32, i32 } }, ptr %tuple7, i32 0, i32 0 +// CHECK:STDOUT: %tuple7 = alloca { ptr, ptr }, align 8 +// CHECK:STDOUT: %13 = getelementptr inbounds { ptr, ptr }, ptr %tuple7, i32 0, i32 0 // CHECK:STDOUT: store ptr %tuple, ptr %13, align 8 -// CHECK:STDOUT: %14 = getelementptr inbounds { { i32, i32, i32 }, { i32, i32, i32 } }, ptr %tuple7, i32 0, i32 1 +// CHECK:STDOUT: %14 = getelementptr inbounds { ptr, ptr }, ptr %tuple7, i32 0, i32 1 // CHECK:STDOUT: store ptr %tuple6, ptr %14, align 8 // CHECK:STDOUT: call void @G(ptr %tuple7) // CHECK:STDOUT: ret void diff --git a/toolchain/lower/testdata/tuple/value_forwarding.carbon b/toolchain/lower/testdata/tuple/value_forwarding.carbon index 5112292a8f65..1e6a79924b02 100644 --- a/toolchain/lower/testdata/tuple/value_forwarding.carbon +++ b/toolchain/lower/testdata/tuple/value_forwarding.carbon @@ -16,10 +16,10 @@ fn F(a: (i32, i32, i32), b: (i32, i32, i32)) { // CHECK:STDOUT: declare void @G(ptr) // CHECK:STDOUT: // CHECK:STDOUT: define void @F(ptr %a, ptr %b) { -// CHECK:STDOUT: %tuple = alloca { { i32, i32, i32 }, { i32, i32, i32 } }, align 8 -// CHECK:STDOUT: %1 = getelementptr inbounds { { i32, i32, i32 }, { i32, i32, i32 } }, ptr %tuple, i32 0, i32 0 +// CHECK:STDOUT: %tuple = alloca { ptr, ptr }, align 8 +// CHECK:STDOUT: %1 = getelementptr inbounds { ptr, ptr }, ptr %tuple, i32 0, i32 0 // CHECK:STDOUT: store ptr %a, ptr %1, align 8 -// CHECK:STDOUT: %2 = getelementptr inbounds { { i32, i32, i32 }, { i32, i32, i32 } }, ptr %tuple, i32 0, i32 1 +// CHECK:STDOUT: %2 = getelementptr inbounds { ptr, ptr }, ptr %tuple, i32 0, i32 1 // CHECK:STDOUT: store ptr %b, ptr %2, align 8 // CHECK:STDOUT: call void @G(ptr %tuple) // CHECK:STDOUT: ret void diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index f05336cb3cc0..fe1ad6975b55 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -13,6 +13,32 @@ namespace Carbon::SemIR { +auto ValueRepresentation::Print(llvm::raw_ostream& out) const -> void { + out << "{kind: "; + switch (kind) { + case Unknown: + out << "unknown"; + break; + case None: + out << "none"; + break; + case Copy: + out << "copy"; + break; + case Pointer: + out << "pointer"; + break; + case Custom: + out << "custom"; + break; + } + out << ", type: " << type_id << "}"; +} + +auto TypeInfo::Print(llvm::raw_ostream& out) const -> void { + out << "{node: " << node_id << ", value_rep: " << value_representation << "}"; +} + File::File() // Builtins are always the first IR, even when self-referential. : filename_(""), @@ -545,144 +571,6 @@ auto GetExpressionCategory(const File& file, NodeId node_id) } } -auto GetValueRepresentation(const File& file, TypeId type_id) - -> ValueRepresentation { - const File* ir = &file; - NodeId node_id = ir->GetTypeAllowBuiltinTypes(type_id); - while (true) { - auto node = ir->GetNode(node_id); - // clang warns on unhandled enum values; clang-tidy is incorrect here. - // NOLINTNEXTLINE(bugprone-switch-missing-default-case) - switch (node.kind()) { - case AddressOf::Kind: - case ArrayIndex::Kind: - case ArrayInit::Kind: - case Assign::Kind: - case BinaryOperatorAdd::Kind: - case BindName::Kind: - case BindValue::Kind: - case BlockArg::Kind: - case BoolLiteral::Kind: - case Branch::Kind: - case BranchIf::Kind: - case BranchWithArg::Kind: - case Call::Kind: - case Dereference::Kind: - case FunctionDeclaration::Kind: - case InitializeFrom::Kind: - case IntegerLiteral::Kind: - case NameReference::Kind: - case Namespace::Kind: - case NoOp::Kind: - case Parameter::Kind: - case RealLiteral::Kind: - case Return::Kind: - case ReturnExpression::Kind: - case StringLiteral::Kind: - case StructAccess::Kind: - case StructTypeField::Kind: - case StructLiteral::Kind: - case StructInit::Kind: - case StructValue::Kind: - case Temporary::Kind: - case TemporaryStorage::Kind: - case TupleAccess::Kind: - case TupleIndex::Kind: - case TupleLiteral::Kind: - case TupleInit::Kind: - case TupleValue::Kind: - case UnaryOperatorNot::Kind: - case ValueAsReference::Kind: - case VarStorage::Kind: - CARBON_FATAL() << "Type refers to non-type node " << node; - - case CrossReference::Kind: { - auto xref = node.As(); - ir = &ir->GetCrossReferenceIR(xref.ir_id); - node_id = xref.node_id; - continue; - } - - case SpliceBlock::Kind: { - node_id = node.As().result_id; - continue; - } - - case ArrayType::Kind: - // For arrays, it's convenient to always use a pointer representation, - // even when the array has zero or one element, in order to support - // indexing. - return {.kind = ValueRepresentation::Pointer, .type = type_id}; - - case StructType::Kind: { - const auto& fields = ir->GetNodeBlock(node.As().fields_id); - if (fields.empty()) { - // An empty struct has an empty representation. - return {.kind = ValueRepresentation::None, .type = TypeId::Invalid}; - } - if (fields.size() == 1) { - // A struct with one field has the same representation as its field. - node_id = ir->GetTypeAllowBuiltinTypes( - ir->GetNode(fields.front()).As().type_id); - continue; - } - // For any other struct, use a pointer representation. - return {.kind = ValueRepresentation::Pointer, .type = type_id}; - } - - case TupleType::Kind: { - const auto& elements = - ir->GetTypeBlock(node.As().elements_id); - if (elements.empty()) { - // An empty tuple has an empty representation. - return {.kind = ValueRepresentation::None, .type = TypeId::Invalid}; - } - if (elements.size() == 1) { - // A one-tuple has the same representation as its sole element. - node_id = ir->GetTypeAllowBuiltinTypes(elements.front()); - continue; - } - // For any other tuple, use a pointer representation. - return {.kind = ValueRepresentation::Pointer, .type = type_id}; - } - - case ClassDeclaration::Kind: { - // TODO: Pick the default value representation in a smarter way. - // TODO: Allow the value representation for a class to be customized. - return {.kind = ValueRepresentation::Pointer, .type = type_id}; - } - - case Builtin::Kind: - // clang warns on unhandled enum values; clang-tidy is incorrect here. - // NOLINTNEXTLINE(bugprone-switch-missing-default-case) - switch (node.As().builtin_kind) { - case BuiltinKind::TypeType: - case BuiltinKind::Error: - case BuiltinKind::Invalid: - case BuiltinKind::NamespaceType: - case BuiltinKind::FunctionType: - return {.kind = ValueRepresentation::None, .type = TypeId::Invalid}; - case BuiltinKind::BoolType: - case BuiltinKind::IntegerType: - case BuiltinKind::FloatingPointType: - return {.kind = ValueRepresentation::Copy, .type = type_id}; - case BuiltinKind::StringType: - // TODO: Decide on string value semantics. This should probably be a - // custom value representation carrying a pointer and size or - // similar. - return {.kind = ValueRepresentation::Pointer, .type = type_id}; - } - - case PointerType::Kind: - return {.kind = ValueRepresentation::Copy, .type = type_id}; - - case ConstType::Kind: - node_id = ir->GetTypeAllowBuiltinTypes(node.As().inner_id); - continue; - } - } -} - auto GetInitializingRepresentation(const File& file, TypeId type_id) -> InitializingRepresentation { auto value_rep = GetValueRepresentation(file, type_id); @@ -698,6 +586,10 @@ auto GetInitializingRepresentation(const File& file, TypeId type_id) case ValueRepresentation::Pointer: case ValueRepresentation::Custom: return {.kind = InitializingRepresentation::InPlace}; + + case ValueRepresentation::Unknown: + CARBON_FATAL() + << "Attempting to perform initialization of incomplete type"; } } diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 896b8ae69c54..01a70121d216 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -79,6 +79,46 @@ struct Real : public Printable { bool is_decimal; }; +// The value representation to use when passing by value. +struct ValueRepresentation : public Printable { + auto Print(llvm::raw_ostream& out) const -> void; + + enum Kind : int8_t { + // The value representation is not yet known. This is used for incomplete + // types, in cases where the incompleteness means the value representation + // can't be determined. + Unknown, + // The type has no value representation. This is used for empty types, such + // as `()`, where there is no value. + None, + // The value representation is a copy of the value. On call boundaries, the + // value itself will be passed. `type` is the value type. + Copy, + // The value representation is a pointer to an object. When used as a + // parameter, the argument is a reference expression. `type` is the pointee + // type. + Pointer, + // The value representation has been customized, and has the same behavior + // as the value representation of some other type. + // TODO: This is not implemented or used yet. + Custom, + }; + // The kind of value representation used by this type. + Kind kind = Unknown; + // The type used to model the value representation. + TypeId type_id = TypeId::Invalid; +}; + +// Information stored about a TypeId. +struct TypeInfo : public Printable { + auto Print(llvm::raw_ostream& out) const -> void; + + // The node that defines this type. + NodeId node_id; + // The value representation for this type. + ValueRepresentation value_representation; +}; + // Provides semantic analysis on a Parse::Tree. class File : public Printable { public: @@ -302,10 +342,25 @@ class File : public Printable { TypeId type_id(types_.size()); // Should never happen, will always overflow node_ids first. CARBON_DCHECK(type_id.index >= 0); - types_.push_back(node_id); + types_.push_back( + {.node_id = node_id, + .value_representation = {.kind = ValueRepresentation::Unknown}}); return type_id; } + // Marks a type as complete, and sets its value representation. + auto CompleteType(TypeId object_type_id, + ValueRepresentation value_representation) -> void { + if (object_type_id.index < 0) { + // We already know our builtin types are complete. + return; + } + CARBON_CHECK(types_[object_type_id.index].value_representation.kind == + ValueRepresentation::Unknown) + << "Type " << object_type_id << " completed more than once"; + types_[object_type_id.index].value_representation = value_representation; + } + // Gets the node ID for a type. This doesn't handle TypeType or InvalidType in // order to avoid a check; callers that need that should use // GetTypeAllowBuiltinTypes. @@ -313,7 +368,7 @@ class File : public Printable { // Double-check it's not called with TypeType or InvalidType. CARBON_CHECK(type_id.index >= 0) << "Invalid argument for GetType: " << type_id; - return types_[type_id.index]; + return types_[type_id.index].node_id; } auto GetTypeAllowBuiltinTypes(TypeId type_id) const -> NodeId { @@ -328,6 +383,21 @@ class File : public Printable { } } + // Gets the value representation to use for a type. This returns an + // invalid type if the given type is not complete. + auto GetValueRepresentation(TypeId type_id) const -> ValueRepresentation { + if (type_id.index < 0) { + // TypeType and InvalidType are their own value representation. + return {.kind = ValueRepresentation::Copy, .type_id = type_id}; + } + return types_[type_id.index].value_representation; + } + + // Gets the pointee type of the given type, which must be a pointer type. + auto GetPointeeType(TypeId pointer_id) const -> TypeId { + return GetNodeAs(GetType(pointer_id)).pointee_id; + } + // Adds a type block with the given content, returning an ID to reference it. auto AddTypeBlock(llvm::ArrayRef content) -> TypeBlockId { TypeBlockId id(type_blocks_.size()); @@ -359,7 +429,7 @@ class File : public Printable { auto nodes_size() const -> int { return nodes_.size(); } auto node_blocks_size() const -> int { return node_blocks_.size(); } - auto types() const -> llvm::ArrayRef { return types_; } + auto types() const -> llvm::ArrayRef { return types_; } auto top_node_block_id() const -> NodeBlockId { return top_node_block_id_; } auto set_top_node_block_id(NodeBlockId block_id) -> void { @@ -426,9 +496,8 @@ class File : public Printable { llvm::StringMap string_to_id_; llvm::SmallVector strings_; - // Nodes which correspond to in-use types. Stored separately for easy access - // by lowering. - llvm::SmallVector types_; + // Descriptions of types used in this file. + llvm::SmallVector types_; // Type blocks within the IR. These reference entries in types_. Storage for // the data is provided by allocator_. @@ -477,35 +546,11 @@ enum class ExpressionCategory : int8_t { auto GetExpressionCategory(const File& file, NodeId node_id) -> ExpressionCategory; -// The value representation to use when passing by value. -struct ValueRepresentation { - enum Kind : int8_t { - // The type has no value representation. This is used for empty types, such - // as `()`, where there is no value. - None, - // The value representation is a copy of the value. On call boundaries, the - // value itself will be passed. `type` is the value type. - // TODO: `type` should be `const`-qualified, but is currently not. - Copy, - // The value representation is a pointer to an object. When used as a - // parameter, the argument is a reference expression. `type` is the pointee - // type. - // TODO: `type` should be `const`-qualified, but is currently not. - Pointer, - // The value representation has been customized, and has the same behavior - // as the value representation of some other type. - // TODO: This is not implemented or used yet. - Custom, - }; - // The kind of value representation used by this type. - Kind kind; - // The type used to model the value representation. - TypeId type; -}; - // Returns information about the value representation to use for a type. -auto GetValueRepresentation(const File& file, TypeId type_id) - -> ValueRepresentation; +inline auto GetValueRepresentation(const File& file, TypeId type_id) + -> ValueRepresentation { + return file.GetValueRepresentation(type_id); +} // The initializing representation to use when returning by value. struct InitializingRepresentation { diff --git a/toolchain/sem_ir/yaml_test.cpp b/toolchain/sem_ir/yaml_test.cpp index 592e1dcd14a7..21c842723a6c 100644 --- a/toolchain/sem_ir/yaml_test.cpp +++ b/toolchain/sem_ir/yaml_test.cpp @@ -43,6 +43,8 @@ TEST(SemIRTest, YAML) { auto node_id = Yaml::Scalar(MatchesRegex(R"(node\+\d+)")); auto node_builtin = Yaml::Scalar(MatchesRegex(R"(node\w+)")); auto type_id = Yaml::Scalar(MatchesRegex(R"(type\d+)")); + auto type_builtin = Yaml::Mapping(ElementsAre( + Pair("node", node_builtin), Pair("value_rep", Yaml::Mapping(_)))); auto file = Yaml::Sequence(ElementsAre(Yaml::Mapping(ElementsAre( Pair("cross_reference_irs_size", "1"), @@ -51,7 +53,7 @@ TEST(SemIRTest, YAML) { Pair("integers", Yaml::Sequence(ElementsAre("0"))), Pair("reals", Yaml::Sequence(IsEmpty())), Pair("strings", Yaml::Sequence(ElementsAre("F", "x"))), - Pair("types", Yaml::Sequence(ElementsAre(node_builtin, node_builtin))), + Pair("types", Yaml::Sequence(Each(type_builtin))), Pair("type_blocks", Yaml::Sequence(IsEmpty())), Pair("nodes", Yaml::Sequence(AllOf(