mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:20:10 +01:00
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:
co-authored by
Richard Smith
parent
b36f85c2a5
commit
43ffd721a4
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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:
|
||||
+3
-3
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
@@ -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'
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user