mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 19:31:08 +01:00
@@ -26,6 +26,7 @@
|
||||
#include "toolchain/check/type_completion.h"
|
||||
#include "toolchain/diagnostics/emitter.h"
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/sem_ir/class.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/inst.h"
|
||||
@@ -48,128 +49,6 @@ auto HandleParseNode(Context& context, Parse::ClassIntroducerId node_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Tries to merge new_class into prev_class_id. Since new_class won't have a
|
||||
// definition even if one is upcoming, set is_definition to indicate the planned
|
||||
// result.
|
||||
//
|
||||
// If merging is successful, returns true and may update the previous class.
|
||||
// Otherwise, returns false. Prints a diagnostic when appropriate.
|
||||
static auto MergeClassRedecl(Context& context, Parse::AnyClassDeclId node_id,
|
||||
SemIR::Class& new_class, bool new_is_definition,
|
||||
SemIR::ClassId prev_class_id,
|
||||
SemIR::ImportIRId prev_import_ir_id) -> bool {
|
||||
auto& prev_class = context.classes().Get(prev_class_id);
|
||||
SemIR::LocId prev_loc_id(prev_class.latest_decl_id());
|
||||
|
||||
// Check the generic parameters match, if they were specified.
|
||||
if (!CheckRedeclParamsMatch(context, DeclParams(new_class),
|
||||
DeclParams(prev_class))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DiagnoseIfInvalidRedecl(
|
||||
context, Lex::TokenKind::Class, prev_class.name_id,
|
||||
RedeclInfo(new_class, node_id, new_is_definition),
|
||||
RedeclInfo(prev_class, prev_loc_id, prev_class.has_definition_started()),
|
||||
prev_import_ir_id);
|
||||
|
||||
if (new_is_definition && prev_class.has_definition_started()) {
|
||||
// Don't attempt to merge multiple definitions.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (new_is_definition) {
|
||||
prev_class.MergeDefinition(new_class);
|
||||
}
|
||||
|
||||
if (prev_import_ir_id.has_value() ||
|
||||
(prev_class.is_extern && !new_class.is_extern)) {
|
||||
prev_class.first_owning_decl_id = new_class.first_owning_decl_id;
|
||||
ReplacePrevInstForMerge(context, new_class.parent_scope_id,
|
||||
prev_class.name_id, new_class.first_owning_decl_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adds the name to name lookup. If there's a conflict, tries to merge. May
|
||||
// update class_decl and class_info when merging.
|
||||
static auto MergeOrAddName(Context& context, Parse::AnyClassDeclId node_id,
|
||||
const DeclNameStack::NameContext& name_context,
|
||||
SemIR::InstId class_decl_id,
|
||||
SemIR::ClassDecl& class_decl,
|
||||
SemIR::Class& class_info, bool is_definition,
|
||||
SemIR::AccessKind access_kind) -> void {
|
||||
SemIR::ScopeLookupResult lookup_result =
|
||||
context.decl_name_stack().LookupOrAddName(name_context, class_decl_id,
|
||||
access_kind);
|
||||
if (lookup_result.is_poisoned()) {
|
||||
// This is a declaration of a poisoned name.
|
||||
DiagnosePoisonedName(context, name_context.name_id_for_new_inst(),
|
||||
lookup_result.poisoning_loc_id(), name_context.loc_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lookup_result.is_found()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SemIR::InstId prev_id = lookup_result.target_inst_id();
|
||||
|
||||
auto prev_class_id = SemIR::ClassId::None;
|
||||
auto prev_import_ir_id = SemIR::ImportIRId::None;
|
||||
auto prev = context.insts().Get(prev_id);
|
||||
CARBON_KIND_SWITCH(prev) {
|
||||
case CARBON_KIND(SemIR::ClassDecl class_decl): {
|
||||
prev_class_id = class_decl.class_id;
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::ImportRefLoaded import_ref): {
|
||||
auto import_ir_inst =
|
||||
context.import_ir_insts().Get(import_ref.import_ir_inst_id);
|
||||
|
||||
// Verify the decl so that things like aliases are name conflicts.
|
||||
const auto* import_ir =
|
||||
context.import_irs().Get(import_ir_inst.ir_id()).sem_ir;
|
||||
if (!import_ir->insts().Is<SemIR::ClassDecl>(import_ir_inst.inst_id())) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Use the constant value to get the ID.
|
||||
auto decl_value = context.insts().Get(
|
||||
context.constant_values().GetConstantInstId(prev_id));
|
||||
if (auto class_type = decl_value.TryAs<SemIR::ClassType>()) {
|
||||
prev_class_id = class_type->class_id;
|
||||
prev_import_ir_id = import_ir_inst.ir_id();
|
||||
} else if (auto generic_class_type =
|
||||
context.types().TryGetAs<SemIR::GenericClassType>(
|
||||
decl_value.type_id())) {
|
||||
prev_class_id = generic_class_type->class_id;
|
||||
prev_import_ir_id = import_ir_inst.ir_id();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!prev_class_id.has_value()) {
|
||||
// This is a redeclaration of something other than a class.
|
||||
DiagnoseDuplicateName(context, name_context.name_id, name_context.loc_id,
|
||||
SemIR::LocId(prev_id));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Fix `extern` logic. It doesn't work correctly, but doesn't seem worth
|
||||
// ripping out because existing code may incrementally help.
|
||||
if (MergeClassRedecl(context, node_id, class_info, is_definition,
|
||||
prev_class_id, prev_import_ir_id)) {
|
||||
// When merging, use the existing entity rather than adding a new one.
|
||||
class_decl.class_id = prev_class_id;
|
||||
class_decl.type_id = prev.type_id();
|
||||
// TODO: Validate that the redeclaration doesn't set an access modifier.
|
||||
}
|
||||
}
|
||||
|
||||
static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
|
||||
bool is_definition)
|
||||
-> std::tuple<SemIR::ClassId, SemIR::InstId> {
|
||||
@@ -223,9 +102,13 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
|
||||
|
||||
DiagnoseIfGenericMissingExplicitParameters(context, class_info);
|
||||
|
||||
MergeOrAddName(context, node_id, name_context, class_decl_id, class_decl,
|
||||
class_info, is_definition,
|
||||
introducer.modifier_set.GetAccessKind());
|
||||
SemIR::ScopeLookupResult lookup_result =
|
||||
context.decl_name_stack().LookupOrAddName(
|
||||
name_context, class_decl_id, introducer.modifier_set.GetAccessKind());
|
||||
TryMergeRedecl(context, name_context, lookup_result,
|
||||
MergeRedeclEntityInfo<SemIR::Class>{
|
||||
.new_entity_decl = class_decl, .new_entity = class_info},
|
||||
is_definition);
|
||||
|
||||
// Create a new class if this isn't a valid redeclaration.
|
||||
bool is_new_class = !class_decl.class_id.has_value();
|
||||
|
||||
@@ -141,131 +141,6 @@ static auto GetInterfaceModifier(const KeywordModifierSet& modifier_set)
|
||||
.Default(None);
|
||||
}
|
||||
|
||||
// Tries to merge new_function into prev_function_id. Since new_function won't
|
||||
// have a definition even if one is upcoming, set is_definition to indicate the
|
||||
// planned result.
|
||||
//
|
||||
// If merging is successful, returns true and may update the previous function.
|
||||
// Otherwise, returns false. Prints a diagnostic when appropriate.
|
||||
static auto MergeFunctionRedecl(Context& context,
|
||||
Parse::AnyFunctionDeclId node_id,
|
||||
SemIR::Function& new_function,
|
||||
bool new_is_definition,
|
||||
SemIR::FunctionId prev_function_id,
|
||||
SemIR::ImportIRId prev_import_ir_id) -> bool {
|
||||
auto& prev_function = context.functions().Get(prev_function_id);
|
||||
|
||||
if (!CheckFunctionTypeMatches(context, new_function, prev_function)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DiagnoseIfInvalidRedecl(
|
||||
context, Lex::TokenKind::Fn, prev_function.name_id,
|
||||
RedeclInfo(new_function, node_id, new_is_definition),
|
||||
RedeclInfo(prev_function, SemIR::LocId(prev_function.latest_decl_id()),
|
||||
prev_function.has_definition_started()),
|
||||
prev_import_ir_id);
|
||||
if (new_is_definition && prev_function.has_definition_started()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!prev_function.first_owning_decl_id.has_value()) {
|
||||
prev_function.first_owning_decl_id = new_function.first_owning_decl_id;
|
||||
}
|
||||
if (new_is_definition) {
|
||||
// Track the signature from the definition, so that IDs in the body
|
||||
// match IDs in the signature.
|
||||
prev_function.MergeDefinition(new_function);
|
||||
}
|
||||
if (prev_import_ir_id.has_value()) {
|
||||
ReplacePrevInstForMerge(context, new_function.parent_scope_id,
|
||||
prev_function.name_id,
|
||||
new_function.first_owning_decl_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check whether this is a redeclaration, merging if needed.
|
||||
static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id,
|
||||
const DeclNameStack::NameContext& name_context,
|
||||
SemIR::FunctionDecl& function_decl,
|
||||
SemIR::Function& function_info, bool is_definition)
|
||||
-> void {
|
||||
// Diagnose if we are declaring a poisoned name. However, don't diagnose at
|
||||
// impl scope: if the name was referenced before being declared, we will have
|
||||
// produced an error already.
|
||||
if (name_context.state == DeclNameStack::NameContext::State::Poisoned) {
|
||||
if (!context.name_scopes().InstIs<SemIR::ImplDecl>(
|
||||
name_context.parent_scope_id)) {
|
||||
DiagnosePoisonedName(context, name_context.name_id_for_new_inst(),
|
||||
name_context.poisoning_loc_id, name_context.loc_id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto prev_id = name_context.prev_inst_id();
|
||||
if (!prev_id.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto prev_function_id = SemIR::FunctionId::None;
|
||||
auto prev_type_id = SemIR::TypeId::None;
|
||||
auto prev_import_ir_id = SemIR::ImportIRId::None;
|
||||
CARBON_KIND_SWITCH(context.insts().Get(prev_id)) {
|
||||
case CARBON_KIND(SemIR::AssociatedEntity assoc_entity): {
|
||||
// This is a function in an interface definition scope.
|
||||
auto function_decl =
|
||||
context.insts().GetAs<SemIR::FunctionDecl>(assoc_entity.decl_id);
|
||||
prev_function_id = function_decl.function_id;
|
||||
prev_type_id = function_decl.type_id;
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::FunctionDecl function_decl): {
|
||||
prev_function_id = function_decl.function_id;
|
||||
prev_type_id = function_decl.type_id;
|
||||
break;
|
||||
}
|
||||
case SemIR::ImportRefLoaded::Kind: {
|
||||
auto import_ir_inst = GetCanonicalImportIRInst(context, prev_id);
|
||||
|
||||
// Verify the decl so that things like aliases are name conflicts.
|
||||
const auto* import_ir =
|
||||
context.import_irs().Get(import_ir_inst.ir_id()).sem_ir;
|
||||
if (!import_ir->insts().Is<SemIR::FunctionDecl>(
|
||||
import_ir_inst.inst_id())) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Use the type to get the ID.
|
||||
if (auto struct_value = context.insts().TryGetAs<SemIR::StructValue>(
|
||||
context.constant_values().GetConstantInstId(prev_id))) {
|
||||
if (auto function_type = context.types().TryGetAs<SemIR::FunctionType>(
|
||||
struct_value->type_id)) {
|
||||
prev_function_id = function_type->function_id;
|
||||
prev_type_id = struct_value->type_id;
|
||||
prev_import_ir_id = import_ir_inst.ir_id();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!prev_function_id.has_value()) {
|
||||
DiagnoseDuplicateName(context, name_context.name_id, name_context.loc_id,
|
||||
SemIR::LocId(prev_id));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MergeFunctionRedecl(context, node_id, function_info, is_definition,
|
||||
prev_function_id, prev_import_ir_id)) {
|
||||
// When merging, use the existing function rather than adding a new one.
|
||||
function_decl.function_id = prev_function_id;
|
||||
function_decl.type_id = prev_type_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the declaration to name lookup when appropriate.
|
||||
static auto MaybeAddToNameLookup(Context& context,
|
||||
const DeclNameStack::NameContext& name_context,
|
||||
@@ -580,8 +455,11 @@ static auto BuildFunctionDecl(Context& context,
|
||||
|
||||
DiagnosePositionalParams(context, function_info);
|
||||
|
||||
TryMergeRedecl(context, node_id, name_context, function_decl, function_info,
|
||||
is_definition);
|
||||
TryMergeRedecl(
|
||||
context, name_context, std::nullopt,
|
||||
MergeRedeclEntityInfo<SemIR::Function>{.new_entity_decl = function_decl,
|
||||
.new_entity = function_info},
|
||||
is_definition);
|
||||
|
||||
// Create a new function if this isn't a valid redeclaration.
|
||||
if (!function_decl.function_id.has_value()) {
|
||||
|
||||
@@ -73,12 +73,11 @@ static auto BuildInterfaceDecl(Context& context,
|
||||
SemIR::ScopeLookupResult lookup_result =
|
||||
context.decl_name_stack().LookupOrAddName(
|
||||
name_context, decl_inst_id, introducer.modifier_set.GetAccessKind());
|
||||
if (auto existing_decl = TryGetExistingDecl(context, name, lookup_result,
|
||||
interface_info, is_definition)) {
|
||||
auto existing_interface_decl = existing_decl->As<SemIR::InterfaceDecl>();
|
||||
interface_decl.interface_id = existing_interface_decl.interface_id;
|
||||
interface_decl.type_id = existing_interface_decl.type_id;
|
||||
|
||||
if (TryMergeRedecl(
|
||||
context, name_context, lookup_result,
|
||||
MergeRedeclEntityInfo<SemIR::Interface>{
|
||||
.new_entity_decl = interface_decl, .new_entity = interface_info},
|
||||
is_definition)) {
|
||||
auto prev_decl_generic_id =
|
||||
context.interfaces().Get(interface_decl.interface_id).generic_id;
|
||||
FinishGenericRedecl(context, prev_decl_generic_id);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/interface.h"
|
||||
#include "toolchain/check/merge.h"
|
||||
#include "toolchain/check/modifiers.h"
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
@@ -69,17 +70,11 @@ static auto BuildNamedConstraintDecl(Context& context,
|
||||
SemIR::ScopeLookupResult lookup_result =
|
||||
context.decl_name_stack().LookupOrAddName(
|
||||
name_context, decl_inst_id, introducer.modifier_set.GetAccessKind());
|
||||
if (auto existing_decl = TryGetExistingDecl(context, name, lookup_result,
|
||||
constraint_info, is_definition)) {
|
||||
auto existing_constraint_decl =
|
||||
existing_decl->As<SemIR::NamedConstraintDecl>();
|
||||
constraint_decl.named_constraint_id =
|
||||
existing_constraint_decl.named_constraint_id;
|
||||
constraint_decl.type_id = existing_constraint_decl.type_id;
|
||||
// TODO: If the new declaration is a definition, keep its parameter
|
||||
// and implicit parameter lists rather than the ones from the
|
||||
// previous declaration.
|
||||
|
||||
if (TryMergeRedecl(context, name_context, lookup_result,
|
||||
MergeRedeclEntityInfo<SemIR::NamedConstraint>{
|
||||
.new_entity_decl = constraint_decl,
|
||||
.new_entity = constraint_info},
|
||||
is_definition)) {
|
||||
auto prev_decl_generic_id = context.named_constraints()
|
||||
.Get(constraint_decl.named_constraint_id)
|
||||
.generic_id;
|
||||
|
||||
@@ -156,167 +156,4 @@ auto AddSelfSymbolicBindingToScope(Context& context,
|
||||
return self_param_inst_id;
|
||||
}
|
||||
|
||||
template <typename EntityT>
|
||||
requires std::same_as<EntityT, SemIR::Interface>
|
||||
static constexpr auto DeclTokenKind() -> Lex::TokenKind {
|
||||
return Lex::TokenKind::Interface;
|
||||
}
|
||||
|
||||
template <typename EntityT>
|
||||
requires std::same_as<EntityT, SemIR::NamedConstraint>
|
||||
static constexpr auto DeclTokenKind() -> Lex::TokenKind {
|
||||
return Lex::TokenKind::Constraint;
|
||||
}
|
||||
|
||||
template <typename EntityT>
|
||||
requires SameAsOneOf<EntityT, SemIR::Interface, SemIR::NamedConstraint>
|
||||
auto TryGetExistingDecl(Context& context, const NameComponent& name,
|
||||
SemIR::ScopeLookupResult lookup_result,
|
||||
const EntityT& entity, bool is_definition)
|
||||
-> std::optional<SemIR::Inst> {
|
||||
using EntityIdT =
|
||||
std::conditional_t<std::is_same_v<EntityT, SemIR::Interface>,
|
||||
SemIR::InterfaceId, SemIR::NamedConstraintId>;
|
||||
constexpr bool IsInterface = std::is_same_v<EntityIdT, SemIR::InterfaceId>;
|
||||
|
||||
if (lookup_result.is_poisoned()) {
|
||||
// This is a declaration of a poisoned name.
|
||||
DiagnosePoisonedName(context, name.name_id,
|
||||
lookup_result.poisoning_loc_id(), name.name_loc_id);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!lookup_result.is_found()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto prev_id = lookup_result.target_inst_id();
|
||||
auto prev = context.insts().Get(prev_id);
|
||||
|
||||
auto prev_entity_id = EntityIdT::None;
|
||||
auto prev_import_ir_id = SemIR::ImportIRId::None;
|
||||
auto existing_decl_id = SemIR::InstId::None;
|
||||
CARBON_KIND_SWITCH(prev) {
|
||||
case CARBON_KIND(SemIR::InterfaceDecl interface_decl): {
|
||||
if constexpr (IsInterface) {
|
||||
prev_entity_id = interface_decl.interface_id;
|
||||
existing_decl_id = prev_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::NamedConstraintDecl named_constraint_decl): {
|
||||
if constexpr (!IsInterface) {
|
||||
prev_entity_id = named_constraint_decl.named_constraint_id;
|
||||
existing_decl_id = prev_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::ImportRefLoaded import_ref): {
|
||||
auto import_ir_inst =
|
||||
context.import_ir_insts().Get(import_ref.import_ir_inst_id);
|
||||
|
||||
// Verify the decl so that things like aliases are name conflicts.
|
||||
const auto* import_ir =
|
||||
context.import_irs().Get(import_ir_inst.ir_id()).sem_ir;
|
||||
if constexpr (IsInterface) {
|
||||
if (!import_ir->insts().Is<SemIR::InterfaceDecl>(
|
||||
import_ir_inst.inst_id())) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!import_ir->insts().Is<SemIR::NamedConstraintDecl>(
|
||||
import_ir_inst.inst_id())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Use the constant value to get the ID.
|
||||
auto decl_value = context.insts().Get(
|
||||
context.constant_values().GetConstantInstId(prev_id));
|
||||
if (auto facet_type = decl_value.TryAs<SemIR::FacetType>()) {
|
||||
auto declared_facet_type = context.declared_facet_types().Get(
|
||||
facet_type->declared_facet_type_id);
|
||||
if constexpr (IsInterface) {
|
||||
prev_entity_id =
|
||||
declared_facet_type.extend_constraints[0].interface_id;
|
||||
} else {
|
||||
prev_entity_id = declared_facet_type.extend_named_constraints[0]
|
||||
.named_constraint_id;
|
||||
}
|
||||
prev_import_ir_id = import_ir_inst.ir_id();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!prev_entity_id.has_value()) {
|
||||
// This is a redeclaration with a different entity kind.
|
||||
DiagnoseDuplicateName(context, name.name_id, name.name_loc_id,
|
||||
SemIR::LocId(prev_id));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto& prev_entity = [&]() -> EntityT& {
|
||||
if constexpr (IsInterface) {
|
||||
return context.interfaces().Get(prev_entity_id);
|
||||
} else {
|
||||
return context.named_constraints().Get(prev_entity_id);
|
||||
}
|
||||
}();
|
||||
|
||||
if (!CheckRedeclParamsMatch(
|
||||
context,
|
||||
DeclParams(SemIR::LocId(entity.latest_decl_id()),
|
||||
name.first_param_node_id, name.last_param_node_id,
|
||||
name.implicit_param_patterns_id, name.param_patterns_id),
|
||||
DeclParams(prev_entity))) {
|
||||
// Mismatch is diagnosed already if found.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
DiagnoseIfInvalidRedecl(
|
||||
context, DeclTokenKind<EntityT>(), prev_entity.name_id,
|
||||
RedeclInfo(entity, SemIR::LocId(entity.latest_decl_id()), is_definition),
|
||||
RedeclInfo(prev_entity, SemIR::LocId(prev_entity.latest_decl_id()),
|
||||
prev_entity.has_definition_started()),
|
||||
prev_import_ir_id);
|
||||
|
||||
if (is_definition && prev_entity.has_definition_started()) {
|
||||
// DiagnoseIfInvalidRedecl would diagnose an error in this case, since we'd
|
||||
// have two definitions. Given the declaration parts of the definitions
|
||||
// match, we would be able to use the prior declaration for error recovery,
|
||||
// except that having two definitions causes larger problems for generics.
|
||||
// All interfaces (and named constraints) are generic with an implicit Self
|
||||
// compile time binding.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (is_definition) {
|
||||
prev_entity.MergeDefinition(entity);
|
||||
}
|
||||
|
||||
if (prev_import_ir_id.has_value()) {
|
||||
prev_entity.first_owning_decl_id = entity.first_owning_decl_id;
|
||||
ReplacePrevInstForMerge(context, entity.parent_scope_id,
|
||||
prev_entity.name_id, entity.first_owning_decl_id);
|
||||
}
|
||||
|
||||
// This is a matching redeclaration of an existing entity of the same type.
|
||||
return existing_decl_id.has_value() ? std::optional<SemIR::Inst>(prev)
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
template auto TryGetExistingDecl(Context& context, const NameComponent& name,
|
||||
SemIR::ScopeLookupResult lookup_result,
|
||||
const SemIR::Interface& entity,
|
||||
bool is_definition)
|
||||
-> std::optional<SemIR::Inst>;
|
||||
template auto TryGetExistingDecl(Context& context, const NameComponent& name,
|
||||
SemIR::ScopeLookupResult lookup_result,
|
||||
const SemIR::NamedConstraint& entity,
|
||||
bool is_definition)
|
||||
-> std::optional<SemIR::Inst>;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
@@ -560,4 +560,329 @@ auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fills the previous class id, type id, and import ir id.
|
||||
static auto FillPrevEntityInfo(Context& context,
|
||||
const SemIR::ImportIRInst& import_ir_inst,
|
||||
SemIR::Inst decl_val,
|
||||
SemIR::ClassId& prev_entity_id,
|
||||
SemIR::TypeId& prev_type_id,
|
||||
SemIR::ImportIRId& prev_import_ir_id) -> void {
|
||||
// Verify the decl so that things like aliases are name conflicts.
|
||||
const auto* import_ir =
|
||||
context.import_irs().Get(import_ir_inst.ir_id()).sem_ir;
|
||||
if (!import_ir->insts().Is<SemIR::ClassDecl>(import_ir_inst.inst_id())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto class_type = decl_val.TryAs<SemIR::ClassType>()) {
|
||||
prev_entity_id = class_type->class_id;
|
||||
prev_type_id = SemIR::TypeId::None;
|
||||
prev_import_ir_id = import_ir_inst.ir_id();
|
||||
} else if (auto generic_class_type =
|
||||
context.types().TryGetAs<SemIR::GenericClassType>(
|
||||
decl_val.type_id())) {
|
||||
prev_entity_id = generic_class_type->class_id;
|
||||
prev_type_id = SemIR::TypeId::None;
|
||||
prev_import_ir_id = import_ir_inst.ir_id();
|
||||
}
|
||||
}
|
||||
|
||||
// Fills the previous function id, type id, and import ir id.
|
||||
static auto FillPrevEntityInfo(Context& context,
|
||||
const SemIR::ImportIRInst& import_ir_inst,
|
||||
SemIR::Inst decl_val,
|
||||
SemIR::FunctionId& prev_entity_id,
|
||||
SemIR::TypeId& prev_type_id,
|
||||
SemIR::ImportIRId& prev_import_ir_id) -> void {
|
||||
// Verify the decl so that things like aliases are name conflicts.
|
||||
const auto* import_ir =
|
||||
context.import_irs().Get(import_ir_inst.ir_id()).sem_ir;
|
||||
if (!import_ir->insts().Is<SemIR::FunctionDecl>(import_ir_inst.inst_id())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto struct_value = decl_val.TryAs<SemIR::StructValue>()) {
|
||||
if (auto function_type = context.types().TryGetAs<SemIR::FunctionType>(
|
||||
struct_value->type_id)) {
|
||||
prev_entity_id = function_type->function_id;
|
||||
prev_type_id = struct_value->type_id;
|
||||
prev_import_ir_id = import_ir_inst.ir_id();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fills the previous interface id, type id, and import ir id.
|
||||
static auto FillPrevEntityInfo(Context& context,
|
||||
const SemIR::ImportIRInst& import_ir_inst,
|
||||
SemIR::Inst decl_val,
|
||||
SemIR::InterfaceId& prev_entity_id,
|
||||
SemIR::TypeId& prev_type_id,
|
||||
SemIR::ImportIRId& prev_import_ir_id) -> void {
|
||||
// Verify the decl so that things like aliases are name conflicts.
|
||||
const auto* import_ir =
|
||||
context.import_irs().Get(import_ir_inst.ir_id()).sem_ir;
|
||||
if (!import_ir->insts().Is<SemIR::InterfaceDecl>(import_ir_inst.inst_id())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto facet_type = decl_val.TryAs<SemIR::FacetType>()) {
|
||||
auto declared_facet_type =
|
||||
context.declared_facet_types().Get(facet_type->declared_facet_type_id);
|
||||
prev_entity_id = declared_facet_type.extend_constraints[0].interface_id;
|
||||
prev_type_id = SemIR::TypeId::None;
|
||||
prev_import_ir_id = import_ir_inst.ir_id();
|
||||
}
|
||||
}
|
||||
|
||||
// Fills the previous named constraint id, type id, and import ir id.
|
||||
static auto FillPrevEntityInfo(Context& context,
|
||||
const SemIR::ImportIRInst& import_ir_inst,
|
||||
SemIR::Inst decl_val,
|
||||
SemIR::NamedConstraintId& prev_entity_id,
|
||||
SemIR::TypeId& prev_type_id,
|
||||
SemIR::ImportIRId& prev_import_ir_id) -> void {
|
||||
// Verify the decl so that things like aliases are name conflicts.
|
||||
const auto* import_ir =
|
||||
context.import_irs().Get(import_ir_inst.ir_id()).sem_ir;
|
||||
if (!import_ir->insts().Is<SemIR::NamedConstraintDecl>(
|
||||
import_ir_inst.inst_id())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto facet_type = decl_val.TryAs<SemIR::FacetType>()) {
|
||||
auto declared_facet_type =
|
||||
context.declared_facet_types().Get(facet_type->declared_facet_type_id);
|
||||
prev_entity_id =
|
||||
declared_facet_type.extend_named_constraints[0].named_constraint_id;
|
||||
prev_type_id = SemIR::TypeId::None;
|
||||
prev_import_ir_id = import_ir_inst.ir_id();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename EntityT>
|
||||
auto TryMergeRedecl(Context& context,
|
||||
const DeclNameStack::NameContext& name_context,
|
||||
std::optional<SemIR::ScopeLookupResult> lookup_result,
|
||||
MergeRedeclEntityInfo<EntityT> entity_info,
|
||||
bool is_definition) -> bool {
|
||||
constexpr bool IsClass = std::is_same_v<EntityT, SemIR::Class>;
|
||||
constexpr bool IsFunction = std::is_same_v<EntityT, SemIR::Function>;
|
||||
constexpr bool IsInterface = std::is_same_v<EntityT, SemIR::Interface>;
|
||||
constexpr bool IsNamedConstraint =
|
||||
std::is_same_v<EntityT, SemIR::NamedConstraint>;
|
||||
|
||||
if constexpr (IsFunction) {
|
||||
CARBON_CHECK(!lookup_result.has_value());
|
||||
// Diagnose if we are declaring a poisoned name. However, don't diagnose
|
||||
// at impl scope: if the name was referenced before being declared, we
|
||||
// will have produced an error already.
|
||||
if (name_context.state == DeclNameStack::NameContext::State::Poisoned) {
|
||||
if (!context.name_scopes().InstIs<SemIR::ImplDecl>(
|
||||
name_context.parent_scope_id)) {
|
||||
DiagnosePoisonedName(context, name_context.name_id_for_new_inst(),
|
||||
name_context.poisoning_loc_id,
|
||||
name_context.loc_id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else if constexpr (IsClass || IsInterface || IsNamedConstraint) {
|
||||
CARBON_CHECK(lookup_result.has_value());
|
||||
if (lookup_result->is_poisoned()) {
|
||||
DiagnosePoisonedName(context, name_context.name_id_for_new_inst(),
|
||||
lookup_result->poisoning_loc_id(),
|
||||
name_context.loc_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lookup_result->is_found()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
CARBON_FATAL("Unhandled entity type.");
|
||||
}
|
||||
|
||||
auto prev_id = lookup_result ? lookup_result->target_inst_id()
|
||||
: name_context.prev_inst_id();
|
||||
if (!prev_id.has_value()) {
|
||||
return false;
|
||||
}
|
||||
auto prev = context.insts().Get(prev_id);
|
||||
|
||||
auto prev_entity_id = MergeRedeclEntityInfo<EntityT>::EntityIdT::None;
|
||||
auto prev_type_id = SemIR::TypeId::None;
|
||||
auto prev_import_ir_id = SemIR::ImportIRId::None;
|
||||
CARBON_KIND_SWITCH(prev) {
|
||||
case CARBON_KIND(SemIR::AssociatedEntity assoc_entity): {
|
||||
if constexpr (IsFunction) {
|
||||
// This is a function in an interface definition scope.
|
||||
auto function_decl =
|
||||
context.insts().GetAs<SemIR::FunctionDecl>(assoc_entity.decl_id);
|
||||
prev_entity_id = function_decl.function_id;
|
||||
prev_type_id = function_decl.type_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::ClassDecl class_decl): {
|
||||
if constexpr (IsClass) {
|
||||
prev_entity_id = class_decl.class_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::FunctionDecl function_decl): {
|
||||
if constexpr (IsFunction) {
|
||||
prev_entity_id = function_decl.function_id;
|
||||
prev_type_id = function_decl.type_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::InterfaceDecl interface_decl): {
|
||||
if constexpr (IsInterface) {
|
||||
prev_entity_id = interface_decl.interface_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::NamedConstraintDecl named_constraint_decl): {
|
||||
if constexpr (IsNamedConstraint) {
|
||||
prev_entity_id = named_constraint_decl.named_constraint_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::ImportRefLoaded import_ref): {
|
||||
// TODO: Should we get canonical inst for all entity types?
|
||||
auto import_ir_inst = [&]() -> SemIR::ImportIRInst {
|
||||
if constexpr (IsClass || IsInterface || IsNamedConstraint) {
|
||||
return context.import_ir_insts().Get(import_ref.import_ir_inst_id);
|
||||
} else if constexpr (IsFunction) {
|
||||
return GetCanonicalImportIRInst(context, prev_id);
|
||||
} else {
|
||||
CARBON_FATAL("Unhandled entity type.");
|
||||
}
|
||||
}();
|
||||
auto decl_val = context.insts().Get(
|
||||
context.constant_values().GetConstantInstId(prev_id));
|
||||
FillPrevEntityInfo(context, import_ir_inst, decl_val, prev_entity_id,
|
||||
prev_type_id, prev_import_ir_id);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prev_entity_id.has_value()) {
|
||||
// This is a redeclaration with a different entity kind.
|
||||
DiagnoseDuplicateName(context, name_context.name_id, name_context.loc_id,
|
||||
SemIR::LocId(prev_id));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& prev_entity = [&]() -> EntityT& {
|
||||
if constexpr (IsClass) {
|
||||
return context.classes().Get(prev_entity_id);
|
||||
} else if constexpr (IsFunction) {
|
||||
return context.functions().Get(prev_entity_id);
|
||||
} else if constexpr (IsInterface) {
|
||||
return context.interfaces().Get(prev_entity_id);
|
||||
} else if constexpr (IsNamedConstraint) {
|
||||
return context.named_constraints().Get(prev_entity_id);
|
||||
} else {
|
||||
CARBON_FATAL("Unhandled entity type.");
|
||||
}
|
||||
}();
|
||||
|
||||
if constexpr (IsClass || IsInterface || IsNamedConstraint) {
|
||||
if (!CheckRedeclParamsMatch(context, DeclParams(entity_info.new_entity),
|
||||
DeclParams(prev_entity))) {
|
||||
// Mismatch is diagnosed already if found.
|
||||
return false;
|
||||
}
|
||||
} else if constexpr (IsFunction) {
|
||||
if (!CheckFunctionTypeMatches(context, entity_info.new_entity,
|
||||
prev_entity)) {
|
||||
// Mismatch is diagnosed already if found.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
CARBON_FATAL("Unhandled entity type.");
|
||||
}
|
||||
|
||||
DiagnoseIfInvalidRedecl(
|
||||
context, MergeRedeclEntityInfo<EntityT>::DeclTokenKind,
|
||||
prev_entity.name_id,
|
||||
RedeclInfo(entity_info.new_entity,
|
||||
SemIR::LocId(entity_info.new_entity.latest_decl_id()),
|
||||
is_definition),
|
||||
RedeclInfo(prev_entity, SemIR::LocId(prev_entity.latest_decl_id()),
|
||||
prev_entity.has_definition_started()),
|
||||
prev_import_ir_id);
|
||||
|
||||
if (is_definition && prev_entity.has_definition_started()) {
|
||||
// DiagnoseIfInvalidRedecl would diagnose an error in this case, since we'd
|
||||
// have two definitions. Given the declaration parts of the definitions
|
||||
// match, we would be able to use the prior declaration for error recovery,
|
||||
// except that having two definitions causes larger problems for generics.
|
||||
// All interfaces (and named constraints) are generic with an implicit Self
|
||||
// compile time binding.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!prev_entity.first_owning_decl_id.has_value()) {
|
||||
prev_entity.first_owning_decl_id =
|
||||
entity_info.new_entity.first_owning_decl_id;
|
||||
}
|
||||
|
||||
if (is_definition) {
|
||||
prev_entity.MergeDefinition(entity_info.new_entity);
|
||||
}
|
||||
|
||||
auto replace_prev_inst = prev_import_ir_id.has_value();
|
||||
if constexpr (IsClass) {
|
||||
replace_prev_inst |=
|
||||
prev_entity.is_extern && !entity_info.new_entity.is_extern;
|
||||
}
|
||||
if (replace_prev_inst) {
|
||||
ReplacePrevInstForMerge(context, entity_info.new_entity.parent_scope_id,
|
||||
prev_entity.name_id,
|
||||
entity_info.new_entity.first_owning_decl_id);
|
||||
}
|
||||
|
||||
// When merging, use the existing entity rather than adding a new one.
|
||||
if constexpr (IsClass) {
|
||||
// TODO: Fix `extern` logic. It doesn't work correctly, but doesn't seem
|
||||
// worth ripping out because existing code may incrementally help.
|
||||
entity_info.new_entity_decl.class_id = prev_entity_id;
|
||||
entity_info.new_entity_decl.type_id = prev.type_id();
|
||||
// TODO: Validate that the redeclaration doesn't set an access modifier.
|
||||
} else if constexpr (IsFunction) {
|
||||
entity_info.new_entity_decl.function_id = prev_entity_id;
|
||||
entity_info.new_entity_decl.type_id = prev_type_id;
|
||||
} else if constexpr (IsInterface) {
|
||||
entity_info.new_entity_decl.interface_id = prev_entity_id;
|
||||
entity_info.new_entity_decl.type_id = prev.type_id();
|
||||
} else if constexpr (IsNamedConstraint) {
|
||||
entity_info.new_entity_decl.named_constraint_id = prev_entity_id;
|
||||
entity_info.new_entity_decl.type_id = prev.type_id();
|
||||
} else {
|
||||
CARBON_FATAL("Unhandled entity type.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template auto TryMergeRedecl(Context&, const DeclNameStack::NameContext&,
|
||||
std::optional<SemIR::ScopeLookupResult>,
|
||||
MergeRedeclEntityInfo<SemIR::Class>, bool) -> bool;
|
||||
template auto TryMergeRedecl(Context&, const DeclNameStack::NameContext&,
|
||||
std::optional<SemIR::ScopeLookupResult>,
|
||||
MergeRedeclEntityInfo<SemIR::Function>, bool)
|
||||
-> bool;
|
||||
template auto TryMergeRedecl(Context&, const DeclNameStack::NameContext&,
|
||||
std::optional<SemIR::ScopeLookupResult>,
|
||||
MergeRedeclEntityInfo<SemIR::Interface>, bool)
|
||||
-> bool;
|
||||
template auto TryMergeRedecl(Context&, const DeclNameStack::NameContext&,
|
||||
std::optional<SemIR::ScopeLookupResult>,
|
||||
MergeRedeclEntityInfo<SemIR::NamedConstraint>,
|
||||
bool) -> bool;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
@@ -5,9 +5,26 @@
|
||||
#ifndef CARBON_TOOLCHAIN_CHECK_MERGE_H_
|
||||
#define CARBON_TOOLCHAIN_CHECK_MERGE_H_
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/check.h"
|
||||
#include "common/concepts.h"
|
||||
#include "toolchain/base/kind_switch.h"
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/decl_name_stack.h"
|
||||
#include "toolchain/check/function.h"
|
||||
#include "toolchain/check/import_ref.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/check/subst.h"
|
||||
#include "toolchain/lex/token_kind.h"
|
||||
#include "toolchain/sem_ir/class.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/import_ir.h"
|
||||
#include "toolchain/sem_ir/interface.h"
|
||||
#include "toolchain/sem_ir/named_constraint.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
@@ -109,6 +126,92 @@ inline auto CheckRedeclParamsMatch(Context& context,
|
||||
/*check_syntax=*/true);
|
||||
}
|
||||
|
||||
// Provides type traits and data for merging redeclarations.
|
||||
template <typename EntityT>
|
||||
struct MergeRedeclEntityInfo;
|
||||
|
||||
// Information for merging redeclarations of classes.
|
||||
template <>
|
||||
struct MergeRedeclEntityInfo<SemIR::Class> {
|
||||
using EntityIdT = SemIR::ClassId;
|
||||
using EntityT = SemIR::Class;
|
||||
using EntityDeclT = SemIR::ClassDecl;
|
||||
|
||||
static constexpr auto DeclTokenKind = Lex::TokenKind::Class;
|
||||
|
||||
EntityDeclT& new_entity_decl;
|
||||
const EntityT& new_entity;
|
||||
};
|
||||
|
||||
// Information for merging redeclarations of functions.
|
||||
template <>
|
||||
struct MergeRedeclEntityInfo<SemIR::Function> {
|
||||
using EntityIdT = SemIR::FunctionId;
|
||||
using EntityT = SemIR::Function;
|
||||
using EntityDeclT = SemIR::FunctionDecl;
|
||||
|
||||
static constexpr auto DeclTokenKind = Lex::TokenKind::Fn;
|
||||
|
||||
EntityDeclT& new_entity_decl;
|
||||
const EntityT& new_entity;
|
||||
};
|
||||
|
||||
// Information for merging redeclarations of interfaces.
|
||||
template <>
|
||||
struct MergeRedeclEntityInfo<SemIR::Interface> {
|
||||
using EntityIdT = SemIR::InterfaceId;
|
||||
using EntityT = SemIR::Interface;
|
||||
using EntityDeclT = SemIR::InterfaceDecl;
|
||||
|
||||
static constexpr auto DeclTokenKind = Lex::TokenKind::Interface;
|
||||
|
||||
EntityDeclT& new_entity_decl;
|
||||
const EntityT& new_entity;
|
||||
};
|
||||
|
||||
// Information for merging redeclarations of named constraints.
|
||||
template <>
|
||||
struct MergeRedeclEntityInfo<SemIR::NamedConstraint> {
|
||||
using EntityIdT = SemIR::NamedConstraintId;
|
||||
using EntityT = SemIR::NamedConstraint;
|
||||
using EntityDeclT = SemIR::NamedConstraintDecl;
|
||||
|
||||
static constexpr auto DeclTokenKind = Lex::TokenKind::Constraint;
|
||||
|
||||
EntityDeclT& new_entity_decl;
|
||||
const EntityT& new_entity;
|
||||
};
|
||||
|
||||
// Tries to merge new_entity into prev_entity_id. Since new_entity won't have a
|
||||
// definition even if one is upcoming, set is_definition to indicate the planned
|
||||
// result.
|
||||
//
|
||||
// If merging is successful, returns the previous declaration.
|
||||
// Otherwise, returns nullopt. Prints a diagnostic when appropriate.
|
||||
template <typename EntityT>
|
||||
auto TryMergeRedecl(Context& context,
|
||||
const DeclNameStack::NameContext& name_context,
|
||||
std::optional<SemIR::ScopeLookupResult> lookup_result,
|
||||
MergeRedeclEntityInfo<EntityT> entity_info,
|
||||
bool is_definition) -> bool;
|
||||
|
||||
extern template auto TryMergeRedecl(Context&, const DeclNameStack::NameContext&,
|
||||
std::optional<SemIR::ScopeLookupResult>,
|
||||
MergeRedeclEntityInfo<SemIR::Class>, bool)
|
||||
-> bool;
|
||||
extern template auto TryMergeRedecl(Context&, const DeclNameStack::NameContext&,
|
||||
std::optional<SemIR::ScopeLookupResult>,
|
||||
MergeRedeclEntityInfo<SemIR::Function>,
|
||||
bool) -> bool;
|
||||
extern template auto TryMergeRedecl(Context&, const DeclNameStack::NameContext&,
|
||||
std::optional<SemIR::ScopeLookupResult>,
|
||||
MergeRedeclEntityInfo<SemIR::Interface>,
|
||||
bool) -> bool;
|
||||
extern template auto TryMergeRedecl(
|
||||
Context&, const DeclNameStack::NameContext&,
|
||||
std::optional<SemIR::ScopeLookupResult>,
|
||||
MergeRedeclEntityInfo<SemIR::NamedConstraint>, bool) -> bool;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_CHECK_MERGE_H_
|
||||
|
||||
@@ -479,7 +479,7 @@ private class Redecl {}
|
||||
// CHECK:STDOUT: %Forward.decl: type = class_decl @Forward [concrete = constants.%Forward] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Forward {
|
||||
// CHECK:STDOUT: class @Forward [from "forward.carbon"] {
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type]
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
// CHECK:STDOUT:
|
||||
|
||||
+4
-4
@@ -576,7 +576,7 @@ extern class C;
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C;
|
||||
// CHECK:STDOUT: class @C [from "extern_decl.carbon"];
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_decl_after_import_extern_decl.carbon
|
||||
// CHECK:STDOUT:
|
||||
@@ -592,7 +592,7 @@ extern class C;
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C;
|
||||
// CHECK:STDOUT: class @C [from "decl.carbon"];
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_def_after_import_extern_decl.carbon
|
||||
// CHECK:STDOUT:
|
||||
@@ -615,7 +615,7 @@ extern class C;
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C {
|
||||
// CHECK:STDOUT: class @C [from "def.carbon"] {
|
||||
// CHECK:STDOUT: complete_type_witness = imports.%Main.import_ref.8f2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
@@ -643,7 +643,7 @@ extern class C;
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C {
|
||||
// CHECK:STDOUT: class @C [from "def.carbon"] {
|
||||
// CHECK:STDOUT: complete_type_witness = imports.%Main.import_ref.8f2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
|
||||
+1
-1
@@ -385,7 +385,7 @@ class Class(U: type) {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic class @Class(imports.%Main.import_ref.b3bc94.1: type) {
|
||||
// CHECK:STDOUT: generic class @Class(imports.%Main.import_ref.b3bc94.1: type) [from "foo.carbon"] {
|
||||
// CHECK:STDOUT: %T.patt.1: %pattern_type.98f = symbolic_binding_pattern T, 0 [symbolic = %T.patt.1 (constants.%T.patt)]
|
||||
// CHECK:STDOUT: %T.1: type = symbolic_binding T, 0 [symbolic = %T.1 (constants.%T)]
|
||||
// CHECK:STDOUT:
|
||||
|
||||
+2
-2
@@ -117,7 +117,7 @@ class B {}
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C {
|
||||
// CHECK:STDOUT: class @C [from "basic.carbon"] {
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type]
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
// CHECK:STDOUT:
|
||||
@@ -170,7 +170,7 @@ class B {}
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C {
|
||||
// CHECK:STDOUT: class @C [from "redecl_after_def.carbon"] {
|
||||
// CHECK:STDOUT: complete_type_witness = imports.%Main.import_ref.8f2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
|
||||
@@ -75,7 +75,7 @@ class ForwardDecl {
|
||||
// CHECK:STDOUT: %ForwardDecl.decl: type = class_decl @ForwardDecl [concrete = constants.%ForwardDecl] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @ForwardDecl {
|
||||
// CHECK:STDOUT: class @ForwardDecl [from "a.carbon"] {
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type]
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
// CHECK:STDOUT:
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
|
||||
// TODO: Add ranges and switch to "--dump-sem-ir-ranges=only".
|
||||
// EXTRA-ARGS: --dump-sem-ir-ranges=if-present
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
@@ -76,149 +74,3 @@ impl library "[[@TEST_NAME]]";
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
class D;
|
||||
|
||||
// CHECK:STDOUT: --- decl_in_api_definition_in_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %A: type = class_type @A [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .A = %A.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %A.decl: type = class_decl @A [concrete = constants.%A] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @A;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- todo_fail_decl_in_api_definition_in_impl.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %A: type = class_type @A [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .A = %A.decl.loc5
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_46.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_46.2 = import <none>
|
||||
// CHECK:STDOUT: %A.decl.loc5: type = class_decl @A [concrete = constants.%A] {} {}
|
||||
// CHECK:STDOUT: %A.decl.loc7: type = class_decl @A [concrete = constants.%A] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @A {
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type]
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%A
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- use_decl_in_api.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- use_decl_in_api.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Main.A = import_ref Main//decl_in_api_definition_in_impl, A, unloaded
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .A = imports.%Main.A
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_31.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_31.2 = import <none>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_only_in_api.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %B: type = class_type @B [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .B = %B.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %B.decl: type = class_decl @B [concrete = constants.%B] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @B;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_only_in_api.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Main.B = import_ref Main//decl_only_in_api, B, unloaded
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .B = imports.%Main.B
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_32.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_32.2 = import <none>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_in_api_decl_in_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_decl_in_api_decl_in_impl.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_40.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_40.2 = import <none>
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_only_in_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_decl_only_in_impl.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %D: type = class_type @D [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .D = %D.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_33.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_33.2 = import <none>
|
||||
// CHECK:STDOUT: %D.decl: type = class_decl @D [concrete = constants.%D] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @D;
|
||||
// CHECK:STDOUT:
|
||||
|
||||
+3
-3
@@ -687,7 +687,7 @@ fn Base.F(ref self: Base) {
|
||||
// CHECK:STDOUT: .Self = imports.%Main.import_ref.e47
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic class @Foo(imports.%Main.import_ref.99696d.1: %C) {
|
||||
// CHECK:STDOUT: generic class @Foo(imports.%Main.import_ref.99696d.1: %C) [from "two_file.carbon"] {
|
||||
// CHECK:STDOUT: %a.patt.1: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.1 (constants.%a.patt)]
|
||||
// CHECK:STDOUT: %a.1: %C = symbolic_binding a, 0 [symbolic = %a.1 (constants.%a)]
|
||||
// CHECK:STDOUT:
|
||||
@@ -702,7 +702,7 @@ fn Base.F(ref self: Base) {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic class @Bar(imports.%Main.import_ref.99696d.2: %C) {
|
||||
// CHECK:STDOUT: generic class @Bar(imports.%Main.import_ref.99696d.2: %C) [from "two_file.carbon"] {
|
||||
// CHECK:STDOUT: %a.patt.1: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.1 (constants.%a.patt)]
|
||||
// CHECK:STDOUT: %a.1: %C = symbolic_binding a, 0 [symbolic = %a.1 (constants.%a)]
|
||||
// CHECK:STDOUT:
|
||||
@@ -1093,7 +1093,7 @@ fn Base.F(ref self: Base) {
|
||||
// CHECK:STDOUT: .Self = imports.%Main.import_ref.e47
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic class @Foo(imports.%Main.import_ref.996: %C) {
|
||||
// CHECK:STDOUT: generic class @Foo(imports.%Main.import_ref.996: %C) [from "alias_two_file.carbon"] {
|
||||
// CHECK:STDOUT: %a.patt.1: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.1 (constants.%a.patt)]
|
||||
// CHECK:STDOUT: %a.1: %C = symbolic_binding a, 0 [symbolic = %a.1 (constants.%a)]
|
||||
// CHECK:STDOUT:
|
||||
|
||||
-149
@@ -3,8 +3,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
|
||||
// TODO: Add ranges and switch to "--dump-sem-ir-ranges=only".
|
||||
// EXTRA-ARGS: --dump-sem-ir-ranges=if-present
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
@@ -76,150 +74,3 @@ impl library "[[@TEST_NAME]]";
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
fn D();
|
||||
|
||||
// CHECK:STDOUT: --- decl_in_api_definition_in_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %A.type: type = fn_type @A [concrete]
|
||||
// CHECK:STDOUT: %A: %A.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .A = %A.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %A.decl: %A.type = fn_decl @A [concrete = constants.%A] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @A();
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- todo_fail_decl_in_api_definition_in_impl.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %A.type: type = fn_type @A [concrete]
|
||||
// CHECK:STDOUT: %A: %A.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .A = %A.decl.loc5
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_46.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_46.2 = import <none>
|
||||
// CHECK:STDOUT: %A.decl.loc5: %A.type = fn_decl @A [concrete = constants.%A] {} {}
|
||||
// CHECK:STDOUT: %A.decl.loc7: %A.type = fn_decl @A [concrete = constants.%A] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @A() [from "decl_in_api_definition_in_impl.carbon"] {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- use_decl_in_api.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- use_decl_in_api.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Main.A = import_ref Main//decl_in_api_definition_in_impl, A, unloaded
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .A = imports.%Main.A
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_31.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_31.2 = import <none>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_only_in_api.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %B.type: type = fn_type @B [concrete]
|
||||
// CHECK:STDOUT: %B: %B.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .B = %B.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %B.decl: %B.type = fn_decl @B [concrete = constants.%B] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @B();
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_only_in_api.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Main.B = import_ref Main//decl_only_in_api, B, unloaded
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .B = imports.%Main.B
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_32.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_32.2 = import <none>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_in_api_decl_in_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C.type: type = fn_type @C [concrete]
|
||||
// CHECK:STDOUT: %C: %C.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: %C.type = fn_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @C();
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_decl_in_api_decl_in_impl.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C.type: type = fn_type @C [concrete]
|
||||
// CHECK:STDOUT: %C: %C.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_40.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_40.2 = import <none>
|
||||
// CHECK:STDOUT: %C.decl: %C.type = fn_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @C [from "decl_in_api_decl_in_impl.carbon"];
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_only_in_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_decl_only_in_impl.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %D.type: type = fn_type @D [concrete]
|
||||
// CHECK:STDOUT: %D: %D.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .D = %D.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_33.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_33.2 = import <none>
|
||||
// CHECK:STDOUT: %D.decl: %D.type = fn_decl @D [concrete = constants.%D] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @D();
|
||||
// CHECK:STDOUT:
|
||||
|
||||
@@ -52,8 +52,8 @@ interface I {}
|
||||
// CHECK:STDOUT: --- fail_b.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %I.type.8e70aa.2: type = facet_type <@I.loc14_13.2> [concrete]
|
||||
// CHECK:STDOUT: %Self: %I.type.8e70aa.2 = symbolic_binding Self, 0 [symbolic]
|
||||
// CHECK:STDOUT: %I.type: type = facet_type <@I> [concrete]
|
||||
// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
@@ -61,14 +61,12 @@ interface I {}
|
||||
// CHECK:STDOUT: .I = %I.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import = import <none>
|
||||
// CHECK:STDOUT: %I.decl: type = interface_decl @I.loc14_13.2 [concrete = constants.%I.type.8e70aa.2] {} {}
|
||||
// CHECK:STDOUT: %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @I.loc14_13.1;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @I.loc14_13.2 {
|
||||
// CHECK:STDOUT: %Self: %I.type.8e70aa.2 = symbolic_binding Self, 0 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %I.WithSelf.decl = interface_with_self_decl @I.loc14_13.2 [concrete]
|
||||
// CHECK:STDOUT: interface @I [from "a.carbon"] {
|
||||
// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %I.WithSelf.decl = interface_with_self_decl @I [concrete]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = %Self
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
|
||||
// TODO: Add ranges and switch to "--dump-sem-ir-ranges=only".
|
||||
// EXTRA-ARGS: --dump-sem-ir-ranges=if-present
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
@@ -76,157 +74,3 @@ impl library "[[@TEST_NAME]]";
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
interface D;
|
||||
|
||||
// CHECK:STDOUT: --- decl_in_api_definition_in_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %A.type: type = facet_type <@A> [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .A = %A.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %A.decl: type = interface_decl @A [concrete = constants.%A.type] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @A;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- todo_fail_decl_in_api_definition_in_impl.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %A.type.3138d6.2: type = facet_type <@A.loc7> [concrete]
|
||||
// CHECK:STDOUT: %Self: %A.type.3138d6.2 = symbolic_binding Self, 0 [symbolic]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .A = %A.decl.loc5
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_46.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_46.2 = import <none>
|
||||
// CHECK:STDOUT: %A.decl.loc5: type = interface_decl @A.loc7 [concrete = constants.%A.type.3138d6.2] {} {}
|
||||
// CHECK:STDOUT: %A.decl.loc7: type = interface_decl @A.loc7 [concrete = constants.%A.type.3138d6.2] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @A.loc5;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @A.loc7 {
|
||||
// CHECK:STDOUT: %Self: %A.type.3138d6.2 = symbolic_binding Self, 0 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %A.WithSelf.decl = interface_with_self_decl @A.loc7 [concrete]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = %Self
|
||||
// CHECK:STDOUT: witness = ()
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !requires:
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @A.WithSelf(constants.%Self) {}
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- use_decl_in_api.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- use_decl_in_api.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Main.A = import_ref Main//decl_in_api_definition_in_impl, A, unloaded
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .A = imports.%Main.A
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_31.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_31.2 = import <none>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_only_in_api.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %B.type: type = facet_type <@B> [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .B = %B.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %B.decl: type = interface_decl @B [concrete = constants.%B.type] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @B;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_only_in_api.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Main.B = import_ref Main//decl_only_in_api, B, unloaded
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .B = imports.%Main.B
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_32.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_32.2 = import <none>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_in_api_decl_in_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C.type: type = facet_type <@C> [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: type = interface_decl @C [concrete = constants.%C.type] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @C;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_decl_in_api_decl_in_impl.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C.type.709119.2: type = facet_type <@C.loc8_12.2> [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_40.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_40.2 = import <none>
|
||||
// CHECK:STDOUT: %C.decl: type = interface_decl @C.loc8_12.2 [concrete = constants.%C.type.709119.2] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @C.loc8_12.1;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @C.loc8_12.2;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- decl_only_in_impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_decl_only_in_impl.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %D.type: type = facet_type <@D> [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .D = %D.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import.loc2_33.1 = import <none>
|
||||
// CHECK:STDOUT: %default.import.loc2_33.2 = import <none>
|
||||
// CHECK:STDOUT: %D.decl: type = interface_decl @D [concrete = constants.%D.type] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @D;
|
||||
// CHECK:STDOUT:
|
||||
|
||||
Reference in New Issue
Block a user