From 475ecca3396d9abd7a2b183f3147a04741e629d7 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Thu, 8 Feb 2024 16:11:37 -0800 Subject: [PATCH] Implement constant handling for types of imports. (#3693) This provides support for Const, Pointer, Struct, and Tuple types. It does not cover Class, Function, or Interface which have their own Id and are tracked slightly differently. --- toolchain/check/BUILD | 2 + toolchain/check/check.cpp | 5 + toolchain/check/context.cpp | 50 +--- toolchain/check/context.h | 15 +- toolchain/check/import_ref.cpp | 275 ++++++++++++++++++ toolchain/check/import_ref.h | 19 ++ .../testdata/class/fail_todo_import.carbon | 90 +++++- toolchain/check/testdata/const/basic.carbon | 42 +++ .../testdata/const/fail_todo_import.carbon | 60 ---- toolchain/check/testdata/const/import.carbon | 79 +++++ .../packages/fail_import_type_error.carbon | 85 ++++++ ...{fail_todo_import.carbon => import.carbon} | 13 +- .../testdata/struct/fail_todo_import.carbon | 58 ---- toolchain/check/testdata/struct/import.carbon | 134 +++++++++ .../testdata/tuples/fail_todo_import.carbon | 62 ---- toolchain/check/testdata/tuples/import.carbon | 169 +++++++++++ toolchain/check/testdata/var/import.carbon | 3 - 17 files changed, 909 insertions(+), 252 deletions(-) create mode 100644 toolchain/check/import_ref.cpp create mode 100644 toolchain/check/import_ref.h create mode 100644 toolchain/check/testdata/const/basic.carbon delete mode 100644 toolchain/check/testdata/const/fail_todo_import.carbon create mode 100644 toolchain/check/testdata/const/import.carbon create mode 100644 toolchain/check/testdata/packages/fail_import_type_error.carbon rename toolchain/check/testdata/pointer/{fail_todo_import.carbon => import.carbon} (78%) delete mode 100644 toolchain/check/testdata/struct/fail_todo_import.carbon create mode 100644 toolchain/check/testdata/struct/import.carbon delete mode 100644 toolchain/check/testdata/tuples/fail_todo_import.carbon create mode 100644 toolchain/check/testdata/tuples/import.carbon diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index 907f4668ef3a..e7824d0ea772 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -54,6 +54,8 @@ cc_library( "convert.cpp", "decl_name_stack.cpp", "eval.cpp", + "import_ref.cpp", + "import_ref.h", "inst_block_stack.cpp", "modifiers.cpp", "return.cpp", diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index 4af321705e0b..af1d49e90a2e 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -16,6 +16,7 @@ #include "toolchain/sem_ir/file.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/typed_insts.h" +#include "toolchain/sem_ir/value_stores.h" namespace Carbon::Check { @@ -196,6 +197,10 @@ static auto InitPackageScopeAndImports(Context& context, UnitInfo& unit_info) context.AddPackageImports(package_imports.node, package_id, sem_irs, package_imports.has_load_error); } + + context.import_ir_constant_values().resize( + context.import_irs().size(), + SemIR::ConstantValueStore(SemIR::ConstantId::Invalid)); } // Loops over all nodes in the tree. On some errors, this may return early, diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 7fa5da35c2cd..124da69dd312 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -12,8 +12,10 @@ #include "llvm/ADT/Sequence.h" #include "toolchain/check/decl_name_stack.h" #include "toolchain/check/eval.h" +#include "toolchain/check/import_ref.h" #include "toolchain/check/inst_block_stack.h" #include "toolchain/lex/tokenized_buffer.h" +#include "toolchain/parse/node_ids.h" #include "toolchain/parse/node_kind.h" #include "toolchain/sem_ir/builtin_kind.h" #include "toolchain/sem_ir/file.h" @@ -228,45 +230,6 @@ auto Context::AddNameToLookup(SemIR::NameId name_id, SemIR::InstId target_id) } } -auto Context::ResolveIfImportRefUnused(SemIR::InstId inst_id) -> void { - auto inst = insts().Get(inst_id); - auto unused_inst = inst.TryAs(); - if (!unused_inst) { - return; - } - const SemIR::File& import_ir = *import_irs().Get(unused_inst->ir_id); - auto import_inst = import_ir.insts().Get(unused_inst->inst_id); - - // If the type ID isn't a normal value, forward it directly. - if (!import_inst.type_id().is_valid()) { - ReplaceInstBeforeConstantUse( - inst_id, - {SemIR::ImportRefUsed{import_inst.type_id(), unused_inst->ir_id, - unused_inst->inst_id}}); - return; - } - - auto import_type_inst_id = import_ir.types().GetInstId(import_inst.type_id()); - CARBON_CHECK(import_type_inst_id.is_valid()); - - // If the type of the instruction is a builtin, use it directly. - auto type_id = SemIR::TypeId::Invalid; - if (import_type_inst_id.is_builtin()) { - type_id = GetBuiltinType(import_type_inst_id.builtin_kind()); - } else { - // TODO: This section probably needs to TryEvalInst for the type. Similar to - // GetTypeImpl, but in the context of import_ir. - TODO(Parse::NodeId::Invalid, - "TODO: ResolveIfImportRefUnused for non-builtin type"); - type_id = SemIR::TypeId::Error; - } - - // TODO: Add breadcrumbs for lowering. - ReplaceInstBeforeConstantUse( - inst_id, {SemIR::ImportRefUsed{type_id, unused_inst->ir_id, - unused_inst->inst_id}}); -} - auto Context::LookupNameInDecl(Parse::NodeId /*parse_node*/, SemIR::NameId name_id, SemIR::NameScopeId scope_id) -> SemIR::InstId { @@ -296,7 +259,7 @@ auto Context::LookupNameInDecl(Parse::NodeId /*parse_node*/, // name A from the outer scope. auto result = scope_stack().LookupInCurrentScope(name_id); if (result.is_valid()) { - ResolveIfImportRefUnused(result); + TryResolveImportRefUnused(*this, result); } return result; } else { @@ -333,7 +296,7 @@ auto Context::LookupUnqualifiedName(Parse::NodeId parse_node, } if (lexical_result.is_valid()) { - ResolveIfImportRefUnused(lexical_result); + TryResolveImportRefUnused(*this, lexical_result); return lexical_result; } @@ -346,7 +309,7 @@ auto Context::LookupNameInExactScope(SemIR::NameId name_id, const SemIR::NameScope& scope) -> SemIR::InstId { if (auto it = scope.names.find(name_id); it != scope.names.end()) { - ResolveIfImportRefUnused(it->second); + TryResolveImportRefUnused(*this, it->second); return it->second; } return SemIR::InstId::Invalid; @@ -985,7 +948,8 @@ auto Context::TryToCompleteType( auto Context::GetTypeIdForTypeConstant(SemIR::ConstantId constant_id) -> SemIR::TypeId { - CARBON_CHECK(constant_id.is_constant()) << "Canonicalizing non-constant type"; + CARBON_CHECK(constant_id.is_constant()) + << "Canonicalizing non-constant type: " << constant_id; auto [it, added] = type_ids_for_type_constants_.insert( {constant_id, SemIR::TypeId::Invalid}); diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 0f4cffa742f2..0cbebc1188b2 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -337,6 +337,11 @@ class Context { return scope_stack().break_continue_stack(); } + auto import_ir_constant_values() + -> llvm::SmallVector& { + return import_ir_constant_values_; + } + // Directly expose SemIR::File data accessors for brevity in calls. auto identifiers() -> StringStoreWrapper& { @@ -394,10 +399,6 @@ class Context { SemIR::TypeId type_id_; }; - // If the passed in instruction ID is a ImportRefUnused, resolves it for use. - // Called when name lookup intends to return an inst_id. - auto ResolveIfImportRefUnused(SemIR::InstId inst_id) -> void; - // Tokens for getting data on literals. const Lex::TokenizedBuffer* tokens_; @@ -452,6 +453,12 @@ class Context { // The list which will form NodeBlockId::Exports. llvm::SmallVector exports_; + + // Per-import constant values. These refer to the main IR and mainly serve as + // a lookup table for quick access. + // + // Inline 0 elements because it's expected to require heap allocation. + llvm::SmallVector import_ir_constant_values_; }; } // namespace Carbon::Check diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp new file mode 100644 index 000000000000..8844b4fe1c55 --- /dev/null +++ b/toolchain/check/import_ref.cpp @@ -0,0 +1,275 @@ +// 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 + +#include "toolchain/check/import_ref.h" + +#include "common/check.h" +#include "toolchain/check/context.h" +#include "toolchain/check/eval.h" +#include "toolchain/parse/node_ids.h" +#include "toolchain/sem_ir/file.h" +#include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/inst.h" +#include "toolchain/sem_ir/inst_kind.h" +#include "toolchain/sem_ir/typed_insts.h" +#include "toolchain/sem_ir/value_stores.h" + +namespace Carbon::Check { + +// Resolves an instruction from an imported IR into a constant referring to the +// current IR. +class ImportRefResolver { + public: + explicit ImportRefResolver( + Context& context, const SemIR::File& import_ir, + SemIR::ConstantValueStore& import_ir_constant_values) + : context_(context), + import_ir_(import_ir), + import_ir_constant_values_(import_ir_constant_values) {} + + // Iteratively resolves an imported instruction's inner references until a + // constant ID referencing the current IR is produced. When an outer + // instruction has unresolved inner references, it will add them to the stack + // for inner evaluation and reattempt outer evaluation after. + auto Resolve(SemIR::InstId inst_id) -> SemIR::ConstantId { + work_stack_.push_back(inst_id); + while (!work_stack_.empty()) { + auto inst_id = work_stack_.back(); + CARBON_CHECK(inst_id.is_valid()); + + // Double-check that the constant still doesn't have a calculated value. + // This should typically be checked before adding it, but a given constant + // may be added multiple times before its constant is evaluated. + if (auto current_const_id = import_ir_constant_values_.Get(inst_id); + current_const_id.is_valid()) { + work_stack_.pop_back(); + } else if (auto new_const_id = TryResolveInst(inst_id); + new_const_id.is_valid()) { + import_ir_constant_values_.Set(inst_id, new_const_id); + work_stack_.pop_back(); + } + } + auto constant_id = import_ir_constant_values_.Get(inst_id); + CARBON_CHECK(constant_id.is_valid()); + return constant_id; + } + + private: + // Returns the ConstantId for an instruction, or adds it to the stack and + // returns Invalid if the ConstantId is not ready. + auto GetConstantId(SemIR::TypeId type_id) -> SemIR::ConstantId { + auto inst_id = import_ir_.types().GetInstId(type_id); + auto const_id = import_ir_constant_values_.Get(inst_id); + if (!const_id.is_valid()) { + work_stack_.push_back(inst_id); + } + return const_id; + } + + // Tries to resolve the InstId, returning a constant when ready, or Invalid if + // more has been added to the stack. A similar API is followed for all + // following TryResolveTypedInst helper functions. + // + // Logic for each TryResolveTypedInst will be in two phases: + // 1. Gather all input constants. + // 2. Produce an output constant. + // + // Although it's possible TryResolveTypedInst could complete in a single call + // when all input constants are ready, a common scenario is that some inputs + // will still be unresolved, and it'll return Invalid between phases. On the + // second call, all previously unready constants will have been resolved, so + // it should run to completion. As a consequence, it's important to reserve + // all expensive logic for the second phase; this in particular includes + // GetTypeIdForTypeConstant calls which do a hash table lookup. + // + // TODO: Error is returned when support is missing, but that should go away. + auto TryResolveInst(SemIR::InstId inst_id) -> SemIR::ConstantId { + if (inst_id.is_builtin()) { + // Constants for builtins can be directly copied. + return context_.constant_values().Get(inst_id); + } + + auto inst = import_ir_.insts().Get(inst_id); + switch (inst.kind()) { + case SemIR::InstKind::ConstType: + return TryResolveTypedInst(inst.As()); + + case SemIR::InstKind::PointerType: + return TryResolveTypedInst(inst.As()); + + case SemIR::InstKind::StructType: + return TryResolveTypedInst(inst.As()); + + case SemIR::InstKind::TupleType: + return TryResolveTypedInst(inst.As()); + + default: + context_.TODO( + Parse::NodeId::Invalid, + llvm::formatv("TryResolveInst on {0}", inst.kind()).str()); + return SemIR::ConstantId::Error; + } + } + + auto TryResolveTypedInst(SemIR::ConstType inst) -> SemIR::ConstantId { + CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); + auto inner_const_id = GetConstantId(inst.inner_id); + if (!inner_const_id.is_valid()) { + return SemIR::ConstantId::Invalid; + } + auto inner_type_id = context_.GetTypeIdForTypeConstant(inner_const_id); + // TODO: Should ConstType have a wrapper for this similar to the others? + return TryEvalInst( + context_, SemIR::InstId::Invalid, + SemIR::ConstType{SemIR::TypeId::TypeType, inner_type_id}); + } + + auto TryResolveTypedInst(SemIR::PointerType inst) -> SemIR::ConstantId { + CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); + auto pointee_const_id = GetConstantId(inst.pointee_id); + if (!pointee_const_id.is_valid()) { + return SemIR::ConstantId::Invalid; + } + auto pointee_type_id = context_.GetTypeIdForTypeConstant(pointee_const_id); + return context_.types().GetConstantId( + context_.GetPointerType(pointee_type_id)); + } + + auto TryResolveTypedInst(SemIR::StructType inst) -> SemIR::ConstantId { + CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); + + // Collect all constants first, locating unresolved ones in a single pass. + bool has_unresolved = false; + auto orig_fields = import_ir_.inst_blocks().Get(inst.fields_id); + llvm::SmallVector field_const_ids; + field_const_ids.reserve(orig_fields.size()); + for (auto field_id : orig_fields) { + auto field = import_ir_.insts().GetAs(field_id); + auto field_const_id = GetConstantId(field.field_type_id); + if (field_const_id.is_valid()) { + field_const_ids.push_back(field_const_id); + } else { + has_unresolved = true; + } + } + if (has_unresolved) { + return SemIR::ConstantId::Invalid; + } + + // Prepare a vector of fields for GetStructType. + // TODO: Should we have field constants so that we can deduplicate fields + // without creating instructions here? + llvm::SmallVector fields; + fields.reserve(orig_fields.size()); + for (auto [field_id, field_const_id] : + llvm::zip(orig_fields, field_const_ids)) { + auto field = import_ir_.insts().GetAs(field_id); + auto name_str = import_ir_.names().GetAsStringIfIdentifier(field.name_id); + auto name_id = name_str ? SemIR::NameId::ForIdentifier( + context_.identifiers().Add(*name_str)) + : field.name_id; + auto field_type_id = context_.GetTypeIdForTypeConstant(field_const_id); + fields.push_back(context_.AddInstInNoBlock( + {Parse::NodeId::Invalid, + SemIR::StructTypeField{.name_id = name_id, + .field_type_id = field_type_id}})); + } + + return context_.types().GetConstantId( + context_.GetStructType(context_.inst_blocks().Add(fields))); + } + + auto TryResolveTypedInst(SemIR::TupleType inst) -> SemIR::ConstantId { + CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); + + // Collect all constants first, locating unresolved ones in a single pass. + bool has_unresolved = false; + auto orig_elem_type_ids = import_ir_.type_blocks().Get(inst.elements_id); + llvm::SmallVector elem_const_ids; + elem_const_ids.reserve(orig_elem_type_ids.size()); + for (auto elem_type_id : orig_elem_type_ids) { + auto elem_const_id = GetConstantId(elem_type_id); + if (elem_const_id.is_valid()) { + elem_const_ids.push_back(elem_const_id); + } else { + has_unresolved = true; + } + } + if (has_unresolved) { + return SemIR::ConstantId::Invalid; + } + + // Prepare a vector of the tuple types for GetTupleType. + llvm::SmallVector elem_type_ids; + elem_type_ids.reserve(orig_elem_type_ids.size()); + for (auto elem_const_id : elem_const_ids) { + elem_type_ids.push_back(context_.GetTypeIdForTypeConstant(elem_const_id)); + } + + return context_.types().GetConstantId(context_.GetTupleType(elem_type_ids)); + } + + Context& context_; + const SemIR::File& import_ir_; + SemIR::ConstantValueStore& import_ir_constant_values_; + llvm::SmallVector work_stack_; +}; + +auto TryResolveImportRefUnused(Context& context, SemIR::InstId inst_id) + -> void { + auto inst = context.insts().Get(inst_id); + auto unused_inst = inst.TryAs(); + if (!unused_inst) { + return; + } + + const SemIR::File& import_ir = *context.import_irs().Get(unused_inst->ir_id); + auto import_inst = import_ir.insts().Get(unused_inst->inst_id); + + // TODO: Types need to be specifically addressed here to prevent crashes in + // constant evaluation while support is incomplete. Functions are also + // incomplete, but are allowed to fail differently because they aren't a type. + // The partial function support is useful for some namespace validation. + if (import_inst.Is() || + import_inst.Is()) { + context.TODO( + Parse::NodeId::Invalid, + llvm::formatv("TryResolveImportRefUnused on {0}", import_inst.kind()) + .str()); + context.ReplaceInstBeforeConstantUse( + inst_id, {SemIR::ImportRefUsed{SemIR::TypeId::Error, unused_inst->ir_id, + unused_inst->inst_id}}); + return; + } + + // If the type ID isn't a normal value, forward it directly. + if (!import_inst.type_id().is_valid()) { + context.ReplaceInstBeforeConstantUse( + inst_id, + {SemIR::ImportRefUsed{import_inst.type_id(), unused_inst->ir_id, + unused_inst->inst_id}}); + return; + } + + auto import_type_inst_id = import_ir.types().GetInstId(import_inst.type_id()); + CARBON_CHECK(import_type_inst_id.is_valid()); + + auto type_id = SemIR::TypeId::Invalid; + if (import_type_inst_id.is_builtin()) { + // Builtins don't require constant resolution; we can use them directly. + type_id = context.GetBuiltinType(import_type_inst_id.builtin_kind()); + } else { + ImportRefResolver resolver( + context, import_ir, + context.import_ir_constant_values()[unused_inst->ir_id.index]); + type_id = + context.GetTypeIdForTypeConstant(resolver.Resolve(import_type_inst_id)); + } + // TODO: Add breadcrumbs for lowering. + context.ReplaceInstBeforeConstantUse( + inst_id, {SemIR::ImportRefUsed{type_id, unused_inst->ir_id, + unused_inst->inst_id}}); +} + +} // namespace Carbon::Check diff --git a/toolchain/check/import_ref.h b/toolchain/check/import_ref.h new file mode 100644 index 000000000000..7c310d2460bc --- /dev/null +++ b/toolchain/check/import_ref.h @@ -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 + +#ifndef CARBON_TOOLCHAIN_CHECK_IMPORT_REF_H_ +#define CARBON_TOOLCHAIN_CHECK_IMPORT_REF_H_ + +#include "toolchain/check/context.h" +#include "toolchain/sem_ir/file.h" + +namespace Carbon::Check { + +// If the passed in instruction ID is a ImportRefUnused, resolves it for use. +// Otherwise, errors. +auto TryResolveImportRefUnused(Context& context, SemIR::InstId inst_id) -> void; + +} // namespace Carbon::Check + +#endif // CARBON_TOOLCHAIN_CHECK_IMPORT_REF_H_ diff --git a/toolchain/check/testdata/class/fail_todo_import.carbon b/toolchain/check/testdata/class/fail_todo_import.carbon index 8e941cebbc52..e8f0155b6ffa 100644 --- a/toolchain/check/testdata/class/fail_todo_import.carbon +++ b/toolchain/check/testdata/class/fail_todo_import.carbon @@ -3,6 +3,10 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE +// CHECK:STDERR: b.carbon: ERROR: Semantics TODO: `TryResolveImportRefUnused on ClassDecl`. +// CHECK:STDERR: b.carbon: ERROR: Semantics TODO: `TryResolveImportRefUnused on ClassDecl`. +// CHECK:STDERR: b.carbon: ERROR: Semantics TODO: `TryResolveInst on ClassType`. +// CHECK:STDERR: b.carbon: ERROR: Semantics TODO: `TryResolveInst on ClassType`. // --- a.carbon @@ -17,6 +21,11 @@ class ForwardDeclared { fn F(); } +var a_ref: Empty = {}; +var b_ref: ForwardDeclared = {}; +var c_ref: ForwardDeclared* = &b_ref; +// var d_ref: (ForwardDeclared,) = ({},); + // --- b.carbon library "b" api; @@ -24,30 +33,58 @@ library "b" api; import library "a"; fn Run() { - // CHECK:STDERR: b.carbon:[[@LINE+3]]:10: ERROR: Expression cannot be used as a value. - // CHECK:STDERR: var x: Empty = {}; - // CHECK:STDERR: ^~~~~ var x: Empty = {}; - // CHECK:STDERR: b.carbon:[[@LINE+3]]:10: ERROR: Expression cannot be used as a value. - // CHECK:STDERR: var y: ForwardDeclared = {}; - // CHECK:STDERR: ^~~~~~~~~~~~~~~ var y: ForwardDeclared = {}; y.F(); } +var a: Empty = a_ref; +var b: ForwardDeclared = b_ref; +var c: ForwardDeclared* = c_ref; +// CHECK:STDERR: b.carbon:[[@LINE+3]]:29: ERROR: Name `d_ref` not found. +// CHECK:STDERR: var d: (ForwardDeclared,) = d_ref; +// CHECK:STDERR: ^~~~~ +var d: (ForwardDeclared,) = d_ref; + // CHECK:STDOUT: --- a.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Empty: type = class_type @Empty [template] // CHECK:STDOUT: %.1: type = struct_type {} [template] // CHECK:STDOUT: %ForwardDeclared: type = class_type @ForwardDeclared [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: %.4: Empty = struct_value () [template] +// CHECK:STDOUT: %.5: ForwardDeclared = struct_value () [template] +// CHECK:STDOUT: %.6: type = ptr_type ForwardDeclared [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.Empty = %Empty.decl, .ForwardDeclared = %ForwardDeclared.decl.loc7} [template] +// CHECK:STDOUT: package: = namespace {.Empty = %Empty.decl, .ForwardDeclared = %ForwardDeclared.decl.loc7, .a_ref = %a_ref, .b_ref = %b_ref, .c_ref = %c_ref} [template] // CHECK:STDOUT: %Empty.decl = class_decl @Empty, () // CHECK:STDOUT: %ForwardDeclared.decl.loc7 = class_decl @ForwardDeclared, () // CHECK:STDOUT: %ForwardDeclared.decl.loc9 = class_decl @ForwardDeclared, () +// CHECK:STDOUT: %Empty.ref: type = name_ref Empty, constants.%Empty [template = constants.%Empty] +// CHECK:STDOUT: %a_ref.var: ref Empty = var a_ref +// CHECK:STDOUT: %a_ref: ref Empty = bind_name a_ref, %a_ref.var +// CHECK:STDOUT: %.loc13_21.1: {} = struct_literal () +// CHECK:STDOUT: %.loc13_21.2: init Empty = class_init (), %a_ref.var [template = constants.%.4] +// CHECK:STDOUT: %.loc13_21.3: init Empty = converted %.loc13_21.1, %.loc13_21.2 [template = constants.%.4] +// CHECK:STDOUT: assign %a_ref.var, %.loc13_21.3 +// CHECK:STDOUT: %ForwardDeclared.ref.loc14: type = name_ref ForwardDeclared, constants.%ForwardDeclared [template = constants.%ForwardDeclared] +// CHECK:STDOUT: %b_ref.var: ref ForwardDeclared = var b_ref +// CHECK:STDOUT: %b_ref: ref ForwardDeclared = bind_name b_ref, %b_ref.var +// CHECK:STDOUT: %.loc14_31.1: {} = struct_literal () +// CHECK:STDOUT: %.loc14_31.2: init ForwardDeclared = class_init (), %b_ref.var [template = constants.%.5] +// CHECK:STDOUT: %.loc14_31.3: init ForwardDeclared = converted %.loc14_31.1, %.loc14_31.2 [template = constants.%.5] +// CHECK:STDOUT: assign %b_ref.var, %.loc14_31.3 +// CHECK:STDOUT: %ForwardDeclared.ref.loc15: type = name_ref ForwardDeclared, constants.%ForwardDeclared [template = constants.%ForwardDeclared] +// CHECK:STDOUT: %.loc15_27: type = ptr_type ForwardDeclared [template = constants.%.6] +// CHECK:STDOUT: %c_ref.var: ref ForwardDeclared* = var c_ref +// CHECK:STDOUT: %c_ref: ref ForwardDeclared* = bind_name c_ref, %c_ref.var +// CHECK:STDOUT: %b_ref.ref: ref ForwardDeclared = name_ref b_ref, %b_ref +// CHECK:STDOUT: %.loc15_31: ForwardDeclared* = addr_of %b_ref.ref +// CHECK:STDOUT: assign %c_ref.var, %.loc15_31 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @Empty { @@ -71,23 +108,48 @@ fn Run() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.Empty = %import_ref.1, .ForwardDeclared = %import_ref.2, .Run = %Run} [template] -// CHECK:STDOUT: %import_ref.1: invalid = import_ref ir1, inst+1, used -// CHECK:STDOUT: %import_ref.2: invalid = import_ref ir1, inst+4, used +// CHECK:STDOUT: package: = namespace {.Empty = %import_ref.1, .ForwardDeclared = %import_ref.2, .a_ref = %import_ref.3, .b_ref = %import_ref.4, .c_ref = %import_ref.5, .Run = %Run, .a = %a, .b = %b, .c = %c, .d = %d} [template] +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, used +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+4, used +// CHECK:STDOUT: %import_ref.3: ref = import_ref ir1, inst+12, used +// CHECK:STDOUT: %import_ref.4: ref = import_ref ir1, inst+20, used +// CHECK:STDOUT: %import_ref.5: ref = import_ref ir1, inst+30, used // CHECK:STDOUT: %Run: = fn_decl @Run [template] +// CHECK:STDOUT: %Empty.ref: = name_ref Empty, %import_ref.1 +// CHECK:STDOUT: %a.var: ref = var a +// CHECK:STDOUT: %a: ref = bind_name a, %a.var +// CHECK:STDOUT: %a_ref.ref: ref = name_ref a_ref, %import_ref.3 +// CHECK:STDOUT: assign %a.var, +// CHECK:STDOUT: %ForwardDeclared.ref.loc13: = name_ref ForwardDeclared, %import_ref.2 +// CHECK:STDOUT: %b.var: ref = var b +// CHECK:STDOUT: %b: ref = bind_name b, %b.var +// CHECK:STDOUT: %b_ref.ref: ref = name_ref b_ref, %import_ref.4 +// CHECK:STDOUT: assign %b.var, +// CHECK:STDOUT: %ForwardDeclared.ref.loc14: = name_ref ForwardDeclared, %import_ref.2 +// CHECK:STDOUT: %.loc14: type = ptr_type [template = ] +// CHECK:STDOUT: %c.var: ref = var c +// CHECK:STDOUT: %c: ref = bind_name c, %c.var +// CHECK:STDOUT: %c_ref.ref: ref = name_ref c_ref, %import_ref.5 +// CHECK:STDOUT: assign %c.var, +// CHECK:STDOUT: %ForwardDeclared.ref.loc18: = name_ref ForwardDeclared, %import_ref.2 +// CHECK:STDOUT: %.loc18: = tuple_literal (%ForwardDeclared.ref.loc18) +// CHECK:STDOUT: %d.var: ref = var d +// CHECK:STDOUT: %d: ref = bind_name d, %d.var +// CHECK:STDOUT: %d_ref.ref: = name_ref d_ref, [template = ] +// CHECK:STDOUT: assign %d.var, // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @Run() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Empty.ref: invalid = name_ref Empty, file.%import_ref.1 +// CHECK:STDOUT: %Empty.ref: = name_ref Empty, file.%import_ref.1 // CHECK:STDOUT: %x.var: ref = var x // CHECK:STDOUT: %x: ref = bind_name x, %x.var -// CHECK:STDOUT: %.loc10: {} = struct_literal () +// CHECK:STDOUT: %.loc7: {} = struct_literal () // CHECK:STDOUT: assign %x.var, -// CHECK:STDOUT: %ForwardDeclared.ref: invalid = name_ref ForwardDeclared, file.%import_ref.2 +// CHECK:STDOUT: %ForwardDeclared.ref: = name_ref ForwardDeclared, file.%import_ref.2 // CHECK:STDOUT: %y.var: ref = var y // CHECK:STDOUT: %y: ref = bind_name y, %y.var -// CHECK:STDOUT: %.loc14: {} = struct_literal () +// CHECK:STDOUT: %.loc8: {} = struct_literal () // CHECK:STDOUT: assign %y.var, // CHECK:STDOUT: %y.ref: ref = name_ref y, %y // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/const/basic.carbon b/toolchain/check/testdata/const/basic.carbon new file mode 100644 index 000000000000..99a325fdd6a0 --- /dev/null +++ b/toolchain/check/testdata/const/basic.carbon @@ -0,0 +1,42 @@ +// 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 A(p: const i32**) -> const i32** { + return p; +} + +fn B(p: const (i32*)) -> const (i32*) { + return p; +} + +// CHECK:STDOUT: --- basic.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = const_type i32 [template] +// CHECK:STDOUT: %.2: type = ptr_type const i32 [template] +// CHECK:STDOUT: %.3: type = ptr_type const i32* [template] +// CHECK:STDOUT: %.4: type = ptr_type i32 [template] +// CHECK:STDOUT: %.5: type = const_type i32* [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.A = %A, .B = %B} [template] +// CHECK:STDOUT: %A: = fn_decl @A [template] +// CHECK:STDOUT: %B: = fn_decl @B [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @A(%p: const i32**) -> const i32** { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %p.ref: const i32** = name_ref p, %p +// CHECK:STDOUT: return %p.ref +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @B(%p: const (i32*)) -> const (i32*) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %p.ref: const (i32*) = name_ref p, %p +// CHECK:STDOUT: return %p.ref +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/const/fail_todo_import.carbon b/toolchain/check/testdata/const/fail_todo_import.carbon deleted file mode 100644 index 10aa0215c9fc..000000000000 --- a/toolchain/check/testdata/const/fail_todo_import.carbon +++ /dev/null @@ -1,60 +0,0 @@ -// 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 -// -// When there are no more cases that can hit a TODO, remove this test. Until -// then, update it whenever its target is implemented. -// -// AUTOUPDATE -// CHECK:STDERR: implicit.impl.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for non-builtin type`. - -// --- implicit.carbon - -package Implicit api; - -fn F() -> const i32; - -var a_ref: const i32 = F(); - -// --- implicit.impl.carbon - -package Implicit impl; - -var a: const i32 = a_ref; - -// CHECK:STDOUT: --- implicit.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = const_type i32 [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.F = %F, .a_ref = %a_ref} [template] -// CHECK:STDOUT: %F: = fn_decl @F [template] -// CHECK:STDOUT: %.loc6_12: type = const_type i32 [template = constants.%.1] -// CHECK:STDOUT: %a_ref.var: ref const i32 = var a_ref -// CHECK:STDOUT: %a_ref: ref const i32 = bind_name a_ref, %a_ref.var -// CHECK:STDOUT: %F.ref: = name_ref F, %F [template = %F] -// CHECK:STDOUT: %.loc6_25: init const i32 = call %F.ref() -// CHECK:STDOUT: assign %a_ref.var, %.loc6_25 -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @F() -> const i32; -// CHECK:STDOUT: -// CHECK:STDOUT: --- implicit.impl.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = const_type i32 [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.F = %import_ref.1, .a_ref = %import_ref.2, .a = %a} [template] -// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+4, unused -// CHECK:STDOUT: %import_ref.2: ref = import_ref ir1, inst+7, used -// CHECK:STDOUT: %.loc4: type = const_type i32 [template = constants.%.1] -// CHECK:STDOUT: %a.var: ref const i32 = var a -// CHECK:STDOUT: %a: ref const i32 = bind_name a, %a.var -// CHECK:STDOUT: %a_ref.ref: ref = name_ref a_ref, %import_ref.2 -// CHECK:STDOUT: assign %a.var, -// CHECK:STDOUT: } -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/const/import.carbon b/toolchain/check/testdata/const/import.carbon new file mode 100644 index 000000000000..16c2b35c9721 --- /dev/null +++ b/toolchain/check/testdata/const/import.carbon @@ -0,0 +1,79 @@ +// 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 + +// --- implicit.carbon + +package Implicit api; + +fn F() -> const i32; + +var a_ref: const i32 = F(); +var a_ptr_ref: const i32* = &a_ref; + +// --- implicit.impl.carbon + +package Implicit impl; + +// Take a reference to avoid unsupported copy logic. This still validates the +// `const` is handled. +var a: const i32* = &a_ref; +var a_ptr: const i32* = a_ptr_ref; + +// CHECK:STDOUT: --- implicit.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = const_type i32 [template] +// CHECK:STDOUT: %.2: type = ptr_type const i32 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.F = %F, .a_ref = %a_ref, .a_ptr_ref = %a_ptr_ref} [template] +// CHECK:STDOUT: %F: = fn_decl @F [template] +// CHECK:STDOUT: %.loc6_12: type = const_type i32 [template = constants.%.1] +// CHECK:STDOUT: %a_ref.var: ref const i32 = var a_ref +// CHECK:STDOUT: %a_ref: ref const i32 = bind_name a_ref, %a_ref.var +// CHECK:STDOUT: %F.ref: = name_ref F, %F [template = %F] +// CHECK:STDOUT: %.loc6_25: init const i32 = call %F.ref() +// CHECK:STDOUT: assign %a_ref.var, %.loc6_25 +// CHECK:STDOUT: %.loc7_16: type = const_type i32 [template = constants.%.1] +// CHECK:STDOUT: %.loc7_25: type = ptr_type const i32 [template = constants.%.2] +// CHECK:STDOUT: %a_ptr_ref.var: ref const i32* = var a_ptr_ref +// CHECK:STDOUT: %a_ptr_ref: ref const i32* = bind_name a_ptr_ref, %a_ptr_ref.var +// CHECK:STDOUT: %a_ref.ref: ref const i32 = name_ref a_ref, %a_ref +// CHECK:STDOUT: %.loc7_29: const i32* = addr_of %a_ref.ref +// CHECK:STDOUT: assign %a_ptr_ref.var, %.loc7_29 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() -> const i32; +// CHECK:STDOUT: +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = const_type i32 [template] +// CHECK:STDOUT: %.2: type = ptr_type const i32 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.F = %import_ref.1, .a_ref = %import_ref.2, .a_ptr_ref = %import_ref.3, .a = %a, .a_ptr = %a_ptr} [template] +// CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+4, unused +// CHECK:STDOUT: %import_ref.2: ref const i32 = import_ref ir1, inst+7, used +// CHECK:STDOUT: %import_ref.3: ref const i32* = import_ref ir1, inst+15, used +// CHECK:STDOUT: %.loc6_8: type = const_type i32 [template = constants.%.1] +// CHECK:STDOUT: %.loc6_17: type = ptr_type const i32 [template = constants.%.2] +// CHECK:STDOUT: %a.var: ref const i32* = var a +// CHECK:STDOUT: %a: ref const i32* = bind_name a, %a.var +// CHECK:STDOUT: %a_ref.ref: ref const i32 = name_ref a_ref, %import_ref.2 +// CHECK:STDOUT: %.loc6_21: const i32* = addr_of %a_ref.ref +// CHECK:STDOUT: assign %a.var, %.loc6_21 +// CHECK:STDOUT: %.loc7_12: type = const_type i32 [template = constants.%.1] +// CHECK:STDOUT: %.loc7_21: type = ptr_type const i32 [template = constants.%.2] +// CHECK:STDOUT: %a_ptr.var: ref const i32* = var a_ptr +// CHECK:STDOUT: %a_ptr: ref const i32* = bind_name a_ptr, %a_ptr.var +// CHECK:STDOUT: %a_ptr_ref.ref: ref const i32* = name_ref a_ptr_ref, %import_ref.3 +// CHECK:STDOUT: %.loc7_25: const i32* = bind_value %a_ptr_ref.ref +// CHECK:STDOUT: assign %a_ptr.var, %.loc7_25 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/fail_import_type_error.carbon b/toolchain/check/testdata/packages/fail_import_type_error.carbon new file mode 100644 index 000000000000..7b82073ef277 --- /dev/null +++ b/toolchain/check/testdata/packages/fail_import_type_error.carbon @@ -0,0 +1,85 @@ +// 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 + +// --- implicit.carbon + +package Implicit api; + +// CHECK:STDERR: implicit.carbon:[[@LINE+3]]:12: ERROR: Name `x` not found. +// CHECK:STDERR: var a_ref: x; +// CHECK:STDERR: ^ +var a_ref: x; +// CHECK:STDERR: implicit.carbon:[[@LINE+3]]:18: ERROR: Name `x` not found. +// CHECK:STDERR: var b_ref: {.a = x}; +// CHECK:STDERR: ^ +var b_ref: {.a = x}; +// CHECK:STDERR: implicit.carbon:[[@LINE+3]]:13: ERROR: Name `x` not found. +// CHECK:STDERR: var c_ref: (x,); +// CHECK:STDERR: ^ +var c_ref: (x,); +// CHECK:STDERR: implicit.carbon:[[@LINE+3]]:12: ERROR: Name `x` not found. +// CHECK:STDERR: var d_ref: x*; +// CHECK:STDERR: ^ +var d_ref: x*; + +// --- implicit.impl.carbon + +package Implicit impl; + +// In each of these cases, name lookup should succeed, but they should all have +// an error type. +var a: i32 = a_ref; +var b: i32 = b_ref; +var c: i32 = c_ref; +var d: i32 = d_ref; + +// CHECK:STDOUT: --- implicit.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.a_ref = %a_ref, .b_ref = %b_ref, .c_ref = %c_ref, .d_ref = %d_ref} [template] +// CHECK:STDOUT: %x.ref.loc7: = name_ref x, [template = ] +// CHECK:STDOUT: %a_ref.var: ref = var a_ref +// CHECK:STDOUT: %a_ref: ref = bind_name a_ref, %a_ref.var +// CHECK:STDOUT: %x.ref.loc11: = name_ref x, [template = ] +// CHECK:STDOUT: %.loc11: = struct_literal (%x.ref.loc11) +// CHECK:STDOUT: %b_ref.var: ref = var b_ref +// CHECK:STDOUT: %b_ref: ref = bind_name b_ref, %b_ref.var +// CHECK:STDOUT: %x.ref.loc15: = name_ref x, [template = ] +// CHECK:STDOUT: %.loc15: = tuple_literal (%x.ref.loc15) +// CHECK:STDOUT: %c_ref.var: ref = var c_ref +// CHECK:STDOUT: %c_ref: ref = bind_name c_ref, %c_ref.var +// CHECK:STDOUT: %x.ref.loc19: = name_ref x, [template = ] +// CHECK:STDOUT: %.loc19: type = ptr_type [template = ] +// CHECK:STDOUT: %d_ref.var: ref = var d_ref +// CHECK:STDOUT: %d_ref: ref = bind_name d_ref, %d_ref.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.a_ref = %import_ref.1, .b_ref = %import_ref.2, .c_ref = %import_ref.3, .d_ref = %import_ref.4, .a = %a, .b = %b, .c = %c, .d = %d} [template] +// CHECK:STDOUT: %import_ref.1: ref = import_ref ir1, inst+3, used +// CHECK:STDOUT: %import_ref.2: ref = import_ref ir1, inst+8, used +// CHECK:STDOUT: %import_ref.3: ref = import_ref ir1, inst+12, used +// CHECK:STDOUT: %import_ref.4: ref = import_ref ir1, inst+16, used +// CHECK:STDOUT: %a.var: ref i32 = var a +// CHECK:STDOUT: %a: ref i32 = bind_name a, %a.var +// CHECK:STDOUT: %a_ref.ref: ref = name_ref a_ref, %import_ref.1 +// CHECK:STDOUT: assign %a.var, +// CHECK:STDOUT: %b.var: ref i32 = var b +// CHECK:STDOUT: %b: ref i32 = bind_name b, %b.var +// CHECK:STDOUT: %b_ref.ref: ref = name_ref b_ref, %import_ref.2 +// CHECK:STDOUT: assign %b.var, +// CHECK:STDOUT: %c.var: ref i32 = var c +// CHECK:STDOUT: %c: ref i32 = bind_name c, %c.var +// CHECK:STDOUT: %c_ref.ref: ref = name_ref c_ref, %import_ref.3 +// CHECK:STDOUT: assign %c.var, +// CHECK:STDOUT: %d.var: ref i32 = var d +// CHECK:STDOUT: %d: ref i32 = bind_name d, %d.var +// CHECK:STDOUT: %d_ref.ref: ref = name_ref d_ref, %import_ref.4 +// CHECK:STDOUT: assign %d.var, +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/pointer/fail_todo_import.carbon b/toolchain/check/testdata/pointer/import.carbon similarity index 78% rename from toolchain/check/testdata/pointer/fail_todo_import.carbon rename to toolchain/check/testdata/pointer/import.carbon index 037703c12472..b174f0d62c8c 100644 --- a/toolchain/check/testdata/pointer/fail_todo_import.carbon +++ b/toolchain/check/testdata/pointer/import.carbon @@ -2,11 +2,7 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// When there are no more cases that can hit a TODO, remove this test. Until -// then, update it whenever its target is implemented. -// // AUTOUPDATE -// CHECK:STDERR: implicit.impl.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for non-builtin type`. // --- implicit.carbon @@ -51,11 +47,12 @@ var a: i32* = a_ref; // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.a_orig = %import_ref.1, .a_ref = %import_ref.2, .a = %a} [template] // CHECK:STDOUT: %import_ref.1 = import_ref ir1, inst+2, unused -// CHECK:STDOUT: %import_ref.2: ref = import_ref ir1, inst+9, used -// CHECK:STDOUT: %.loc4: type = ptr_type i32 [template = constants.%.1] +// CHECK:STDOUT: %import_ref.2: ref i32* = import_ref ir1, inst+9, used +// CHECK:STDOUT: %.loc4_11: type = ptr_type i32 [template = constants.%.1] // CHECK:STDOUT: %a.var: ref i32* = var a // CHECK:STDOUT: %a: ref i32* = bind_name a, %a.var -// CHECK:STDOUT: %a_ref.ref: ref = name_ref a_ref, %import_ref.2 -// CHECK:STDOUT: assign %a.var, +// CHECK:STDOUT: %a_ref.ref: ref i32* = name_ref a_ref, %import_ref.2 +// CHECK:STDOUT: %.loc4_15: i32* = bind_value %a_ref.ref +// CHECK:STDOUT: assign %a.var, %.loc4_15 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/struct/fail_todo_import.carbon b/toolchain/check/testdata/struct/fail_todo_import.carbon deleted file mode 100644 index d0c634adeddf..000000000000 --- a/toolchain/check/testdata/struct/fail_todo_import.carbon +++ /dev/null @@ -1,58 +0,0 @@ -// 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 -// -// When there are no more cases that can hit a TODO, remove this test. Until -// then, update it whenever its target is implemented. -// -// AUTOUPDATE -// CHECK:STDERR: implicit.impl.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for non-builtin type`. - -// --- implicit.carbon - -package Implicit api; - -var a_ref: {.a: i32} = {.a = 0}; - -// --- implicit.impl.carbon - -package Implicit impl; - -var a: {.a: i32} = a_ref; - -// CHECK:STDOUT: --- implicit.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = struct_type {.a: i32} [template] -// CHECK:STDOUT: %.2: i32 = int_literal 0 [template] -// CHECK:STDOUT: %.3: {.a: i32} = struct_value (%.2) [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.a_ref = %a_ref} [template] -// CHECK:STDOUT: %.loc4_20: type = struct_type {.a: i32} [template = constants.%.1] -// CHECK:STDOUT: %a_ref.var: ref {.a: i32} = var a_ref -// CHECK:STDOUT: %a_ref: ref {.a: i32} = bind_name a_ref, %a_ref.var -// CHECK:STDOUT: %.loc4_30: i32 = int_literal 0 [template = constants.%.2] -// CHECK:STDOUT: %.loc4_31.1: {.a: i32} = struct_literal (%.loc4_30) -// CHECK:STDOUT: %.loc4_31.2: init {.a: i32} = struct_init (%.loc4_30) to %a_ref.var [template = constants.%.3] -// CHECK:STDOUT: %.loc4_31.3: init {.a: i32} = converted %.loc4_31.1, %.loc4_31.2 [template = constants.%.3] -// CHECK:STDOUT: assign %a_ref.var, %.loc4_31.3 -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: --- implicit.impl.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = struct_type {.a: i32} [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.a_ref = %import_ref, .a = %a} [template] -// CHECK:STDOUT: %import_ref: ref = import_ref ir1, inst+6, used -// CHECK:STDOUT: %.loc4: type = struct_type {.a: i32} [template = constants.%.1] -// CHECK:STDOUT: %a.var: ref {.a: i32} = var a -// CHECK:STDOUT: %a: ref {.a: i32} = bind_name a, %a.var -// CHECK:STDOUT: %a_ref.ref: ref = name_ref a_ref, %import_ref -// CHECK:STDOUT: assign %a.var, -// CHECK:STDOUT: } -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/struct/import.carbon b/toolchain/check/testdata/struct/import.carbon new file mode 100644 index 000000000000..ef3b945c7f7e --- /dev/null +++ b/toolchain/check/testdata/struct/import.carbon @@ -0,0 +1,134 @@ +// 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 + +// --- implicit.carbon + +package Implicit api; + +var a_ref: {.a: i32} = {.a = 0}; +var b_ref: {.a: {.b: i32, .c: (i32,)}, .d: i32} = + {.a = {.b = 0, .c = (0,)}, .d = 0}; + +// --- implicit.impl.carbon + +package Implicit impl; + +var a: {.a: i32} = a_ref; +var b: {.a: {.b: i32, .c: (i32,)}, .d: i32} = b_ref; + +// CHECK:STDOUT: --- implicit.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = struct_type {.a: i32} [template] +// CHECK:STDOUT: %.2: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.3: {.a: i32} = struct_value (%.2) [template] +// CHECK:STDOUT: %.4: type = tuple_type (type) [template] +// CHECK:STDOUT: %.5: type = tuple_type (i32) [template] +// CHECK:STDOUT: %.6: type = struct_type {.b: i32, .c: (i32,)} [template] +// CHECK:STDOUT: %.7: type = struct_type {.a: {.b: i32, .c: (i32,)}, .d: i32} [template] +// CHECK:STDOUT: %.8: type = ptr_type {.b: i32, .c: (i32,)} [template] +// CHECK:STDOUT: %.9: type = struct_type {.a: {.b: i32, .c: (i32,)}*, .d: i32} [template] +// CHECK:STDOUT: %.10: type = ptr_type {.a: {.b: i32, .c: (i32,)}*, .d: i32} [template] +// CHECK:STDOUT: %.11: (i32,) = tuple_value (%.2) [template] +// CHECK:STDOUT: %.12: {.b: i32, .c: (i32,)} = struct_value (%.2, %.11) [template] +// CHECK:STDOUT: %.13: {.a: {.b: i32, .c: (i32,)}, .d: i32} = struct_value (%.12, %.2) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.a_ref = %a_ref, .b_ref = %b_ref} [template] +// CHECK:STDOUT: %.loc4_20: type = struct_type {.a: i32} [template = constants.%.1] +// CHECK:STDOUT: %a_ref.var: ref {.a: i32} = var a_ref +// CHECK:STDOUT: %a_ref: ref {.a: i32} = bind_name a_ref, %a_ref.var +// CHECK:STDOUT: %.loc4_30: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_31.1: {.a: i32} = struct_literal (%.loc4_30) +// CHECK:STDOUT: %.loc4_31.2: init {.a: i32} = struct_init (%.loc4_30) to %a_ref.var [template = constants.%.3] +// CHECK:STDOUT: %.loc4_31.3: init {.a: i32} = converted %.loc4_31.1, %.loc4_31.2 [template = constants.%.3] +// CHECK:STDOUT: assign %a_ref.var, %.loc4_31.3 +// CHECK:STDOUT: %.loc5_36.1: (type,) = tuple_literal (i32) +// CHECK:STDOUT: %.loc5_36.2: type = converted %.loc5_36.1, constants.%.5 [template = constants.%.5] +// CHECK:STDOUT: %.loc5_37: type = struct_type {.b: i32, .c: (i32,)} [template = constants.%.6] +// CHECK:STDOUT: %.loc5_47: type = struct_type {.a: {.b: i32, .c: (i32,)}, .d: i32} [template = constants.%.7] +// CHECK:STDOUT: %b_ref.var: ref {.a: {.b: i32, .c: (i32,)}, .d: i32} = var b_ref +// CHECK:STDOUT: %b_ref: ref {.a: {.b: i32, .c: (i32,)}, .d: i32} = bind_name b_ref, %b_ref.var +// CHECK:STDOUT: %.loc6_17: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc6_26: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc6_28.1: (i32,) = tuple_literal (%.loc6_26) +// CHECK:STDOUT: %.loc6_29.1: {.b: i32, .c: (i32,)} = struct_literal (%.loc6_17, %.loc6_28.1) +// CHECK:STDOUT: %.loc6_37: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc6_38.1: {.a: {.b: i32, .c: (i32,)}, .d: i32} = struct_literal (%.loc6_29.1, %.loc6_37) +// CHECK:STDOUT: %.loc6_38.2: ref {.b: i32, .c: (i32,)} = struct_access %b_ref.var, element0 +// CHECK:STDOUT: %.loc6_29.2: ref i32 = struct_access %.loc6_38.2, element0 +// CHECK:STDOUT: %.loc6_29.3: init i32 = initialize_from %.loc6_17 to %.loc6_29.2 [template = constants.%.2] +// CHECK:STDOUT: %.loc6_29.4: ref (i32,) = struct_access %.loc6_38.2, element1 +// CHECK:STDOUT: %.loc6_28.2: init (i32,) = tuple_init (%.loc6_26) to %.loc6_29.4 [template = constants.%.11] +// CHECK:STDOUT: %.loc6_28.3: init (i32,) = converted %.loc6_28.1, %.loc6_28.2 [template = constants.%.11] +// CHECK:STDOUT: %.loc6_29.5: init (i32,) = initialize_from %.loc6_28.3 to %.loc6_29.4 [template = constants.%.11] +// CHECK:STDOUT: %.loc6_29.6: init {.b: i32, .c: (i32,)} = struct_init (%.loc6_29.3, %.loc6_29.5) to %.loc6_38.2 [template = constants.%.12] +// CHECK:STDOUT: %.loc6_29.7: init {.b: i32, .c: (i32,)} = converted %.loc6_29.1, %.loc6_29.6 [template = constants.%.12] +// CHECK:STDOUT: %.loc6_38.3: ref i32 = struct_access %b_ref.var, element1 +// CHECK:STDOUT: %.loc6_38.4: init i32 = initialize_from %.loc6_37 to %.loc6_38.3 [template = constants.%.2] +// CHECK:STDOUT: %.loc6_38.5: init {.a: {.b: i32, .c: (i32,)}, .d: i32} = struct_init (%.loc6_29.7, %.loc6_38.4) to %b_ref.var [template = constants.%.13] +// CHECK:STDOUT: %.loc6_38.6: init {.a: {.b: i32, .c: (i32,)}, .d: i32} = converted %.loc6_38.1, %.loc6_38.5 [template = constants.%.13] +// CHECK:STDOUT: assign %b_ref.var, %.loc6_38.6 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = struct_type {.a: i32} [template] +// CHECK:STDOUT: %.2: type = tuple_type (type) [template] +// CHECK:STDOUT: %.3: type = tuple_type (i32) [template] +// CHECK:STDOUT: %.4: type = struct_type {.b: i32, .c: (i32,)} [template] +// CHECK:STDOUT: %.5: type = struct_type {.a: {.b: i32, .c: (i32,)}, .d: i32} [template] +// CHECK:STDOUT: %.6: type = ptr_type {.b: i32, .c: (i32,)} [template] +// CHECK:STDOUT: %.7: type = struct_type {.a: {.b: i32, .c: (i32,)}*, .d: i32} [template] +// CHECK:STDOUT: %.8: type = ptr_type {.a: {.b: i32, .c: (i32,)}*, .d: i32} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.a_ref = %import_ref.1, .b_ref = %import_ref.2, .a = %a, .b = %b} [template] +// CHECK:STDOUT: %import_ref.1: ref {.a: i32} = import_ref ir1, inst+6, used +// CHECK:STDOUT: %import_ref.2: ref {.a: {.b: i32, .c: (i32,)}, .d: i32} = import_ref ir1, inst+37, used +// CHECK:STDOUT: %.loc4_16: type = struct_type {.a: i32} [template = constants.%.1] +// CHECK:STDOUT: %a.var: ref {.a: i32} = var a +// CHECK:STDOUT: %a: ref {.a: i32} = bind_name a, %a.var +// CHECK:STDOUT: %a_ref.ref: ref {.a: i32} = name_ref a_ref, %import_ref.1 +// CHECK:STDOUT: %.loc4_20.1: ref i32 = struct_access %a_ref.ref, element0 +// CHECK:STDOUT: %.loc4_20.2: i32 = bind_value %.loc4_20.1 +// CHECK:STDOUT: %.loc4_20.3: init {.a: i32} = struct_init (%.loc4_20.2) to %a.var +// CHECK:STDOUT: %.loc4_20.4: init {.a: i32} = converted %a_ref.ref, %.loc4_20.3 +// CHECK:STDOUT: assign %a.var, %.loc4_20.4 +// CHECK:STDOUT: %.loc5_32.1: (type,) = tuple_literal (i32) +// CHECK:STDOUT: %.loc5_32.2: type = converted %.loc5_32.1, constants.%.3 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_33: type = struct_type {.b: i32, .c: (i32,)} [template = constants.%.4] +// CHECK:STDOUT: %.loc5_43: type = struct_type {.a: {.b: i32, .c: (i32,)}, .d: i32} [template = constants.%.5] +// CHECK:STDOUT: %b.var: ref {.a: {.b: i32, .c: (i32,)}, .d: i32} = var b +// CHECK:STDOUT: %b: ref {.a: {.b: i32, .c: (i32,)}, .d: i32} = bind_name b, %b.var +// CHECK:STDOUT: %b_ref.ref: ref {.a: {.b: i32, .c: (i32,)}, .d: i32} = name_ref b_ref, %import_ref.2 +// CHECK:STDOUT: %.loc5_47.1: ref {.b: i32, .c: (i32,)} = struct_access %b_ref.ref, element0 +// CHECK:STDOUT: %.loc5_47.2: ref i32 = struct_access %.loc5_47.1, element0 +// CHECK:STDOUT: %.loc5_47.3: i32 = bind_value %.loc5_47.2 +// CHECK:STDOUT: %.loc5_47.4: ref {.b: i32, .c: (i32,)} = struct_access %b.var, element0 +// CHECK:STDOUT: %.loc5_47.5: ref i32 = struct_access %.loc5_47.4, element0 +// CHECK:STDOUT: %.loc5_47.6: init i32 = initialize_from %.loc5_47.3 to %.loc5_47.5 +// CHECK:STDOUT: %.loc5_47.7: ref (i32,) = struct_access %.loc5_47.1, element1 +// CHECK:STDOUT: %.loc5_47.8: ref i32 = tuple_access %.loc5_47.7, element0 +// CHECK:STDOUT: %.loc5_47.9: i32 = bind_value %.loc5_47.8 +// CHECK:STDOUT: %.loc5_47.10: ref (i32,) = struct_access %.loc5_47.4, element1 +// CHECK:STDOUT: %.loc5_47.11: init (i32,) = tuple_init (%.loc5_47.9) to %.loc5_47.10 +// CHECK:STDOUT: %.loc5_47.12: init (i32,) = converted %.loc5_47.7, %.loc5_47.11 +// CHECK:STDOUT: %.loc5_47.13: init (i32,) = initialize_from %.loc5_47.12 to %.loc5_47.10 +// CHECK:STDOUT: %.loc5_47.14: init {.b: i32, .c: (i32,)} = struct_init (%.loc5_47.6, %.loc5_47.13) to %.loc5_47.4 +// CHECK:STDOUT: %.loc5_47.15: init {.b: i32, .c: (i32,)} = converted %.loc5_47.1, %.loc5_47.14 +// CHECK:STDOUT: %.loc5_47.16: ref i32 = struct_access %b_ref.ref, element1 +// CHECK:STDOUT: %.loc5_47.17: i32 = bind_value %.loc5_47.16 +// CHECK:STDOUT: %.loc5_47.18: ref i32 = struct_access %b.var, element1 +// CHECK:STDOUT: %.loc5_47.19: init i32 = initialize_from %.loc5_47.17 to %.loc5_47.18 +// CHECK:STDOUT: %.loc5_47.20: init {.a: {.b: i32, .c: (i32,)}, .d: i32} = struct_init (%.loc5_47.15, %.loc5_47.19) to %b.var +// CHECK:STDOUT: %.loc5_47.21: init {.a: {.b: i32, .c: (i32,)}, .d: i32} = converted %b_ref.ref, %.loc5_47.20 +// CHECK:STDOUT: assign %b.var, %.loc5_47.21 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/tuples/fail_todo_import.carbon b/toolchain/check/testdata/tuples/fail_todo_import.carbon deleted file mode 100644 index af543b55ee86..000000000000 --- a/toolchain/check/testdata/tuples/fail_todo_import.carbon +++ /dev/null @@ -1,62 +0,0 @@ -// 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 -// -// When there are no more cases that can hit a TODO, remove this test. Until -// then, update it whenever its target is implemented. -// -// AUTOUPDATE -// CHECK:STDERR: implicit.impl.carbon: ERROR: Semantics TODO: `TODO: ResolveIfImportRefUnused for non-builtin type`. - -// --- implicit.carbon - -package Implicit api; - -var a_ref: (i32,) = (0,); - -// --- implicit.impl.carbon - -package Implicit impl; - -var a: (i32,) = a_ref; - -// CHECK:STDOUT: --- implicit.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = tuple_type (type) [template] -// CHECK:STDOUT: %.2: type = tuple_type (i32) [template] -// CHECK:STDOUT: %.3: i32 = int_literal 0 [template] -// CHECK:STDOUT: %.4: (i32,) = tuple_value (%.3) [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.a_ref = %a_ref} [template] -// CHECK:STDOUT: %.loc4_17.1: (type,) = tuple_literal (i32) -// CHECK:STDOUT: %.loc4_17.2: type = converted %.loc4_17.1, constants.%.2 [template = constants.%.2] -// CHECK:STDOUT: %a_ref.var: ref (i32,) = var a_ref -// CHECK:STDOUT: %a_ref: ref (i32,) = bind_name a_ref, %a_ref.var -// CHECK:STDOUT: %.loc4_22: i32 = int_literal 0 [template = constants.%.3] -// CHECK:STDOUT: %.loc4_24.1: (i32,) = tuple_literal (%.loc4_22) -// CHECK:STDOUT: %.loc4_24.2: init (i32,) = tuple_init (%.loc4_22) to %a_ref.var [template = constants.%.4] -// CHECK:STDOUT: %.loc4_24.3: init (i32,) = converted %.loc4_24.1, %.loc4_24.2 [template = constants.%.4] -// CHECK:STDOUT: assign %a_ref.var, %.loc4_24.3 -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: --- implicit.impl.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = tuple_type (type) [template] -// CHECK:STDOUT: %.2: type = tuple_type (i32) [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {.a_ref = %import_ref, .a = %a} [template] -// CHECK:STDOUT: %import_ref: ref = import_ref ir1, inst+6, used -// CHECK:STDOUT: %.loc4_13.1: (type,) = tuple_literal (i32) -// CHECK:STDOUT: %.loc4_13.2: type = converted %.loc4_13.1, constants.%.2 [template = constants.%.2] -// CHECK:STDOUT: %a.var: ref (i32,) = var a -// CHECK:STDOUT: %a: ref (i32,) = bind_name a, %a.var -// CHECK:STDOUT: %a_ref.ref: ref = name_ref a_ref, %import_ref -// CHECK:STDOUT: assign %a.var, -// CHECK:STDOUT: } -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/tuples/import.carbon b/toolchain/check/testdata/tuples/import.carbon new file mode 100644 index 000000000000..757049f889a8 --- /dev/null +++ b/toolchain/check/testdata/tuples/import.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 + +// --- implicit.carbon + +package Implicit api; + +var a_ref: (i32,) = (0,); +var b_ref: (((i32,), i32), (i32, i32)) = (((0,), 1), (2, 3)); + +// --- implicit.impl.carbon + +package Implicit impl; + +var a: (i32,) = a_ref; +var b: (((i32,), i32), (i32, i32)) = b_ref; + +// CHECK:STDOUT: --- implicit.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = tuple_type (type) [template] +// CHECK:STDOUT: %.2: type = tuple_type (i32) [template] +// CHECK:STDOUT: %.3: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.4: (i32,) = tuple_value (%.3) [template] +// CHECK:STDOUT: %.5: type = tuple_type ((type,), type) [template] +// CHECK:STDOUT: %.6: type = tuple_type (type, type) [template] +// CHECK:STDOUT: %.7: type = tuple_type (((type,), type), (type, type)) [template] +// CHECK:STDOUT: %.8: type = tuple_type ((i32,), i32) [template] +// CHECK:STDOUT: %.9: type = tuple_type (i32, i32) [template] +// CHECK:STDOUT: %.10: type = tuple_type (((i32,), i32), (i32, i32)) [template] +// CHECK:STDOUT: %.11: type = ptr_type (i32, i32) [template] +// CHECK:STDOUT: %.12: type = ptr_type ((i32,), i32) [template] +// CHECK:STDOUT: %.13: type = tuple_type (((i32,), i32)*, (i32, i32)*) [template] +// CHECK:STDOUT: %.14: type = ptr_type (((i32,), i32)*, (i32, i32)*) [template] +// CHECK:STDOUT: %.15: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.16: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.17: i32 = int_literal 3 [template] +// CHECK:STDOUT: %.18: ((i32,), i32) = tuple_value (%.4, %.15) [template] +// CHECK:STDOUT: %.19: (i32, i32) = tuple_value (%.16, %.17) [template] +// CHECK:STDOUT: %.20: (((i32,), i32), (i32, i32)) = tuple_value (%.18, %.19) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.a_ref = %a_ref, .b_ref = %b_ref} [template] +// CHECK:STDOUT: %.loc4_17.1: (type,) = tuple_literal (i32) +// CHECK:STDOUT: %.loc4_17.2: type = converted %.loc4_17.1, constants.%.2 [template = constants.%.2] +// CHECK:STDOUT: %a_ref.var: ref (i32,) = var a_ref +// CHECK:STDOUT: %a_ref: ref (i32,) = bind_name a_ref, %a_ref.var +// CHECK:STDOUT: %.loc4_22: i32 = int_literal 0 [template = constants.%.3] +// CHECK:STDOUT: %.loc4_24.1: (i32,) = tuple_literal (%.loc4_22) +// CHECK:STDOUT: %.loc4_24.2: init (i32,) = tuple_init (%.loc4_22) to %a_ref.var [template = constants.%.4] +// CHECK:STDOUT: %.loc4_24.3: init (i32,) = converted %.loc4_24.1, %.loc4_24.2 [template = constants.%.4] +// CHECK:STDOUT: assign %a_ref.var, %.loc4_24.3 +// CHECK:STDOUT: %.loc5_19.1: (type,) = tuple_literal (i32) +// CHECK:STDOUT: %.loc5_25.1: ((type,), type) = tuple_literal (%.loc5_19.1, i32) +// CHECK:STDOUT: %.loc5_37.1: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc5_38.1: (((type,), type), (type, type)) = tuple_literal (%.loc5_25.1, %.loc5_37.1) +// CHECK:STDOUT: %.loc5_19.2: type = converted %.loc5_19.1, constants.%.2 [template = constants.%.2] +// CHECK:STDOUT: %.loc5_25.2: type = converted %.loc5_25.1, constants.%.8 [template = constants.%.8] +// CHECK:STDOUT: %.loc5_37.2: type = converted %.loc5_37.1, constants.%.9 [template = constants.%.9] +// CHECK:STDOUT: %.loc5_38.2: type = converted %.loc5_38.1, constants.%.10 [template = constants.%.10] +// CHECK:STDOUT: %b_ref.var: ref (((i32,), i32), (i32, i32)) = var b_ref +// CHECK:STDOUT: %b_ref: ref (((i32,), i32), (i32, i32)) = bind_name b_ref, %b_ref.var +// CHECK:STDOUT: %.loc5_45: i32 = int_literal 0 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_47.1: (i32,) = tuple_literal (%.loc5_45) +// CHECK:STDOUT: %.loc5_50: i32 = int_literal 1 [template = constants.%.15] +// CHECK:STDOUT: %.loc5_51.1: ((i32,), i32) = tuple_literal (%.loc5_47.1, %.loc5_50) +// CHECK:STDOUT: %.loc5_55: i32 = int_literal 2 [template = constants.%.16] +// CHECK:STDOUT: %.loc5_58: i32 = int_literal 3 [template = constants.%.17] +// CHECK:STDOUT: %.loc5_59.1: (i32, i32) = tuple_literal (%.loc5_55, %.loc5_58) +// CHECK:STDOUT: %.loc5_60.1: (((i32,), i32), (i32, i32)) = tuple_literal (%.loc5_51.1, %.loc5_59.1) +// CHECK:STDOUT: %.loc5_60.2: ref ((i32,), i32) = tuple_access %b_ref.var, element0 +// CHECK:STDOUT: %.loc5_51.2: ref (i32,) = tuple_access %.loc5_60.2, element0 +// CHECK:STDOUT: %.loc5_47.2: init (i32,) = tuple_init (%.loc5_45) to %.loc5_51.2 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_47.3: init (i32,) = converted %.loc5_47.1, %.loc5_47.2 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_51.3: init (i32,) = initialize_from %.loc5_47.3 to %.loc5_51.2 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_51.4: ref i32 = tuple_access %.loc5_60.2, element1 +// CHECK:STDOUT: %.loc5_51.5: init i32 = initialize_from %.loc5_50 to %.loc5_51.4 [template = constants.%.15] +// CHECK:STDOUT: %.loc5_51.6: init ((i32,), i32) = tuple_init (%.loc5_51.3, %.loc5_51.5) to %.loc5_60.2 [template = constants.%.18] +// CHECK:STDOUT: %.loc5_51.7: init ((i32,), i32) = converted %.loc5_51.1, %.loc5_51.6 [template = constants.%.18] +// CHECK:STDOUT: %.loc5_60.3: ref (i32, i32) = tuple_access %b_ref.var, element1 +// CHECK:STDOUT: %.loc5_59.2: ref i32 = tuple_access %.loc5_60.3, element0 +// CHECK:STDOUT: %.loc5_59.3: init i32 = initialize_from %.loc5_55 to %.loc5_59.2 [template = constants.%.16] +// CHECK:STDOUT: %.loc5_59.4: ref i32 = tuple_access %.loc5_60.3, element1 +// CHECK:STDOUT: %.loc5_59.5: init i32 = initialize_from %.loc5_58 to %.loc5_59.4 [template = constants.%.17] +// CHECK:STDOUT: %.loc5_59.6: init (i32, i32) = tuple_init (%.loc5_59.3, %.loc5_59.5) to %.loc5_60.3 [template = constants.%.19] +// CHECK:STDOUT: %.loc5_59.7: init (i32, i32) = converted %.loc5_59.1, %.loc5_59.6 [template = constants.%.19] +// CHECK:STDOUT: %.loc5_60.4: init (((i32,), i32), (i32, i32)) = tuple_init (%.loc5_51.7, %.loc5_59.7) to %b_ref.var [template = constants.%.20] +// CHECK:STDOUT: %.loc5_60.5: init (((i32,), i32), (i32, i32)) = converted %.loc5_60.1, %.loc5_60.4 [template = constants.%.20] +// CHECK:STDOUT: assign %b_ref.var, %.loc5_60.5 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = tuple_type (type) [template] +// CHECK:STDOUT: %.2: type = tuple_type (i32) [template] +// CHECK:STDOUT: %.3: type = tuple_type ((type,), type) [template] +// CHECK:STDOUT: %.4: type = tuple_type (type, type) [template] +// CHECK:STDOUT: %.5: type = tuple_type (((type,), type), (type, type)) [template] +// CHECK:STDOUT: %.6: type = tuple_type ((i32,), i32) [template] +// CHECK:STDOUT: %.7: type = tuple_type (i32, i32) [template] +// CHECK:STDOUT: %.8: type = tuple_type (((i32,), i32), (i32, i32)) [template] +// CHECK:STDOUT: %.9: type = ptr_type (i32, i32) [template] +// CHECK:STDOUT: %.10: type = ptr_type ((i32,), i32) [template] +// CHECK:STDOUT: %.11: type = tuple_type (((i32,), i32)*, (i32, i32)*) [template] +// CHECK:STDOUT: %.12: type = ptr_type (((i32,), i32)*, (i32, i32)*) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.a_ref = %import_ref.1, .b_ref = %import_ref.2, .a = %a, .b = %b} [template] +// CHECK:STDOUT: %import_ref.1: ref (i32,) = import_ref ir1, inst+6, used +// CHECK:STDOUT: %import_ref.2: ref (((i32,), i32), (i32, i32)) = import_ref ir1, inst+34, used +// CHECK:STDOUT: %.loc4_13.1: (type,) = tuple_literal (i32) +// CHECK:STDOUT: %.loc4_13.2: type = converted %.loc4_13.1, constants.%.2 [template = constants.%.2] +// CHECK:STDOUT: %a.var: ref (i32,) = var a +// CHECK:STDOUT: %a: ref (i32,) = bind_name a, %a.var +// CHECK:STDOUT: %a_ref.ref: ref (i32,) = name_ref a_ref, %import_ref.1 +// CHECK:STDOUT: %.loc4_17.1: ref i32 = tuple_access %a_ref.ref, element0 +// CHECK:STDOUT: %.loc4_17.2: i32 = bind_value %.loc4_17.1 +// CHECK:STDOUT: %.loc4_17.3: init (i32,) = tuple_init (%.loc4_17.2) to %a.var +// CHECK:STDOUT: %.loc4_17.4: init (i32,) = converted %a_ref.ref, %.loc4_17.3 +// CHECK:STDOUT: assign %a.var, %.loc4_17.4 +// CHECK:STDOUT: %.loc5_15.1: (type,) = tuple_literal (i32) +// CHECK:STDOUT: %.loc5_21.1: ((type,), type) = tuple_literal (%.loc5_15.1, i32) +// CHECK:STDOUT: %.loc5_33.1: (type, type) = tuple_literal (i32, i32) +// CHECK:STDOUT: %.loc5_34.1: (((type,), type), (type, type)) = tuple_literal (%.loc5_21.1, %.loc5_33.1) +// CHECK:STDOUT: %.loc5_15.2: type = converted %.loc5_15.1, constants.%.2 [template = constants.%.2] +// CHECK:STDOUT: %.loc5_21.2: type = converted %.loc5_21.1, constants.%.6 [template = constants.%.6] +// CHECK:STDOUT: %.loc5_33.2: type = converted %.loc5_33.1, constants.%.7 [template = constants.%.7] +// CHECK:STDOUT: %.loc5_34.2: type = converted %.loc5_34.1, constants.%.8 [template = constants.%.8] +// CHECK:STDOUT: %b.var: ref (((i32,), i32), (i32, i32)) = var b +// CHECK:STDOUT: %b: ref (((i32,), i32), (i32, i32)) = bind_name b, %b.var +// CHECK:STDOUT: %b_ref.ref: ref (((i32,), i32), (i32, i32)) = name_ref b_ref, %import_ref.2 +// CHECK:STDOUT: %.loc5_38.1: ref ((i32,), i32) = tuple_access %b_ref.ref, element0 +// CHECK:STDOUT: %.loc5_38.2: ref (i32,) = tuple_access %.loc5_38.1, element0 +// CHECK:STDOUT: %.loc5_38.3: ref i32 = tuple_access %.loc5_38.2, element0 +// CHECK:STDOUT: %.loc5_38.4: i32 = bind_value %.loc5_38.3 +// CHECK:STDOUT: %.loc5_38.5: ref ((i32,), i32) = tuple_access %b.var, element0 +// CHECK:STDOUT: %.loc5_38.6: ref (i32,) = tuple_access %.loc5_38.5, element0 +// CHECK:STDOUT: %.loc5_38.7: init (i32,) = tuple_init (%.loc5_38.4) to %.loc5_38.6 +// CHECK:STDOUT: %.loc5_38.8: init (i32,) = converted %.loc5_38.2, %.loc5_38.7 +// CHECK:STDOUT: %.loc5_38.9: init (i32,) = initialize_from %.loc5_38.8 to %.loc5_38.6 +// CHECK:STDOUT: %.loc5_38.10: ref i32 = tuple_access %.loc5_38.1, element1 +// CHECK:STDOUT: %.loc5_38.11: i32 = bind_value %.loc5_38.10 +// CHECK:STDOUT: %.loc5_38.12: ref i32 = tuple_access %.loc5_38.5, element1 +// CHECK:STDOUT: %.loc5_38.13: init i32 = initialize_from %.loc5_38.11 to %.loc5_38.12 +// CHECK:STDOUT: %.loc5_38.14: init ((i32,), i32) = tuple_init (%.loc5_38.9, %.loc5_38.13) to %.loc5_38.5 +// CHECK:STDOUT: %.loc5_38.15: init ((i32,), i32) = converted %.loc5_38.1, %.loc5_38.14 +// CHECK:STDOUT: %.loc5_38.16: ref (i32, i32) = tuple_access %b_ref.ref, element1 +// CHECK:STDOUT: %.loc5_38.17: ref i32 = tuple_access %.loc5_38.16, element0 +// CHECK:STDOUT: %.loc5_38.18: i32 = bind_value %.loc5_38.17 +// CHECK:STDOUT: %.loc5_38.19: ref (i32, i32) = tuple_access %b.var, element1 +// CHECK:STDOUT: %.loc5_38.20: ref i32 = tuple_access %.loc5_38.19, element0 +// CHECK:STDOUT: %.loc5_38.21: init i32 = initialize_from %.loc5_38.18 to %.loc5_38.20 +// CHECK:STDOUT: %.loc5_38.22: ref i32 = tuple_access %.loc5_38.16, element1 +// CHECK:STDOUT: %.loc5_38.23: i32 = bind_value %.loc5_38.22 +// CHECK:STDOUT: %.loc5_38.24: ref i32 = tuple_access %.loc5_38.19, element1 +// CHECK:STDOUT: %.loc5_38.25: init i32 = initialize_from %.loc5_38.23 to %.loc5_38.24 +// CHECK:STDOUT: %.loc5_38.26: init (i32, i32) = tuple_init (%.loc5_38.21, %.loc5_38.25) to %.loc5_38.19 +// CHECK:STDOUT: %.loc5_38.27: init (i32, i32) = converted %.loc5_38.16, %.loc5_38.26 +// CHECK:STDOUT: %.loc5_38.28: init (((i32,), i32), (i32, i32)) = tuple_init (%.loc5_38.15, %.loc5_38.27) to %b.var +// CHECK:STDOUT: %.loc5_38.29: init (((i32,), i32), (i32, i32)) = converted %b_ref.ref, %.loc5_38.28 +// CHECK:STDOUT: assign %b.var, %.loc5_38.29 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/var/import.carbon b/toolchain/check/testdata/var/import.carbon index 4ceb2bc8976c..0f44154932b4 100644 --- a/toolchain/check/testdata/var/import.carbon +++ b/toolchain/check/testdata/var/import.carbon @@ -2,9 +2,6 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// When there are no more cases that can hit a TODO, remove this test. Until -// then, update it whenever its target is implemented. -// // AUTOUPDATE // --- implicit.carbon