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.