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:
Richard Smith
2024-06-05 18:52:17 +00:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent 268dd04511
commit 7792e5fce3
19 changed files with 1096 additions and 323 deletions
+173 -152
View File
@@ -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;
}
}
}
+7 -18
View File
@@ -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_;
+1 -1
View File
@@ -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;
}
+20 -9
View File
@@ -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);
+12 -4
View File
@@ -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 {
+23 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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:
@@ -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
View File
@@ -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: }
@@ -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:
@@ -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:
@@ -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
View File
@@ -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 {
+4
View File
@@ -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;