Support ref tags on arguments to ref params (#6312)

The issue of whether/how to include `ref` tags in the textual and
in-memory SemIR (see discussion
[here](https://discord.com/channels/655572317891461132/655578254970716160/1431316355742961805))
is left as future work.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
Geoff Romer
2025-11-11 20:30:19 +00:00
committed by GitHub
co-authored by Richard Smith
parent b36f85c2a5
commit 43ffd721a4
39 changed files with 798 additions and 337 deletions
+2 -2
View File
@@ -300,8 +300,6 @@ auto PerformCallToFunction(Context& context, SemIR::LocId loc_id,
}
case SemIR::Function::SpecialFunctionKind::HasCppThunk: {
// This recurses back into `PerformCall`. However, we never form a C++
// thunk to a C++ thunk, so we only recurse once.
return PerformCppThunkCall(context, loc_id, callee_function.function_id,
context.inst_blocks().Get(converted_args_id),
callee.cpp_thunk_decl_id());
@@ -359,6 +357,7 @@ auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id,
return SemIR::ErrorInst::InstId;
}
case CARBON_KIND(SemIR::CalleeFunction fn): {
context.ref_tags().Insert(fn.self_id, Context::RefTag::NotRequired);
return PerformCallToFunction(context, loc_id, callee_id, fn, arg_ids);
}
case CARBON_KIND(SemIR::CalleeNonFunction _): {
@@ -366,6 +365,7 @@ auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id,
}
case CARBON_KIND(SemIR::CalleeCppOverloadSet overload): {
context.ref_tags().Insert(overload.self_id, Context::RefTag::NotRequired);
return PerformCallToCppFunction(context, loc_id,
overload.cpp_overload_set_id,
overload.self_id, arg_ids);
+14
View File
@@ -8,6 +8,7 @@
#include <utility>
#include "common/check.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/check/deferred_definition_worklist.h"
#include "toolchain/sem_ir/ids.h"
@@ -77,6 +78,19 @@ auto Context::VerifyOnFinish() const -> void {
CARBON_FATAL("{0}Built invalid semantics IR: {1}\n", sem_ir_,
verify.error());
}
if (!sem_ir_->has_errors()) {
auto ref_tags_needed = sem_ir_->CollectRefTagsNeeded();
ref_tags_.ForEach([&ref_tags_needed](SemIR::InstId inst_id, RefTag kind) {
CARBON_CHECK(
ref_tags_needed.Erase(inst_id) || kind == RefTag::NotRequired,
"Inst has unnecessary `ref` tag: {0}", inst_id);
});
ref_tags_needed.ForEach([this](SemIR::InstId inst_id) {
CARBON_FATAL("Inst missing `ref` tag: {0}", insts().Get(inst_id));
});
}
#endif
}
+14
View File
@@ -193,6 +193,13 @@ class Context {
return var_storage_map_;
}
enum class RefTag { Present, NotRequired };
auto ref_tags() -> Map<SemIR::InstId, RefTag>& { return ref_tags_; }
auto ref_tags() const -> const Map<SemIR::InstId, RefTag>& {
return ref_tags_;
}
// During Choice typechecking, each alternative turns into a name binding on
// the Choice type, but this can't be done until the full Choice type is
// known. This represents each binding to be done at the end of checking the
@@ -445,6 +452,13 @@ class Context {
// processing the enclosing full-pattern.
Map<SemIR::InstId, SemIR::InstId> var_storage_map_;
// Insts in this map are syntactically permitted to be bound to a reference
// parameter, either because they've been explicitly tagged with `ref` in the
// source code, or because they appear in a position where that tag is not
// required, such as an operator operand (the RefTag value indicates which
// of those is the case).
Map<SemIR::InstId, RefTag> ref_tags_;
// Each alternative in a Choice gets an entry here, they are stored in
// declaration order. The vector is consumed and emptied at the end of the
// Choice definition.
+47 -1
View File
@@ -738,6 +738,10 @@ static auto IsValidExprCategoryForConversionTarget(
category == SemIR::ExprCategory::DurableRef ||
category == SemIR::ExprCategory::EphemeralRef ||
category == SemIR::ExprCategory::Initializing;
case ConversionTarget::RefParam:
return category == SemIR::ExprCategory::DurableRef ||
category == SemIR::ExprCategory::EphemeralRef ||
category == SemIR::ExprCategory::Initializing;
case ConversionTarget::DurableRef:
return category == SemIR::ExprCategory::DurableRef;
case ConversionTarget::CppThunkRef:
@@ -1381,6 +1385,28 @@ auto PerformAction(Context& context, SemIR::LocId loc_id,
action.target_type_inst_id)});
}
// Diagnoses a missing or unnecessary `ref` tag when converting `expr_id` to
// `target`, and returns whether a `ref` tag is present.
static auto CheckRefTag(Context& context, SemIR::InstId expr_id,
ConversionTarget target) -> bool {
if (auto lookup_result = context.ref_tags().Lookup(expr_id)) {
if (lookup_result.value() == Context::RefTag::Present &&
target.kind != ConversionTarget::RefParam) {
CARBON_DIAGNOSTIC(RefTagNoRefParam, Error,
"`ref` tag is not an argument to a `ref` parameter");
context.emitter().Emit(expr_id, RefTagNoRefParam);
}
return true;
} else {
if (target.kind == ConversionTarget::RefParam) {
CARBON_DIAGNOSTIC(RefParamNoRefTag, Error,
"argument to `ref` parameter not marked with `ref`");
context.emitter().Emit(expr_id, RefParamNoRefTag);
}
return false;
}
}
auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
ConversionTarget target, SemIR::ClassType* vtable_class_type)
-> SemIR::InstId {
@@ -1406,6 +1432,8 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
return SemIR::ErrorInst::InstId;
}
bool has_ref_tag = CheckRefTag(context, expr_id, target);
// We can only perform initialization for complete, non-abstract types. Note
// that `RequireConcreteType` returns true for facet types, since their
// representation is fixed. This allows us to support using the `Self` of an
@@ -1538,6 +1566,9 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
{.type_id = target.type_id,
.original_id = orig_expr_id,
.result_id = expr_id});
if (has_ref_tag) {
context.ref_tags().Insert(expr_id, Context::RefTag::NotRequired);
}
}
// For `as`, don't perform any value category conversions. In particular, an
@@ -1592,7 +1623,8 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
// If a reference expression is an acceptable result, we're done.
if (target.kind == ConversionTarget::ValueOrRef ||
target.kind == ConversionTarget::Discarded ||
target.kind == ConversionTarget::CppThunkRef) {
target.kind == ConversionTarget::CppThunkRef ||
target.kind == ConversionTarget::RefParam) {
break;
}
@@ -1617,6 +1649,20 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
}
return SemIR::ErrorInst::InstId;
}
if (target.kind == ConversionTarget::RefParam) {
// Don't diagnose a non-reference scrutinee if it has a user-written
// `ref` tag, because that's diagnosed in `CheckRefTag`.
if (target.diagnose) {
if (auto lookup_result = context.ref_tags().Lookup(expr_id);
!lookup_result ||
lookup_result.value() != Context::RefTag::Present) {
CARBON_DIAGNOSTIC(ValueForRefParam, Error,
"value expression passed to reference parameter");
context.emitter().Emit(loc_id, ValueForRefParam);
}
}
return SemIR::ErrorInst::InstId;
}
// When initializing from a value, perform a copy.
if (target.is_initializer()) {
+5
View File
@@ -21,6 +21,11 @@ struct ConversionTarget {
ValueOrRef,
// Convert to a durable reference of type `type_id`.
DurableRef,
// Convert to a reference, suitable for binding to a reference parameter.
// This allows both durable and ephemeral references. The restriction that
// only a `ref self` parameter can bind to an ephemeral reference is
// enforced separately when handling `ref` tags on call arguments.
RefParam,
// Convert to a reference of type `type_id`, for use as the argument to a
// C++ thunk.
CppThunkRef,
+16 -6
View File
@@ -5,6 +5,8 @@
#include "toolchain/check/call.h"
#include "toolchain/check/context.h"
#include "toolchain/check/handle.h"
#include "toolchain/check/inst.h"
#include "toolchain/sem_ir/expr_info.h"
#include "toolchain/sem_ir/inst.h"
namespace Carbon::Check {
@@ -16,12 +18,6 @@ auto HandleParseNode(Context& context, Parse::CallExprStartId node_id) -> bool {
return true;
}
auto HandleParseNode(Context& context, Parse::CallExprCommaId /*node_id*/)
-> bool {
context.param_and_arg_refs_stack().ApplyComma();
return true;
}
auto HandleParseNode(Context& context, Parse::CallExprId node_id) -> bool {
// Process the final explicit call argument now, but leave the arguments
// block on the stack until the end of this function.
@@ -37,4 +33,18 @@ auto HandleParseNode(Context& context, Parse::CallExprId node_id) -> bool {
return true;
}
auto HandleParseNode(Context& context, Parse::RefTagId node_id) -> bool {
auto expr_id = context.node_stack().Peek<Parse::NodeCategory::Expr>();
if (SemIR::GetExprCategory(context.sem_ir(), expr_id) !=
SemIR::ExprCategory::DurableRef) {
CARBON_DIAGNOSTIC(
RefTagNotDurableRef, Error,
"expression tagged with `ref` is not a durable reference");
context.emitter().Emit(node_id, RefTagNotDurableRef);
}
context.ref_tags().Insert(expr_id, Context::RefTag::Present);
return true;
}
} // namespace Carbon::Check
+1 -1
View File
@@ -127,7 +127,7 @@ auto HandleParseNode(Context& context, Parse::VariablePatternId node_id)
switch (context.full_pattern_stack().CurrentKind()) {
case FullPatternStack::Kind::ExplicitParamList:
case FullPatternStack::Kind::ImplicitParamList:
subpattern_id = AddPatternInst<SemIR::RefParamPattern>(
subpattern_id = AddPatternInst<SemIR::VarParamPattern>(
context, node_id,
{.type_id = type_id,
.subpattern_id = subpattern_id,
+3
View File
@@ -3570,6 +3570,9 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver,
case CARBON_KIND(SemIR::ValueParamPattern inst): {
return TryResolveTypedInst(resolver, inst, constant_inst_id);
}
case CARBON_KIND(SemIR::VarParamPattern inst): {
return TryResolveTypedInst(resolver, inst, constant_inst_id);
}
case CARBON_KIND(SemIR::VarPattern inst): {
return TryResolveTypedInst(resolver, inst, constant_inst_id);
}
+2 -1
View File
@@ -257,7 +257,8 @@ static auto CheckRedeclParam(Context& context, bool is_implicit_param,
}
case SemIR::OutParamPattern::Kind:
case SemIR::RefParamPattern::Kind:
case SemIR::ValueParamPattern::Kind: {
case SemIR::ValueParamPattern::Kind:
case SemIR::VarParamPattern::Kind: {
pattern_stack.push_back(
{.prev_id =
prev_param_pattern.As<SemIR::AnyParamPattern>().subpattern_id,
-1
View File
@@ -485,7 +485,6 @@ class NodeStack {
case Parse::NodeKind::BaseColon:
case Parse::NodeKind::BaseIntroducer:
case Parse::NodeKind::BreakStatementStart:
case Parse::NodeKind::CallExprComma:
case Parse::NodeKind::ChoiceAlternativeListComma:
case Parse::NodeKind::CodeBlock:
case Parse::NodeKind::CompileTimeBindingPatternStart:
+7
View File
@@ -64,6 +64,9 @@ auto BuildUnaryOperator(Context& context, SemIR::LocId loc_id, Operator op,
return SemIR::ErrorInst::InstId;
}
// Operator operands don't require `ref` tags.
context.ref_tags().Insert(operand_id, Context::RefTag::NotRequired);
// For unary operators with a C++ class as the operand, try to import and call
// the C++ operator.
// TODO: Change impl lookup instead. See
@@ -102,6 +105,10 @@ auto BuildBinaryOperator(Context& context, SemIR::LocId loc_id, Operator op,
return SemIR::ErrorInst::InstId;
}
// Operator operands don't require `ref` tags.
context.ref_tags().Insert(lhs_id, Context::RefTag::NotRequired);
context.ref_tags().Insert(rhs_id, Context::RefTag::NotRequired);
// For binary operators with a C++ class as at least one of the operands, try
// to import and call the C++ operator.
// TODO: Instead of hooking this here, change impl lookup, so that a generic
+23 -28
View File
@@ -103,9 +103,11 @@ class MatchContext {
auto DoEmitPatternMatch(Context& context,
SemIR::ValueParamPattern param_pattern,
WorkItem entry) -> void;
auto DoEmitPatternMatch(Context& context,
SemIR::RefParamPattern param_pattern, WorkItem entry)
-> void;
template <typename RefParamPatternT>
requires std::is_same_v<RefParamPatternT, SemIR::RefParamPattern> ||
std::is_same_v<RefParamPatternT, SemIR::VarParamPattern>
auto DoEmitPatternMatch(Context& context, RefParamPatternT param_pattern,
WorkItem entry) -> void;
auto DoEmitPatternMatch(Context& context,
SemIR::OutParamPattern param_pattern, WorkItem entry)
-> void;
@@ -337,8 +339,11 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
}
}
template <typename RefParamPatternT>
requires std::is_same_v<RefParamPatternT, SemIR::RefParamPattern> ||
std::is_same_v<RefParamPatternT, SemIR::VarParamPattern>
auto MatchContext::DoEmitPatternMatch(Context& context,
SemIR::RefParamPattern param_pattern,
RefParamPatternT param_pattern,
WorkItem entry) -> void {
switch (kind_) {
case MatchKind::Caller: {
@@ -348,31 +353,17 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
param_pattern.index.index);
CARBON_CHECK(entry.scrutinee_id.has_value());
// TODO: If this is a `ref` pattern and !entry.is_self, require the
// scrutinee to have a `ref` tag.
auto scrutinee_ref_id = ConvertToValueOrRefOfType(
context, SemIR::LocId(entry.scrutinee_id), entry.scrutinee_id,
ExtractScrutineeType(
context.sem_ir(),
SemIR::GetTypeOfInstInSpecific(
context.sem_ir(), callee_specific_id_, entry.pattern_id)));
switch (SemIR::GetExprCategory(context.sem_ir(), scrutinee_ref_id)) {
case SemIR::ExprCategory::Error:
case SemIR::ExprCategory::DurableRef:
case SemIR::ExprCategory::EphemeralRef:
break;
default:
CARBON_DIAGNOSTIC(ValueForRefParam, Error,
"value expression passed to reference parameter");
context.emitter().Emit(entry.scrutinee_id, ValueForRefParam);
// Add fake reference expression to preserve invariants.
auto scrutinee = context.insts().GetWithLocId(entry.scrutinee_id);
scrutinee_ref_id = AddInst<SemIR::TemporaryStorage>(
context, scrutinee.loc_id, {.type_id = scrutinee.inst.type_id()});
if (std::is_same_v<RefParamPatternT, SemIR::VarParamPattern>) {
results_.push_back(entry.scrutinee_id);
break;
}
results_.push_back(scrutinee_ref_id);
auto scrutinee_type_id = ExtractScrutineeType(
context.sem_ir(),
SemIR::GetTypeOfInstInSpecific(context.sem_ir(), callee_specific_id_,
entry.pattern_id));
results_.push_back(Convert(
context, SemIR::LocId(entry.scrutinee_id), entry.scrutinee_id,
{.kind = ConversionTarget::RefParam, .type_id = scrutinee_type_id}));
// Do not traverse farther, because the caller side of the pattern
// ends here.
break;
@@ -627,6 +618,10 @@ auto MatchContext::EmitPatternMatch(Context& context,
DoEmitPatternMatch(context, param_pattern, entry);
break;
}
case CARBON_KIND(SemIR::VarParamPattern param_pattern): {
DoEmitPatternMatch(context, param_pattern, entry);
break;
}
case CARBON_KIND(SemIR::OutParamPattern param_pattern): {
DoEmitPatternMatch(context, param_pattern, entry);
break;
+1 -2
View File
@@ -129,8 +129,7 @@ fn F(c: Class, p: Class*) {
// CHECK:STDOUT: %c.ref: %Class = name_ref c, %c
// CHECK:STDOUT: %F.ref.loc29: %Class.F.type = name_ref F, @Class.%Class.F.decl [concrete = constants.%Class.F]
// CHECK:STDOUT: %Class.F.bound.loc29: <bound method> = bound_method %c.ref, %F.ref.loc29
// CHECK:STDOUT: %.loc29: ref %Class = temporary_storage
// CHECK:STDOUT: %Class.F.call.loc29: init %empty_tuple.type = call %Class.F.bound.loc29(%.loc29)
// CHECK:STDOUT: %Class.F.call.loc29: init %empty_tuple.type = call %Class.F.bound.loc29(<error>)
// CHECK:STDOUT: %p.ref: %ptr.e71 = name_ref p, %p
// CHECK:STDOUT: %.loc32: ref %Class = deref %p.ref
// CHECK:STDOUT: %F.ref.loc32: %Class.F.type = name_ref F, @Class.%Class.F.decl [concrete = constants.%Class.F]
+253
View File
@@ -0,0 +1,253 @@
// 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/int.carbon
// EXTRA-ARGS: --dump-sem-ir-ranges=only
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/function/call/ref.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/function/call/ref.carbon
// --- basics.carbon
library "[[@TEST_NAME]]";
//@dump-sem-ir-begin
fn F(ref x: i32);
fn G() {
var y: i32 = 0;
F(ref y);
}
//@dump-sem-ir-end
// --- class.carbon
library "[[@TEST_NAME]]";
//@dump-sem-ir-begin
class C {
fn F[ref self: Self]();
}
fn G() {
var c: C;
c.F();
}
//@dump-sem-ir-end
// --- fail_ref_not_durable_ref.carbon
library "[[@TEST_NAME]]";
fn F(ref x: i32);
fn G() {
let y: i32 = 0;
// CHECK:STDERR: fail_ref_not_durable_ref.carbon:[[@LINE+4]]:5: error: expression tagged with `ref` is not a durable reference [RefTagNotDurableRef]
// CHECK:STDERR: F(ref y);
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
F(ref y);
}
// --- fail_missing_ref.carbon
library "[[@TEST_NAME]]";
fn F(ref x: i32);
fn G() {
var y: i32 = 0;
// CHECK:STDERR: fail_missing_ref.carbon:[[@LINE+7]]:5: error: argument to `ref` parameter not marked with `ref` [RefParamNoRefTag]
// CHECK:STDERR: F(y);
// CHECK:STDERR: ^
// CHECK:STDERR: fail_missing_ref.carbon:[[@LINE-7]]:6: note: initializing function parameter [InCallToFunctionParam]
// CHECK:STDERR: fn F(ref x: i32);
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR:
F(y);
}
// --- fail_unnecessary_ref.carbon
library "[[@TEST_NAME]]";
fn F(x: i32);
fn G() {
var y: i32 = 0;
// CHECK:STDERR: fail_unnecessary_ref.carbon:[[@LINE+4]]:24: error: `ref` tag is not an argument to a `ref` parameter [RefTagNoRefParam]
// CHECK:STDERR: var z: (i32,) = (ref y,);
// CHECK:STDERR: ^
// CHECK:STDERR:
var z: (i32,) = (ref y,);
// CHECK:STDERR: fail_unnecessary_ref.carbon:[[@LINE+7]]:9: error: `ref` tag is not an argument to a `ref` parameter [RefTagNoRefParam]
// CHECK:STDERR: F(ref y);
// CHECK:STDERR: ^
// CHECK:STDERR: fail_unnecessary_ref.carbon:[[@LINE-13]]:6: note: initializing function parameter [InCallToFunctionParam]
// CHECK:STDERR: fn F(x: i32);
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
F(ref y);
}
// CHECK:STDOUT: --- basics.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: %G.type: type = fn_type @G [concrete]
// CHECK:STDOUT: %G: %G.type = struct_value () [concrete]
// CHECK:STDOUT: %int_0.5c6: Core.IntLiteral = int_value 0 [concrete]
// CHECK:STDOUT: %ImplicitAs.type.d14: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
// CHECK:STDOUT: %ImplicitAs.Convert.type.1b6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete]
// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.f51: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.2a1: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.f51 = struct_value () [symbolic]
// CHECK:STDOUT: %ImplicitAs.impl_witness.bc9: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.132, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.51e: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.51e = struct_value () [concrete]
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.d14 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.bc9) [concrete]
// CHECK:STDOUT: %.322: type = fn_type_with_self_type %ImplicitAs.Convert.type.1b6, %ImplicitAs.facet [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: <bound method> = bound_method %int_0.5c6, %Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_0.5c6, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
// CHECK:STDOUT: %int_0.6a9: %i32 = int_value 0 [concrete]
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanDestroy>> [concrete]
// CHECK:STDOUT: %facet_value: %type_where = facet_value %i32, () [concrete]
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.d4e: type = fn_type @DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value) [concrete]
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.424: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.d4e = struct_value () [concrete]
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core.import_ref.e24: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.f51) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.2a1)]
// CHECK:STDOUT: %ImplicitAs.impl_witness_table.132 = impl_witness_table (%Core.import_ref.e24), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
// CHECK:STDOUT: %x.patt: %pattern_type.7ce = ref_binding_pattern x [concrete]
// CHECK:STDOUT: %x.param_patt: %pattern_type.7ce = ref_param_pattern %x.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %x.param: ref %i32 = ref_param call_param0
// CHECK:STDOUT: %.loc5: type = splice_block %i32 [concrete = constants.%i32] {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x: ref %i32 = ref_binding x, %x.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [concrete = constants.%G] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F(%x.param: %i32);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @G() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %y.patt: %pattern_type.7ce = ref_binding_pattern y [concrete]
// CHECK:STDOUT: %y.var_patt: %pattern_type.7ce = var_pattern %y.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %y.var: ref %i32 = var %y.var_patt
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [concrete = constants.%int_0.5c6]
// CHECK:STDOUT: %impl.elem0: %.322 = impl_witness_access constants.%ImplicitAs.impl_witness.bc9, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b]
// CHECK:STDOUT: %bound_method.loc8_3.1: <bound method> = bound_method %int_0, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc8_3.2: <bound method> = bound_method %int_0, %specific_fn [concrete = constants.%bound_method]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc8_3.2(%int_0) [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc8_3: init %i32 = converted %int_0, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: assign %y.var, %.loc8_3
// CHECK:STDOUT: %.loc8_10: type = splice_block %i32 [concrete = constants.%i32] {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: }
// CHECK:STDOUT: %y: ref %i32 = ref_binding y, %y.var
// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F]
// CHECK:STDOUT: %y.ref: ref %i32 = name_ref y, %y
// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.ref(%y.ref)
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %y.var, constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.424
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_3.3: <bound method> = bound_method %y.var, %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr: %ptr.235 = addr_of %y.var
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_3.3(%addr)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- class.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %pattern_type.c48: type = pattern_type %C [concrete]
// CHECK:STDOUT: %C.F.type: type = fn_type @C.F [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C.F: %C.F.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
// CHECK:STDOUT: %G.type: type = fn_type @G [concrete]
// CHECK:STDOUT: %G: %G.type = struct_value () [concrete]
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanDestroy>> [concrete]
// CHECK:STDOUT: %facet_value: %type_where = facet_value %C, () [concrete]
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.eeb: type = fn_type @DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value) [concrete]
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.88a: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.eeb = struct_value () [concrete]
// CHECK:STDOUT: %ptr.019: type = ptr_type %C [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [concrete = constants.%G] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %C.F.decl: %C.F.type = fn_decl @C.F [concrete = constants.%C.F] {
// CHECK:STDOUT: %self.patt: %pattern_type.c48 = ref_binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type.c48 = ref_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: ref %C = ref_param call_param0
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%C [concrete = constants.%C]
// CHECK:STDOUT: %self: ref %C = ref_binding self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type.357]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: .F = %C.F.decl
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @C.F(%self.param: %C);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @G() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %c.patt: %pattern_type.c48 = ref_binding_pattern c [concrete]
// CHECK:STDOUT: %c.var_patt: %pattern_type.c48 = var_pattern %c.patt [concrete]
// CHECK:STDOUT: }
// 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 = ref_binding c, %c.var
// CHECK:STDOUT: %c.ref: ref %C = name_ref c, %c
// CHECK:STDOUT: %F.ref: %C.F.type = name_ref F, @C.%C.F.decl [concrete = constants.%C.F]
// CHECK:STDOUT: %C.F.bound: <bound method> = bound_method %c.ref, %F.ref
// CHECK:STDOUT: %C.F.call: init %empty_tuple.type = call %C.F.bound(%c.ref)
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %c.var, constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.88a
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %c.var, %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr: %ptr.019 = addr_of %c.var
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -854,7 +854,7 @@ fn F[T:! Ptr](var t: T) -> T.(Ptr.Type) {
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
// CHECK:STDOUT: %T.patt: %pattern_type.98f = symbolic_binding_pattern T, 0 [concrete]
// CHECK:STDOUT: %t.patt: @F.%pattern_type.loc9_20 (%pattern_type.e68) = ref_binding_pattern t [concrete]
// CHECK:STDOUT: %t.param_patt: @F.%pattern_type.loc9_20 (%pattern_type.e68) = ref_param_pattern %t.patt, call_param0 [concrete]
// CHECK:STDOUT: %t.param_patt: @F.%pattern_type.loc9_20 (%pattern_type.e68) = var_param_pattern %t.patt, call_param0 [concrete]
// CHECK:STDOUT: %t.var_patt: @F.%pattern_type.loc9_20 (%pattern_type.e68) = var_pattern %t.param_patt [concrete]
// CHECK:STDOUT: %return.patt: @F.%pattern_type.loc9_26 (%pattern_type.a60) = return_slot_pattern [concrete]
// CHECK:STDOUT: %return.param_patt: @F.%pattern_type.loc9_26 (%pattern_type.a60) = out_param_pattern %return.patt, call_param1 [concrete]
@@ -1055,7 +1055,7 @@ fn F[T:! Ptr](var t: T) -> T.(Ptr.Type) {
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
// CHECK:STDOUT: %T.patt: %pattern_type.3d8 = symbolic_binding_pattern T, 0 [concrete]
// CHECK:STDOUT: %t.patt: @F.%pattern_type.loc9_19 (%pattern_type.6f0) = ref_binding_pattern t [concrete]
// CHECK:STDOUT: %t.param_patt: @F.%pattern_type.loc9_19 (%pattern_type.6f0) = ref_param_pattern %t.patt, call_param0 [concrete]
// CHECK:STDOUT: %t.param_patt: @F.%pattern_type.loc9_19 (%pattern_type.6f0) = var_param_pattern %t.patt, call_param0 [concrete]
// CHECK:STDOUT: %t.var_patt: @F.%pattern_type.loc9_19 (%pattern_type.6f0) = var_pattern %t.param_patt [concrete]
// CHECK:STDOUT: %return.patt: @F.%pattern_type.loc9_25 (%pattern_type.425) = return_slot_pattern [concrete]
// CHECK:STDOUT: %return.param_patt: @F.%pattern_type.loc9_25 (%pattern_type.425) = out_param_pattern %return.patt, call_param1 [concrete]
@@ -1262,7 +1262,7 @@ fn F[T:! Ptr](var t: T) -> T.(Ptr.Type) {
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
// CHECK:STDOUT: %T.patt: %pattern_type.3d8 = symbolic_binding_pattern T, 0 [concrete]
// CHECK:STDOUT: %t.patt: @F.%pattern_type.loc9_19 (%pattern_type.6f0) = ref_binding_pattern t [concrete]
// CHECK:STDOUT: %t.param_patt: @F.%pattern_type.loc9_19 (%pattern_type.6f0) = ref_param_pattern %t.patt, call_param0 [concrete]
// CHECK:STDOUT: %t.param_patt: @F.%pattern_type.loc9_19 (%pattern_type.6f0) = var_param_pattern %t.patt, call_param0 [concrete]
// CHECK:STDOUT: %t.var_patt: @F.%pattern_type.loc9_19 (%pattern_type.6f0) = var_pattern %t.param_patt [concrete]
// CHECK:STDOUT: %return.patt: @F.%pattern_type.loc9_25 (%pattern_type.425) = return_slot_pattern [concrete]
// CHECK:STDOUT: %return.param_patt: @F.%pattern_type.loc9_25 (%pattern_type.425) = out_param_pattern %return.patt, call_param1 [concrete]
-206
View File
@@ -22,35 +22,6 @@ fn F(a: i32) {
//@dump-sem-ir-end
}
// --- param.carbon
library "[[@TEST_NAME]]";
//@dump-sem-ir-begin
fn F(ref a: i32) {
a = 1;
}
fn G() {
var x: i32 = 0;
F(x);
}
//@dump-sem-ir-end
// --- self.carbon
library "[[@TEST_NAME]]";
//@dump-sem-ir-begin
class C {
var a: i32;
fn F[ref self: Self]() {
self.a = 1;
}
}
//@dump-sem-ir-end
// --- fail_ref_to_value.carbon
library "[[@TEST_NAME]]";
@@ -123,180 +94,3 @@ fn F() {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- param.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete]
// CHECK:STDOUT: %ImplicitAs.type.d14: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
// CHECK:STDOUT: %ImplicitAs.Convert.type.1b6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete]
// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.f51: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.2a1: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.f51 = struct_value () [symbolic]
// CHECK:STDOUT: %ImplicitAs.impl_witness.bc9: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.132, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.51e: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.51e = struct_value () [concrete]
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.d14 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.bc9) [concrete]
// CHECK:STDOUT: %.322: type = fn_type_with_self_type %ImplicitAs.Convert.type.1b6, %ImplicitAs.facet [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.265: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete]
// CHECK:STDOUT: %bound_method.dfc: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
// CHECK:STDOUT: %int_1.5d2: %i32 = int_value 1 [concrete]
// CHECK:STDOUT: %G.type: type = fn_type @G [concrete]
// CHECK:STDOUT: %G: %G.type = struct_value () [concrete]
// CHECK:STDOUT: %int_0.5c6: Core.IntLiteral = int_value 0 [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.0b3: <bound method> = bound_method %int_0.5c6, %Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b [concrete]
// CHECK:STDOUT: %bound_method.9be: <bound method> = bound_method %int_0.5c6, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
// CHECK:STDOUT: %int_0.6a9: %i32 = int_value 0 [concrete]
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanDestroy>> [concrete]
// CHECK:STDOUT: %facet_value: %type_where = facet_value %i32, () [concrete]
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.d4e: type = fn_type @DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value) [concrete]
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.424: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.d4e = struct_value () [concrete]
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core.import_ref.e24: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.f51) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.2a1)]
// CHECK:STDOUT: %ImplicitAs.impl_witness_table.132 = impl_witness_table (%Core.import_ref.e24), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
// CHECK:STDOUT: %a.patt: %pattern_type.7ce = ref_binding_pattern a [concrete]
// CHECK:STDOUT: %a.param_patt: %pattern_type.7ce = ref_param_pattern %a.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %a.param: ref %i32 = ref_param call_param0
// CHECK:STDOUT: %.loc5: type = splice_block %i32 [concrete = constants.%i32] {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: }
// CHECK:STDOUT: %a: ref %i32 = ref_binding a, %a.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [concrete = constants.%G] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F(%a.param: %i32) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
// CHECK:STDOUT: %impl.elem0: %.322 = impl_witness_access constants.%ImplicitAs.impl_witness.bc9, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b]
// CHECK:STDOUT: %bound_method.loc6_5.1: <bound method> = bound_method %int_1, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.265]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc6_5.2: <bound method> = bound_method %int_1, %specific_fn [concrete = constants.%bound_method.dfc]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc6_5.2(%int_1) [concrete = constants.%int_1.5d2]
// CHECK:STDOUT: %.loc6: init %i32 = converted %int_1, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_1.5d2]
// CHECK:STDOUT: assign %a.ref, %.loc6
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @G() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %x.patt: %pattern_type.7ce = ref_binding_pattern x [concrete]
// CHECK:STDOUT: %x.var_patt: %pattern_type.7ce = var_pattern %x.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x.var: ref %i32 = var %x.var_patt
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [concrete = constants.%int_0.5c6]
// CHECK:STDOUT: %impl.elem0: %.322 = impl_witness_access constants.%ImplicitAs.impl_witness.bc9, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b]
// CHECK:STDOUT: %bound_method.loc10_3.1: <bound method> = bound_method %int_0, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.0b3]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc10_3.2: <bound method> = bound_method %int_0, %specific_fn [concrete = constants.%bound_method.9be]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc10_3.2(%int_0) [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc10_3: init %i32 = converted %int_0, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: assign %x.var, %.loc10_3
// CHECK:STDOUT: %.loc10_10: type = splice_block %i32 [concrete = constants.%i32] {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x: ref %i32 = ref_binding x, %x.var
// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F]
// CHECK:STDOUT: %x.ref: ref %i32 = name_ref x, %x
// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.ref(%x.ref)
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %x.var, constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.424
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc10_3.3: <bound method> = bound_method %x.var, %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr: %ptr.235 = addr_of %x.var
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc10_3.3(%addr)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- self.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %C.elem: type = unbound_element_type %C, %i32 [concrete]
// CHECK:STDOUT: %pattern_type.c48: type = pattern_type %C [concrete]
// CHECK:STDOUT: %C.F.type: type = fn_type @C.F [concrete]
// CHECK:STDOUT: %C.F: %C.F.type = struct_value () [concrete]
// CHECK:STDOUT: %struct_type.a: type = struct_type {.a: %i32} [concrete]
// CHECK:STDOUT: %complete_type.fd7: <witness> = complete_type_witness %struct_type.a [concrete]
// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete]
// CHECK:STDOUT: %ImplicitAs.type.d14: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
// CHECK:STDOUT: %ImplicitAs.Convert.type.1b6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete]
// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.f51: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.2a1: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.f51 = struct_value () [symbolic]
// CHECK:STDOUT: %ImplicitAs.impl_witness.bc9: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.132, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.51e: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.51e = struct_value () [concrete]
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.d14 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.bc9) [concrete]
// CHECK:STDOUT: %.322: type = fn_type_with_self_type %ImplicitAs.Convert.type.1b6, %ImplicitAs.facet [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b [concrete]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
// CHECK:STDOUT: %int_1.5d2: %i32 = int_value 1 [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core.import_ref.e24: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.f51) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.2a1)]
// CHECK:STDOUT: %ImplicitAs.impl_witness_table.132 = impl_witness_table (%Core.import_ref.e24), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %.loc6: %C.elem = field_decl a, element0 [concrete]
// CHECK:STDOUT: %C.F.decl: %C.F.type = fn_decl @C.F [concrete = constants.%C.F] {
// CHECK:STDOUT: %self.patt: %pattern_type.c48 = ref_binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type.c48 = ref_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: ref %C = ref_param call_param0
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%C [concrete = constants.%C]
// CHECK:STDOUT: %self: ref %C = ref_binding self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%struct_type.a [concrete = constants.%complete_type.fd7]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: .a = %.loc6
// CHECK:STDOUT: .F = %C.F.decl
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @C.F(%self.param: %C) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: ref %C = name_ref self, %self
// CHECK:STDOUT: %a.ref: %C.elem = name_ref a, @C.%.loc6 [concrete = @C.%.loc6]
// CHECK:STDOUT: %.loc9_9: ref %i32 = class_element_access %self.ref, element0
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
// CHECK:STDOUT: %impl.elem0: %.322 = impl_witness_access constants.%ImplicitAs.impl_witness.bc9, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.e9b]
// CHECK:STDOUT: %bound_method.loc9_12.1: <bound method> = bound_method %int_1, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc9_12.2: <bound method> = bound_method %int_1, %specific_fn [concrete = constants.%bound_method]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc9_12.2(%int_1) [concrete = constants.%int_1.5d2]
// CHECK:STDOUT: %.loc9_12: init %i32 = converted %int_1, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_1.5d2]
// CHECK:STDOUT: assign %.loc9_9, %.loc9_12
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
+4 -4
View File
@@ -473,7 +473,7 @@ fn G() {
// CHECK:STDOUT: %x.patt: %pattern_type.cb1 = value_binding_pattern x [concrete]
// CHECK:STDOUT: %x.param_patt: %pattern_type.cb1 = value_param_pattern %x.patt, call_param0 [concrete]
// CHECK:STDOUT: %y.patt: %pattern_type.cb1 = ref_binding_pattern y [concrete]
// CHECK:STDOUT: %y.param_patt: %pattern_type.cb1 = ref_param_pattern %y.patt, call_param1 [concrete]
// CHECK:STDOUT: %y.param_patt: %pattern_type.cb1 = var_param_pattern %y.patt, call_param1 [concrete]
// CHECK:STDOUT: %y.var_patt: %pattern_type.cb1 = var_pattern %y.param_patt [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %x.param: %empty_tuple.type = value_param call_param0
@@ -559,7 +559,7 @@ fn G() {
// CHECK:STDOUT: %x.patt: %pattern_type = value_binding_pattern x [concrete]
// CHECK:STDOUT: %x.param_patt: %pattern_type = value_param_pattern %x.patt, call_param0 [concrete]
// CHECK:STDOUT: %y.patt: %pattern_type = ref_binding_pattern y [concrete]
// CHECK:STDOUT: %y.param_patt: %pattern_type = ref_param_pattern %y.patt, call_param1 [concrete]
// CHECK:STDOUT: %y.param_patt: %pattern_type = var_param_pattern %y.patt, call_param1 [concrete]
// CHECK:STDOUT: %y.var_patt: %pattern_type = var_pattern %y.param_patt [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %x.param: %empty_tuple.type = value_param call_param0
@@ -607,7 +607,7 @@ fn G() {
// CHECK:STDOUT: %x.patt: %pattern_type = value_binding_pattern x [concrete]
// CHECK:STDOUT: %x.param_patt: %pattern_type = value_param_pattern %x.patt, call_param0 [concrete]
// CHECK:STDOUT: %y.patt: %pattern_type = ref_binding_pattern y [concrete]
// CHECK:STDOUT: %y.param_patt: %pattern_type = ref_param_pattern %y.patt, call_param1 [concrete]
// CHECK:STDOUT: %y.param_patt: %pattern_type = var_param_pattern %y.patt, call_param1 [concrete]
// CHECK:STDOUT: %y.var_patt: %pattern_type = var_pattern %y.param_patt [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %x.param: %empty_tuple.type = value_param call_param0
@@ -863,7 +863,7 @@ fn G() {
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %C.F.decl: %C.F.type = fn_decl @C.F [concrete = constants.%C.F] {
// CHECK:STDOUT: %self.patt: %pattern_type = ref_binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type = ref_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type = var_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: %self.var_patt: %pattern_type = var_pattern %self.param_patt [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: ref %C = ref_param call_param0
+1 -2
View File
@@ -298,8 +298,7 @@ static auto BuildPatternRef(Context& context,
auto pattern_ref_id = SemIR::InstId::None;
if (auto value_param = pattern.TryAs<SemIR::AnyParamPattern>();
value_param.has_value() &&
(value_param->kind == SemIR::ValueParamPattern::Kind ||
value_param->kind == SemIR::RefParamPattern::Kind)) {
value_param->kind != SemIR::OutParamPattern::Kind) {
pattern_ref_id = arg_ids[value_param->index.index];
} else {
if (pattern_id != SemIR::ErrorInst::InstId) {
@@ -118,6 +118,7 @@ CARBON_DIAGNOSTIC_KIND(UnaryOperatorRequiresWhitespace)
CARBON_DIAGNOSTIC_KIND(UnexpectedTokenAfterListElement)
CARBON_DIAGNOSTIC_KIND(UnrecognizedDecl)
CARBON_DIAGNOSTIC_KIND(UnexpectedTokenInCompoundMemberAccess)
CARBON_DIAGNOSTIC_KIND(UnexpectedRef)
// Match diagnostics.
CARBON_DIAGNOSTIC_KIND(ExpectedMatchCaseArrow)
@@ -255,6 +256,9 @@ CARBON_DIAGNOSTIC_KIND(InCallToEntity)
CARBON_DIAGNOSTIC_KIND(InCallToFunction)
CARBON_DIAGNOSTIC_KIND(InCallToFunctionParam)
CARBON_DIAGNOSTIC_KIND(MissingObjectInMethodCall)
CARBON_DIAGNOSTIC_KIND(RefParamNoRefTag)
CARBON_DIAGNOSTIC_KIND(RefTagNoRefParam)
CARBON_DIAGNOSTIC_KIND(RefTagNotDurableRef)
CARBON_DIAGNOSTIC_KIND(SelfParameterNotAllowed)
CARBON_DIAGNOSTIC_KIND(ValueForRefParam)
+2 -1
View File
@@ -357,7 +357,8 @@ auto FileContext::BuildFunctionTypeInfo(const SemIR::Function& function,
}
// TODO: Use a more general mechanism to determine if the binding is a
// reference binding.
if (param_pattern_info->inst.kind == SemIR::RefParamPattern::Kind) {
if (param_pattern_info->inst.kind == SemIR::RefParamPattern::Kind ||
param_pattern_info->inst.kind == SemIR::VarParamPattern::Kind) {
param_types.push_back(
llvm::PointerType::get(llvm_context(), /*AddressSpace=*/0));
param_inst_ids.push_back(param_pattern_id);
+1 -1
View File
@@ -14,7 +14,7 @@ fn DoNothing(ref a: i32) {}
fn Main() {
var a: i32 = 0;
DoNothing(a);
DoNothing(ref a);
}
// CHECK:STDOUT: ; ModuleID = 'ref_param.carbon'
+5
View File
@@ -133,6 +133,11 @@ static auto HandleBraceExprParamAfterDesignator(Context& context,
// that one has a `:` separator and the other has an `=` separator.
state.token = context.Consume();
context.PushState(state, param_finish_kind);
if (param_finish_kind == StateKind::BraceExprParamFinishAsValue &&
context.PositionIs(Lex::TokenKind::Ref)) {
context.PushState(StateKind::RefTagFinishAsRegular);
context.ConsumeChecked(Lex::TokenKind::Ref);
}
context.PushState(StateKind::Expr);
}
-42
View File
@@ -1,42 +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 "toolchain/parse/context.h"
#include "toolchain/parse/handle.h"
namespace Carbon::Parse {
auto HandleCallExpr(Context& context) -> void {
auto state = context.PopState();
context.PushState(state, StateKind::CallExprFinish);
context.AddNode(NodeKind::CallExprStart, context.Consume(), state.has_error);
if (!context.PositionIs(Lex::TokenKind::CloseParen)) {
context.PushState(StateKind::CallExprParamFinish);
context.PushState(StateKind::Expr);
}
}
auto HandleCallExprParamFinish(Context& context) -> void {
auto state = context.PopState();
if (state.has_error) {
context.ReturnErrorOnState();
}
if (context.ConsumeListToken(NodeKind::CallExprComma,
Lex::TokenKind::CloseParen, state.has_error) ==
Context::ListTokenKind::Comma) {
context.PushState(StateKind::CallExprParamFinish);
context.PushState(StateKind::Expr);
}
}
auto HandleCallExprFinish(Context& context) -> void {
auto state = context.PopState();
context.AddNode(NodeKind::CallExpr, context.Consume(), state.has_error);
}
} // namespace Carbon::Parse
+54 -5
View File
@@ -43,6 +43,34 @@ auto HandleOnlyParenExprFinish(Context& context) -> void {
FinishParenExpr(context, state);
}
static auto HandleRefTagFinish(Context& context, StateKind state_kind) -> void {
auto state = context.PopState();
if (state_kind == StateKind::RefTagFinishAsAfterOpenParen &&
!context.PositionIs(Lex::TokenKind::Comma)) {
CARBON_DIAGNOSTIC(UnexpectedRef, Error,
"found `ref` in unexpected position");
context.emitter().Emit(state.token, UnexpectedRef);
}
context.AddNode(NodeKind::RefTag, state.token, state.has_error);
}
auto HandleRefTagFinishAsRegular(Context& context) -> void {
HandleRefTagFinish(context, StateKind::RefTagFinishAsRegular);
}
auto HandleRefTagFinishAsAfterOpenParen(Context& context) -> void {
HandleRefTagFinish(context, StateKind::RefTagFinishAsAfterOpenParen);
}
static auto StartTupleLiteralElement(Context& context) -> void {
context.PushState(StateKind::TupleLiteralElementFinish);
if (context.PositionIs(Lex::TokenKind::Ref)) {
context.PushState(StateKind::RefTagFinishAsRegular);
context.ConsumeChecked(Lex::TokenKind::Ref);
}
context.PushState(StateKind::Expr);
}
auto HandleParenExpr(Context& context) -> void {
auto state = context.PopState();
@@ -56,6 +84,10 @@ auto HandleParenExpr(Context& context) -> void {
} else {
context.PushState(state, StateKind::ParenExprFinish);
context.PushState(StateKind::ExprAfterOpenParenFinish);
if (context.PositionIs(Lex::TokenKind::Ref)) {
context.PushState(StateKind::RefTagFinishAsAfterOpenParen);
context.ConsumeChecked(Lex::TokenKind::Ref);
}
context.PushState(StateKind::Expr);
}
}
@@ -78,25 +110,26 @@ auto HandleExprAfterOpenParenFinish(Context& context) -> void {
// If the comma is not immediately followed by a close paren, push handlers
// for the next tuple element.
if (list_token_kind != Context::ListTokenKind::CommaClose) {
context.PushState(state, StateKind::TupleLiteralElementFinish);
context.PushState(StateKind::Expr);
StartTupleLiteralElement(context);
}
}
auto HandleTupleLiteralElementFinish(Context& context) -> void {
auto state = context.PopState();
if (state.has_error) {
context.ReturnErrorOnState();
}
if (context.ConsumeListToken(NodeKind::TupleLiteralComma,
Lex::TokenKind::CloseParen, state.has_error) ==
Context::ListTokenKind::Comma) {
context.PushState(state);
context.PushState(StateKind::Expr);
StartTupleLiteralElement(context);
}
}
auto HandleParenExprFinish(Context& context) -> void {
auto state = context.PopState();
context.ReplacePlaceholderNode(state.subtree_start, NodeKind::ParenExprStart,
state.token);
FinishParenExpr(context, state);
@@ -110,4 +143,20 @@ auto HandleTupleLiteralFinish(Context& context) -> void {
context.AddNode(NodeKind::TupleLiteral, context.Consume(), state.has_error);
}
auto HandleCallExpr(Context& context) -> void {
auto state = context.PopState();
context.PushState(state, StateKind::CallExprFinish);
context.AddNode(NodeKind::CallExprStart, context.Consume(), state.has_error);
if (!context.PositionIs(Lex::TokenKind::CloseParen)) {
StartTupleLiteralElement(context);
}
}
auto HandleCallExprFinish(Context& context) -> void {
auto state = context.PopState();
context.AddNode(NodeKind::CallExpr, context.Consume(), state.has_error);
}
} // namespace Carbon::Parse
+2 -1
View File
@@ -234,7 +234,6 @@ CARBON_PARSE_NODE_KIND(TupleLiteralComma)
CARBON_PARSE_NODE_KIND(TupleLiteral)
CARBON_PARSE_NODE_KIND(CallExprStart)
CARBON_PARSE_NODE_KIND(CallExprComma)
CARBON_PARSE_NODE_KIND(CallExpr)
CARBON_PARSE_NODE_KIND(MemberAccessExpr)
@@ -243,6 +242,8 @@ CARBON_PARSE_NODE_KIND(PointerMemberAccessExpr)
CARBON_PARSE_NODE_KIND(IntLiteral)
CARBON_PARSE_NODE_KIND(RefTag)
CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(BoolLiteralFalse, False)
CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(BoolLiteralTrue, True)
CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(CharLiteral, CharLiteral)
+51 -16
View File
@@ -125,6 +125,12 @@ CARBON_PARSE_STATE_VARIANTS3(BraceExprParam, Type, Value, Unknown)
// Handles a brace expression parameter after the initial designator. This
// should be at a `:` or `=`, depending on whether it's a type or value literal.
//
// { .foo = ref bar ... }
// ^~~~~
// 1. Expr
// 2. RefTagFinishAsRegular
// 3. BraceExprParamFinishAsValue
//
// { .foo = bar ... }
// ^
// 1. Expr
@@ -167,31 +173,35 @@ CARBON_PARSE_STATE_VARIANTS3(BraceExprParamFinish, Type, Value, Unknown)
// (state done)
CARBON_PARSE_STATE_VARIANTS3(BraceExprFinish, Type, Value, Unknown)
// Handles a call expression `(...)`.
// Handles the end of an argument expression tagged with `ref`. The
// `AfterOpenParen` variant diagnoses if the expression is not followed by `,`.
//
// ref ...
// ^
// (state done)
CARBON_PARSE_STATE_VARIANTS2(RefTagFinish, Regular, AfterOpenParen)
// Handles a call expression `(...)`, including the initial `ref`, if any.
//
// F()
// ^
// 1. CallExprFinish
//
// F(ref ...
// ^~~~
//
// 1. Expr
// 2. RefTagFinishAsRegular
// 2. TupleLiteralElementFinish
// 3. CallExprFinish
//
// F( ...
// ^
// 1. Expr
// 2. CallExprParamFinish
// 2. TupleLiteralElementFinish
// 3. CallExprFinish
CARBON_PARSE_STATE(CallExpr)
// Handles the `,` or `)` after a call parameter.
//
// F(a, ...)
// ^
// 1. Expr
// 2. CallExprParamFinish
//
// F(a )
// ^
// (state done)
CARBON_PARSE_STATE(CallExprParamFinish)
// Handles finishing the call expression.
//
// F(a, b)
@@ -924,17 +934,29 @@ CARBON_PARSE_STATE(OnlyParenExpr)
// ^
CARBON_PARSE_STATE(OnlyParenExprFinish)
// Handles the `(` of a parenthesized single expression
// Handles the `(` of an expression that's presumed to be a parenthesized
// single expression, but may later be reclassified as a tuple literal.
// This also handles a `ref` following the `(`, if present. That's only
// valid in tuple literals, but doesn't cause the expression to be a tuple
// literal.
//
// ( )
// ^
// 1. TupleLiteralFinish
//
// (ref ... )
// ^~~~
//
// 1. Expr
// 2. RefTagFinishAsAfterOpenParen
// 3. ExprAfterOpenParenFinish
// 4. ParenExprFinish (SPECIAL: may be replaced)
//
// ( ... )
// ^
// 1. Expr
// 2. ExprAfterOpenParenFinish
// 3. ParenExprFinish (SPECIAL: may be replaced)
// 3. ParenExprFinish (SPECIAL: may be replaced)
CARBON_PARSE_STATE(ParenExpr)
// Handles the `)` of a tuple literal.
@@ -951,6 +973,13 @@ CARBON_PARSE_STATE(TupleLiteralFinish)
// (state done)
// SPECIAL: parent becomes TupleLiteralFinish
//
// ( ... , ref ... )
// ^~~~~
// 1. Expr
// 2. RefTagFinishAsRegular
// 3. TupleLiteralElementFinish
// SPECIAL: parent becomes TupleLiteralFinish
//
// ( ... , ... )
// ^
// 1. Expr
@@ -969,6 +998,12 @@ CARBON_PARSE_STATE(ExprAfterOpenParenFinish)
// ^
// (state done)
//
// ( ... , ref ... )
// ^~~~~
// 1. Expr
// 2. RefTagFinishAsRegular
// 3. TupleLiteralElementFinish
//
// ( ... , ... )
// ^
// 1. Expr
+1 -1
View File
@@ -30,7 +30,7 @@ fn F() {
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'c'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'd'},
// CHECK:STDOUT: {kind: 'MemberAccessExpr', text: '.', subtree_size: 3},
// CHECK:STDOUT: {kind: 'CallExprComma', text: ','},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'ParenExprStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'e'},
// CHECK:STDOUT: {kind: 'ParenExpr', text: ')', subtree_size: 3},
+201
View File
@@ -0,0 +1,201 @@
// 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/parse/testdata/function/call.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/function/call.carbon
// --- basic.carbon
fn F() {
a.b.f(c.d, (e)).g();
}
// --- ref_args.carbon
fn F() {
G(ref x);
G(ref x, y);
G(x, ref y);
}
// --- nested_ref.carbon
fn F() {
G(x, (ref x,));
G(x, (ref y, z));
G(x, (y, ref z));
G(x, {.y = ref y, .z = z});
}
// --- fail_ref_out_of_place.carbon
fn F() {
(ref x,);
G(ref x);
// CHECK:STDERR: fail_ref_out_of_place.carbon:[[@LINE+4]]:4: error: found `ref` in unexpected position [UnexpectedRef]
// CHECK:STDERR: (ref x);
// CHECK:STDERR: ^~~
// CHECK:STDERR:
(ref x);
}
// CHECK:STDOUT: - filename: basic.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'F'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'a'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'b'},
// CHECK:STDOUT: {kind: 'MemberAccessExpr', text: '.', subtree_size: 3},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'f'},
// CHECK:STDOUT: {kind: 'MemberAccessExpr', text: '.', subtree_size: 5},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 6},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'c'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'd'},
// CHECK:STDOUT: {kind: 'MemberAccessExpr', text: '.', subtree_size: 3},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'ParenExprStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'e'},
// CHECK:STDOUT: {kind: 'ParenExpr', text: ')', subtree_size: 3},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 14},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'g'},
// CHECK:STDOUT: {kind: 'MemberAccessExpr', text: '.', subtree_size: 16},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 17},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 18},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 19},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 25},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: ref_args.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'F'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'G'},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'RefTag', text: 'ref', subtree_size: 2},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 6},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'G'},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'RefTag', text: 'ref', subtree_size: 2},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'y'},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 7},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 8},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'G'},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'y'},
// CHECK:STDOUT: {kind: 'RefTag', text: 'ref', subtree_size: 2},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 7},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 8},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 28},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: nested_ref.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'F'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'G'},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'RefTag', text: 'ref', subtree_size: 2},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 5},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 10},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 11},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'G'},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'y'},
// CHECK:STDOUT: {kind: 'RefTag', text: 'ref', subtree_size: 2},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'z'},
// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 6},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 11},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 12},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'G'},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'y'},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'z'},
// CHECK:STDOUT: {kind: 'RefTag', text: 'ref', subtree_size: 2},
// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 6},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 11},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 12},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'G'},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'StructLiteralStart', text: '{'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'y'},
// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'y'},
// CHECK:STDOUT: {kind: 'RefTag', text: 'ref', subtree_size: 2},
// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 5},
// CHECK:STDOUT: {kind: 'StructLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'z'},
// CHECK:STDOUT: {kind: 'StructFieldDesignator', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'z'},
// CHECK:STDOUT: {kind: 'StructLiteralField', text: '=', subtree_size: 4},
// CHECK:STDOUT: {kind: 'StructLiteral', text: '}', subtree_size: 12},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 17},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 18},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 59},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_ref_out_of_place.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'F'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
// CHECK:STDOUT: {kind: 'TupleLiteralStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'RefTag', text: 'ref', subtree_size: 2},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 6},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'G'},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'RefTag', text: 'ref', subtree_size: 2},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 6},
// CHECK:STDOUT: {kind: 'ParenExprStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'x'},
// CHECK:STDOUT: {kind: 'RefTag', text: 'ref', subtree_size: 2},
// CHECK:STDOUT: {kind: 'ParenExpr', text: ')', subtree_size: 4},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 23},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
+1 -1
View File
@@ -107,7 +107,7 @@ fn TestRecoveryFromSpuriousEquals();
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'foo'},
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'baz'},
// CHECK:STDOUT: {kind: 'CallExprComma', text: ','},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'bar'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'baz'},
// CHECK:STDOUT: {kind: 'InfixOperatorPlus', text: '+', subtree_size: 3},
@@ -27,7 +27,7 @@ var n: i8 = F(i8 *, 0);
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i8'},
// CHECK:STDOUT: {kind: 'PostfixOperatorStar', text: '*', subtree_size: 2},
// CHECK:STDOUT: {kind: 'CallExprComma', text: ','},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '0'},
// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 7},
// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 14},
+1 -1
View File
@@ -24,7 +24,7 @@ fn F() {
// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'PostfixOperatorStar', text: '*', subtree_size: 2},
// CHECK:STDOUT: {kind: 'CallExprComma', text: ','},
// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'n'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'n'},
// CHECK:STDOUT: {kind: 'InfixOperatorStar', text: '*', subtree_size: 3},
+10 -3
View File
@@ -996,18 +996,25 @@ struct CallExprStart {
Lex::OpenParenTokenIndex token;
};
using CallExprComma = LeafNode<NodeKind::CallExprComma, Lex::CommaTokenIndex>;
// A call expression: `F(a, b, c)`.
struct CallExpr {
static constexpr auto Kind = NodeKind::CallExpr.Define(
{.category = NodeCategory::Expr, .bracketed_by = CallExprStart::Kind});
CallExprStartId start;
CommaSeparatedList<AnyExprId, CallExprCommaId> arguments;
CommaSeparatedList<AnyExprId, TupleLiteralCommaId> arguments;
Lex::CloseParenTokenIndex token;
};
// A callsite `ref` tag: `F(ref x)` or `F({.x = ref x})
struct RefTag {
static constexpr auto Kind = NodeKind::RefTag.Define(
{.category = NodeCategory::Expr, .child_count = 1});
Lex::RefTokenIndex token;
AnyExprId tagged_expr;
};
// A member access expression: `a.b` or `a.(b)`.
struct MemberAccessExpr {
static constexpr auto Kind = NodeKind::MemberAccessExpr.Define(
+1
View File
@@ -47,6 +47,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
case TuplePattern::Kind:
case ValueBindingPattern::Kind:
case ValueParamPattern::Kind:
case VarParamPattern::Kind:
case VarPattern::Kind:
return ExprCategory::NotExpr;
+37
View File
@@ -157,6 +157,43 @@ auto File::OutputYaml(bool include_singletons) const -> Yaml::OutputMapping {
});
}
auto File::CollectRefTagsNeeded() const -> Set<SemIR::InstId> {
CARBON_CHECK(!has_errors_);
Set<SemIR::InstId> ref_tags_needed;
for (auto [id, inst] : insts_.enumerate()) {
if (inst.kind() != SemIR::InstKind::Call) {
continue;
}
auto call_inst = inst.As<SemIR::Call>();
auto callee = SemIR::GetCallee(*this, call_inst.callee_id);
CARBON_KIND_SWITCH(callee) {
case CARBON_KIND(SemIR::CalleeError _):
break;
case CARBON_KIND(SemIR::CalleeNonFunction _):
break;
case CARBON_KIND(SemIR::CalleeCppOverloadSet _): {
// TODO: Perform validation here once we model C++ ref parameters as
// Carbon ref parameters.
break;
}
case CARBON_KIND(SemIR::CalleeFunction fn): {
auto function = functions_.Get(fn.function_id);
auto args = inst_blocks_.GetOrEmpty(call_inst.args_id);
for (auto param_id : llvm::concat<const InstId>(
inst_blocks_.GetOrEmpty(function.implicit_param_patterns_id),
inst_blocks_.GetOrEmpty(function.param_patterns_id))) {
if (auto ref_param_pattern =
insts_.TryGetAs<SemIR::RefParamPattern>(param_id)) {
ref_tags_needed.Insert(args[ref_param_pattern->index.index]);
}
}
break;
}
}
}
return ref_tags_needed;
}
auto File::CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
-> void {
mem_usage.Collect(MemUsage::ConcatLabel(label, "allocator_"), allocator_);
+6
View File
@@ -94,6 +94,12 @@ class File : public Printable<File> {
}
auto OutputYaml(bool include_singletons) const -> Yaml::OutputMapping;
// Returns the set of all insts corresponding to expressions that are used
// in positions where a `ref` tag is needed. Should only be called if
// has_errors is false. This is intended for validation purposes, and should
// only be called if !NDEBUG, because it walks the entire IR.
auto CollectRefTagsNeeded() const -> Set<SemIR::InstId>;
// Collects memory usage of members.
auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
-> void;
+3 -4
View File
@@ -157,11 +157,10 @@ struct AnyParam {
};
// A pattern that represents a `Call` parameter. It delegates to subpattern_id
// in pattern matching. The sub-kinds differ only in the expression category
// of the corresponding parameter inst.
// in pattern matching.
struct AnyParamPattern {
using CategoryInfo =
CategoryOf<OutParamPattern, RefParamPattern, ValueParamPattern>;
using CategoryInfo = CategoryOf<OutParamPattern, RefParamPattern,
ValueParamPattern, VarParamPattern>;
InstKind kind;
+1
View File
@@ -153,6 +153,7 @@ CARBON_SEM_IR_INST_KIND(ValueBindingPattern)
CARBON_SEM_IR_INST_KIND(ValueOfInitializer)
CARBON_SEM_IR_INST_KIND(ValueParam)
CARBON_SEM_IR_INST_KIND(ValueParamPattern)
CARBON_SEM_IR_INST_KIND(VarParamPattern)
CARBON_SEM_IR_INST_KIND(VarPattern)
CARBON_SEM_IR_INST_KIND(VarStorage)
CARBON_SEM_IR_INST_KIND(VtableDecl)
+2 -1
View File
@@ -1153,7 +1153,8 @@ auto InstNamer::NamingContext::NameInst() -> void {
}
case OutParamPattern::Kind:
case RefParamPattern::Kind:
case ValueParamPattern::Kind: {
case ValueParamPattern::Kind:
case VarParamPattern::Kind: {
AddInstNameId(GetPrettyNameFromPatternId(sem_ir(), inst_id_),
".param_patt");
return;
+18 -2
View File
@@ -1296,7 +1296,8 @@ struct RefBindingPattern {
EntityNameId entity_name_id;
};
// A by-reference `Call` parameter. See AnyParam for member documentation.
// A by-reference `Call` parameter. See AnyParam for member documentation. Note
// that this may correspond to either a RefParamPattern or a VarParamPattern.
struct RefParam {
// TODO: Make Parse::NodeId more specific.
static constexpr auto Kind = InstKind::RefParam.Define<Parse::NodeId>(
@@ -1307,7 +1308,7 @@ struct RefParam {
NameId pretty_name_id;
};
// A pattern that represents a by-reference `Call` parameter. See
// A pattern that represents a `ref`-qualified `Call` parameter. See
// `AnyParamPattern` for member documentation.
struct RefParamPattern {
// TODO: Make Parse::NodeId more specific.
@@ -1912,6 +1913,21 @@ struct ValueParamPattern {
CallParamIndex index;
};
// A pattern that represents a `Call` parameter corresponding to a `var`
// pattern. See `AnyParamPattern` for member documentation. Note that there is
// no `VarParam` -- a `VarParamPattern` corresponds to a `RefParam`.
struct VarParamPattern {
static constexpr auto Kind =
InstKind::VarParamPattern.Define<Parse::VariablePatternId>(
{.ir_name = "var_param_pattern",
.constant_kind = InstConstantKind::AlwaysUnique,
.is_lowered = false});
TypeId type_id;
InstId subpattern_id;
CallParamIndex index;
};
// A `var` pattern.
struct VarPattern {
static constexpr auto Kind =