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(