mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:10:13 +01:00
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:
co-authored by
Jon Ross-Perkins
parent
4f5d11a28b
commit
95903dc624
+7
-17
@@ -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"],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
+590
-343
File diff suppressed because it is too large
Load Diff
+86
-54
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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}};
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user