mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:10:12 +01:00
Support out-of-line definitions of members of generic classes and interfaces. (#4029)
Check the parameters specified in a name qualifier against the parameters of the entity that the qualifier refers to. For interfaces, this required adding minimal support for parameterized interface names. --------- Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
co-authored by
Jon Ross-Perkins
parent
268dd04511
commit
7792e5fce3
+173
-152
@@ -7,6 +7,8 @@
|
||||
#include "toolchain/base/kind_switch.h"
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/diagnostic_helpers.h"
|
||||
#include "toolchain/check/merge.h"
|
||||
#include "toolchain/check/name_component.h"
|
||||
#include "toolchain/diagnostics/diagnostic.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
|
||||
@@ -24,7 +26,6 @@ auto DeclNameStack::NameContext::prev_inst_id() -> SemIR::InstId {
|
||||
"that may change based on error handling).";
|
||||
|
||||
case NameContext::State::Resolved:
|
||||
case NameContext::State::ResolvedNonScope:
|
||||
return resolved_inst_id;
|
||||
|
||||
case NameContext::State::Unresolved:
|
||||
@@ -44,7 +45,7 @@ auto DeclNameStack::MakeEmptyNameContext() -> NameContext {
|
||||
auto DeclNameStack::MakeUnqualifiedName(SemIR::LocId loc_id,
|
||||
SemIR::NameId name_id) -> NameContext {
|
||||
NameContext context = MakeEmptyNameContext();
|
||||
ApplyAndLookupName(context, loc_id, name_id, /*is_unqualified=*/true);
|
||||
ApplyAndLookupName(context, loc_id, name_id);
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -59,8 +60,7 @@ auto DeclNameStack::FinishName(const NameComponent& name) -> NameContext {
|
||||
CARBON_CHECK(decl_name_stack_.back().state != NameContext::State::Finished)
|
||||
<< "Finished name twice";
|
||||
|
||||
ApplyAndLookupName(decl_name_stack_.back(), name.name_loc_id, name.name_id,
|
||||
/*is_unqualified=*/false);
|
||||
ApplyAndLookupName(decl_name_stack_.back(), name.name_loc_id, name.name_id);
|
||||
|
||||
NameContext result = decl_name_stack_.back();
|
||||
decl_name_stack_.back().state = NameContext::State::Finished;
|
||||
@@ -179,24 +179,43 @@ auto DeclNameStack::LookupOrAddName(NameContext name_context,
|
||||
return SemIR::InstId::Invalid;
|
||||
}
|
||||
|
||||
auto DeclNameStack::ApplyNameQualifier(const NameComponent& name) -> void {
|
||||
if (name.implicit_params_id.is_valid() || name.params_id.is_valid()) {
|
||||
context_->TODO(name.params_loc_id, "name qualifier with parameters");
|
||||
}
|
||||
// Push a scope corresponding to a name qualifier. For example, for
|
||||
// `fn Class(T:! type).F(n: i32)` we will push the scope for `Class(T:! type)`
|
||||
// between the scope containing the declaration of `T` and the scope
|
||||
// containing the declaration of `n`.
|
||||
static auto PushNameQualifierScope(Context& context,
|
||||
SemIR::InstId scope_inst_id,
|
||||
SemIR::NameScopeId scope_id,
|
||||
bool has_error = false) -> void {
|
||||
// If the qualifier has no parameters, we don't need to keep around a
|
||||
// parameter scope.
|
||||
context.scope_stack().PopIfEmpty();
|
||||
|
||||
context.scope_stack().Push(scope_inst_id, scope_id, has_error);
|
||||
|
||||
// Enter a parameter scope in case the qualified name itself has parameters.
|
||||
context.scope_stack().Push();
|
||||
}
|
||||
|
||||
auto DeclNameStack::ApplyNameQualifier(const NameComponent& name) -> void {
|
||||
auto& name_context = decl_name_stack_.back();
|
||||
ApplyAndLookupName(name_context, name.name_loc_id, name.name_id,
|
||||
/*is_unqualified=*/false);
|
||||
ApplyAndLookupName(name_context, name.name_loc_id, name.name_id);
|
||||
name_context.has_qualifiers = true;
|
||||
if (!CheckValidAsQualifier(name_context)) {
|
||||
|
||||
// Resolve the qualifier as a scope and enter the new scope.
|
||||
auto scope_id = ResolveAsScope(name_context, name);
|
||||
if (scope_id.is_valid()) {
|
||||
PushNameQualifierScope(*context_, name_context.resolved_inst_id, scope_id,
|
||||
context_->name_scopes().Get(scope_id).has_error);
|
||||
name_context.parent_scope_id = scope_id;
|
||||
} else {
|
||||
name_context.state = NameContext::State::Error;
|
||||
}
|
||||
}
|
||||
|
||||
auto DeclNameStack::ApplyAndLookupName(NameContext& name_context,
|
||||
SemIR::LocId loc_id,
|
||||
SemIR::NameId name_id,
|
||||
bool is_unqualified) -> void {
|
||||
SemIR::NameId name_id) -> void {
|
||||
// The location of the name is the location of the last name token we've
|
||||
// processed so far.
|
||||
name_context.loc_id = loc_id;
|
||||
@@ -215,165 +234,167 @@ auto DeclNameStack::ApplyAndLookupName(NameContext& name_context,
|
||||
// Invalid indicates an unresolved name. Store it and return.
|
||||
name_context.unresolved_name_id = name_id;
|
||||
name_context.state = NameContext::State::Unresolved;
|
||||
return;
|
||||
} else {
|
||||
// Store the resolved instruction and continue for the target scope
|
||||
// update.
|
||||
name_context.resolved_inst_id = resolved_inst_id;
|
||||
name_context.state = NameContext::State::Resolved;
|
||||
}
|
||||
}
|
||||
|
||||
// Checks and returns whether name_context, which is used as a name qualifier,
|
||||
// was successfully resolved. Issues a suitable diagnostic if not.
|
||||
static auto CheckQualifierIsResolved(
|
||||
Context& context, const DeclNameStack::NameContext& name_context) -> bool {
|
||||
switch (name_context.state) {
|
||||
case DeclNameStack::NameContext::State::Empty:
|
||||
CARBON_FATAL() << "No qualifier to resolve";
|
||||
|
||||
case DeclNameStack::NameContext::State::Resolved:
|
||||
return true;
|
||||
|
||||
case DeclNameStack::NameContext::State::Unresolved:
|
||||
// Because more qualifiers were found, we diagnose that the earlier
|
||||
// qualifier failed to resolve.
|
||||
context.DiagnoseNameNotFound(name_context.loc_id,
|
||||
name_context.unresolved_name_id);
|
||||
return false;
|
||||
|
||||
case DeclNameStack::NameContext::State::Finished:
|
||||
CARBON_FATAL() << "Added a qualifier after calling FinishName";
|
||||
|
||||
case DeclNameStack::NameContext::State::Error:
|
||||
// Already in an error state, so return without examining.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Diagnose that a qualified declaration name specifies an incomplete class as
|
||||
// its scope.
|
||||
static auto DiagnoseQualifiedDeclInIncompleteClassScope(Context& context,
|
||||
SemIRLoc loc,
|
||||
SemIR::ClassId class_id)
|
||||
-> void {
|
||||
CARBON_DIAGNOSTIC(QualifiedDeclInIncompleteClassScope, Error,
|
||||
"Cannot declare a member of incomplete class `{0}`.",
|
||||
SemIR::TypeId);
|
||||
auto builder =
|
||||
context.emitter().Build(loc, QualifiedDeclInIncompleteClassScope,
|
||||
context.classes().Get(class_id).self_type_id);
|
||||
context.NoteIncompleteClass(class_id, builder);
|
||||
builder.Emit();
|
||||
}
|
||||
|
||||
// Diagnose that a qualified declaration name specifies an undefined interface
|
||||
// as its scope.
|
||||
static auto DiagnoseQualifiedDeclInUndefinedInterfaceScope(
|
||||
Context& context, SemIRLoc loc, SemIR::InterfaceId interface_id,
|
||||
SemIR::InstId interface_inst_id) -> void {
|
||||
CARBON_DIAGNOSTIC(QualifiedDeclInUndefinedInterfaceScope, Error,
|
||||
"Cannot declare a member of undefined interface `{0}`.",
|
||||
std::string);
|
||||
auto builder = context.emitter().Build(
|
||||
loc, QualifiedDeclInUndefinedInterfaceScope,
|
||||
context.sem_ir().StringifyTypeExpr(
|
||||
context.sem_ir().constant_values().Get(interface_inst_id).inst_id()));
|
||||
context.NoteUndefinedInterface(interface_id, builder);
|
||||
builder.Emit();
|
||||
}
|
||||
|
||||
// Diagnose that a qualified declaration name specifies a different package as
|
||||
// its scope.
|
||||
static auto DiagnoseQualifiedDeclInImportedPackage(Context& context,
|
||||
SemIRLoc use_loc,
|
||||
SemIRLoc import_loc)
|
||||
-> void {
|
||||
CARBON_DIAGNOSTIC(QualifiedDeclOutsidePackage, Error,
|
||||
"Imported packages cannot be used for declarations.");
|
||||
CARBON_DIAGNOSTIC(QualifiedDeclOutsidePackageSource, Note,
|
||||
"Package imported here.");
|
||||
context.emitter()
|
||||
.Build(use_loc, QualifiedDeclOutsidePackage)
|
||||
.Note(import_loc, QualifiedDeclOutsidePackageSource)
|
||||
.Emit();
|
||||
}
|
||||
|
||||
// Diagnose that a qualified declaration name specifies a non-scope entity as
|
||||
// its scope.
|
||||
static auto DiagnoseQualifiedDeclInNonScope(Context& context, SemIRLoc use_loc,
|
||||
SemIRLoc non_scope_entity_loc)
|
||||
-> void {
|
||||
CARBON_DIAGNOSTIC(QualifiedNameInNonScope, Error,
|
||||
"Name qualifiers are only allowed for entities that "
|
||||
"provide a scope.");
|
||||
CARBON_DIAGNOSTIC(QualifiedNameNonScopeEntity, Note,
|
||||
"Referenced non-scope entity declared here.");
|
||||
context.emitter()
|
||||
.Build(use_loc, QualifiedNameInNonScope)
|
||||
.Note(non_scope_entity_loc, QualifiedNameNonScopeEntity)
|
||||
.Emit();
|
||||
}
|
||||
|
||||
auto DeclNameStack::ResolveAsScope(const NameContext& name_context,
|
||||
const NameComponent& name) const
|
||||
-> SemIR::NameScopeId {
|
||||
if (!CheckQualifierIsResolved(*context_, name_context)) {
|
||||
return SemIR::NameScopeId::Invalid;
|
||||
}
|
||||
|
||||
// Enter the scope of the existing entity.
|
||||
UpdateScopeIfNeeded(name_context, is_unqualified);
|
||||
}
|
||||
auto new_params =
|
||||
DeclParams(name.name_loc_id, name.implicit_params_id, name.params_id);
|
||||
|
||||
// Push a scope corresponding to a name qualifier. For example, for
|
||||
//
|
||||
// fn Class(T:! type).F(n: i32)
|
||||
//
|
||||
// we will push the scope for `Class(T:! type)` between the scope containing the
|
||||
// declaration of `T` and the scope containing the declaration of `n`.
|
||||
static auto PushNameQualifierScope(Context& context,
|
||||
SemIR::InstId scope_inst_id,
|
||||
SemIR::NameScopeId scope_id,
|
||||
bool has_error = false) -> void {
|
||||
// If the qualifier has no parameters, we don't need to keep around a
|
||||
// parameter scope.
|
||||
context.scope_stack().PopIfEmpty();
|
||||
|
||||
context.scope_stack().Push(scope_inst_id, scope_id, has_error);
|
||||
|
||||
// Enter a parameter scope in case the qualified name itself has parameters.
|
||||
context.scope_stack().Push();
|
||||
}
|
||||
|
||||
auto DeclNameStack::UpdateScopeIfNeeded(NameContext& name_context,
|
||||
bool is_unqualified) -> void {
|
||||
// This will only be reached for resolved instructions. We update the target
|
||||
// scope based on the resolved type.
|
||||
// Find the scope corresponding to the resolved instruction.
|
||||
CARBON_KIND_SWITCH(context_->insts().Get(name_context.resolved_inst_id)) {
|
||||
case CARBON_KIND(SemIR::ClassDecl resolved_inst): {
|
||||
const auto& class_info = context_->classes().Get(resolved_inst.class_id);
|
||||
if (class_info.is_defined()) {
|
||||
name_context.state = NameContext::State::Resolved;
|
||||
name_context.parent_scope_id = class_info.scope_id;
|
||||
if (!is_unqualified) {
|
||||
PushNameQualifierScope(*context_, name_context.resolved_inst_id,
|
||||
class_info.scope_id);
|
||||
}
|
||||
} else {
|
||||
name_context.state = NameContext::State::ResolvedNonScope;
|
||||
case CARBON_KIND(SemIR::ClassDecl class_decl): {
|
||||
const auto& class_info = context_->classes().Get(class_decl.class_id);
|
||||
if (!CheckRedeclParamsMatch(*context_, new_params,
|
||||
DeclParams(class_info))) {
|
||||
return SemIR::NameScopeId::Invalid;
|
||||
}
|
||||
break;
|
||||
if (!class_info.is_defined()) {
|
||||
DiagnoseQualifiedDeclInIncompleteClassScope(
|
||||
*context_, name_context.loc_id, class_decl.class_id);
|
||||
return SemIR::NameScopeId::Invalid;
|
||||
}
|
||||
return class_info.scope_id;
|
||||
}
|
||||
case CARBON_KIND(SemIR::InterfaceDecl resolved_inst): {
|
||||
case CARBON_KIND(SemIR::InterfaceDecl interface_decl): {
|
||||
const auto& interface_info =
|
||||
context_->interfaces().Get(resolved_inst.interface_id);
|
||||
if (interface_info.is_defined()) {
|
||||
name_context.state = NameContext::State::Resolved;
|
||||
name_context.parent_scope_id = interface_info.scope_id;
|
||||
if (!is_unqualified) {
|
||||
PushNameQualifierScope(*context_, name_context.resolved_inst_id,
|
||||
interface_info.scope_id);
|
||||
}
|
||||
} else {
|
||||
name_context.state = NameContext::State::ResolvedNonScope;
|
||||
context_->interfaces().Get(interface_decl.interface_id);
|
||||
if (!CheckRedeclParamsMatch(*context_, new_params,
|
||||
DeclParams(interface_info))) {
|
||||
return SemIR::NameScopeId::Invalid;
|
||||
}
|
||||
break;
|
||||
if (!interface_info.is_defined()) {
|
||||
DiagnoseQualifiedDeclInUndefinedInterfaceScope(
|
||||
*context_, name_context.loc_id, interface_decl.interface_id,
|
||||
name_context.resolved_inst_id);
|
||||
return SemIR::NameScopeId::Invalid;
|
||||
}
|
||||
return interface_info.scope_id;
|
||||
}
|
||||
case CARBON_KIND(SemIR::Namespace resolved_inst): {
|
||||
auto scope_id = resolved_inst.name_scope_id;
|
||||
name_context.state = NameContext::State::Resolved;
|
||||
name_context.parent_scope_id = scope_id;
|
||||
auto& scope = context_->name_scopes().Get(scope_id);
|
||||
if (!CheckRedeclParamsMatch(*context_, new_params,
|
||||
DeclParams(name_context.resolved_inst_id,
|
||||
SemIR::InstBlockId::Invalid,
|
||||
SemIR::InstBlockId::Invalid))) {
|
||||
return SemIR::NameScopeId::Invalid;
|
||||
}
|
||||
if (scope.is_closed_import) {
|
||||
CARBON_DIAGNOSTIC(QualifiedDeclOutsidePackage, Error,
|
||||
"Imported packages cannot be used for declarations.");
|
||||
CARBON_DIAGNOSTIC(QualifiedDeclOutsidePackageSource, Note,
|
||||
"Package imported here.");
|
||||
context_->emitter()
|
||||
.Build(name_context.loc_id, QualifiedDeclOutsidePackage)
|
||||
.Note(scope.inst_id, QualifiedDeclOutsidePackageSource)
|
||||
.Emit();
|
||||
// Only error once per package.
|
||||
DiagnoseQualifiedDeclInImportedPackage(*context_, name_context.loc_id,
|
||||
scope.inst_id);
|
||||
// Only error once per package. Recover by allowing this package name to
|
||||
// be used as a name qualifier.
|
||||
scope.is_closed_import = false;
|
||||
}
|
||||
if (!is_unqualified) {
|
||||
PushNameQualifierScope(*context_, name_context.resolved_inst_id,
|
||||
scope_id,
|
||||
context_->name_scopes().Get(scope_id).has_error);
|
||||
}
|
||||
break;
|
||||
return scope_id;
|
||||
}
|
||||
default:
|
||||
name_context.state = NameContext::State::ResolvedNonScope;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto DeclNameStack::CheckValidAsQualifier(const NameContext& name_context)
|
||||
-> bool {
|
||||
switch (name_context.state) {
|
||||
case NameContext::State::Error:
|
||||
// Already in an error state, so return without examining.
|
||||
return false;
|
||||
|
||||
case NameContext::State::Resolved:
|
||||
return true;
|
||||
|
||||
case NameContext::State::Empty:
|
||||
CARBON_FATAL() << "No qualifier to resolve";
|
||||
|
||||
case NameContext::State::Finished:
|
||||
CARBON_FATAL() << "Added a qualifier after calling FinishName";
|
||||
|
||||
case NameContext::State::Unresolved:
|
||||
// Because more qualifiers were found, we diagnose that the earlier
|
||||
// qualifier failed to resolve.
|
||||
context_->DiagnoseNameNotFound(name_context.loc_id,
|
||||
name_context.unresolved_name_id);
|
||||
return false;
|
||||
|
||||
case NameContext::State::ResolvedNonScope: {
|
||||
// Because more qualifiers were found, we diagnose that the earlier
|
||||
// qualifier didn't resolve to a scoped entity.
|
||||
if (auto class_decl = context_->insts().TryGetAs<SemIR::ClassDecl>(
|
||||
name_context.resolved_inst_id)) {
|
||||
CARBON_DIAGNOSTIC(QualifiedDeclInIncompleteClassScope, Error,
|
||||
"Cannot declare a member of incomplete class `{0}`.",
|
||||
SemIR::TypeId);
|
||||
auto builder = context_->emitter().Build(
|
||||
name_context.loc_id, QualifiedDeclInIncompleteClassScope,
|
||||
context_->classes().Get(class_decl->class_id).self_type_id);
|
||||
context_->NoteIncompleteClass(class_decl->class_id, builder);
|
||||
builder.Emit();
|
||||
} else if (auto interface_decl =
|
||||
context_->insts().TryGetAs<SemIR::InterfaceDecl>(
|
||||
name_context.resolved_inst_id)) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
QualifiedDeclInUndefinedInterfaceScope, Error,
|
||||
"Cannot declare a member of undefined interface `{0}`.",
|
||||
std::string);
|
||||
auto builder = context_->emitter().Build(
|
||||
name_context.loc_id, QualifiedDeclInUndefinedInterfaceScope,
|
||||
context_->sem_ir().StringifyTypeExpr(
|
||||
context_->sem_ir()
|
||||
.constant_values()
|
||||
.Get(name_context.resolved_inst_id)
|
||||
.inst_id()));
|
||||
context_->NoteUndefinedInterface(interface_decl->interface_id, builder);
|
||||
builder.Emit();
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(QualifiedNameInNonScope, Error,
|
||||
"Name qualifiers are only allowed for entities that "
|
||||
"provide a scope.");
|
||||
CARBON_DIAGNOSTIC(QualifiedNameNonScopeEntity, Note,
|
||||
"Referenced non-scope entity declared here.");
|
||||
context_->emitter()
|
||||
.Build(name_context.loc_id, QualifiedNameInNonScope)
|
||||
.Note(name_context.resolved_inst_id, QualifiedNameNonScopeEntity)
|
||||
.Emit();
|
||||
}
|
||||
return false;
|
||||
default: {
|
||||
DiagnoseQualifiedDeclInNonScope(*context_, name_context.loc_id,
|
||||
name_context.resolved_inst_id);
|
||||
return SemIR::NameScopeId::Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,15 +70,9 @@ class DeclNameStack {
|
||||
// A context that has not processed any parts of the qualifier.
|
||||
Empty,
|
||||
|
||||
// An instruction ID has been resolved, whether through an identifier or
|
||||
// expression. This provided a new scope, such as a type.
|
||||
// The name has been resolved to an instruction ID.
|
||||
Resolved,
|
||||
|
||||
// An instruction ID has been resolved, whether through an identifier or
|
||||
// expression. It did not provide a new scope, so must be the final part,
|
||||
// such as an out-of-line function definition.
|
||||
ResolvedNonScope,
|
||||
|
||||
// An identifier didn't resolve.
|
||||
Unresolved,
|
||||
|
||||
@@ -231,18 +225,13 @@ class DeclNameStack {
|
||||
// Appends a name to the given name context, and performs a lookup to find
|
||||
// what, if anything, the name refers to.
|
||||
auto ApplyAndLookupName(NameContext& name_context, SemIR::LocId loc_id,
|
||||
SemIR::NameId name_id, bool is_unqualified) -> void;
|
||||
SemIR::NameId name_id) -> void;
|
||||
|
||||
// Checks and returns whether the given name context can be used as a
|
||||
// qualifier. A suitable diagnostic is issued if not.
|
||||
auto CheckValidAsQualifier(const NameContext& name_context) -> bool;
|
||||
|
||||
// Updates the scope on name_context as needed. This is called after
|
||||
// resolution is complete, whether for Name or expression. When updating for
|
||||
// an unqualified name, the resolution is noted without pushing scopes; it's
|
||||
// instead expected this will become a name conflict.
|
||||
auto UpdateScopeIfNeeded(NameContext& name_context, bool is_unqualified)
|
||||
-> void;
|
||||
// Attempts to resolve the given name context as a scope, and returns the
|
||||
// corresponding scope. Issues a suitable diagnostic and returns Invalid if
|
||||
// the name doesn't resolve to a scope.
|
||||
auto ResolveAsScope(const NameContext& name_context,
|
||||
const NameComponent& name) const -> SemIR::NameScopeId;
|
||||
|
||||
// The linked context.
|
||||
Context* context_;
|
||||
|
||||
@@ -58,7 +58,7 @@ static auto MergeClassRedecl(Context& context, SemIRLoc new_loc,
|
||||
|
||||
// Check the generic parameters match, if they were specified.
|
||||
if (!CheckRedeclParamsMatch(context, DeclParams(new_class),
|
||||
DeclParams(prev_class), {})) {
|
||||
DeclParams(prev_class))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/interface.h"
|
||||
#include "toolchain/check/merge.h"
|
||||
#include "toolchain/check/modifiers.h"
|
||||
#include "toolchain/check/name_component.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
@@ -28,10 +29,6 @@ static auto BuildInterfaceDecl(Context& context,
|
||||
Parse::AnyInterfaceDeclId node_id)
|
||||
-> std::tuple<SemIR::InterfaceId, SemIR::InstId> {
|
||||
auto name = PopNameComponent(context);
|
||||
if (name.params_id.is_valid() || name.implicit_params_id.is_valid()) {
|
||||
context.TODO(node_id, "generic interface");
|
||||
}
|
||||
|
||||
auto name_context = context.decl_name_stack().FinishName(name);
|
||||
context.node_stack()
|
||||
.PopAndDiscardSoloNodeId<Parse::NodeKind::InterfaceIntroducer>();
|
||||
@@ -63,11 +60,20 @@ static auto BuildInterfaceDecl(Context& context,
|
||||
if (existing_id.is_valid()) {
|
||||
if (auto existing_interface_decl =
|
||||
context.insts().Get(existing_id).TryAs<SemIR::InterfaceDecl>()) {
|
||||
// This is a redeclaration of an existing interface.
|
||||
interface_decl.interface_id = existing_interface_decl->interface_id;
|
||||
|
||||
// TODO: Check that the generic parameter list agrees with the prior
|
||||
// declaration.
|
||||
// TODO: Implement full redeclaration checking. See `MergeClassDecl`. For
|
||||
// now we just check the generic parameters match.
|
||||
if (CheckRedeclParamsMatch(
|
||||
context,
|
||||
DeclParams(interface_decl_id, name.implicit_params_id,
|
||||
name.params_id),
|
||||
DeclParams(context.interfaces().Get(
|
||||
existing_interface_decl->interface_id)))) {
|
||||
// This is a redeclaration of an existing interface.
|
||||
interface_decl.interface_id = existing_interface_decl->interface_id;
|
||||
// TODO: If the new declaration is a definition, keep its parameter
|
||||
// and implicit parameter lists rather than the ones from the
|
||||
// previous declaration.
|
||||
}
|
||||
} else {
|
||||
// This is a redeclaration of something other than a interface.
|
||||
context.DiagnoseDuplicateName(interface_decl_id, existing_id);
|
||||
@@ -83,9 +89,14 @@ static auto BuildInterfaceDecl(Context& context,
|
||||
interface_decl.interface_id = context.interfaces().Add(
|
||||
{.name_id = name_context.name_id_for_new_inst(),
|
||||
.parent_scope_id = name_context.parent_scope_id_for_new_inst(),
|
||||
.implicit_param_refs_id = name.implicit_params_id,
|
||||
.param_refs_id = name.params_id,
|
||||
.decl_id = interface_decl_id});
|
||||
}
|
||||
|
||||
// TODO: For a generic interface declaration, set the `type_id` to a suitable
|
||||
// generic interface type rather than `type`.
|
||||
|
||||
// Write the interface ID into the InterfaceDecl.
|
||||
context.ReplaceInstBeforeConstantUse(interface_decl_id, interface_decl);
|
||||
|
||||
|
||||
@@ -45,10 +45,18 @@ auto HandleNamespace(Context& context, Parse::NamespaceId node_id) -> bool {
|
||||
// previous declaration. Otherwise, diagnose the issue.
|
||||
if (auto existing =
|
||||
context.insts().TryGetAs<SemIR::Namespace>(existing_inst_id)) {
|
||||
// When the name conflict is an imported namespace, fill the location ID
|
||||
// so that future diagnostics point at this declaration.
|
||||
if (existing->import_id.is_valid() &&
|
||||
!context.insts().GetLocId(existing_inst_id).is_valid()) {
|
||||
if (context.name_scopes().Get(existing->name_scope_id).is_closed_import) {
|
||||
// The existing name is a package name, so this is a name conflict.
|
||||
context.DiagnoseDuplicateName(namespace_id, existing_inst_id);
|
||||
|
||||
// Treat this as a local namespace name from now on to avoid further
|
||||
// diagnostics.
|
||||
context.name_scopes().Get(existing->name_scope_id).is_closed_import =
|
||||
false;
|
||||
} else if (existing->import_id.is_valid() &&
|
||||
!context.insts().GetLocId(existing_inst_id).is_valid()) {
|
||||
// When the name conflict is an imported namespace, fill the location ID
|
||||
// so that future diagnostics point at this declaration.
|
||||
context.SetNamespaceNodeId(existing_inst_id, node_id);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -832,6 +832,9 @@ class ImportRefResolver {
|
||||
|
||||
auto TryResolveTypedInst(SemIR::ClassDecl inst,
|
||||
SemIR::ConstantId class_const_id) -> ResolveResult {
|
||||
// TODO: The handling of interfaces repeats a lot with the handling of
|
||||
// classes, and will likely also be repeated for named constraints and
|
||||
// choice types. Factor out some of this functionality.
|
||||
const auto& import_class = import_ir_.classes().Get(inst.class_id);
|
||||
|
||||
SemIR::ClassId class_id = SemIR::ClassId::Invalid;
|
||||
@@ -1070,8 +1073,19 @@ class ImportRefResolver {
|
||||
// Start with an incomplete interface.
|
||||
SemIR::Interface new_interface = {
|
||||
.name_id = GetLocalNameId(import_interface.name_id),
|
||||
// Set in the second pass once we've imported it.
|
||||
// These are set in the second pass once we've imported them. Import
|
||||
// enough of the parameter lists that we know whether this interface is
|
||||
// a generic interface and can build the right constant value for it.
|
||||
// TODO: Add a better way to represent a generic `Interface` prior to
|
||||
// importing the parameters.
|
||||
.parent_scope_id = SemIR::NameScopeId::Invalid,
|
||||
.implicit_param_refs_id =
|
||||
import_interface.implicit_param_refs_id.is_valid()
|
||||
? SemIR::InstBlockId::Empty
|
||||
: SemIR::InstBlockId::Invalid,
|
||||
.param_refs_id = import_interface.param_refs_id.is_valid()
|
||||
? SemIR::InstBlockId::Empty
|
||||
: SemIR::InstBlockId::Invalid,
|
||||
.decl_id = interface_decl_id,
|
||||
};
|
||||
|
||||
@@ -1122,6 +1136,10 @@ class ImportRefResolver {
|
||||
|
||||
auto parent_scope_id =
|
||||
GetLocalNameScopeId(import_interface.parent_scope_id);
|
||||
llvm::SmallVector<SemIR::ConstantId> implicit_param_const_ids =
|
||||
GetLocalParamConstantIds(import_interface.implicit_param_refs_id);
|
||||
llvm::SmallVector<SemIR::ConstantId> param_const_ids =
|
||||
GetLocalParamConstantIds(import_interface.param_refs_id);
|
||||
auto self_param_id = GetLocalConstantId(import_interface.self_param_id);
|
||||
|
||||
if (HasNewWork(initial_work)) {
|
||||
@@ -1133,6 +1151,10 @@ class ImportRefResolver {
|
||||
.GetAs<SemIR::InterfaceType>(interface_const_id.inst_id())
|
||||
.interface_id);
|
||||
new_interface.parent_scope_id = parent_scope_id;
|
||||
new_interface.implicit_param_refs_id = GetLocalParamRefsId(
|
||||
import_interface.implicit_param_refs_id, implicit_param_const_ids);
|
||||
new_interface.param_refs_id =
|
||||
GetLocalParamRefsId(import_interface.param_refs_id, param_const_ids);
|
||||
|
||||
if (import_interface.is_defined()) {
|
||||
AddInterfaceDefinition(import_interface, new_interface, self_param_id);
|
||||
|
||||
+10
-10
@@ -210,9 +210,9 @@ static auto CheckRedeclParam(Context& context,
|
||||
}
|
||||
|
||||
// Returns false if the param refs differ for a redeclaration.
|
||||
static auto CheckRedeclParams(Context& context, SemIR::InstId new_decl_id,
|
||||
static auto CheckRedeclParams(Context& context, SemIRLoc new_decl_loc,
|
||||
SemIR::InstBlockId new_param_refs_id,
|
||||
SemIR::InstId prev_decl_id,
|
||||
SemIRLoc prev_decl_loc,
|
||||
SemIR::InstBlockId prev_param_refs_id,
|
||||
llvm::StringLiteral param_diag_label,
|
||||
Substitutions substitutions) -> bool {
|
||||
@@ -231,9 +231,9 @@ static auto CheckRedeclParams(Context& context, SemIR::InstId new_decl_id,
|
||||
llvm::StringLiteral, llvm::StringLiteral);
|
||||
context.emitter()
|
||||
.Build(
|
||||
new_decl_id, RedeclParamListDiffers, param_diag_label,
|
||||
new_decl_loc, RedeclParamListDiffers, param_diag_label,
|
||||
new_param_refs_id.is_valid() ? llvm::StringLiteral("") : "missing ")
|
||||
.Note(prev_decl_id, RedeclParamListPrevious, param_diag_label,
|
||||
.Note(prev_decl_loc, RedeclParamListPrevious, param_diag_label,
|
||||
prev_param_refs_id.is_valid() ? llvm::StringLiteral("") : "out")
|
||||
.Emit();
|
||||
return false;
|
||||
@@ -251,9 +251,9 @@ static auto CheckRedeclParams(Context& context, SemIR::InstId new_decl_id,
|
||||
"Previously declared with {0}parameter count of {1}.",
|
||||
llvm::StringLiteral, int32_t);
|
||||
context.emitter()
|
||||
.Build(new_decl_id, RedeclParamCountDiffers, param_diag_label,
|
||||
.Build(new_decl_loc, RedeclParamCountDiffers, param_diag_label,
|
||||
new_param_ref_ids.size())
|
||||
.Note(prev_decl_id, RedeclParamCountPrevious, param_diag_label,
|
||||
.Note(prev_decl_loc, RedeclParamCountPrevious, param_diag_label,
|
||||
prev_param_ref_ids.size())
|
||||
.Emit();
|
||||
return false;
|
||||
@@ -275,12 +275,12 @@ auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
|
||||
EntityHasParamError(context, prev_entity)) {
|
||||
return false;
|
||||
}
|
||||
if (!CheckRedeclParams(context, new_entity.decl_id,
|
||||
new_entity.implicit_param_refs_id, prev_entity.decl_id,
|
||||
if (!CheckRedeclParams(context, new_entity.loc,
|
||||
new_entity.implicit_param_refs_id, prev_entity.loc,
|
||||
prev_entity.implicit_param_refs_id, "implicit ",
|
||||
substitutions) ||
|
||||
!CheckRedeclParams(context, new_entity.decl_id, new_entity.param_refs_id,
|
||||
prev_entity.decl_id, prev_entity.param_refs_id, "",
|
||||
!CheckRedeclParams(context, new_entity.loc, new_entity.param_refs_id,
|
||||
prev_entity.loc, prev_entity.param_refs_id, "",
|
||||
substitutions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+11
-4
@@ -46,12 +46,18 @@ auto ReplacePrevInstForMerge(Context& context, SemIR::NameScopeId scope_id,
|
||||
struct DeclParams {
|
||||
template <typename Entity>
|
||||
explicit DeclParams(const Entity& entity)
|
||||
: decl_id(entity.decl_id),
|
||||
: loc(entity.decl_id),
|
||||
implicit_param_refs_id(entity.implicit_param_refs_id),
|
||||
param_refs_id(entity.param_refs_id) {}
|
||||
|
||||
// The declaration of the entity.
|
||||
SemIR::InstId decl_id;
|
||||
DeclParams(SemIRLoc loc, SemIR::InstBlockId implicit_params_id,
|
||||
SemIR::InstBlockId params_id)
|
||||
: loc(loc),
|
||||
implicit_param_refs_id(implicit_params_id),
|
||||
param_refs_id(params_id) {}
|
||||
|
||||
// The location of the declaration of the entity.
|
||||
SemIRLoc loc;
|
||||
// The implicit parameters of the entity. Can be Invalid if there is no
|
||||
// implicit parameter list.
|
||||
SemIR::InstBlockId implicit_param_refs_id;
|
||||
@@ -65,7 +71,8 @@ struct DeclParams {
|
||||
// returns false.
|
||||
auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
|
||||
const DeclParams& prev_entity,
|
||||
Substitutions substitutions) -> bool;
|
||||
Substitutions substitutions = Substitutions())
|
||||
-> bool;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
// 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
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/fail_generic_method.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_generic_method.carbon
|
||||
|
||||
class Class(T:! type) {
|
||||
var a: T;
|
||||
fn F[self: Self](n: T);
|
||||
}
|
||||
|
||||
// TODO: The follow-on errors here aren't great. Investigate whether we can
|
||||
// enter the scope anyway if the parameters don't match.
|
||||
// CHECK:STDERR: fail_generic_method.carbon:[[@LINE+14]]:10: ERROR: Redeclaration differs at parameter 1.
|
||||
// CHECK:STDERR: fn Class(N:! i32).F[self: Self](n: T) {}
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_generic_method.carbon:[[@LINE-10]]:13: Previous declaration's corresponding parameter here.
|
||||
// CHECK:STDERR: class Class(T:! type) {
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_generic_method.carbon:[[@LINE+7]]:27: ERROR: Name `Self` not found.
|
||||
// CHECK:STDERR: fn Class(N:! i32).F[self: Self](n: T) {}
|
||||
// CHECK:STDERR: ^~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_generic_method.carbon:[[@LINE+3]]:36: ERROR: Name `T` not found.
|
||||
// CHECK:STDERR: fn Class(N:! i32).F[self: Self](n: T) {}
|
||||
// CHECK:STDERR: ^
|
||||
fn Class(N:! i32).F[self: Self](n: T) {}
|
||||
|
||||
// CHECK:STDOUT: --- fail_generic_method.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %Class.1: type = generic_class_type @Class [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct.1: Class = struct_value () [template]
|
||||
// CHECK:STDOUT: %Class.2: type = class_type @Class [template]
|
||||
// CHECK:STDOUT: %.2: type = unbound_element_type Class, T [symbolic]
|
||||
// CHECK:STDOUT: %F: type = fn_type @F [template]
|
||||
// CHECK:STDOUT: %struct.2: F = struct_value () [template]
|
||||
// CHECK:STDOUT: %.3: type = struct_type {.a: T} [symbolic]
|
||||
// CHECK:STDOUT: %Int32: type = fn_type @Int32 [template]
|
||||
// CHECK:STDOUT: %struct.3: Int32 = struct_value () [template]
|
||||
// CHECK:STDOUT: %N: i32 = bind_symbolic_name N 0 [symbolic]
|
||||
// CHECK:STDOUT: %.4: type = fn_type @.1 [template]
|
||||
// CHECK:STDOUT: %struct.4: <invalid> = struct_value () [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Core = %Core
|
||||
// CHECK:STDOUT: .Class = %Class.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %Class.decl: Class = class_decl @Class [template = constants.%struct.1] {
|
||||
// CHECK:STDOUT: %T.loc11_13.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %import_ref: Int32 = import_ref ir3, inst+3, loaded [template = constants.%struct.3]
|
||||
// CHECK:STDOUT: %.decl: <invalid> = fn_decl @.1 [template = constants.%struct.4] {
|
||||
// CHECK:STDOUT: %int.make_type_32: init type = call constants.%struct.3() [template = i32]
|
||||
// CHECK:STDOUT: %.loc32_14.1: type = value_of_initializer %int.make_type_32 [template = i32]
|
||||
// CHECK:STDOUT: %.loc32_14.2: type = converted %int.make_type_32, %.loc32_14.1 [template = i32]
|
||||
// CHECK:STDOUT: %N.loc32_10.1: i32 = param N
|
||||
// CHECK:STDOUT: %N.loc32_10.2: i32 = bind_symbolic_name N 0, %N.loc32_10.1 [symbolic = constants.%N]
|
||||
// CHECK:STDOUT: %Self.ref: <error> = name_ref Self, <error> [template = <error>]
|
||||
// CHECK:STDOUT: %self.loc32_21.1: <error> = param self
|
||||
// CHECK:STDOUT: @.1.%self: <error> = bind_name self, %self.loc32_21.1
|
||||
// CHECK:STDOUT: %T.ref: <error> = name_ref T, <error> [template = <error>]
|
||||
// CHECK:STDOUT: %n.loc32_33.1: <error> = param n
|
||||
// CHECK:STDOUT: @.1.%n: <error> = bind_name n, %n.loc32_33.1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Class {
|
||||
// CHECK:STDOUT: %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %.loc12: <unbound element of class Class> = field_decl a, element0 [template]
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] {
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Class.2 [template = constants.%Class.2]
|
||||
// CHECK:STDOUT: %self.loc13_8.1: Class = param self
|
||||
// CHECK:STDOUT: %self.loc13_8.2: Class = bind_name self, %self.loc13_8.1
|
||||
// CHECK:STDOUT: %T.ref.loc13: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %n.loc13_20.1: T = param n
|
||||
// CHECK:STDOUT: %n.loc13_20.2: T = bind_name n, %n.loc13_20.1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%Class.2
|
||||
// CHECK:STDOUT: .a = %.loc12
|
||||
// CHECK:STDOUT: .F = %F.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F[@Class.%self.loc13_8.2: Class](@Class.%n.loc13_20.2: T);
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @.1[%self: <error>](%n: <error>) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -1,75 +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
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/generic/fail_todo_member_out_of_line.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/generic/fail_todo_member_out_of_line.carbon
|
||||
|
||||
class Class(T:! type) {
|
||||
fn F(n: T) -> T;
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_todo_member_out_of_line.carbon:[[@LINE+3]]:9: ERROR: Semantics TODO: `name qualifier with parameters`.
|
||||
// CHECK:STDERR: fn Class(T:! type).F(n: T) -> T {
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
fn Class(T:! type).F(n: T) -> T {
|
||||
return n;
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: --- fail_todo_member_out_of_line.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %Class.1: type = generic_class_type @Class [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct.1: Class = struct_value () [template]
|
||||
// CHECK:STDOUT: %Class.2: type = class_type @Class [template]
|
||||
// CHECK:STDOUT: %F: type = fn_type @F [template]
|
||||
// CHECK:STDOUT: %struct.2: F = struct_value () [template]
|
||||
// CHECK:STDOUT: %.2: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Core = %Core
|
||||
// CHECK:STDOUT: .Class = %Class.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %Class.decl: Class = class_decl @Class [template = constants.%struct.1] {
|
||||
// CHECK:STDOUT: %T.loc11_13.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] {
|
||||
// CHECK:STDOUT: %T.loc18_10.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc18_10.2: type = bind_symbolic_name T 0, %T.loc18_10.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %T.ref.loc18_25: type = name_ref T, %T.loc18_10.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %n.loc18_22.1: T = param n
|
||||
// CHECK:STDOUT: @F.%n: T = bind_name n, %n.loc18_22.1
|
||||
// CHECK:STDOUT: %T.ref.loc18_31: type = name_ref T, %T.loc18_10.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: @F.%return: ref T = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Class {
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] {
|
||||
// CHECK:STDOUT: %T.ref.loc12_11: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %n.loc12_8.1: T = param n
|
||||
// CHECK:STDOUT: %n.loc12_8.2: T = bind_name n, %n.loc12_8.1
|
||||
// CHECK:STDOUT: %T.ref.loc12_17: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %return.var: ref T = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%Class.2
|
||||
// CHECK:STDOUT: .F = %F.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F(%n: T) -> T {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %n.ref: T = name_ref n, %n
|
||||
// CHECK:STDOUT: return %n.ref
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -0,0 +1,412 @@
|
||||
// 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
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/generic/member_out_of_line.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/generic/member_out_of_line.carbon
|
||||
|
||||
// --- basic.carbon
|
||||
|
||||
library "basic";
|
||||
|
||||
class Class(T:! type) {
|
||||
fn F(n: T) -> T;
|
||||
}
|
||||
|
||||
fn Class(T:! type).F(n: T) -> T {
|
||||
return n;
|
||||
}
|
||||
|
||||
// --- nested.carbon
|
||||
|
||||
library "nested";
|
||||
|
||||
class A(T:! type) {
|
||||
class B(N:! T) {
|
||||
fn F[self: Self](a: T);
|
||||
}
|
||||
}
|
||||
|
||||
fn A(T:! type).B(N:! T).F[self: Self](a: T) {}
|
||||
|
||||
// --- fail_mismatched_not_generic_vs_generic.carbon
|
||||
|
||||
library "fail_mismatched_not_generic_vs_generic";
|
||||
|
||||
class NotGeneric {
|
||||
fn F();
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_mismatched_not_generic_vs_generic.carbon:[[@LINE+7]]:4: ERROR: Redeclaration differs because of parameter list.
|
||||
// CHECK:STDERR: fn NotGeneric(T:! type).F() {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR: fail_mismatched_not_generic_vs_generic.carbon:[[@LINE-7]]:1: Previously declared without parameter list.
|
||||
// CHECK:STDERR: class NotGeneric {
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
fn NotGeneric(T:! type).F() {}
|
||||
|
||||
// --- fail_mismatched_too_few_args.carbon
|
||||
|
||||
library "fail_mismatched_too_few_args";
|
||||
|
||||
class Generic(T:! type) {
|
||||
fn TooFew();
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_mismatched_too_few_args.carbon:[[@LINE+7]]:4: ERROR: Redeclaration differs because of parameter count of 0.
|
||||
// CHECK:STDERR: fn Generic().TooFew() {}
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_mismatched_too_few_args.carbon:[[@LINE-7]]:1: Previously declared with parameter count of 1.
|
||||
// CHECK:STDERR: class Generic(T:! type) {
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
fn Generic().TooFew() {}
|
||||
|
||||
// --- fail_mismatched_too_many_args.carbon
|
||||
|
||||
library "fail_mismatched_too_many_args";
|
||||
|
||||
class Generic(T:! type) {
|
||||
fn TooMany();
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_mismatched_too_many_args.carbon:[[@LINE+7]]:4: ERROR: Redeclaration differs because of parameter count of 2.
|
||||
// CHECK:STDERR: fn Generic(T:! type, U:! type).TooMany() {}
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_mismatched_too_many_args.carbon:[[@LINE-7]]:1: Previously declared with parameter count of 1.
|
||||
// CHECK:STDERR: class Generic(T:! type) {
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
fn Generic(T:! type, U:! type).TooMany() {}
|
||||
|
||||
// --- fail_mismatched_wrong_arg_type.carbon
|
||||
|
||||
library "fail_mismatched_wrong_arg_type";
|
||||
|
||||
class Generic(T:! type) {
|
||||
fn WrongType();
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_mismatched_wrong_arg_type.carbon:[[@LINE+6]]:12: ERROR: Redeclaration differs at parameter 1.
|
||||
// CHECK:STDERR: fn Generic(T:! ()).WrongType() {}
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_mismatched_wrong_arg_type.carbon:[[@LINE-7]]:15: Previous declaration's corresponding parameter here.
|
||||
// CHECK:STDERR: class Generic(T:! type) {
|
||||
// CHECK:STDERR: ^
|
||||
fn Generic(T:! ()).WrongType() {}
|
||||
|
||||
// CHECK:STDOUT: --- basic.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %Class.1: type = generic_class_type @Class [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct.1: Class = struct_value () [template]
|
||||
// CHECK:STDOUT: %Class.2: type = class_type @Class [template]
|
||||
// CHECK:STDOUT: %F: type = fn_type @F [template]
|
||||
// CHECK:STDOUT: %struct.2: F = struct_value () [template]
|
||||
// CHECK:STDOUT: %.2: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Core = %Core
|
||||
// CHECK:STDOUT: .Class = %Class.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %Class.decl: Class = class_decl @Class [template = constants.%struct.1] {
|
||||
// CHECK:STDOUT: %T.loc4_13.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc4_13.2: type = bind_symbolic_name T 0, %T.loc4_13.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] {
|
||||
// CHECK:STDOUT: %T.loc8_10.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc8_10.2: type = bind_symbolic_name T 0, %T.loc8_10.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %T.ref.loc8_25: type = name_ref T, %T.loc8_10.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %n.loc8_22.1: T = param n
|
||||
// CHECK:STDOUT: @F.%n: T = bind_name n, %n.loc8_22.1
|
||||
// CHECK:STDOUT: %T.ref.loc8_31: type = name_ref T, %T.loc8_10.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: @F.%return: ref T = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Class {
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] {
|
||||
// CHECK:STDOUT: %T.ref.loc5_11: type = name_ref T, file.%T.loc4_13.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %n.loc5_8.1: T = param n
|
||||
// CHECK:STDOUT: %n.loc5_8.2: T = bind_name n, %n.loc5_8.1
|
||||
// CHECK:STDOUT: %T.ref.loc5_17: type = name_ref T, file.%T.loc4_13.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %return.var: ref T = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%Class.2
|
||||
// CHECK:STDOUT: .F = %F.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F(%n: T) -> T {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %n.ref: T = name_ref n, %n
|
||||
// CHECK:STDOUT: return %n.ref
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- nested.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %A.1: type = generic_class_type @A [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct.1: A = struct_value () [template]
|
||||
// CHECK:STDOUT: %A.2: type = class_type @A [template]
|
||||
// CHECK:STDOUT: %N: T = bind_symbolic_name N 1 [symbolic]
|
||||
// CHECK:STDOUT: %B.1: type = generic_class_type @B [template]
|
||||
// CHECK:STDOUT: %struct.2: B = struct_value () [template]
|
||||
// CHECK:STDOUT: %B.2: type = class_type @B [template]
|
||||
// CHECK:STDOUT: %F: type = fn_type @F [template]
|
||||
// CHECK:STDOUT: %struct.3: F = struct_value () [template]
|
||||
// CHECK:STDOUT: %.2: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: %.3: type = ptr_type {} [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Core = %Core
|
||||
// CHECK:STDOUT: .A = %A.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %A.decl: A = class_decl @A [template = constants.%struct.1] {
|
||||
// CHECK:STDOUT: %T.loc4_9.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc4_9.2: type = bind_symbolic_name T 0, %T.loc4_9.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.3] {
|
||||
// CHECK:STDOUT: %T.loc10_6.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc10_6.2: type = bind_symbolic_name T 0, %T.loc10_6.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %T.ref.loc10_22: type = name_ref T, %T.loc10_6.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %N.loc10_18.1: T = param N
|
||||
// CHECK:STDOUT: %N.loc10_18.2: T = bind_symbolic_name N 1, %N.loc10_18.1 [symbolic = constants.%N]
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B.2 [template = constants.%B.2]
|
||||
// CHECK:STDOUT: %self.loc10_27.1: B = param self
|
||||
// CHECK:STDOUT: @F.%self: B = bind_name self, %self.loc10_27.1
|
||||
// CHECK:STDOUT: %T.ref.loc10_42: type = name_ref T, %T.loc10_6.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %a.loc10_39.1: T = param a
|
||||
// CHECK:STDOUT: @F.%a: T = bind_name a, %a.loc10_39.1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @A {
|
||||
// CHECK:STDOUT: %B.decl: B = class_decl @B [template = constants.%struct.2] {
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc4_9.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %N.loc5_11.1: T = param N
|
||||
// CHECK:STDOUT: %N.loc5_11.2: T = bind_symbolic_name N 1, %N.loc5_11.1 [symbolic = constants.%N]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%A.2
|
||||
// CHECK:STDOUT: .B = %B.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @B {
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.3] {
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B.2 [template = constants.%B.2]
|
||||
// CHECK:STDOUT: %self.loc6_10.1: B = param self
|
||||
// CHECK:STDOUT: %self.loc6_10.2: B = bind_name self, %self.loc6_10.1
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc4_9.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %a.loc6_22.1: T = param a
|
||||
// CHECK:STDOUT: %a.loc6_22.2: T = bind_name a, %a.loc6_22.1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%B.2
|
||||
// CHECK:STDOUT: .F = %F.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F[%self: B](%a: T) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_mismatched_not_generic_vs_generic.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %NotGeneric: type = class_type @NotGeneric [template]
|
||||
// CHECK:STDOUT: %F: type = fn_type @F [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct.1: F = struct_value () [template]
|
||||
// CHECK:STDOUT: %.2: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %.3: type = fn_type @.1 [template]
|
||||
// CHECK:STDOUT: %struct.2: <invalid> = struct_value () [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Core = %Core
|
||||
// CHECK:STDOUT: .NotGeneric = %NotGeneric.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %NotGeneric.decl: type = class_decl @NotGeneric [template = constants.%NotGeneric] {}
|
||||
// CHECK:STDOUT: %.decl: <invalid> = fn_decl @.1 [template = constants.%struct.2] {
|
||||
// CHECK:STDOUT: %T.loc15_15.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc15_15.2: type = bind_symbolic_name T 0, %T.loc15_15.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @NotGeneric {
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.1] {}
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%NotGeneric
|
||||
// CHECK:STDOUT: .F = %F.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F();
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @.1() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_mismatched_too_few_args.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %Generic.1: type = generic_class_type @Generic [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct.1: Generic = struct_value () [template]
|
||||
// CHECK:STDOUT: %Generic.2: type = class_type @Generic [template]
|
||||
// CHECK:STDOUT: %TooFew: type = fn_type @TooFew [template]
|
||||
// CHECK:STDOUT: %struct.2: TooFew = struct_value () [template]
|
||||
// CHECK:STDOUT: %.2: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: %.3: type = fn_type @.1 [template]
|
||||
// CHECK:STDOUT: %struct.3: <invalid> = struct_value () [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Core = %Core
|
||||
// CHECK:STDOUT: .Generic = %Generic.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %Generic.decl: Generic = class_decl @Generic [template = constants.%struct.1] {
|
||||
// CHECK:STDOUT: %T.loc4_15.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc4_15.2: type = bind_symbolic_name T 0, %T.loc4_15.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %.decl: <invalid> = fn_decl @.1 [template = constants.%struct.3] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Generic {
|
||||
// CHECK:STDOUT: %TooFew.decl: TooFew = fn_decl @TooFew [template = constants.%struct.2] {}
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%Generic.2
|
||||
// CHECK:STDOUT: .TooFew = %TooFew.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @TooFew();
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @.1() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_mismatched_too_many_args.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %Generic.1: type = generic_class_type @Generic [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct.1: Generic = struct_value () [template]
|
||||
// CHECK:STDOUT: %Generic.2: type = class_type @Generic [template]
|
||||
// CHECK:STDOUT: %TooMany: type = fn_type @TooMany [template]
|
||||
// CHECK:STDOUT: %struct.2: TooMany = struct_value () [template]
|
||||
// CHECK:STDOUT: %.2: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: %U: type = bind_symbolic_name U 1 [symbolic]
|
||||
// CHECK:STDOUT: %.3: type = fn_type @.1 [template]
|
||||
// CHECK:STDOUT: %struct.3: <invalid> = struct_value () [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Core = %Core
|
||||
// CHECK:STDOUT: .Generic = %Generic.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %Generic.decl: Generic = class_decl @Generic [template = constants.%struct.1] {
|
||||
// CHECK:STDOUT: %T.loc4_15.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc4_15.2: type = bind_symbolic_name T 0, %T.loc4_15.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %.decl: <invalid> = fn_decl @.1 [template = constants.%struct.3] {
|
||||
// CHECK:STDOUT: %T.loc15_12.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc15_12.2: type = bind_symbolic_name T 0, %T.loc15_12.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %U.loc15_22.1: type = param U
|
||||
// CHECK:STDOUT: %U.loc15_22.2: type = bind_symbolic_name U 1, %U.loc15_22.1 [symbolic = constants.%U]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Generic {
|
||||
// CHECK:STDOUT: %TooMany.decl: TooMany = fn_decl @TooMany [template = constants.%struct.2] {}
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%Generic.2
|
||||
// CHECK:STDOUT: .TooMany = %TooMany.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @TooMany();
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @.1() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_mismatched_wrong_arg_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T.1: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %Generic.1: type = generic_class_type @Generic [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct.1: Generic = struct_value () [template]
|
||||
// CHECK:STDOUT: %Generic.2: type = class_type @Generic [template]
|
||||
// CHECK:STDOUT: %WrongType: type = fn_type @WrongType [template]
|
||||
// CHECK:STDOUT: %struct.2: WrongType = struct_value () [template]
|
||||
// CHECK:STDOUT: %.2: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: %T.2: () = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %.3: type = fn_type @.1 [template]
|
||||
// CHECK:STDOUT: %struct.3: <invalid> = struct_value () [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Core = %Core
|
||||
// CHECK:STDOUT: .Generic = %Generic.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %Generic.decl: Generic = class_decl @Generic [template = constants.%struct.1] {
|
||||
// CHECK:STDOUT: %T.loc4_15.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc4_15.2: type = bind_symbolic_name T 0, %T.loc4_15.1 [symbolic = constants.%T.1]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %.decl: <invalid> = fn_decl @.1 [template = constants.%struct.3] {
|
||||
// CHECK:STDOUT: %.loc14_17.1: () = tuple_literal ()
|
||||
// CHECK:STDOUT: %.loc14_17.2: type = converted %.loc14_17.1, constants.%.1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %T.loc14_12.1: () = param T
|
||||
// CHECK:STDOUT: %T.loc14_12.2: () = bind_symbolic_name T 0, %T.loc14_12.1 [symbolic = constants.%T.2]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Generic {
|
||||
// CHECK:STDOUT: %WrongType.decl: WrongType = fn_decl @WrongType [template = constants.%struct.2] {}
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%Generic.2
|
||||
// CHECK:STDOUT: .WrongType = %WrongType.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @WrongType();
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @.1() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+10
-13
@@ -4,21 +4,18 @@
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/fail_todo_generic_method.carbon
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/generic_method.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_todo_generic_method.carbon
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/generic_method.carbon
|
||||
|
||||
class Class(T:! type) {
|
||||
var a: T;
|
||||
fn F[self: Self](n: T);
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_todo_generic_method.carbon:[[@LINE+3]]:9: ERROR: Semantics TODO: `name qualifier with parameters`.
|
||||
// CHECK:STDERR: fn Class(T:! type).F[self: Self](n: T) {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
fn Class(T:! type).F[self: Self](n: T) {}
|
||||
|
||||
// CHECK:STDOUT: --- fail_todo_generic_method.carbon
|
||||
// CHECK:STDOUT: --- generic_method.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
@@ -44,14 +41,14 @@ fn Class(T:! type).F[self: Self](n: T) {}
|
||||
// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] {
|
||||
// CHECK:STDOUT: %T.loc19_10.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc19_10.2: type = bind_symbolic_name T 0, %T.loc19_10.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %T.loc16_10.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc16_10.2: type = bind_symbolic_name T 0, %T.loc16_10.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Class.2 [template = constants.%Class.2]
|
||||
// CHECK:STDOUT: %self.loc19_22.1: Class = param self
|
||||
// CHECK:STDOUT: @F.%self: Class = bind_name self, %self.loc19_22.1
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc19_10.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %n.loc19_34.1: T = param n
|
||||
// CHECK:STDOUT: @F.%n: T = bind_name n, %n.loc19_34.1
|
||||
// CHECK:STDOUT: %self.loc16_22.1: Class = param self
|
||||
// CHECK:STDOUT: @F.%self: Class = bind_name self, %self.loc16_22.1
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc16_10.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %n.loc16_34.1: T = param n
|
||||
// CHECK:STDOUT: @F.%n: T = bind_name n, %n.loc16_34.1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+15
-19
@@ -8,10 +8,6 @@
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/fail_extend_impl_forall.carbon
|
||||
|
||||
// CHECK:STDERR: fail_extend_impl_forall.carbon:[[@LINE+4]]:1: ERROR: Semantics TODO: `generic interface`.
|
||||
// CHECK:STDERR: interface GenericInterface(T:! type) {
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
interface GenericInterface(T:! type) {
|
||||
fn F(x: T);
|
||||
}
|
||||
@@ -58,8 +54,8 @@ class C {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %GenericInterface.decl: type = interface_decl @GenericInterface [template = constants.%.1] {
|
||||
// CHECK:STDOUT: %T.loc15_28.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc15_28.2: type = bind_symbolic_name T 0, %T.loc15_28.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %T.loc11_28.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc11_28.2: type = bind_symbolic_name T 0, %T.loc11_28.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
|
||||
// CHECK:STDOUT: }
|
||||
@@ -67,23 +63,23 @@ class C {
|
||||
// CHECK:STDOUT: interface @GenericInterface {
|
||||
// CHECK:STDOUT: %Self: GenericInterface = bind_symbolic_name Self 1 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F.1 [template = constants.%struct.1] {
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc15_28.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %x.loc16_8.1: T = param x
|
||||
// CHECK:STDOUT: %x.loc16_8.2: T = bind_name x, %x.loc16_8.1
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc11_28.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %x.loc12_8.1: T = param x
|
||||
// CHECK:STDOUT: %x.loc12_8.2: T = bind_name x, %x.loc12_8.1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %.loc16: <associated F in GenericInterface> = assoc_entity element0, %F.decl [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc12: <associated F in GenericInterface> = assoc_entity element0, %F.decl [template = constants.%.4]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = %Self
|
||||
// CHECK:STDOUT: .F = %.loc16
|
||||
// CHECK:STDOUT: .F = %.loc12
|
||||
// CHECK:STDOUT: witness = (%F.decl)
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: impl @impl: C as <error> {
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F.2 [template = constants.%struct.2] {
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, @C.%T.loc31_23.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %x.loc32_10.1: T = param x
|
||||
// CHECK:STDOUT: %x.loc32_10.2: T = bind_name x, %x.loc32_10.1
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, @C.%T.loc27_23.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %x.loc28_10.1: T = param x
|
||||
// CHECK:STDOUT: %x.loc28_10.2: T = bind_name x, %x.loc28_10.1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
@@ -93,10 +89,10 @@ class C {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C {
|
||||
// CHECK:STDOUT: impl_decl @impl {
|
||||
// CHECK:STDOUT: %T.loc31_23.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc31_23.2: type = bind_symbolic_name T 0, %T.loc31_23.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %T.loc27_23.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc27_23.2: type = bind_symbolic_name T 0, %T.loc27_23.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %GenericInterface.ref: type = name_ref GenericInterface, file.%GenericInterface.decl [template = constants.%.1]
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc31_23.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc27_23.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
@@ -104,9 +100,9 @@ class C {
|
||||
// CHECK:STDOUT: has_error
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F.1(@GenericInterface.%x.loc16_8.2: T);
|
||||
// CHECK:STDOUT: fn @F.1(@GenericInterface.%x.loc12_8.2: T);
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F.2(@impl.%x.loc32_10.2: T) {
|
||||
// CHECK:STDOUT: fn @F.2(@impl.%x.loc28_10.2: T) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
// 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
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon
|
||||
|
||||
interface NotGeneric;
|
||||
// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE+7]]:1: ERROR: Redeclaration differs because of parameter list.
|
||||
// CHECK:STDERR: interface NotGeneric(T:! type) {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE-4]]:1: Previously declared without parameter list.
|
||||
// CHECK:STDERR: interface NotGeneric;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
interface NotGeneric(T:! type) {}
|
||||
|
||||
interface Generic(T:! type);
|
||||
// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE+7]]:1: ERROR: Redeclaration differs because of missing parameter list.
|
||||
// CHECK:STDERR: interface Generic {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE-4]]:1: Previously declared with parameter list.
|
||||
// CHECK:STDERR: interface Generic(T:! type);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
interface Generic {}
|
||||
|
||||
interface DifferentParams(T:! type);
|
||||
// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE+6]]:27: ERROR: Redeclaration differs at parameter 1.
|
||||
// CHECK:STDERR: interface DifferentParams(T:! ()) {}
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE-4]]:27: Previous declaration's corresponding parameter here.
|
||||
// CHECK:STDERR: interface DifferentParams(T:! type);
|
||||
// CHECK:STDERR: ^
|
||||
interface DifferentParams(T:! ()) {}
|
||||
|
||||
// CHECK:STDOUT: --- fail_generic_redeclaration.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %.1: type = interface_type @NotGeneric [template]
|
||||
// CHECK:STDOUT: %T.1: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %.2: type = interface_type @.1 [template]
|
||||
// CHECK:STDOUT: %Self.1: <invalid> = bind_symbolic_name Self 1 [symbolic]
|
||||
// CHECK:STDOUT: %.3: type = interface_type @Generic [template]
|
||||
// CHECK:STDOUT: %.4: type = interface_type @.2 [template]
|
||||
// CHECK:STDOUT: %Self.2: <invalid> = bind_symbolic_name Self 0 [symbolic]
|
||||
// CHECK:STDOUT: %.5: type = interface_type @DifferentParams [template]
|
||||
// CHECK:STDOUT: %.6: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %T.2: () = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %.7: type = interface_type @.3 [template]
|
||||
// CHECK:STDOUT: %Self.3: <invalid> = bind_symbolic_name Self 1 [symbolic]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .NotGeneric = %NotGeneric.decl
|
||||
// CHECK:STDOUT: .Generic = %Generic.decl
|
||||
// CHECK:STDOUT: .DifferentParams = %DifferentParams.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %NotGeneric.decl: type = interface_decl @NotGeneric [template = constants.%.1] {}
|
||||
// CHECK:STDOUT: %.decl.loc19: type = interface_decl @.1 [template = constants.%.2] {
|
||||
// CHECK:STDOUT: %T.loc19_22.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc19_22.2: type = bind_symbolic_name T 0, %T.loc19_22.1 [symbolic = constants.%T.1]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Generic.decl: type = interface_decl @Generic [template = constants.%.3] {
|
||||
// CHECK:STDOUT: %T.loc21_19.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc21_19.2: type = bind_symbolic_name T 0, %T.loc21_19.1 [symbolic = constants.%T.1]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %.decl.loc29: type = interface_decl @.2 [template = constants.%.4] {}
|
||||
// CHECK:STDOUT: %DifferentParams.decl: type = interface_decl @DifferentParams [template = constants.%.5] {
|
||||
// CHECK:STDOUT: %T.loc31_27.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc31_27.2: type = bind_symbolic_name T 0, %T.loc31_27.1 [symbolic = constants.%T.1]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %.decl.loc38: type = interface_decl @.3 [template = constants.%.7] {
|
||||
// CHECK:STDOUT: %.loc38_32.1: () = tuple_literal ()
|
||||
// CHECK:STDOUT: %.loc38_32.2: type = converted %.loc38_32.1, constants.%.6 [template = constants.%.6]
|
||||
// CHECK:STDOUT: %T.loc38_27.1: () = param T
|
||||
// CHECK:STDOUT: %T.loc38_27.2: () = bind_symbolic_name T 0, %T.loc38_27.1 [symbolic = constants.%T.2]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @NotGeneric;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @.1 {
|
||||
// CHECK:STDOUT: %Self: <invalid> = bind_symbolic_name Self 1 [symbolic = constants.%Self.1]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = %Self
|
||||
// CHECK:STDOUT: witness = ()
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @Generic;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @.2 {
|
||||
// CHECK:STDOUT: %Self: <invalid> = bind_symbolic_name Self 0 [symbolic = constants.%Self.2]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = %Self
|
||||
// CHECK:STDOUT: witness = ()
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @DifferentParams;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @.3 {
|
||||
// CHECK:STDOUT: %Self: <invalid> = bind_symbolic_name Self 1 [symbolic = constants.%Self.3]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = %Self
|
||||
// CHECK:STDOUT: witness = ()
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
// 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
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon
|
||||
|
||||
interface I(T:! type) {
|
||||
// TODO: Use `default` here.
|
||||
fn F[self: Self]() -> Self;
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+6]]:1: ERROR: Duplicate name being declared in the same scope.
|
||||
// CHECK:STDERR: fn I(T:! type).F[self: Self]() -> Self { return self; }
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE-6]]:3: Name is previously declared here.
|
||||
// CHECK:STDERR: fn F[self: Self]() -> Self;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
fn I(T:! type).F[self: Self]() -> Self { return self; }
|
||||
|
||||
// CHECK:STDOUT: --- fail_todo_generic_default_fn.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %.1: type = interface_type @I [template]
|
||||
// CHECK:STDOUT: %Self: I = bind_symbolic_name Self 1 [symbolic]
|
||||
// CHECK:STDOUT: %F: type = fn_type @F [template]
|
||||
// CHECK:STDOUT: %.2: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct.1: F = struct_value () [template]
|
||||
// CHECK:STDOUT: %.3: type = assoc_entity_type @I, F [template]
|
||||
// CHECK:STDOUT: %.4: <associated F in I> = assoc_entity element0, @I.%F.decl [template]
|
||||
// CHECK:STDOUT: %.5: type = fn_type @.1 [template]
|
||||
// CHECK:STDOUT: %struct.2: <invalid> = struct_value () [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .I = %I.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%.1] {
|
||||
// CHECK:STDOUT: %T.loc11_13.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %.decl: <invalid> = fn_decl @.1 [template = constants.%struct.2] {
|
||||
// CHECK:STDOUT: %T.loc22_6.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc22_6.2: type = bind_symbolic_name T 0, %T.loc22_6.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %Self.ref.loc22_24: I = name_ref Self, @I.%Self [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %.loc22_24.1: type = facet_type_access %Self.ref.loc22_24 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %.loc22_24.2: type = converted %Self.ref.loc22_24, %.loc22_24.1 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %self.loc22_18.1: Self = param self
|
||||
// CHECK:STDOUT: @.1.%self: Self = bind_name self, %self.loc22_18.1
|
||||
// CHECK:STDOUT: %Self.ref.loc22_35: I = name_ref Self, @I.%Self [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %.loc22_35.1: type = facet_type_access %Self.ref.loc22_35 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %.loc22_35.2: type = converted %Self.ref.loc22_35, %.loc22_35.1 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: @.1.%return: ref Self = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @I {
|
||||
// CHECK:STDOUT: %Self: I = bind_symbolic_name Self 1 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.1] {
|
||||
// CHECK:STDOUT: %Self.ref.loc13_14: I = name_ref Self, %Self [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %.loc13_14.1: type = facet_type_access %Self.ref.loc13_14 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %.loc13_14.2: type = converted %Self.ref.loc13_14, %.loc13_14.1 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %self.loc13_8.1: Self = param self
|
||||
// CHECK:STDOUT: %self.loc13_8.2: Self = bind_name self, %self.loc13_8.1
|
||||
// CHECK:STDOUT: %Self.ref.loc13_25: I = name_ref Self, %Self [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %.loc13_25.1: type = facet_type_access %Self.ref.loc13_25 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %.loc13_25.2: type = converted %Self.ref.loc13_25, %.loc13_25.1 [symbolic = constants.%Self]
|
||||
// CHECK:STDOUT: %return.var: ref Self = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %.loc13_29: <associated F in I> = assoc_entity element0, %F.decl [template = constants.%.4]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = %Self
|
||||
// CHECK:STDOUT: .F = %.loc13_29
|
||||
// CHECK:STDOUT: witness = (%F.decl)
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F[@I.%self.loc13_8.2: Self]() -> Self;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @.1[%self: Self]() -> Self {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %self.ref: Self = name_ref self, %self
|
||||
// CHECK:STDOUT: return %self.ref
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+13
-8
@@ -4,18 +4,17 @@
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_generic.carbon
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/generic.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_generic.carbon
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/generic.carbon
|
||||
|
||||
// CHECK:STDERR: fail_todo_generic.carbon:[[@LINE+3]]:1: ERROR: Semantics TODO: `generic interface`.
|
||||
// CHECK:STDERR: interface I[]();
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
|
||||
interface I[]();
|
||||
interface I[T:! type](N:! T);
|
||||
|
||||
// CHECK:STDOUT: --- fail_todo_generic.carbon
|
||||
// CHECK:STDOUT: --- generic.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %N: T = bind_symbolic_name N 1 [symbolic]
|
||||
// CHECK:STDOUT: %.1: type = interface_type @I [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -23,7 +22,13 @@ interface I[]();
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .I = %I.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%.1] {}
|
||||
// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%.1] {
|
||||
// CHECK:STDOUT: %T.loc11_13.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc11_13.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %N.loc11_23.1: T = param N
|
||||
// CHECK:STDOUT: %N.loc11_23.2: T = bind_symbolic_name N 1, %N.loc11_23.1 [symbolic = constants.%N]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @I;
|
||||
+29
-6
@@ -23,11 +23,21 @@ fn A.F() {}
|
||||
// CHECK:STDERR:
|
||||
namespace B(n: i32);
|
||||
|
||||
// CHECK:STDERR: fail_params.carbon:[[@LINE+3]]:12: ERROR: `namespace` declaration cannot have parameters.
|
||||
// CHECK:STDERR: fail_params.carbon:[[@LINE+4]]:12: ERROR: `namespace` declaration cannot have parameters.
|
||||
// CHECK:STDERR: namespace C[T:! type](x: T);
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
namespace C[T:! type](x: T);
|
||||
|
||||
namespace D;
|
||||
// CHECK:STDERR: fail_params.carbon:[[@LINE+6]]:4: ERROR: Redeclaration differs because of parameter list.
|
||||
// CHECK:STDERR: fn D(T:! type).F() {}
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_params.carbon:[[@LINE-4]]:1: Previously declared without parameter list.
|
||||
// CHECK:STDERR: namespace D;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~
|
||||
fn D(T:! type).F() {}
|
||||
|
||||
// CHECK:STDOUT: --- fail_params.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
@@ -37,6 +47,8 @@ namespace C[T:! type](x: T);
|
||||
// CHECK:STDOUT: %Int32: type = fn_type @Int32 [template]
|
||||
// CHECK:STDOUT: %struct.2: Int32 = struct_value () [template]
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %.2: type = fn_type @.1 [template]
|
||||
// CHECK:STDOUT: %struct.3: <invalid> = struct_value () [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
@@ -45,6 +57,7 @@ namespace C[T:! type](x: T);
|
||||
// CHECK:STDOUT: .A = %A
|
||||
// CHECK:STDOUT: .B = %B
|
||||
// CHECK:STDOUT: .C = %C
|
||||
// CHECK:STDOUT: .D = %D
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %A: <namespace> = namespace [template] {
|
||||
@@ -58,12 +71,17 @@ namespace C[T:! type](x: T);
|
||||
// CHECK:STDOUT: %n.loc24_13.1: i32 = param n
|
||||
// CHECK:STDOUT: %n.loc24_13.2: i32 = bind_name n, %n.loc24_13.1
|
||||
// CHECK:STDOUT: %B: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %T.loc29_13.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc29_13.2: type = bind_symbolic_name T 0, %T.loc29_13.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc29_13.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %x.loc29_23.1: T = param x
|
||||
// CHECK:STDOUT: %x.loc29_23.2: T = bind_name x, %x.loc29_23.1
|
||||
// CHECK:STDOUT: %T.loc30_13.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc30_13.2: type = bind_symbolic_name T 0, %T.loc30_13.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc30_13.2 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: %x.loc30_23.1: T = param x
|
||||
// CHECK:STDOUT: %x.loc30_23.2: T = bind_name x, %x.loc30_23.1
|
||||
// CHECK:STDOUT: %C: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %D: <namespace> = namespace [template] {}
|
||||
// CHECK:STDOUT: %.decl: <invalid> = fn_decl @.1 [template = constants.%struct.3] {
|
||||
// CHECK:STDOUT: %T.loc39_6.1: type = param T
|
||||
// CHECK:STDOUT: %T.loc39_6.2: type = bind_symbolic_name T 0, %T.loc39_6.1 [symbolic = constants.%T]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
@@ -73,3 +91,8 @@ namespace C[T:! type](x: T);
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @.1() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
@@ -162,10 +162,10 @@ library "reopen_other";
|
||||
|
||||
import Other library "fn";
|
||||
|
||||
// CHECK:STDERR: fail_main_reopen_other.carbon:[[@LINE+7]]:11: ERROR: Imported packages cannot be used for declarations.
|
||||
// CHECK:STDERR: fail_main_reopen_other.carbon:[[@LINE+7]]:1: ERROR: Duplicate name being declared in the same scope.
|
||||
// CHECK:STDERR: namespace Other;
|
||||
// CHECK:STDERR: ^~~~~
|
||||
// CHECK:STDERR: fail_main_reopen_other.carbon:[[@LINE-5]]:1: Package imported here.
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_main_reopen_other.carbon:[[@LINE-5]]:1: Name is previously declared here.
|
||||
// CHECK:STDERR: import Other library "fn";
|
||||
// CHECK:STDERR: ^~~~~~
|
||||
// CHECK:STDERR:
|
||||
@@ -174,6 +174,24 @@ namespace Other;
|
||||
// This is not diagnosed after the diagnostic on `namespace Other;`.
|
||||
fn Other.G() {}
|
||||
|
||||
// --- fail_main_reopen_other_nested.carbon
|
||||
|
||||
library "reopen_other_nested";
|
||||
|
||||
import Other library "fn";
|
||||
|
||||
// CHECK:STDERR: fail_main_reopen_other_nested.carbon:[[@LINE+7]]:11: ERROR: Imported packages cannot be used for declarations.
|
||||
// CHECK:STDERR: namespace Other.Nested;
|
||||
// CHECK:STDERR: ^~~~~
|
||||
// CHECK:STDERR: fail_main_reopen_other_nested.carbon:[[@LINE-5]]:1: Package imported here.
|
||||
// CHECK:STDERR: import Other library "fn";
|
||||
// CHECK:STDERR: ^~~~~~
|
||||
// CHECK:STDERR:
|
||||
namespace Other.Nested;
|
||||
|
||||
// This is not diagnosed after the diagnostic on `namespace Other;`.
|
||||
fn Other.Nested.F() {}
|
||||
|
||||
// --- fail_main_add_to_other.carbon
|
||||
|
||||
library "add_to_other";
|
||||
@@ -475,6 +493,32 @@ fn UseF() { Other.F(); }
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_main_reopen_other_nested.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %F: type = fn_type @F [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct: F = struct_value () [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Other = %Other
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Other: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Nested = %Nested
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Nested: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .F = %F.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_main_add_to_other.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
|
||||
@@ -32,6 +32,10 @@ struct Interface : public Printable<Interface> {
|
||||
NameId name_id;
|
||||
// The parent scope.
|
||||
NameScopeId parent_scope_id;
|
||||
// A block containing a single reference instruction per implicit parameter.
|
||||
InstBlockId implicit_param_refs_id;
|
||||
// A block containing a single reference instruction per parameter.
|
||||
InstBlockId param_refs_id;
|
||||
// The first declaration of the interface. This is a InterfaceDecl.
|
||||
InstId decl_id;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user