Drop fn destroy support (#6136)

`fn destroy` is being removed per decision on #6124. It seems like the
relevant decision will result in no more keyword-based function names,
so this is removing all related support.
This commit is contained in:
Jon Ross-Perkins
2025-09-25 21:56:48 +00:00
committed by GitHub
parent 5b34054341
commit 705c95d6e0
18 changed files with 160 additions and 701 deletions
+2 -2
View File
@@ -7,8 +7,8 @@ package Core library "prelude/destroy";
import library "prelude/types/bool";
import library "prelude/types/int_literal";
// Object destruction, including running `fn destroy()`. Note this is distinct
// from memory deallocation.
// Destroys objects. Note this is distinct from memory deallocation.
// TODO: Switch to `Destructor`+`Destroy` model.
interface Destroy {
fn Op[addr self: Self*]();
}
+1 -84
View File
@@ -64,9 +64,7 @@ auto HandleParseNode(Context& context, Parse::ReturnTypeId node_id) -> bool {
// not on the pattern stacks yet. They are only needed in that case if we have
// a return type, which we now know that we do.
if (context.node_stack().PeekNodeKind() ==
Parse::NodeKind::IdentifierNameNotBeforeParams ||
context.node_stack().PeekNodeKind() ==
Parse::NodeKind::KeywordNameNotBeforeParams) {
Parse::NodeKind::IdentifierNameNotBeforeParams) {
context.pattern_block_stack().Push();
context.full_pattern_stack().PushFullPattern(
FullPatternStack::Kind::ExplicitParamList);
@@ -365,81 +363,6 @@ static auto RequestVtableIfVirtual(
context.vtable_stack().AddInstId(decl_id);
}
// Validates the `destroy` function's signature. May replace invalid values for
// recovery.
static auto ValidateIfDestroy(Context& context, bool is_redecl,
std::optional<SemIR::Inst> parent_scope_inst,
SemIR::Function& function_info) -> void {
if (function_info.name_id != SemIR::NameId::Destroy) {
return;
}
// For recovery, always force explicit parameters to be empty. We do this
// before any of the returns for simplicity.
auto orig_param_patterns_id = function_info.param_patterns_id;
function_info.param_patterns_id = SemIR::InstBlockId::Empty;
// Use differences on merge to diagnose remaining issues.
if (is_redecl) {
return;
}
if (!parent_scope_inst || !parent_scope_inst->Is<SemIR::ClassDecl>()) {
CARBON_DIAGNOSTIC(DestroyFunctionOutsideClass, Error,
"declaring `fn destroy` in non-class scope");
context.emitter().Emit(function_info.latest_decl_id(),
DestroyFunctionOutsideClass);
return;
}
if (!function_info.self_param_id.has_value()) {
CARBON_DIAGNOSTIC(DestroyFunctionMissingSelf, Error,
"missing implicit `self` parameter");
context.emitter().Emit(function_info.latest_decl_id(),
DestroyFunctionMissingSelf);
return;
}
// `self` must be the only implicit parameter.
if (auto block =
context.inst_blocks().Get(function_info.implicit_param_patterns_id);
block.size() > 1) {
// Point at the first non-`self` parameter.
auto param_id = block[function_info.self_param_id == block[0] ? 1 : 0];
CARBON_DIAGNOSTIC(DestroyFunctionUnexpectedImplicitParam, Error,
"unexpected implicit parameter");
context.emitter().Emit(param_id, DestroyFunctionUnexpectedImplicitParam);
return;
}
if (!orig_param_patterns_id.has_value()) {
CARBON_DIAGNOSTIC(DestroyFunctionPositionalParams, Error,
"missing empty explicit parameter list");
context.emitter().Emit(function_info.latest_decl_id(),
DestroyFunctionPositionalParams);
return;
}
if (orig_param_patterns_id != SemIR::InstBlockId::Empty) {
CARBON_DIAGNOSTIC(DestroyFunctionNonEmptyExplicitParams, Error,
"unexpected parameter");
context.emitter().Emit(context.inst_blocks().Get(orig_param_patterns_id)[0],
DestroyFunctionNonEmptyExplicitParams);
return;
}
if (auto return_type_id =
function_info.GetDeclaredReturnType(context.sem_ir());
return_type_id.has_value() &&
return_type_id != GetTupleType(context, {})) {
CARBON_DIAGNOSTIC(DestroyFunctionIncorrectReturnType, Error,
"incorrect return type; must be unspecified or `()`");
context.emitter().Emit(function_info.return_slot_pattern_id,
DestroyFunctionIncorrectReturnType);
return;
}
}
// Diagnoses when positional params aren't supported. Reassigns the pattern
// block if needed.
static auto DiagnosePositionalParams(Context& context,
@@ -505,12 +428,6 @@ static auto BuildFunctionDecl(Context& context,
function_info.definition_id = decl_id;
}
// Analyze standard function signatures before positional parameters, so that
// we can have more specific diagnostics and recovery.
bool is_redecl =
name_context.state == DeclNameStack::NameContext::State::Resolved;
ValidateIfDestroy(context, is_redecl, parent_scope_inst, function_info);
DiagnosePositionalParams(context, function_info);
TryMergeRedecl(context, node_id, name_context, function_decl, function_info,
-44
View File
@@ -140,38 +140,6 @@ auto HandleParseNode(Context& context, Parse::IdentifierNameExprId node_id)
return true;
}
// Returns the `NameId` for a keyword node.
static auto GetKeywordAsNameId(
Context& context, Parse::NodeIdOneOf<Parse::KeywordNameNotBeforeParamsId,
Parse::KeywordNameBeforeParamsId>
node_id) -> SemIR::NameId {
auto token = context.parse_tree().node_token(node_id);
switch (auto token_kind = context.tokens().GetKind(token)) {
case Lex::TokenKind::Destroy:
return SemIR::NameId::Destroy;
default:
CARBON_FATAL("Unexpected token kind: {0}", token_kind);
}
}
auto HandleParseNode(Context& context,
Parse::KeywordNameNotBeforeParamsId node_id) -> bool {
// The parent is responsible for binding the name.
context.node_stack().Push(node_id, GetKeywordAsNameId(context, node_id));
return true;
}
auto HandleParseNode(Context& context, Parse::KeywordNameBeforeParamsId node_id)
-> bool {
// Push a pattern block stack entry to handle the parameter pattern.
context.pattern_block_stack().Push();
context.full_pattern_stack().PushFullPattern(
FullPatternStack::Kind::ImplicitParamList);
// The parent is responsible for binding the name.
context.node_stack().Push(node_id, GetKeywordAsNameId(context, node_id));
return true;
}
auto HandleParseNode(Context& context, Parse::BaseNameId node_id) -> bool {
context.node_stack().Push(node_id, SemIR::NameId::Base);
return true;
@@ -219,18 +187,6 @@ auto HandleParseNode(Context& context,
return ApplyNameQualifier(context);
}
auto HandleParseNode(Context& context,
Parse::KeywordNameQualifierWithParamsId /*node_id*/)
-> bool {
return ApplyNameQualifier(context);
}
auto HandleParseNode(Context& context,
Parse::KeywordNameQualifierWithoutParamsId /*node_id*/)
-> bool {
return ApplyNameQualifier(context);
}
auto HandleParseNode(Context& context, Parse::DesignatorExprId node_id)
-> bool {
SemIR::NameId name_id = context.node_stack().PopName();
-2
View File
@@ -496,8 +496,6 @@ class NodeStack {
case Parse::NodeKind::ImportIntroducer:
case Parse::NodeKind::IndexExprStart:
case Parse::NodeKind::InvalidParseStart:
case Parse::NodeKind::KeywordNameQualifierWithParams:
case Parse::NodeKind::KeywordNameQualifierWithoutParams:
case Parse::NodeKind::LibraryIntroducer:
case Parse::NodeKind::LibrarySpecifier:
case Parse::NodeKind::InlineImportSpecifier:
+2 -2
View File
@@ -295,8 +295,8 @@ class ScopeStack {
// A stack for scope context.
llvm::SmallVector<ScopeStackEntry> scope_stack_;
// A stack of `destroy` functions to call. This only has entries inside of
// function bodies, where destruction on scope exit is required.
// A stack of instances to destroy. This only has entries inside of function
// bodies, where destruction on scope exit is required.
ArrayStack<SemIR::InstId> destroy_id_stack_;
// Information about non-lexical scopes. This is a subset of the entries and
+144 -202
View File
@@ -10,50 +10,36 @@
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/destroy_calls.carbon
// --- types.carbon
library "[[@TEST_NAME]]";
class NoAddr {
fn Make() -> NoAddr;
fn destroy[self: Self]();
}
class ExplicitReturn {
fn Make() -> ExplicitReturn;
fn destroy[self: Self]() -> ();
}
class WithAddr {
fn Make() -> WithAddr;
fn destroy[addr self: Self*]();
}
// --- implicit_return.carbon
library "[[@TEST_NAME]]";
import library "types";
class A {}
class B {}
class C {}
//@dump-sem-ir-begin
fn F() {
var no_addr: NoAddr;
var explicit_return: ExplicitReturn;
var with_addr: WithAddr;
var a: A;
var b: B;
var c: C;
}
//@dump-sem-ir-end
// --- nested_scope.carbon
library "[[@TEST_NAME]]";
import library "types";
class A {}
class B {}
class C {}
//@dump-sem-ir-begin
fn F() {
var no_addr: NoAddr;
var explicit_return: ExplicitReturn;
var with_addr: WithAddr;
var a: A;
var b: B;
if (true) {
var in_scope: NoAddr;
var c: C;
}
}
//@dump-sem-ir-end
@@ -61,43 +47,21 @@ fn F() {
// --- temp.carbon
library "[[@TEST_NAME]]";
import library "types";
class A { fn Make() -> A; }
class B { fn Make() -> B; }
class C { fn Make() -> C; }
//@dump-sem-ir-begin
fn F() {
// TODO: The scoping of these destroy calls is incorrect. Maybe we need to
// establish statement scopes?
NoAddr.Make();
ExplicitReturn.Make();
WithAddr.Make();
A.Make();
B.Make();
C.Make();
}
//@dump-sem-ir-end
// --- fail_recovery.carbon
library "[[@TEST_NAME]]";
class NoSelf {
// CHECK:STDERR: fail_recovery.carbon:[[@LINE+4]]:3: error: missing implicit `self` parameter [DestroyFunctionMissingSelf]
// CHECK:STDERR: fn destroy();
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
fn destroy();
}
class Args {
// CHECK:STDERR: fail_recovery.carbon:[[@LINE+4]]:26: error: unexpected parameter [DestroyFunctionNonEmptyExplicitParams]
// CHECK:STDERR: fn destroy[self: Self](x: ());
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
fn destroy[self: Self](x: ());
}
fn F() {
var a: NoSelf;
var b: Args;
}
// --- generic_class.carbon
library "[[@TEST_NAME]]";
@@ -127,30 +91,27 @@ fn G() { F({}); }
// CHECK:STDOUT: --- implicit_return.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %A: type = class_type @A [concrete]
// CHECK:STDOUT: %ptr.6db: type = ptr_type %A [concrete]
// CHECK:STDOUT: %A.as.Destroy.impl.Op.type: type = fn_type @A.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %A.as.Destroy.impl.Op: %A.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %B: type = class_type @B [concrete]
// CHECK:STDOUT: %ptr.e79: type = ptr_type %B [concrete]
// CHECK:STDOUT: %B.as.Destroy.impl.Op.type: type = fn_type @B.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %B.as.Destroy.impl.Op: %B.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %ptr.019: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C.as.Destroy.impl.Op.type: type = fn_type @C.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %C.as.Destroy.impl.Op: %C.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: %NoAddr: type = class_type @NoAddr [concrete]
// CHECK:STDOUT: %pattern_type.88f: type = pattern_type %NoAddr [concrete]
// CHECK:STDOUT: %ExplicitReturn: type = class_type @ExplicitReturn [concrete]
// CHECK:STDOUT: %pattern_type.611: type = pattern_type %ExplicitReturn [concrete]
// CHECK:STDOUT: %WithAddr: type = class_type @WithAddr [concrete]
// CHECK:STDOUT: %pattern_type.f93: type = pattern_type %WithAddr [concrete]
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op.type: type = fn_type @WithAddr.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op: %WithAddr.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.b4e: type = ptr_type %WithAddr [concrete]
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op.type: type = fn_type @ExplicitReturn.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op: %ExplicitReturn.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.b0a: type = ptr_type %ExplicitReturn [concrete]
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.type: type = fn_type @NoAddr.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op: %NoAddr.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.4b8: type = ptr_type %NoAddr [concrete]
// CHECK:STDOUT: %pattern_type.c10: type = pattern_type %A [concrete]
// CHECK:STDOUT: %pattern_type.049: type = pattern_type %B [concrete]
// CHECK:STDOUT: %pattern_type.c48: type = pattern_type %C [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Main.NoAddr: type = import_ref Main//types, NoAddr, loaded [concrete = constants.%NoAddr]
// CHECK:STDOUT: %Main.ExplicitReturn: type = import_ref Main//types, ExplicitReturn, loaded [concrete = constants.%ExplicitReturn]
// CHECK:STDOUT: %Main.WithAddr: type = import_ref Main//types, WithAddr, loaded [concrete = constants.%WithAddr]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -160,66 +121,63 @@ fn G() { F({}); }
// CHECK:STDOUT: fn @F() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %no_addr.patt: %pattern_type.88f = binding_pattern no_addr [concrete]
// CHECK:STDOUT: %no_addr.var_patt: %pattern_type.88f = var_pattern %no_addr.patt [concrete]
// CHECK:STDOUT: %a.patt: %pattern_type.c10 = binding_pattern a [concrete]
// CHECK:STDOUT: %a.var_patt: %pattern_type.c10 = var_pattern %a.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %no_addr.var: ref %NoAddr = var %no_addr.var_patt
// CHECK:STDOUT: %NoAddr.ref: type = name_ref NoAddr, imports.%Main.NoAddr [concrete = constants.%NoAddr]
// CHECK:STDOUT: %no_addr: ref %NoAddr = bind_name no_addr, %no_addr.var
// CHECK:STDOUT: %a.var: ref %A = var %a.var_patt
// CHECK:STDOUT: %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A]
// CHECK:STDOUT: %a: ref %A = bind_name a, %a.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %explicit_return.patt: %pattern_type.611 = binding_pattern explicit_return [concrete]
// CHECK:STDOUT: %explicit_return.var_patt: %pattern_type.611 = var_pattern %explicit_return.patt [concrete]
// CHECK:STDOUT: %b.patt: %pattern_type.049 = binding_pattern b [concrete]
// CHECK:STDOUT: %b.var_patt: %pattern_type.049 = var_pattern %b.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %explicit_return.var: ref %ExplicitReturn = var %explicit_return.var_patt
// CHECK:STDOUT: %ExplicitReturn.ref: type = name_ref ExplicitReturn, imports.%Main.ExplicitReturn [concrete = constants.%ExplicitReturn]
// CHECK:STDOUT: %explicit_return: ref %ExplicitReturn = bind_name explicit_return, %explicit_return.var
// CHECK:STDOUT: %b.var: ref %B = var %b.var_patt
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
// CHECK:STDOUT: %b: ref %B = bind_name b, %b.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %with_addr.patt: %pattern_type.f93 = binding_pattern with_addr [concrete]
// CHECK:STDOUT: %with_addr.var_patt: %pattern_type.f93 = var_pattern %with_addr.patt [concrete]
// CHECK:STDOUT: %c.patt: %pattern_type.c48 = binding_pattern c [concrete]
// CHECK:STDOUT: %c.var_patt: %pattern_type.c48 = var_pattern %c.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %with_addr.var: ref %WithAddr = var %with_addr.var_patt
// CHECK:STDOUT: %WithAddr.ref: type = name_ref WithAddr, imports.%Main.WithAddr [concrete = constants.%WithAddr]
// CHECK:STDOUT: %with_addr: ref %WithAddr = bind_name with_addr, %with_addr.var
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op.bound: <bound method> = bound_method %with_addr.var, constants.%WithAddr.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc9: %ptr.b4e = addr_of %with_addr.var
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op.call: init %empty_tuple.type = call %WithAddr.as.Destroy.impl.Op.bound(%addr.loc9)
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op.bound: <bound method> = bound_method %explicit_return.var, constants.%ExplicitReturn.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc8: %ptr.b0a = addr_of %explicit_return.var
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op.call: init %empty_tuple.type = call %ExplicitReturn.as.Destroy.impl.Op.bound(%addr.loc8)
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.bound: <bound method> = bound_method %no_addr.var, constants.%NoAddr.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc7: %ptr.4b8 = addr_of %no_addr.var
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.call: init %empty_tuple.type = call %NoAddr.as.Destroy.impl.Op.bound(%addr.loc7)
// CHECK:STDOUT: %c.var: ref %C = var %c.var_patt
// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %c: ref %C = bind_name c, %c.var
// CHECK:STDOUT: %C.as.Destroy.impl.Op.bound: <bound method> = bound_method %c.var, constants.%C.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc12: %ptr.019 = addr_of %c.var
// CHECK:STDOUT: %C.as.Destroy.impl.Op.call: init %empty_tuple.type = call %C.as.Destroy.impl.Op.bound(%addr.loc12)
// CHECK:STDOUT: %B.as.Destroy.impl.Op.bound: <bound method> = bound_method %b.var, constants.%B.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc11: %ptr.e79 = addr_of %b.var
// CHECK:STDOUT: %B.as.Destroy.impl.Op.call: init %empty_tuple.type = call %B.as.Destroy.impl.Op.bound(%addr.loc11)
// CHECK:STDOUT: %A.as.Destroy.impl.Op.bound: <bound method> = bound_method %a.var, constants.%A.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc10: %ptr.6db = addr_of %a.var
// CHECK:STDOUT: %A.as.Destroy.impl.Op.call: init %empty_tuple.type = call %A.as.Destroy.impl.Op.bound(%addr.loc10)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- nested_scope.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %A: type = class_type @A [concrete]
// CHECK:STDOUT: %ptr.6db: type = ptr_type %A [concrete]
// CHECK:STDOUT: %A.as.Destroy.impl.Op.type: type = fn_type @A.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %A.as.Destroy.impl.Op: %A.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %B: type = class_type @B [concrete]
// CHECK:STDOUT: %ptr.e79: type = ptr_type %B [concrete]
// CHECK:STDOUT: %B.as.Destroy.impl.Op.type: type = fn_type @B.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %B.as.Destroy.impl.Op: %B.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %ptr.019: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C.as.Destroy.impl.Op.type: type = fn_type @C.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %C.as.Destroy.impl.Op: %C.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: %NoAddr: type = class_type @NoAddr [concrete]
// CHECK:STDOUT: %pattern_type.88f: type = pattern_type %NoAddr [concrete]
// CHECK:STDOUT: %ExplicitReturn: type = class_type @ExplicitReturn [concrete]
// CHECK:STDOUT: %pattern_type.611: type = pattern_type %ExplicitReturn [concrete]
// CHECK:STDOUT: %WithAddr: type = class_type @WithAddr [concrete]
// CHECK:STDOUT: %pattern_type.f93: type = pattern_type %WithAddr [concrete]
// CHECK:STDOUT: %pattern_type.c10: type = pattern_type %A [concrete]
// CHECK:STDOUT: %pattern_type.049: type = pattern_type %B [concrete]
// CHECK:STDOUT: %true: bool = bool_literal true [concrete]
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.type: type = fn_type @NoAddr.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op: %NoAddr.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.4b8: type = ptr_type %NoAddr [concrete]
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op.type: type = fn_type @WithAddr.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op: %WithAddr.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.b4e: type = ptr_type %WithAddr [concrete]
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op.type: type = fn_type @ExplicitReturn.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op: %ExplicitReturn.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.b0a: type = ptr_type %ExplicitReturn [concrete]
// CHECK:STDOUT: %pattern_type.c48: type = pattern_type %C [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Main.NoAddr: type = import_ref Main//types, NoAddr, loaded [concrete = constants.%NoAddr]
// CHECK:STDOUT: %Main.ExplicitReturn: type = import_ref Main//types, ExplicitReturn, loaded [concrete = constants.%ExplicitReturn]
// CHECK:STDOUT: %Main.WithAddr: type = import_ref Main//types, WithAddr, loaded [concrete = constants.%WithAddr]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -229,88 +187,72 @@ fn G() { F({}); }
// CHECK:STDOUT: fn @F() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %no_addr.patt: %pattern_type.88f = binding_pattern no_addr [concrete]
// CHECK:STDOUT: %no_addr.var_patt: %pattern_type.88f = var_pattern %no_addr.patt [concrete]
// CHECK:STDOUT: %a.patt: %pattern_type.c10 = binding_pattern a [concrete]
// CHECK:STDOUT: %a.var_patt: %pattern_type.c10 = var_pattern %a.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %no_addr.var: ref %NoAddr = var %no_addr.var_patt
// CHECK:STDOUT: %NoAddr.ref.loc7: type = name_ref NoAddr, imports.%Main.NoAddr [concrete = constants.%NoAddr]
// CHECK:STDOUT: %no_addr: ref %NoAddr = bind_name no_addr, %no_addr.var
// CHECK:STDOUT: %a.var: ref %A = var %a.var_patt
// CHECK:STDOUT: %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A]
// CHECK:STDOUT: %a: ref %A = bind_name a, %a.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %explicit_return.patt: %pattern_type.611 = binding_pattern explicit_return [concrete]
// CHECK:STDOUT: %explicit_return.var_patt: %pattern_type.611 = var_pattern %explicit_return.patt [concrete]
// CHECK:STDOUT: %b.patt: %pattern_type.049 = binding_pattern b [concrete]
// CHECK:STDOUT: %b.var_patt: %pattern_type.049 = var_pattern %b.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %explicit_return.var: ref %ExplicitReturn = var %explicit_return.var_patt
// CHECK:STDOUT: %ExplicitReturn.ref: type = name_ref ExplicitReturn, imports.%Main.ExplicitReturn [concrete = constants.%ExplicitReturn]
// CHECK:STDOUT: %explicit_return: ref %ExplicitReturn = bind_name explicit_return, %explicit_return.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %with_addr.patt: %pattern_type.f93 = binding_pattern with_addr [concrete]
// CHECK:STDOUT: %with_addr.var_patt: %pattern_type.f93 = var_pattern %with_addr.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %with_addr.var: ref %WithAddr = var %with_addr.var_patt
// CHECK:STDOUT: %WithAddr.ref: type = name_ref WithAddr, imports.%Main.WithAddr [concrete = constants.%WithAddr]
// CHECK:STDOUT: %with_addr: ref %WithAddr = bind_name with_addr, %with_addr.var
// CHECK:STDOUT: %b.var: ref %B = var %b.var_patt
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
// CHECK:STDOUT: %b: ref %B = bind_name b, %b.var
// CHECK:STDOUT: %true: bool = bool_literal true [concrete = constants.%true]
// CHECK:STDOUT: if %true br !if.then else br !if.else
// CHECK:STDOUT:
// CHECK:STDOUT: !if.then:
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %in_scope.patt: %pattern_type.88f = binding_pattern in_scope [concrete]
// CHECK:STDOUT: %in_scope.var_patt: %pattern_type.88f = var_pattern %in_scope.patt [concrete]
// CHECK:STDOUT: %c.patt: %pattern_type.c48 = binding_pattern c [concrete]
// CHECK:STDOUT: %c.var_patt: %pattern_type.c48 = var_pattern %c.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %in_scope.var: ref %NoAddr = var %in_scope.var_patt
// CHECK:STDOUT: %NoAddr.ref.loc11: type = name_ref NoAddr, imports.%Main.NoAddr [concrete = constants.%NoAddr]
// CHECK:STDOUT: %in_scope: ref %NoAddr = bind_name in_scope, %in_scope.var
// CHECK:STDOUT: %c.var: ref %C = var %c.var_patt
// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %c: ref %C = bind_name c, %c.var
// CHECK:STDOUT: br !if.else
// CHECK:STDOUT:
// CHECK:STDOUT: !if.else:
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.bound.loc11: <bound method> = bound_method %in_scope.var, constants.%NoAddr.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc11: %ptr.4b8 = addr_of %in_scope.var
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.call.loc11: init %empty_tuple.type = call %NoAddr.as.Destroy.impl.Op.bound.loc11(%addr.loc11)
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op.bound: <bound method> = bound_method %with_addr.var, constants.%WithAddr.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc9: %ptr.b4e = addr_of %with_addr.var
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op.call: init %empty_tuple.type = call %WithAddr.as.Destroy.impl.Op.bound(%addr.loc9)
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op.bound: <bound method> = bound_method %explicit_return.var, constants.%ExplicitReturn.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc8: %ptr.b0a = addr_of %explicit_return.var
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op.call: init %empty_tuple.type = call %ExplicitReturn.as.Destroy.impl.Op.bound(%addr.loc8)
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.bound.loc7: <bound method> = bound_method %no_addr.var, constants.%NoAddr.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc7: %ptr.4b8 = addr_of %no_addr.var
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.call.loc7: init %empty_tuple.type = call %NoAddr.as.Destroy.impl.Op.bound.loc7(%addr.loc7)
// CHECK:STDOUT: %C.as.Destroy.impl.Op.bound: <bound method> = bound_method %c.var, constants.%C.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc13: %ptr.019 = addr_of %c.var
// CHECK:STDOUT: %C.as.Destroy.impl.Op.call: init %empty_tuple.type = call %C.as.Destroy.impl.Op.bound(%addr.loc13)
// CHECK:STDOUT: %B.as.Destroy.impl.Op.bound: <bound method> = bound_method %b.var, constants.%B.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc11: %ptr.e79 = addr_of %b.var
// CHECK:STDOUT: %B.as.Destroy.impl.Op.call: init %empty_tuple.type = call %B.as.Destroy.impl.Op.bound(%addr.loc11)
// CHECK:STDOUT: %A.as.Destroy.impl.Op.bound: <bound method> = bound_method %a.var, constants.%A.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc10: %ptr.6db = addr_of %a.var
// CHECK:STDOUT: %A.as.Destroy.impl.Op.call: init %empty_tuple.type = call %A.as.Destroy.impl.Op.bound(%addr.loc10)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- temp.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %A: type = class_type @A [concrete]
// CHECK:STDOUT: %A.Make.type: type = fn_type @A.Make [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %A.Make: %A.Make.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.6db: type = ptr_type %A [concrete]
// CHECK:STDOUT: %A.as.Destroy.impl.Op.type: type = fn_type @A.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %A.as.Destroy.impl.Op: %A.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %B: type = class_type @B [concrete]
// CHECK:STDOUT: %B.Make.type: type = fn_type @B.Make [concrete]
// CHECK:STDOUT: %B.Make: %B.Make.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.e79: type = ptr_type %B [concrete]
// CHECK:STDOUT: %B.as.Destroy.impl.Op.type: type = fn_type @B.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %B.as.Destroy.impl.Op: %B.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %C.Make.type: type = fn_type @C.Make [concrete]
// CHECK:STDOUT: %C.Make: %C.Make.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.019: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C.as.Destroy.impl.Op.type: type = fn_type @C.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %C.as.Destroy.impl.Op: %C.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: %NoAddr: type = class_type @NoAddr [concrete]
// CHECK:STDOUT: %NoAddr.Make.type: type = fn_type @NoAddr.Make [concrete]
// CHECK:STDOUT: %NoAddr.Make: %NoAddr.Make.type = struct_value () [concrete]
// CHECK:STDOUT: %ExplicitReturn: type = class_type @ExplicitReturn [concrete]
// CHECK:STDOUT: %ExplicitReturn.Make.type: type = fn_type @ExplicitReturn.Make [concrete]
// CHECK:STDOUT: %ExplicitReturn.Make: %ExplicitReturn.Make.type = struct_value () [concrete]
// CHECK:STDOUT: %WithAddr: type = class_type @WithAddr [concrete]
// CHECK:STDOUT: %WithAddr.Make.type: type = fn_type @WithAddr.Make [concrete]
// CHECK:STDOUT: %WithAddr.Make: %WithAddr.Make.type = struct_value () [concrete]
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op.type: type = fn_type @WithAddr.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op: %WithAddr.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.b4e: type = ptr_type %WithAddr [concrete]
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op.type: type = fn_type @ExplicitReturn.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op: %ExplicitReturn.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.b0a: type = ptr_type %ExplicitReturn [concrete]
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.type: type = fn_type @NoAddr.as.Destroy.impl.Op [concrete]
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op: %NoAddr.as.Destroy.impl.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.4b8: type = ptr_type %NoAddr [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Main.NoAddr: type = import_ref Main//types, NoAddr, loaded [concrete = constants.%NoAddr]
// CHECK:STDOUT: %Main.ExplicitReturn: type = import_ref Main//types, ExplicitReturn, loaded [concrete = constants.%ExplicitReturn]
// CHECK:STDOUT: %Main.WithAddr: type = import_ref Main//types, WithAddr, loaded [concrete = constants.%WithAddr]
// CHECK:STDOUT: %Main.import_ref.784: %NoAddr.Make.type = import_ref Main//types, loc5_22, loaded [concrete = constants.%NoAddr.Make]
// CHECK:STDOUT: %Main.import_ref.8e0: %ExplicitReturn.Make.type = import_ref Main//types, loc10_30, loaded [concrete = constants.%ExplicitReturn.Make]
// CHECK:STDOUT: %Main.import_ref.974: %WithAddr.Make.type = import_ref Main//types, loc15_24, loaded [concrete = constants.%WithAddr.Make]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -319,30 +261,30 @@ fn G() { F({}); }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %NoAddr.ref: type = name_ref NoAddr, imports.%Main.NoAddr [concrete = constants.%NoAddr]
// CHECK:STDOUT: %Make.ref.loc9: %NoAddr.Make.type = name_ref Make, imports.%Main.import_ref.784 [concrete = constants.%NoAddr.Make]
// CHECK:STDOUT: %.loc9_15.1: ref %NoAddr = temporary_storage
// CHECK:STDOUT: %NoAddr.Make.call: init %NoAddr = call %Make.ref.loc9() to %.loc9_15.1
// CHECK:STDOUT: %.loc9_15.2: ref %NoAddr = temporary %.loc9_15.1, %NoAddr.Make.call
// CHECK:STDOUT: %ExplicitReturn.ref: type = name_ref ExplicitReturn, imports.%Main.ExplicitReturn [concrete = constants.%ExplicitReturn]
// CHECK:STDOUT: %Make.ref.loc10: %ExplicitReturn.Make.type = name_ref Make, imports.%Main.import_ref.8e0 [concrete = constants.%ExplicitReturn.Make]
// CHECK:STDOUT: %.loc10_23.1: ref %ExplicitReturn = temporary_storage
// CHECK:STDOUT: %ExplicitReturn.Make.call: init %ExplicitReturn = call %Make.ref.loc10() to %.loc10_23.1
// CHECK:STDOUT: %.loc10_23.2: ref %ExplicitReturn = temporary %.loc10_23.1, %ExplicitReturn.Make.call
// CHECK:STDOUT: %WithAddr.ref: type = name_ref WithAddr, imports.%Main.WithAddr [concrete = constants.%WithAddr]
// CHECK:STDOUT: %Make.ref.loc11: %WithAddr.Make.type = name_ref Make, imports.%Main.import_ref.974 [concrete = constants.%WithAddr.Make]
// CHECK:STDOUT: %.loc11_17.1: ref %WithAddr = temporary_storage
// CHECK:STDOUT: %WithAddr.Make.call: init %WithAddr = call %Make.ref.loc11() to %.loc11_17.1
// CHECK:STDOUT: %.loc11_17.2: ref %WithAddr = temporary %.loc11_17.1, %WithAddr.Make.call
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc11_17.2, constants.%WithAddr.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc11: %ptr.b4e = addr_of %.loc11_17.2
// CHECK:STDOUT: %WithAddr.as.Destroy.impl.Op.call: init %empty_tuple.type = call %WithAddr.as.Destroy.impl.Op.bound(%addr.loc11)
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc10_23.2, constants.%ExplicitReturn.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc10: %ptr.b0a = addr_of %.loc10_23.2
// CHECK:STDOUT: %ExplicitReturn.as.Destroy.impl.Op.call: init %empty_tuple.type = call %ExplicitReturn.as.Destroy.impl.Op.bound(%addr.loc10)
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc9_15.2, constants.%NoAddr.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc9: %ptr.4b8 = addr_of %.loc9_15.2
// CHECK:STDOUT: %NoAddr.as.Destroy.impl.Op.call: init %empty_tuple.type = call %NoAddr.as.Destroy.impl.Op.bound(%addr.loc9)
// CHECK:STDOUT: %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A]
// CHECK:STDOUT: %Make.ref.loc12: %A.Make.type = name_ref Make, @A.%A.Make.decl [concrete = constants.%A.Make]
// CHECK:STDOUT: %.loc12_10.1: ref %A = temporary_storage
// CHECK:STDOUT: %A.Make.call: init %A = call %Make.ref.loc12() to %.loc12_10.1
// CHECK:STDOUT: %.loc12_10.2: ref %A = temporary %.loc12_10.1, %A.Make.call
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
// CHECK:STDOUT: %Make.ref.loc13: %B.Make.type = name_ref Make, @B.%B.Make.decl [concrete = constants.%B.Make]
// CHECK:STDOUT: %.loc13_10.1: ref %B = temporary_storage
// CHECK:STDOUT: %B.Make.call: init %B = call %Make.ref.loc13() to %.loc13_10.1
// CHECK:STDOUT: %.loc13_10.2: ref %B = temporary %.loc13_10.1, %B.Make.call
// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %Make.ref.loc14: %C.Make.type = name_ref Make, @C.%C.Make.decl [concrete = constants.%C.Make]
// CHECK:STDOUT: %.loc14_10.1: ref %C = temporary_storage
// CHECK:STDOUT: %C.Make.call: init %C = call %Make.ref.loc14() to %.loc14_10.1
// CHECK:STDOUT: %.loc14_10.2: ref %C = temporary %.loc14_10.1, %C.Make.call
// CHECK:STDOUT: %C.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc14_10.2, constants.%C.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc14: %ptr.019 = addr_of %.loc14_10.2
// CHECK:STDOUT: %C.as.Destroy.impl.Op.call: init %empty_tuple.type = call %C.as.Destroy.impl.Op.bound(%addr.loc14)
// CHECK:STDOUT: %B.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc13_10.2, constants.%B.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc13: %ptr.e79 = addr_of %.loc13_10.2
// CHECK:STDOUT: %B.as.Destroy.impl.Op.call: init %empty_tuple.type = call %B.as.Destroy.impl.Op.bound(%addr.loc13)
// CHECK:STDOUT: %A.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc12_10.2, constants.%A.as.Destroy.impl.Op
// CHECK:STDOUT: %addr.loc12: %ptr.6db = addr_of %.loc12_10.2
// CHECK:STDOUT: %A.as.Destroy.impl.Op.call: init %empty_tuple.type = call %A.as.Destroy.impl.Op.bound(%addr.loc12)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
-219
View File
@@ -1,219 +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
//
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/destroy.carbon
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/destroy_decl.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/destroy_decl.carbon
// --- self.carbon
library "[[@TEST_NAME]]";
class C {
fn destroy[self: Self]();
}
// --- declare_impl.carbon
library "[[@TEST_NAME]]";
class C {
impl as Core.Destroy;
}
// --- fail_define_impl.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_define_impl.carbon:[[@LINE+3]]:1: error: redefinition of `impl Self as Core.Destroy` [ImplRedefinition]
// CHECK:STDERR: class C {
// CHECK:STDERR: ^~~~~~~~~
class C {
// CHECK:STDERR: fail_define_impl.carbon:[[@LINE+4]]:3: note: previous definition was here [ImplPreviousDefinition]
// CHECK:STDERR: impl as Core.Destroy {
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
impl as Core.Destroy {
fn Op[addr self: Self*]() {}
}
}
// --- addr_self.carbon
library "[[@TEST_NAME]]";
class C {
fn destroy[addr self: Self*]();
}
// --- explicit_return.carbon
library "[[@TEST_NAME]]";
class C {
fn destroy[self: Self]() -> ();
}
// --- fail_class_function.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_class_function.carbon:[[@LINE+4]]:3: error: missing implicit `self` parameter [DestroyFunctionMissingSelf]
// CHECK:STDERR: fn destroy();
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
fn destroy();
}
// --- fail_extra_implicit_params_second.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_extra_implicit_params_second.carbon:[[@LINE+4]]:26: error: unexpected implicit parameter [DestroyFunctionUnexpectedImplicitParam]
// CHECK:STDERR: fn destroy[self: Self, T:! type]();
// CHECK:STDERR: ^
// CHECK:STDERR:
fn destroy[self: Self, T:! type]();
}
// --- fail_extra_implicit_params_first.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_extra_implicit_params_first.carbon:[[@LINE+4]]:14: error: unexpected implicit parameter [DestroyFunctionUnexpectedImplicitParam]
// CHECK:STDERR: fn destroy[T:! type, self: Self]();
// CHECK:STDERR: ^
// CHECK:STDERR:
fn destroy[T:! type, self: Self]();
}
// --- fail_positional_params.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_positional_params.carbon:[[@LINE+4]]:3: error: missing empty explicit parameter list [DestroyFunctionPositionalParams]
// CHECK:STDERR: fn destroy[self: Self];
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn destroy[self: Self];
}
// --- fail_explicit_params.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_explicit_params.carbon:[[@LINE+4]]:26: error: unexpected parameter [DestroyFunctionNonEmptyExplicitParams]
// CHECK:STDERR: fn destroy[self: Self](x: ());
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
fn destroy[self: Self](x: ());
}
// --- fail_return_type.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_return_type.carbon:[[@LINE+4]]:28: error: incorrect return type; must be unspecified or `()` [DestroyFunctionIncorrectReturnType]
// CHECK:STDERR: fn destroy[self: Self]() -> {};
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
fn destroy[self: Self]() -> {};
}
// --- fail_out_of_line_missing_params.carbon
library "[[@TEST_NAME]]";
class C {
fn destroy[self: Self]();
}
// CHECK:STDERR: fail_out_of_line_missing_params.carbon:[[@LINE+7]]:1: error: redeclaration differs because of missing implicit parameter list [RedeclParamListDiffers]
// CHECK:STDERR: fn C.destroy {}
// CHECK:STDERR: ^~~~~~~~~~~~~~
// CHECK:STDERR: fail_out_of_line_missing_params.carbon:[[@LINE-6]]:3: note: previously declared with implicit parameter list [RedeclParamListPrevious]
// CHECK:STDERR: fn destroy[self: Self]();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn C.destroy {}
// --- fail_destroy_in_file_scope.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_destroy_in_file_scope.carbon:[[@LINE+4]]:1: error: declaring `fn destroy` in non-class scope [DestroyFunctionOutsideClass]
// CHECK:STDERR: fn destroy[self: ()]();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn destroy[self: ()]();
// --- fail_destroy_in_namespace_scope.carbon
library "[[@TEST_NAME]]";
namespace NS;
// CHECK:STDERR: fail_destroy_in_namespace_scope.carbon:[[@LINE+4]]:1: error: declaring `fn destroy` in non-class scope [DestroyFunctionOutsideClass]
// CHECK:STDERR: fn NS.destroy();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn NS.destroy();
// --- fail_invalid_qualifier_with_params.carbon
library "[[@TEST_NAME]]";
class C {
fn destroy[self: Self]();
}
// CHECK:STDERR: fail_invalid_qualifier_with_params.carbon:[[@LINE+7]]:6: error: name qualifiers are only allowed for entities that provide a scope [QualifiedNameInNonScope]
// CHECK:STDERR: fn C.destroy[self: Self]().Foo() {}
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR: fail_invalid_qualifier_with_params.carbon:[[@LINE-6]]:3: note: referenced non-scope entity declared here [QualifiedNameNonScopeEntity]
// CHECK:STDERR: fn destroy[self: Self]();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn C.destroy[self: Self]().Foo() {}
// --- fail_invalid_qualifier_no_params.carbon
library "[[@TEST_NAME]]";
class C {
fn destroy[self: Self]();
}
// CHECK:STDERR: fail_invalid_qualifier_no_params.carbon:[[@LINE+7]]:6: error: name qualifiers are only allowed for entities that provide a scope [QualifiedNameInNonScope]
// CHECK:STDERR: fn C.destroy.Foo() {}
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR: fail_invalid_qualifier_no_params.carbon:[[@LINE-6]]:3: note: referenced non-scope entity declared here [QualifiedNameNonScopeEntity]
// CHECK:STDERR: fn destroy[self: Self]();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn C.destroy.Foo() {}
// --- fail_return_type_after_no_params.carbon
library "[[@TEST_NAME]]";
// Return type handling special-cases the "no params" case.
class C {
// CHECK:STDERR: fail_return_type_after_no_params.carbon:[[@LINE+4]]:3: error: missing implicit `self` parameter [DestroyFunctionMissingSelf]
// CHECK:STDERR: fn destroy -> ();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn destroy -> ();
}
@@ -268,13 +268,6 @@ CARBON_DIAGNOSTIC_KIND(InvalidBuiltinSignature)
CARBON_DIAGNOSTIC_KIND(ThunkSignature)
CARBON_DIAGNOSTIC_KIND(ThunkCallee)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionOutsideClass)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionMissingSelf)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionUnexpectedImplicitParam)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionPositionalParams)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionNonEmptyExplicitParams)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionIncorrectReturnType)
// Class checking.
CARBON_DIAGNOSTIC_KIND(AdaptDeclRepeated)
CARBON_DIAGNOSTIC_KIND(AdaptWithBase)
-1
View File
@@ -181,7 +181,6 @@ CARBON_KEYWORD_TOKEN(Const, "const")
CARBON_KEYWORD_TOKEN(Continue, "continue")
CARBON_KEYWORD_TOKEN(Core, "Core")
CARBON_KEYWORD_TOKEN(Default, "default")
CARBON_KEYWORD_TOKEN(Destroy, "destroy")
CARBON_KEYWORD_TOKEN(Else, "else")
CARBON_KEYWORD_TOKEN(Extend, "extend")
CARBON_KEYWORD_TOKEN(Extern, "extern")
@@ -16,7 +16,7 @@
library "[[@TEST_NAME]]";
class HasDestroy {
// TODO: Use `fn destroy` instead once lowering supports it.
// TODO: Change for `Destruction`+`Destroy`.
impl as Core.Destroy {
fn Op[self: Self]();
}
@@ -55,13 +55,6 @@ auto HandleDeclNameAndParams(Context& context) -> void {
return;
}
if (auto keyword = context.ConsumeIf(Lex::TokenKind::Destroy)) {
HandleName(context, state, *keyword, NodeKind::KeywordNameNotBeforeParams,
NodeKind::KeywordNameQualifierWithoutParams,
NodeKind::KeywordNameBeforeParams);
return;
}
Lex::TokenIndex token = *context.position();
if (context.tokens().GetKind(token) == Lex::TokenKind::FileEnd) {
// The end of file is an unhelpful diagnostic location. Instead, use the
@@ -100,11 +93,10 @@ auto HandleDeclNameAndParamsAfterParams(Context& context) -> void {
auto state = context.PopState();
if (auto period = context.ConsumeIf(Lex::TokenKind::Period)) {
auto start_kind = context.tree().node_kind(NodeId(state.subtree_start));
auto node_kind = start_kind == NodeKind::IdentifierNameBeforeParams
? NodeKind::IdentifierNameQualifierWithParams
: NodeKind::KeywordNameQualifierWithParams;
context.AddNode(node_kind, *period, state.has_error);
CARBON_CHECK(context.tree().node_kind(NodeId(state.subtree_start)) ==
NodeKind::IdentifierNameBeforeParams);
context.AddNode(NodeKind::IdentifierNameQualifierWithParams, *period,
state.has_error);
context.PushState(StateKind::DeclNameAndParams);
}
}
-5
View File
@@ -98,9 +98,6 @@ CARBON_PARSE_NODE_KIND(EmptyDecl)
CARBON_PARSE_NODE_KIND(IdentifierNameNotBeforeParams)
CARBON_PARSE_NODE_KIND(IdentifierNameBeforeParams)
CARBON_PARSE_NODE_KIND(KeywordNameNotBeforeParams)
CARBON_PARSE_NODE_KIND(KeywordNameBeforeParams)
CARBON_PARSE_NODE_KIND(IdentifierNameExpr)
CARBON_PARSE_NODE_KIND(SelfValueName)
@@ -133,8 +130,6 @@ CARBON_PARSE_NODE_KIND(InlineImportBody)
CARBON_PARSE_NODE_KIND(IdentifierNameQualifierWithParams)
CARBON_PARSE_NODE_KIND(IdentifierNameQualifierWithoutParams)
CARBON_PARSE_NODE_KIND(KeywordNameQualifierWithParams)
CARBON_PARSE_NODE_KIND(KeywordNameQualifierWithoutParams)
CARBON_PARSE_NODE_KIND(ExportIntroducer)
CARBON_PARSE_NODE_KIND(ExportDecl)
-86
View File
@@ -36,26 +36,6 @@ fn foo(a: i32, b: i32);
fn foo() -> u32;
// --- keyword.carbon
fn destroy() {}
// --- keyword_no_params.carbon
fn destroy {}
// --- keyword_in_qualified.carbon
fn MyClass.destroy() {}
// --- keyword_decl_qualified_no_params.carbon
fn destroy.Foo() {}
// --- keyword_decl_qualified_with_params.carbon
fn destroy[self: Self]().Foo() {}
// --- impl_fn.carbon
override fn F();
@@ -276,72 +256,6 @@ fn (a tokens c d e f g h i j k l m n o p q r s t u v w x y z);
// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 7},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: keyword.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'KeywordNameBeforeParams', text: 'destroy'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 6},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: keyword_no_params.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'KeywordNameNotBeforeParams', text: 'destroy'},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 3},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 4},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: keyword_in_qualified.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'MyClass'},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'KeywordNameBeforeParams', text: 'destroy'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 7},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: keyword_decl_qualified_no_params.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'KeywordNameNotBeforeParams', text: 'destroy'},
// CHECK:STDOUT: {kind: 'KeywordNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 7},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: keyword_decl_qualified_with_params.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'KeywordNameBeforeParams', text: 'destroy'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'SelfValueName', text: 'self'},
// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'},
// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'KeywordNameQualifierWithParams', text: '.', subtree_size: 9},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 14},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 15},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: impl_fn.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
+2 -26
View File
@@ -132,18 +132,12 @@ using EmptyDecl =
using IdentifierNameBeforeParams =
LeafNode<NodeKind::IdentifierNameBeforeParams, Lex::IdentifierTokenIndex,
NodeCategory::MemberName | NodeCategory::NonExprName>;
using KeywordNameBeforeParams =
LeafNode<NodeKind::KeywordNameBeforeParams, Lex::TokenIndex,
NodeCategory::MemberName | NodeCategory::NonExprName>;
// A name in a non-expression context, such as a declaration, that is known
// to not be followed by parameters.
using IdentifierNameNotBeforeParams =
LeafNode<NodeKind::IdentifierNameNotBeforeParams, Lex::IdentifierTokenIndex,
NodeCategory::MemberName | NodeCategory::NonExprName>;
using KeywordNameNotBeforeParams =
LeafNode<NodeKind::KeywordNameNotBeforeParams, Lex::TokenIndex,
NodeCategory::MemberName | NodeCategory::NonExprName>;
// A name in an expression context.
using IdentifierNameExpr =
@@ -184,15 +178,6 @@ struct IdentifierNameQualifierWithParams {
std::optional<ExplicitParamListId> params;
Lex::PeriodTokenIndex token;
};
struct KeywordNameQualifierWithParams {
static constexpr auto Kind = NodeKind::KeywordNameQualifierWithParams.Define(
{.bracketed_by = KeywordNameBeforeParams::Kind});
KeywordNameBeforeParamsId name;
std::optional<ImplicitParamListId> implicit_params;
std::optional<ExplicitParamListId> params;
Lex::PeriodTokenIndex token;
};
// A name qualifier without parameters, such as `A.`.
struct IdentifierNameQualifierWithoutParams {
@@ -203,21 +188,12 @@ struct IdentifierNameQualifierWithoutParams {
IdentifierNameNotBeforeParamsId name;
Lex::PeriodTokenIndex token;
};
struct KeywordNameQualifierWithoutParams {
static constexpr auto Kind =
NodeKind::KeywordNameQualifierWithoutParams.Define(
{.bracketed_by = KeywordNameNotBeforeParams::Kind});
KeywordNameNotBeforeParamsId name;
Lex::PeriodTokenIndex token;
};
// A complete name in a declaration: `A.C(T:! type).F(n: i32)`.
// Note that this includes the parameters of the entity itself.
struct DeclName {
llvm::SmallVector<NodeIdOneOf<
IdentifierNameQualifierWithParams, IdentifierNameQualifierWithoutParams,
KeywordNameQualifierWithParams, KeywordNameQualifierWithoutParams>>
llvm::SmallVector<NodeIdOneOf<IdentifierNameQualifierWithParams,
IdentifierNameQualifierWithoutParams>>
qualifiers;
AnyNonExprNameId name;
std::optional<ImplicitParamListId> implicit_params;
+2 -2
View File
@@ -293,8 +293,8 @@ NodeIdForKind error: wrong kind IdentifierNameBeforeParams, expected ImplicitPar
Optional [^:]*: missing
NodeIdInCategory NonExprName: kind IdentifierNameBeforeParams consumed
Vector: begin
NodeIdOneOf IdentifierNameQualifierWithParams or IdentifierNameQualifierWithoutParams or KeywordNameQualifierWithParams or KeywordNameQualifierWithoutParams: IdentifierNameQualifierWithoutParams consumed
NodeIdOneOf error: wrong kind AbstractModifier, expected IdentifierNameQualifierWithParams or IdentifierNameQualifierWithoutParams or KeywordNameQualifierWithParams or KeywordNameQualifierWithoutParams
NodeIdOneOf IdentifierNameQualifierWithParams or IdentifierNameQualifierWithoutParams: IdentifierNameQualifierWithoutParams consumed
NodeIdOneOf error: wrong kind AbstractModifier, expected IdentifierNameQualifierWithParams or IdentifierNameQualifierWithoutParams
Vector: end
Aggregate [^:]*: success
Vector: begin
-2
View File
@@ -566,8 +566,6 @@ constexpr FloatKind FloatKind::PPCFloat128 = FloatKind(6);
X(ChoiceDiscriminant) \
/* The name of the package `Core`. */ \
X(Core) \
/* The name of `destroy`. */ \
X(Destroy) \
/* The name of `package`. */ \
X(PackageNamespace) \
/* The name of `.Self`. */ \
-2
View File
@@ -23,8 +23,6 @@ static auto GetSpecialName(NameId name_id, bool for_ir) -> llvm::StringRef {
return "discriminant";
case NameId::SpecialNameId::Core:
return "Core";
case NameId::SpecialNameId::Destroy:
return "destroy";
case NameId::SpecialNameId::PackageNamespace:
return "package";
case NameId::SpecialNameId::PeriodSelf:
@@ -12,8 +12,8 @@ package Core library "prelude/parts/destroy";
import library "prelude/parts/bool";
import library "prelude/parts/int_literal";
// Object destruction, including running `fn destroy()`. Note this is distinct
// from memory deallocation.
// Destroys objects. Note this is distinct from memory deallocation.
// TODO: Switch to `Destructor`+`Destroy` model.
interface Destroy {
fn Op[addr self: Self*]();
}