From 69353ed271dd2bb29dd5f7f59e4ee8437fa11bc3 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 17 Oct 2023 12:30:51 -0700 Subject: [PATCH] Basic support for incomplete types. (#3302) Incomplete types may be nested within other types; for example, a tuple type might have an incomplete type as an element. Handle such cases by walking through nested incomplete types when completing a type. This is done non-recursively in case a very complex type is formed. Types are generally no longer completed at the point where they're formed. Instead, we attempt to complete a type when it is used in a context that requires a complete type, and diagnose if the type cannot be completed at that point. This will be necessary for classes, which can become complete after their first use, and helps tease out bugs where a type completeness check is missing. --- toolchain/check/context.cpp | 642 +++++++++++------- toolchain/check/context.h | 25 +- toolchain/check/convert.cpp | 25 +- toolchain/check/handle_function.cpp | 43 +- toolchain/check/handle_index.cpp | 2 +- toolchain/check/handle_literal.cpp | 9 +- toolchain/check/handle_namespace.cpp | 2 +- toolchain/check/handle_pattern_binding.cpp | 26 + .../testdata/array/array_in_place.carbon | 9 +- .../check/testdata/array/assign_var.carbon | 7 +- toolchain/check/testdata/array/base.carbon | 26 +- .../array/fail_incomplete_element.carbon | 38 ++ .../testdata/array/fail_out_of_bound.carbon | 3 +- .../testdata/array/fail_type_mismatch.carbon | 22 +- .../testdata/array/function_param.carbon | 32 +- .../check/testdata/array/nine_elements.carbon | 61 +- .../check/testdata/basics/fail_bad_run.carbon | 1 + .../testdata/basics/numeric_literals.carbon | 86 ++- .../testdata/basics/raw_and_textual_ir.carbon | 54 +- toolchain/check/testdata/basics/raw_ir.carbon | 53 +- .../check/testdata/basics/textual_ir.carbon | 1 + .../testdata/class/fail_incomplete.carbon | 169 +++++ .../in_place_tuple_initialization.carbon | 1 + .../function/call/empty_struct.carbon | 1 + .../testdata/if_expression/struct.carbon | 1 + .../index/array_element_access.carbon | 19 +- .../testdata/index/expression_category.carbon | 26 +- .../index/fail_expression_category.carbon | 1 + .../testdata/index/fail_invalid_base.carbon | 6 +- .../index/fail_non_deterministic_type.carbon | 7 +- .../index/fail_tuple_index_error.carbon | 7 +- .../index/fail_tuple_non_int_indexing.carbon | 7 +- .../fail_tuple_out_of_bound_access.carbon | 7 +- toolchain/check/testdata/let/convert.carbon | 7 +- .../testdata/operators/assignment.carbon | 7 +- ... fail_assignment_to_non_assignable.carbon} | 42 +- .../testdata/pointer/address_of_lvalue.carbon | 7 +- .../pointer/fail_address_of_value.carbon | 6 +- toolchain/check/testdata/return/tuple.carbon | 1 + toolchain/check/testdata/struct/empty.carbon | 4 +- .../testdata/struct/fail_assign_empty.carbon | 3 +- .../testdata/struct/fail_assign_nested.carbon | 7 +- .../struct/fail_assign_to_empty.carbon | 4 +- .../struct/fail_nested_incomplete.carbon | 36 + .../struct/literal_member_access.carbon | 9 +- .../struct/nested_struct_in_place.carbon | 1 + .../testdata/tuples/fail_assign_nested.carbon | 24 +- .../tuples/fail_element_type_mismatch.carbon | 14 +- .../tuples/fail_nested_incomplete.carbon | 39 ++ .../tuples/fail_too_few_element.carbon | 7 +- .../check/testdata/tuples/nested_tuple.carbon | 17 +- .../tuples/nested_tuple_in_place.carbon | 21 +- .../check/testdata/tuples/two_elements.carbon | 7 +- toolchain/diagnostics/diagnostic_kind.def | 8 + .../testdata/pointer/address_of_unused.carbon | 19 + toolchain/sem_ir/file.h | 18 +- toolchain/sem_ir/node.h | 11 +- 57 files changed, 1141 insertions(+), 597 deletions(-) create mode 100644 toolchain/check/testdata/array/fail_incomplete_element.carbon create mode 100644 toolchain/check/testdata/class/fail_incomplete.carbon rename toolchain/check/testdata/operators/{fail_assigment_to_non_assignable.carbon => fail_assignment_to_non_assignable.carbon} (80%) create mode 100644 toolchain/check/testdata/struct/fail_nested_incomplete.carbon create mode 100644 toolchain/check/testdata/tuples/fail_nested_incomplete.carbon create mode 100644 toolchain/lower/testdata/pointer/address_of_unused.carbon diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 50fdad22bb8d..8e8b44c89ab4 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -21,8 +21,7 @@ namespace Carbon::Check { -Context::Context(const Lex::TokenizedBuffer& tokens, - DiagnosticEmitter& emitter, +Context::Context(const Lex::TokenizedBuffer& tokens, DiagnosticEmitter& emitter, const Parse::Tree& parse_tree, SemIR::File& semantics_ir, llvm::raw_ostream* vlog_stream) : tokens_(&tokens), @@ -279,233 +278,411 @@ 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); +namespace { +// Worklist-based type completion mechanism. +// +// When attempting to complete a type, we may find other types that also need to +// be completed: types nested within that type, and the value representation of +// the type. In order to complete a type without recursing arbitrarily deeply, +// we use a worklist of tasks: +// +// - An `AddNestedIncompleteTypes` step adds a task for all incomplete types +// nested within a type to the work list. +// - A `BuildValueRepresentation` step computes the value representation for a +// type, once all of its nested types are complete, and marks the type as +// complete. +class TypeCompleter { + public: + TypeCompleter( + Context& context, + std::optionalContext::DiagnosticBuilder>> + diagnoser) + : context_(context), diagnoser_(diagnoser) {} - 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) { + // Attempts to complete the given type. Returns true if it is now complete, + // false if it could not be completed. + auto Complete(SemIR::TypeId type_id) -> bool { + Push(type_id); + while (!work_list_.empty()) { + if (!ProcessStep()) { return false; } - semantics_ir().CompleteType(type_id, inner_value_rep); - return true; + } + return true; + } + + private: + // Adds `type_id` to the work list, if it's not already complete. + auto Push(SemIR::TypeId type_id) -> void { + if (!context_.semantics_ir().IsTypeComplete(type_id)) { + work_list_.push_back({type_id, Phase::AddNestedIncompleteTypes}); } } - llvm_unreachable("All node kinds were handled above"); + // Runs the next step. + auto ProcessStep() -> bool { + auto [type_id, phase] = work_list_.back(); + + // We might have enqueued the same type more than once. Just skip the + // type if it's already complete. + if (context_.semantics_ir().IsTypeComplete(type_id)) { + work_list_.pop_back(); + return true; + } + + auto node_id = context_.semantics_ir().GetTypeAllowBuiltinTypes(type_id); + auto node = context_.semantics_ir().GetNode(node_id); + + auto old_work_list_size = work_list_.size(); + + switch (phase) { + case Phase::AddNestedIncompleteTypes: + if (!AddNestedIncompleteTypes(node)) { + return false; + } + CARBON_CHECK(work_list_.size() >= old_work_list_size) + << "AddNestedIncompleteTypes should not remove work items"; + work_list_[old_work_list_size - 1].phase = + Phase::BuildValueRepresentation; + break; + + case Phase::BuildValueRepresentation: { + auto value_rep = BuildValueRepresentation(type_id, node); + context_.semantics_ir().CompleteType(type_id, value_rep); + CARBON_CHECK(old_work_list_size == work_list_.size()) + << "BuildValueRepresentation should not change work items"; + work_list_.pop_back(); + + // Also complete the value representation type, if necessary. This + // should never fail: the value representation shouldn't require any + // additional nested types to be complete. + if (!context_.semantics_ir().IsTypeComplete(value_rep.type_id)) { + work_list_.push_back( + {value_rep.type_id, Phase::BuildValueRepresentation}); + } + break; + } + } + + return true; + } + + // Adds any types nested within `type_node` that need to be complete for + // `type_node` to be complete to our work list. + auto AddNestedIncompleteTypes(SemIR::Node type_node) -> bool { + switch (type_node.kind()) { + case SemIR::ArrayType::Kind: + Push(type_node.As().element_type_id); + break; + + case SemIR::StructType::Kind: + for (auto field_id : context_.semantics_ir().GetNodeBlock( + type_node.As().fields_id)) { + Push(context_.semantics_ir() + .GetNodeAs(field_id) + .type_id); + } + break; + + case SemIR::TupleType::Kind: + for (auto element_type_id : context_.semantics_ir().GetTypeBlock( + type_node.As().elements_id)) { + Push(element_type_id); + } + break; + + case SemIR::ClassDeclaration::Kind: + // TODO: Support class definitions and complete class types. + if (diagnoser_) { + CARBON_DIAGNOSTIC(ClassForwardDeclaredHere, Note, + "Class was forward declared here."); + (*diagnoser_)() + .Note(type_node.parse_node(), ClassForwardDeclaredHere) + .Emit(); + } + return false; + + case SemIR::ConstType::Kind: + Push(type_node.As().inner_id); + break; + + default: + break; + } + + return true; + } + + // Makes an empty value representation, which is used for types that have no + // state, such as empty structs and tuples. + auto MakeEmptyRepresentation(Parse::Node parse_node) const + -> SemIR::ValueRepresentation { + return {.kind = SemIR::ValueRepresentation::None, + .type_id = context_.CanonicalizeTupleType(parse_node, {})}; + } + + // Makes a value representation that uses pass-by-copy, copying the given + // type. + auto MakeCopyRepresentation(SemIR::TypeId rep_id) const + -> SemIR::ValueRepresentation { + return {.kind = SemIR::ValueRepresentation::Copy, .type_id = rep_id}; + } + + // Makes a value representation that uses pass-by-address with the given + // pointee type. + auto MakePointerRepresentation(Parse::Node parse_node, + SemIR::TypeId pointee_id) const + -> SemIR::ValueRepresentation { + // TODO: Should we add `const` qualification to `pointee_id`? + return {.kind = SemIR::ValueRepresentation::Pointer, + .type_id = context_.GetPointerType(parse_node, pointee_id)}; + } + + // Gets the value representation of a nested type, which should already be + // complete. + auto GetNestedValueRepresentation(SemIR::TypeId nested_type_id) const { + CARBON_CHECK(context_.semantics_ir().IsTypeComplete(nested_type_id)) + << "Nested type should already be complete"; + auto value_rep = + context_.semantics_ir().GetValueRepresentation(nested_type_id); + CARBON_CHECK(value_rep.kind != SemIR::ValueRepresentation::Unknown) + << "Complete type should have a value representation"; + return value_rep; + }; + + auto BuildCrossReferenceValueRepresentation(SemIR::TypeId type_id, + SemIR::CrossReference xref) const + -> SemIR::ValueRepresentation { + auto xref_node = context_.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 MakeCopyRepresentation(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 MakePointerRepresentation(Parse::Node::Invalid, type_id); + } + llvm_unreachable("All builtin kinds were handled above"); + } + + auto BuildStructTypeValueRepresentation(SemIR::TypeId type_id, + SemIR::StructType struct_type) const + -> SemIR::ValueRepresentation { + // TODO: Share code with tuples. + auto fields = context_.semantics_ir().GetNodeBlock(struct_type.fields_id); + if (fields.empty()) { + return MakeEmptyRepresentation(struct_type.parse_node); + } + + // 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 = + context_.semantics_ir().GetNodeAs(field_id); + auto field_value_rep = GetNestedValueRepresentation(field.type_id); + if (field_value_rep.type_id != field.type_id) { + same_as_object_rep = false; + field.type_id = field_value_rep.type_id; + field_id = context_.AddNode(field); + } + value_rep_fields.push_back(field_id); + } + + auto value_rep = + same_as_object_rep + ? type_id + : context_.CanonicalizeStructType( + struct_type.parse_node, + context_.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 MakeCopyRepresentation(value_rep); + } + // For a struct with multiple fields, we use a pointer representation. + return MakePointerRepresentation(struct_type.parse_node, value_rep); + } + + auto BuildTupleTypeValueRepresentation(SemIR::TypeId type_id, + SemIR::TupleType tuple_type) const + -> SemIR::ValueRepresentation { + // TODO: Share code with structs. + auto elements = + context_.semantics_ir().GetTypeBlock(tuple_type.elements_id); + if (elements.empty()) { + return MakeEmptyRepresentation(tuple_type.parse_node); + } + + // 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) { + auto element_value_rep = GetNestedValueRepresentation(element_type_id); + 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 + : context_.CanonicalizeTupleType(tuple_type.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 MakeCopyRepresentation(value_rep); + } + // For a tuple with multiple elements, we use a pointer representation. + return MakePointerRepresentation(tuple_type.parse_node, value_rep); + } + + // Builds and returns the value representation for the given type. All nested + // types, as found by AddNestedIncompleteTypes, are known to be complete. + auto BuildValueRepresentation(SemIR::TypeId type_id, SemIR::Node node) const + -> SemIR::ValueRepresentation { + // TODO: This can emit new SemIR nodes. Consider emitting them into a + // dedicated file-scope node block where possible, or somewhere else that + // better reflects the definition of the type, rather than wherever the + // type happens to first be required to be complete. + + // 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: + return BuildCrossReferenceValueRepresentation( + type_id, node.As()); + + 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 MakePointerRepresentation(node.parse_node(), type_id); + } + + case SemIR::StructType::Kind: + return BuildStructTypeValueRepresentation(type_id, + node.As()); + + case SemIR::TupleType::Kind: + return BuildTupleTypeValueRepresentation(type_id, + node.As()); + + case SemIR::ClassDeclaration::Kind: + // TODO: Support class definitions and complete class types. + CARBON_FATAL() << "Class types are currently never complete"; + + case SemIR::Builtin::Kind: + CARBON_FATAL() << "Builtins should be named as cross-references"; + + case SemIR::PointerType::Kind: + return MakeCopyRepresentation(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. + return GetNestedValueRepresentation( + node.As().inner_id); + } + } + + enum class Phase : int8_t { + // The next step is to add nested types to the list of types to complete. + AddNestedIncompleteTypes, + // The next step is to build the value representation for the type. + BuildValueRepresentation, + }; + + struct WorkItem { + SemIR::TypeId type_id; + Phase phase; + }; + + Context& context_; + llvm::SmallVector work_list_; + std::optionalContext::DiagnosticBuilder>> + diagnoser_; +}; +} // namespace + +auto Context::TryToCompleteType( + SemIR::TypeId type_id, + std::optionalDiagnosticBuilder>> diagnoser) + -> bool { + return TypeCompleter(*this, diagnoser).Complete(type_id); } auto Context::CanonicalizeTypeImpl( @@ -539,16 +716,6 @@ 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; } @@ -665,6 +832,15 @@ auto Context::CanonicalizeTupleType(Parse::Node parse_node, make_tuple_node); } +auto Context::GetBuiltinType(SemIR::BuiltinKind kind) -> SemIR::TypeId { + CARBON_CHECK(kind != SemIR::BuiltinKind::Invalid); + auto type_id = CanonicalizeType(SemIR::NodeId::ForBuiltin(kind)); + // To keep client code simpler, complete builtin types before returning them. + bool complete = TryToCompleteType(type_id); + CARBON_CHECK(complete) << "Failed to complete builtin type"; + return type_id; +} + auto Context::GetPointerType(Parse::Node parse_node, SemIR::TypeId pointee_type_id) -> SemIR::TypeId { return CanonicalizeTypeAndAddNodeIfNew( diff --git a/toolchain/check/context.h b/toolchain/check/context.h index b9ac682e2b07..01f9721b3328 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -21,6 +21,9 @@ namespace Carbon::Check { // Context and shared functionality for semantics handlers. class Context { public: + using DiagnosticEmitter = Carbon::DiagnosticEmitter; + using DiagnosticBuilder = DiagnosticEmitter::DiagnosticBuilder; + // A scope in which `break` and `continue` can be used. struct BreakContinueScope { SemIR::NodeBlockId break_target; @@ -29,9 +32,8 @@ class Context { // Stores references for work. explicit Context(const Lex::TokenizedBuffer& tokens, - DiagnosticEmitter& emitter, - const Parse::Tree& parse_tree, SemIR::File& semantics, - llvm::raw_ostream* vlog_stream); + DiagnosticEmitter& emitter, const Parse::Tree& parse_tree, + SemIR::File& semantics, llvm::raw_ostream* vlog_stream); // Marks an implementation TODO. Always returns false. auto TODO(Parse::Node parse_node, std::string label) -> bool; @@ -136,8 +138,17 @@ class Context { // 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; + // + // If the type is not complete, `diagnoser` is invoked to diagnose the issue. + // The builder it returns will be annotated to describe the reason why the + // type is not complete. + auto TryToCompleteType( + SemIR::TypeId type_id, + std::optionalDiagnosticBuilder>> diagnoser = + std::nullopt) -> bool; + + // Gets a builtin type. The returned type will be complete. + auto GetBuiltinType(SemIR::BuiltinKind kind) -> SemIR::TypeId; // Returns a pointer type whose pointee type is `pointee_type_id`. auto GetPointerType(Parse::Node parse_node, SemIR::TypeId pointee_type_id) @@ -179,7 +190,7 @@ class Context { auto tokens() -> const Lex::TokenizedBuffer& { return *tokens_; } - auto emitter() -> DiagnosticEmitter& { return *emitter_; } + auto emitter() -> DiagnosticEmitter& { return *emitter_; } auto parse_tree() -> const Parse::Tree& { return *parse_tree_; } @@ -255,7 +266,7 @@ class Context { const Lex::TokenizedBuffer* tokens_; // Handles diagnostics. - DiagnosticEmitter* emitter_; + DiagnosticEmitter* emitter_; // The file's parse tree. const Parse::Tree* parse_tree_; diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index eabee81529fa..8a2ca70cc4cc 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -133,7 +133,7 @@ static auto MakeElemAccessNode(Context& context, Parse::Node parse_node, // so that we don't need an integer literal node here, and remove this // special case. auto index_id = block.AddNode(SemIR::IntegerLiteral( - parse_node, context.CanonicalizeType(SemIR::NodeId::BuiltinIntegerType), + parse_node, context.GetBuiltinType(SemIR::BuiltinKind::IntegerType), context.semantics_ir().AddInteger(llvm::APInt(32, i)))); return block.AddNode( AccessNodeT(parse_node, elem_type_id, aggregate_id, index_id)); @@ -634,6 +634,27 @@ auto Convert(Context& context, Parse::Node parse_node, SemIR::NodeId expr_id, return SemIR::NodeId::BuiltinError; } + // We can only perform initialization for complete types. + if (!context.TryToCompleteType(target.type_id, [&] { + CARBON_DIAGNOSTIC(IncompleteTypeInInitialization, Error, + "Initialization of incomplete type `{0}`.", + std::string); + CARBON_DIAGNOSTIC(IncompleteTypeInValueConversion, Error, + "Forming value of incomplete type `{0}`.", + std::string); + CARBON_DIAGNOSTIC(IncompleteTypeInConversion, Error, + "Invalid use of incomplete type `{0}`.", std::string); + return context.emitter().Build( + parse_node, + target.is_initializer() ? IncompleteTypeInInitialization + : target.kind == ConversionTarget::Value + ? IncompleteTypeInValueConversion + : IncompleteTypeInConversion, + context.semantics_ir().StringifyType(target.type_id, true)); + })) { + return SemIR::NodeId::BuiltinError; + } + // Check whether any builtin conversion applies. expr_id = PerformBuiltinConversion(context, parse_node, expr_id, target); if (expr_id == SemIR::NodeId::BuiltinError) { @@ -755,7 +776,7 @@ auto ConvertToBoolValue(Context& context, Parse::Node parse_node, SemIR::NodeId value_id) -> SemIR::NodeId { return ConvertToValueOfType( context, parse_node, value_id, - context.CanonicalizeType(SemIR::NodeId::BuiltinBoolType)); + context.GetBuiltinType(SemIR::BuiltinKind::BoolType)); } auto ConvertCallArgs(Context& context, Parse::Node call_parse_node, diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp index 39246b67f470..17d96590bbc3 100644 --- a/toolchain/check/handle_function.cpp +++ b/toolchain/check/handle_function.cpp @@ -26,14 +26,27 @@ static auto BuildFunctionDeclaration(Context& context) auto return_slot_id = SemIR::NodeId::Invalid; if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) == Parse::NodeKind::ReturnType) { - return_slot_id = context.node_stack().Pop(); - return_type_id = context.semantics_ir().GetNode(return_slot_id).type_id(); + auto [return_node, return_storage_id] = + context.node_stack().PopWithParseNode(); + auto return_node_copy = return_node; + return_type_id = + context.semantics_ir().GetNode(return_storage_id).type_id(); - // The function only has a return slot if it uses in-place initialization. - if (!SemIR::GetInitializingRepresentation(context.semantics_ir(), - return_type_id) - .has_return_slot()) { - return_slot_id = SemIR::NodeId::Invalid; + if (!context.TryToCompleteType(return_type_id, [&] { + CARBON_DIAGNOSTIC(IncompleteTypeInFunctionReturnType, Error, + "Function returns incomplete type `{0}`.", + std::string); + return context.emitter().Build( + return_node_copy, IncompleteTypeInFunctionReturnType, + context.semantics_ir().StringifyType(return_type_id, true)); + })) { + return_type_id = SemIR::TypeId::Error; + } else if (!SemIR::GetInitializingRepresentation(context.semantics_ir(), + return_type_id) + .has_return_slot()) { + // The function only has a return slot if it uses in-place initialization. + } else { + return_slot_id = return_storage_id; } } @@ -58,7 +71,7 @@ static auto BuildFunctionDeclaration(Context& context) .return_slot_id = return_slot_id, .body_block_ids = {}}); auto decl_id = context.AddNode(SemIR::FunctionDeclaration( - fn_node, context.CanonicalizeType(SemIR::NodeId::BuiltinFunctionType), + fn_node, context.GetBuiltinType(SemIR::BuiltinKind::FunctionType), function_id)); context.declaration_name_stack().AddNameToLookup(name_context, decl_id); @@ -67,7 +80,7 @@ static auto BuildFunctionDeclaration(Context& context) if (!context.semantics_ir().GetNodeBlock(param_refs_id).empty() || (return_slot_id.is_valid() && return_type_id != - context.CanonicalizeType(SemIR::NodeId::BuiltinBoolType) && + context.GetBuiltinType(SemIR::BuiltinKind::BoolType) && return_type_id != context.CanonicalizeTupleType(fn_node, {}))) { CARBON_DIAGNOSTIC(InvalidMainRunSignature, Error, "Invalid signature for `Main.Run` function. Expected " @@ -127,6 +140,18 @@ auto HandleFunctionDefinitionStart(Context& context, Parse::Node parse_node) for (auto param_id : context.semantics_ir().GetNodeBlock(function.param_refs_id)) { auto param = context.semantics_ir().GetNodeAs(param_id); + + // The parameter types need to be complete. + context.TryToCompleteType(param.type_id, [&] { + CARBON_DIAGNOSTIC( + IncompleteTypeInFunctionParam, Error, + "Parameter has incomplete type `{0}` in function definition.", + std::string); + return context.emitter().Build( + param.parse_node, IncompleteTypeInFunctionParam, + context.semantics_ir().StringifyType(param.type_id, true)); + }); + context.AddNameToLookup(param.parse_node, param.name_id, param_id); } diff --git a/toolchain/check/handle_index.cpp b/toolchain/check/handle_index.cpp index a26178331c78..96bd677caf7b 100644 --- a/toolchain/check/handle_index.cpp +++ b/toolchain/check/handle_index.cpp @@ -63,7 +63,7 @@ auto HandleIndexExpression(Context& context, Parse::Node parse_node) -> bool { } auto cast_index_id = ConvertToValueOfType( context, index_node.parse_node(), index_node_id, - context.CanonicalizeType(SemIR::NodeId::BuiltinIntegerType)); + context.GetBuiltinType(SemIR::BuiltinKind::IntegerType)); auto array_cat = SemIR::GetExpressionCategory(context.semantics_ir(), operand_node_id); if (array_cat == SemIR::ExpressionCategory::Value) { diff --git a/toolchain/check/handle_literal.cpp b/toolchain/check/handle_literal.cpp index 6698f4822c84..976d9b7e19da 100644 --- a/toolchain/check/handle_literal.cpp +++ b/toolchain/check/handle_literal.cpp @@ -14,8 +14,7 @@ auto HandleLiteral(Context& context, Parse::Node parse_node) -> bool { context.AddNodeAndPush( parse_node, SemIR::BoolLiteral( - parse_node, - context.CanonicalizeType(SemIR::NodeId::BuiltinBoolType), + parse_node, context.GetBuiltinType(SemIR::BuiltinKind::BoolType), token_kind == Lex::TokenKind::True ? SemIR::BoolValue::True : SemIR::BoolValue::False)); break; @@ -27,7 +26,7 @@ auto HandleLiteral(Context& context, Parse::Node parse_node) -> bool { parse_node, SemIR::IntegerLiteral( parse_node, - context.CanonicalizeType(SemIR::NodeId::BuiltinIntegerType), id)); + context.GetBuiltinType(SemIR::BuiltinKind::IntegerType), id)); break; } case Lex::TokenKind::RealLiteral: { @@ -40,7 +39,7 @@ auto HandleLiteral(Context& context, Parse::Node parse_node) -> bool { parse_node, SemIR::RealLiteral( parse_node, - context.CanonicalizeType(SemIR::NodeId::BuiltinFloatingPointType), + context.GetBuiltinType(SemIR::BuiltinKind::FloatingPointType), id)); break; } @@ -51,7 +50,7 @@ auto HandleLiteral(Context& context, Parse::Node parse_node) -> bool { parse_node, SemIR::StringLiteral( parse_node, - context.CanonicalizeType(SemIR::NodeId::BuiltinStringType), id)); + context.GetBuiltinType(SemIR::BuiltinKind::StringType), id)); break; } case Lex::TokenKind::Type: { diff --git a/toolchain/check/handle_namespace.cpp b/toolchain/check/handle_namespace.cpp index 18859a52f37f..16ddfc00cb8b 100644 --- a/toolchain/check/handle_namespace.cpp +++ b/toolchain/check/handle_namespace.cpp @@ -16,7 +16,7 @@ auto HandleNamespaceStart(Context& context, Parse::Node /*parse_node*/) auto HandleNamespace(Context& context, Parse::Node parse_node) -> bool { auto name_context = context.declaration_name_stack().Pop(); auto namespace_id = context.AddNode(SemIR::Namespace( - parse_node, context.CanonicalizeType(SemIR::NodeId::BuiltinNamespaceType), + parse_node, context.GetBuiltinType(SemIR::BuiltinKind::NamespaceType), context.semantics_ir().AddNameScope())); context.declaration_name_stack().AddNameToLookup(name_context, namespace_id); return true; diff --git a/toolchain/check/handle_pattern_binding.cpp b/toolchain/check/handle_pattern_binding.cpp index d4fce2eef958..962415fa79fa 100644 --- a/toolchain/check/handle_pattern_binding.cpp +++ b/toolchain/check/handle_pattern_binding.cpp @@ -20,6 +20,7 @@ auto HandleGenericPatternBinding(Context& context, Parse::Node parse_node) auto HandlePatternBinding(Context& context, Parse::Node parse_node) -> bool { auto [type_node, parsed_type_id] = context.node_stack().PopExpressionWithParseNode(); + auto type_node_copy = type_node; auto cast_type_id = ExpressionAsType(context, type_node, parsed_type_id); // Get the name. @@ -32,14 +33,38 @@ auto HandlePatternBinding(Context& context, Parse::Node parse_node) -> bool { switch (auto context_parse_node_kind = context.parse_tree().node_kind( context.node_stack().PeekParseNode())) { case Parse::NodeKind::VariableIntroducer: + if (!context.TryToCompleteType(cast_type_id, [&] { + CARBON_DIAGNOSTIC(IncompleteTypeInVarDeclaration, Error, + "Variable has incomplete type `{0}`.", + std::string); + return context.emitter().Build( + type_node_copy, IncompleteTypeInVarDeclaration, + context.semantics_ir().StringifyType(cast_type_id, true)); + })) { + cast_type_id = SemIR::TypeId::Error; + } context.AddNodeAndPush( parse_node, SemIR::VarStorage(name_node, cast_type_id, name_id)); break; + case Parse::NodeKind::ParameterListStart: + // Parameters can have incomplete types in a function declaration, but not + // in a function definition. We don't know which kind we have here. context.AddNodeAndPush( parse_node, SemIR::Parameter(name_node, cast_type_id, name_id)); break; + case Parse::NodeKind::LetIntroducer: + if (!context.TryToCompleteType(cast_type_id, [&] { + CARBON_DIAGNOSTIC(IncompleteTypeInLetDeclaration, Error, + "`let` binding has incomplete type `{0}`.", + std::string); + return context.emitter().Build( + type_node_copy, IncompleteTypeInLetDeclaration, + context.semantics_ir().StringifyType(cast_type_id, true)); + })) { + cast_type_id = SemIR::TypeId::Error; + } // Create the node, but don't add it to a block until after we've formed // its initializer. // TODO: For general pattern parsing, we'll need to create a block to hold @@ -49,6 +74,7 @@ auto HandlePatternBinding(Context& context, Parse::Node parse_node) -> bool { context.semantics_ir().AddNodeInNoBlock(SemIR::BindName( name_node, cast_type_id, name_id, SemIR::NodeId::Invalid))); break; + default: CARBON_FATAL() << "Found a pattern binding in unexpected context " << context_parse_node_kind; diff --git a/toolchain/check/testdata/array/array_in_place.carbon b/toolchain/check/testdata/array/array_in_place.carbon index 2c8ad5d5b8d8..45aae2491067 100644 --- a/toolchain/check/testdata/array/array_in_place.carbon +++ b/toolchain/check/testdata/array/array_in_place.carbon @@ -11,6 +11,7 @@ fn G() { } // CHECK:STDOUT: file "array_in_place.carbon" { +// CHECK:STDOUT: %.loc7: type = ptr_type (i32, i32, i32) // CHECK:STDOUT: %F: = fn_decl @F // CHECK:STDOUT: %G: = fn_decl @G // CHECK:STDOUT: } @@ -37,10 +38,8 @@ 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: 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: %.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: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/array/assign_var.carbon b/toolchain/check/testdata/array/assign_var.carbon index ad76a5c9d088..61ed98a03af4 100644 --- a/toolchain/check/testdata/array/assign_var.carbon +++ b/toolchain/check/testdata/array/assign_var.carbon @@ -9,10 +9,9 @@ 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 = 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: %.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.4: 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 diff --git a/toolchain/check/testdata/array/base.carbon b/toolchain/check/testdata/array/base.carbon index a7669ac8c89f..62305a54f4a7 100644 --- a/toolchain/check/testdata/array/base.carbon +++ b/toolchain/check/testdata/array/base.carbon @@ -28,16 +28,15 @@ var c: [(); 5] = ((), (), (), (), (),); // 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: 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: %.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: %.loc9_10.1: type = tuple_type () // CHECK:STDOUT: %.loc9_10.2: () = tuple_literal () // CHECK:STDOUT: %.loc9_13: i32 = int_literal 5 @@ -50,13 +49,12 @@ 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: 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_38.2: ((), (), (), (), ()) = 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.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: %.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: } diff --git a/toolchain/check/testdata/array/fail_incomplete_element.carbon b/toolchain/check/testdata/array/fail_incomplete_element.carbon new file mode 100644 index 000000000000..d5b8ff24e1a5 --- /dev/null +++ b/toolchain/check/testdata/array/fail_incomplete_element.carbon @@ -0,0 +1,38 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +class Incomplete; + +// CHECK:STDERR: fail_incomplete_element.carbon:[[@LINE+6]]:22: ERROR: Variable has incomplete type `[Incomplete; 1]`. +// CHECK:STDERR: var a: [Incomplete; 1]; +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_incomplete_element.carbon:[[@LINE-5]]:1: Class was forward declared here. +// CHECK:STDERR: class Incomplete; +// CHECK:STDERR: ^ +var a: [Incomplete; 1]; + +// CHECK:STDERR: fail_incomplete_element.carbon:[[@LINE+3]]:27: ERROR: Cannot implicitly convert from `*` to `Incomplete*`. +// CHECK:STDERR: var p: Incomplete* = &a[0]; +// CHECK:STDERR: ^ +var p: Incomplete* = &a[0]; + +// CHECK:STDOUT: file "fail_incomplete_element.carbon" { +// CHECK:STDOUT: %Incomplete: type = class_declaration @Incomplete +// CHECK:STDOUT: %Incomplete.ref.loc15: type = name_reference "Incomplete", %Incomplete +// CHECK:STDOUT: %.loc15_21: i32 = int_literal 1 +// CHECK:STDOUT: %.loc15_22: type = array_type %.loc15_21, Incomplete +// CHECK:STDOUT: %a: ref = var "a" +// CHECK:STDOUT: %Incomplete.ref.loc20: type = name_reference "Incomplete", %Incomplete +// CHECK:STDOUT: %.loc20_18: type = ptr_type Incomplete +// CHECK:STDOUT: %p: ref Incomplete* = var "p" +// CHECK:STDOUT: %a.ref: ref = name_reference "a", %a +// CHECK:STDOUT: %.loc20_25: i32 = int_literal 0 +// CHECK:STDOUT: %.loc20_22.1: type = ptr_type +// CHECK:STDOUT: %.loc20_22.2: * = address_of +// CHECK:STDOUT: assign %p, +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Incomplete; diff --git a/toolchain/check/testdata/array/fail_out_of_bound.carbon b/toolchain/check/testdata/array/fail_out_of_bound.carbon index 9b4e674d2eed..2fa05cea3f31 100644 --- a/toolchain/check/testdata/array/fail_out_of_bound.carbon +++ b/toolchain/check/testdata/array/fail_out_of_bound.carbon @@ -18,7 +18,6 @@ var a: [i32; 1] = (1, 2, 3); // 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: type = ptr_type (i32, i32, i32) -// CHECK:STDOUT: %.loc10_27.3: (i32, i32, i32) = tuple_literal (%.loc10_20, %.loc10_23, %.loc10_26) +// CHECK:STDOUT: %.loc10_27.2: (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 6e400a66e3f5..b4727f74a505 100644 --- a/toolchain/check/testdata/array/fail_type_mismatch.carbon +++ b/toolchain/check/testdata/array/fail_type_mismatch.carbon @@ -36,16 +36,15 @@ var d: [i32; 3] = t2; // 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: 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: %.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: assign %a, // CHECK:STDOUT: %.loc12_29.1: type = tuple_type (type, type, type) -// 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: %.loc12_29.2: (type, type, type) = tuple_literal (i32, String, String) +// CHECK:STDOUT: %.loc10_39.6: type = tuple_type (i32, String*, String*) +// CHECK:STDOUT: %.loc10_39.7: type = ptr_type (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 @@ -64,12 +63,11 @@ 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: type = ptr_type (i32, i32) -// CHECK:STDOUT: %.loc21_24.3: (i32, i32) = tuple_literal (%.loc21_20, %.loc21_23) +// CHECK:STDOUT: %.loc21_24.2: (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 = ptr_type (type, type) -// CHECK:STDOUT: %.loc23_18.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc23_18.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc21_24.3: type = ptr_type (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 b83e7bd936a6..51c61a855df6 100644 --- a/toolchain/check/testdata/array/function_param.carbon +++ b/toolchain/check/testdata/array/function_param.carbon @@ -19,6 +19,7 @@ fn G() -> i32 { // CHECK:STDOUT: // CHECK:STDOUT: fn @F(%arr: [i32; 3], %i: i32) -> i32 { // CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc7: type = ptr_type [i32; 3] // CHECK:STDOUT: %arr.ref: [i32; 3] = name_reference "arr", %arr // CHECK:STDOUT: %i.ref: i32 = name_reference "i", %i // CHECK:STDOUT: %.loc8_15.1: ref [i32; 3] = value_as_reference %arr.ref @@ -34,23 +35,22 @@ 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: 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_20.2: (i32, i32, i32) = tuple_literal (%.loc12_13, %.loc12_16, %.loc12_19) // CHECK:STDOUT: %.loc12_23: i32 = int_literal 1 -// CHECK:STDOUT: %.loc12_20.4: ref [i32; 3] = temporary_storage -// CHECK:STDOUT: %.loc12_20.5: i32 = int_literal 0 -// CHECK:STDOUT: %.loc12_20.6: ref i32 = array_index %.loc12_20.4, %.loc12_20.5 -// CHECK:STDOUT: %.loc12_20.7: init i32 = initialize_from %.loc12_13 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_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_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 3e18e7c54c36..67ef23f2930e 100644 --- a/toolchain/check/testdata/array/nine_elements.carbon +++ b/toolchain/check/testdata/array/nine_elements.carbon @@ -21,35 +21,34 @@ 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: 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: %.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: } diff --git a/toolchain/check/testdata/basics/fail_bad_run.carbon b/toolchain/check/testdata/basics/fail_bad_run.carbon index 5669167cddd9..5b9364d88174 100644 --- a/toolchain/check/testdata/basics/fail_bad_run.carbon +++ b/toolchain/check/testdata/basics/fail_bad_run.carbon @@ -13,6 +13,7 @@ fn Run() -> String {} // CHECK:STDOUT: file "fail_bad_run.carbon" { +// CHECK:STDOUT: %.1: type = ptr_type String // CHECK:STDOUT: %Run: = fn_decl @Run // CHECK:STDOUT: %.loc13: type = tuple_type () // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/basics/numeric_literals.carbon b/toolchain/check/testdata/basics/numeric_literals.carbon index 2bd90e385749..3715ab1b1610 100644 --- a/toolchain/check/testdata/basics/numeric_literals.carbon +++ b/toolchain/check/testdata/basics/numeric_literals.carbon @@ -41,25 +41,24 @@ 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: 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: %.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: %.loc17_21: i32 = int_literal 7 // CHECK:STDOUT: %.loc17_22.1: type = array_type %.loc17_21, f64 // CHECK:STDOUT: %.loc17_22.2: type = ptr_type [f64; 7] @@ -72,30 +71,29 @@ 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: 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: %.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: 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 3ea7b5f1e16b..e5fa8ca47d06 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: type4, return_slot: node+6, body: [block4]}, +// CHECK:STDOUT: {name: str0, param_refs: block1, return_type: type3, return_slot: node+4, body: [block4]}, // CHECK:STDOUT: ] // CHECK:STDOUT: classes: [ // CHECK:STDOUT: ] @@ -33,12 +33,11 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: ] // CHECK:STDOUT: types: [ // 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: {node: node+1, value_rep: {kind: unknown, type: type}}, +// CHECK:STDOUT: {node: nodeFloatingPointType, value_rep: {kind: copy, type: type2}}, +// CHECK:STDOUT: {node: node+3, value_rep: {kind: pointer, type: type4}}, +// CHECK:STDOUT: {node: node+5, value_rep: {kind: copy, type: type4}}, +// CHECK:STDOUT: {node: nodeFunctionType, value_rep: {kind: copy, type: type5}}, // CHECK:STDOUT: ] // CHECK:STDOUT: type_blocks: [ // CHECK:STDOUT: [ @@ -47,29 +46,28 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: type0, -// CHECK:STDOUT: type3, +// CHECK:STDOUT: type2, // 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: PointerType, arg0: type4, type: typeTypeType}, -// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type4}, -// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0, type: type6}, +// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type3}, +// CHECK:STDOUT: {kind: PointerType, arg0: type3, type: typeTypeType}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0, type: type5}, // 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+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: {kind: BinaryOperatorAdd, arg0: node+7, arg1: node+8, 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+9, arg1: node+12, type: type0}, +// CHECK:STDOUT: {kind: TupleAccess, arg0: node+4, arg1: member1, type: type2}, +// CHECK:STDOUT: {kind: InitializeFrom, arg0: node+10, arg1: node+14, type: type2}, +// CHECK:STDOUT: {kind: TupleInit, arg0: node+11, arg1: block6, type: type3}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+16}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ // CHECK:STDOUT: [ @@ -87,10 +85,9 @@ 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+7, // CHECK:STDOUT: node+8, // CHECK:STDOUT: node+9, // CHECK:STDOUT: node+10, @@ -101,22 +98,23 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: node+15, // CHECK:STDOUT: node+16, // CHECK:STDOUT: node+17, -// CHECK:STDOUT: node+18, // CHECK:STDOUT: ], // CHECK:STDOUT: [ +// CHECK:STDOUT: node+9, // CHECK:STDOUT: node+10, -// CHECK:STDOUT: node+11, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+14, -// CHECK:STDOUT: node+16, +// CHECK:STDOUT: node+13, +// CHECK:STDOUT: node+15, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, // CHECK:STDOUT: ], // CHECK:STDOUT: ] // CHECK:STDOUT: // CHECK:STDOUT: file "raw_and_textual_ir.carbon" { +// CHECK:STDOUT: %.loc11: type = ptr_type (i32, f64) // CHECK:STDOUT: %Foo: = fn_decl @Foo // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/basics/raw_ir.carbon b/toolchain/check/testdata/basics/raw_ir.carbon index b0a2ef371f7c..b5898760e98c 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: type4, return_slot: node+6, body: [block4]}, +// CHECK:STDOUT: {name: str0, param_refs: block1, return_type: type3, return_slot: node+4, body: [block4]}, // CHECK:STDOUT: ] // CHECK:STDOUT: classes: [ // CHECK:STDOUT: ] @@ -33,12 +33,11 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: ] // CHECK:STDOUT: types: [ // 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: {node: node+1, value_rep: {kind: unknown, type: type}}, +// CHECK:STDOUT: {node: nodeFloatingPointType, value_rep: {kind: copy, type: type2}}, +// CHECK:STDOUT: {node: node+3, value_rep: {kind: pointer, type: type4}}, +// CHECK:STDOUT: {node: node+5, value_rep: {kind: copy, type: type4}}, +// CHECK:STDOUT: {node: nodeFunctionType, value_rep: {kind: copy, type: type5}}, // CHECK:STDOUT: ] // CHECK:STDOUT: type_blocks: [ // CHECK:STDOUT: [ @@ -47,29 +46,28 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: type0, -// CHECK:STDOUT: type3, +// CHECK:STDOUT: type2, // 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: PointerType, arg0: type4, type: typeTypeType}, -// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type4}, -// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0, type: type6}, +// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type3}, +// CHECK:STDOUT: {kind: PointerType, arg0: type3, type: typeTypeType}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0, type: type5}, // 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+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: {kind: BinaryOperatorAdd, arg0: node+7, arg1: node+8, 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+9, arg1: node+12, type: type0}, +// CHECK:STDOUT: {kind: TupleAccess, arg0: node+4, arg1: member1, type: type2}, +// CHECK:STDOUT: {kind: InitializeFrom, arg0: node+10, arg1: node+14, type: type2}, +// CHECK:STDOUT: {kind: TupleInit, arg0: node+11, arg1: block6, type: type3}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+16}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ // CHECK:STDOUT: [ @@ -87,10 +85,9 @@ 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+7, // CHECK:STDOUT: node+8, // CHECK:STDOUT: node+9, // CHECK:STDOUT: node+10, @@ -101,17 +98,17 @@ fn Foo(n: i32) -> (i32, f64) { // CHECK:STDOUT: node+15, // CHECK:STDOUT: node+16, // CHECK:STDOUT: node+17, -// CHECK:STDOUT: node+18, // CHECK:STDOUT: ], // CHECK:STDOUT: [ +// CHECK:STDOUT: node+9, // CHECK:STDOUT: node+10, -// CHECK:STDOUT: node+11, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+14, -// CHECK:STDOUT: node+16, +// CHECK:STDOUT: node+13, +// CHECK:STDOUT: node+15, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, // CHECK:STDOUT: ], // CHECK:STDOUT: ] diff --git a/toolchain/check/testdata/basics/textual_ir.carbon b/toolchain/check/testdata/basics/textual_ir.carbon index 9bed1a5101e8..a48c46909c3d 100644 --- a/toolchain/check/testdata/basics/textual_ir.carbon +++ b/toolchain/check/testdata/basics/textual_ir.carbon @@ -13,6 +13,7 @@ fn Foo(n: i32) -> (i32, f64) { } // CHECK:STDOUT: file "textual_ir.carbon" { +// CHECK:STDOUT: %.loc11: type = ptr_type (i32, f64) // CHECK:STDOUT: %Foo: = fn_decl @Foo // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/fail_incomplete.carbon b/toolchain/check/testdata/class/fail_incomplete.carbon new file mode 100644 index 000000000000..2f8feeffea71 --- /dev/null +++ b/toolchain/check/testdata/class/fail_incomplete.carbon @@ -0,0 +1,169 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +class Class; + +// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+6]]:17: ERROR: Variable has incomplete type `Class`. +// CHECK:STDERR: var global_var: Class; +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-5]]:1: Class was forward declared here. +// CHECK:STDERR: class Class; +// CHECK:STDERR: ^ +var global_var: Class; + +// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+6]]:24: ERROR: Function returns incomplete type `Class`. +// CHECK:STDERR: fn ConvertFromStruct() -> Class { return {}; } +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-13]]:1: Class was forward declared here. +// CHECK:STDERR: class Class; +// CHECK:STDERR: ^ +fn ConvertFromStruct() -> Class { return {}; } + +// TODO: Once the `->` operator is supported: +// TODO: fn G(p: Class*) -> i32 { +// TODO: return p->n; +// TODO: } + +fn MemberAccess(p: Class*) -> i32 { + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE+9]]:11: ERROR: Invalid use of incomplete type `Class`. + // CHECK:STDERR: return (*p).n; + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE-27]]:1: Class was forward declared here. + // CHECK:STDERR: class Class; + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE+3]]:14: ERROR: Type `Class` does not support qualified expressions. + // CHECK:STDERR: return (*p).n; + // CHECK:STDERR: ^ + return (*p).n; +} + +// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+6]]:20: ERROR: Function returns incomplete type `Class`. +// CHECK:STDERR: fn Copy(p: Class*) -> Class { +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-39]]:1: Class was forward declared here. +// CHECK:STDERR: class Class; +// CHECK:STDERR: ^ +fn Copy(p: Class*) -> Class { + return *p; +} + +fn Let(p: Class*) { + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE+6]]:10: ERROR: `let` binding has incomplete type `Class`. + // CHECK:STDERR: let c: Class = *p; + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE-50]]:1: Class was forward declared here. + // CHECK:STDERR: class Class; + // CHECK:STDERR: ^ + let c: Class = *p; +} + +fn TakeIncomplete(c: Class); + +// TODO: We should allow this, and only reject calls to the function. +// +// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+6]]:23: ERROR: Function returns incomplete type `Class`. +// CHECK:STDERR: fn ReturnIncomplete() -> Class; +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_incomplete.carbon:[[@LINE-63]]:1: Class was forward declared here. +// CHECK:STDERR: class Class; +// CHECK:STDERR: ^ +fn ReturnIncomplete() -> Class; + +fn CallTakeIncomplete(p: Class*) { + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE+9]]:17: ERROR: Forming value of incomplete type `Class`. + // CHECK:STDERR: TakeIncomplete(*p); + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE-72]]:1: Class was forward declared here. + // CHECK:STDERR: class Class; + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE-19]]:1: Initializing parameter 1 of function declared here. + // CHECK:STDERR: fn TakeIncomplete(c: Class); + // CHECK:STDERR: ^ + TakeIncomplete(*p); + + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE+9]]:17: ERROR: Forming value of incomplete type `Class`. + // CHECK:STDERR: TakeIncomplete({}); + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE-83]]:1: Class was forward declared here. + // CHECK:STDERR: class Class; + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_incomplete.carbon:[[@LINE-30]]:1: Initializing parameter 1 of function declared here. + // CHECK:STDERR: fn TakeIncomplete(c: Class); + // CHECK:STDERR: ^ + TakeIncomplete({}); +} + +fn CallReturnIncomplete() { + ReturnIncomplete(); +} + +// CHECK:STDOUT: file "fail_incomplete.carbon" { +// CHECK:STDOUT: %Class: type = class_declaration @Class +// CHECK:STDOUT: %Class.ref: type = name_reference "Class", %Class +// CHECK:STDOUT: %global_var: ref = var "global_var" +// CHECK:STDOUT: %ConvertFromStruct: = fn_decl @ConvertFromStruct +// CHECK:STDOUT: %MemberAccess: = fn_decl @MemberAccess +// CHECK:STDOUT: %Copy: = fn_decl @Copy +// CHECK:STDOUT: %Let: = fn_decl @Let +// CHECK:STDOUT: %TakeIncomplete: = fn_decl @TakeIncomplete +// CHECK:STDOUT: %ReturnIncomplete: = fn_decl @ReturnIncomplete +// CHECK:STDOUT: %CallTakeIncomplete: = fn_decl @CallTakeIncomplete +// CHECK:STDOUT: %CallReturnIncomplete: = fn_decl @CallReturnIncomplete +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Class; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @ConvertFromStruct() -> { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc23_43.1: type = struct_type {} +// CHECK:STDOUT: %.loc23_43.2: {} = struct_literal () +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @MemberAccess(%p: Class*) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %p.ref: Class* = name_reference "p", %p +// CHECK:STDOUT: %.loc40: ref Class = dereference %p.ref +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Copy(%p: Class*) -> { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %p.ref: Class* = name_reference "p", %p +// CHECK:STDOUT: %.loc50: ref Class = dereference %p.ref +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Let(%p: Class*) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Class.ref: type = name_reference "Class", package.%Class +// CHECK:STDOUT: %p.ref: Class* = name_reference "p", %p +// CHECK:STDOUT: %.loc60: ref Class = dereference %p.ref +// CHECK:STDOUT: %c: = bind_name "c", +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TakeIncomplete(%c: Class); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @ReturnIncomplete() -> ; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @CallTakeIncomplete(%p: Class*) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TakeIncomplete.ref.loc85: = name_reference "TakeIncomplete", package.%TakeIncomplete +// CHECK:STDOUT: %p.ref: Class* = name_reference "p", %p +// CHECK:STDOUT: %.loc85_18: ref Class = dereference %p.ref +// CHECK:STDOUT: %.loc85_17: type = tuple_type () +// CHECK:STDOUT: %TakeIncomplete.ref.loc96: = name_reference "TakeIncomplete", package.%TakeIncomplete +// CHECK:STDOUT: %.loc96: {} = struct_literal () +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @CallReturnIncomplete() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %ReturnIncomplete.ref: = name_reference "ReturnIncomplete", package.%ReturnIncomplete +// CHECK:STDOUT: %.loc100: init = call %ReturnIncomplete.ref() +// CHECK:STDOUT: return +// CHECK:STDOUT: } diff --git a/toolchain/check/testdata/expression_category/in_place_tuple_initialization.carbon b/toolchain/check/testdata/expression_category/in_place_tuple_initialization.carbon index 43f32cd65008..c3e41b683ca7 100644 --- a/toolchain/check/testdata/expression_category/in_place_tuple_initialization.carbon +++ b/toolchain/check/testdata/expression_category/in_place_tuple_initialization.carbon @@ -17,6 +17,7 @@ fn H() -> i32 { } // CHECK:STDOUT: file "in_place_tuple_initialization.carbon" { +// CHECK:STDOUT: %.loc7: type = ptr_type (i32, i32) // CHECK:STDOUT: %F: = fn_decl @F // CHECK:STDOUT: %G: = fn_decl @G // CHECK:STDOUT: %H: = fn_decl @H diff --git a/toolchain/check/testdata/function/call/empty_struct.carbon b/toolchain/check/testdata/function/call/empty_struct.carbon index 699b6fb9d2e8..b63692909da6 100644 --- a/toolchain/check/testdata/function/call/empty_struct.carbon +++ b/toolchain/check/testdata/function/call/empty_struct.carbon @@ -13,6 +13,7 @@ fn Main() { } // CHECK:STDOUT: file "empty_struct.carbon" { +// CHECK:STDOUT: %.loc7: type = tuple_type () // CHECK:STDOUT: %Echo: = fn_decl @Echo // CHECK:STDOUT: %Main: = fn_decl @Main // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/if_expression/struct.carbon b/toolchain/check/testdata/if_expression/struct.carbon index a149c7f477ab..45579099ce14 100644 --- a/toolchain/check/testdata/if_expression/struct.carbon +++ b/toolchain/check/testdata/if_expression/struct.carbon @@ -21,6 +21,7 @@ fn F(cond: bool) { // CHECK:STDOUT: fn @F(%cond: bool) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc10_27: type = struct_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc7: type = ptr_type {.a: i32, .b: i32} // CHECK:STDOUT: %a: ref {.a: i32, .b: i32} = var "a" // CHECK:STDOUT: %.loc10_37: i32 = int_literal 1 // CHECK:STDOUT: %.loc10_45: i32 = int_literal 2 diff --git a/toolchain/check/testdata/index/array_element_access.carbon b/toolchain/check/testdata/index/array_element_access.carbon index d37996d573cb..703593991d70 100644 --- a/toolchain/check/testdata/index/array_element_access.carbon +++ b/toolchain/check/testdata/index/array_element_access.carbon @@ -17,16 +17,15 @@ var d: i32 = a[b]; // 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: 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: %.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: %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 8527dcc06dbb..04acd9d09c23 100644 --- a/toolchain/check/testdata/index/expression_category.carbon +++ b/toolchain/check/testdata/index/expression_category.carbon @@ -25,6 +25,7 @@ fn ValueBinding(b: [i32; 3]) { } // CHECK:STDOUT: file "expression_category.carbon" { +// CHECK:STDOUT: %.loc7: type = ptr_type [i32; 3] // CHECK:STDOUT: %F: = fn_decl @F // CHECK:STDOUT: %G: = fn_decl @G // CHECK:STDOUT: %ValueBinding: = fn_decl @ValueBinding @@ -41,19 +42,18 @@ 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: 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: %.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: %.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_expression_category.carbon b/toolchain/check/testdata/index/fail_expression_category.carbon index ae45b0f0f1a9..c3e5d088d038 100644 --- a/toolchain/check/testdata/index/fail_expression_category.carbon +++ b/toolchain/check/testdata/index/fail_expression_category.carbon @@ -30,6 +30,7 @@ fn G(b: [i32; 3]) { } // CHECK:STDOUT: file "fail_expression_category.carbon" { +// CHECK:STDOUT: %.loc7: type = ptr_type [i32; 3] // CHECK:STDOUT: %F: = fn_decl @F // CHECK:STDOUT: %G: = fn_decl @G // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/index/fail_invalid_base.carbon b/toolchain/check/testdata/index/fail_invalid_base.carbon index b530f6543ec8..0ebd6a3c9c53 100644 --- a/toolchain/check/testdata/index/fail_invalid_base.carbon +++ b/toolchain/check/testdata/index/fail_invalid_base.carbon @@ -45,10 +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: 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_29.2: {.a: i32, .b: i32} = struct_literal (%.loc26_20, %.loc26_28) // CHECK:STDOUT: %.loc26_31: i32 = int_literal 0 -// CHECK:STDOUT: %.loc26_29.4: {.a: i32, .b: i32} = struct_value %.loc26_29.3, (%.loc26_20, %.loc26_28) +// CHECK:STDOUT: %.loc26_29.3: type = ptr_type {.a: i32, .b: i32} +// CHECK:STDOUT: %.loc26_29.4: {.a: i32, .b: i32} = struct_value %.loc26_29.2, (%.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 78dd1bbc4014..f5d76fe291d7 100644 --- a/toolchain/check/testdata/index/fail_non_deterministic_type.carbon +++ b/toolchain/check/testdata/index/fail_non_deterministic_type.carbon @@ -13,10 +13,9 @@ 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 = 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: %.loc7_17.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.4: 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 b07ff69582a6..c187c93d64c1 100644 --- a/toolchain/check/testdata/index/fail_tuple_index_error.carbon +++ b/toolchain/check/testdata/index/fail_tuple_index_error.carbon @@ -12,10 +12,9 @@ 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 = 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: %.loc7_17.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.4: 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 8548c3cc46af..66aa8bd2b656 100644 --- a/toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon +++ b/toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon @@ -12,10 +12,9 @@ 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 = 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: %.loc7_17.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.4: 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 42cc31300bae..8d5cb8c1cb26 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,10 +12,9 @@ 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 = 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: %.loc7_17.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.4: 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 75c60c60ff07..f36e70acf1b1 100644 --- a/toolchain/check/testdata/let/convert.carbon +++ b/toolchain/check/testdata/let/convert.carbon @@ -18,10 +18,9 @@ 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 = 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: %.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.4: 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 819571ddfcae..656acc98a059 100644 --- a/toolchain/check/testdata/operators/assignment.carbon +++ b/toolchain/check/testdata/operators/assignment.carbon @@ -35,10 +35,9 @@ 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 = 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: %.loc11_19.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc11_19.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc11_19.4: 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 diff --git a/toolchain/check/testdata/operators/fail_assigment_to_non_assignable.carbon b/toolchain/check/testdata/operators/fail_assignment_to_non_assignable.carbon similarity index 80% rename from toolchain/check/testdata/operators/fail_assigment_to_non_assignable.carbon rename to toolchain/check/testdata/operators/fail_assignment_to_non_assignable.carbon index 5acce19a42b2..dc8d5630ba5c 100644 --- a/toolchain/check/testdata/operators/fail_assigment_to_non_assignable.carbon +++ b/toolchain/check/testdata/operators/fail_assignment_to_non_assignable.carbon @@ -7,45 +7,45 @@ fn F() -> i32; fn Main() { - // CHECK:STDERR: fail_assigment_to_non_assignable.carbon:[[@LINE+3]]:3: ERROR: Expression is not assignable. + // CHECK:STDERR: fail_assignment_to_non_assignable.carbon:[[@LINE+3]]:3: ERROR: Expression is not assignable. // CHECK:STDERR: 1 = 2; // CHECK:STDERR: ^ 1 = 2; - // CHECK:STDERR: fail_assigment_to_non_assignable.carbon:[[@LINE+3]]:5: ERROR: Expression is not assignable. + // CHECK:STDERR: fail_assignment_to_non_assignable.carbon:[[@LINE+3]]:5: ERROR: Expression is not assignable. // CHECK:STDERR: F() = 1; // CHECK:STDERR: ^ F() = 1; - // CHECK:STDERR: fail_assigment_to_non_assignable.carbon:[[@LINE+3]]:8: ERROR: Expression is not assignable. + // CHECK:STDERR: fail_assignment_to_non_assignable.carbon:[[@LINE+3]]:8: ERROR: Expression is not assignable. // CHECK:STDERR: (1, 2) = (3, 4); // CHECK:STDERR: ^ (1, 2) = (3, 4); var n: i32 = 0; - // CHECK:STDERR: fail_assigment_to_non_assignable.carbon:[[@LINE+3]]:8: ERROR: Expression is not assignable. + // CHECK:STDERR: fail_assignment_to_non_assignable.carbon:[[@LINE+3]]:8: ERROR: Expression is not assignable. // CHECK:STDERR: (n, n) = (1, 2); // CHECK:STDERR: ^ (n, n) = (1, 2); - // CHECK:STDERR: fail_assigment_to_non_assignable.carbon:[[@LINE+3]]:3: ERROR: Expression is not assignable. + // CHECK:STDERR: fail_assignment_to_non_assignable.carbon:[[@LINE+3]]:3: ERROR: Expression is not assignable. // CHECK:STDERR: i32 = i32*; // CHECK:STDERR: ^ i32 = i32*; - // CHECK:STDERR: fail_assigment_to_non_assignable.carbon:[[@LINE+3]]:18: ERROR: Expression is not assignable. + // CHECK:STDERR: fail_assignment_to_non_assignable.carbon:[[@LINE+3]]:18: ERROR: Expression is not assignable. // CHECK:STDERR: {.x = 1, .y = 2} = {.x = 3, .y = 4}; // CHECK:STDERR: ^ {.x = 1, .y = 2} = {.x = 3, .y = 4}; - // CHECK:STDERR: fail_assigment_to_non_assignable.carbon:[[@LINE+3]]:25: ERROR: Expression is not assignable. + // CHECK:STDERR: fail_assignment_to_non_assignable.carbon:[[@LINE+3]]:25: ERROR: Expression is not assignable. // CHECK:STDERR: (if true then 1 else 2) = 3; // CHECK:STDERR: ^ (if true then 1 else 2) = 3; // Under #911, if expressions are never reference expressions. var a: i32; - // CHECK:STDERR: fail_assigment_to_non_assignable.carbon:[[@LINE+3]]:25: ERROR: Expression is not assignable. + // CHECK:STDERR: fail_assignment_to_non_assignable.carbon:[[@LINE+3]]:25: ERROR: Expression is not assignable. // CHECK:STDERR: (if true then a else a) = 10; // CHECK:STDERR: ^ (if true then a else a) = 10; } -// CHECK:STDOUT: file "fail_assigment_to_non_assignable.carbon" { +// CHECK:STDOUT: file "fail_assignment_to_non_assignable.carbon" { // CHECK:STDOUT: %F: = fn_decl @F // CHECK:STDOUT: %Main: = fn_decl @Main // CHECK:STDOUT: } @@ -64,18 +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: type = ptr_type (i32, i32) -// CHECK:STDOUT: %.loc21_8.3: (i32, i32) = tuple_literal (%.loc21_4, %.loc21_7) +// CHECK:STDOUT: %.loc21_8.2: (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.3, member0 +// CHECK:STDOUT: %.loc21_8.3: type = ptr_type (i32, i32) +// CHECK:STDOUT: %.loc21_17.2: i32 = tuple_access %.loc21_8.2, 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.3, member1 +// CHECK:STDOUT: %.loc21_17.4: i32 = tuple_access %.loc21_8.2, 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.3, %.loc21_17.6 -// CHECK:STDOUT: %.loc21_8.4: (i32, i32) = tuple_value %.loc21_8.3, (%.loc21_4, %.loc21_7) +// CHECK:STDOUT: assign %.loc21_8.2, %.loc21_17.6 +// CHECK:STDOUT: %.loc21_8.4: (i32, i32) = tuple_value %.loc21_8.2, (%.loc21_4, %.loc21_7) // CHECK:STDOUT: %n: ref i32 = var "n" // CHECK:STDOUT: %.loc22: i32 = int_literal 0 // CHECK:STDOUT: assign %n, %.loc22 @@ -99,18 +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: 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_18.2: {.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.3, member0 +// CHECK:STDOUT: %.loc34_18.3: type = ptr_type {.x: i32, .y: i32} +// CHECK:STDOUT: %.loc34_37.2: i32 = struct_access %.loc34_18.2, 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.3, member1 +// CHECK:STDOUT: %.loc34_37.4: i32 = struct_access %.loc34_18.2, 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.3, %.loc34_37.6 -// CHECK:STDOUT: %.loc34_18.4: {.x: i32, .y: i32} = struct_value %.loc34_18.3, (%.loc34_9, %.loc34_17) +// CHECK:STDOUT: assign %.loc34_18.2, %.loc34_37.6 +// CHECK:STDOUT: %.loc34_18.4: {.x: i32, .y: i32} = struct_value %.loc34_18.2, (%.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 e98aaf7e548f..1b687682fc70 100644 --- a/toolchain/check/testdata/pointer/address_of_lvalue.carbon +++ b/toolchain/check/testdata/pointer/address_of_lvalue.carbon @@ -53,10 +53,9 @@ 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 = 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: %.loc14_19.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc14_19.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc14_19.4: 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 94c86ab7bfb4..4e0736f3dd8e 100644 --- a/toolchain/check/testdata/pointer/fail_address_of_value.carbon +++ b/toolchain/check/testdata/pointer/fail_address_of_value.carbon @@ -114,9 +114,9 @@ fn AddressOfParameter(param: i32) { // 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: 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: %.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: %.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/return/tuple.carbon b/toolchain/check/testdata/return/tuple.carbon index 3e2d1fcda9a7..3bf5c1813fbf 100644 --- a/toolchain/check/testdata/return/tuple.carbon +++ b/toolchain/check/testdata/return/tuple.carbon @@ -10,6 +10,7 @@ fn Main() -> (i32, i32) { } // CHECK:STDOUT: file "tuple.carbon" { +// CHECK:STDOUT: %.loc8: type = ptr_type (i32, i32) // CHECK:STDOUT: %Main: = fn_decl @Main // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/struct/empty.carbon b/toolchain/check/testdata/struct/empty.carbon index 9a6d03265964..0c91dc7ae234 100644 --- a/toolchain/check/testdata/struct/empty.carbon +++ b/toolchain/check/testdata/struct/empty.carbon @@ -9,8 +9,8 @@ var y: {} = x; // CHECK:STDOUT: file "empty.carbon" { // CHECK:STDOUT: %.loc7_9.1: type = struct_type {} -// CHECK:STDOUT: %.loc7_9.2: type = tuple_type () -// CHECK:STDOUT: %.loc7_9.3: {} = struct_literal () +// CHECK:STDOUT: %.loc7_9.2: {} = struct_literal () +// CHECK:STDOUT: %.loc7_9.3: type = tuple_type () // 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 7b5afbd5017f..8bb50da638f8 100644 --- a/toolchain/check/testdata/struct/fail_assign_empty.carbon +++ b/toolchain/check/testdata/struct/fail_assign_empty.carbon @@ -13,7 +13,6 @@ 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: type = tuple_type () -// CHECK:STDOUT: %.loc10_21.3: {} = struct_literal () +// CHECK:STDOUT: %.loc10_21.2: {} = 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 9831b1fd20b0..d205599f0879 100644 --- a/toolchain/check/testdata/struct/fail_assign_nested.carbon +++ b/toolchain/check/testdata/struct/fail_assign_nested.carbon @@ -11,14 +11,13 @@ var x: {.a: {}} = {.b = {}}; // CHECK:STDOUT: file "fail_assign_nested.carbon" { // CHECK:STDOUT: %.loc10_14.1: type = struct_type {} -// CHECK:STDOUT: %.loc10_14.2: type = tuple_type () -// CHECK:STDOUT: %.loc10_14.3: {} = struct_literal () +// CHECK:STDOUT: %.loc10_14.2: {} = struct_literal () // CHECK:STDOUT: %.loc10_15.1: type = struct_type {.a: {}} +// CHECK:STDOUT: %.loc10_14.3: type = tuple_type () // 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: type = struct_type {.b: ()} -// CHECK:STDOUT: %.loc10_27.3: {.b: {}} = struct_literal (%.loc10_26) +// CHECK:STDOUT: %.loc10_27.2: {.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 5e92a7baa626..52862c1c7122 100644 --- a/toolchain/check/testdata/struct/fail_assign_to_empty.carbon +++ b/toolchain/check/testdata/struct/fail_assign_to_empty.carbon @@ -11,8 +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: type = tuple_type () -// CHECK:STDOUT: %.loc10_9.3: {} = struct_literal () +// CHECK:STDOUT: %.loc10_9.2: {} = struct_literal () +// CHECK:STDOUT: %.loc10_9.3: type = tuple_type () // 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_nested_incomplete.carbon b/toolchain/check/testdata/struct/fail_nested_incomplete.carbon new file mode 100644 index 000000000000..d7c5bd56f1e7 --- /dev/null +++ b/toolchain/check/testdata/struct/fail_nested_incomplete.carbon @@ -0,0 +1,36 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +class Incomplete; + +// CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE+6]]:23: ERROR: Variable has incomplete type `{.a: Incomplete}`. +// CHECK:STDERR: var s: {.a: Incomplete}; +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE-5]]:1: Class was forward declared here. +// CHECK:STDERR: class Incomplete; +// CHECK:STDERR: ^ +var s: {.a: Incomplete}; + +// CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE+3]]:26: ERROR: Cannot implicitly convert from `*` to `Incomplete*`. +// CHECK:STDERR: var p: Incomplete* = &s.a; +// CHECK:STDERR: ^ +var p: Incomplete* = &s.a; + +// CHECK:STDOUT: file "fail_nested_incomplete.carbon" { +// CHECK:STDOUT: %Incomplete: type = class_declaration @Incomplete +// CHECK:STDOUT: %Incomplete.ref.loc15: type = name_reference "Incomplete", %Incomplete +// CHECK:STDOUT: %.loc15: type = struct_type {.a: Incomplete} +// CHECK:STDOUT: %s: ref = var "s" +// CHECK:STDOUT: %Incomplete.ref.loc20: type = name_reference "Incomplete", %Incomplete +// CHECK:STDOUT: %.loc20_18: type = ptr_type Incomplete +// CHECK:STDOUT: %p: ref Incomplete* = var "p" +// CHECK:STDOUT: %s.ref: ref = name_reference "s", %s +// CHECK:STDOUT: %.loc20_22.1: type = ptr_type +// CHECK:STDOUT: %.loc20_22.2: * = address_of +// CHECK:STDOUT: assign %p, +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Incomplete; diff --git a/toolchain/check/testdata/struct/literal_member_access.carbon b/toolchain/check/testdata/struct/literal_member_access.carbon index d096aab76b91..5ed6537b41a4 100644 --- a/toolchain/check/testdata/struct/literal_member_access.carbon +++ b/toolchain/check/testdata/struct/literal_member_access.carbon @@ -11,6 +11,7 @@ fn F() -> i32 { } // CHECK:STDOUT: file "literal_member_access.carbon" { +// CHECK:STDOUT: %.loc7: type = ptr_type {.x: i32, .y: i32, .z: i32} // CHECK:STDOUT: %G: = fn_decl @G // CHECK:STDOUT: %F: = fn_decl @F // CHECK:STDOUT: } @@ -25,9 +26,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: 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_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.3: type = struct_type {.a: i32, .b: {.x: i32, .y: i32, .z: i32}*, .c: i32} +// CHECK:STDOUT: %.loc10_35.4: type = ptr_type {.a: i32, .b: {.x: i32, .y: i32, .z: i32}*, .c: i32} // 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 @@ -36,7 +37,7 @@ 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.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_35.5: {.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.5, member1 // CHECK:STDOUT: %.loc10_38: i32 = struct_access %.loc10_36, member1 // CHECK:STDOUT: return %.loc10_38 diff --git a/toolchain/check/testdata/struct/nested_struct_in_place.carbon b/toolchain/check/testdata/struct/nested_struct_in_place.carbon index ecbefc3dfef9..bb91f9f14f7d 100644 --- a/toolchain/check/testdata/struct/nested_struct_in_place.carbon +++ b/toolchain/check/testdata/struct/nested_struct_in_place.carbon @@ -11,6 +11,7 @@ fn G() { } // CHECK:STDOUT: file "nested_struct_in_place.carbon" { +// CHECK:STDOUT: %.loc7: type = ptr_type (i32, i32, i32) // CHECK:STDOUT: %F: = fn_decl @F // CHECK:STDOUT: %G: = fn_decl @G // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/tuples/fail_assign_nested.carbon b/toolchain/check/testdata/tuples/fail_assign_nested.carbon index 06f0918ee5e8..0e095e1ab023 100644 --- a/toolchain/check/testdata/tuples/fail_assign_nested.carbon +++ b/toolchain/check/testdata/tuples/fail_assign_nested.carbon @@ -11,32 +11,26 @@ 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 = ptr_type (type, type) -// CHECK:STDOUT: %.loc10_18.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc10_18.2: (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 = 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: %.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.5: type = ptr_type (i32, i32) +// CHECK:STDOUT: %.loc10_31.6: type = tuple_type ((i32, i32)*, (i32, i32)*) +// CHECK:STDOUT: %.loc10_31.7: 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: 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_44.2: (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: 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: %.loc10_56.2: ((i32, i32, i32), (i32, i32, i32)) = tuple_literal (%.loc10_44.2, %.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 123dda82778f..e6cb299266cb 100644 --- a/toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon +++ b/toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon @@ -11,17 +11,15 @@ 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 = 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: %.loc10_17.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc10_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc10_17.4: 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: 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: %.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: assign %x, // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/tuples/fail_nested_incomplete.carbon b/toolchain/check/testdata/tuples/fail_nested_incomplete.carbon new file mode 100644 index 000000000000..ea06d602aecd --- /dev/null +++ b/toolchain/check/testdata/tuples/fail_nested_incomplete.carbon @@ -0,0 +1,39 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +class Incomplete; + +// CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE+6]]:24: ERROR: Variable has incomplete type `(i32, Incomplete)`. +// CHECK:STDERR: var t: (i32, Incomplete); +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE-5]]:1: Class was forward declared here. +// CHECK:STDERR: class Incomplete; +// CHECK:STDERR: ^ +var t: (i32, Incomplete); + +// CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE+3]]:27: ERROR: Cannot implicitly convert from `*` to `Incomplete*`. +// CHECK:STDERR: var p: Incomplete* = &t[1]; +// CHECK:STDERR: ^ +var p: Incomplete* = &t[1]; + +// CHECK:STDOUT: file "fail_nested_incomplete.carbon" { +// CHECK:STDOUT: %Incomplete: type = class_declaration @Incomplete +// CHECK:STDOUT: %Incomplete.ref.loc15: type = name_reference "Incomplete", %Incomplete +// CHECK:STDOUT: %.loc15_24.1: type = tuple_type (type, type) +// CHECK:STDOUT: %.loc15_24.2: (type, type) = tuple_literal (i32, %Incomplete.ref.loc15) +// CHECK:STDOUT: %.loc15_24.3: type = tuple_type (i32, Incomplete) +// CHECK:STDOUT: %t: ref = var "t" +// CHECK:STDOUT: %Incomplete.ref.loc20: type = name_reference "Incomplete", %Incomplete +// CHECK:STDOUT: %.loc20_18: type = ptr_type Incomplete +// CHECK:STDOUT: %p: ref Incomplete* = var "p" +// CHECK:STDOUT: %t.ref: ref = name_reference "t", %t +// CHECK:STDOUT: %.loc20_25: i32 = int_literal 1 +// CHECK:STDOUT: %.loc20_22.1: type = ptr_type +// CHECK:STDOUT: %.loc20_22.2: * = address_of +// CHECK:STDOUT: assign %p, +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Incomplete; diff --git a/toolchain/check/testdata/tuples/fail_too_few_element.carbon b/toolchain/check/testdata/tuples/fail_too_few_element.carbon index e0c7b28486fc..002e9b488a38 100644 --- a/toolchain/check/testdata/tuples/fail_too_few_element.carbon +++ b/toolchain/check/testdata/tuples/fail_too_few_element.carbon @@ -11,10 +11,9 @@ 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 = 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: %.loc10_17.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc10_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc10_17.4: 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 a5f72a0edc2d..7519202c50c2 100644 --- a/toolchain/check/testdata/tuples/nested_tuple.carbon +++ b/toolchain/check/testdata/tuples/nested_tuple.carbon @@ -8,17 +8,14 @@ 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 = ptr_type (type, type) -// CHECK:STDOUT: %.loc7_18.3: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_18.2: (type, type) = tuple_literal (i32, i32) // CHECK:STDOUT: %.loc7_24.1: type = tuple_type ((type, type), type) -// 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: %.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.5: type = ptr_type (i32, i32) +// CHECK:STDOUT: %.loc7_24.6: type = tuple_type ((i32, i32)*, i32) +// CHECK:STDOUT: %.loc7_24.7: 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 052fda770897..b2140cade670 100644 --- a/toolchain/check/testdata/tuples/nested_tuple_in_place.carbon +++ b/toolchain/check/testdata/tuples/nested_tuple_in_place.carbon @@ -15,6 +15,7 @@ fn H() { } // CHECK:STDOUT: file "nested_tuple_in_place.carbon" { +// CHECK:STDOUT: %.loc7: type = ptr_type (i32, i32, i32) // CHECK:STDOUT: %F: = fn_decl @F // CHECK:STDOUT: %G: = fn_decl @G // CHECK:STDOUT: %H: = fn_decl @H @@ -27,12 +28,10 @@ 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 = 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: %.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.4: type = tuple_type ((i32, i32, i32)*, (i32, i32, i32)*) +// CHECK:STDOUT: %.loc10_43.5: 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 @@ -50,12 +49,10 @@ 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 = 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: %.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.4: type = tuple_type (i32, (i32, i32, i32)*, i32) +// CHECK:STDOUT: %.loc14_36.5: 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 ef71ba7c5cb4..ab250e4e35d6 100644 --- a/toolchain/check/testdata/tuples/two_elements.carbon +++ b/toolchain/check/testdata/tuples/two_elements.carbon @@ -9,10 +9,9 @@ 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 = 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: %.loc7_17.2: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc7_17.3: type = tuple_type (i32, i32) +// CHECK:STDOUT: %.loc7_17.4: 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/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 8a794c69ce6a..fcc41218beba 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -115,6 +115,7 @@ CARBON_DIAGNOSTIC_KIND(ArrayInitFromLiteralArgCountMismatch) CARBON_DIAGNOSTIC_KIND(ArrayInitFromExpressionArgCountMismatch) CARBON_DIAGNOSTIC_KIND(AssignmentToNonAssignable) CARBON_DIAGNOSTIC_KIND(BreakOutsideLoop) +CARBON_DIAGNOSTIC_KIND(ClassForwardDeclaredHere) CARBON_DIAGNOSTIC_KIND(ContinueOutsideLoop) CARBON_DIAGNOSTIC_KIND(DereferenceOfNonPointer) CARBON_DIAGNOSTIC_KIND(DereferenceOfType) @@ -126,6 +127,13 @@ CARBON_DIAGNOSTIC_KIND(InCallToFunction) CARBON_DIAGNOSTIC_KIND(InCallToFunctionParam) CARBON_DIAGNOSTIC_KIND(MissingReturnStatement) CARBON_DIAGNOSTIC_KIND(RepeatedConst) +CARBON_DIAGNOSTIC_KIND(IncompleteTypeInConversion) +CARBON_DIAGNOSTIC_KIND(IncompleteTypeInFunctionParam) +CARBON_DIAGNOSTIC_KIND(IncompleteTypeInFunctionReturnType) +CARBON_DIAGNOSTIC_KIND(IncompleteTypeInInitialization) +CARBON_DIAGNOSTIC_KIND(IncompleteTypeInLetDeclaration) +CARBON_DIAGNOSTIC_KIND(IncompleteTypeInValueConversion) +CARBON_DIAGNOSTIC_KIND(IncompleteTypeInVarDeclaration) CARBON_DIAGNOSTIC_KIND(InvalidArrayExpression) CARBON_DIAGNOSTIC_KIND(TypeNotIndexable) CARBON_DIAGNOSTIC_KIND(IndexOutOfBounds) diff --git a/toolchain/lower/testdata/pointer/address_of_unused.carbon b/toolchain/lower/testdata/pointer/address_of_unused.carbon new file mode 100644 index 000000000000..7f91e2eae275 --- /dev/null +++ b/toolchain/lower/testdata/pointer/address_of_unused.carbon @@ -0,0 +1,19 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +fn F() { + var n: i32 = 0; + &n; +} + +// CHECK:STDOUT: ; ModuleID = 'address_of_unused.carbon' +// CHECK:STDOUT: source_filename = "address_of_unused.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define void @F() { +// CHECK:STDOUT: %n = alloca i32, align 4 +// CHECK:STDOUT: store i32 0, ptr %n, align 4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 01a70121d216..1dd775f49926 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -85,8 +85,7 @@ struct ValueRepresentation : public Printable { 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. + // types. Unknown, // The type has no value representation. This is used for empty types, such // as `()`, where there is no value. @@ -115,8 +114,9 @@ struct TypeInfo : public Printable { // The node that defines this type. NodeId node_id; - // The value representation for this type. - ValueRepresentation value_representation; + // The value representation for this type. Will be `Unknown` if the type is + // not complete. + ValueRepresentation value_representation = ValueRepresentation(); }; // Provides semantic analysis on a Parse::Tree. @@ -342,9 +342,7 @@ 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 = node_id, - .value_representation = {.kind = ValueRepresentation::Unknown}}); + types_.push_back({.node_id = node_id}); return type_id; } @@ -393,6 +391,12 @@ class File : public Printable { return types_[type_id.index].value_representation; } + // Determines whether the given type is known to be complete. This does not + // determine whether the type could be completed, only whether it has been. + auto IsTypeComplete(TypeId type_id) const -> bool { + return GetValueRepresentation(type_id).kind != ValueRepresentation::Unknown; + } + // 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; diff --git a/toolchain/sem_ir/node.h b/toolchain/sem_ir/node.h index ca40407a494f..c94e2d920316 100644 --- a/toolchain/sem_ir/node.h +++ b/toolchain/sem_ir/node.h @@ -27,6 +27,12 @@ struct NodeId : public IndexBase, public Printable { static const NodeId Builtin##Name; #include "toolchain/sem_ir/builtin_kind.def" + // Returns the cross-reference node ID for a builtin. This relies on File + // guarantees for builtin cross-reference placement. + static constexpr auto ForBuiltin(BuiltinKind kind) -> NodeId { + return NodeId(kind.AsInt()); + } + using IndexBase::IndexBase; auto Print(llvm::raw_ostream& out) const -> void { out << "node"; @@ -44,10 +50,9 @@ struct NodeId : public IndexBase, public Printable { constexpr NodeId NodeId::Invalid = NodeId(NodeId::InvalidIndex); -// Uses the cross-reference node ID for a builtin. This relies on File -// guarantees for builtin cross-reference placement. #define CARBON_SEMANTICS_BUILTIN_KIND_NAME(Name) \ - constexpr NodeId NodeId::Builtin##Name = NodeId(BuiltinKind::Name.AsInt()); + constexpr NodeId NodeId::Builtin##Name = \ + NodeId::ForBuiltin(BuiltinKind::Name); #include "toolchain/sem_ir/builtin_kind.def" // The ID of a function.