From 1b0a5709e6ed8e218e95c89097ecac1a1a7a4e4e Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 6 Oct 2026 20:12:58 +0000 Subject: [PATCH] Initial support for fn expressions. (#7893) Support for `fn` expressions with the same feature set as `fn` declarations. In particular, there is no support for captures, positional parameters, `=>` bodies, or `auto` return types. Note that this results in two parse nodes for each `=>` token. That's a bug, but it matches the behavior of function declarations, and will be fixed in a follow-up change. Assisted-by: Gemini via Antigravity --- toolchain/check/function.cpp | 183 +++ toolchain/check/function.h | 9 + toolchain/check/handle_function.cpp | 178 +-- toolchain/check/handle_lambda.cpp | 131 +- toolchain/check/handle_loop_statement.cpp | 14 +- toolchain/check/node_stack.h | 1 + toolchain/check/scope_stack.h | 1 + .../function/capture/uncaptured_locals.carbon | 51 + toolchain/check/testdata/lambda/lambda.carbon | 1308 +++++++++++++++++ toolchain/diagnostics/kind.def | 3 + toolchain/lower/file_context.cpp | 16 +- toolchain/lower/testdata/lambda/lambda.carbon | 111 ++ toolchain/parse/handle_lambda.cpp | 106 +- toolchain/parse/node_ids.h | 5 +- toolchain/parse/node_kind.def | 1 + toolchain/parse/state.def | 7 +- .../testdata/function/default_values.carbon | 21 +- toolchain/parse/testdata/lambda/lambda.carbon | 112 +- toolchain/parse/typed_nodes.h | 23 +- toolchain/sem_ir/formatter.cpp | 1 + toolchain/sem_ir/inst_fingerprinter.cpp | 15 +- toolchain/sem_ir/inst_namer.cpp | 4 +- toolchain/sem_ir/mangler.cpp | 9 +- toolchain/sem_ir/stringify.cpp | 13 + 24 files changed, 2015 insertions(+), 308 deletions(-) create mode 100644 toolchain/check/testdata/function/capture/uncaptured_locals.carbon create mode 100644 toolchain/check/testdata/lambda/lambda.carbon create mode 100644 toolchain/lower/testdata/lambda/lambda.carbon diff --git a/toolchain/check/function.cpp b/toolchain/check/function.cpp index b71c723e0420..da292f4561fc 100644 --- a/toolchain/check/function.cpp +++ b/toolchain/check/function.cpp @@ -7,6 +7,7 @@ #include "common/find.h" #include "toolchain/base/kind_switch.h" #include "toolchain/check/action.h" +#include "toolchain/check/control_flow.h" #include "toolchain/check/convert.h" #include "toolchain/check/eval.h" #include "toolchain/check/generic.h" @@ -14,6 +15,7 @@ #include "toolchain/check/merge.h" #include "toolchain/check/pattern.h" #include "toolchain/check/pattern_match.h" +#include "toolchain/check/return.h" #include "toolchain/check/scope_stack.h" #include "toolchain/check/type.h" #include "toolchain/check/type_completion.h" @@ -454,6 +456,170 @@ auto MakeFunctionDecl(Context& context, SemIR::LocId loc_id, return {decl_id, function_decl.function_id}; } +// Diagnoses when positional params aren't supported. Reassigns the pattern +// block if needed. +static auto DiagnosePositionalParams(Context& context, + SemIR::Function& function_info) -> void { + if (function_info.param_patterns_id.has_value()) { + return; + } + + context.TODO(function_info.latest_decl_id(), + "function with positional parameters"); + function_info.param_patterns_id = SemIR::InstBlockId::Empty; +} + +// For the top-level parameter patterns list, and for any level of nested tuple +// patterns, ensure that if a subpattern provides a default value, all +// subsequent patterns at that level of nesting must provide a default value as +// well. Returns the number of default values provided at the top level of the +// function parameter, useful for efficient arity checking in callers later on. +// +// TODO: per https://github.com/carbon-language/carbon-lang/issues/7529, this +// should also consider automatically supplied defaults for fully-specified +// tuple subpatterns, and consider them as having a default for the purposes +// of the out-of-order detection. It will also need to detect the error +// condition when a default is also specified for those fully-specified tuple +// subpatterns. +static auto CheckDefaults(Context& context, SemIR::Function& function) + -> int32_t { + if (!function.param_patterns_id.has_value()) { + return 0; + } + + struct PatternLevelState { + // The inst ids of the subpatterns on this level of tuple subpattern + // nesting, treated as a work list, so in reverse order of declaration. + llvm::SmallVector subpattern_ids; + + // If patterns at this level of nesting have default values, this refers + // to the first instruction to specify a default, useful for diagnostics. + SemIR::InstId first_pattern_with_default = SemIR::InstId::None; + + // If we encounter a tuple-pattern during processing, we suspend processing + // of this pattern level, in the middle of processing a single pattern from + // root to leaves. So we record the current state of processing of a single + // pattern to return to it after processing any tuple subpatterns. + + // True if the current pattern being processed has a default value + // specified. + bool current_pattern_has_default = false; + + // The current pattern we are processing, stored separately since it's been + // popped from the `pattern_work_list` and already processed, just may need + // subsequent processing. + SemIR::InstId current_id = SemIR::InstId::None; + + // A work list of patterns to be processed at this level of nesting. + llvm::SmallVector pattern_work_list; + + // A list of subpatterns missing required defaults, to coalesce error + // reporting into a single diagnostic. + llvm::SmallVector patterns_missing_defaults; + + // A count of the number of patterns on this level that have defaults. + int32_t default_count = 0; + }; + + llvm::SmallVector level_state_stack; + size_t default_count = 0; + level_state_stack.push_back({}); + llvm::append_range( + level_state_stack.back().subpattern_ids, + llvm::reverse(context.inst_blocks().Get(function.param_patterns_id))); + + while (!level_state_stack.empty()) { + PatternLevelState* state = &level_state_stack.back(); + while (!state->subpattern_ids.empty() || + !state->pattern_work_list.empty() || state->current_id.has_value()) { + // If we're not resuming processing a pattern from a nested state, start + // processing the next subpattern. + if (!state->current_id.has_value()) { + state->pattern_work_list.push_back( + state->subpattern_ids.pop_back_val()); + state->current_pattern_has_default = false; + } + while (!state->pattern_work_list.empty()) { + state->current_id = state->pattern_work_list.pop_back_val(); + auto inst = context.insts().Get(state->current_id); + CARBON_KIND_SWITCH(inst) { + case CARBON_KIND(SemIR::DefaultValuePattern default_value_pattern): { + state->current_pattern_has_default = true; + state->default_count += 1; + state->pattern_work_list.push_back( + default_value_pattern.subpattern_id); + break; + } + case CARBON_KIND( + SemIR::WrapperBindingPattern wrapper_binding_pattern): { + state->pattern_work_list.push_back( + wrapper_binding_pattern.subpattern_id); + break; + } + case CARBON_KIND(SemIR::TuplePattern tuple_pattern): { + auto elements = + context.inst_blocks().Get(tuple_pattern.elements_id); + if (!elements.empty()) { + // Start a new state for the nested tuple pattern elements. + level_state_stack.push_back({}); + state = &level_state_stack.back(); + llvm::append_range(state->subpattern_ids, + llvm::reverse(elements)); + } + break; + } + default: + // We only process patterns containing subpatterns, so this is an + // intentional no-op. + break; + } + } + // Finished processing this subpattern, detect a missing default if + // required. + if (state->current_pattern_has_default && + !state->first_pattern_with_default.has_value()) { + state->first_pattern_with_default = state->current_id; + } else if (!state->current_pattern_has_default && + state->first_pattern_with_default.has_value()) { + state->patterns_missing_defaults.push_back(state->current_id); + } + state->current_id = SemIR::InstId::None; + } + // Finished processing this tuple-pattern, emit diagnostics if any. + if (!state->patterns_missing_defaults.empty()) { + CARBON_DIAGNOSTIC(RequiredPatternDefaultValueMissing, Error, + "this pattern is missing a required default value."); + CARBON_DIAGNOSTIC(RequiredPatternDefaultValueFirstDefault, Note, + "all patterns to the right of this first pattern with " + "a default value must also specify a default value."); + CARBON_DIAGNOSTIC( + RequiredPatternDefaultValueMissingAdditional, Note, + "this pattern is also missing a required default value."); + auto inst_ref = llvm::ArrayRef(state->patterns_missing_defaults); + auto builder = context.emitter().Build( + inst_ref.consume_front(), RequiredPatternDefaultValueMissing); + for (auto inst_id : inst_ref) { + builder.Note(inst_id, RequiredPatternDefaultValueMissingAdditional); + } + builder.Note(state->first_pattern_with_default, + RequiredPatternDefaultValueFirstDefault); + builder.Emit(); + } + + // Extract the count from the level we just completed, overwriting any + // nested level value extracted previously. + default_count = level_state_stack.back().default_count; + level_state_stack.pop_back(); + } + + return default_count; +} + +auto CheckFunctionParams(Context& context, SemIR::Function& function) -> void { + function.default_value_arity = CheckDefaults(context, function); + DiagnosePositionalParams(context, function); +} + auto StartFunctionDefinition(Context& context, SemIR::InstId decl_id, SemIR::FunctionId function_id) -> void { // Create the function scope and the entry block. @@ -467,6 +633,23 @@ auto StartFunctionDefinition(Context& context, SemIR::InstId decl_id, CheckFunctionDefinitionSignature(context, function_id); } +auto CheckFunctionReturnOnFinish(Context& context, Parse::NodeId node_id, + SemIR::FunctionId function_id) -> void { + // If the `}` of the function is reachable, reject if we need a return value + // and otherwise add an implicit `return;`. + if (IsCurrentPositionReachable(context)) { + if (context.functions().Get(function_id).return_form_inst_id.has_value()) { + CARBON_DIAGNOSTIC( + MissingReturnStatement, Error, + "missing `return` at end of function with declared return type"); + context.emitter().Emit(LocIdForDiagnostics::TokenOnly(node_id), + MissingReturnStatement); + } else { + AddReturnInstWithCleanups(context, node_id); + } + } +} + auto FinishFunctionDefinition(Context& context, SemIR::FunctionId function_id) -> void { context.inst_block_stack().Pop(); diff --git a/toolchain/check/function.h b/toolchain/check/function.h index 080c012a34a3..0f12130afe98 100644 --- a/toolchain/check/function.h +++ b/toolchain/check/function.h @@ -125,12 +125,21 @@ auto MakeFunctionDecl(Context& context, SemIR::LocId loc_id, bool is_definition, SemIR::Function function) -> std::pair; +// Checks that a function's parameter patterns have valid default values and +// diagnoses unsupported positional parameters. +auto CheckFunctionParams(Context& context, SemIR::Function& function) -> void; + // Starts a function definition. Handles necessary stack setup, creating the // function scope and entry block, and definition validation. This is used for // both generated functions/thunks and user-declared functions. auto StartFunctionDefinition(Context& context, SemIR::InstId decl_id, SemIR::FunctionId function_id) -> void; +// Checks that a function definition has a `return` at the end if required, or +// adds an implicit `return;` if reachable. +auto CheckFunctionReturnOnFinish(Context& context, Parse::NodeId node_id, + SemIR::FunctionId function_id) -> void; + // Finishes definitions started by `StartFunctionDefinition`. auto FinishFunctionDefinition(Context& context, SemIR::FunctionId function_id) -> void; diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp index 775686a95c83..5f17a17c0e9f 100644 --- a/toolchain/check/handle_function.cpp +++ b/toolchain/check/handle_function.cpp @@ -360,165 +360,6 @@ static auto RequestVtableIfVirtual( context.vtable_stack().AddInstId(decl_id); } -// Diagnoses when positional params aren't supported. Reassigns the pattern -// block if needed. -static auto DiagnosePositionalParams(Context& context, - SemIR::Function& function_info) -> void { - if (function_info.param_patterns_id.has_value()) { - return; - } - - context.TODO(function_info.latest_decl_id(), - "function with positional parameters"); - function_info.param_patterns_id = SemIR::InstBlockId::Empty; -} - -// For the top-level parameter patterns list, and for any level of nested tuple -// patterns, ensure that if a subpattern provides a default value, all -// subsequent patterns at that level of nesting must provide a default value as -// well. Returns the number of default values provided at the top level of the -// function parameter, useful for efficient arity checking in callers later on. -// -// TODO: per https://github.com/carbon-language/carbon-lang/issues/7529, this -// should also consider automatically supplied defaults for fully-specified -// tuple subpatterns, and consider them as having a default for the purposes -// of the out-of-order detection. It will also need to detect the error -// condition when a default is also specified for those fully-specified tuple -// subpatterns. -static auto CheckDefaults(Context& context, SemIR::Function& function) - -> int32_t { - if (!function.param_patterns_id.has_value()) { - return 0; - } - - struct PatternLevelState { - // The inst ids of the subpatterns on this level of tuple subpattern - // nesting, treated as a work list, so in reverse order of declaration. - llvm::SmallVector subpattern_ids; - - // If patterns at this level of nesting have default values, this refers - // to the first instruction to specify a default, useful for diagnostics. - SemIR::InstId first_pattern_with_default = SemIR::InstId::None; - - // If we encounter a tuple-pattern during processing, we suspend processing - // of this pattern level, in the middle of processing a single pattern from - // root to leaves. So we record the current state of processing of a single - // pattern to return to it after processing any tuple subpatterns. - - // True if the current pattern being processed has a default value - // specified. - bool current_pattern_has_default = false; - - // The current pattern we are processing, stored separately since it's been - // popped from the `pattern_work_list` and already processed, just may need - // subsequent processing. - SemIR::InstId current_id = SemIR::InstId::None; - - // A work list of patterns to be processed at this level of nesting. - llvm::SmallVector pattern_work_list; - - // A list of subpatterns missing required defaults, to coalesce error - // reporting into a single diagnostic. - llvm::SmallVector patterns_missing_defaults; - - // A count of the number of patterns on this level that have defaults. - int32_t default_count = 0; - }; - - llvm::SmallVector level_state_stack; - size_t default_count = 0; - level_state_stack.push_back({}); - llvm::append_range( - level_state_stack.back().subpattern_ids, - llvm::reverse(context.inst_blocks().Get(function.param_patterns_id))); - - while (!level_state_stack.empty()) { - PatternLevelState* state = &level_state_stack.back(); - while (!state->subpattern_ids.empty() || - !state->pattern_work_list.empty() || state->current_id.has_value()) { - // If we're not resuming processing a pattern from a nested state, start - // processing the next subpattern. - if (!state->current_id.has_value()) { - state->pattern_work_list.push_back( - state->subpattern_ids.pop_back_val()); - state->current_pattern_has_default = false; - } - while (!state->pattern_work_list.empty()) { - state->current_id = state->pattern_work_list.pop_back_val(); - auto inst = context.insts().Get(state->current_id); - CARBON_KIND_SWITCH(inst) { - case CARBON_KIND(SemIR::DefaultValuePattern default_value_pattern): { - state->current_pattern_has_default = true; - state->default_count += 1; - state->pattern_work_list.push_back( - default_value_pattern.subpattern_id); - break; - } - case CARBON_KIND( - SemIR::WrapperBindingPattern wrapper_binding_pattern): { - state->pattern_work_list.push_back( - wrapper_binding_pattern.subpattern_id); - break; - } - case CARBON_KIND(SemIR::TuplePattern tuple_pattern): { - auto elements = - context.inst_blocks().Get(tuple_pattern.elements_id); - if (!elements.empty()) { - // Start a new state for the nested tuple pattern elements. - level_state_stack.push_back({}); - state = &level_state_stack.back(); - llvm::append_range(state->subpattern_ids, - llvm::reverse(elements)); - } - break; - } - default: - // We only process patterns containing subpatterns, so this is an - // intentional no-op. - break; - } - } - // Finished processing this subpattern, detect a missing default if - // required. - if (state->current_pattern_has_default && - !state->first_pattern_with_default.has_value()) { - state->first_pattern_with_default = state->current_id; - } else if (!state->current_pattern_has_default && - state->first_pattern_with_default.has_value()) { - state->patterns_missing_defaults.push_back(state->current_id); - } - state->current_id = SemIR::InstId::None; - } - // Finished processing this tuple-pattern, emit diagnostics if any. - if (!state->patterns_missing_defaults.empty()) { - CARBON_DIAGNOSTIC(RequiredPatternDefaultValueMissing, Error, - "this pattern is missing a required default value."); - CARBON_DIAGNOSTIC(RequiredPatternDefaultValueFirstDefault, Note, - "all patterns to the right of this first pattern with " - "a default value must also specify a default value."); - CARBON_DIAGNOSTIC( - RequiredPatternDefaultValueMissingAdditional, Note, - "this pattern is also missing a required default value."); - auto inst_ref = llvm::ArrayRef(state->patterns_missing_defaults); - auto builder = context.emitter().Build( - inst_ref.consume_front(), RequiredPatternDefaultValueMissing); - for (auto inst_id : inst_ref) { - builder.Note(inst_id, RequiredPatternDefaultValueMissingAdditional); - } - builder.Note(state->first_pattern_with_default, - RequiredPatternDefaultValueFirstDefault); - builder.Emit(); - } - - // Extract the count from the level we just completed, overwriting any - // nested level value extracted previously. - default_count = level_state_stack.back().default_count; - level_state_stack.pop_back(); - } - - return default_count; -} - // Build a FunctionDecl describing the signature of a function. This // handles the common logic shared by function declaration syntax and function // definition syntax. @@ -601,9 +442,7 @@ static auto BuildFunctionDecl(Context& context, function_info.definition_id = decl_id; } - function_info.default_value_arity = CheckDefaults(context, function_info); - - DiagnosePositionalParams(context, function_info); + CheckFunctionParams(context, function_info); TryMergeRedecl( context, name_context, std::nullopt, @@ -778,20 +617,7 @@ auto HandleParseNode(Context& context, Parse::FunctionDefinitionId node_id) SemIR::FunctionId function_id = context.node_stack().Pop(); - // If the `}` of the function is reachable, reject if we need a return value - // and otherwise add an implicit `return;`. - if (IsCurrentPositionReachable(context)) { - if (context.functions().Get(function_id).return_form_inst_id.has_value()) { - CARBON_DIAGNOSTIC( - MissingReturnStatement, Error, - "missing `return` at end of function with declared return type"); - context.emitter().Emit(LocIdForDiagnostics::TokenOnly(node_id), - MissingReturnStatement); - } else { - AddReturnInstWithCleanups(context, node_id); - } - } - + CheckFunctionReturnOnFinish(context, node_id, function_id); FinishFunctionDefinition(context, function_id); context.decl_name_stack().PopScope(/*check_unused=*/true); diff --git a/toolchain/check/handle_lambda.cpp b/toolchain/check/handle_lambda.cpp index 0170ccf22ba9..a934a0d2081c 100644 --- a/toolchain/check/handle_lambda.cpp +++ b/toolchain/check/handle_lambda.cpp @@ -3,17 +3,144 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/check/context.h" +#include "toolchain/check/decl_introducer_state.h" +#include "toolchain/check/function.h" +#include "toolchain/check/generic.h" #include "toolchain/check/handle.h" +#include "toolchain/check/pattern_match.h" +#include "toolchain/lex/token_kind.h" +#include "toolchain/parse/node_ids.h" +#include "toolchain/sem_ir/function.h" +#include "toolchain/sem_ir/ids.h" namespace Carbon::Check { auto HandleParseNode(Context& context, Parse::LambdaIntroducerId node_id) -> bool { - return context.TODO(node_id, "HandleLambdaIntroducer"); + // The function expression is potentially generic. + StartGenericDecl(context); + StartFunctionSignature(context); + context.node_stack().Push(node_id); + context.decl_introducer_state_stack().Push(); + return true; +} + +auto HandleParseNode(Context& context, Parse::LambdaDefinitionStartId node_id) + -> bool { + auto return_pattern_id = SemIR::InstId::None; + auto return_type_inst_id = SemIR::TypeInstId::None; + auto return_form_inst_id = SemIR::InstId::None; + if (auto [return_node, maybe_return_pattern_id] = + context.node_stack() + .PopWithNodeIdIf(); + maybe_return_pattern_id) { + return_pattern_id = *maybe_return_pattern_id; + auto return_form = context.PopReturnForm(); + return_type_inst_id = return_form.type_component_inst_id; + return_form_inst_id = return_form.form_inst_id; + } + + Parse::NodeId first_param_node_id = Parse::NoneNodeId(); + Parse::NodeId last_param_node_id = Parse::NoneNodeId(); + + // Explicit params. + auto [params_node_id, param_patterns_id] = + context.node_stack() + .PopWithNodeIdIf(); + if (param_patterns_id) { + first_param_node_id = + context.node_stack() + .PopForSoloNodeId(); + last_param_node_id = params_node_id; + } else { + param_patterns_id = SemIR::InstBlockId::None; + } + + // Implicit params. + auto [implicit_params_node_id, implicit_param_patterns_id] = + context.node_stack() + .PopWithNodeIdIf(); + if (implicit_param_patterns_id) { + first_param_node_id = + context.node_stack() + .PopForSoloNodeId(); + if (!last_param_node_id.has_value()) { + last_param_node_id = implicit_params_node_id; + } + } else { + implicit_param_patterns_id = SemIR::InstBlockId::None; + } + + auto match_results = + CalleePatternMatch(context, *implicit_param_patterns_id, + *param_patterns_id, return_pattern_id); + context.full_pattern_stack().PopFullPattern(); + auto pattern_block_id = context.pattern_block_stack().Pop(); + if (!param_patterns_id->has_value() && + !implicit_param_patterns_id->has_value() && + !return_pattern_id.has_value()) { + pattern_block_id = SemIR::InstBlockId::None; + } + auto decl_block_id = context.inst_block_stack().Pop(); + + context.node_stack() + .PopAndDiscardSoloNodeId(); + context.decl_introducer_state_stack().Pop(); + + // Function expressions may not take `self` as a parameter. (`self` in the + // implicit parameter list is already diagnosed by `SelfInImplicitParamList`.) + if (auto self_param_id = FindSelfPattern(context, SemIR::InstBlockId::None, + *param_patterns_id); + self_param_id.has_value()) { + CARBON_DIAGNOSTIC(SelfParameterInLambda, Error, + "`self` parameter in function expression"); + context.emitter().Emit(SemIR::LocId(self_param_id), SelfParameterInLambda); + } + + auto [decl_id, function_id] = MakeFunctionDecl( + context, node_id, decl_block_id, /*build_generic=*/true, + /*is_definition=*/true, + SemIR::Function{ + { + .name_id = SemIR::NameId::None, + .parent_scope_id = SemIR::NameScopeId::None, + .generic_id = SemIR::GenericId::None, + .first_param_node_id = first_param_node_id, + .last_param_node_id = 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 = SemIR::InstId::None, + }, + { + .call_param_patterns_id = match_results.call_param_patterns_id, + .call_params_id = match_results.call_params_id, + .call_param_ranges = match_results.param_ranges, + .return_type_inst_id = return_type_inst_id, + .return_form_inst_id = return_form_inst_id, + .return_pattern_id = return_pattern_id, + }}); + context.inst_block_stack().AddInstId(decl_id); + + CheckFunctionParams(context, context.functions().Get(function_id)); + + StartFunctionDefinition(context, decl_id, function_id); + context.node_stack().Push(node_id, function_id); + return true; } auto HandleParseNode(Context& context, Parse::LambdaId node_id) -> bool { - return context.TODO(node_id, "HandleLambda"); + auto function_id = + context.node_stack().Pop(); + CheckFunctionReturnOnFinish(context, node_id, function_id); + FinishFunctionDefinition(context, function_id); + context.scope_stack().Pop(/*check_unused=*/true); + context.node_stack().Push( + node_id, context.functions().Get(function_id).first_owning_decl_id); + return true; } auto HandleParseNode(Context& context, Parse::TerseBodyArrowId node_id) diff --git a/toolchain/check/handle_loop_statement.cpp b/toolchain/check/handle_loop_statement.cpp index 52afbb8ed775..0737b2890ae2 100644 --- a/toolchain/check/handle_loop_statement.cpp +++ b/toolchain/check/handle_loop_statement.cpp @@ -67,7 +67,11 @@ static auto BranchAndStartLoopBody(Context& context, Parse::NodeId node_id, {.break_target = loop_exit_id, .break_depth = context.scope_stack().cleanup_scope_depth(), .continue_target = loop_header_id, - .continue_depth = continue_depth}); + .continue_depth = continue_depth, + .return_scope_decl_id = + context.scope_stack().IsInFunctionScope() + ? context.scope_stack().GetReturnScopeDeclId() + : SemIR::InstId::None}); } // Finishes emitting the body for a `while`-like loop. Adds a back-edge to the @@ -276,7 +280,9 @@ auto HandleParseNode(Context& context, Parse::ForStatementId node_id) -> bool { auto HandleParseNode(Context& context, Parse::BreakStatementStartId node_id) -> bool { auto& stack = context.break_continue_stack(); - if (stack.empty()) { + if (stack.empty() || !context.scope_stack().IsInFunctionScope() || + stack.back().return_scope_decl_id != + context.scope_stack().GetReturnScopeDeclId()) { CARBON_DIAGNOSTIC(BreakOutsideLoop, Error, "`break` can only be used in a loop"); context.emitter().Emit(node_id, BreakOutsideLoop); @@ -301,7 +307,9 @@ auto HandleParseNode(Context& /*context*/, Parse::BreakStatementId /*node_id*/) auto HandleParseNode(Context& context, Parse::ContinueStatementStartId node_id) -> bool { auto& stack = context.break_continue_stack(); - if (stack.empty()) { + if (stack.empty() || !context.scope_stack().IsInFunctionScope() || + stack.back().return_scope_decl_id != + context.scope_stack().GetReturnScopeDeclId()) { CARBON_DIAGNOSTIC(ContinueOutsideLoop, Error, "`continue` can only be used in a loop"); context.emitter().Emit(node_id, ContinueOutsideLoop); diff --git a/toolchain/check/node_stack.h b/toolchain/check/node_stack.h index dfada597538d..0c6a2ab9ef2f 100644 --- a/toolchain/check/node_stack.h +++ b/toolchain/check/node_stack.h @@ -431,6 +431,7 @@ class NodeStack { return Id::KindFor(); case Parse::NodeKind::FunctionDefinitionStart: case Parse::NodeKind::BuiltinFunctionDefinitionStart: + case Parse::NodeKind::LambdaDefinitionStart: return Id::KindFor(); case Parse::NodeKind::ChoiceDefinitionStart: // TODO: Should we have a separate SemIR::ChoiceId? diff --git a/toolchain/check/scope_stack.h b/toolchain/check/scope_stack.h index ac4585bb71d2..f80145136d9d 100644 --- a/toolchain/check/scope_stack.h +++ b/toolchain/check/scope_stack.h @@ -56,6 +56,7 @@ class ScopeStack { CleanupScopeDepth break_depth; SemIR::InstBlockId continue_target; CleanupScopeDepth continue_depth; + SemIR::InstId return_scope_decl_id; }; // A non-lexical scope in which unqualified lookup may be required. diff --git a/toolchain/check/testdata/function/capture/uncaptured_locals.carbon b/toolchain/check/testdata/function/capture/uncaptured_locals.carbon new file mode 100644 index 000000000000..fd6f4e2231b1 --- /dev/null +++ b/toolchain/check/testdata/function/capture/uncaptured_locals.carbon @@ -0,0 +1,51 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/function/capture/uncaptured_locals.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/function/capture/uncaptured_locals.carbon + +// --- fail_todo_reference_uncaptured.carbon +library "[[@TEST_NAME]]"; + +class X {} + +fn Test() { + let x: X = {}; + fn Inner() { + // TODO: This should fail. We can't reference `x` from here. + let unused y: X = x; + } +} + +// Intentionally include an error here so we skip dominance checking, which CHECK-fails for the above example. +// CHECK:STDERR: fail_todo_reference_uncaptured.carbon:[[@LINE+4]]:14: error: name `error` not found [NameNotFound] +// CHECK:STDERR: fn Error() { error; } +// CHECK:STDERR: ^~~~~ +// CHECK:STDERR: +fn Error() { error; } + +// --- fail_todo_reference_uncaptured_lambda.carbon +library "[[@TEST_NAME]]"; + +class X {} + +fn Test() { + let x: X = {}; + (fn() { + // TODO: This should fail. We can't reference `x` from here. + let unused y: X = x; + }); +} + +// Intentionally include an error here so we skip dominance checking, which CHECK-fails for the above example. +// CHECK:STDERR: fail_todo_reference_uncaptured_lambda.carbon:[[@LINE+4]]:14: error: name `error` not found [NameNotFound] +// CHECK:STDERR: fn Error() { error; } +// CHECK:STDERR: ^~~~~ +// CHECK:STDERR: +fn Error() { error; } diff --git a/toolchain/check/testdata/lambda/lambda.carbon b/toolchain/check/testdata/lambda/lambda.carbon new file mode 100644 index 000000000000..9a90f441d73e --- /dev/null +++ b/toolchain/check/testdata/lambda/lambda.carbon @@ -0,0 +1,1308 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/lambda/lambda.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/lambda/lambda.carbon + +// --- empty.carbon +library "[[@TEST_NAME]]"; + +fn TestEmpty() { + //@dump-sem-ir-begin + alias empty = fn () {}; + empty(); + //@dump-sem-ir-end +} + +// --- identity.carbon +library "[[@TEST_NAME]]"; + +fn TestIdentity() { + //@dump-sem-ir-begin + alias id_i32 = fn (x: i32) -> i32 { return x; }; + let unused a: i32 = id_i32(42); + let unused b: i32 = (fn (x: i32) -> i32 { return x; })(10); + //@dump-sem-ir-end +} + +// --- generic_identity.carbon +library "[[@TEST_NAME]]"; + +fn TestGeneric() { + //@dump-sem-ir-begin + alias generic_id = fn [T: Core.Copy](x: T) -> T { return x; }; + let unused c: i32 = generic_id(42 as i32); + let unused d: bool = generic_id(true); + //@dump-sem-ir-end +} + +// --- generic_nested.carbon +library "[[@TEST_NAME]]"; + +fn TestGenericNested() { + //@dump-sem-ir-begin + alias generic_id = fn [T: Core.Copy](x: T) -> T { + return fn(y: T) -> T { + return fn(z: T) -> T { + return z; + }(y); + }(x); + }; + let unused c: i32 = generic_id(42 as i32); + let unused d: bool = generic_id(true); + //@dump-sem-ir-end +} + +// --- extended_types.carbon +library "[[@TEST_NAME]]"; + +fn TestExtendedTypes() { + alias with_var = fn (var x: i32) -> i32 { + returned var r: i32 = x; + return var; + }; + let _: i32 = with_var(5); + + alias with_ref_return = fn (ref x: i32) ->? form(ref i32) { + return x; + }; + var v: i32 = 1; + let unused ref r: i32 = with_ref_return(ref v); +} + +// --- default_arguments.carbon +library "[[@TEST_NAME]]"; + +fn TestDefaultArgument() { + alias with_default = fn (x: i32 = 7) -> i32 { + return x; + }; + let _: i32 = with_default(); + let _: i32 = with_default(8); +} + +// --- nested.carbon +library "[[@TEST_NAME]]"; + +fn TestNested() { + alias outer = fn () -> i32 { + alias inner = fn (x: i32) -> i32 { return x; }; + return inner(3); + }; + let _: i32 = outer(); +} + +// --- control_flow.carbon +library "[[@TEST_NAME]]"; + +fn TestControlFlow() { + //@dump-sem-ir-begin + alias loop_in_lambda = fn () { + while (true) { + break; + } + }; + loop_in_lambda(); + //@dump-sem-ir-end +} + +// --- as_generic_argument.carbon +library "[[@TEST_NAME]]"; + +fn PassToGeneric[F: type](unused f: F) {} + +alias id_fn = fn (x: i32) -> i32 { return x; }; + +fn TestAsGenericArgument() { + PassToGeneric(id_fn); +} + +// --- as_template_argument.carbon +library "[[@TEST_NAME]]"; + +fn PassToTemplate[template F: type](template f: F) { f(42); } + +alias id_fn = fn (x: i32) -> i32 { return x; }; + +fn TestAsTemplateArgument() { + PassToTemplate(id_fn); +} + +// --- fail_todo_as_non_constant_template_argument.carbon +library "[[@TEST_NAME]]"; + +// TODO: This should work even when `f` is not constant. +fn PassToTemplate[template F: type](f: F) { f(42); } + +alias id_fn = fn (x: i32) -> i32 { return x; }; + +fn TestAsTemplateArgument() { + // CHECK:STDERR: fail_todo_as_non_constant_template_argument.carbon:[[@LINE+7]]:3: error: unable to monomorphize specific `PassToTemplate()` [ResolvingSpecificHere] + // CHECK:STDERR: PassToTemplate(id_fn); + // CHECK:STDERR: ^~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_as_non_constant_template_argument.carbon:[[@LINE-8]]:45: note: value of type `` is not callable [CallToNonCallable] + // CHECK:STDERR: fn PassToTemplate[template F: type](f: F) { f(42); } + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + PassToTemplate(id_fn); +} + +// --- in_class.carbon +library "[[@TEST_NAME]]"; + +class InClass { + var field: i32 = (fn (x: i32) -> i32 { return x; })(1); +} + +// --- fail_self.carbon +library "[[@TEST_NAME]]"; + +class C { + fn M() { + // CHECK:STDERR: fail_self.carbon:[[@LINE+4]]:17: error: `self` parameter in function expression [SelfParameterInLambda] + // CHECK:STDERR: (fn (unused self: Self) {}); + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: + (fn (unused self: Self) {}); + // CHECK:STDERR: fail_self.carbon:[[@LINE+4]]:17: error: `self` must be declared in the explicit parameter list [SelfInImplicitParamList] + // CHECK:STDERR: (fn [unused self: Self]() {}); + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: + (fn [unused self: Self]() {}); + } +} + +fn F() { + // CHECK:STDERR: fail_self.carbon:[[@LINE+4]]:15: error: `self` parameter in function expression [SelfParameterInLambda] + // CHECK:STDERR: (fn (unused self: i32) {}); + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: + (fn (unused self: i32) {}); + // CHECK:STDERR: fail_self.carbon:[[@LINE+4]]:30: error: `self` parameter in function expression [SelfParameterInLambda] + // CHECK:STDERR: (fn (unused x: i32, unused self: i32) {}); + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: + (fn (unused x: i32, unused self: i32) {}); +} + +// --- fail_return.carbon +library "[[@TEST_NAME]]"; + +fn Outer() -> i32 { + // CHECK:STDERR: fail_return.carbon:[[@LINE+4]]:18: error: missing `return` at end of function with declared return type [MissingReturnStatement] + // CHECK:STDERR: (fn () -> i32 {}); + // CHECK:STDERR: ^ + // CHECK:STDERR: + (fn () -> i32 {}); + // CHECK:STDERR: fail_return.carbon:[[@LINE+7]]:20: error: cannot implicitly convert expression of type `Core.IntLiteral` to `bool` [ConversionFailure] + // CHECK:STDERR: (fn () -> bool { return 1; }); + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: fail_return.carbon:[[@LINE+4]]:20: note: type `Core.IntLiteral` does not implement interface `Core.ImplicitAs(bool)` [MissingImplInMemberAccessInContext] + // CHECK:STDERR: (fn () -> bool { return 1; }); + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: + (fn () -> bool { return 1; }); + // CHECK:STDERR: fail_return.carbon:[[@LINE+7]]:12: error: no return expression should be provided in this context [ReturnStatementDisallowExpr] + // CHECK:STDERR: (fn () { return 1; }); + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: fail_return.carbon:[[@LINE+4]]:4: note: there was no return type provided [ReturnTypeOmittedNote] + // CHECK:STDERR: (fn () { return 1; }); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + (fn () { return 1; }); + + return 0; +} + +// --- fail_unused.carbon +library "[[@TEST_NAME]]"; + +fn F() { + // CHECK:STDERR: fail_unused.carbon:[[@LINE+7]]:8: warning: binding `x` unused [UnusedBinding] + // CHECK:STDERR: (fn (x: i32, unused y: i32) -> i32 { + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_unused.carbon:[[@LINE+3]]:23: error: variable `y` marked `unused` but used [UnusedButUsed] + // CHECK:STDERR: (fn (x: i32, unused y: i32) -> i32 { + // CHECK:STDERR: ^~~~~~ + (fn (x: i32, unused y: i32) -> i32 { + let z: i32 = 1; + // CHECK:STDERR: fail_unused.carbon:[[@LINE+8]]:12: note: usage here [UnusedButUsedHere] + // CHECK:STDERR: return y; + // CHECK:STDERR: ^ + // CHECK:STDERR: + // CHECK:STDERR: fail_unused.carbon:[[@LINE-5]]:9: warning: binding `z` unused [UnusedBinding] + // CHECK:STDERR: let z: i32 = 1; + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: + return y; + }); +} + +// --- fail_break_continue.carbon +library "[[@TEST_NAME]]"; + +fn F() { + while (true) { + (fn () { + // CHECK:STDERR: fail_break_continue.carbon:[[@LINE+4]]:7: error: `break` can only be used in a loop [BreakOutsideLoop] + // CHECK:STDERR: break; + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + break; + }); + (fn () { + // CHECK:STDERR: fail_break_continue.carbon:[[@LINE+4]]:7: error: `continue` can only be used in a loop [ContinueOutsideLoop] + // CHECK:STDERR: continue; + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: + continue; + }); + break; + } +} + +// --- fail_default_values.carbon +library "[[@TEST_NAME]]"; + +fn F() { + // CHECK:STDERR: fail_default_values.carbon:[[@LINE+7]]:34: error: this pattern is missing a required default value. [RequiredPatternDefaultValueMissing] + // CHECK:STDERR: (fn (unused x: i32 = 1, unused y: i32) {}); + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_default_values.carbon:[[@LINE+4]]:15: note: all patterns to the right of this first pattern with a default value must also specify a default value. [RequiredPatternDefaultValueFirstDefault] + // CHECK:STDERR: (fn (unused x: i32 = 1, unused y: i32) {}); + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: + (fn (unused x: i32 = 1, unused y: i32) {}); +} + +// --- fail_incomplete_type.carbon +library "[[@TEST_NAME]]"; + +class Incomplete; + +fn F() { + // CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE+7]]:15: error: parameter has incomplete type `Incomplete` in function definition [IncompleteTypeInFunctionParam] + // CHECK:STDERR: (fn (unused x: Incomplete) {}); + // CHECK:STDERR: ^~~~~~~~~~~~~ + // CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE-6]]:1: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: class Incomplete; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + (fn (unused x: Incomplete) {}); + // CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE+11]]:10: error: function returns incomplete type `Incomplete` [IncompleteTypeInFunctionReturnType] + // CHECK:STDERR: (fn () -> Incomplete {}); + // CHECK:STDERR: ^~~~~~~~~~~~~ + // CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE-14]]:1: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: class Incomplete; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE+4]]:25: error: missing `return` at end of function with declared return type [MissingReturnStatement] + // CHECK:STDERR: (fn () -> Incomplete {}); + // CHECK:STDERR: ^ + // CHECK:STDERR: + (fn () -> Incomplete {}); +} + +// --- fail_conversion.carbon +library "[[@TEST_NAME]]"; + +fn F() { + // CHECK:STDERR: fail_conversion.carbon:[[@LINE+7]]:16: error: cannot implicitly convert expression of type `` to `i32` [ConversionFailure] + // CHECK:STDERR: let _: i32 = fn () {}; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_conversion.carbon:[[@LINE+4]]:16: note: type `` does not implement interface `Core.ImplicitAs(i32)` [MissingImplInMemberAccessInContext] + // CHECK:STDERR: let _: i32 = fn () {}; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + let _: i32 = fn () {}; +} + +// --- fail_todo_positional_params.carbon +library "[[@TEST_NAME]]"; + +fn F() { + // CHECK:STDERR: fail_todo_positional_params.carbon:[[@LINE+4]]:4: error: semantics TODO: `function with positional parameters` [SemanticsTodo] + // CHECK:STDERR: (fn {}); + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: + (fn {}); + // CHECK:STDERR: fail_todo_positional_params.carbon:[[@LINE+4]]:4: error: semantics TODO: `function with positional parameters` [SemanticsTodo] + // CHECK:STDERR: (fn -> i32 { return 0; }); + // CHECK:STDERR: ^~~~~~~~~~~ + // CHECK:STDERR: + (fn -> i32 { return 0; }); +} + +// --- fail_todo_terse_body.carbon +library "[[@TEST_NAME]]"; + +fn F() { + // CHECK:STDERR: fail_todo_terse_body.carbon:[[@LINE+4]]:16: error: semantics TODO: `HandleTerseBodyArrow` [SemanticsTodo] + // CHECK:STDERR: (fn (x: i32) => x); + // CHECK:STDERR: ^~ + // CHECK:STDERR: + (fn (x: i32) => x); +} + +// CHECK:STDOUT: --- empty.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: type: type = facet_type [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %fn.type: type = fn_type @fn [concrete] +// CHECK:STDOUT: %fn: %fn.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestEmpty() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %fn.decl: %fn.type = fn_decl @fn [concrete = constants.%fn] {} {} +// CHECK:STDOUT: %empty: %fn.type = alias_binding empty, %fn.decl [concrete = constants.%fn] +// CHECK:STDOUT: %empty.ref: %fn.type = name_ref empty, %empty [concrete = constants.%fn] +// CHECK:STDOUT: %fn.call: init %empty_tuple.type = call %empty.ref() +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @fn() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- identity.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: type: type = facet_type [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %N: Core.IntLiteral = symbolic_binding N, 0 [symbolic] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.6b6: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %x.param_patt: %pattern_type.6b6 = value_param_pattern [concrete] +// CHECK:STDOUT: %x.patt: %pattern_type.6b6 = wrapper_binding_pattern x, %x.param_patt [concrete] +// CHECK:STDOUT: %.795f: Core.Form = init_form %i32 [concrete] +// CHECK:STDOUT: %return.param_patt.a9a: %pattern_type.6b6 = out_param_pattern [concrete] +// CHECK:STDOUT: %return.patt.e1b: %pattern_type.6b6 = return_slot_pattern %return.param_patt.a9a, %i32 [concrete] +// CHECK:STDOUT: %fn.type.4ee: type = fn_type @fn.loc5 [concrete] +// CHECK:STDOUT: %fn.eaf: %fn.type.4ee = struct_value () [concrete] +// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.ac8: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%N) [symbolic] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.5e0: %Int.as.Copy.impl.Op.type.ac8 = struct_value () [symbolic] +// CHECK:STDOUT: %Copy.impl_witness.b51: = impl_witness imports.%Copy.impl_witness_table.8d2, @Int.as.Copy.impl(%int_32) [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.3f6: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%int_32) [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.4f6: %Int.as.Copy.impl.Op.type.3f6 = struct_value () [concrete] +// CHECK:STDOUT: %Copy.facet: %Copy.type = facet_value %i32, (%Copy.impl_witness.b51) [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.381: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%Copy.facet) [concrete] +// CHECK:STDOUT: %.737: type = fn_type_with_self_type %Copy.WithSelf.Op.type.381, %Copy.facet [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.specific_fn: = specific_function %Int.as.Copy.impl.Op.4f6, @Int.as.Copy.impl.Op(%int_32) [concrete] +// CHECK:STDOUT: %a.patt: %pattern_type.6b6 = value_binding_pattern a [concrete] +// CHECK:STDOUT: %int_42.20e: Core.IntLiteral = int_value 42 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.914: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.e74: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.845: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.e74 = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.a2a: = impl_witness imports.%ImplicitAs.impl_witness_table.1aa, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.2ba: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.e39: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.2ba = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.914 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.a2a) [concrete] +// CHECK:STDOUT: %ImplicitAs.WithSelf.Convert.type.8eb: type = fn_type @ImplicitAs.WithSelf.Convert, @ImplicitAs.WithSelf(%i32, %ImplicitAs.facet) [concrete] +// CHECK:STDOUT: %.b7a: type = fn_type_with_self_type %ImplicitAs.WithSelf.Convert.type.8eb, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.bf3: = bound_method %int_42.20e, %Core.IntLiteral.as.ImplicitAs.impl.Convert.e39 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.e39, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method.098: = bound_method %int_42.20e, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_42.ac4: %i32 = int_value 42 [concrete] +// CHECK:STDOUT: %b.patt: %pattern_type.6b6 = value_binding_pattern b [concrete] +// CHECK:STDOUT: %fn.type.ee2: type = fn_type @fn.loc7 [concrete] +// CHECK:STDOUT: %fn.eb8: %fn.type.ee2 = struct_value () [concrete] +// CHECK:STDOUT: %int_10.64f: Core.IntLiteral = int_value 10 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.dcb: = bound_method %int_10.64f, %Core.IntLiteral.as.ImplicitAs.impl.Convert.e39 [concrete] +// CHECK:STDOUT: %bound_method.1b6: = bound_method %int_10.64f, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_10.6bf: %i32 = int_value 10 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core.import_ref.cd6: @Int.as.Copy.impl.%Int.as.Copy.impl.Op.type (%Int.as.Copy.impl.Op.type.ac8) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Int.as.Copy.impl.%Int.as.Copy.impl.Op (constants.%Int.as.Copy.impl.Op.5e0)] +// CHECK:STDOUT: %Copy.impl_witness_table.8d2 = impl_witness_table (%Core.import_ref.cd6), @Int.as.Copy.impl [concrete] +// CHECK:STDOUT: %Core.import_ref.edf: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.e74) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.845)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table.1aa = impl_witness_table (%Core.import_ref.edf), @Core.IntLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestIdentity() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %fn.decl.loc5: %fn.type.4ee = fn_decl @fn.loc5 [concrete = constants.%fn.eaf] { +// CHECK:STDOUT: %x.param_patt: %pattern_type.6b6 = value_param_pattern [concrete = constants.%x.param_patt] +// CHECK:STDOUT: %x.patt: %pattern_type.6b6 = wrapper_binding_pattern x, %x.param_patt [concrete = constants.%x.patt] +// CHECK:STDOUT: %return.param_patt: %pattern_type.6b6 = out_param_pattern [concrete = constants.%return.param_patt.a9a] +// CHECK:STDOUT: %return.patt: %pattern_type.6b6 = return_slot_pattern %return.param_patt, %i32.loc5_33 [concrete = constants.%return.patt.e1b] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %i32.loc5_33: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %.loc5: Core.Form = init_form %i32.loc5_33 [concrete = constants.%.795f] +// CHECK:STDOUT: %x.param: %i32 = value_param call_param0 +// CHECK:STDOUT: %i32.loc5_25: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %x: %i32 = wrapper_binding x, %x.param +// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %id_i32: %fn.type.4ee = alias_binding id_i32, %fn.decl.loc5 [concrete = constants.%fn.eaf] +// CHECK:STDOUT: %id_i32.ref: %fn.type.4ee = name_ref id_i32, %id_i32 [concrete = constants.%fn.eaf] +// CHECK:STDOUT: %int_42: Core.IntLiteral = int_value 42 [concrete = constants.%int_42.20e] +// CHECK:STDOUT: %impl.elem0.loc6: %.b7a = impl_witness_access constants.%ImplicitAs.impl_witness.a2a, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.e39] +// CHECK:STDOUT: %bound_method.loc6_30.1: = bound_method %int_42, %impl.elem0.loc6 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.bf3] +// CHECK:STDOUT: %specific_fn.loc6: = specific_function %impl.elem0.loc6, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc6_30.2: = bound_method %int_42, %specific_fn.loc6 [concrete = constants.%bound_method.098] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc6: init %i32 = call %bound_method.loc6_30.2(%int_42) [concrete = constants.%int_42.ac4] +// CHECK:STDOUT: %.loc6_30.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc6 [concrete = constants.%int_42.ac4] +// CHECK:STDOUT: %.loc6_30.2: %i32 = converted %int_42, %.loc6_30.1 [concrete = constants.%int_42.ac4] +// CHECK:STDOUT: %fn.call.loc6: init %i32 = call %id_i32.ref(%.loc6_30.2) +// CHECK:STDOUT: %.loc6_32.1: %i32 = value_of_initializer %fn.call.loc6 +// CHECK:STDOUT: %.loc6_32.2: %i32 = converted %fn.call.loc6, %.loc6_32.1 +// CHECK:STDOUT: %i32.loc6: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %a: %i32 = wrapper_binding a, %.loc6_32.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.6b6 = value_binding_pattern a [concrete = constants.%a.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: %fn.decl.loc7: %fn.type.ee2 = fn_decl @fn.loc7 [concrete = constants.%fn.eb8] { +// CHECK:STDOUT: %x.param_patt: %pattern_type.6b6 = value_param_pattern [concrete = constants.%x.param_patt] +// CHECK:STDOUT: %x.patt: %pattern_type.6b6 = wrapper_binding_pattern x, %x.param_patt [concrete = constants.%x.patt] +// CHECK:STDOUT: %return.param_patt: %pattern_type.6b6 = out_param_pattern [concrete = constants.%return.param_patt.a9a] +// CHECK:STDOUT: %return.patt: %pattern_type.6b6 = return_slot_pattern %return.param_patt, %i32.loc7_39 [concrete = constants.%return.patt.e1b] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %i32.loc7_39: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %.loc7: Core.Form = init_form %i32.loc7_39 [concrete = constants.%.795f] +// CHECK:STDOUT: %x.param: %i32 = value_param call_param0 +// CHECK:STDOUT: %i32.loc7_31: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %x: %i32 = wrapper_binding x, %x.param +// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %int_10: Core.IntLiteral = int_value 10 [concrete = constants.%int_10.64f] +// CHECK:STDOUT: %impl.elem0.loc7: %.b7a = impl_witness_access constants.%ImplicitAs.impl_witness.a2a, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.e39] +// CHECK:STDOUT: %bound_method.loc7_58.1: = bound_method %int_10, %impl.elem0.loc7 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.dcb] +// CHECK:STDOUT: %specific_fn.loc7: = specific_function %impl.elem0.loc7, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc7_58.2: = bound_method %int_10, %specific_fn.loc7 [concrete = constants.%bound_method.1b6] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc7: init %i32 = call %bound_method.loc7_58.2(%int_10) [concrete = constants.%int_10.6bf] +// CHECK:STDOUT: %.loc7_58.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc7 [concrete = constants.%int_10.6bf] +// CHECK:STDOUT: %.loc7_58.2: %i32 = converted %int_10, %.loc7_58.1 [concrete = constants.%int_10.6bf] +// CHECK:STDOUT: %fn.call.loc7: init %i32 = call %fn.decl.loc7(%.loc7_58.2) +// CHECK:STDOUT: %.loc7_60.1: %i32 = value_of_initializer %fn.call.loc7 +// CHECK:STDOUT: %.loc7_60.2: %i32 = converted %fn.call.loc7, %.loc7_60.1 +// CHECK:STDOUT: %i32.loc7: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %b: %i32 = wrapper_binding b, %.loc7_60.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %b.patt: %pattern_type.6b6 = value_binding_pattern b [concrete = constants.%b.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @fn.loc5(%x.param: %i32) -> out %return.param: %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %x.ref: %i32 = name_ref x, %x +// CHECK:STDOUT: %impl.elem0: %.737 = impl_witness_access constants.%Copy.impl_witness.b51, element0 [concrete = constants.%Int.as.Copy.impl.Op.4f6] +// CHECK:STDOUT: %bound_method.loc5_46.1: = bound_method %x.ref, %impl.elem0 +// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn] +// CHECK:STDOUT: %bound_method.loc5_46.2: = bound_method %x.ref, %specific_fn +// CHECK:STDOUT: %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc5_46.2(%x.ref) +// CHECK:STDOUT: return %Int.as.Copy.impl.Op.call +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @fn.loc7(%x.param: %i32) -> out %return.param: %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %x.ref: %i32 = name_ref x, %x +// CHECK:STDOUT: %impl.elem0: %.737 = impl_witness_access constants.%Copy.impl_witness.b51, element0 [concrete = constants.%Int.as.Copy.impl.Op.4f6] +// CHECK:STDOUT: %bound_method.loc7_52.1: = bound_method %x.ref, %impl.elem0 +// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn] +// CHECK:STDOUT: %bound_method.loc7_52.2: = bound_method %x.ref, %specific_fn +// CHECK:STDOUT: %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc7_52.2(%x.ref) +// CHECK:STDOUT: return %Int.as.Copy.impl.Op.call +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- generic_identity.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: type: type = facet_type [concrete] +// CHECK:STDOUT: %.Self.frozen: type = symbolic_binding .Self [symbolic_self] +// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete] +// CHECK:STDOUT: %pattern_type.e81: type = pattern_type %Copy.type [concrete] +// CHECK:STDOUT: %T.patt.fe6: %pattern_type.e81 = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %T.f84: %Copy.type = symbolic_binding T, 0 [symbolic] +// CHECK:STDOUT: %T.as_type: type = facet_access_type %T.f84 [symbolic] +// CHECK:STDOUT: %pattern_type.2c66b4.2: type = pattern_type %T.as_type [symbolic] +// CHECK:STDOUT: %x.param_patt.1f4: %pattern_type.2c66b4.2 = value_param_pattern [symbolic] +// CHECK:STDOUT: %x.patt.cec: %pattern_type.2c66b4.2 = wrapper_binding_pattern x, %x.param_patt.1f4 [symbolic] +// CHECK:STDOUT: %.1ce700.2: Core.Form = init_form %T.as_type [symbolic] +// CHECK:STDOUT: %return.param_patt.bf4475.2: %pattern_type.2c66b4.2 = out_param_pattern [symbolic] +// CHECK:STDOUT: %return.patt.f44: %pattern_type.2c66b4.2 = return_slot_pattern %return.param_patt.bf4475.2, %T.as_type [symbolic] +// CHECK:STDOUT: %fn.type: type = fn_type @fn [concrete] +// CHECK:STDOUT: %fn: %fn.type = struct_value () [concrete] +// CHECK:STDOUT: %require_complete.d83: = require_complete_type %T.as_type [symbolic] +// CHECK:STDOUT: %Copy.lookup_impl_witness.d9c: = lookup_impl_witness %T.f84, @Copy [symbolic] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.c85f21.2: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%T.f84) [symbolic] +// CHECK:STDOUT: %.c29: type = fn_type_with_self_type %Copy.WithSelf.Op.type.c85f21.2, %T.f84 [symbolic] +// CHECK:STDOUT: %impl.elem0.bd2: %.c29 = impl_witness_access %Copy.lookup_impl_witness.d9c, element0 [symbolic] +// CHECK:STDOUT: %specific_impl_fn.e2a: = specific_impl_function %impl.elem0.bd2, @Copy.WithSelf.Op(%T.f84) [symbolic] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete] +// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete] +// CHECK:STDOUT: %N: Core.IntLiteral = symbolic_binding N, 0 [symbolic] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %i32.builtin: type = int_type signed, %int_32 [concrete] +// CHECK:STDOUT: %complete_type.f8a: = complete_type_witness %i32.builtin [concrete] +// CHECK:STDOUT: %pattern_type.6b6: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %c.patt: %pattern_type.6b6 = value_binding_pattern c [concrete] +// CHECK:STDOUT: %int_42.20e: Core.IntLiteral = int_value 42 [concrete] +// CHECK:STDOUT: %As.type.116: type = generic_interface_type @As [concrete] +// CHECK:STDOUT: %As.generic: %As.type.116 = struct_value () [concrete] +// CHECK:STDOUT: %As.type.155: type = facet_type <@As, @As(%i32)> [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.c5d: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.6ee: %Core.IntLiteral.as.As.impl.Convert.type.c5d = struct_value () [symbolic] +// CHECK:STDOUT: %As.impl_witness.e7f: = impl_witness imports.%As.impl_witness_table.d22, @Core.IntLiteral.as.As.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.e79: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.8a4: %Core.IntLiteral.as.As.impl.Convert.type.e79 = struct_value () [concrete] +// CHECK:STDOUT: %As.facet: %As.type.155 = facet_value Core.IntLiteral, (%As.impl_witness.e7f) [concrete] +// CHECK:STDOUT: %As.WithSelf.Convert.type.d02: type = fn_type @As.WithSelf.Convert, @As.WithSelf(%i32, %As.facet) [concrete] +// CHECK:STDOUT: %.453: type = fn_type_with_self_type %As.WithSelf.Convert.type.d02, %As.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.bound: = bound_method %int_42.20e, %Core.IntLiteral.as.As.impl.Convert.8a4 [concrete] +// CHECK:STDOUT: %.795: Core.Form = init_form %i32 [concrete] +// CHECK:STDOUT: %return.param_patt.a9a: %pattern_type.6b6 = out_param_pattern [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.8a4, @Core.IntLiteral.as.As.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method: = bound_method %int_42.20e, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_42.ac4: %i32 = int_value 42 [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.ac8: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%N) [symbolic] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.5e0: %Int.as.Copy.impl.Op.type.ac8 = struct_value () [symbolic] +// CHECK:STDOUT: %Copy.impl_witness.b51: = impl_witness imports.%Copy.impl_witness_table.8d2, @Int.as.Copy.impl(%int_32) [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.3f6: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%int_32) [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.4f6: %Int.as.Copy.impl.Op.type.3f6 = struct_value () [concrete] +// CHECK:STDOUT: %Copy.facet.1e1: %Copy.type = facet_value %i32, (%Copy.impl_witness.b51) [concrete] +// CHECK:STDOUT: %x.param_patt.cee: %pattern_type.6b6 = value_param_pattern [concrete] +// CHECK:STDOUT: %x.patt.e3b: %pattern_type.6b6 = wrapper_binding_pattern x, %x.param_patt.cee [concrete] +// CHECK:STDOUT: %return.patt.e1b: %pattern_type.6b6 = return_slot_pattern %return.param_patt.a9a, %i32 [concrete] +// CHECK:STDOUT: %fn.specific_fn.2d9: = specific_function %fn, @fn(%Copy.facet.1e1) [concrete] +// CHECK:STDOUT: %pattern_type.831: type = pattern_type bool [concrete] +// CHECK:STDOUT: %d.patt: %pattern_type.831 = value_binding_pattern d [concrete] +// CHECK:STDOUT: %true: bool = bool_literal true [concrete] +// CHECK:STDOUT: %Copy.impl_witness.5e1: = impl_witness imports.%Copy.impl_witness_table.bda [concrete] +// CHECK:STDOUT: %Copy.facet.7af: %Copy.type = facet_value bool, (%Copy.impl_witness.5e1) [concrete] +// CHECK:STDOUT: %x.param_patt.37d: %pattern_type.831 = value_param_pattern [concrete] +// CHECK:STDOUT: %x.patt.e47: %pattern_type.831 = wrapper_binding_pattern x, %x.param_patt.37d [concrete] +// CHECK:STDOUT: %.f34: Core.Form = init_form bool [concrete] +// CHECK:STDOUT: %return.param_patt.5a1: %pattern_type.831 = out_param_pattern [concrete] +// CHECK:STDOUT: %return.patt.c0c: %pattern_type.831 = return_slot_pattern %return.param_patt.5a1, bool [concrete] +// CHECK:STDOUT: %fn.specific_fn.4f4: = specific_function %fn, @fn(%Copy.facet.7af) [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.381: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%Copy.facet.1e1) [concrete] +// CHECK:STDOUT: %.737: type = fn_type_with_self_type %Copy.WithSelf.Op.type.381, %Copy.facet.1e1 [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.specific_fn: = specific_function %Int.as.Copy.impl.Op.4f6, @Int.as.Copy.impl.Op(%int_32) [concrete] +// CHECK:STDOUT: %complete_type.127: = complete_type_witness bool [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.d02: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%Copy.facet.7af) [concrete] +// CHECK:STDOUT: %.e28: type = fn_type_with_self_type %Copy.WithSelf.Op.type.d02, %Copy.facet.7af [concrete] +// CHECK:STDOUT: %bool.as.Copy.impl.Op.type: type = fn_type @bool.as.Copy.impl.Op [concrete] +// CHECK:STDOUT: %bool.as.Copy.impl.Op: %bool.as.Copy.impl.Op.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .Copy = %Core.Copy +// CHECK:STDOUT: .Int = %Core.Int +// CHECK:STDOUT: .As = %Core.As +// CHECK:STDOUT: .Bool = %Core.Bool +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.Copy: type = import_ref Core//prelude/parts/copy, Copy, loaded [concrete = constants.%Copy.type] +// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic] +// CHECK:STDOUT: %Core.As: %As.type.116 = import_ref Core//prelude/parts/as, As, loaded [concrete = constants.%As.generic] +// CHECK:STDOUT: %Core.import_ref.64b: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.c5d) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.6ee)] +// CHECK:STDOUT: %As.impl_witness_table.d22 = impl_witness_table (%Core.import_ref.64b), @Core.IntLiteral.as.As.impl [concrete] +// CHECK:STDOUT: %Core.import_ref.cd6: @Int.as.Copy.impl.%Int.as.Copy.impl.Op.type (%Int.as.Copy.impl.Op.type.ac8) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Int.as.Copy.impl.%Int.as.Copy.impl.Op (constants.%Int.as.Copy.impl.Op.5e0)] +// CHECK:STDOUT: %Copy.impl_witness_table.8d2 = impl_witness_table (%Core.import_ref.cd6), @Int.as.Copy.impl [concrete] +// CHECK:STDOUT: %Core.Bool: type = import_ref Core//prelude/parts/bool, Bool, loaded [concrete = bool] +// CHECK:STDOUT: %Core.import_ref.9c3: %bool.as.Copy.impl.Op.type = import_ref Core//prelude/parts/copy, loc{{\d+_\d+}}, loaded [concrete = constants.%bool.as.Copy.impl.Op] +// CHECK:STDOUT: %Copy.impl_witness_table.bda = impl_witness_table (%Core.import_ref.9c3), @bool.as.Copy.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestGeneric() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %fn.decl: %fn.type = fn_decl @fn [concrete = constants.%fn] { +// CHECK:STDOUT: %T.patt.loc5_27.1: %pattern_type.e81 = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc5_27.2 (constants.%T.patt.fe6)] +// CHECK:STDOUT: %x.param_patt.loc5_41.1: @fn.%pattern_type (%pattern_type.2c66b4.2) = value_param_pattern [symbolic = %x.param_patt.loc5_41.2 (constants.%x.param_patt.1f4)] +// CHECK:STDOUT: %x.patt.loc5_41.1: @fn.%pattern_type (%pattern_type.2c66b4.2) = wrapper_binding_pattern x, %x.param_patt.loc5_41.1 [symbolic = %x.patt.loc5_41.2 (constants.%x.patt.cec)] +// CHECK:STDOUT: %return.param_patt.loc5_49.1: @fn.%pattern_type (%pattern_type.2c66b4.2) = out_param_pattern [symbolic = %return.param_patt.loc5_49.2 (constants.%return.param_patt.bf4475.2)] +// CHECK:STDOUT: %return.patt.loc5_46.1: @fn.%pattern_type (%pattern_type.2c66b4.2) = return_slot_pattern %return.param_patt.loc5_49.1, %.loc5_49.3 [symbolic = %return.patt.loc5_46.2 (constants.%return.patt.f44)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.ref.loc5_49: %Copy.type = name_ref T, %T.loc5_27.2 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc5_49: type = facet_access_type %T.ref.loc5_49 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc5_49.3: type = converted %T.ref.loc5_49, %T.as_type.loc5_49 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc5_49.4: Core.Form = init_form %.loc5_49.3 [symbolic = %.loc5_49.2 (constants.%.1ce700.2)] +// CHECK:STDOUT: %.loc5_33: type = splice_block %Copy.ref [concrete = constants.%Copy.type] { +// CHECK:STDOUT: %.Self.frozen: type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] +// CHECK:STDOUT: %Core.ref: = name_ref Core, imports.%Core [concrete = imports.%Core] +// CHECK:STDOUT: %Copy.ref: type = name_ref Copy, imports.%Core.Copy [concrete = constants.%Copy.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %T.loc5_27.2: %Copy.type = symbolic_binding T, 0 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %x.param: @fn.%T.as_type.loc5_43.1 (%T.as_type) = value_param call_param0 +// CHECK:STDOUT: %.loc5_43.1: type = splice_block %.loc5_43.2 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] { +// CHECK:STDOUT: %T.ref.loc5_43: %Copy.type = name_ref T, %T.loc5_27.2 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc5_43.2: type = facet_access_type %T.ref.loc5_43 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc5_43.2: type = converted %T.ref.loc5_43, %T.as_type.loc5_43.2 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %x: @fn.%T.as_type.loc5_43.1 (%T.as_type) = wrapper_binding x, %x.param +// CHECK:STDOUT: %return.param: ref @fn.%T.as_type.loc5_43.1 (%T.as_type) = out_param call_param1 +// CHECK:STDOUT: %return: ref @fn.%T.as_type.loc5_43.1 (%T.as_type) = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %generic_id: %fn.type = alias_binding generic_id, %fn.decl [concrete = constants.%fn] +// CHECK:STDOUT: %generic_id.ref.loc6: %fn.type = name_ref generic_id, %generic_id [concrete = constants.%fn] +// CHECK:STDOUT: %int_42: Core.IntLiteral = int_value 42 [concrete = constants.%int_42.20e] +// CHECK:STDOUT: %i32.loc6_40: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %impl.elem0: %.453 = impl_witness_access constants.%As.impl_witness.e7f, element0 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.8a4] +// CHECK:STDOUT: %bound_method.loc6_37.1: = bound_method %int_42, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.bound] +// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Core.IntLiteral.as.As.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc6_37.2: = bound_method %int_42, %specific_fn [concrete = constants.%bound_method] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i32 = call %bound_method.loc6_37.2(%int_42) [concrete = constants.%int_42.ac4] +// CHECK:STDOUT: %.loc6_37.1: %i32 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_42.ac4] +// CHECK:STDOUT: %.loc6_37.2: %i32 = converted %int_42, %.loc6_37.1 [concrete = constants.%int_42.ac4] +// CHECK:STDOUT: %Copy.facet.loc6_43.1: %Copy.type = facet_value constants.%i32, (constants.%Copy.impl_witness.b51) [concrete = constants.%Copy.facet.1e1] +// CHECK:STDOUT: %.loc6_43.1: %Copy.type = converted constants.%i32, %Copy.facet.loc6_43.1 [concrete = constants.%Copy.facet.1e1] +// CHECK:STDOUT: %Copy.facet.loc6_43.2: %Copy.type = facet_value constants.%i32, (constants.%Copy.impl_witness.b51) [concrete = constants.%Copy.facet.1e1] +// CHECK:STDOUT: %.loc6_43.2: %Copy.type = converted constants.%i32, %Copy.facet.loc6_43.2 [concrete = constants.%Copy.facet.1e1] +// CHECK:STDOUT: %fn.specific_fn.loc6: = specific_function %generic_id.ref.loc6, @fn(constants.%Copy.facet.1e1) [concrete = constants.%fn.specific_fn.2d9] +// CHECK:STDOUT: %fn.call.loc6: init %i32 = call %fn.specific_fn.loc6(%.loc6_37.2) +// CHECK:STDOUT: %.loc6_43.3: %i32 = value_of_initializer %fn.call.loc6 +// CHECK:STDOUT: %.loc6_43.4: %i32 = converted %fn.call.loc6, %.loc6_43.3 +// CHECK:STDOUT: %i32.loc6_17: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %c: %i32 = wrapper_binding c, %.loc6_43.4 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c.patt: %pattern_type.6b6 = value_binding_pattern c [concrete = constants.%c.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: %generic_id.ref.loc7: %fn.type = name_ref generic_id, %generic_id [concrete = constants.%fn] +// CHECK:STDOUT: %true: bool = bool_literal true [concrete = constants.%true] +// CHECK:STDOUT: %Copy.facet.loc7_39.1: %Copy.type = facet_value bool, (constants.%Copy.impl_witness.5e1) [concrete = constants.%Copy.facet.7af] +// CHECK:STDOUT: %.loc7_39.1: %Copy.type = converted bool, %Copy.facet.loc7_39.1 [concrete = constants.%Copy.facet.7af] +// CHECK:STDOUT: %Copy.facet.loc7_39.2: %Copy.type = facet_value bool, (constants.%Copy.impl_witness.5e1) [concrete = constants.%Copy.facet.7af] +// CHECK:STDOUT: %.loc7_39.2: %Copy.type = converted bool, %Copy.facet.loc7_39.2 [concrete = constants.%Copy.facet.7af] +// CHECK:STDOUT: %fn.specific_fn.loc7: = specific_function %generic_id.ref.loc7, @fn(constants.%Copy.facet.7af) [concrete = constants.%fn.specific_fn.4f4] +// CHECK:STDOUT: %fn.call.loc7: init bool = call %fn.specific_fn.loc7(%true) +// CHECK:STDOUT: %.loc7_39.3: bool = value_of_initializer %fn.call.loc7 +// CHECK:STDOUT: %.loc7_39.4: bool = converted %fn.call.loc7, %.loc7_39.3 +// CHECK:STDOUT: %.loc7_17: type = type_literal bool [concrete = bool] +// CHECK:STDOUT: %d: bool = wrapper_binding d, %.loc7_39.4 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %d.patt: %pattern_type.831 = value_binding_pattern d [concrete = constants.%d.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @fn(%T.loc5_27.2: %Copy.type) { +// CHECK:STDOUT: %T.patt.loc5_27.2: %pattern_type.e81 = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc5_27.2 (constants.%T.patt.fe6)] +// CHECK:STDOUT: %T.loc5_27.1: %Copy.type = symbolic_binding T, 0 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc5_43.1: type = facet_access_type %T.loc5_27.1 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %T.as_type.loc5_43.1 [symbolic = %pattern_type (constants.%pattern_type.2c66b4.2)] +// CHECK:STDOUT: %x.param_patt.loc5_41.2: @fn.%pattern_type (%pattern_type.2c66b4.2) = value_param_pattern [symbolic = %x.param_patt.loc5_41.2 (constants.%x.param_patt.1f4)] +// CHECK:STDOUT: %x.patt.loc5_41.2: @fn.%pattern_type (%pattern_type.2c66b4.2) = wrapper_binding_pattern x, %x.param_patt.loc5_41.2 [symbolic = %x.patt.loc5_41.2 (constants.%x.patt.cec)] +// CHECK:STDOUT: %.loc5_49.2: Core.Form = init_form %T.as_type.loc5_43.1 [symbolic = %.loc5_49.2 (constants.%.1ce700.2)] +// CHECK:STDOUT: %return.param_patt.loc5_49.2: @fn.%pattern_type (%pattern_type.2c66b4.2) = out_param_pattern [symbolic = %return.param_patt.loc5_49.2 (constants.%return.param_patt.bf4475.2)] +// CHECK:STDOUT: %return.patt.loc5_46.2: @fn.%pattern_type (%pattern_type.2c66b4.2) = return_slot_pattern %return.param_patt.loc5_49.2, %T.as_type.loc5_43.1 [symbolic = %return.patt.loc5_46.2 (constants.%return.patt.f44)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %T.as_type.loc5_43.1 [symbolic = %require_complete (constants.%require_complete.d83)] +// CHECK:STDOUT: %Copy.WithSelf.Op.type: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%T.loc5_27.1) [symbolic = %Copy.WithSelf.Op.type (constants.%Copy.WithSelf.Op.type.c85f21.2)] +// CHECK:STDOUT: %.loc5_60.3: type = fn_type_with_self_type %Copy.WithSelf.Op.type, %T.loc5_27.1 [symbolic = %.loc5_60.3 (constants.%.c29)] +// CHECK:STDOUT: %Copy.lookup_impl_witness: = lookup_impl_witness %T.loc5_27.1, @Copy [symbolic = %Copy.lookup_impl_witness (constants.%Copy.lookup_impl_witness.d9c)] +// CHECK:STDOUT: %impl.elem0.loc5_60.2: @fn.%.loc5_60.3 (%.c29) = impl_witness_access %Copy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc5_60.2 (constants.%impl.elem0.bd2)] +// CHECK:STDOUT: %specific_impl_fn.loc5_60.2: = specific_impl_function %impl.elem0.loc5_60.2, @Copy.WithSelf.Op(%T.loc5_27.1) [symbolic = %specific_impl_fn.loc5_60.2 (constants.%specific_impl_fn.e2a)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%x.param: @fn.%T.as_type.loc5_43.1 (%T.as_type)) -> out %return.param: @fn.%T.as_type.loc5_43.1 (%T.as_type) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %x.ref: @fn.%T.as_type.loc5_43.1 (%T.as_type) = name_ref x, %x +// CHECK:STDOUT: %impl.elem0.loc5_60.1: @fn.%.loc5_60.3 (%.c29) = impl_witness_access constants.%Copy.lookup_impl_witness.d9c, element0 [symbolic = %impl.elem0.loc5_60.2 (constants.%impl.elem0.bd2)] +// CHECK:STDOUT: %bound_method.loc5_60.1: = bound_method %x.ref, %impl.elem0.loc5_60.1 +// CHECK:STDOUT: %.loc5_60.1: %Copy.type = converted constants.%T.as_type, constants.%T.f84 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %.loc5_60.2: %Copy.type = converted constants.%T.as_type, constants.%T.f84 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %specific_impl_fn.loc5_60.1: = specific_impl_function %impl.elem0.loc5_60.1, @Copy.WithSelf.Op(constants.%T.f84) [symbolic = %specific_impl_fn.loc5_60.2 (constants.%specific_impl_fn.e2a)] +// CHECK:STDOUT: %bound_method.loc5_60.2: = bound_method %x.ref, %specific_impl_fn.loc5_60.1 +// CHECK:STDOUT: %.loc5_49.1: ref @fn.%T.as_type.loc5_43.1 (%T.as_type) = splice_block %return.param {} +// CHECK:STDOUT: %Copy.WithSelf.Op.call: init @fn.%T.as_type.loc5_43.1 (%T.as_type) to %.loc5_49.1 = call %bound_method.loc5_60.2(%x.ref) +// CHECK:STDOUT: return %Copy.WithSelf.Op.call to %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn(constants.%T.f84) { +// CHECK:STDOUT: %T.patt.loc5_27.2 => constants.%T.patt.fe6 +// CHECK:STDOUT: %T.loc5_27.1 => constants.%T.f84 +// CHECK:STDOUT: %T.as_type.loc5_43.1 => constants.%T.as_type +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.2c66b4.2 +// CHECK:STDOUT: %x.param_patt.loc5_41.2 => constants.%x.param_patt.1f4 +// CHECK:STDOUT: %x.patt.loc5_41.2 => constants.%x.patt.cec +// CHECK:STDOUT: %.loc5_49.2 => constants.%.1ce700.2 +// CHECK:STDOUT: %return.param_patt.loc5_49.2 => constants.%return.param_patt.bf4475.2 +// CHECK:STDOUT: %return.patt.loc5_46.2 => constants.%return.patt.f44 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn(constants.%Copy.facet.1e1) { +// CHECK:STDOUT: %T.patt.loc5_27.2 => constants.%T.patt.fe6 +// CHECK:STDOUT: %T.loc5_27.1 => constants.%Copy.facet.1e1 +// CHECK:STDOUT: %T.as_type.loc5_43.1 => constants.%i32 +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.6b6 +// CHECK:STDOUT: %x.param_patt.loc5_41.2 => constants.%x.param_patt.cee +// CHECK:STDOUT: %x.patt.loc5_41.2 => constants.%x.patt.e3b +// CHECK:STDOUT: %.loc5_49.2 => constants.%.795 +// CHECK:STDOUT: %return.param_patt.loc5_49.2 => constants.%return.param_patt.a9a +// CHECK:STDOUT: %return.patt.loc5_46.2 => constants.%return.patt.e1b +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type.f8a +// CHECK:STDOUT: %Copy.WithSelf.Op.type => constants.%Copy.WithSelf.Op.type.381 +// CHECK:STDOUT: %.loc5_60.3 => constants.%.737 +// CHECK:STDOUT: %Copy.lookup_impl_witness => constants.%Copy.impl_witness.b51 +// CHECK:STDOUT: %impl.elem0.loc5_60.2 => constants.%Int.as.Copy.impl.Op.4f6 +// CHECK:STDOUT: %specific_impl_fn.loc5_60.2 => constants.%Int.as.Copy.impl.Op.specific_fn +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn(constants.%Copy.facet.7af) { +// CHECK:STDOUT: %T.patt.loc5_27.2 => constants.%T.patt.fe6 +// CHECK:STDOUT: %T.loc5_27.1 => constants.%Copy.facet.7af +// CHECK:STDOUT: %T.as_type.loc5_43.1 => bool +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.831 +// CHECK:STDOUT: %x.param_patt.loc5_41.2 => constants.%x.param_patt.37d +// CHECK:STDOUT: %x.patt.loc5_41.2 => constants.%x.patt.e47 +// CHECK:STDOUT: %.loc5_49.2 => constants.%.f34 +// CHECK:STDOUT: %return.param_patt.loc5_49.2 => constants.%return.param_patt.5a1 +// CHECK:STDOUT: %return.patt.loc5_46.2 => constants.%return.patt.c0c +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type.127 +// CHECK:STDOUT: %Copy.WithSelf.Op.type => constants.%Copy.WithSelf.Op.type.d02 +// CHECK:STDOUT: %.loc5_60.3 => constants.%.e28 +// CHECK:STDOUT: %Copy.lookup_impl_witness => constants.%Copy.impl_witness.5e1 +// CHECK:STDOUT: %impl.elem0.loc5_60.2 => constants.%bool.as.Copy.impl.Op +// CHECK:STDOUT: %specific_impl_fn.loc5_60.2 => constants.%bool.as.Copy.impl.Op +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- generic_nested.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: type: type = facet_type [concrete] +// CHECK:STDOUT: %.Self.frozen: type = symbolic_binding .Self [symbolic_self] +// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete] +// CHECK:STDOUT: %pattern_type.e81: type = pattern_type %Copy.type [concrete] +// CHECK:STDOUT: %T.patt.fe6: %pattern_type.e81 = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %T.f84: %Copy.type = symbolic_binding T, 0 [symbolic] +// CHECK:STDOUT: %T.as_type: type = facet_access_type %T.f84 [symbolic] +// CHECK:STDOUT: %pattern_type.2c66b4.2: type = pattern_type %T.as_type [symbolic] +// CHECK:STDOUT: %x.param_patt.1f4: %pattern_type.2c66b4.2 = value_param_pattern [symbolic] +// CHECK:STDOUT: %x.patt.cec: %pattern_type.2c66b4.2 = wrapper_binding_pattern x, %x.param_patt.1f4 [symbolic] +// CHECK:STDOUT: %.1ce700.2: Core.Form = init_form %T.as_type [symbolic] +// CHECK:STDOUT: %return.param_patt.bf4475.2: %pattern_type.2c66b4.2 = out_param_pattern [symbolic] +// CHECK:STDOUT: %return.patt.f44: %pattern_type.2c66b4.2 = return_slot_pattern %return.param_patt.bf4475.2, %T.as_type [symbolic] +// CHECK:STDOUT: %fn.type.c16: type = fn_type @fn.loc5 [concrete] +// CHECK:STDOUT: %fn.415: %fn.type.c16 = struct_value () [concrete] +// CHECK:STDOUT: %require_complete.d83: = require_complete_type %T.as_type [symbolic] +// CHECK:STDOUT: %y.param_patt.ec0: %pattern_type.2c66b4.2 = value_param_pattern [symbolic] +// CHECK:STDOUT: %y.patt.d6d: %pattern_type.2c66b4.2 = wrapper_binding_pattern y, %y.param_patt.ec0 [symbolic] +// CHECK:STDOUT: %fn.type.cce: type = fn_type @fn.loc6, @fn.loc5(%T.f84) [symbolic] +// CHECK:STDOUT: %fn.e7c: %fn.type.cce = struct_value () [symbolic] +// CHECK:STDOUT: %z.param_patt.b42: %pattern_type.2c66b4.2 = value_param_pattern [symbolic] +// CHECK:STDOUT: %z.patt.513: %pattern_type.2c66b4.2 = wrapper_binding_pattern z, %z.param_patt.b42 [symbolic] +// CHECK:STDOUT: %fn.type.278: type = fn_type @fn.loc7, @fn.loc6(%T.f84) [symbolic] +// CHECK:STDOUT: %fn.ea9: %fn.type.278 = struct_value () [symbolic] +// CHECK:STDOUT: %Copy.lookup_impl_witness.d9c: = lookup_impl_witness %T.f84, @Copy [symbolic] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.c85f21.2: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%T.f84) [symbolic] +// CHECK:STDOUT: %.c29: type = fn_type_with_self_type %Copy.WithSelf.Op.type.c85f21.2, %T.f84 [symbolic] +// CHECK:STDOUT: %impl.elem0.bd2: %.c29 = impl_witness_access %Copy.lookup_impl_witness.d9c, element0 [symbolic] +// CHECK:STDOUT: %specific_impl_fn.e2a: = specific_impl_function %impl.elem0.bd2, @Copy.WithSelf.Op(%T.f84) [symbolic] +// CHECK:STDOUT: %fn.specific_fn.79b: = specific_function %fn.ea9, @fn.loc7(%T.f84) [symbolic] +// CHECK:STDOUT: %fn.specific_fn.6cf: = specific_function %fn.e7c, @fn.loc6(%T.f84) [symbolic] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete] +// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete] +// CHECK:STDOUT: %N: Core.IntLiteral = symbolic_binding N, 0 [symbolic] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %i32.builtin: type = int_type signed, %int_32 [concrete] +// CHECK:STDOUT: %complete_type.f8a: = complete_type_witness %i32.builtin [concrete] +// CHECK:STDOUT: %pattern_type.6b6: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %c.patt: %pattern_type.6b6 = value_binding_pattern c [concrete] +// CHECK:STDOUT: %int_42.20e: Core.IntLiteral = int_value 42 [concrete] +// CHECK:STDOUT: %As.type.116: type = generic_interface_type @As [concrete] +// CHECK:STDOUT: %As.generic: %As.type.116 = struct_value () [concrete] +// CHECK:STDOUT: %As.type.155: type = facet_type <@As, @As(%i32)> [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.c5d: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.6ee: %Core.IntLiteral.as.As.impl.Convert.type.c5d = struct_value () [symbolic] +// CHECK:STDOUT: %As.impl_witness.e7f: = impl_witness imports.%As.impl_witness_table.d22, @Core.IntLiteral.as.As.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.e79: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.8a4: %Core.IntLiteral.as.As.impl.Convert.type.e79 = struct_value () [concrete] +// CHECK:STDOUT: %As.facet: %As.type.155 = facet_value Core.IntLiteral, (%As.impl_witness.e7f) [concrete] +// CHECK:STDOUT: %As.WithSelf.Convert.type.d02: type = fn_type @As.WithSelf.Convert, @As.WithSelf(%i32, %As.facet) [concrete] +// CHECK:STDOUT: %.453: type = fn_type_with_self_type %As.WithSelf.Convert.type.d02, %As.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.bound: = bound_method %int_42.20e, %Core.IntLiteral.as.As.impl.Convert.8a4 [concrete] +// CHECK:STDOUT: %.795: Core.Form = init_form %i32 [concrete] +// CHECK:STDOUT: %return.param_patt.a9a: %pattern_type.6b6 = out_param_pattern [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.8a4, @Core.IntLiteral.as.As.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method: = bound_method %int_42.20e, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_42.ac4: %i32 = int_value 42 [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.ac8: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%N) [symbolic] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.5e0: %Int.as.Copy.impl.Op.type.ac8 = struct_value () [symbolic] +// CHECK:STDOUT: %Copy.impl_witness.b51: = impl_witness imports.%Copy.impl_witness_table.8d2, @Int.as.Copy.impl(%int_32) [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.3f6: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%int_32) [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.4f6: %Int.as.Copy.impl.Op.type.3f6 = struct_value () [concrete] +// CHECK:STDOUT: %Copy.facet.1e1: %Copy.type = facet_value %i32, (%Copy.impl_witness.b51) [concrete] +// CHECK:STDOUT: %x.param_patt.cee: %pattern_type.6b6 = value_param_pattern [concrete] +// CHECK:STDOUT: %x.patt.e3b: %pattern_type.6b6 = wrapper_binding_pattern x, %x.param_patt.cee [concrete] +// CHECK:STDOUT: %return.patt.e1b: %pattern_type.6b6 = return_slot_pattern %return.param_patt.a9a, %i32 [concrete] +// CHECK:STDOUT: %fn.specific_fn.eb8: = specific_function %fn.415, @fn.loc5(%Copy.facet.1e1) [concrete] +// CHECK:STDOUT: %pattern_type.831: type = pattern_type bool [concrete] +// CHECK:STDOUT: %d.patt: %pattern_type.831 = value_binding_pattern d [concrete] +// CHECK:STDOUT: %true: bool = bool_literal true [concrete] +// CHECK:STDOUT: %Copy.impl_witness.5e1: = impl_witness imports.%Copy.impl_witness_table.bda [concrete] +// CHECK:STDOUT: %Copy.facet.7af: %Copy.type = facet_value bool, (%Copy.impl_witness.5e1) [concrete] +// CHECK:STDOUT: %x.param_patt.37d: %pattern_type.831 = value_param_pattern [concrete] +// CHECK:STDOUT: %x.patt.e47: %pattern_type.831 = wrapper_binding_pattern x, %x.param_patt.37d [concrete] +// CHECK:STDOUT: %.f34: Core.Form = init_form bool [concrete] +// CHECK:STDOUT: %return.param_patt.5a1: %pattern_type.831 = out_param_pattern [concrete] +// CHECK:STDOUT: %return.patt.c0c: %pattern_type.831 = return_slot_pattern %return.param_patt.5a1, bool [concrete] +// CHECK:STDOUT: %fn.specific_fn.1a6: = specific_function %fn.415, @fn.loc5(%Copy.facet.7af) [concrete] +// CHECK:STDOUT: %fn.type.b76: type = fn_type @fn.loc6, @fn.loc5(%Copy.facet.1e1) [concrete] +// CHECK:STDOUT: %fn.5bc: %fn.type.b76 = struct_value () [concrete] +// CHECK:STDOUT: %y.param_patt.673: %pattern_type.6b6 = value_param_pattern [concrete] +// CHECK:STDOUT: %y.patt.547: %pattern_type.6b6 = wrapper_binding_pattern y, %y.param_patt.673 [concrete] +// CHECK:STDOUT: %fn.specific_fn.097: = specific_function %fn.5bc, @fn.loc6(%Copy.facet.1e1) [concrete] +// CHECK:STDOUT: %complete_type.127: = complete_type_witness bool [concrete] +// CHECK:STDOUT: %fn.type.60a: type = fn_type @fn.loc6, @fn.loc5(%Copy.facet.7af) [concrete] +// CHECK:STDOUT: %fn.bab: %fn.type.60a = struct_value () [concrete] +// CHECK:STDOUT: %y.param_patt.077: %pattern_type.831 = value_param_pattern [concrete] +// CHECK:STDOUT: %y.patt.252: %pattern_type.831 = wrapper_binding_pattern y, %y.param_patt.077 [concrete] +// CHECK:STDOUT: %fn.specific_fn.b85: = specific_function %fn.bab, @fn.loc6(%Copy.facet.7af) [concrete] +// CHECK:STDOUT: %fn.type.7d5: type = fn_type @fn.loc7, @fn.loc6(%Copy.facet.1e1) [concrete] +// CHECK:STDOUT: %fn.ecf: %fn.type.7d5 = struct_value () [concrete] +// CHECK:STDOUT: %z.param_patt.9ae: %pattern_type.6b6 = value_param_pattern [concrete] +// CHECK:STDOUT: %z.patt.45e: %pattern_type.6b6 = wrapper_binding_pattern z, %z.param_patt.9ae [concrete] +// CHECK:STDOUT: %fn.specific_fn.73d: = specific_function %fn.ecf, @fn.loc7(%Copy.facet.1e1) [concrete] +// CHECK:STDOUT: %fn.type.d10: type = fn_type @fn.loc7, @fn.loc6(%Copy.facet.7af) [concrete] +// CHECK:STDOUT: %fn.ac0: %fn.type.d10 = struct_value () [concrete] +// CHECK:STDOUT: %z.param_patt.a49: %pattern_type.831 = value_param_pattern [concrete] +// CHECK:STDOUT: %z.patt.246: %pattern_type.831 = wrapper_binding_pattern z, %z.param_patt.a49 [concrete] +// CHECK:STDOUT: %fn.specific_fn.99d: = specific_function %fn.ac0, @fn.loc7(%Copy.facet.7af) [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.381: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%Copy.facet.1e1) [concrete] +// CHECK:STDOUT: %.737: type = fn_type_with_self_type %Copy.WithSelf.Op.type.381, %Copy.facet.1e1 [concrete] +// CHECK:STDOUT: %Int.as.Copy.impl.Op.specific_fn: = specific_function %Int.as.Copy.impl.Op.4f6, @Int.as.Copy.impl.Op(%int_32) [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.d02: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%Copy.facet.7af) [concrete] +// CHECK:STDOUT: %.e28: type = fn_type_with_self_type %Copy.WithSelf.Op.type.d02, %Copy.facet.7af [concrete] +// CHECK:STDOUT: %bool.as.Copy.impl.Op.type: type = fn_type @bool.as.Copy.impl.Op [concrete] +// CHECK:STDOUT: %bool.as.Copy.impl.Op: %bool.as.Copy.impl.Op.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .Copy = %Core.Copy +// CHECK:STDOUT: .Int = %Core.Int +// CHECK:STDOUT: .As = %Core.As +// CHECK:STDOUT: .Bool = %Core.Bool +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.Copy: type = import_ref Core//prelude/parts/copy, Copy, loaded [concrete = constants.%Copy.type] +// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic] +// CHECK:STDOUT: %Core.As: %As.type.116 = import_ref Core//prelude/parts/as, As, loaded [concrete = constants.%As.generic] +// CHECK:STDOUT: %Core.import_ref.64b: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.c5d) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.6ee)] +// CHECK:STDOUT: %As.impl_witness_table.d22 = impl_witness_table (%Core.import_ref.64b), @Core.IntLiteral.as.As.impl [concrete] +// CHECK:STDOUT: %Core.import_ref.cd6: @Int.as.Copy.impl.%Int.as.Copy.impl.Op.type (%Int.as.Copy.impl.Op.type.ac8) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Int.as.Copy.impl.%Int.as.Copy.impl.Op (constants.%Int.as.Copy.impl.Op.5e0)] +// CHECK:STDOUT: %Copy.impl_witness_table.8d2 = impl_witness_table (%Core.import_ref.cd6), @Int.as.Copy.impl [concrete] +// CHECK:STDOUT: %Core.Bool: type = import_ref Core//prelude/parts/bool, Bool, loaded [concrete = bool] +// CHECK:STDOUT: %Core.import_ref.9c3: %bool.as.Copy.impl.Op.type = import_ref Core//prelude/parts/copy, loc{{\d+_\d+}}, loaded [concrete = constants.%bool.as.Copy.impl.Op] +// CHECK:STDOUT: %Copy.impl_witness_table.bda = impl_witness_table (%Core.import_ref.9c3), @bool.as.Copy.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestGenericNested() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %fn.decl: %fn.type.c16 = fn_decl @fn.loc5 [concrete = constants.%fn.415] { +// CHECK:STDOUT: %T.patt.loc5_27.1: %pattern_type.e81 = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc5_27.2 (constants.%T.patt.fe6)] +// CHECK:STDOUT: %x.param_patt.loc5_41.1: @fn.loc5.%pattern_type (%pattern_type.2c66b4.2) = value_param_pattern [symbolic = %x.param_patt.loc5_41.2 (constants.%x.param_patt.1f4)] +// CHECK:STDOUT: %x.patt.loc5_41.1: @fn.loc5.%pattern_type (%pattern_type.2c66b4.2) = wrapper_binding_pattern x, %x.param_patt.loc5_41.1 [symbolic = %x.patt.loc5_41.2 (constants.%x.patt.cec)] +// CHECK:STDOUT: %return.param_patt.loc5_49.1: @fn.loc5.%pattern_type (%pattern_type.2c66b4.2) = out_param_pattern [symbolic = %return.param_patt.loc5_49.2 (constants.%return.param_patt.bf4475.2)] +// CHECK:STDOUT: %return.patt.loc5_46.1: @fn.loc5.%pattern_type (%pattern_type.2c66b4.2) = return_slot_pattern %return.param_patt.loc5_49.1, %.loc5_49.3 [symbolic = %return.patt.loc5_46.2 (constants.%return.patt.f44)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.ref.loc5_49: %Copy.type = name_ref T, %T.loc5_27.2 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc5_49: type = facet_access_type %T.ref.loc5_49 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc5_49.3: type = converted %T.ref.loc5_49, %T.as_type.loc5_49 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc5_49.4: Core.Form = init_form %.loc5_49.3 [symbolic = %.loc5_49.2 (constants.%.1ce700.2)] +// CHECK:STDOUT: %.loc5_33: type = splice_block %Copy.ref [concrete = constants.%Copy.type] { +// CHECK:STDOUT: %.Self.frozen: type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] +// CHECK:STDOUT: %Core.ref: = name_ref Core, imports.%Core [concrete = imports.%Core] +// CHECK:STDOUT: %Copy.ref: type = name_ref Copy, imports.%Core.Copy [concrete = constants.%Copy.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %T.loc5_27.2: %Copy.type = symbolic_binding T, 0 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %x.param: @fn.loc5.%T.as_type.loc5_43.1 (%T.as_type) = value_param call_param0 +// CHECK:STDOUT: %.loc5_43.1: type = splice_block %.loc5_43.2 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] { +// CHECK:STDOUT: %T.ref.loc5_43: %Copy.type = name_ref T, %T.loc5_27.2 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc5_43.2: type = facet_access_type %T.ref.loc5_43 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc5_43.2: type = converted %T.ref.loc5_43, %T.as_type.loc5_43.2 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %x: @fn.loc5.%T.as_type.loc5_43.1 (%T.as_type) = wrapper_binding x, %x.param +// CHECK:STDOUT: %return.param: ref @fn.loc5.%T.as_type.loc5_43.1 (%T.as_type) = out_param call_param1 +// CHECK:STDOUT: %return: ref @fn.loc5.%T.as_type.loc5_43.1 (%T.as_type) = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %generic_id: %fn.type.c16 = alias_binding generic_id, %fn.decl [concrete = constants.%fn.415] +// CHECK:STDOUT: %generic_id.ref.loc12: %fn.type.c16 = name_ref generic_id, %generic_id [concrete = constants.%fn.415] +// CHECK:STDOUT: %int_42: Core.IntLiteral = int_value 42 [concrete = constants.%int_42.20e] +// CHECK:STDOUT: %i32.loc12_40: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %impl.elem0: %.453 = impl_witness_access constants.%As.impl_witness.e7f, element0 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.8a4] +// CHECK:STDOUT: %bound_method.loc12_37.1: = bound_method %int_42, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.bound] +// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Core.IntLiteral.as.As.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc12_37.2: = bound_method %int_42, %specific_fn [concrete = constants.%bound_method] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i32 = call %bound_method.loc12_37.2(%int_42) [concrete = constants.%int_42.ac4] +// CHECK:STDOUT: %.loc12_37.1: %i32 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_42.ac4] +// CHECK:STDOUT: %.loc12_37.2: %i32 = converted %int_42, %.loc12_37.1 [concrete = constants.%int_42.ac4] +// CHECK:STDOUT: %Copy.facet.loc12_43.1: %Copy.type = facet_value constants.%i32, (constants.%Copy.impl_witness.b51) [concrete = constants.%Copy.facet.1e1] +// CHECK:STDOUT: %.loc12_43.1: %Copy.type = converted constants.%i32, %Copy.facet.loc12_43.1 [concrete = constants.%Copy.facet.1e1] +// CHECK:STDOUT: %Copy.facet.loc12_43.2: %Copy.type = facet_value constants.%i32, (constants.%Copy.impl_witness.b51) [concrete = constants.%Copy.facet.1e1] +// CHECK:STDOUT: %.loc12_43.2: %Copy.type = converted constants.%i32, %Copy.facet.loc12_43.2 [concrete = constants.%Copy.facet.1e1] +// CHECK:STDOUT: %fn.specific_fn.loc12: = specific_function %generic_id.ref.loc12, @fn.loc5(constants.%Copy.facet.1e1) [concrete = constants.%fn.specific_fn.eb8] +// CHECK:STDOUT: %fn.call.loc12: init %i32 = call %fn.specific_fn.loc12(%.loc12_37.2) +// CHECK:STDOUT: %.loc12_43.3: %i32 = value_of_initializer %fn.call.loc12 +// CHECK:STDOUT: %.loc12_43.4: %i32 = converted %fn.call.loc12, %.loc12_43.3 +// CHECK:STDOUT: %i32.loc12_17: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %c: %i32 = wrapper_binding c, %.loc12_43.4 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c.patt: %pattern_type.6b6 = value_binding_pattern c [concrete = constants.%c.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: %generic_id.ref.loc13: %fn.type.c16 = name_ref generic_id, %generic_id [concrete = constants.%fn.415] +// CHECK:STDOUT: %true: bool = bool_literal true [concrete = constants.%true] +// CHECK:STDOUT: %Copy.facet.loc13_39.1: %Copy.type = facet_value bool, (constants.%Copy.impl_witness.5e1) [concrete = constants.%Copy.facet.7af] +// CHECK:STDOUT: %.loc13_39.1: %Copy.type = converted bool, %Copy.facet.loc13_39.1 [concrete = constants.%Copy.facet.7af] +// CHECK:STDOUT: %Copy.facet.loc13_39.2: %Copy.type = facet_value bool, (constants.%Copy.impl_witness.5e1) [concrete = constants.%Copy.facet.7af] +// CHECK:STDOUT: %.loc13_39.2: %Copy.type = converted bool, %Copy.facet.loc13_39.2 [concrete = constants.%Copy.facet.7af] +// CHECK:STDOUT: %fn.specific_fn.loc13: = specific_function %generic_id.ref.loc13, @fn.loc5(constants.%Copy.facet.7af) [concrete = constants.%fn.specific_fn.1a6] +// CHECK:STDOUT: %fn.call.loc13: init bool = call %fn.specific_fn.loc13(%true) +// CHECK:STDOUT: %.loc13_39.3: bool = value_of_initializer %fn.call.loc13 +// CHECK:STDOUT: %.loc13_39.4: bool = converted %fn.call.loc13, %.loc13_39.3 +// CHECK:STDOUT: %.loc13_17: type = type_literal bool [concrete = bool] +// CHECK:STDOUT: %d: bool = wrapper_binding d, %.loc13_39.4 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %d.patt: %pattern_type.831 = value_binding_pattern d [concrete = constants.%d.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @fn.loc5(%T.loc5_27.2: %Copy.type) { +// CHECK:STDOUT: %T.patt.loc5_27.2: %pattern_type.e81 = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc5_27.2 (constants.%T.patt.fe6)] +// CHECK:STDOUT: %T.loc5_27.1: %Copy.type = symbolic_binding T, 0 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc5_43.1: type = facet_access_type %T.loc5_27.1 [symbolic = %T.as_type.loc5_43.1 (constants.%T.as_type)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %T.as_type.loc5_43.1 [symbolic = %pattern_type (constants.%pattern_type.2c66b4.2)] +// CHECK:STDOUT: %x.param_patt.loc5_41.2: @fn.loc5.%pattern_type (%pattern_type.2c66b4.2) = value_param_pattern [symbolic = %x.param_patt.loc5_41.2 (constants.%x.param_patt.1f4)] +// CHECK:STDOUT: %x.patt.loc5_41.2: @fn.loc5.%pattern_type (%pattern_type.2c66b4.2) = wrapper_binding_pattern x, %x.param_patt.loc5_41.2 [symbolic = %x.patt.loc5_41.2 (constants.%x.patt.cec)] +// CHECK:STDOUT: %.loc5_49.2: Core.Form = init_form %T.as_type.loc5_43.1 [symbolic = %.loc5_49.2 (constants.%.1ce700.2)] +// CHECK:STDOUT: %return.param_patt.loc5_49.2: @fn.loc5.%pattern_type (%pattern_type.2c66b4.2) = out_param_pattern [symbolic = %return.param_patt.loc5_49.2 (constants.%return.param_patt.bf4475.2)] +// CHECK:STDOUT: %return.patt.loc5_46.2: @fn.loc5.%pattern_type (%pattern_type.2c66b4.2) = return_slot_pattern %return.param_patt.loc5_49.2, %T.as_type.loc5_43.1 [symbolic = %return.patt.loc5_46.2 (constants.%return.patt.f44)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %T.as_type.loc5_43.1 [symbolic = %require_complete (constants.%require_complete.d83)] +// CHECK:STDOUT: %fn.type: type = fn_type @fn.loc6, @fn.loc5(%T.loc5_27.1) [symbolic = %fn.type (constants.%fn.type.cce)] +// CHECK:STDOUT: %fn: @fn.loc5.%fn.type (%fn.type.cce) = struct_value () [symbolic = %fn (constants.%fn.e7c)] +// CHECK:STDOUT: %fn.specific_fn.loc6_26.2: = specific_function %fn, @fn.loc6(%T.loc5_27.1) [symbolic = %fn.specific_fn.loc6_26.2 (constants.%fn.specific_fn.6cf)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%x.param: @fn.loc5.%T.as_type.loc5_43.1 (%T.as_type)) -> out %return.param: @fn.loc5.%T.as_type.loc5_43.1 (%T.as_type) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %fn.decl: @fn.loc5.%fn.type (%fn.type.cce) = fn_decl @fn.loc6 [symbolic = @fn.loc5.%fn (constants.%fn.e7c)] { +// CHECK:STDOUT: %y.param_patt.loc6_16.1: @fn.loc6.%pattern_type (%pattern_type.2c66b4.2) = value_param_pattern [symbolic = %y.param_patt.loc6_16.2 (constants.%y.param_patt.ec0)] +// CHECK:STDOUT: %y.patt.loc6_16.1: @fn.loc6.%pattern_type (%pattern_type.2c66b4.2) = wrapper_binding_pattern y, %y.param_patt.loc6_16.1 [symbolic = %y.patt.loc6_16.2 (constants.%y.patt.d6d)] +// CHECK:STDOUT: %return.param_patt.loc6_24.1: @fn.loc6.%pattern_type (%pattern_type.2c66b4.2) = out_param_pattern [symbolic = %return.param_patt.loc6_24.2 (constants.%return.param_patt.bf4475.2)] +// CHECK:STDOUT: %return.patt.loc6_21.1: @fn.loc6.%pattern_type (%pattern_type.2c66b4.2) = return_slot_pattern %return.param_patt.loc6_24.1, %.loc6_24.3 [symbolic = %return.patt.loc6_21.2 (constants.%return.patt.f44)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.ref.loc6_24: %Copy.type = name_ref T, @fn.loc5.%T.loc5_27.2 [symbolic = %T (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc6_24: type = facet_access_type %T.ref.loc6_24 [symbolic = %T.as_type.loc6_18.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc6_24.3: type = converted %T.ref.loc6_24, %T.as_type.loc6_24 [symbolic = %T.as_type.loc6_18.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc6_24.4: Core.Form = init_form %.loc6_24.3 [symbolic = %.loc6_24.2 (constants.%.1ce700.2)] +// CHECK:STDOUT: %y.param: @fn.loc6.%T.as_type.loc6_18.1 (%T.as_type) = value_param call_param0 +// CHECK:STDOUT: %.loc6_18.1: type = splice_block %.loc6_18.2 [symbolic = %T.as_type.loc6_18.1 (constants.%T.as_type)] { +// CHECK:STDOUT: %T.ref.loc6_18: %Copy.type = name_ref T, @fn.loc5.%T.loc5_27.2 [symbolic = %T (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc6_18.2: type = facet_access_type %T.ref.loc6_18 [symbolic = %T.as_type.loc6_18.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc6_18.2: type = converted %T.ref.loc6_18, %T.as_type.loc6_18.2 [symbolic = %T.as_type.loc6_18.1 (constants.%T.as_type)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %y: @fn.loc6.%T.as_type.loc6_18.1 (%T.as_type) = wrapper_binding y, %y.param +// CHECK:STDOUT: %return.param: ref @fn.loc6.%T.as_type.loc6_18.1 (%T.as_type) = out_param call_param1 +// CHECK:STDOUT: %return: ref @fn.loc6.%T.as_type.loc6_18.1 (%T.as_type) = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %x.ref: @fn.loc5.%T.as_type.loc5_43.1 (%T.as_type) = name_ref x, %x +// CHECK:STDOUT: %.loc10_8.1: %Copy.type = converted constants.%T.as_type, constants.%T.f84 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %.loc10_8.2: %Copy.type = converted constants.%T.as_type, constants.%T.f84 [symbolic = %T.loc5_27.1 (constants.%T.f84)] +// CHECK:STDOUT: %fn.specific_fn.loc6_26.1: = specific_function %fn.decl, @fn.loc6(constants.%T.f84) [symbolic = %fn.specific_fn.loc6_26.2 (constants.%fn.specific_fn.6cf)] +// CHECK:STDOUT: %.loc5_49.1: ref @fn.loc5.%T.as_type.loc5_43.1 (%T.as_type) = splice_block %return.param {} +// CHECK:STDOUT: %fn.call: init @fn.loc5.%T.as_type.loc5_43.1 (%T.as_type) to %.loc5_49.1 = call %fn.specific_fn.loc6_26.1(%x.ref) +// CHECK:STDOUT: return %fn.call to %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @fn.loc6(@fn.loc5.%T.loc5_27.2: %Copy.type) { +// CHECK:STDOUT: %T: %Copy.type = symbolic_binding T, 0 [symbolic = %T (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc6_18.1: type = facet_access_type %T [symbolic = %T.as_type.loc6_18.1 (constants.%T.as_type)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %T.as_type.loc6_18.1 [symbolic = %pattern_type (constants.%pattern_type.2c66b4.2)] +// CHECK:STDOUT: %y.param_patt.loc6_16.2: @fn.loc6.%pattern_type (%pattern_type.2c66b4.2) = value_param_pattern [symbolic = %y.param_patt.loc6_16.2 (constants.%y.param_patt.ec0)] +// CHECK:STDOUT: %y.patt.loc6_16.2: @fn.loc6.%pattern_type (%pattern_type.2c66b4.2) = wrapper_binding_pattern y, %y.param_patt.loc6_16.2 [symbolic = %y.patt.loc6_16.2 (constants.%y.patt.d6d)] +// CHECK:STDOUT: %.loc6_24.2: Core.Form = init_form %T.as_type.loc6_18.1 [symbolic = %.loc6_24.2 (constants.%.1ce700.2)] +// CHECK:STDOUT: %return.param_patt.loc6_24.2: @fn.loc6.%pattern_type (%pattern_type.2c66b4.2) = out_param_pattern [symbolic = %return.param_patt.loc6_24.2 (constants.%return.param_patt.bf4475.2)] +// CHECK:STDOUT: %return.patt.loc6_21.2: @fn.loc6.%pattern_type (%pattern_type.2c66b4.2) = return_slot_pattern %return.param_patt.loc6_24.2, %T.as_type.loc6_18.1 [symbolic = %return.patt.loc6_21.2 (constants.%return.patt.f44)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %T.as_type.loc6_18.1 [symbolic = %require_complete (constants.%require_complete.d83)] +// CHECK:STDOUT: %fn.type: type = fn_type @fn.loc7, @fn.loc6(%T) [symbolic = %fn.type (constants.%fn.type.278)] +// CHECK:STDOUT: %fn: @fn.loc6.%fn.type (%fn.type.278) = struct_value () [symbolic = %fn (constants.%fn.ea9)] +// CHECK:STDOUT: %fn.specific_fn.loc7_28.2: = specific_function %fn, @fn.loc7(%T) [symbolic = %fn.specific_fn.loc7_28.2 (constants.%fn.specific_fn.79b)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%y.param: @fn.loc6.%T.as_type.loc6_18.1 (%T.as_type)) -> out %return.param: @fn.loc6.%T.as_type.loc6_18.1 (%T.as_type) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %fn.decl: @fn.loc6.%fn.type (%fn.type.278) = fn_decl @fn.loc7 [symbolic = @fn.loc6.%fn (constants.%fn.ea9)] { +// CHECK:STDOUT: %z.param_patt.loc7_18.1: @fn.loc7.%pattern_type (%pattern_type.2c66b4.2) = value_param_pattern [symbolic = %z.param_patt.loc7_18.2 (constants.%z.param_patt.b42)] +// CHECK:STDOUT: %z.patt.loc7_18.1: @fn.loc7.%pattern_type (%pattern_type.2c66b4.2) = wrapper_binding_pattern z, %z.param_patt.loc7_18.1 [symbolic = %z.patt.loc7_18.2 (constants.%z.patt.513)] +// CHECK:STDOUT: %return.param_patt.loc7_26.1: @fn.loc7.%pattern_type (%pattern_type.2c66b4.2) = out_param_pattern [symbolic = %return.param_patt.loc7_26.2 (constants.%return.param_patt.bf4475.2)] +// CHECK:STDOUT: %return.patt.loc7_23.1: @fn.loc7.%pattern_type (%pattern_type.2c66b4.2) = return_slot_pattern %return.param_patt.loc7_26.1, %.loc7_26.3 [symbolic = %return.patt.loc7_23.2 (constants.%return.patt.f44)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.ref.loc7_26: %Copy.type = name_ref T, @fn.loc5.%T.loc5_27.2 [symbolic = %T (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc7_26: type = facet_access_type %T.ref.loc7_26 [symbolic = %T.as_type.loc7_20.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc7_26.3: type = converted %T.ref.loc7_26, %T.as_type.loc7_26 [symbolic = %T.as_type.loc7_20.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc7_26.4: Core.Form = init_form %.loc7_26.3 [symbolic = %.loc7_26.2 (constants.%.1ce700.2)] +// CHECK:STDOUT: %z.param: @fn.loc7.%T.as_type.loc7_20.1 (%T.as_type) = value_param call_param0 +// CHECK:STDOUT: %.loc7_20.1: type = splice_block %.loc7_20.2 [symbolic = %T.as_type.loc7_20.1 (constants.%T.as_type)] { +// CHECK:STDOUT: %T.ref.loc7_20: %Copy.type = name_ref T, @fn.loc5.%T.loc5_27.2 [symbolic = %T (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc7_20.2: type = facet_access_type %T.ref.loc7_20 [symbolic = %T.as_type.loc7_20.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc7_20.2: type = converted %T.ref.loc7_20, %T.as_type.loc7_20.2 [symbolic = %T.as_type.loc7_20.1 (constants.%T.as_type)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %z: @fn.loc7.%T.as_type.loc7_20.1 (%T.as_type) = wrapper_binding z, %z.param +// CHECK:STDOUT: %return.param: ref @fn.loc7.%T.as_type.loc7_20.1 (%T.as_type) = out_param call_param1 +// CHECK:STDOUT: %return: ref @fn.loc7.%T.as_type.loc7_20.1 (%T.as_type) = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %y.ref: @fn.loc6.%T.as_type.loc6_18.1 (%T.as_type) = name_ref y, %y +// CHECK:STDOUT: %.loc9_10.1: %Copy.type = converted constants.%T.as_type, constants.%T.f84 [symbolic = %T (constants.%T.f84)] +// CHECK:STDOUT: %.loc9_10.2: %Copy.type = converted constants.%T.as_type, constants.%T.f84 [symbolic = %T (constants.%T.f84)] +// CHECK:STDOUT: %fn.specific_fn.loc7_28.1: = specific_function %fn.decl, @fn.loc7(constants.%T.f84) [symbolic = %fn.specific_fn.loc7_28.2 (constants.%fn.specific_fn.79b)] +// CHECK:STDOUT: %.loc6_24.1: ref @fn.loc6.%T.as_type.loc6_18.1 (%T.as_type) = splice_block %return.param {} +// CHECK:STDOUT: %fn.call: init @fn.loc6.%T.as_type.loc6_18.1 (%T.as_type) to %.loc6_24.1 = call %fn.specific_fn.loc7_28.1(%y.ref) +// CHECK:STDOUT: return %fn.call to %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @fn.loc7(@fn.loc5.%T.loc5_27.2: %Copy.type) { +// CHECK:STDOUT: %T: %Copy.type = symbolic_binding T, 0 [symbolic = %T (constants.%T.f84)] +// CHECK:STDOUT: %T.as_type.loc7_20.1: type = facet_access_type %T [symbolic = %T.as_type.loc7_20.1 (constants.%T.as_type)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %T.as_type.loc7_20.1 [symbolic = %pattern_type (constants.%pattern_type.2c66b4.2)] +// CHECK:STDOUT: %z.param_patt.loc7_18.2: @fn.loc7.%pattern_type (%pattern_type.2c66b4.2) = value_param_pattern [symbolic = %z.param_patt.loc7_18.2 (constants.%z.param_patt.b42)] +// CHECK:STDOUT: %z.patt.loc7_18.2: @fn.loc7.%pattern_type (%pattern_type.2c66b4.2) = wrapper_binding_pattern z, %z.param_patt.loc7_18.2 [symbolic = %z.patt.loc7_18.2 (constants.%z.patt.513)] +// CHECK:STDOUT: %.loc7_26.2: Core.Form = init_form %T.as_type.loc7_20.1 [symbolic = %.loc7_26.2 (constants.%.1ce700.2)] +// CHECK:STDOUT: %return.param_patt.loc7_26.2: @fn.loc7.%pattern_type (%pattern_type.2c66b4.2) = out_param_pattern [symbolic = %return.param_patt.loc7_26.2 (constants.%return.param_patt.bf4475.2)] +// CHECK:STDOUT: %return.patt.loc7_23.2: @fn.loc7.%pattern_type (%pattern_type.2c66b4.2) = return_slot_pattern %return.param_patt.loc7_26.2, %T.as_type.loc7_20.1 [symbolic = %return.patt.loc7_23.2 (constants.%return.patt.f44)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %T.as_type.loc7_20.1 [symbolic = %require_complete (constants.%require_complete.d83)] +// CHECK:STDOUT: %Copy.WithSelf.Op.type: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%T) [symbolic = %Copy.WithSelf.Op.type (constants.%Copy.WithSelf.Op.type.c85f21.2)] +// CHECK:STDOUT: %.loc8_16.3: type = fn_type_with_self_type %Copy.WithSelf.Op.type, %T [symbolic = %.loc8_16.3 (constants.%.c29)] +// CHECK:STDOUT: %Copy.lookup_impl_witness: = lookup_impl_witness %T, @Copy [symbolic = %Copy.lookup_impl_witness (constants.%Copy.lookup_impl_witness.d9c)] +// CHECK:STDOUT: %impl.elem0.loc8_16.2: @fn.loc7.%.loc8_16.3 (%.c29) = impl_witness_access %Copy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc8_16.2 (constants.%impl.elem0.bd2)] +// CHECK:STDOUT: %specific_impl_fn.loc8_16.2: = specific_impl_function %impl.elem0.loc8_16.2, @Copy.WithSelf.Op(%T) [symbolic = %specific_impl_fn.loc8_16.2 (constants.%specific_impl_fn.e2a)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%z.param: @fn.loc7.%T.as_type.loc7_20.1 (%T.as_type)) -> out %return.param: @fn.loc7.%T.as_type.loc7_20.1 (%T.as_type) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %z.ref: @fn.loc7.%T.as_type.loc7_20.1 (%T.as_type) = name_ref z, %z +// CHECK:STDOUT: %impl.elem0.loc8_16.1: @fn.loc7.%.loc8_16.3 (%.c29) = impl_witness_access constants.%Copy.lookup_impl_witness.d9c, element0 [symbolic = %impl.elem0.loc8_16.2 (constants.%impl.elem0.bd2)] +// CHECK:STDOUT: %bound_method.loc8_16.1: = bound_method %z.ref, %impl.elem0.loc8_16.1 +// CHECK:STDOUT: %.loc8_16.1: %Copy.type = converted constants.%T.as_type, constants.%T.f84 [symbolic = %T (constants.%T.f84)] +// CHECK:STDOUT: %.loc8_16.2: %Copy.type = converted constants.%T.as_type, constants.%T.f84 [symbolic = %T (constants.%T.f84)] +// CHECK:STDOUT: %specific_impl_fn.loc8_16.1: = specific_impl_function %impl.elem0.loc8_16.1, @Copy.WithSelf.Op(constants.%T.f84) [symbolic = %specific_impl_fn.loc8_16.2 (constants.%specific_impl_fn.e2a)] +// CHECK:STDOUT: %bound_method.loc8_16.2: = bound_method %z.ref, %specific_impl_fn.loc8_16.1 +// CHECK:STDOUT: %.loc7_26.1: ref @fn.loc7.%T.as_type.loc7_20.1 (%T.as_type) = splice_block %return.param {} +// CHECK:STDOUT: %Copy.WithSelf.Op.call: init @fn.loc7.%T.as_type.loc7_20.1 (%T.as_type) to %.loc7_26.1 = call %bound_method.loc8_16.2(%z.ref) +// CHECK:STDOUT: return %Copy.WithSelf.Op.call to %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn.loc5(constants.%T.f84) { +// CHECK:STDOUT: %T.patt.loc5_27.2 => constants.%T.patt.fe6 +// CHECK:STDOUT: %T.loc5_27.1 => constants.%T.f84 +// CHECK:STDOUT: %T.as_type.loc5_43.1 => constants.%T.as_type +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.2c66b4.2 +// CHECK:STDOUT: %x.param_patt.loc5_41.2 => constants.%x.param_patt.1f4 +// CHECK:STDOUT: %x.patt.loc5_41.2 => constants.%x.patt.cec +// CHECK:STDOUT: %.loc5_49.2 => constants.%.1ce700.2 +// CHECK:STDOUT: %return.param_patt.loc5_49.2 => constants.%return.param_patt.bf4475.2 +// CHECK:STDOUT: %return.patt.loc5_46.2 => constants.%return.patt.f44 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn.loc6(constants.%T.f84) { +// CHECK:STDOUT: %T => constants.%T.f84 +// CHECK:STDOUT: %T.as_type.loc6_18.1 => constants.%T.as_type +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.2c66b4.2 +// CHECK:STDOUT: %y.param_patt.loc6_16.2 => constants.%y.param_patt.ec0 +// CHECK:STDOUT: %y.patt.loc6_16.2 => constants.%y.patt.d6d +// CHECK:STDOUT: %.loc6_24.2 => constants.%.1ce700.2 +// CHECK:STDOUT: %return.param_patt.loc6_24.2 => constants.%return.param_patt.bf4475.2 +// CHECK:STDOUT: %return.patt.loc6_21.2 => constants.%return.patt.f44 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%require_complete.d83 +// CHECK:STDOUT: %fn.type => constants.%fn.type.278 +// CHECK:STDOUT: %fn => constants.%fn.ea9 +// CHECK:STDOUT: %fn.specific_fn.loc7_28.2 => constants.%fn.specific_fn.79b +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn.loc7(constants.%T.f84) { +// CHECK:STDOUT: %T => constants.%T.f84 +// CHECK:STDOUT: %T.as_type.loc7_20.1 => constants.%T.as_type +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.2c66b4.2 +// CHECK:STDOUT: %z.param_patt.loc7_18.2 => constants.%z.param_patt.b42 +// CHECK:STDOUT: %z.patt.loc7_18.2 => constants.%z.patt.513 +// CHECK:STDOUT: %.loc7_26.2 => constants.%.1ce700.2 +// CHECK:STDOUT: %return.param_patt.loc7_26.2 => constants.%return.param_patt.bf4475.2 +// CHECK:STDOUT: %return.patt.loc7_23.2 => constants.%return.patt.f44 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%require_complete.d83 +// CHECK:STDOUT: %Copy.WithSelf.Op.type => constants.%Copy.WithSelf.Op.type.c85f21.2 +// CHECK:STDOUT: %.loc8_16.3 => constants.%.c29 +// CHECK:STDOUT: %Copy.lookup_impl_witness => constants.%Copy.lookup_impl_witness.d9c +// CHECK:STDOUT: %impl.elem0.loc8_16.2 => constants.%impl.elem0.bd2 +// CHECK:STDOUT: %specific_impl_fn.loc8_16.2 => constants.%specific_impl_fn.e2a +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn.loc5(constants.%Copy.facet.1e1) { +// CHECK:STDOUT: %T.patt.loc5_27.2 => constants.%T.patt.fe6 +// CHECK:STDOUT: %T.loc5_27.1 => constants.%Copy.facet.1e1 +// CHECK:STDOUT: %T.as_type.loc5_43.1 => constants.%i32 +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.6b6 +// CHECK:STDOUT: %x.param_patt.loc5_41.2 => constants.%x.param_patt.cee +// CHECK:STDOUT: %x.patt.loc5_41.2 => constants.%x.patt.e3b +// CHECK:STDOUT: %.loc5_49.2 => constants.%.795 +// CHECK:STDOUT: %return.param_patt.loc5_49.2 => constants.%return.param_patt.a9a +// CHECK:STDOUT: %return.patt.loc5_46.2 => constants.%return.patt.e1b +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type.f8a +// CHECK:STDOUT: %fn.type => constants.%fn.type.b76 +// CHECK:STDOUT: %fn => constants.%fn.5bc +// CHECK:STDOUT: %fn.specific_fn.loc6_26.2 => constants.%fn.specific_fn.097 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn.loc5(constants.%Copy.facet.7af) { +// CHECK:STDOUT: %T.patt.loc5_27.2 => constants.%T.patt.fe6 +// CHECK:STDOUT: %T.loc5_27.1 => constants.%Copy.facet.7af +// CHECK:STDOUT: %T.as_type.loc5_43.1 => bool +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.831 +// CHECK:STDOUT: %x.param_patt.loc5_41.2 => constants.%x.param_patt.37d +// CHECK:STDOUT: %x.patt.loc5_41.2 => constants.%x.patt.e47 +// CHECK:STDOUT: %.loc5_49.2 => constants.%.f34 +// CHECK:STDOUT: %return.param_patt.loc5_49.2 => constants.%return.param_patt.5a1 +// CHECK:STDOUT: %return.patt.loc5_46.2 => constants.%return.patt.c0c +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type.127 +// CHECK:STDOUT: %fn.type => constants.%fn.type.60a +// CHECK:STDOUT: %fn => constants.%fn.bab +// CHECK:STDOUT: %fn.specific_fn.loc6_26.2 => constants.%fn.specific_fn.b85 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn.loc6(constants.%Copy.facet.1e1) { +// CHECK:STDOUT: %T => constants.%Copy.facet.1e1 +// CHECK:STDOUT: %T.as_type.loc6_18.1 => constants.%i32 +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.6b6 +// CHECK:STDOUT: %y.param_patt.loc6_16.2 => constants.%y.param_patt.673 +// CHECK:STDOUT: %y.patt.loc6_16.2 => constants.%y.patt.547 +// CHECK:STDOUT: %.loc6_24.2 => constants.%.795 +// CHECK:STDOUT: %return.param_patt.loc6_24.2 => constants.%return.param_patt.a9a +// CHECK:STDOUT: %return.patt.loc6_21.2 => constants.%return.patt.e1b +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type.f8a +// CHECK:STDOUT: %fn.type => constants.%fn.type.7d5 +// CHECK:STDOUT: %fn => constants.%fn.ecf +// CHECK:STDOUT: %fn.specific_fn.loc7_28.2 => constants.%fn.specific_fn.73d +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn.loc6(constants.%Copy.facet.7af) { +// CHECK:STDOUT: %T => constants.%Copy.facet.7af +// CHECK:STDOUT: %T.as_type.loc6_18.1 => bool +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.831 +// CHECK:STDOUT: %y.param_patt.loc6_16.2 => constants.%y.param_patt.077 +// CHECK:STDOUT: %y.patt.loc6_16.2 => constants.%y.patt.252 +// CHECK:STDOUT: %.loc6_24.2 => constants.%.f34 +// CHECK:STDOUT: %return.param_patt.loc6_24.2 => constants.%return.param_patt.5a1 +// CHECK:STDOUT: %return.patt.loc6_21.2 => constants.%return.patt.c0c +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type.127 +// CHECK:STDOUT: %fn.type => constants.%fn.type.d10 +// CHECK:STDOUT: %fn => constants.%fn.ac0 +// CHECK:STDOUT: %fn.specific_fn.loc7_28.2 => constants.%fn.specific_fn.99d +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn.loc7(constants.%Copy.facet.1e1) { +// CHECK:STDOUT: %T => constants.%Copy.facet.1e1 +// CHECK:STDOUT: %T.as_type.loc7_20.1 => constants.%i32 +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.6b6 +// CHECK:STDOUT: %z.param_patt.loc7_18.2 => constants.%z.param_patt.9ae +// CHECK:STDOUT: %z.patt.loc7_18.2 => constants.%z.patt.45e +// CHECK:STDOUT: %.loc7_26.2 => constants.%.795 +// CHECK:STDOUT: %return.param_patt.loc7_26.2 => constants.%return.param_patt.a9a +// CHECK:STDOUT: %return.patt.loc7_23.2 => constants.%return.patt.e1b +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type.f8a +// CHECK:STDOUT: %Copy.WithSelf.Op.type => constants.%Copy.WithSelf.Op.type.381 +// CHECK:STDOUT: %.loc8_16.3 => constants.%.737 +// CHECK:STDOUT: %Copy.lookup_impl_witness => constants.%Copy.impl_witness.b51 +// CHECK:STDOUT: %impl.elem0.loc8_16.2 => constants.%Int.as.Copy.impl.Op.4f6 +// CHECK:STDOUT: %specific_impl_fn.loc8_16.2 => constants.%Int.as.Copy.impl.Op.specific_fn +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @fn.loc7(constants.%Copy.facet.7af) { +// CHECK:STDOUT: %T => constants.%Copy.facet.7af +// CHECK:STDOUT: %T.as_type.loc7_20.1 => bool +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.831 +// CHECK:STDOUT: %z.param_patt.loc7_18.2 => constants.%z.param_patt.a49 +// CHECK:STDOUT: %z.patt.loc7_18.2 => constants.%z.patt.246 +// CHECK:STDOUT: %.loc7_26.2 => constants.%.f34 +// CHECK:STDOUT: %return.param_patt.loc7_26.2 => constants.%return.param_patt.5a1 +// CHECK:STDOUT: %return.patt.loc7_23.2 => constants.%return.patt.c0c +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type.127 +// CHECK:STDOUT: %Copy.WithSelf.Op.type => constants.%Copy.WithSelf.Op.type.d02 +// CHECK:STDOUT: %.loc8_16.3 => constants.%.e28 +// CHECK:STDOUT: %Copy.lookup_impl_witness => constants.%Copy.impl_witness.5e1 +// CHECK:STDOUT: %impl.elem0.loc8_16.2 => constants.%bool.as.Copy.impl.Op +// CHECK:STDOUT: %specific_impl_fn.loc8_16.2 => constants.%bool.as.Copy.impl.Op +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- control_flow.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: type: type = facet_type [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %fn.type: type = fn_type @fn [concrete] +// CHECK:STDOUT: %fn: %fn.type = struct_value () [concrete] +// CHECK:STDOUT: %true: bool = bool_literal true [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TestControlFlow() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %fn.decl: %fn.type = fn_decl @fn [concrete = constants.%fn] {} {} +// CHECK:STDOUT: %loop_in_lambda: %fn.type = alias_binding loop_in_lambda, %fn.decl [concrete = constants.%fn] +// CHECK:STDOUT: %loop_in_lambda.ref: %fn.type = name_ref loop_in_lambda, %loop_in_lambda [concrete = constants.%fn] +// CHECK:STDOUT: %fn.call: init %empty_tuple.type = call %loop_in_lambda.ref() +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @fn() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: br !while.cond +// CHECK:STDOUT: +// CHECK:STDOUT: !while.cond: +// CHECK:STDOUT: %true: bool = bool_literal true [concrete = constants.%true] +// CHECK:STDOUT: if %true br !while.body else br !while.done +// CHECK:STDOUT: +// CHECK:STDOUT: !while.body: +// CHECK:STDOUT: br !while.done +// CHECK:STDOUT: +// CHECK:STDOUT: !while.done: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/diagnostics/kind.def b/toolchain/diagnostics/kind.def index fdacb23597da..936fa93ced8c 100644 --- a/toolchain/diagnostics/kind.def +++ b/toolchain/diagnostics/kind.def @@ -637,6 +637,9 @@ CARBON_DIAGNOSTIC_KIND(UnusedModifierWithoutDefinition) CARBON_DIAGNOSTIC_KIND(UnusedPatternNoBindings) CARBON_DIAGNOSTIC_KIND(UnusedBinding) +// Function expression diagnostics. +CARBON_DIAGNOSTIC_KIND(SelfParameterInLambda) + // ============================================================================ // CodeGen diagnostics // ============================================================================ diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index ffd3ff4b0fe2..d118c934a0ec 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -116,7 +116,7 @@ auto FileContext::LowerDefinitions() -> void { LowerGlobalVariables(sem_ir().top_inst_block_id()); // Lower static class variable definitions. - for (auto class_info : sem_ir().classes().values()) { + for (const auto& class_info : sem_ir().classes().values()) { auto inst_block_id = class_info.body_block_id; if (inst_block_id.has_value()) { LowerGlobalVariables(inst_block_id); @@ -699,14 +699,18 @@ auto FileContext::BuildDISubprogram(const SemIR::Function& function, if (!context().di_compile_unit()) { return nullptr; } - auto name = sem_ir().names().GetAsStringIfIdentifier(function.name_id); - CARBON_CHECK(name, "Unexpected special name for function: {0}", - function.name_id); + llvm::StringRef name = ""; + if (function.name_id.has_value()) { + auto maybe_name = + sem_ir().names().GetAsStringIfIdentifier(function.name_id); + CARBON_CHECK(maybe_name, "Unexpected special name for function: {0}", + function.name_id); + name = *maybe_name; + } auto loc = GetLocForDI(function.definition_id); llvm::DISubroutineType* subroutine_type = function_info.di_type; auto* subprogram = context().di_builder().createFunction( - context().di_compile_unit(), *name, - function_info.llvm_function->getName(), + context().di_compile_unit(), name, function_info.llvm_function->getName(), /*File=*/context().di_builder().createFile(loc.filename, ""), /*LineNo=*/loc.line_number, subroutine_type, /*ScopeLine=*/0, llvm::DINode::FlagZero, diff --git a/toolchain/lower/testdata/lambda/lambda.carbon b/toolchain/lower/testdata/lambda/lambda.carbon new file mode 100644 index 000000000000..9248a5160bd3 --- /dev/null +++ b/toolchain/lower/testdata/lambda/lambda.carbon @@ -0,0 +1,111 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/lambda/lambda.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/lambda/lambda.carbon + +// --- lib.carbon +library "[[@TEST_NAME]]"; + +alias Imported = fn (x: i32) -> i32 { return x; }; + +// --- main.carbon +library "[[@TEST_NAME]]"; + +import library "lib"; + +fn Test() -> i32 { + alias f = fn (x: i32) -> i32 { + return x; + }; + return (fn (y: i32) -> i32 { return y; })(f(Imported(1))); +} + +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'lib.carbon' +// CHECK:STDOUT: source_filename = "lib.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @"_Cfn:enclosed.3c14c8ca6559e7d0"(i32 %x) #0 !dbg !23 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret i32 %x, !dbg !29 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!19} +// CHECK:STDOUT: !llvm.module.flags = !{!2, !3} +// CHECK:STDOUT: +// CHECK:STDOUT: !2 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !3 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !18 = !DIFile(filename: "lib.carbon", directory: "") +// CHECK:STDOUT: !19 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !18, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK:STDOUT: !21 = !{!20, !20} +// CHECK:STDOUT: !22 = !DISubroutineType(types: !21) +// CHECK:STDOUT: !23 = distinct !DISubprogram(linkageName: "_Cfn:enclosed.3c14c8ca6559e7d0", scope: null, file: !18, line: 3, type: !22, spFlags: DISPFlagDefinition, unit: !19, retainedNodes: !30) +// CHECK:STDOUT: !24 = !DILocalVariable(arg: 1, scope: !23, type: !20) +// CHECK:STDOUT: !29 = !DILocation(line: 3, column: 39, scope: !23) +// CHECK:STDOUT: !30 = !{!24} +// CHECK:STDOUT: +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'main.carbon' +// CHECK:STDOUT: source_filename = "main.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @_CTest.Main() #0 !dbg !35 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %fn.call.loc9_57 = call i32 @"_Cfn:enclosed.3c14c8ca6559e7d0"(i32 1), !dbg !38 +// CHECK:STDOUT: %fn.call.loc9_58 = call i32 @"_Cfn:enclosed.4f93545957a800ba"(i32 %fn.call.loc9_57), !dbg !39 +// CHECK:STDOUT: %fn.call.loc9_59 = call i32 @"_Cfn:enclosed.1e20c3b8ac0c9b5a"(i32 %fn.call.loc9_58), !dbg !40 +// CHECK:STDOUT: ret i32 %fn.call.loc9_59, !dbg !41 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @"_Cfn:enclosed.4f93545957a800ba"(i32 %x) #0 !dbg !42 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret i32 %x, !dbg !48 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @"_Cfn:enclosed.1e20c3b8ac0c9b5a"(i32 %y) #0 !dbg !50 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret i32 %y, !dbg !56 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: declare i32 @"_Cfn:enclosed.3c14c8ca6559e7d0"(i32) +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!32} +// CHECK:STDOUT: !llvm.module.flags = !{!2, !3} +// CHECK:STDOUT: +// CHECK:STDOUT: !2 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !3 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK:STDOUT: !21 = !{!20, !20} +// CHECK:STDOUT: !22 = !DISubroutineType(types: !21) +// CHECK:STDOUT: !31 = !DIFile(filename: "main.carbon", directory: "") +// CHECK:STDOUT: !32 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !31, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !33 = !{!20} +// CHECK:STDOUT: !34 = !DISubroutineType(types: !33) +// CHECK:STDOUT: !35 = distinct !DISubprogram(name: "Test", linkageName: "_CTest.Main", scope: null, file: !31, line: 5, type: !34, spFlags: DISPFlagDefinition, unit: !32) +// CHECK:STDOUT: !38 = !DILocation(line: 9, column: 47, scope: !35) +// CHECK:STDOUT: !39 = !DILocation(line: 9, column: 45, scope: !35) +// CHECK:STDOUT: !40 = !DILocation(line: 9, column: 10, scope: !35) +// CHECK:STDOUT: !41 = !DILocation(line: 9, column: 3, scope: !35) +// CHECK:STDOUT: !42 = distinct !DISubprogram(linkageName: "_Cfn:enclosed.4f93545957a800ba", scope: null, file: !31, line: 6, type: !22, spFlags: DISPFlagDefinition, unit: !32, retainedNodes: !49) +// CHECK:STDOUT: !43 = !DILocalVariable(arg: 1, scope: !42, type: !20) +// CHECK:STDOUT: !48 = !DILocation(line: 7, column: 5, scope: !42) +// CHECK:STDOUT: !49 = !{!43} +// CHECK:STDOUT: !50 = distinct !DISubprogram(linkageName: "_Cfn:enclosed.1e20c3b8ac0c9b5a", scope: null, file: !31, line: 9, type: !22, spFlags: DISPFlagDefinition, unit: !32, retainedNodes: !57) +// CHECK:STDOUT: !51 = !DILocalVariable(arg: 1, scope: !50, type: !20) +// CHECK:STDOUT: !56 = !DILocation(line: 9, column: 32, scope: !50) +// CHECK:STDOUT: !57 = !{!51} +// CHECK:STDOUT: diff --git a/toolchain/parse/handle_lambda.cpp b/toolchain/parse/handle_lambda.cpp index 225b56577407..37a2cf976382 100644 --- a/toolchain/parse/handle_lambda.cpp +++ b/toolchain/parse/handle_lambda.cpp @@ -18,7 +18,8 @@ auto HandleLambdaAfterIntroducer(Context& context) -> void { if (context.PositionIs(Lex::TokenKind::OpenSquareBracket)) { context.PushState(state, StateKind::LambdaAfterImplicitParams); - context.PushState(StateKind::PatternListAsImplicit); + context.PushState(StateKind::PatternListAsImplicit, *context.position(), + BindingContext::DeducedParam); } else if (context.PositionIs(Lex::TokenKind::OpenParen)) { context.PushState(state, StateKind::LambdaAfterParams); context.PushState(StateKind::PatternListAsExplicit); @@ -40,6 +41,44 @@ auto HandleLambdaAfterImplicitParams(Context& context) -> void { } } +static auto ParseLambdaBody(Context& context, Context::State state, + bool has_return_type) -> void { + if (context.PositionIs(Lex::TokenKind::EqualGreater)) { + // Terse body `=> expr` + auto arrow_token = context.Consume(); + context.AddNode(NodeKind::LambdaDefinitionStart, arrow_token, + state.has_error); + state.has_error = false; + context.AddLeafNode(NodeKind::TerseBodyArrow, arrow_token); + context.PushState(state, StateKind::LambdaBodyFinish); + context.PushStateForExpr(PrecedenceGroup::ForTopLevelExpr()); + } else if (context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) { + // Block body `{ ... }` + context.PushState(StateKind::LambdaBodyFinish); + context.AddNode(NodeKind::LambdaDefinitionStart, context.Consume(), + state.has_error); + context.PushState(StateKind::StatementScopeLoop); + } else { + if (has_return_type) { + CARBON_DIAGNOSTIC(ExpectedLambdaBodyAfterReturnType, Error, + "expected `=>` or `{{` after return type"); + context.emitter().Emit(*context.position(), + ExpectedLambdaBodyAfterReturnType); + } else { + CARBON_DIAGNOSTIC(ExpectedLambdaBody, Error, + "expected `->`, `=>`, or `{{`"); + context.emitter().Emit(*context.position(), ExpectedLambdaBody); + } + + // Bundle everything into a complete lambda node for error recovery -- + // otherwise the orphaned `LambdaIntroducer` would be left where an + // expression is required, for example in `(fn)`. + context.AddNode(NodeKind::LambdaDefinitionStart, *context.position(), + /*has_error=*/true); + context.AddNode(NodeKind::Lambda, state.token, /*has_error=*/true); + } +} + auto HandleLambdaAfterParams(Context& context) -> void { auto state = context.PopState(); @@ -49,68 +88,29 @@ auto HandleLambdaAfterParams(Context& context) -> void { context.PushState(StateKind::FunctionReturnTypeFinish); context.ConsumeAndDiscard(); context.PushStateForExpr(PrecedenceGroup::ForType()); - } else if (context.PositionIs(Lex::TokenKind::EqualGreater)) { - // Terse body `=> expr` - context.AddLeafNode(NodeKind::TerseBodyArrow, context.Consume()); - context.PushState(state, StateKind::LambdaBodyFinish); - context.PushStateForExpr(PrecedenceGroup::ForTopLevelExpr()); - } else if (context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) { - // Block body `{ ... }` - context.PushState(state, StateKind::LambdaBodyFinish); - context.PushState(StateKind::CodeBlock); + } else if (context.PositionIs(Lex::TokenKind::MinusGreaterQuestion)) { + // Has return form. + context.PushState(state, StateKind::LambdaBody); + context.PushState(StateKind::FunctionReturnFormFinish); + context.ConsumeAndDiscard(); + context.PushStateForExpr(PrecedenceGroup::ForType()); } else { - CARBON_DIAGNOSTIC(ExpectedLambdaBody, Error, - "expected `->`, `=>`, or `{{`"); - context.emitter().Emit(*context.position(), ExpectedLambdaBody); - - // Add a dummy node for the missing body without consuming the current - // token, then bundle everything into a complete lambda node. This keeps the - // lambda a valid expression for error recovery -- otherwise the orphaned - // `LambdaIntroducer` would be left where an expression is required, for - // example in `(fn)`. - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); - - state.has_error = true; - context.PushState(state, StateKind::LambdaBodyFinish); + ParseLambdaBody(context, state, /*has_return_type=*/false); } } auto HandleLambdaBody(Context& context) -> void { auto state = context.PopState(); - - // We arrive here after parsing return type. - // So we look for `=>` or `{`. - - if (context.PositionIs(Lex::TokenKind::EqualGreater)) { - // Terse body `=> expr` - context.AddLeafNode(NodeKind::TerseBodyArrow, context.Consume()); - context.PushState(state, StateKind::LambdaBodyFinish); - context.PushStateForExpr(PrecedenceGroup::ForTopLevelExpr()); - } else if (context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) { - // Block body `{ ... }` - context.PushState(state, StateKind::LambdaBodyFinish); - context.PushState(StateKind::CodeBlock); - } else { - CARBON_DIAGNOSTIC(ExpectedLambdaBodyAfterReturnType, Error, - "expected `=>` or `{{` after return type"); - context.emitter().Emit(*context.position(), - ExpectedLambdaBodyAfterReturnType); - - // Add a dummy node for the missing body without consuming the current - // token. - context.AddLeafNode(NodeKind::InvalidParse, *context.position(), - /*has_error=*/true); - - state.has_error = true; - // Bundle all nodes into a complete lambda node. - context.PushState(state, StateKind::LambdaBodyFinish); - } + ParseLambdaBody(context, state, /*has_return_type=*/true); } auto HandleLambdaBodyFinish(Context& context) -> void { auto state = context.PopState(); - context.AddNode(NodeKind::Lambda, state.token, state.has_error); + if (context.tokens().GetKind(state.token) == Lex::TokenKind::OpenCurlyBrace) { + context.AddNode(NodeKind::Lambda, context.Consume(), state.has_error); + } else { + context.AddNode(NodeKind::Lambda, state.token, state.has_error); + } } } // namespace Carbon::Parse diff --git a/toolchain/parse/node_ids.h b/toolchain/parse/node_ids.h index 5cda0473d7a7..70140a3abbe7 100644 --- a/toolchain/parse/node_ids.h +++ b/toolchain/parse/node_ids.h @@ -175,8 +175,9 @@ using AnyClassDeclId = // class, so they are a form of class decls. This avoids // duplicating all of SemIR::ClassDecl. ChoiceDefinitionStartId>; -using AnyFunctionDeclId = NodeIdOneOf; +using AnyFunctionDeclId = + NodeIdOneOf; using AnyFunctionDefinitionId = NodeIdOneOf; diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index fb623749baaa..dfb8e6dd7999 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -201,6 +201,7 @@ CARBON_PARSE_NODE_KIND_DECLARATION(FunctionDefinitionStart) CARBON_PARSE_NODE_KIND_DECLARATION(FunctionDefinition) CARBON_PARSE_NODE_KIND_DECLARATION(FunctionTerseDefinition) CARBON_PARSE_NODE_KIND_DECLARATION(FunctionDecl) +CARBON_PARSE_NODE_KIND_DECLARATION(LambdaDefinitionStart) CARBON_PARSE_NODE_KIND_DECLARATION(Lambda) CARBON_PARSE_NODE_KIND_DECLARATION(TerseBodyArrow) CARBON_PARSE_NODE_KIND_DECLARATION(BuiltinFunctionDefinitionStart) diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def index fa08dc0ecd9d..b813f07a10ec 100644 --- a/toolchain/parse/state.def +++ b/toolchain/parse/state.def @@ -815,7 +815,12 @@ CARBON_PARSE_STATE(LambdaAfterImplicitParams) // // fn <...> -> <...> // ^ -// 1. FunctionReturnTypeFinish (Reused) +// 1. FunctionReturnTypeFinish +// 2. LambdaBody +// +// fn <...> ->? <...> +// ^ +// 1. FunctionReturnFormFinish // 2. LambdaBody // // fn <...> => <...> diff --git a/toolchain/parse/testdata/function/default_values.carbon b/toolchain/parse/testdata/function/default_values.carbon index 9b50cc50ce3d..f3575860adc7 100644 --- a/toolchain/parse/testdata/function/default_values.carbon +++ b/toolchain/parse/testdata/function/default_values.carbon @@ -75,16 +75,17 @@ var b: auto = fn (x: i32 = 0) => x; // CHECK:STDOUT: │ │ ╭─VarBindingPattern ':' // CHECK:STDOUT: │ ├─VariablePattern 'var' // CHECK:STDOUT: │ ├─VariableInitializer '=' -// CHECK:STDOUT: │ │ ╭─LambdaIntroducer 'fn' -// CHECK:STDOUT: │ │ │ ╭─ExplicitParamListStart '(' -// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'x' -// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':' -// CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32' -// CHECK:STDOUT: │ │ │ │ ╭─LetBindingPattern ':' -// CHECK:STDOUT: │ │ │ │ ├─DefaultValueExprStart '=' -// CHECK:STDOUT: │ │ │ │ ├─IntLiteral '0' -// CHECK:STDOUT: │ │ │ ├─DefaultValuePattern '=' -// CHECK:STDOUT: │ │ ├─ExplicitParamList ')' +// CHECK:STDOUT: │ │ ╭─LambdaIntroducer 'fn' +// CHECK:STDOUT: │ │ │ ╭─ExplicitParamListStart '(' +// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'x' +// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':' +// CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32' +// CHECK:STDOUT: │ │ │ │ ╭─LetBindingPattern ':' +// CHECK:STDOUT: │ │ │ │ ├─DefaultValueExprStart '=' +// CHECK:STDOUT: │ │ │ │ ├─IntLiteral '0' +// CHECK:STDOUT: │ │ │ ├─DefaultValuePattern '=' +// CHECK:STDOUT: │ │ ├─ExplicitParamList ')' +// CHECK:STDOUT: │ │ ╭─LambdaDefinitionStart '=>' // CHECK:STDOUT: │ │ ├─TerseBodyArrow '=>' // CHECK:STDOUT: │ │ ├─IdentifierNameExpr 'x' // CHECK:STDOUT: │ ├─Lambda 'fn' diff --git a/toolchain/parse/testdata/lambda/lambda.carbon b/toolchain/parse/testdata/lambda/lambda.carbon index b58ce9f2d01d..113ffb2f2806 100644 --- a/toolchain/parse/testdata/lambda/lambda.carbon +++ b/toolchain/parse/testdata/lambda/lambda.carbon @@ -13,6 +13,7 @@ var a: auto = fn [T: type] (x: T) -> T { return x; }; var b: auto = fn (x: i32) => x; var c: auto = fn { }; +var d: auto = fn (ref x: i32) ->? ref i32 { return x; }; // --- fail_unconsumed_lambda_introducer.carbon @@ -74,27 +75,26 @@ fn G() { // CHECK:STDOUT: │ │ ╭─VarBindingPattern ':' // CHECK:STDOUT: │ ├─VariablePattern 'var' // CHECK:STDOUT: │ ├─VariableInitializer '=' -// CHECK:STDOUT: │ │ ╭─LambdaIntroducer 'fn' -// CHECK:STDOUT: │ │ │ ╭─ImplicitParamListStart '[' -// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'T' -// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':' -// CHECK:STDOUT: │ │ │ │ ├─TypeTypeLiteral 'type' -// CHECK:STDOUT: │ │ │ ├─LetBindingPattern ':' -// CHECK:STDOUT: │ │ ├─ImplicitParamList ']' -// CHECK:STDOUT: │ │ │ ╭─ExplicitParamListStart '(' -// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'x' -// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':' -// CHECK:STDOUT: │ │ │ │ ├─IdentifierNameExpr 'T' -// CHECK:STDOUT: │ │ │ ├─LetBindingPattern ':' -// CHECK:STDOUT: │ │ ├─ExplicitParamList ')' -// CHECK:STDOUT: │ │ │ ╭─IdentifierNameExpr 'T' -// CHECK:STDOUT: │ │ ├─ReturnType '->' -// CHECK:STDOUT: │ │ │ ╭─CodeBlockStart '{' -// CHECK:STDOUT: │ │ │ │ ╭─ReturnStatementStart 'return' -// CHECK:STDOUT: │ │ │ │ ├─IdentifierNameExpr 'x' -// CHECK:STDOUT: │ │ │ ├─ReturnStatement ';' -// CHECK:STDOUT: │ │ ├─CodeBlock '}' -// CHECK:STDOUT: │ ├─Lambda 'fn' +// CHECK:STDOUT: │ │ ╭─LambdaIntroducer 'fn' +// CHECK:STDOUT: │ │ │ ╭─ImplicitParamListStart '[' +// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'T' +// CHECK:STDOUT: │ │ │ │ ├─CompileTimeBindingPatternTypeStart ':' +// CHECK:STDOUT: │ │ │ │ ├─TypeTypeLiteral 'type' +// CHECK:STDOUT: │ │ │ ├─CompileTimeBindingPattern ':' +// CHECK:STDOUT: │ │ ├─ImplicitParamList ']' +// CHECK:STDOUT: │ │ │ ╭─ExplicitParamListStart '(' +// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'x' +// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':' +// CHECK:STDOUT: │ │ │ │ ├─IdentifierNameExpr 'T' +// CHECK:STDOUT: │ │ │ ├─LetBindingPattern ':' +// CHECK:STDOUT: │ │ ├─ExplicitParamList ')' +// CHECK:STDOUT: │ │ │ ╭─IdentifierNameExpr 'T' +// CHECK:STDOUT: │ │ ├─ReturnType '->' +// CHECK:STDOUT: │ │ ╭─LambdaDefinitionStart '{' +// CHECK:STDOUT: │ │ │ ╭─ReturnStatementStart 'return' +// CHECK:STDOUT: │ │ │ ├─IdentifierNameExpr 'x' +// CHECK:STDOUT: │ │ ├─ReturnStatement ';' +// CHECK:STDOUT: │ ├─Lambda '}' // CHECK:STDOUT: ├─VariableDecl ';' // CHECK:STDOUT: │ ╭─VariableIntroducer 'var' // CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'b' @@ -103,13 +103,14 @@ fn G() { // CHECK:STDOUT: │ │ ╭─VarBindingPattern ':' // CHECK:STDOUT: │ ├─VariablePattern 'var' // CHECK:STDOUT: │ ├─VariableInitializer '=' -// CHECK:STDOUT: │ │ ╭─LambdaIntroducer 'fn' -// CHECK:STDOUT: │ │ │ ╭─ExplicitParamListStart '(' -// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'x' -// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':' -// CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32' -// CHECK:STDOUT: │ │ │ ├─LetBindingPattern ':' -// CHECK:STDOUT: │ │ ├─ExplicitParamList ')' +// CHECK:STDOUT: │ │ ╭─LambdaIntroducer 'fn' +// CHECK:STDOUT: │ │ │ ╭─ExplicitParamListStart '(' +// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'x' +// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':' +// CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32' +// CHECK:STDOUT: │ │ │ ├─LetBindingPattern ':' +// CHECK:STDOUT: │ │ ├─ExplicitParamList ')' +// CHECK:STDOUT: │ │ ╭─LambdaDefinitionStart '=>' // CHECK:STDOUT: │ │ ├─TerseBodyArrow '=>' // CHECK:STDOUT: │ │ ├─IdentifierNameExpr 'x' // CHECK:STDOUT: │ ├─Lambda 'fn' @@ -121,10 +122,33 @@ fn G() { // CHECK:STDOUT: │ │ ╭─VarBindingPattern ':' // CHECK:STDOUT: │ ├─VariablePattern 'var' // CHECK:STDOUT: │ ├─VariableInitializer '=' -// CHECK:STDOUT: │ │ ╭─LambdaIntroducer 'fn' -// CHECK:STDOUT: │ │ │ ╭─CodeBlockStart '{' -// CHECK:STDOUT: │ │ ├─CodeBlock '}' -// CHECK:STDOUT: │ ├─Lambda 'fn' +// CHECK:STDOUT: │ │ ╭─LambdaIntroducer 'fn' +// CHECK:STDOUT: │ │ ╭─LambdaDefinitionStart '{' +// CHECK:STDOUT: │ ├─Lambda '}' +// CHECK:STDOUT: ├─VariableDecl ';' +// CHECK:STDOUT: │ ╭─VariableIntroducer 'var' +// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'd' +// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':' +// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto' +// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':' +// CHECK:STDOUT: │ ├─VariablePattern 'var' +// CHECK:STDOUT: │ ├─VariableInitializer '=' +// CHECK:STDOUT: │ │ ╭─LambdaIntroducer 'fn' +// CHECK:STDOUT: │ │ │ ╭─ExplicitParamListStart '(' +// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'x' +// CHECK:STDOUT: │ │ │ │ ╭─RefBindingName 'ref' +// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':' +// CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32' +// CHECK:STDOUT: │ │ │ ├─LetBindingPattern ':' +// CHECK:STDOUT: │ │ ├─ExplicitParamList ')' +// CHECK:STDOUT: │ │ │ ╭─IntTypeLiteral 'i32' +// CHECK:STDOUT: │ │ │ ╭─PrefixOperatorRef 'ref' +// CHECK:STDOUT: │ │ ├─ReturnForm '->?' +// CHECK:STDOUT: │ │ ╭─LambdaDefinitionStart '{' +// CHECK:STDOUT: │ │ │ ╭─ReturnStatementStart 'return' +// CHECK:STDOUT: │ │ │ ├─IdentifierNameExpr 'x' +// CHECK:STDOUT: │ │ ├─ReturnStatement ';' +// CHECK:STDOUT: │ ├─Lambda '}' // CHECK:STDOUT: ├─VariableDecl ';' // CHECK:STDOUT: ├─FileEnd '' // CHECK:STDOUT: (root) @@ -132,12 +156,12 @@ fn G() { // CHECK:STDOUT: ╭─FileStart '' // CHECK:STDOUT: │ ╭─RequireIntroducer 'require' // CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'j' -// CHECK:STDOUT: │ │ │ ╭─LambdaIntroducer 'fn' -// CHECK:STDOUT: │ │ │ │ ╭─InvalidParse '>' has_error -// CHECK:STDOUT: │ │ │ │ ├─InvalidParse '' has_error -// CHECK:STDOUT: │ │ │ │ ╭─InfixOperatorGreater '>' has_error -// CHECK:STDOUT: │ │ │ ├─ReturnType '->' -// CHECK:STDOUT: │ │ │ ├─InvalidParse '' has_error +// CHECK:STDOUT: │ │ │ ╭─LambdaIntroducer 'fn' +// CHECK:STDOUT: │ │ │ │ ╭─InvalidParse '>' has_error +// CHECK:STDOUT: │ │ │ │ ├─InvalidParse '' has_error +// CHECK:STDOUT: │ │ │ │ ╭─InfixOperatorGreater '>' has_error +// CHECK:STDOUT: │ │ │ ├─ReturnType '->' +// CHECK:STDOUT: │ │ │ ╭─LambdaDefinitionStart '' has_error // CHECK:STDOUT: │ │ │ ╭─Lambda 'fn' has_error // CHECK:STDOUT: │ │ ├─PrefixOperatorMinus '-' // CHECK:STDOUT: │ ├─InfixOperatorPercent '%' @@ -158,8 +182,8 @@ fn G() { // CHECK:STDOUT: │ │ │ ╭─VarBindingPattern ':' // CHECK:STDOUT: │ │ ├─VariablePattern 'var' // CHECK:STDOUT: │ │ ├─VariableInitializer '=' -// CHECK:STDOUT: │ │ │ ╭─LambdaIntroducer 'fn' -// CHECK:STDOUT: │ │ │ ├─InvalidParse ';' has_error +// CHECK:STDOUT: │ │ │ ╭─LambdaIntroducer 'fn' +// CHECK:STDOUT: │ │ │ ╭─LambdaDefinitionStart ';' has_error // CHECK:STDOUT: │ │ ├─Lambda 'fn' has_error // CHECK:STDOUT: │ ├─VariableDecl ';' // CHECK:STDOUT: ├─FunctionDefinition '}' @@ -179,10 +203,10 @@ fn G() { // CHECK:STDOUT: │ │ │ ╭─VarBindingPattern ':' // CHECK:STDOUT: │ │ ├─VariablePattern 'var' // CHECK:STDOUT: │ │ ├─VariableInitializer '=' -// CHECK:STDOUT: │ │ │ ╭─LambdaIntroducer 'fn' -// CHECK:STDOUT: │ │ │ │ ╭─IntTypeLiteral 'i32' -// CHECK:STDOUT: │ │ │ ├─ReturnType '->' -// CHECK:STDOUT: │ │ │ ├─InvalidParse ';' has_error +// CHECK:STDOUT: │ │ │ ╭─LambdaIntroducer 'fn' +// CHECK:STDOUT: │ │ │ │ ╭─IntTypeLiteral 'i32' +// CHECK:STDOUT: │ │ │ ├─ReturnType '->' +// CHECK:STDOUT: │ │ │ ╭─LambdaDefinitionStart ';' has_error // CHECK:STDOUT: │ │ ├─Lambda 'fn' has_error // CHECK:STDOUT: │ ├─VariableDecl ';' // CHECK:STDOUT: ├─FunctionDefinition '}' diff --git a/toolchain/parse/typed_nodes.h b/toolchain/parse/typed_nodes.h index b2d50d323e7d..e8d66c69942b 100644 --- a/toolchain/parse/typed_nodes.h +++ b/toolchain/parse/typed_nodes.h @@ -792,18 +792,27 @@ struct CodeBlock { using LambdaIntroducer = LeafNode; -struct Lambda { - static constexpr auto Kind = NodeKind::Lambda.Define( - {.category = NodeCategory::Expr, .bracketed_by = LambdaIntroducer::Kind}); +struct LambdaDefinitionStart { + static constexpr auto Kind = NodeKind::LambdaDefinitionStart.Define( + {.bracketed_by = LambdaIntroducer::Kind}); LambdaIntroducerId introducer; std::optional implicit_params; std::optional explicit_params; - std::optional return_type; + std::optional return_type; + Lex::TokenIndex token; +}; + +struct Lambda { + static constexpr auto Kind = + NodeKind::Lambda.Define({.category = NodeCategory::Expr, + .bracketed_by = LambdaDefinitionStart::Kind}); + + LambdaDefinitionStartId signature; std::optional arrow; - NodeId body; - // Use a generic token index because the token might be `}` or part of an - // expression. + std::optional terse_body; + llvm::SmallVector body; + // Use a generic token index because the token might be `}` or `fn`. Lex::TokenIndex token; }; diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 736297846bf4..a67c960a1888 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -171,6 +171,7 @@ static auto IsDefinitionStart(Parse::NodeKind node_kind) -> bool { case Parse::NodeKind::FunctionDefinitionStart: case Parse::NodeKind::ImplDefinitionStart: case Parse::NodeKind::InterfaceDefinitionStart: + case Parse::NodeKind::LambdaDefinitionStart: case Parse::NodeKind::NamedConstraintDefinitionStart: return true; default: diff --git a/toolchain/sem_ir/inst_fingerprinter.cpp b/toolchain/sem_ir/inst_fingerprinter.cpp index 9d2cf6b678a8..2aa9f81b980c 100644 --- a/toolchain/sem_ir/inst_fingerprinter.cpp +++ b/toolchain/sem_ir/inst_fingerprinter.cpp @@ -26,6 +26,7 @@ #include "toolchain/sem_ir/dump.h" #include "toolchain/sem_ir/entity_with_params_base.h" #include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/import_ir.h" #include "toolchain/sem_ir/name_scope.h" #include "toolchain/sem_ir/typed_insts.h" @@ -421,7 +422,19 @@ struct Worklist { } auto Add(FunctionId function_id) -> void { - AddEntity(sem_ir->functions().Get(function_id)); + const auto& function = sem_ir->functions().Get(function_id); + if (!function.name_id.has_value()) { + auto [canonical_ir, canonical_decl_id] = + GetCanonicalFileAndInstId(sem_ir, function.first_decl_id()); + llvm::SaveAndRestore in_file(sem_ir, canonical_ir); + AddPackage(NameScopeId::Package); + AddLibrary(canonical_ir); + // TODO: Find a more stable way to assign fingerprints to unnamed + // functions. + AddInteger(canonical_decl_id.index); + return; + } + AddEntity(function); } auto Add(CppOverloadSetId cpp_overload_set_id) -> void { diff --git a/toolchain/sem_ir/inst_namer.cpp b/toolchain/sem_ir/inst_namer.cpp index 10a2dc47185a..82c77f3a8565 100644 --- a/toolchain/sem_ir/inst_namer.cpp +++ b/toolchain/sem_ir/inst_namer.cpp @@ -634,7 +634,9 @@ auto InstNamer::PushEntity(FunctionId function_id, ScopeId scope_id, scope.name = globals_.AllocateName( *this, fn_loc, llvm::formatv("{0}{1}{2}", scope_prefix, scope_prefix.empty() ? "" : ".", - sem_ir_->names().GetIRBaseName(fn.name_id))); + fn.name_id.has_value() + ? sem_ir_->names().GetIRBaseName(fn.name_id) + : "fn")); if (!fn.body_block_ids.empty()) { AddBlockLabel(scope_id, fn.body_block_ids.front(), "entry", fn_loc); } diff --git a/toolchain/sem_ir/mangler.cpp b/toolchain/sem_ir/mangler.cpp index 01f95cd7920d..cbdb77b7d750 100644 --- a/toolchain/sem_ir/mangler.cpp +++ b/toolchain/sem_ir/mangler.cpp @@ -211,7 +211,11 @@ auto Mangler::MangleImpl(SemIR::FunctionId function_id, os << "_C"; - MangleNameId(os, function.name_id); + if (function.name_id.has_value()) { + MangleNameId(os, function.name_id); + } else { + os << "fn"; + } char separator = '.'; // For a special function, add a marker to disambiguate. @@ -275,7 +279,8 @@ auto Mangler::MangleImpl(SemIR::FunctionId function_id, MangleInverseQualifiedNameScope(os, function.parent_scope_id, SemIR::SpecificId::None, separator); - if (sem_ir().name_scopes().IsPrivateToLibrary(function.name_id, + if (!function.name_id.has_value() || + sem_ir().name_scopes().IsPrivateToLibrary(function.name_id, function.parent_scope_id)) { os << "."; MangleFingerprint(os, &sem_ir(), function.first_decl_id()); diff --git a/toolchain/sem_ir/stringify.cpp b/toolchain/sem_ir/stringify.cpp index a893c47d028a..5d129a535911 100644 --- a/toolchain/sem_ir/stringify.cpp +++ b/toolchain/sem_ir/stringify.cpp @@ -158,6 +158,10 @@ class StepStack { // Pushes all components of a qualified name (`A.B.C`) onto the stack. auto PushQualifiedName(NameScopeId name_scope_id, NameId name_id) -> void { + if (!name_id.has_value()) { + PushString(""); + return; + } PushNameId(name_id); if (!qualified_names_) { return; @@ -671,8 +675,17 @@ class Stringifier { *out_ << ""; } + auto StringifyInst(InstId /*inst_id*/, FunctionDecl inst) -> void { + const auto& fn = sem_ir_->functions().Get(inst.function_id); + step_stack_->PushQualifiedName(fn.parent_scope_id, fn.name_id); + } + auto StringifyInst(InstId /*inst_id*/, FunctionType inst) -> void { const auto& fn = sem_ir_->functions().Get(inst.function_id); + if (!fn.name_id.has_value()) { + *out_ << ""; + return; + } *out_ << "Push( StepStack::QualifiedNameItem{fn.parent_scope_id, fn.name_id}, ">");