Generate thunks for functions in impls (#5390)

Generate a thunk when a function in an `impl` has a different signature
than the function in the interface. This follows the design in
[#3763](https://docs.carbon-lang.dev/proposals/p3763.html#impl-members-vs-interface-members),
although some of the checks described there are not yet implemented.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Richard Smith
2025-05-01 22:17:55 +00:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent 4f5d11a28b
commit 95903dc624
31 changed files with 3438 additions and 710 deletions
+7 -17
View File
@@ -44,10 +44,12 @@ cc_library(
"name_component.cpp",
"name_lookup.cpp",
"operator.cpp",
"pattern.cpp",
"pattern_match.cpp",
"pointer_dereference.cpp",
"return.cpp",
"subpattern.cpp",
"subst.cpp",
"thunk.cpp",
"type.cpp",
"type_completion.cpp",
"type_structure.cpp",
@@ -86,12 +88,14 @@ cc_library(
"name_lookup.h",
"operator.h",
"param_and_arg_refs_stack.h",
"pattern.h",
"pattern_match.h",
"pending_block.h",
"pointer_dereference.h",
"region_stack.h",
"return.h",
"subpattern.h",
"subst.h",
"thunk.h",
"type.h",
"type_completion.h",
"type_structure.h",
@@ -100,6 +104,7 @@ cc_library(
":node_stack",
"//common:array_stack",
"//common:check",
"//common:find",
"//common:map",
"//common:ostream",
"//common:raw_string_ostream",
@@ -167,7 +172,6 @@ cc_library(
":context",
":diagnostic_emitter",
":dump",
":pointer_dereference",
"//common:check",
"//common:error",
"//common:find",
@@ -238,20 +242,6 @@ cc_library(
],
)
cc_library(
name = "pointer_dereference",
srcs = ["pointer_dereference.cpp"],
hdrs = ["pointer_dereference.h"],
deps = [
":context",
"//common:check",
"//toolchain/parse:node_kind",
"//toolchain/sem_ir:file",
"//toolchain/sem_ir:typed_insts",
"@llvm-project//llvm:Support",
],
)
cc_library(
name = "scope_stack",
srcs = ["scope_stack.cpp"],
+71 -16
View File
@@ -4,29 +4,29 @@
#include "toolchain/check/function.h"
#include "common/find.h"
#include "toolchain/check/merge.h"
#include "toolchain/check/type_completion.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/pattern.h"
namespace Carbon::Check {
auto CheckFunctionTypeMatches(Context& context,
const SemIR::Function& new_function,
const SemIR::Function& prev_function,
SemIR::SpecificId prev_specific_id,
bool check_syntax, bool check_self) -> bool {
// TODO: When check_syntax is false, the functions should be allowed to have
// different signatures as long as we can synthesize a suitable thunk. i.e.,
// when there's an implicit conversion from the original parameter types to
// the overriding parameter types, and from the overriding return type to the
// original return type.
// Also, build that thunk.
if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
DeclParams(prev_function), prev_specific_id,
/*diagnose=*/true, check_syntax, check_self)) {
return false;
}
auto FindSelfPattern(Context& context,
SemIR::InstBlockId implicit_param_patterns_id)
-> SemIR::InstId {
auto implicit_param_patterns =
context.inst_blocks().GetOrEmpty(implicit_param_patterns_id);
return FindIfOrNone(implicit_param_patterns, [&](auto implicit_param_id) {
return SemIR::IsSelfPattern(context.sem_ir(), implicit_param_id);
});
}
auto CheckFunctionReturnTypeMatches(Context& context,
const SemIR::Function& new_function,
const SemIR::Function& prev_function,
SemIR::SpecificId prev_specific_id,
bool diagnose) -> bool {
// TODO: Pass a specific ID for `prev_function` instead of substitutions and
// use it here.
auto new_return_type_id =
@@ -39,6 +39,10 @@ auto CheckFunctionTypeMatches(Context& context,
}
if (!context.types().AreEqualAcrossDeclarations(new_return_type_id,
prev_return_type_id)) {
if (!diagnose) {
return false;
}
CARBON_DIAGNOSTIC(
FunctionRedeclReturnTypeDiffers, Error,
"function redeclaration differs because return type is {0}",
@@ -72,6 +76,21 @@ auto CheckFunctionTypeMatches(Context& context,
return true;
}
auto CheckFunctionTypeMatches(Context& context,
const SemIR::Function& new_function,
const SemIR::Function& prev_function,
SemIR::SpecificId prev_specific_id,
bool check_syntax, bool check_self, bool diagnose)
-> bool {
if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
DeclParams(prev_function), prev_specific_id,
diagnose, check_syntax, check_self)) {
return false;
}
return CheckFunctionReturnTypeMatches(context, new_function, prev_function,
prev_specific_id, diagnose);
}
auto CheckFunctionReturnType(Context& context, SemIR::LocId loc_id,
const SemIR::Function& function,
SemIR::SpecificId specific_id)
@@ -108,4 +127,40 @@ auto CheckFunctionReturnType(Context& context, SemIR::LocId loc_id,
return return_info;
}
auto CheckFunctionDefinitionSignature(Context& context,
SemIR::FunctionId function_id) -> void {
auto& function = context.functions().Get(function_id);
auto params_to_complete =
context.inst_blocks().GetOrEmpty(function.call_params_id);
// Check the return type is complete.
if (function.return_slot_pattern_id.has_value()) {
CheckFunctionReturnType(context,
SemIR::LocId(function.return_slot_pattern_id),
function, SemIR::SpecificId::None);
// Don't re-check the return type below.
params_to_complete = params_to_complete.drop_back();
}
// Check the parameter types are complete.
for (auto param_ref_id : params_to_complete) {
if (param_ref_id == SemIR::ErrorInst::InstId) {
continue;
}
// The parameter types need to be complete.
RequireCompleteType(
context, context.insts().GetAs<SemIR::AnyParam>(param_ref_id).type_id,
SemIR::LocId(param_ref_id), [&] {
CARBON_DIAGNOSTIC(
IncompleteTypeInFunctionParam, Error,
"parameter has incomplete type {0} in function definition",
TypeOfInstId);
return context.emitter().Build(
param_ref_id, IncompleteTypeInFunctionParam, param_ref_id);
});
}
}
} // namespace Carbon::Check
+24 -1
View File
@@ -26,6 +26,22 @@ struct SuspendedFunction {
DeclNameStack::SuspendedName saved_name_state;
};
// Returns the ID of the self parameter pattern, or None.
// TODO: Do this during initial traversal of implicit params.
auto FindSelfPattern(Context& context,
SemIR::InstBlockId implicit_param_patterns_id)
-> SemIR::InstId;
// Checks that `new_function` has the same return type as `prev_function`, or if
// `prev_function_id` is specified, a specific version of `prev_function`.
// Prints a suitable diagnostic and returns false if not. Never checks for a
// syntactic match.
auto CheckFunctionReturnTypeMatches(Context& context,
const SemIR::Function& new_function,
const SemIR::Function& prev_function,
SemIR::SpecificId prev_specific_id,
bool diagnose = true) -> bool;
// Checks that `new_function` has the same parameter types and return type as
// `prev_function`, or if `prev_function_id` is specified, a specific version of
// `prev_function`. Prints a suitable diagnostic and returns false if not.
@@ -38,7 +54,8 @@ auto CheckFunctionTypeMatches(Context& context,
const SemIR::Function& new_function,
const SemIR::Function& prev_function,
SemIR::SpecificId prev_specific_id,
bool check_syntax, bool check_self) -> bool;
bool check_syntax, bool check_self,
bool diagnose = true) -> bool;
inline auto CheckFunctionTypeMatches(Context& context,
const SemIR::Function& new_function,
@@ -58,6 +75,12 @@ auto CheckFunctionReturnType(Context& context, SemIR::LocId loc_id,
SemIR::SpecificId specific_id)
-> SemIR::ReturnTypeInfo;
// Checks that a function declaration's signature is suitable to support a
// function definition. This requires the parameter types to be complete and the
// return type to be concrete.
auto CheckFunctionDefinitionSignature(Context& context,
SemIR::FunctionId function_id) -> void;
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_FUNCTION_H_
+7 -45
View File
@@ -8,8 +8,8 @@
#include "toolchain/check/inst.h"
#include "toolchain/check/interface.h"
#include "toolchain/check/name_lookup.h"
#include "toolchain/check/pattern.h"
#include "toolchain/check/return.h"
#include "toolchain/check/subpattern.h"
#include "toolchain/check/type.h"
#include "toolchain/check/type_completion.h"
#include "toolchain/diagnostics/format_providers.h"
@@ -51,62 +51,24 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
context.decl_introducer_state_stack().innermost();
auto make_binding_pattern = [&]() -> SemIR::InstId {
// bind_id and entity_name_id are not populated if name_id is Underscore.
auto bind_id = SemIR::InstId::None;
// TODO: Eventually the name will need to support associations with other
// scopes, but right now we don't support qualified names here.
auto entity_name_id = SemIR::EntityNameId::None;
entity_name_id = context.entity_names().AddSymbolicBindingName(
name_id, context.scope_stack().PeekNameScopeId(),
is_generic ? context.scope_stack().AddCompileTimeBinding()
: SemIR::CompileTimeBindIndex::None,
is_template);
if (is_generic) {
bind_id = AddInstInNoBlock(
context, name_node,
SemIR::BindSymbolicName{.type_id = cast_type_id,
.entity_name_id = entity_name_id,
.value_id = SemIR::InstId::None});
} else {
bind_id =
AddInstInNoBlock(context, name_node,
SemIR::BindName{.type_id = cast_type_id,
.entity_name_id = entity_name_id,
.value_id = SemIR::InstId::None});
}
auto binding =
AddBindingPattern(context, name_node, name_id, cast_type_id,
type_expr_region_id, is_generic, is_template);
auto pattern_type_id = GetPatternType(context, cast_type_id);
auto binding_pattern_id = SemIR::InstId::None;
if (is_generic) {
binding_pattern_id = AddPatternInst<SemIR::SymbolicBindingPattern>(
context, name_node,
{.type_id = pattern_type_id, .entity_name_id = entity_name_id});
} else {
binding_pattern_id = AddPatternInst<SemIR::BindingPattern>(
context, name_node,
{.type_id = pattern_type_id, .entity_name_id = entity_name_id});
}
if (is_generic) {
context.scope_stack().PushCompileTimeBinding(bind_id);
}
if (name_id != SemIR::NameId::Underscore) {
// Add name to lookup immediately, so it can be used in the rest of the
// enclosing pattern.
auto name_context =
context.decl_name_stack().MakeUnqualifiedName(name_node, name_id);
context.decl_name_stack().AddNameOrDiagnose(
name_context, bind_id, introducer.modifier_set.GetAccessKind());
name_context, binding.bind_id,
introducer.modifier_set.GetAccessKind());
context.full_pattern_stack().AddBindName(name_id);
}
bool inserted = context.bind_name_map()
.Insert(binding_pattern_id,
{.bind_name_id = bind_id,
.type_expr_region_id = type_expr_region_id})
.is_inserted();
CARBON_CHECK(inserted);
return binding_pattern_id;
return binding.pattern_id;
};
// A `self` binding can only appear in an implicit parameter list.
+5 -53
View File
@@ -5,7 +5,6 @@
#include <optional>
#include <utility>
#include "common/find.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/check/context.h"
#include "toolchain/check/control_flow.h"
@@ -34,7 +33,6 @@
#include "toolchain/sem_ir/function.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/inst.h"
#include "toolchain/sem_ir/pattern.h"
#include "toolchain/sem_ir/typed_insts.h"
namespace Carbon::Check {
@@ -85,18 +83,6 @@ auto HandleParseNode(Context& context, Parse::ReturnTypeId node_id) -> bool {
return true;
}
// Returns the ID of the self parameter pattern, or None.
// TODO: Do this during initial traversal of implicit params.
static auto FindSelfPattern(Context& context,
SemIR::InstBlockId implicit_param_patterns_id)
-> SemIR::InstId {
auto implicit_param_patterns =
context.inst_blocks().GetOrEmpty(implicit_param_patterns_id);
return FindIfOrNone(implicit_param_patterns, [&](auto implicit_param_id) {
return SemIR::IsSelfPattern(context.sem_ir(), implicit_param_id);
});
}
// Diagnoses issues with the modifiers, removing modifiers that shouldn't be
// present.
static auto DiagnoseModifiers(Context& context,
@@ -577,55 +563,20 @@ auto HandleParseNode(Context& context, Parse::FunctionDeclId node_id) -> bool {
return true;
}
static auto CheckFunctionDefinitionSignature(Context& context,
SemIR::Function& function)
-> void {
auto params_to_complete =
context.inst_blocks().GetOrEmpty(function.call_params_id);
// Check the return type is complete.
if (function.return_slot_pattern_id.has_value()) {
CheckFunctionReturnType(context,
SemIR::LocId(function.return_slot_pattern_id),
function, SemIR::SpecificId::None);
params_to_complete = params_to_complete.drop_back();
}
// Check the parameter types are complete.
for (auto param_ref_id : params_to_complete) {
if (param_ref_id == SemIR::ErrorInst::InstId) {
continue;
}
// The parameter types need to be complete.
RequireCompleteType(
context, context.insts().GetAs<SemIR::AnyParam>(param_ref_id).type_id,
SemIR::LocId(param_ref_id), [&] {
CARBON_DIAGNOSTIC(
IncompleteTypeInFunctionParam, Error,
"parameter has incomplete type {0} in function definition",
TypeOfInstId);
return context.emitter().Build(
param_ref_id, IncompleteTypeInFunctionParam, param_ref_id);
});
}
}
// Processes a function definition after a signature for which we have already
// built a function ID. This logic is shared between processing regular function
// definitions and delayed parsing of inline method definitions.
static auto HandleFunctionDefinitionAfterSignature(
Context& context, Parse::FunctionDefinitionStartId node_id,
SemIR::FunctionId function_id, SemIR::InstId decl_id) -> void {
auto& function = context.functions().Get(function_id);
// Create the function scope and the entry block.
context.scope_stack().PushForFunctionBody(decl_id);
context.inst_block_stack().Push();
context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
StartGenericDefinition(context, function.generic_id);
StartGenericDefinition(context,
context.functions().Get(function_id).generic_id);
CheckFunctionDefinitionSignature(context, function);
CheckFunctionDefinitionSignature(context, function_id);
context.node_stack().Push(node_id, function_id);
}
@@ -765,8 +716,9 @@ auto HandleParseNode(Context& context,
auto builtin_kind = LookupBuiltinFunctionKind(context, name_id);
if (builtin_kind != SemIR::BuiltinFunctionKind::None) {
CheckFunctionDefinitionSignature(context, function_id);
auto& function = context.functions().Get(function_id);
CheckFunctionDefinitionSignature(context, function);
if (IsValidBuiltinDeclaration(context, function, builtin_kind)) {
function.builtin_function_kind = builtin_kind;
// Build an empty generic definition if this is a generic builtin.
+2 -2
View File
@@ -564,9 +564,9 @@ auto HandleParseNode(Context& context, Parse::ImplDefinitionId /*node_id*/)
auto impl_id =
context.node_stack().Pop<Parse::NodeKind::ImplDefinitionStart>();
FinishImplWitness(context, impl_id);
auto& impl_info = context.impls().Get(impl_id);
CARBON_CHECK(!impl_info.is_complete());
FinishImplWitness(context, impl_info);
impl_info.defined = true;
FinishGenericDefinition(context, impl_info.generic_id);
+1 -1
View File
@@ -14,9 +14,9 @@
#include "toolchain/check/interface.h"
#include "toolchain/check/keyword_modifier_set.h"
#include "toolchain/check/modifiers.h"
#include "toolchain/check/pattern.h"
#include "toolchain/check/pattern_match.h"
#include "toolchain/check/return.h"
#include "toolchain/check/subpattern.h"
#include "toolchain/diagnostics/diagnostic_emitter.h"
#include "toolchain/diagnostics/format_providers.h"
#include "toolchain/lex/token_kind.h"
+1 -1
View File
@@ -5,7 +5,7 @@
#include "toolchain/check/context.h"
#include "toolchain/check/handle.h"
#include "toolchain/check/inst.h"
#include "toolchain/check/subpattern.h"
#include "toolchain/check/pattern.h"
#include "toolchain/check/type.h"
namespace Carbon::Check {
+8 -9
View File
@@ -14,6 +14,7 @@
#include "toolchain/check/inst.h"
#include "toolchain/check/interface.h"
#include "toolchain/check/name_lookup.h"
#include "toolchain/check/thunk.h"
#include "toolchain/check/type.h"
#include "toolchain/check/type_completion.h"
#include "toolchain/diagnostics/diagnostic_emitter.h"
@@ -76,14 +77,8 @@ static auto CheckAssociatedFunctionImplementation(
.generic_id,
impl_enclosing_specific_id, self_type_id, witness_inst_id);
if (!CheckFunctionTypeMatches(
context, context.functions().Get(impl_function_decl->function_id),
context.functions().Get(interface_function_type.function_id),
interface_function_specific_id, /*check_syntax=*/false,
/*check_self=*/true)) {
return SemIR::ErrorInst::InstId;
}
return impl_decl_id;
return BuildThunk(context, interface_function_type.function_id,
interface_function_specific_id, impl_decl_id);
}
// Builds an initial witness from the rewrites in the facet type, if any.
@@ -168,7 +163,11 @@ auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void {
// Adds functions to the witness that the specified impl implements the given
// interface.
auto FinishImplWitness(Context& context, SemIR::Impl& impl) -> void {
auto FinishImplWitness(Context& context, SemIR::ImplId impl_id) -> void {
// Make a copy of the impl. We're going to reference it a lot, and `impl`s
// could get invalidated by some of the things we do.
const auto impl = context.impls().Get(impl_id);
CARBON_CHECK(impl.is_being_defined());
CARBON_CHECK(impl.witness_id.has_value());
if (impl.witness_id == SemIR::ErrorInst::InstId) {
+1 -1
View File
@@ -21,7 +21,7 @@ auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl,
auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void;
// Adds the function members to the witness for `impl`.
auto FinishImplWitness(Context& context, SemIR::Impl& impl) -> void;
auto FinishImplWitness(Context& context, SemIR::ImplId impl_id) -> void;
// Sets all unset members of the witness for `impl` to the error instruction.
auto FillImplWitnessWithErrors(Context& context, SemIR::Impl& impl) -> void;
+5 -6
View File
@@ -132,12 +132,11 @@ auto AddPatternInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
// Convenience for AddPatternInst with typed nodes.
//
// As a safety check, prevent use with storage insts (see `AddInstWithCleanup`).
template <typename InstT>
requires(SemIR::Internal::HasNodeId<InstT> && !InstT::Kind.has_cleanup())
auto AddPatternInst(Context& context,
typename decltype(InstT::Kind)::TypedNodeId node_id,
InstT inst) -> SemIR::InstId {
return AddPatternInst(context, SemIR::LocIdAndInst(node_id, inst));
template <typename InstT, typename LocT>
requires(!InstT::Kind.has_cleanup() &&
std::convertible_to<LocT, SemIR::LocId>)
auto AddPatternInst(Context& context, LocT loc, InstT inst) -> SemIR::InstId {
return AddPatternInst(context, SemIR::LocIdAndInst(loc, inst));
}
// Adds an instruction to the current block, returning the produced ID. The
+99
View File
@@ -0,0 +1,99 @@
// 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/check/pattern.h"
#include "toolchain/check/inst.h"
#include "toolchain/check/type.h"
namespace Carbon::Check {
auto BeginSubpattern(Context& context) -> void {
context.inst_block_stack().Push();
context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
}
auto EndSubpatternAsExpr(Context& context, SemIR::InstId result_id)
-> SemIR::ExprRegionId {
if (context.region_stack().PeekRegion().size() > 1) {
// End the exit block with a branch to a successor block, whose contents
// will be determined later.
AddInst(context,
SemIR::LocIdAndInst::NoLoc<SemIR::Branch>(
{.target_id = context.inst_blocks().AddPlaceholder()}));
} else {
// This single-block region will be inserted as a SpliceBlock, so we don't
// need control flow out of it.
}
auto block_id = context.inst_block_stack().Pop();
CARBON_CHECK(block_id == context.region_stack().PeekRegion().back());
// TODO: Is it possible to validate that this region is genuinely
// single-entry, single-exit?
return context.sem_ir().expr_regions().Add(
{.block_ids = context.region_stack().PopRegion(),
.result_id = result_id});
}
auto EndSubpatternAsNonExpr(Context& context) -> void {
auto block_id = context.inst_block_stack().Pop();
CARBON_CHECK(block_id == context.region_stack().PeekRegion().back());
CARBON_CHECK(context.region_stack().PeekRegion().size() == 1);
// TODO: Add `CARBON_CHECK(inst_blocks().Get(block_id).empty())`.
// Currently that can fail when ending a tuple pattern in a name binding
// decl in a class or interface.
context.region_stack().PopAndDiscardRegion();
}
auto AddBindingPattern(Context& context, SemIR::LocId name_loc,
SemIR::NameId name_id, SemIR::TypeId type_id,
SemIR::ExprRegionId type_region_id, bool is_generic,
bool is_template) -> BindingPatternInfo {
auto entity_name_id = context.entity_names().AddSymbolicBindingName(
name_id, context.scope_stack().PeekNameScopeId(),
is_generic ? context.scope_stack().AddCompileTimeBinding()
: SemIR::CompileTimeBindIndex::None,
is_template);
auto bind_id = SemIR::InstId::None;
if (is_generic) {
bind_id = AddInstInNoBlock<SemIR::BindSymbolicName>(
context, name_loc,
{.type_id = type_id,
.entity_name_id = entity_name_id,
.value_id = SemIR::InstId::None});
} else {
bind_id =
AddInstInNoBlock<SemIR::BindName>(context, name_loc,
{.type_id = type_id,
.entity_name_id = entity_name_id,
.value_id = SemIR::InstId::None});
}
auto pattern_type_id = GetPatternType(context, type_id);
auto binding_pattern_id = SemIR::InstId::None;
if (is_generic) {
binding_pattern_id = AddPatternInst<SemIR::SymbolicBindingPattern>(
context, name_loc,
{.type_id = pattern_type_id, .entity_name_id = entity_name_id});
} else {
binding_pattern_id = AddPatternInst<SemIR::BindingPattern>(
context, name_loc,
{.type_id = pattern_type_id, .entity_name_id = entity_name_id});
}
if (is_generic) {
context.scope_stack().PushCompileTimeBinding(bind_id);
}
bool inserted =
context.bind_name_map()
.Insert(binding_pattern_id, {.bind_name_id = bind_id,
.type_expr_region_id = type_region_id})
.is_inserted();
CARBON_CHECK(inserted);
return {.pattern_id = binding_pattern_id, .bind_id = bind_id};
}
} // namespace Carbon::Check
@@ -2,8 +2,8 @@
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CARBON_TOOLCHAIN_CHECK_SUBPATTERN_H_
#define CARBON_TOOLCHAIN_CHECK_SUBPATTERN_H_
#ifndef CARBON_TOOLCHAIN_CHECK_PATTERN_H_
#define CARBON_TOOLCHAIN_CHECK_PATTERN_H_
#include "toolchain/check/context.h"
#include "toolchain/sem_ir/ids.h"
@@ -27,8 +27,21 @@ auto EndSubpatternAsExpr(Context& context, SemIR::InstId result_id)
// it had no expression content.
auto EndSubpatternAsNonExpr(Context& context) -> void;
// Information about a created binding pattern.
struct BindingPatternInfo {
SemIR::InstId pattern_id;
SemIR::InstId bind_id;
};
// TODO: Add EndSubpatternAsPattern, when needed.
// Creates a binding pattern. Returns the binding pattern and the bind name
// instruction.
auto AddBindingPattern(Context& context, SemIR::LocId name_loc,
SemIR::NameId name_id, SemIR::TypeId type_id,
SemIR::ExprRegionId type_region_id, bool is_generic,
bool is_template) -> BindingPatternInfo;
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_SUBPATTERN_H_
#endif // CARBON_TOOLCHAIN_CHECK_PATTERN_H_
+1 -1
View File
@@ -14,7 +14,7 @@
#include "toolchain/check/context.h"
#include "toolchain/check/control_flow.h"
#include "toolchain/check/convert.h"
#include "toolchain/check/subpattern.h"
#include "toolchain/check/pattern.h"
#include "toolchain/check/type.h"
#include "toolchain/diagnostics/format_providers.h"
#include "toolchain/sem_ir/expr_info.h"
+3 -4
View File
@@ -14,13 +14,12 @@
namespace Carbon::Check {
auto PerformPointerDereference(
Context& context, Parse::AnyPointerDeferenceExprId node_id,
SemIR::InstId base_id,
Context& context, SemIR::LocId loc_id, SemIR::InstId base_id,
llvm::function_ref<auto(SemIR::TypeId not_pointer_type_id)->void>
diagnose_not_pointer) -> SemIR::InstId {
// TODO: Once we have a finalized design for a pointer interface, use
//
// HandleUnaryOperator(context, node_id, {"Pointer", "Dereference"});
// HandleUnaryOperator(context, loc_id, {"Pointer", "Dereference"});
//
// to convert to a pointer value.
base_id = ConvertToValueExpr(context, base_id);
@@ -35,7 +34,7 @@ auto PerformPointerDereference(
diagnose_not_pointer(type_id);
}
return AddInst<SemIR::Deref>(
context, node_id, {.type_id = result_type_id, .pointer_id = base_id});
context, loc_id, {.type_id = result_type_id, .pointer_id = base_id});
}
} // namespace Carbon::Check
+1 -2
View File
@@ -15,8 +15,7 @@ namespace Carbon::Check {
// Creates SemIR to perform a pointer dereference with base expression
// `base_id`. Returns the result of the access.
auto PerformPointerDereference(
Context& context, Parse::AnyPointerDeferenceExprId node_id,
SemIR::InstId base_i,
Context& context, SemIR::LocId loc_id, SemIR::InstId base_i,
llvm::function_ref<auto(SemIR::TypeId not_pointer_type_id)->void>
diagnose_not_pointer) -> SemIR::InstId;
+9 -10
View File
@@ -113,23 +113,22 @@ auto RegisterReturnedVar(Context& context, Parse::NodeId returned_node,
}
}
auto BuildReturnWithNoExpr(Context& context, Parse::ReturnStatementId node_id)
-> void {
auto BuildReturnWithNoExpr(Context& context, SemIR::LocId loc_id) -> void {
const auto& function = GetCurrentFunctionForReturn(context);
auto return_type_id = function.GetDeclaredReturnType(context.sem_ir());
if (return_type_id.has_value()) {
CARBON_DIAGNOSTIC(ReturnStatementMissingExpr, Error,
"missing return value");
auto diag = context.emitter().Build(node_id, ReturnStatementMissingExpr);
auto diag = context.emitter().Build(loc_id, ReturnStatementMissingExpr);
NoteReturnType(context, diag, function);
diag.Emit();
}
AddInst<SemIR::Return>(context, node_id, {});
AddInst<SemIR::Return>(context, loc_id, {});
}
auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
auto BuildReturnWithExpr(Context& context, SemIR::LocId loc_id,
SemIR::InstId expr_id) -> void {
const auto& function = GetCurrentFunctionForReturn(context);
auto returned_var_id = GetCurrentReturnedVar(context);
@@ -141,7 +140,7 @@ auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
CARBON_DIAGNOSTIC(
ReturnStatementDisallowExpr, Error,
"no return expression should be provided in this context");
auto diag = context.emitter().Build(node_id, ReturnStatementDisallowExpr);
auto diag = context.emitter().Build(loc_id, ReturnStatementDisallowExpr);
NoteNoReturnTypeProvided(diag, function);
diag.Emit();
expr_id = SemIR::ErrorInst::InstId;
@@ -149,7 +148,7 @@ auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
CARBON_DIAGNOSTIC(
ReturnExprWithReturnedVar, Error,
"can only `return var;` in the scope of a `returned var`");
auto diag = context.emitter().Build(node_id, ReturnExprWithReturnedVar);
auto diag = context.emitter().Build(loc_id, ReturnExprWithReturnedVar);
NoteReturnedVar(diag, returned_var_id);
diag.Emit();
expr_id = SemIR::ErrorInst::InstId;
@@ -161,13 +160,13 @@ auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
return_slot_id = GetCurrentReturnSlot(context);
CARBON_CHECK(return_slot_id.has_value());
// Note that this can import a function and invalidate `function`.
expr_id = Initialize(context, node_id, return_slot_id, expr_id);
expr_id = Initialize(context, loc_id, return_slot_id, expr_id);
} else {
expr_id =
ConvertToValueOfType(context, node_id, expr_id, return_info.type_id);
ConvertToValueOfType(context, loc_id, expr_id, return_info.type_id);
}
AddInst<SemIR::ReturnExpr>(context, node_id,
AddInst<SemIR::ReturnExpr>(context, loc_id,
{.expr_id = expr_id, .dest_id = return_slot_id});
}
+2 -3
View File
@@ -25,11 +25,10 @@ auto RegisterReturnedVar(Context& context, Parse::NodeId returned_node,
SemIR::InstId bind_id) -> void;
// Checks and builds SemIR for a `return;` statement.
auto BuildReturnWithNoExpr(Context& context, Parse::ReturnStatementId node_id)
-> void;
auto BuildReturnWithNoExpr(Context& context, SemIR::LocId loc_id) -> void;
// Checks and builds SemIR for a `return <expression>;` statement.
auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
auto BuildReturnWithExpr(Context& context, SemIR::LocId loc_id,
SemIR::InstId expr_id) -> void;
// Checks and builds SemIR for a `return var;` statement.
-48
View File
@@ -1,48 +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/check/subpattern.h"
#include "toolchain/check/inst.h"
namespace Carbon::Check {
auto BeginSubpattern(Context& context) -> void {
context.inst_block_stack().Push();
context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
}
auto EndSubpatternAsExpr(Context& context, SemIR::InstId result_id)
-> SemIR::ExprRegionId {
if (context.region_stack().PeekRegion().size() > 1) {
// End the exit block with a branch to a successor block, whose contents
// will be determined later.
AddInst(context,
SemIR::LocIdAndInst::NoLoc<SemIR::Branch>(
{.target_id = context.inst_blocks().AddPlaceholder()}));
} else {
// This single-block region will be inserted as a SpliceBlock, so we don't
// need control flow out of it.
}
auto block_id = context.inst_block_stack().Pop();
CARBON_CHECK(block_id == context.region_stack().PeekRegion().back());
// TODO: Is it possible to validate that this region is genuinely
// single-entry, single-exit?
return context.sem_ir().expr_regions().Add(
{.block_ids = context.region_stack().PopRegion(),
.result_id = result_id});
}
auto EndSubpatternAsNonExpr(Context& context) -> void {
auto block_id = context.inst_block_stack().Pop();
CARBON_CHECK(block_id == context.region_stack().PeekRegion().back());
CARBON_CHECK(context.region_stack().PeekRegion().size() == 1);
// TODO: Add `CARBON_CHECK(inst_blocks().Get(block_id).empty())`.
// Currently that can fail when ending a tuple pattern in a name binding
// decl in a class or interface.
context.region_stack().PopAndDiscardRegion();
}
} // namespace Carbon::Check
+27 -7
View File
@@ -32,6 +32,7 @@ fn InstanceCall(n: i32) {
// CHECK:STDOUT: %Self.as_type.716: type = facet_access_type %Self.3c9 [symbolic]
// CHECK:STDOUT: %pattern_type.f88: type = pattern_type %Self.as_type.716 [symbolic]
// CHECK:STDOUT: %G.type.b60: type = fn_type @G.1 [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %G.cb0: %G.type.b60 = struct_value () [concrete]
// CHECK:STDOUT: %Simple.assoc_type: type = assoc_entity_type @Simple [concrete]
// CHECK:STDOUT: %assoc0.db2: %Simple.assoc_type = assoc_entity element0, @Simple.%G.decl [concrete]
@@ -40,13 +41,15 @@ fn InstanceCall(n: i32) {
// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %Simple.impl_witness: <witness> = impl_witness file.%Simple.impl_witness_table [concrete]
// CHECK:STDOUT: %G.type.c98: type = fn_type @G.2 [concrete]
// CHECK:STDOUT: %G.e73: %G.type.c98 = struct_value () [concrete]
// CHECK:STDOUT: %G.type.c9825d.1: type = fn_type @G.2 [concrete]
// CHECK:STDOUT: %G.e73e91.1: %G.type.c9825d.1 = struct_value () [concrete]
// CHECK:STDOUT: %Simple.facet: %Simple.type = facet_value %i32, (%Simple.impl_witness) [concrete]
// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete]
// CHECK:STDOUT: %G.type.c9825d.2: type = fn_type @G.3 [concrete]
// CHECK:STDOUT: %G.e73e91.2: %G.type.c9825d.2 = struct_value () [concrete]
// CHECK:STDOUT: %InstanceCall.type: type = fn_type @InstanceCall [concrete]
// CHECK:STDOUT: %InstanceCall: %InstanceCall.type = struct_value () [concrete]
// CHECK:STDOUT: %.0aa: type = fn_type_with_self_type %G.type.b60, %Simple.facet [concrete]
// CHECK:STDOUT: %.8e6: type = fn_type_with_self_type %G.type.b60, %Simple.facet [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -72,7 +75,7 @@ fn InstanceCall(n: i32) {
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %Simple.ref: type = name_ref Simple, file.%Simple.decl [concrete = constants.%Simple.type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %Simple.impl_witness_table = impl_witness_table (<error>), @impl.006 [concrete]
// CHECK:STDOUT: %Simple.impl_witness_table = impl_witness_table (@impl.006.%G.decl.loc20_27.2), @impl.006 [concrete]
// CHECK:STDOUT: %Simple.impl_witness: <witness> = impl_witness %Simple.impl_witness_table [concrete = constants.%Simple.impl_witness]
// CHECK:STDOUT: %InstanceCall.decl: %InstanceCall.type = fn_decl @InstanceCall [concrete = constants.%InstanceCall] {
// CHECK:STDOUT: %n.patt: %pattern_type.7ce = binding_pattern n [concrete]
@@ -110,7 +113,7 @@ fn InstanceCall(n: i32) {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl.006: %i32 as %Simple.ref {
// CHECK:STDOUT: %G.decl: %G.type.c98 = fn_decl @G.2 [concrete = constants.%G.e73] {
// CHECK:STDOUT: %G.decl.loc20_27.1: %G.type.c9825d.1 = fn_decl @G.2 [concrete = constants.%G.e73e91.1] {
// CHECK:STDOUT: %self.patt: <error> = binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: <error> = value_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
@@ -118,10 +121,17 @@ fn InstanceCall(n: i32) {
// CHECK:STDOUT: %Undeclared.ref: <error> = name_ref Undeclared, <error> [concrete = <error>]
// CHECK:STDOUT: %self: <error> = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %G.decl.loc20_27.2: %G.type.c9825d.2 = fn_decl @G.3 [concrete = constants.%G.e73e91.2] {
// CHECK:STDOUT: %self.patt: %pattern_type.7ce = binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type.7ce = value_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %i32 = value_param call_param0
// CHECK:STDOUT: %self: %i32 = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Undeclared = <poisoned>
// CHECK:STDOUT: .G = %G.decl
// CHECK:STDOUT: .G = %G.decl.loc20_27.1
// CHECK:STDOUT: witness = file.%Simple.impl_witness
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -135,12 +145,22 @@ fn InstanceCall(n: i32) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @G.2(%self.param: <error>);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @G.3(%self.param: %i32) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: %i32 = name_ref self, %self.param
// CHECK:STDOUT: %G.bound: <bound method> = bound_method %self.ref, @impl.006.%G.decl.loc20_27.1
// CHECK:STDOUT: %G.call: init %empty_tuple.type = call %G.bound(<error>)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @InstanceCall(%n.param: %i32) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %n.ref: %i32 = name_ref n, %n
// CHECK:STDOUT: %Simple.ref: type = name_ref Simple, file.%Simple.decl [concrete = constants.%Simple.type]
// CHECK:STDOUT: %G.ref: %Simple.assoc_type = name_ref G, @Simple.%assoc0 [concrete = constants.%assoc0.db2]
// CHECK:STDOUT: %impl.elem0: %.0aa = impl_witness_access constants.%Simple.impl_witness, element0 [concrete = <error>]
// CHECK:STDOUT: %impl.elem0: %.8e6 = impl_witness_access constants.%Simple.impl_witness, element0 [concrete = constants.%G.e73e91.2]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %n.ref, %impl.elem0
// CHECK:STDOUT: %G.call: init %empty_tuple.type = call %bound_method(%n.ref)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
File diff suppressed because it is too large Load Diff
+86 -54
View File
@@ -12,6 +12,12 @@ class C[T:! type](X:! T) {}
interface I {
// Uses of `Self` inside the definition of `I` have type `I`.
// CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE+6]]:8: error: cannot implicitly convert expression of type `C(i32 as I)` to `C(i32)` [ConversionFailure]
// CHECK:STDERR: fn F(c: C(Self));
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE+3]]:8: note: type `C(i32 as I)` does not implement interface `Core.ImplicitAs(C(i32))` [MissingImplInMemberAccessNote]
// CHECK:STDERR: fn F(c: C(Self));
// CHECK:STDERR: ^~~~~~~~~~
fn F(c: C(Self));
}
@@ -23,12 +29,12 @@ impl bool as I {
}
impl i32 as I {
// CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE+7]]:8: error: type `<pattern for C(i32)>` of parameter 1 in redeclaration differs from previous parameter type `<pattern for C(i32 as I)>` [RedeclParamDiffersType]
// CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE+7]]:8: note: initializing function parameter [InCallToFunctionParam]
// CHECK:STDERR: fn F(c: C(i32));
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE-14]]:8: note: previous declaration's corresponding parameter here [RedeclParamPrevious]
// CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE-14]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
// CHECK:STDERR: fn F(c: C(Self));
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn F(c: C(i32));
}
@@ -39,24 +45,25 @@ impl i32 as I {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic]
// CHECK:STDOUT: %pattern_type.98f: type = pattern_type type [concrete]
// CHECK:STDOUT: %X: %T = bind_symbolic_name X, 1 [symbolic]
// CHECK:STDOUT: %pattern_type.7dc: type = pattern_type %T [symbolic]
// CHECK:STDOUT: %pattern_type.7dcd0a.1: type = pattern_type %T [symbolic]
// CHECK:STDOUT: %C.type: type = generic_class_type @C [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C.generic: %C.type = struct_value () [concrete]
// CHECK:STDOUT: %C.b36: type = class_type @C, @C(%T, %X) [symbolic]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
// CHECK:STDOUT: %I.type: type = facet_type <@I> [concrete]
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
// CHECK:STDOUT: %Self.826: %I.type = bind_symbolic_name Self, 0 [symbolic]
// CHECK:STDOUT: %pattern_type.2b5: type = pattern_type %I.type [concrete]
// CHECK:STDOUT: %C.dbb: type = class_type @C, @C(%I.type, %Self) [symbolic]
// CHECK:STDOUT: %C.dbb: type = class_type @C, @C(%I.type, %Self.826) [symbolic]
// CHECK:STDOUT: %pattern_type.4fb: type = pattern_type %C.dbb [symbolic]
// CHECK:STDOUT: %F.type.cf0: type = fn_type @F.1 [concrete]
// CHECK:STDOUT: %F.bc6: %F.type.cf0 = struct_value () [concrete]
// CHECK:STDOUT: %I.assoc_type: type = assoc_entity_type @I [concrete]
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, @I.%F.decl [concrete]
// CHECK:STDOUT: %assoc0.82e: %I.assoc_type = assoc_entity element0, @I.%F.decl [concrete]
// CHECK:STDOUT: %Bool.type: type = fn_type @Bool [concrete]
// CHECK:STDOUT: %Bool: %Bool.type = struct_value () [concrete]
// CHECK:STDOUT: %I.impl_witness.c21: <witness> = impl_witness file.%I.impl_witness_table.loc18 [concrete]
// CHECK:STDOUT: %I.impl_witness.c21: <witness> = impl_witness file.%I.impl_witness_table.loc24 [concrete]
// CHECK:STDOUT: %I.facet.e8a: %I.type = facet_value bool, (%I.impl_witness.c21) [concrete]
// CHECK:STDOUT: %C.7db: type = class_type @C, @C(%I.type, %I.facet.e8a) [concrete]
// CHECK:STDOUT: %pattern_type.225: type = pattern_type %C.7db [concrete]
@@ -66,25 +73,31 @@ impl i32 as I {
// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete]
// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %I.impl_witness.d39: <witness> = impl_witness file.%I.impl_witness_table.loc25 [concrete]
// CHECK:STDOUT: %I.impl_witness.863: <witness> = impl_witness file.%I.impl_witness_table.loc31 [concrete]
// CHECK:STDOUT: %C.6fb: type = class_type @C, @C(type, %i32) [concrete]
// CHECK:STDOUT: %pattern_type.52b: type = pattern_type %C.6fb [concrete]
// CHECK:STDOUT: %F.type.066: type = fn_type @F.3 [concrete]
// CHECK:STDOUT: %F.9ec: %F.type.066 = struct_value () [concrete]
// CHECK:STDOUT: %I.facet.8b2: %I.type = facet_value %i32, (%I.impl_witness.d39) [concrete]
// CHECK:STDOUT: %C.835: type = class_type @C, @C(%I.type, %I.facet.8b2) [concrete]
// CHECK:STDOUT: %pattern_type.023: type = pattern_type %C.835 [concrete]
// CHECK:STDOUT: %F.type.066a53.1: type = fn_type @F.3 [concrete]
// CHECK:STDOUT: %F.9ec58f.1: %F.type.066a53.1 = struct_value () [concrete]
// CHECK:STDOUT: %I.facet.118: %I.type = facet_value %i32, (%I.impl_witness.863) [concrete]
// CHECK:STDOUT: %C.d88: type = class_type @C, @C(%I.type, %I.facet.118) [concrete]
// CHECK:STDOUT: %pattern_type.c65: type = pattern_type %C.d88 [concrete]
// CHECK:STDOUT: %F.type.066a53.2: type = fn_type @F.4 [concrete]
// CHECK:STDOUT: %F.9ec58f.2: %F.type.066a53.2 = struct_value () [concrete]
// CHECK:STDOUT: %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete]
// CHECK:STDOUT: %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
// CHECK:STDOUT: .Bool = %Core.Bool
// CHECK:STDOUT: .Int = %Core.Int
// CHECK:STDOUT: .ImplicitAs = %Core.ImplicitAs
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.Bool: %Bool.type = import_ref Core//prelude/types/bool, Bool, loaded [concrete = constants.%Bool]
// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/types/int, Int, loaded [concrete = constants.%Int.generic]
// CHECK:STDOUT: %Core.ImplicitAs: %ImplicitAs.type.cc7 = import_ref Core//prelude/operators/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -96,7 +109,7 @@ impl i32 as I {
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %C.decl: %C.type = class_decl @C [concrete = constants.%C.generic] {
// CHECK:STDOUT: %T.patt: %pattern_type.98f = symbolic_binding_pattern T, 0 [concrete]
// CHECK:STDOUT: %X.patt: @C.%pattern_type (%pattern_type.7dc) = symbolic_binding_pattern X, 1 [concrete]
// CHECK:STDOUT: %X.patt: @C.%pattern_type (%pattern_type.7dcd0a.1) = symbolic_binding_pattern X, 1 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %T.loc11_9.1: type = bind_symbolic_name T, 0 [symbolic = %T.loc11_9.2 (constants.%T)]
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc11_9.1 [symbolic = %T.loc11_9.2 (constants.%T)]
@@ -105,36 +118,36 @@ impl i32 as I {
// CHECK:STDOUT: %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
// CHECK:STDOUT: impl_decl @impl.049 [concrete] {} {
// CHECK:STDOUT: %bool.make_type: init type = call constants.%Bool() [concrete = bool]
// CHECK:STDOUT: %.loc18_6.1: type = value_of_initializer %bool.make_type [concrete = bool]
// CHECK:STDOUT: %.loc18_6.2: type = converted %bool.make_type, %.loc18_6.1 [concrete = bool]
// CHECK:STDOUT: %.loc24_6.1: type = value_of_initializer %bool.make_type [concrete = bool]
// CHECK:STDOUT: %.loc24_6.2: type = converted %bool.make_type, %.loc24_6.1 [concrete = bool]
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %I.impl_witness_table.loc18 = impl_witness_table (@impl.049.%F.decl), @impl.049 [concrete]
// CHECK:STDOUT: %I.impl_witness.loc18: <witness> = impl_witness %I.impl_witness_table.loc18 [concrete = constants.%I.impl_witness.c21]
// CHECK:STDOUT: %I.impl_witness_table.loc24 = impl_witness_table (@impl.049.%F.decl), @impl.049 [concrete]
// CHECK:STDOUT: %I.impl_witness.loc24: <witness> = impl_witness %I.impl_witness_table.loc24 [concrete = constants.%I.impl_witness.c21]
// CHECK:STDOUT: impl_decl @impl.a9a [concrete] {} {
// 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: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %I.impl_witness_table.loc25 = impl_witness_table (<error>), @impl.a9a [concrete]
// CHECK:STDOUT: %I.impl_witness.loc25: <witness> = impl_witness %I.impl_witness_table.loc25 [concrete = constants.%I.impl_witness.d39]
// CHECK:STDOUT: %I.impl_witness_table.loc31 = impl_witness_table (@impl.a9a.%F.decl.loc39_18.2), @impl.a9a [concrete]
// CHECK:STDOUT: %I.impl_witness.loc31: <witness> = impl_witness %I.impl_witness_table.loc31 [concrete = constants.%I.impl_witness.863]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @I {
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.826]
// CHECK:STDOUT: %F.decl: %F.type.cf0 = fn_decl @F.1 [concrete = constants.%F.bc6] {
// CHECK:STDOUT: %c.patt: @F.1.%pattern_type (%pattern_type.4fb) = binding_pattern c [concrete]
// CHECK:STDOUT: %c.param_patt: @F.1.%pattern_type (%pattern_type.4fb) = value_param_pattern %c.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %c.param: @F.1.%C.loc15_17.1 (%C.dbb) = value_param call_param0
// CHECK:STDOUT: %.loc15: type = splice_block %C.loc15_17.2 [symbolic = %C.loc15_17.1 (constants.%C.dbb)] {
// CHECK:STDOUT: %c.param: @F.1.%C.loc21_17.1 (%C.dbb) = value_param call_param0
// CHECK:STDOUT: %.loc21: type = splice_block %C.loc21_17.2 [symbolic = %C.loc21_17.1 (constants.%C.dbb)] {
// CHECK:STDOUT: %C.ref: %C.type = name_ref C, file.%C.decl [concrete = constants.%C.generic]
// CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)]
// CHECK:STDOUT: %C.loc15_17.2: type = class_type @C, @C(constants.%I.type, constants.%Self) [symbolic = %C.loc15_17.1 (constants.%C.dbb)]
// CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self.826)]
// CHECK:STDOUT: %C.loc21_17.2: type = class_type @C, @C(constants.%I.type, constants.%Self.826) [symbolic = %C.loc21_17.1 (constants.%C.dbb)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %c: @F.1.%C.loc15_17.1 (%C.dbb) = bind_name c, %c.param
// CHECK:STDOUT: %c: @F.1.%C.loc21_17.1 (%C.dbb) = bind_name c, %c.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0.82e]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self
@@ -143,18 +156,18 @@ impl i32 as I {
// CHECK:STDOUT: witness = (%F.decl)
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl.049: %.loc18_6.2 as %I.ref {
// CHECK:STDOUT: impl @impl.049: %.loc24_6.2 as %I.ref {
// CHECK:STDOUT: %F.decl: %F.type.8ba = fn_decl @F.2 [concrete = constants.%F.2cf] {
// CHECK:STDOUT: %c.patt: %pattern_type.225 = binding_pattern c [concrete]
// CHECK:STDOUT: %c.param_patt: %pattern_type.225 = value_param_pattern %c.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %c.param: %C.7db = value_param call_param0
// CHECK:STDOUT: %.loc22_22: type = splice_block %C [concrete = constants.%C.7db] {
// CHECK:STDOUT: %.loc28_22: type = splice_block %C [concrete = constants.%C.7db] {
// CHECK:STDOUT: %C.ref: %C.type = name_ref C, file.%C.decl [concrete = constants.%C.generic]
// CHECK:STDOUT: %bool.make_type: init type = call constants.%Bool() [concrete = bool]
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
// CHECK:STDOUT: %I.facet: %I.type = facet_value bool, (constants.%I.impl_witness.c21) [concrete = constants.%I.facet.e8a]
// CHECK:STDOUT: %.loc22_18: %I.type = converted %bool.make_type, %I.facet [concrete = constants.%I.facet.e8a]
// CHECK:STDOUT: %.loc28_18: %I.type = converted %bool.make_type, %I.facet [concrete = constants.%I.facet.e8a]
// CHECK:STDOUT: %C: type = class_type @C, @C(constants.%I.type, constants.%I.facet.e8a) [concrete = constants.%C.7db]
// CHECK:STDOUT: }
// CHECK:STDOUT: %c: %C.7db = bind_name c, %c.param
@@ -164,16 +177,16 @@ impl i32 as I {
// CHECK:STDOUT: .C = <poisoned>
// CHECK:STDOUT: .I = <poisoned>
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: witness = file.%I.impl_witness.loc18
// CHECK:STDOUT: witness = file.%I.impl_witness.loc24
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl.a9a: %i32 as %I.ref {
// CHECK:STDOUT: %F.decl: %F.type.066 = fn_decl @F.3 [concrete = constants.%F.9ec] {
// CHECK:STDOUT: %F.decl.loc39_18.1: %F.type.066a53.1 = fn_decl @F.3 [concrete = constants.%F.9ec58f.1] {
// CHECK:STDOUT: %c.patt: %pattern_type.52b = binding_pattern c [concrete]
// CHECK:STDOUT: %c.param_patt: %pattern_type.52b = value_param_pattern %c.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %c.param: %C.6fb = value_param call_param0
// CHECK:STDOUT: %.loc33: type = splice_block %C [concrete = constants.%C.6fb] {
// CHECK:STDOUT: %.loc39: type = splice_block %C [concrete = constants.%C.6fb] {
// CHECK:STDOUT: %C.ref: %C.type = name_ref C, file.%C.decl [concrete = constants.%C.generic]
// 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]
@@ -181,17 +194,24 @@ impl i32 as I {
// CHECK:STDOUT: }
// CHECK:STDOUT: %c: %C.6fb = bind_name c, %c.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %F.decl.loc39_18.2: %F.type.066a53.2 = fn_decl @F.4 [concrete = constants.%F.9ec58f.2] {
// CHECK:STDOUT: %c.patt: %pattern_type.c65 = binding_pattern c [concrete]
// CHECK:STDOUT: %c.param_patt: %pattern_type.c65 = value_param_pattern %c.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %c.param: %C.d88 = value_param call_param0
// CHECK:STDOUT: %c: %C.d88 = bind_name c, %c.param
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .C = <poisoned>
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: witness = file.%I.impl_witness.loc25
// CHECK:STDOUT: .F = %F.decl.loc39_18.1
// CHECK:STDOUT: witness = file.%I.impl_witness.loc31
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic class @C(%T.loc11_9.1: type, %X.loc11_19.1: @C.%T.loc11_9.2 (%T)) {
// CHECK:STDOUT: %T.loc11_9.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc11_9.2 (constants.%T)]
// CHECK:STDOUT: %X.loc11_19.2: @C.%T.loc11_9.2 (%T) = bind_symbolic_name X, 1 [symbolic = %X.loc11_19.2 (constants.%X)]
// CHECK:STDOUT: %pattern_type: type = pattern_type %T.loc11_9.2 [symbolic = %pattern_type (constants.%pattern_type.7dc)]
// CHECK:STDOUT: %pattern_type: type = pattern_type %T.loc11_9.2 [symbolic = %pattern_type (constants.%pattern_type.7dcd0a.1)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT:
@@ -206,32 +226,40 @@ impl i32 as I {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @F.1(@I.%Self: %I.type) {
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
// CHECK:STDOUT: %C.loc15_17.1: type = class_type @C, @C(constants.%I.type, %Self) [symbolic = %C.loc15_17.1 (constants.%C.dbb)]
// CHECK:STDOUT: %pattern_type: type = pattern_type %C.loc15_17.1 [symbolic = %pattern_type (constants.%pattern_type.4fb)]
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self.826)]
// CHECK:STDOUT: %C.loc21_17.1: type = class_type @C, @C(constants.%I.type, %Self) [symbolic = %C.loc21_17.1 (constants.%C.dbb)]
// CHECK:STDOUT: %pattern_type: type = pattern_type %C.loc21_17.1 [symbolic = %pattern_type (constants.%pattern_type.4fb)]
// CHECK:STDOUT:
// CHECK:STDOUT: fn(%c.param: @F.1.%C.loc15_17.1 (%C.dbb));
// CHECK:STDOUT: fn(%c.param: @F.1.%C.loc21_17.1 (%C.dbb));
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.2(%c.param: %C.7db);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.3(%c.param: %C.6fb);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.4(%c.param: %C.d88) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %c.ref: %C.d88 = name_ref c, %c.param
// CHECK:STDOUT: %.loc21: %C.6fb = converted %c.ref, <error> [concrete = <error>]
// CHECK:STDOUT: %F.call: init %empty_tuple.type = call @impl.a9a.%F.decl.loc39_18.1(<error>)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @C(constants.%T, constants.%X) {
// CHECK:STDOUT: %T.loc11_9.2 => constants.%T
// CHECK:STDOUT: %X.loc11_19.2 => constants.%X
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.7dc
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.7dcd0a.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @C(constants.%I.type, constants.%Self) {
// CHECK:STDOUT: specific @C(constants.%I.type, constants.%Self.826) {
// CHECK:STDOUT: %T.loc11_9.2 => constants.%I.type
// CHECK:STDOUT: %X.loc11_19.2 => constants.%Self
// CHECK:STDOUT: %X.loc11_19.2 => constants.%Self.826
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.2b5
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F.1(constants.%Self) {
// CHECK:STDOUT: %Self => constants.%Self
// CHECK:STDOUT: %C.loc15_17.1 => constants.%C.dbb
// CHECK:STDOUT: specific @F.1(constants.%Self.826) {
// CHECK:STDOUT: %Self => constants.%Self.826
// CHECK:STDOUT: %C.loc21_17.1 => constants.%C.dbb
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.4fb
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -243,7 +271,7 @@ impl i32 as I {
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F.1(constants.%I.facet.e8a) {
// CHECK:STDOUT: %Self => constants.%I.facet.e8a
// CHECK:STDOUT: %C.loc15_17.1 => constants.%C.7db
// CHECK:STDOUT: %C.loc21_17.1 => constants.%C.7db
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.225
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -251,17 +279,21 @@ impl i32 as I {
// CHECK:STDOUT: %T.loc11_9.2 => type
// CHECK:STDOUT: %X.loc11_19.2 => constants.%i32
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.98f
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F.1(constants.%I.facet.8b2) {
// CHECK:STDOUT: %Self => constants.%I.facet.8b2
// CHECK:STDOUT: %C.loc15_17.1 => constants.%C.835
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.023
// CHECK:STDOUT: specific @F.1(constants.%I.facet.118) {
// CHECK:STDOUT: %Self => constants.%I.facet.118
// CHECK:STDOUT: %C.loc21_17.1 => constants.%C.d88
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.c65
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @C(constants.%I.type, constants.%I.facet.8b2) {
// CHECK:STDOUT: specific @C(constants.%I.type, constants.%I.facet.118) {
// CHECK:STDOUT: %T.loc11_9.2 => constants.%I.type
// CHECK:STDOUT: %X.loc11_19.2 => constants.%I.facet.8b2
// CHECK:STDOUT: %X.loc11_19.2 => constants.%I.facet.118
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.2b5
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: }
// CHECK:STDOUT:
File diff suppressed because it is too large Load Diff
+157 -60
View File
@@ -189,6 +189,13 @@ interface J2 {
}
impl () as J2 where .U2 = {} {
// CHECK:STDERR: fail_todo_self_period_associated_type.carbon:[[@LINE+7]]:3: error: expression cannot be used as a value [UseOfNonExprAsValue]
// CHECK:STDERR: fn F[self: Self](z: {}) -> {} { return z; }
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_self_period_associated_type.carbon:[[@LINE-7]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
// CHECK:STDERR: fn F[self: Self](z: Self.U2) -> Self.U2;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn F[self: Self](z: {}) -> {} { return z; }
}
@@ -210,12 +217,12 @@ interface K {
}
impl () as K where .V = {.a: ()} {
// CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE+7]]:20: error: type `<pattern for {.x: ()}>` of parameter 1 in redeclaration differs from previous parameter type `<pattern for {.a: ()}>` [RedeclParamDiffersType]
// CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE+7]]:3: error: expression cannot be used as a value [UseOfNonExprAsValue]
// CHECK:STDERR: fn F[self: Self](v: {.x: ()}) -> {.x: ()} { return v; }
// CHECK:STDERR: ^~~~~~~~~~~
// CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE-7]]:20: note: previous declaration's corresponding parameter here [RedeclParamPrevious]
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE-7]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
// CHECK:STDERR: fn F[self: Self](v: V) -> V;
// CHECK:STDERR: ^~~~
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn F[self: Self](v: {.x: ()}) -> {.x: ()} { return v; }
}
@@ -2256,10 +2263,12 @@ fn F() {
// CHECK:STDOUT: %J.impl_witness: <witness> = impl_witness @E.%J.impl_witness_table [concrete]
// CHECK:STDOUT: %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete]
// CHECK:STDOUT: %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete]
// CHECK:STDOUT: %F.type.b84: type = fn_type @F.2 [concrete]
// CHECK:STDOUT: %F.b07: %F.type.b84 = struct_value () [concrete]
// CHECK:STDOUT: %J.facet.bd9: %J.type = facet_value %E, (%J.impl_witness) [concrete]
// CHECK:STDOUT: %F.type.b842fd.1: type = fn_type @F.2 [concrete]
// CHECK:STDOUT: %F.b07d12.1: %F.type.b842fd.1 = struct_value () [concrete]
// CHECK:STDOUT: %J.facet.f43: %J.type = facet_value %E, (%J.impl_witness) [concrete]
// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete]
// CHECK:STDOUT: %F.type.b842fd.2: type = fn_type @F.3 [concrete]
// CHECK:STDOUT: %F.b07d12.2: %F.type.b842fd.2 = 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: %int_1: Core.IntLiteral = int_value 1 [concrete]
@@ -2326,7 +2335,7 @@ fn F() {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: %Self.ref as %.loc9_20 {
// CHECK:STDOUT: %F.decl: %F.type.b84 = fn_decl @F.2 [concrete = constants.%F.b07] {
// CHECK:STDOUT: %F.decl.loc24_21.1: %F.type.b842fd.1 = fn_decl @F.2 [concrete = constants.%F.b07d12.1] {
// CHECK:STDOUT: %u.patt: <error> = binding_pattern u [concrete]
// CHECK:STDOUT: %u.param_patt: <error> = value_param_pattern %u.patt, call_param0 [concrete]
// CHECK:STDOUT: %return.patt: <error> = return_slot_pattern [concrete]
@@ -2343,10 +2352,21 @@ fn F() {
// CHECK:STDOUT: %return.param: ref <error> = out_param call_param1
// CHECK:STDOUT: %return: ref <error> = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %F.decl.loc24_21.2: %F.type.b842fd.2 = fn_decl @F.3 [concrete = constants.%F.b07d12.2] {
// CHECK:STDOUT: %u.patt: %pattern_type.7ce = binding_pattern u [concrete]
// CHECK:STDOUT: %u.param_patt: %pattern_type.7ce = value_param_pattern %u.patt, call_param0 [concrete]
// CHECK:STDOUT: %return.patt: %pattern_type.7ce = return_slot_pattern [concrete]
// CHECK:STDOUT: %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param1 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %u.param: %i32 = value_param call_param0
// CHECK:STDOUT: %u: %i32 = bind_name u, %u.param
// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1
// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .U = <poisoned>
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: .F = %F.decl.loc24_21.1
// CHECK:STDOUT: witness = @E.%J.impl_witness
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -2366,7 +2386,7 @@ fn F() {
// CHECK:STDOUT: requirement_rewrite %impl.elem0, %i32
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT: %J.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, <error>), @impl [concrete]
// CHECK:STDOUT: %J.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, @impl.%F.decl.loc24_21.2), @impl [concrete]
// CHECK:STDOUT: %J.impl_witness: <witness> = impl_witness %J.impl_witness_table [concrete = constants.%J.impl_witness]
// CHECK:STDOUT: %impl_witness_assoc_constant: type = impl_witness_assoc_constant constants.%i32 [concrete = constants.%i32]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
@@ -2397,6 +2417,13 @@ fn F() {
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.3(%u.param: %i32) -> %i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %u.ref: %i32 = name_ref u, %u.param
// CHECK:STDOUT: %F.call: init <error> = call @impl.%F.decl.loc24_21.1(<error>)
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @U(constants.%Self.ccd) {}
// CHECK:STDOUT:
// CHECK:STDOUT: specific @U(constants.%J.facet.521) {}
@@ -2410,8 +2437,8 @@ fn F() {
// CHECK:STDOUT:
// CHECK:STDOUT: specific @U(constants.%J.facet.330) {}
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F.1(constants.%J.facet.bd9) {
// CHECK:STDOUT: %Self => constants.%J.facet.bd9
// CHECK:STDOUT: specific @F.1(constants.%J.facet.f43) {
// CHECK:STDOUT: %Self => constants.%J.facet.f43
// CHECK:STDOUT: %J.lookup_impl_witness => constants.%J.impl_witness
// CHECK:STDOUT: %impl.elem0.loc5_11.1 => constants.%i32
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.7ce
@@ -2437,20 +2464,24 @@ fn F() {
// CHECK:STDOUT: %impl.elem0: type = impl_witness_access %J2.lookup_impl_witness, element0 [symbolic_self]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %J2_where.type.9e1: type = facet_type <@J2 where %impl.elem0 = %empty_struct_type> [concrete]
// CHECK:STDOUT: %J2.impl_witness.1aa: <witness> = impl_witness file.%J2.impl_witness_table.loc22 [concrete]
// CHECK:STDOUT: %J2.impl_witness.6a9: <witness> = impl_witness file.%J2.impl_witness_table.loc22 [concrete]
// CHECK:STDOUT: %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete]
// CHECK:STDOUT: %pattern_type.a96: type = pattern_type %empty_struct_type [concrete]
// CHECK:STDOUT: %F.type.f40: type = fn_type @F.2 [concrete]
// CHECK:STDOUT: %F.214: %F.type.f40 = struct_value () [concrete]
// CHECK:STDOUT: %J2.facet.af8: %J2.type = facet_value %empty_tuple.type, (%J2.impl_witness.1aa) [concrete]
// CHECK:STDOUT: %F.type.f405c5.1: type = fn_type @F.2 [concrete]
// CHECK:STDOUT: %F.214a71.1: %F.type.f405c5.1 = struct_value () [concrete]
// CHECK:STDOUT: %J2.facet.86f: %J2.type = facet_value %empty_tuple.type, (%J2.impl_witness.6a9) [concrete]
// CHECK:STDOUT: %F.type.f405c5.2: type = fn_type @F.3 [concrete]
// CHECK:STDOUT: %F.214a71.2: %F.type.f405c5.2 = struct_value () [concrete]
// CHECK:STDOUT: %C2: type = class_type @C2 [concrete]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
// CHECK:STDOUT: %J2_where.type.df9: type = facet_type <@J2 where %impl.elem0 = %C2> [concrete]
// CHECK:STDOUT: %J2.impl_witness.774: <witness> = impl_witness file.%J2.impl_witness_table.loc31 [concrete]
// CHECK:STDOUT: %J2.impl_witness.267: <witness> = impl_witness file.%J2.impl_witness_table.loc38 [concrete]
// CHECK:STDOUT: %pattern_type.838: type = pattern_type %C2 [concrete]
// CHECK:STDOUT: %F.type.05d: type = fn_type @F.3 [concrete]
// CHECK:STDOUT: %F.bfa: %F.type.05d = struct_value () [concrete]
// CHECK:STDOUT: %J2.facet.eed: %J2.type = facet_value %C2, (%J2.impl_witness.774) [concrete]
// CHECK:STDOUT: %F.type.05d6a0.1: type = fn_type @F.4 [concrete]
// CHECK:STDOUT: %F.bfa759.1: %F.type.05d6a0.1 = struct_value () [concrete]
// CHECK:STDOUT: %J2.facet.c3f: %J2.type = facet_value %C2, (%J2.impl_witness.267) [concrete]
// CHECK:STDOUT: %F.type.05d6a0.2: type = fn_type @F.5 [concrete]
// CHECK:STDOUT: %F.bfa759.2: %F.type.05d6a0.2 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -2484,27 +2515,27 @@ fn F() {
// CHECK:STDOUT: requirement_rewrite %impl.elem0, %.loc22_28.2
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT: %J2.impl_witness_table.loc22 = impl_witness_table (%impl_witness_assoc_constant.loc22, <error>), @impl.4e9 [concrete]
// CHECK:STDOUT: %J2.impl_witness.loc22: <witness> = impl_witness %J2.impl_witness_table.loc22 [concrete = constants.%J2.impl_witness.1aa]
// CHECK:STDOUT: %J2.impl_witness_table.loc22 = impl_witness_table (%impl_witness_assoc_constant.loc22, @impl.4e9.%F.decl.loc30_33.2), @impl.4e9 [concrete]
// CHECK:STDOUT: %J2.impl_witness.loc22: <witness> = impl_witness %J2.impl_witness_table.loc22 [concrete = constants.%J2.impl_witness.6a9]
// CHECK:STDOUT: %impl_witness_assoc_constant.loc22: type = impl_witness_assoc_constant constants.%empty_struct_type [concrete = constants.%empty_struct_type]
// CHECK:STDOUT: %C2.decl: type = class_decl @C2 [concrete = constants.%C2] {} {}
// CHECK:STDOUT: impl_decl @impl.8b3 [concrete] {} {
// CHECK:STDOUT: %C2.ref.loc31_6: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
// CHECK:STDOUT: %C2.ref.loc38_6: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
// CHECK:STDOUT: %J2.ref: type = name_ref J2, file.%J2.decl [concrete = constants.%J2.type]
// CHECK:STDOUT: %.Self: %J2.type = bind_symbolic_name .Self [symbolic_self = constants.%.Self]
// CHECK:STDOUT: %.Self.ref: %J2.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self]
// CHECK:STDOUT: %U2.ref: %J2.assoc_type = name_ref U2, @U2.%assoc0 [concrete = constants.%assoc0]
// CHECK:STDOUT: %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.as_type]
// CHECK:STDOUT: %.loc31_21: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.as_type]
// CHECK:STDOUT: %.loc38_21: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.as_type]
// CHECK:STDOUT: %impl.elem0: type = impl_witness_access constants.%J2.lookup_impl_witness, element0 [symbolic_self = constants.%impl.elem0]
// CHECK:STDOUT: %C2.ref.loc31_27: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
// CHECK:STDOUT: %.loc31_15: type = where_expr %.Self [concrete = constants.%J2_where.type.df9] {
// CHECK:STDOUT: requirement_rewrite %impl.elem0, %C2.ref.loc31_27
// CHECK:STDOUT: %C2.ref.loc38_27: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
// CHECK:STDOUT: %.loc38_15: type = where_expr %.Self [concrete = constants.%J2_where.type.df9] {
// CHECK:STDOUT: requirement_rewrite %impl.elem0, %C2.ref.loc38_27
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT: %J2.impl_witness_table.loc31 = impl_witness_table (%impl_witness_assoc_constant.loc31, <error>), @impl.8b3 [concrete]
// CHECK:STDOUT: %J2.impl_witness.loc31: <witness> = impl_witness %J2.impl_witness_table.loc31 [concrete = constants.%J2.impl_witness.774]
// CHECK:STDOUT: %impl_witness_assoc_constant.loc31: type = impl_witness_assoc_constant constants.%C2 [concrete = constants.%C2]
// CHECK:STDOUT: %J2.impl_witness_table.loc38 = impl_witness_table (%impl_witness_assoc_constant.loc38, @impl.8b3.%F.decl.loc39_33.2), @impl.8b3 [concrete]
// CHECK:STDOUT: %J2.impl_witness.loc38: <witness> = impl_witness %J2.impl_witness_table.loc38 [concrete = constants.%J2.impl_witness.267]
// CHECK:STDOUT: %impl_witness_assoc_constant.loc38: type = impl_witness_assoc_constant constants.%C2 [concrete = constants.%C2]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @J2 {
@@ -2548,7 +2579,7 @@ fn F() {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl.4e9: %.loc22_7.2 as %.loc22_15 {
// CHECK:STDOUT: %F.decl: %F.type.f40 = fn_decl @F.2 [concrete = constants.%F.214] {
// CHECK:STDOUT: %F.decl.loc30_33.1: %F.type.f405c5.1 = fn_decl @F.2 [concrete = constants.%F.214a71.1] {
// CHECK:STDOUT: %self.patt: %pattern_type.cb1 = binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type.cb1 = value_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: %z.patt: %pattern_type.a96 = binding_pattern z [concrete]
@@ -2556,28 +2587,41 @@ fn F() {
// CHECK:STDOUT: %return.patt: %pattern_type.a96 = return_slot_pattern [concrete]
// CHECK:STDOUT: %return.param_patt: %pattern_type.a96 = out_param_pattern %return.patt, call_param2 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %.loc23_31.1: %empty_struct_type = struct_literal ()
// CHECK:STDOUT: %.loc23_31.2: type = converted %.loc23_31.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
// CHECK:STDOUT: %.loc30_31.1: %empty_struct_type = struct_literal ()
// CHECK:STDOUT: %.loc30_31.2: type = converted %.loc30_31.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
// CHECK:STDOUT: %self.param: %empty_tuple.type = value_param call_param0
// CHECK:STDOUT: %Self.ref: type = name_ref Self, @impl.4e9.%.loc22_7.2 [concrete = constants.%empty_tuple.type]
// CHECK:STDOUT: %self: %empty_tuple.type = bind_name self, %self.param
// CHECK:STDOUT: %z.param: %empty_struct_type = value_param call_param1
// CHECK:STDOUT: %.loc23_24.1: type = splice_block %.loc23_24.3 [concrete = constants.%empty_struct_type] {
// CHECK:STDOUT: %.loc23_24.2: %empty_struct_type = struct_literal ()
// CHECK:STDOUT: %.loc23_24.3: type = converted %.loc23_24.2, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
// CHECK:STDOUT: %.loc30_24.1: type = splice_block %.loc30_24.3 [concrete = constants.%empty_struct_type] {
// CHECK:STDOUT: %.loc30_24.2: %empty_struct_type = struct_literal ()
// CHECK:STDOUT: %.loc30_24.3: type = converted %.loc30_24.2, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %z: %empty_struct_type = bind_name z, %z.param
// CHECK:STDOUT: %return.param: ref %empty_struct_type = out_param call_param2
// CHECK:STDOUT: %return: ref %empty_struct_type = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %F.decl.loc30_33.2: %F.type.f405c5.2 = fn_decl @F.3 [concrete = constants.%F.214a71.2] {
// CHECK:STDOUT: %self.patt: %pattern_type.cb1 = binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type.cb1 = value_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: %.param_patt: <error> = value_param_pattern <error>, call_param1 [concrete]
// CHECK:STDOUT: %return.patt: <error> = return_slot_pattern [concrete]
// CHECK:STDOUT: %return.param_patt: <error> = out_param_pattern %return.patt, call_param2 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %empty_tuple.type = value_param call_param0
// CHECK:STDOUT: %self: %empty_tuple.type = bind_name self, %self.param
// CHECK:STDOUT: %.param: <error> = value_param call_param1
// CHECK:STDOUT: %return.param: ref <error> = out_param call_param2
// CHECK:STDOUT: %return: ref <error> = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: .F = %F.decl.loc30_33.1
// CHECK:STDOUT: witness = file.%J2.impl_witness.loc22
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl.8b3: %C2.ref.loc31_6 as %.loc31_15 {
// CHECK:STDOUT: %F.decl: %F.type.05d = fn_decl @F.3 [concrete = constants.%F.bfa] {
// CHECK:STDOUT: impl @impl.8b3: %C2.ref.loc38_6 as %.loc38_15 {
// CHECK:STDOUT: %F.decl.loc39_33.1: %F.type.05d6a0.1 = fn_decl @F.4 [concrete = constants.%F.bfa759.1] {
// CHECK:STDOUT: %self.patt: %pattern_type.838 = binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type.838 = value_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: %z.patt: %pattern_type.838 = binding_pattern z [concrete]
@@ -2585,27 +2629,40 @@ fn F() {
// CHECK:STDOUT: %return.patt: %pattern_type.838 = return_slot_pattern [concrete]
// CHECK:STDOUT: %return.param_patt: %pattern_type.838 = out_param_pattern %return.patt, call_param2 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %C2.ref.loc32_30: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
// CHECK:STDOUT: %C2.ref.loc39_30: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
// CHECK:STDOUT: %self.param: %C2 = value_param call_param0
// CHECK:STDOUT: %Self.ref: type = name_ref Self, @impl.8b3.%C2.ref.loc31_6 [concrete = constants.%C2]
// CHECK:STDOUT: %Self.ref: type = name_ref Self, @impl.8b3.%C2.ref.loc38_6 [concrete = constants.%C2]
// CHECK:STDOUT: %self: %C2 = bind_name self, %self.param
// CHECK:STDOUT: %z.param: %C2 = value_param call_param1
// CHECK:STDOUT: %C2.ref.loc32_23: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
// CHECK:STDOUT: %C2.ref.loc39_23: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
// CHECK:STDOUT: %z: %C2 = bind_name z, %z.param
// CHECK:STDOUT: %return.param: ref %C2 = out_param call_param2
// CHECK:STDOUT: %return: ref %C2 = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %F.decl.loc39_33.2: %F.type.05d6a0.2 = fn_decl @F.5 [concrete = constants.%F.bfa759.2] {
// CHECK:STDOUT: %self.patt: %pattern_type.838 = binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type.838 = value_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: %.param_patt: <error> = value_param_pattern <error>, call_param1 [concrete]
// CHECK:STDOUT: %return.patt: <error> = return_slot_pattern [concrete]
// CHECK:STDOUT: %return.param_patt: <error> = out_param_pattern %return.patt, call_param2 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %C2 = value_param call_param0
// CHECK:STDOUT: %self: %C2 = bind_name self, %self.param
// CHECK:STDOUT: %.param: <error> = value_param call_param1
// CHECK:STDOUT: %return.param: ref <error> = out_param call_param2
// CHECK:STDOUT: %return: ref <error> = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .C2 = <poisoned>
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: witness = file.%J2.impl_witness.loc31
// CHECK:STDOUT: .F = %F.decl.loc39_33.1
// CHECK:STDOUT: witness = file.%J2.impl_witness.loc38
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C2 {
// CHECK:STDOUT: %.loc28_10: %empty_struct_type = struct_literal ()
// CHECK:STDOUT: %.loc28_11: type = converted %.loc28_10, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
// CHECK:STDOUT: adapt_decl %.loc28_11 [concrete]
// CHECK:STDOUT: %.loc35_10: %empty_struct_type = struct_literal ()
// CHECK:STDOUT: %.loc35_11: type = converted %.loc35_10, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
// CHECK:STDOUT: adapt_decl %.loc35_11 [concrete]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT:
@@ -2627,12 +2684,28 @@ fn F() {
// CHECK:STDOUT: return %z.ref
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.3(%self.param: %C2, %z.param: %C2) -> %C2 {
// CHECK:STDOUT: fn @F.3(%self.param: %empty_tuple.type, %.param: <error>) -> <error> {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: %empty_tuple.type = name_ref self, %self.param
// CHECK:STDOUT: %.ref: <error> = name_ref <none>, %.param [concrete = <error>]
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.4(%self.param: %C2, %z.param: %C2) -> %C2 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: %C2 = name_ref self, %self
// CHECK:STDOUT: return %self.ref
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.5(%self.param: %C2, %.param: <error>) -> <error> {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: %C2 = name_ref self, %self.param
// CHECK:STDOUT: %F.bound: <bound method> = bound_method %self.ref, @impl.8b3.%F.decl.loc39_33.1
// CHECK:STDOUT: %.ref: <error> = name_ref <none>, %.param [concrete = <error>]
// CHECK:STDOUT: %F.call: init %C2 = call %F.bound(%self.ref, <error>)
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @U2(constants.%Self) {}
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F.1(constants.%Self) {
@@ -2643,14 +2716,14 @@ fn F() {
// CHECK:STDOUT:
// CHECK:STDOUT: specific @U2(constants.%J2.facet.e30) {}
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F.1(constants.%J2.facet.af8) {
// CHECK:STDOUT: %Self => constants.%J2.facet.af8
// CHECK:STDOUT: specific @F.1(constants.%J2.facet.86f) {
// CHECK:STDOUT: %Self => constants.%J2.facet.86f
// CHECK:STDOUT: %Self.as_type.loc19_14.1 => constants.%empty_tuple.type
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.cb1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F.1(constants.%J2.facet.eed) {
// CHECK:STDOUT: %Self => constants.%J2.facet.eed
// CHECK:STDOUT: specific @F.1(constants.%J2.facet.c3f) {
// CHECK:STDOUT: %Self => constants.%J2.facet.c3f
// CHECK:STDOUT: %Self.as_type.loc19_14.1 => constants.%C2
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.838
// CHECK:STDOUT: }
@@ -2683,10 +2756,12 @@ fn F() {
// CHECK:STDOUT: %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete]
// CHECK:STDOUT: %struct_type.x: type = struct_type {.x: %empty_tuple.type} [concrete]
// CHECK:STDOUT: %pattern_type.414: type = pattern_type %struct_type.x [concrete]
// CHECK:STDOUT: %F.type.c52: type = fn_type @F.2 [concrete]
// CHECK:STDOUT: %F.5eb: %F.type.c52 = struct_value () [concrete]
// CHECK:STDOUT: %K.facet.77f: %K.type = facet_value %empty_tuple.type, (%K.impl_witness) [concrete]
// CHECK:STDOUT: %F.type.c5249c.1: type = fn_type @F.2 [concrete]
// CHECK:STDOUT: %F.5eb4dd.1: %F.type.c5249c.1 = struct_value () [concrete]
// CHECK:STDOUT: %K.facet.e32: %K.type = facet_value %empty_tuple.type, (%K.impl_witness) [concrete]
// CHECK:STDOUT: %pattern_type.e85: type = pattern_type %struct_type.a [concrete]
// CHECK:STDOUT: %F.type.c5249c.2: type = fn_type @F.3 [concrete]
// CHECK:STDOUT: %F.5eb4dd.2: %F.type.c5249c.2 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -2720,7 +2795,7 @@ fn F() {
// CHECK:STDOUT: requirement_rewrite %impl.elem0, %struct_type.a
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT: %K.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, <error>), @impl [concrete]
// CHECK:STDOUT: %K.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, @impl.%F.decl.loc16_45.2), @impl [concrete]
// CHECK:STDOUT: %K.impl_witness: <witness> = impl_witness %K.impl_witness_table [concrete = constants.%K.impl_witness]
// CHECK:STDOUT: %impl_witness_assoc_constant: type = impl_witness_assoc_constant constants.%struct_type.a [concrete = constants.%struct_type.a]
// CHECK:STDOUT: }
@@ -2770,7 +2845,7 @@ fn F() {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: %.loc8_7.2 as %.loc8_14 {
// CHECK:STDOUT: %F.decl: %F.type.c52 = fn_decl @F.2 [concrete = constants.%F.5eb] {
// CHECK:STDOUT: %F.decl.loc16_45.1: %F.type.c5249c.1 = fn_decl @F.2 [concrete = constants.%F.5eb4dd.1] {
// CHECK:STDOUT: %self.patt: %pattern_type.cb1 = binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type.cb1 = value_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: %v.patt: %pattern_type.414 = binding_pattern v [concrete]
@@ -2794,9 +2869,24 @@ fn F() {
// CHECK:STDOUT: %return.param: ref %struct_type.x = out_param call_param2
// CHECK:STDOUT: %return: ref %struct_type.x = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %F.decl.loc16_45.2: %F.type.c5249c.2 = fn_decl @F.3 [concrete = constants.%F.5eb4dd.2] {
// CHECK:STDOUT: %self.patt: %pattern_type.cb1 = binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type.cb1 = value_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: %v.patt: %pattern_type.e85 = binding_pattern v [concrete]
// CHECK:STDOUT: %v.param_patt: %pattern_type.e85 = value_param_pattern %v.patt, call_param1 [concrete]
// CHECK:STDOUT: %return.patt: %pattern_type.e85 = return_slot_pattern [concrete]
// CHECK:STDOUT: %return.param_patt: %pattern_type.e85 = out_param_pattern %return.patt, call_param2 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %empty_tuple.type = value_param call_param0
// CHECK:STDOUT: %self: %empty_tuple.type = bind_name self, %self.param
// CHECK:STDOUT: %v.param: %struct_type.a = value_param call_param1
// CHECK:STDOUT: %v: %struct_type.a = bind_name v, %v.param
// CHECK:STDOUT: %return.param: ref %struct_type.a = out_param call_param2
// CHECK:STDOUT: %return: ref %struct_type.a = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: .F = %F.decl.loc16_45.1
// CHECK:STDOUT: witness = file.%K.impl_witness
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -2817,6 +2907,13 @@ fn F() {
// CHECK:STDOUT: return %v.ref
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.3(%self.param: %empty_tuple.type, %v.param: %struct_type.a) -> %struct_type.a {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: %empty_tuple.type = name_ref self, %self.param
// CHECK:STDOUT: %v.ref: %struct_type.a = name_ref v, %v.param
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @V(constants.%Self) {}
// CHECK:STDOUT:
// CHECK:STDOUT: specific @V(constants.%K.facet.589) {}
@@ -2832,8 +2929,8 @@ fn F() {
// CHECK:STDOUT:
// CHECK:STDOUT: specific @V(constants.%K.facet.b09) {}
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F.1(constants.%K.facet.77f) {
// CHECK:STDOUT: %Self => constants.%K.facet.77f
// CHECK:STDOUT: specific @F.1(constants.%K.facet.e32) {
// CHECK:STDOUT: %Self => constants.%K.facet.e32
// CHECK:STDOUT: %Self.as_type.loc5_14.1 => constants.%empty_tuple.type
// CHECK:STDOUT: %pattern_type.loc5_8 => constants.%pattern_type.cb1
// CHECK:STDOUT: %K.lookup_impl_witness => constants.%K.impl_witness
+410
View File
@@ -0,0 +1,410 @@
// 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/check/thunk.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/check/call.h"
#include "toolchain/check/diagnostic_helpers.h"
#include "toolchain/check/function.h"
#include "toolchain/check/generic.h"
#include "toolchain/check/inst.h"
#include "toolchain/check/member_access.h"
#include "toolchain/check/pattern.h"
#include "toolchain/check/pattern_match.h"
#include "toolchain/check/pointer_dereference.h"
#include "toolchain/check/return.h"
#include "toolchain/check/type.h"
#include "toolchain/diagnostics/diagnostic.h"
#include "toolchain/sem_ir/function.h"
#include "toolchain/sem_ir/generic.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/inst.h"
#include "toolchain/sem_ir/pattern.h"
#include "toolchain/sem_ir/typed_insts.h"
namespace Carbon::Check {
// Adds a pattern instruction for a thunk, copying the location from an existing
// instruction.
static auto RebuildPatternInst(Context& context, SemIR::InstId orig_inst_id,
SemIR::Inst new_inst) -> SemIR::InstId {
// Ensure we built the same kind of instruction. In particular, this ensures
// that the location of the old instruction can be reused for the new one.
CARBON_CHECK(context.insts().Get(orig_inst_id).kind() == new_inst.kind(),
"Rebuilt pattern with the wrong kind: {0} -> {1}",
context.insts().Get(orig_inst_id), new_inst);
return AddPatternInst(context, SemIR::LocIdAndInst::UncheckedLoc(
SemIR::LocId(orig_inst_id), new_inst));
}
// Wrapper to allow the type to be specified as a template argument for API
// consistency with `AddInst`.
template <typename InstT>
static auto RebuildPatternInst(Context& context, SemIR::InstId orig_inst_id,
InstT new_inst) -> SemIR::InstId {
return RebuildPatternInst(context, orig_inst_id, SemIR::Inst(new_inst));
}
// Makes a copy of the given binding pattern, with its type adjusted to be
// `new_pattern_type_id`.
static auto CloneBindingPattern(Context& context, SemIR::InstId pattern_id,
SemIR::AnyBindingPattern pattern,
SemIR::TypeId new_pattern_type_id)
-> SemIR::InstId {
bool is_generic = pattern.kind == SemIR::SymbolicBindingPattern::Kind;
auto entity_name = context.entity_names().Get(pattern.entity_name_id);
CARBON_CHECK(is_generic == entity_name.bind_index().has_value());
// Get the transformed type of the binding.
if (new_pattern_type_id == SemIR::ErrorInst::TypeId) {
return SemIR::ErrorInst::InstId;
}
auto type_inst_id = context.types()
.GetAs<SemIR::PatternType>(new_pattern_type_id)
.scrutinee_type_inst_id;
auto type_id = context.types().GetTypeIdForTypeInstId(type_inst_id);
auto type_expr_region_id = context.sem_ir().expr_regions().Add(
{.block_ids = {SemIR::InstBlockId::Empty}, .result_id = type_inst_id});
// Rebuild the binding pattern.
return AddBindingPattern(context, SemIR::LocId(pattern_id),
entity_name.name_id, type_id, type_expr_region_id,
is_generic, entity_name.is_template)
.pattern_id;
}
// Makes a copy of the given pattern instruction, substituting values from a
// specific as needed. The resulting pattern behaves like a newly-created
// pattern, so is suitable for running `CalleePatternMatch` against.
static auto ClonePattern(Context& context, SemIR::SpecificId specific_id,
SemIR::InstId pattern_id) -> SemIR::InstId {
if (!pattern_id.has_value()) {
return SemIR::InstId::None;
}
auto get_type = [&](SemIR::InstId inst_id) -> SemIR::TypeId {
return SemIR::GetTypeOfInstInSpecific(context.sem_ir(), specific_id,
inst_id);
};
auto pattern = context.insts().Get(pattern_id);
// Decompose the pattern. The forms we allow for patterns in a function
// parameter list are currently fairly restrictive.
// Optional `addr`, only for `self`.
auto [addr, addr_id] = context.insts().TryUnwrap(
pattern, pattern_id, &SemIR::AddrPattern::inner_id);
// Optional parameter pattern.
auto [param, param_id] = context.insts().TryUnwrap(
pattern, pattern_id, &SemIR::AnyParamPattern::subpattern_id);
// Finally, either a binding pattern or a return slot pattern.
auto new_pattern_id = SemIR::InstId::None;
if (auto binding = pattern.TryAs<SemIR::AnyBindingPattern>()) {
new_pattern_id = CloneBindingPattern(context, pattern_id, *binding,
get_type(pattern_id));
} else if (auto return_slot = pattern.TryAs<SemIR::ReturnSlotPattern>()) {
new_pattern_id = RebuildPatternInst<SemIR::ReturnSlotPattern>(
context, pattern_id,
{.type_id = get_type(pattern_id),
.type_inst_id = SemIR::TypeInstId::None});
} else {
CARBON_CHECK(pattern.Is<SemIR::ErrorInst>(),
"Unexpected pattern {0} in function signature", pattern);
return SemIR::ErrorInst::InstId;
}
// Rebuild parameter.
if (param) {
new_pattern_id = RebuildPatternInst<SemIR::AnyParamPattern>(
context, param_id,
{.kind = param->kind,
.type_id = get_type(param_id),
.subpattern_id = new_pattern_id,
.index = SemIR::CallParamIndex::None});
}
// Rebuild `addr`.
if (addr) {
new_pattern_id = RebuildPatternInst<SemIR::AddrPattern>(
context, addr_id,
{.type_id = get_type(addr_id), .inner_id = new_pattern_id});
}
return new_pattern_id;
}
static auto ClonePatternBlock(Context& context, SemIR::SpecificId specific_id,
SemIR::InstBlockId inst_block_id)
-> SemIR::InstBlockId {
if (!inst_block_id.has_value()) {
return SemIR::InstBlockId::None;
}
return context.inst_blocks().Transform(
inst_block_id, [&](SemIR::InstId inst_id) {
return ClonePattern(context, specific_id, inst_id);
});
}
static auto CloneFunctionDecl(Context& context, SemIR::LocId loc_id,
SemIR::FunctionId signature_id,
SemIR::SpecificId signature_specific_id,
SemIR::FunctionId callee_id)
-> std::pair<SemIR::FunctionId, SemIR::InstId> {
StartGenericDecl(context);
// Clone the signature. Note that we re-get the function after each of these,
// because they might trigger imports that invalidate the function.
context.pattern_block_stack().Push();
auto implicit_param_patterns_id = ClonePatternBlock(
context, signature_specific_id,
context.functions().Get(signature_id).implicit_param_patterns_id);
auto param_patterns_id = ClonePatternBlock(
context, signature_specific_id,
context.functions().Get(signature_id).param_patterns_id);
auto return_slot_pattern_id = ClonePattern(
context, signature_specific_id,
context.functions().Get(signature_id).return_slot_pattern_id);
auto self_param_id = FindSelfPattern(context, implicit_param_patterns_id);
auto pattern_block_id = context.pattern_block_stack().Pop();
// Perform callee-side pattern matching to rebuild the parameter list.
context.inst_block_stack().Push();
auto call_params_id =
CalleePatternMatch(context, implicit_param_patterns_id, param_patterns_id,
return_slot_pattern_id);
auto decl_block_id = context.inst_block_stack().Pop();
// Create the `FunctionDecl` instruction.
SemIR::FunctionDecl function_decl = {SemIR::TypeId::None,
SemIR::FunctionId::None, decl_block_id};
auto decl_id = AddPlaceholderInst(
context, SemIR::LocIdAndInst::UncheckedLoc(loc_id, function_decl));
auto generic_id = BuildGenericDecl(context, decl_id);
// Create the `Function` object.
auto& signature = context.functions().Get(signature_id);
auto& callee = context.functions().Get(callee_id);
function_decl.function_id = context.functions().Add(
SemIR::Function{{.name_id = signature.name_id,
.parent_scope_id = callee.parent_scope_id,
.generic_id = generic_id,
.first_param_node_id = signature.first_param_node_id,
.last_param_node_id = signature.last_param_node_id,
.pattern_block_id = pattern_block_id,
.implicit_param_patterns_id = implicit_param_patterns_id,
.param_patterns_id = param_patterns_id,
.is_extern = false,
.extern_library_id = SemIR::LibraryNameId::None,
.non_owning_decl_id = SemIR::InstId::None,
.first_owning_decl_id = decl_id,
.definition_id = decl_id},
{.call_params_id = call_params_id,
.return_slot_pattern_id = return_slot_pattern_id,
.virtual_modifier = callee.virtual_modifier,
.virtual_index = callee.virtual_index,
.self_param_id = self_param_id}});
function_decl.type_id =
GetFunctionType(context, function_decl.function_id,
context.scope_stack().PeekSpecificId());
ReplaceInstBeforeConstantUse(context, decl_id, function_decl);
return {function_decl.function_id, decl_id};
}
// Build an expression that names the value matched by a pattern.
static auto BuildPatternRef(Context& context, SemIR::FunctionId function_id,
SemIR::InstId pattern_id) -> SemIR::InstId {
auto pattern = context.insts().Get(pattern_id);
auto addr = context.insts()
.TryUnwrap(pattern, pattern_id, &SemIR::AddrPattern::inner_id)
.first;
auto pattern_ref_id = SemIR::InstId::None;
if (auto value_param = pattern.TryAs<SemIR::ValueParamPattern>()) {
// Build a reference to this parameter.
auto call_param_id = context.inst_blocks().Get(
context.functions()
.Get(function_id)
.call_params_id)[value_param->index.index];
// Use a pretty name for the `name_ref`. While it's suspicious to use a
// pretty name in the IR like this, the only reason we include a name at
// all here is to make the formatted SemIR more readable.
pattern_ref_id = AddInst<SemIR::NameRef>(
context, SemIR::LocId(pattern_id),
{.type_id = context.insts().Get(call_param_id).type_id(),
.name_id = SemIR::GetPrettyNameFromPatternId(
context.sem_ir(), value_param->subpattern_id),
.value_id = call_param_id});
} else {
if (pattern_id != SemIR::ErrorInst::InstId) {
context.TODO(
pattern_id,
"don't know how to build reference to this pattern in thunk");
}
return SemIR::ErrorInst::InstId;
}
if (addr) {
pattern_ref_id = PerformPointerDereference(
context, SemIR::LocId(pattern_id), pattern_ref_id, [](SemIR::TypeId) {
CARBON_FATAL("addr subpattern is not a pointer");
});
}
return pattern_ref_id;
}
// Build a call to a function that forwards the arguments of the enclosing
// function, for use when constructing a thunk.
static auto BuildThunkCall(Context& context, SemIR::FunctionId function_id,
SemIR::InstId callee_id) -> SemIR::InstId {
auto loc_id = SemIR::LocId(callee_id);
auto& function = context.functions().Get(function_id);
// If we have a self parameter, form `self.<callee_id>`.
if (function.self_param_id.has_value()) {
callee_id = PerformCompoundMemberAccess(
context, loc_id,
BuildPatternRef(context, function_id, function.self_param_id),
callee_id);
}
// Form an argument list.
llvm::SmallVector<SemIR::InstId> args;
for (auto pattern_id :
context.inst_blocks().Get(function.param_patterns_id)) {
args.push_back(BuildPatternRef(context, function_id, pattern_id));
}
return PerformCall(context, loc_id, callee_id, args);
}
static auto HasDeclaredReturnType(Context& context,
SemIR::FunctionId function_id) -> bool {
return context.functions()
.Get(function_id)
.return_slot_pattern_id.has_value();
}
// Given a declaration of a thunk and the function that it should call, build
// the thunk body.
static auto BuildThunkDefinition(Context& context,
SemIR::FunctionId signature_id,
SemIR::FunctionId function_id,
SemIR::InstId thunk_id,
SemIR::InstId callee_id) {
// TODO: Improve the diagnostics produced here. Specifically, it would likely
// be better for the primary error message to be that we tried to produce a
// thunk because of a type mismatch, but couldn't, with notes explaining
// why, rather than the primary error message being whatever went wrong
// building the thunk.
{
// The check below produces diagnostics referring to the signature, so also
// note the callee.
Diagnostics::AnnotationScope annot_scope(
&context.emitter(), [&](DiagnosticBuilder& builder) {
CARBON_DIAGNOSTIC(ThunkCallee, Note,
"while building thunk calling this function");
builder.Note(callee_id, ThunkCallee);
});
CheckFunctionDefinitionSignature(context, function_id);
}
// TODO: This duplicates much of the handling for FunctionDefinitionStart and
// FunctionDefinition parse nodes. Consider refactoring.
context.scope_stack().PushForFunctionBody(thunk_id);
context.inst_block_stack().Push();
context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
StartGenericDefinition(context,
context.functions().Get(function_id).generic_id);
// The checks below produce diagnostics pointing at the callee, so also note
// the signature.
Diagnostics::AnnotationScope annot_scope(
&context.emitter(), [&](DiagnosticBuilder& builder) {
CARBON_DIAGNOSTIC(
ThunkSignature, Note,
"while building thunk to match the signature of this function");
builder.Note(context.functions().Get(signature_id).first_owning_decl_id,
ThunkSignature);
});
auto call_id = BuildThunkCall(context, function_id, callee_id);
if (HasDeclaredReturnType(context, function_id)) {
BuildReturnWithExpr(context, SemIR::LocId(callee_id), call_id);
} else {
BuildReturnWithNoExpr(context, SemIR::LocId(callee_id));
}
context.inst_block_stack().Pop();
context.scope_stack().Pop();
auto& function = context.functions().Get(function_id);
function.body_block_ids = context.region_stack().PopRegion();
FinishGenericDefinition(context, function.generic_id);
}
auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
SemIR::SpecificId signature_specific_id,
SemIR::InstId callee_id) -> SemIR::InstId {
auto callee = SemIR::GetCalleeFunction(context.sem_ir(), callee_id);
// Check whether we can use the given function without a thunk.
// TODO: For virtual functions, we want different rules for checking `self`.
// TODO: This is too strict; for example, we should not compare parameter
// names here.
if (CheckFunctionTypeMatches(
context, context.functions().Get(callee.function_id),
context.functions().Get(signature_id), signature_specific_id,
/*check_syntax=*/false, /*check_self=*/true, /*diagnose=*/false)) {
return callee_id;
}
// From P3763:
// If the function in the interface does not have a return type, the
// program is invalid if the function in the impl specifies a return type.
//
// Call into the redeclaration checking logic to produce a suitable error.
//
// TODO: Consider a different rule: always use an explicit return type for the
// thunk, and always convert the result of the wrapped call to the return type
// of the thunk.
if (!HasDeclaredReturnType(context, signature_id) &&
HasDeclaredReturnType(context, callee.function_id)) {
bool success = CheckFunctionReturnTypeMatches(
context, context.functions().Get(callee.function_id),
context.functions().Get(signature_id), signature_specific_id);
CARBON_CHECK(!success, "Return type unexpectedly matches");
return SemIR::ErrorInst::InstId;
}
// Create a scope for the function's parameters and generic parameters.
context.scope_stack().PushForDeclName();
// We can't use the function directly. Build a thunk.
// TODO: Check for and diagnose obvious reasons why this will fail, such as
// arity mismatch, before trying to build the thunk.
auto [function_id, thunk_id] =
CloneFunctionDecl(context, SemIR::LocId(callee_id), signature_id,
signature_specific_id, callee.function_id);
// Define the thunk.
// TODO: We should delay doing this until we get to the end of the enclosing
// deferred definition scope, if there is one. For example, an `impl` inside a
// `class` definition should have its thunks defined at the end of the class,
// like they would be if they were defined inline.
BuildThunkDefinition(context, signature_id, function_id, thunk_id, callee_id);
context.scope_stack().Pop();
return thunk_id;
}
} // namespace Carbon::Check
+22
View File
@@ -0,0 +1,22 @@
// 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
#ifndef CARBON_TOOLCHAIN_CHECK_THUNK_H_
#define CARBON_TOOLCHAIN_CHECK_THUNK_H_
#include "toolchain/check/context.h"
#include "toolchain/sem_ir/ids.h"
namespace Carbon::Check {
// Given a function signature and a callee function, build a thunk that matches
// the given signature and calls the specified callee. Returns the callee
// unchanged if it can be used directly.
auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
SemIR::SpecificId signature_specific_id,
SemIR::InstId callee_id) -> SemIR::InstId;
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_THUNK_H_
@@ -240,6 +240,8 @@ CARBON_DIAGNOSTIC_KIND(InvalidMainRunSignature)
CARBON_DIAGNOSTIC_KIND(MissingReturnStatement)
CARBON_DIAGNOSTIC_KIND(UnknownBuiltinFunctionName)
CARBON_DIAGNOSTIC_KIND(InvalidBuiltinSignature)
CARBON_DIAGNOSTIC_KIND(ThunkSignature)
CARBON_DIAGNOSTIC_KIND(ThunkCallee)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionOutsideClass)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionMissingSelf)
+8
View File
@@ -57,6 +57,14 @@ class BlockValueStore : public Yaml::Printable<BlockValueStore<IdT>> {
return values_.Get(id);
}
// Returns a new block formed by applying `transform(elem_id)` to each element
// in the specified block.
template <typename TransformFnT>
auto Transform(IdT id, TransformFnT transform) -> IdT {
llvm::SmallVector<ElementType> block(llvm::map_range(Get(id), transform));
return Add(block);
}
// Adds a block or finds an existing canonical block with the given content,
// and returns an ID to reference it.
auto AddCanonical(llvm::ArrayRef<ElementType> content) -> IdT {
+5 -12
View File
@@ -70,23 +70,16 @@ auto Function::GetParamPatternInfoFromPatternId(const File& sem_ir,
auto inst_id = pattern_id;
auto inst = sem_ir.insts().Get(inst_id);
if (auto addr_pattern = inst.TryAs<AddrPattern>()) {
inst_id = addr_pattern->inner_id;
inst = sem_ir.insts().Get(inst_id);
}
auto param_pattern_inst = inst.TryAs<AnyParamPattern>();
if (!param_pattern_inst) {
sem_ir.insts().TryUnwrap(inst, inst_id, &AddrPattern::inner_id);
auto [param_pattern, param_pattern_id] =
sem_ir.insts().TryUnwrap(inst, inst_id, &AnyParamPattern::subpattern_id);
if (!param_pattern) {
return std::nullopt;
}
auto param_pattern_id = inst_id;
inst_id = param_pattern_inst->subpattern_id;
inst = sem_ir.insts().Get(inst_id);
auto binding_pattern = inst.As<AnyBindingPattern>();
return {{.inst_id = param_pattern_id,
.inst = *param_pattern_inst,
.inst = *param_pattern,
.entity_name_id = binding_pattern.entity_name_id}};
}
+17
View File
@@ -451,6 +451,23 @@ class InstStore {
return TryGetAs<InstT>(inst_id);
}
// Attempts to convert the given instruction to the type that contains
// `member`. If it can be converted, the instruction ID and instruction are
// replaced by the unwrapped value of that member, and the converted wrapper
// instruction and its ID are returned. Otherwise returns {nullopt, None}.
template <typename InstT, typename InstIdT>
requires std::derived_from<InstIdT, InstId>
auto TryUnwrap(Inst& inst, InstId& inst_id, InstIdT InstT::*member) const
-> std::pair<std::optional<InstT>, InstId> {
if (auto wrapped_inst = inst.TryAs<InstT>()) {
auto wrapped_inst_id = inst_id;
inst_id = (*wrapped_inst).*member;
inst = Get(inst_id);
return {wrapped_inst, wrapped_inst_id};
}
return {std::nullopt, InstId::None};
}
// Returns a resolved LocId, which will point to a parse node, an import, or
// be None.
//
+8 -11
View File
@@ -1393,23 +1393,20 @@ struct RequireCompleteType {
};
struct Return {
static constexpr auto Kind =
InstKind::Return.Define<Parse::NodeIdOneOf<Parse::FunctionDefinitionId,
Parse::ReturnStatementId>>(
{.ir_name = "return",
.constant_kind = InstConstantKind::Never,
.terminator_kind = TerminatorKind::Terminator});
static constexpr auto Kind = InstKind::Return.Define<Parse::NodeId>(
{.ir_name = "return",
.constant_kind = InstConstantKind::Never,
.terminator_kind = TerminatorKind::Terminator});
// This is a statement, so has no type.
};
// A `return expr;` statement.
struct ReturnExpr {
static constexpr auto Kind =
InstKind::ReturnExpr.Define<Parse::ReturnStatementId>(
{.ir_name = "return",
.constant_kind = InstConstantKind::Never,
.terminator_kind = TerminatorKind::Terminator});
static constexpr auto Kind = InstKind::ReturnExpr.Define<Parse::NodeId>(
{.ir_name = "return",
.constant_kind = InstConstantKind::Never,
.terminator_kind = TerminatorKind::Terminator});
// This is a statement, so has no type.
InstId expr_id;