Detect control flow in entities nested inside functions (#5336)

Right now, return_scope_stack is being used to determine whether logic
is in a function scope. However, we need to handle nested entities
inside function scopes. For example where this crashes right now:

```
base class C(B:! bool) {}

fn F() {
  class B {
    extend base: C(true or false);
  }
}
```

This is doing a few things to make this kind of code not crash:

- Split `scope_stack().Push` into `PushForDeclName`, `PushForEntity`,
`PushForExpr`, and `PushForFunction` so that better decisions can be
made about behaviors.
- Hide `return_scope_stack` in the API, instead using interfaces to get
at the underlying data.
- Also using `PushForFunction` to update it similar to the other stacks
that `ScopeStack` manages.
- Add `IsInFunctionScope` as the best way to determine presence in
function scope.
- Remove `PeekIsLexicalScope` since destruction really wants function
scope information anyways.
- Clean up `destroy_id_stack` handling to be for function scopes rather
than lexical scopes.
- Return after related `context.TODO`s in a couple more spots, so that
code doesn't proceed to add control flow in spite of the lack of
support.

---------

Co-authored-by: Geoff Romer <gromer@google.com>
This commit is contained in:
Jon Ross-Perkins
2025-04-23 19:03:53 +00:00
committed by GitHub
co-authored by Geoff Romer
parent 51498547c9
commit 03e693873b
22 changed files with 476 additions and 391 deletions
+4 -2
View File
@@ -229,7 +229,9 @@ auto CheckUnit::ImportCurrentPackage(SemIR::InstId package_inst_id,
unit_and_imports_->package_imports_map.Lookup(PackageNameId::None);
if (!import_map_lookup) {
// Push the scope; there are no names to add.
context_.scope_stack().Push(package_inst_id, SemIR::NameScopeId::Package);
context_.scope_stack().PushForEntity(
package_inst_id, SemIR::NameScopeId::Package, SemIR::SpecificId::None,
/*lexical_lookup_has_load_error=*/false);
return;
}
PackageImports& self_import =
@@ -244,7 +246,7 @@ auto CheckUnit::ImportCurrentPackage(SemIR::InstId package_inst_id,
CollectTransitiveImports(self_import.import_decl_id, &self_import,
/*api_imports=*/nullptr));
context_.scope_stack().Push(
context_.scope_stack().PushForEntity(
package_inst_id, SemIR::NameScopeId::Package, SemIR::SpecificId::None,
context_.name_scopes().Get(SemIR::NameScopeId::Package).has_error());
}
+1 -4
View File
@@ -118,10 +118,7 @@ class Context {
auto scope_stack() -> ScopeStack& { return scope_stack_; }
// Conveneicne functions for frequently-used `scope_stack` members.
auto return_scope_stack() -> llvm::SmallVector<ScopeStack::ReturnScope>& {
return scope_stack().return_scope_stack();
}
// Convenience functions for frequently-used `scope_stack` members.
auto break_continue_stack()
-> llvm::SmallVector<ScopeStack::BreakContinueScope>& {
return scope_stack().break_continue_stack();
+2 -2
View File
@@ -139,8 +139,8 @@ auto IsCurrentPositionReachable(Context& context) -> bool {
auto MaybeAddCleanupForInst(Context& context, SemIR::TypeId type_id,
SemIR::InstId inst_id) -> void {
if (!context.scope_stack().PeekIsLexicalScope()) {
// Cleanup can only occur in lexical scopes.
if (!context.scope_stack().IsInFunctionScope()) {
// Cleanup can only occur in function scopes.
return;
}
+4 -4
View File
@@ -62,7 +62,7 @@ auto DeclNameStack::PushScopeAndStartName() -> void {
decl_name_stack_.push_back(MakeEmptyNameContext());
// Create a scope for any parameters introduced in this name.
context_->scope_stack().Push();
context_->scope_stack().PushForDeclName();
}
auto DeclNameStack::FinishName(const NameComponent& name) -> NameContext {
@@ -233,8 +233,8 @@ static auto PushNameQualifierScope(Context& context, SemIR::LocId loc_id,
// providing the definition.
StartGenericDecl(context);
context.scope_stack().Push(scope_inst_id, scope_id, self_specific_id,
has_error);
context.scope_stack().PushForEntity(scope_inst_id, scope_id, self_specific_id,
has_error);
// An interface also introduces its 'Self' parameter into scope, despite it
// not being redeclared as part of the qualifier.
@@ -246,7 +246,7 @@ static auto PushNameQualifierScope(Context& context, SemIR::LocId loc_id,
}
// Enter a parameter scope in case the qualified name itself has parameters.
context.scope_stack().Push();
context.scope_stack().PushForSameRegion();
}
auto DeclNameStack::ApplyNameQualifier(const NameComponent& name) -> void {
+2 -2
View File
@@ -108,8 +108,8 @@ auto HandleParseNode(Context& context, Parse::ChoiceDefinitionStartId node_id)
mut_class.self_type_id = self_type_id;
// Enter the choice scope.
context.scope_stack().Push(class_decl_id, class_info.scope_id,
self_specific_id);
context.scope_stack().PushForEntity(class_decl_id, class_info.scope_id,
self_specific_id);
// Checking the binding pattern for an alternative requires a non-empty stack.
// We reuse the Choice token even though we're now checking an alternative
// inside the Choice, since there's no better token to use.
+1 -1
View File
@@ -278,7 +278,7 @@ auto HandleParseNode(Context& context, Parse::ClassDefinitionStartId node_id)
StartClassDefinition(context, class_info, class_decl_id);
// Enter the class scope.
context.scope_stack().Push(
context.scope_stack().PushForEntity(
class_decl_id, class_info.scope_id,
context.generics().GetSelfSpecific(class_info.generic_id));
StartGenericDefinition(context);
+1 -1
View File
@@ -10,7 +10,7 @@ namespace Carbon::Check {
auto HandleParseNode(Context& context, Parse::CodeBlockStartId node_id)
-> bool {
context.node_stack().Push(node_id);
context.scope_stack().Push();
context.scope_stack().PushForSameRegion();
return true;
}
+2 -4
View File
@@ -585,10 +585,9 @@ static auto HandleFunctionDefinitionAfterSignature(
auto& function = context.functions().Get(function_id);
// Create the function scope and the entry block.
context.return_scope_stack().push_back({.decl_id = decl_id});
context.scope_stack().PushForFunctionBody(decl_id);
context.inst_block_stack().Push();
context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
context.scope_stack().Push(decl_id);
StartGenericDefinition(context);
CheckFunctionDefinitionSignature(context, function);
@@ -645,9 +644,8 @@ auto HandleParseNode(Context& context, Parse::FunctionDefinitionId node_id)
}
}
context.scope_stack().Pop();
context.inst_block_stack().Pop();
context.return_scope_stack().pop_back();
context.scope_stack().Pop();
context.decl_name_stack().PopScope();
auto& function = context.functions().Get(function_id);
+4 -4
View File
@@ -64,10 +64,10 @@ auto HandleParseNode(Context& context, Parse::IfExprThenId node_id) -> bool {
}
auto HandleParseNode(Context& context, Parse::IfExprElseId node_id) -> bool {
if (context.return_scope_stack().empty()) {
context.TODO(node_id,
"Control flow expressions are currently only supported inside "
"functions.");
if (!context.scope_stack().IsInFunctionScope()) {
return context.TODO(node_id,
"Control flow expressions are currently only supported "
"inside functions.");
}
// Alias node_id for if/then/else consistency.
auto& else_node = node_id;
+1 -1
View File
@@ -537,7 +537,7 @@ auto HandleParseNode(Context& context, Parse::ImplDefinitionStartId node_id)
context.name_scopes().Add(impl_decl_id, SemIR::NameId::None,
context.decl_name_stack().PeekParentScopeId());
context.scope_stack().Push(
context.scope_stack().PushForEntity(
impl_decl_id, impl_info.scope_id,
context.generics().GetSelfSpecific(impl_info.generic_id));
StartGenericDefinition(context);
+2 -2
View File
@@ -193,8 +193,8 @@ auto HandleParseNode(Context& context,
interface_info.self_param_id);
// Enter the interface scope.
context.scope_stack().Push(interface_decl_id, interface_info.scope_id,
self_specific_id);
context.scope_stack().PushForEntity(
interface_decl_id, interface_info.scope_id, self_specific_id);
// TODO: Handle the case where there's control flow in the interface body. For
// example:
+4 -4
View File
@@ -398,10 +398,10 @@ auto HandleParseNode(Context& context, Parse::ShortCircuitOperandOrId node_id)
// occurs during operand handling.
static auto HandleShortCircuitOperator(Context& context, Parse::NodeId node_id)
-> bool {
if (context.return_scope_stack().empty()) {
context.TODO(node_id,
"Control flow expressions are currently only supported inside "
"functions.");
if (!context.scope_stack().IsInFunctionScope()) {
return context.TODO(node_id,
"Control flow expressions are currently only supported "
"inside functions.");
}
auto [rhs_node, rhs_id] = context.node_stack().PopExprWithNodeId();
auto short_circuit_result_id = context.node_stack().PopExpr();
+2 -2
View File
@@ -14,7 +14,7 @@ namespace Carbon::Check {
auto HandleParseNode(Context& context, Parse::StructLiteralStartId node_id)
-> bool {
context.scope_stack().Push();
context.scope_stack().PushForSameRegion();
context.node_stack().Push(node_id);
context.struct_type_fields_stack().PushArray();
context.param_and_arg_refs_stack().Push();
@@ -23,7 +23,7 @@ auto HandleParseNode(Context& context, Parse::StructLiteralStartId node_id)
auto HandleParseNode(Context& context, Parse::StructTypeLiteralStartId node_id)
-> bool {
context.scope_stack().Push();
context.scope_stack().PushForSameRegion();
context.node_stack().Push(node_id);
context.struct_type_fields_stack().PushArray();
return true;
+1 -1
View File
@@ -27,7 +27,7 @@ auto HandleParseNode(Context& context, Parse::WhereOperandId node_id) -> bool {
// Introduce a name scope so that we can remove the `.Self` entry we are
// adding to name lookup at the end of the `where` expression.
context.scope_stack().Push();
context.scope_stack().PushForSameRegion();
// Introduce `.Self` as a symbolic binding. Its type is the value of the
// expression to the left of `where`, so `MyInterface` in the example above.
auto entity_name_id = context.entity_names().Add(
+6 -7
View File
@@ -12,12 +12,11 @@ namespace Carbon::Check {
// Gets the function that lexically encloses the current location.
auto GetCurrentFunctionForReturn(Context& context) -> SemIR::Function& {
CARBON_CHECK(!context.return_scope_stack().empty(),
CARBON_CHECK(context.scope_stack().IsInFunctionScope(),
"Handling return but not in a function");
auto function_id = context.insts()
.GetAs<SemIR::FunctionDecl>(
context.return_scope_stack().back().decl_id)
.function_id;
auto decl_id = context.scope_stack().GetReturnScopeDeclId();
auto function_id =
context.insts().GetAs<SemIR::FunctionDecl>(decl_id).function_id;
return context.functions().Get(function_id);
}
@@ -33,9 +32,9 @@ auto GetCurrentReturnSlot(Context& context) -> SemIR::InstId {
// Gets the currently in scope `returned var`, if any, that would be returned
// by a `return var;`.
static auto GetCurrentReturnedVar(Context& context) -> SemIR::InstId {
CARBON_CHECK(!context.return_scope_stack().empty(),
CARBON_CHECK(context.scope_stack().IsInFunctionScope(),
"Handling return but not in a function");
return context.return_scope_stack().back().returned_var;
return context.scope_stack().GetReturnedVar();
}
// Produces a note that the given function has no explicit return type.
+49 -17
View File
@@ -63,8 +63,6 @@ auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
// specifics, we'll need to somehow track them in lookup.
CARBON_CHECK(!specific_id.has_value(),
"Lexical scope should not have an associated specific.");
destroy_id_stack_.PushArray();
} else {
non_lexical_scope_stack_.push_back({.scope_index = next_scope_index_,
.name_scope_id = scope_id,
@@ -79,6 +77,36 @@ auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
VerifyNextCompileTimeBindIndex("Push", scope_stack_.back());
}
auto ScopeStack::PushForDeclName() -> void {
Push(SemIR::InstId::None, SemIR::NameScopeId::None, SemIR::SpecificId::None,
/*lexical_lookup_has_load_error=*/false);
MarkNestingIfInReturnScope();
}
auto ScopeStack::PushForEntity(SemIR::InstId scope_inst_id,
SemIR::NameScopeId scope_id,
SemIR::SpecificId specific_id,
bool lexical_lookup_has_load_error) -> void {
CARBON_CHECK(scope_inst_id.has_value());
CARBON_DCHECK(!sem_ir_->insts().Is<SemIR::FunctionDecl>(scope_inst_id));
Push(scope_inst_id, scope_id, specific_id, lexical_lookup_has_load_error);
MarkNestingIfInReturnScope();
}
auto ScopeStack::PushForSameRegion() -> void {
Push(SemIR::InstId::None, SemIR::NameScopeId::None, SemIR::SpecificId::None,
/*lexical_lookup_has_load_error=*/false);
}
auto ScopeStack::PushForFunctionBody(SemIR::InstId scope_inst_id) -> void {
CARBON_DCHECK(sem_ir_->insts().Is<SemIR::FunctionDecl>(scope_inst_id));
Push(scope_inst_id, SemIR::NameScopeId::None, SemIR::SpecificId::None,
/*lexical_lookup_has_load_error=*/false);
return_scope_stack_.push_back({.decl_id = scope_inst_id});
destroy_id_stack_.PushArray();
}
auto ScopeStack::Pop() -> void {
auto scope = scope_stack_.pop_back_val();
@@ -89,17 +117,27 @@ auto ScopeStack::Pop() -> void {
lexical_results.pop_back();
});
if (scope.is_lexical_scope()) {
destroy_id_stack_.PopArray();
} else {
if (!scope.is_lexical_scope()) {
CARBON_CHECK(non_lexical_scope_stack_.back().scope_index == scope.index);
non_lexical_scope_stack_.pop_back();
}
if (scope.has_returned_var) {
CARBON_CHECK(!return_scope_stack_.empty());
CARBON_CHECK(return_scope_stack_.back().returned_var.has_value());
return_scope_stack_.back().returned_var = SemIR::InstId::None;
if (!return_scope_stack_.empty()) {
if (scope.has_returned_var) {
CARBON_CHECK(return_scope_stack_.back().returned_var.has_value());
return_scope_stack_.back().returned_var = SemIR::InstId::None;
}
if (return_scope_stack_.back().decl_id == scope.scope_inst_id) {
// Leaving the function scope.
return_scope_stack_.pop_back();
destroy_id_stack_.PopArray();
} else if (return_scope_stack_.back().nested_scope_index == scope.index) {
// Returned to a function scope from a non-function nested entity scope.
return_scope_stack_.back().nested_scope_index = ScopeIndex::None;
}
} else {
CARBON_CHECK(!scope.has_returned_var);
}
VerifyNextCompileTimeBindIndex("Pop", scope);
@@ -218,11 +256,7 @@ auto ScopeStack::Suspend() -> SuspendedScope {
CARBON_CHECK(!scope_stack_.empty(), "No scope to suspend");
SuspendedScope result = {.entry = scope_stack_.pop_back_val(),
.suspended_items = {}};
if (result.entry.is_lexical_scope()) {
CARBON_CHECK(destroy_id_stack_.PeekArray().empty(),
"Missing support to suspend scopes with destructed storage");
destroy_id_stack_.PopArray();
} else {
if (!result.entry.is_lexical_scope()) {
non_lexical_scope_stack_.pop_back();
}
auto peek_compile_time_bindings = compile_time_binding_stack_.PeekArray();
@@ -265,9 +299,7 @@ auto ScopeStack::Restore(SuspendedScope scope) -> void {
VerifyNextCompileTimeBindIndex("Restore", scope.entry);
if (scope.entry.is_lexical_scope()) {
destroy_id_stack_.PushArray();
} else {
if (!scope.entry.is_lexical_scope()) {
non_lexical_scope_stack_.push_back(
{.scope_index = scope.entry.index,
.name_scope_id = scope.entry.scope_id,
+76 -29
View File
@@ -31,17 +31,6 @@ class ScopeStack {
SemIR::InstBlockId continue_target;
};
// A scope in which `return` can be used.
struct ReturnScope {
// The declaration from which we can return. Inside a function, this will
// be a `FunctionDecl`.
SemIR::InstId decl_id;
// The value corresponding to the current `returned var`, if any. Will be
// set and unset as `returned var`s are declared and go out of scope.
SemIR::InstId returned_var = SemIR::InstId::None;
};
// A non-lexical scope in which unqualified lookup may be required.
struct NonLexicalScope {
// The index of the scope in the scope stack.
@@ -57,17 +46,24 @@ class ScopeStack {
// Information about a scope that has been temporarily removed from the stack.
struct SuspendedScope;
// Pushes a scope onto scope_stack_. NameScopeId::None is used for new
// scopes. lexical_lookup_has_load_error is used to limit diagnostics when a
// given namespace may contain a mix of both successful and failed name
// imports.
auto Push(SemIR::InstId scope_inst_id = SemIR::InstId::None,
SemIR::NameScopeId scope_id = SemIR::NameScopeId::None,
SemIR::SpecificId specific_id = SemIR::SpecificId::None,
bool lexical_lookup_has_load_error = false) -> void;
// Pushes a scope for a declaration name's parameters.
auto PushForDeclName() -> void;
// Pops the top scope from scope_stack_, cleaning up names from
// lexical_lookup_.
// Pushes a non-function entity scope. Functions must use
// `PushForFunctionBody` instead.
auto PushForEntity(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
SemIR::SpecificId specific_id,
bool lexical_lookup_has_load_error = false) -> void;
// Pushes a scope which should be in the same region as the current scope.
// These can be in a function without breaking `return` scoping. For example,
// this is used by struct literals and code blocks.
auto PushForSameRegion() -> void;
// Pushes a function scope.
auto PushForFunctionBody(SemIR::InstId scope_inst_id) -> void;
// Pops the top scope from scope_stack_. Removes names from lexical_lookup_.
auto Pop() -> void;
// Pops the top scope from scope_stack_ if it contains no names.
@@ -98,8 +94,12 @@ class ScopeStack {
return Peek().specific_id;
}
// Returns true if current scope is lexical.
auto PeekIsLexicalScope() const -> bool { return Peek().is_lexical_scope(); }
// Returns true if the current scope is inside a function scope (either the
// scope itself, or a lexical scope), without an intervening entity scope.
auto IsInFunctionScope() const -> bool {
return !return_scope_stack_.empty() &&
!return_scope_stack_.back().nested_scope_index.has_value();
}
// Returns the current scope, if it is of the specified kind. Otherwise,
// returns nullopt.
@@ -117,6 +117,19 @@ class ScopeStack {
// is already a `returned var`, returns it instead.
auto SetReturnedVarOrGetExisting(SemIR::InstId inst_id) -> SemIR::InstId;
// Returns the `returned var` instruction that's currently in scope, or `None`
// if there isn't one.
auto GetReturnedVar() -> SemIR::InstId {
CARBON_CHECK(IsInFunctionScope(), "Handling return but not in a function");
return return_scope_stack_.back().returned_var;
}
// Returns the decl ID for the current return scope.
auto GetReturnScopeDeclId() -> SemIR::InstId {
CARBON_CHECK(IsInFunctionScope(), "Handling return but not in a function");
return return_scope_stack_.back().decl_id;
}
// Looks up the name `name_id` in the current scope and enclosing scopes, but
// do not look past `scope_index`. Returns the existing lookup result, if any.
auto LookupInLexicalScopesWithin(SemIR::NameId name_id,
@@ -160,10 +173,6 @@ class ScopeStack {
// Runs verification that the processing cleanly finished.
auto VerifyOnFinish() const -> void;
auto return_scope_stack() -> llvm::SmallVector<ReturnScope>& {
return return_scope_stack_;
}
auto break_continue_stack() -> llvm::SmallVector<BreakContinueScope>& {
return break_continue_stack_;
}
@@ -219,6 +228,35 @@ class ScopeStack {
Set<SemIR::NameId> names = {};
};
// A scope in which `return` can be used.
struct ReturnScope {
// The `FunctionDecl`.
SemIR::InstId decl_id;
// The value corresponding to the current `returned var`, if any. Will be
// set and unset as `returned var`s are declared and go out of scope.
SemIR::InstId returned_var = SemIR::InstId::None;
// When a nested scope interrupts a return scope, this is the index of the
// outermost interrupting scope (the one closest to the function scope).
// This can then be used to determine whether we're actually inside the most
// recent `ReturnScope`, or inside a different entity scope.
//
// This won't be set for functions directly inside functions, because they
// will have their own `ReturnScope`.
// For example, when a `class` is inside a `fn`, it interrupts the function
// body by setting this on `PushEntity`; `Pop` will set it back to `None`.
ScopeIndex nested_scope_index = ScopeIndex::None;
};
// Pushes a scope onto scope_stack_. NameScopeId::None is used for new scopes.
// lexical_lookup_has_load_error is used to limit diagnostics when a given
// namespace may contain a mix of both successful and failed name imports.
auto Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
SemIR::SpecificId specific_id, bool lexical_lookup_has_load_error)
-> void;
auto Peek() const -> const ScopeStackEntry& { return scope_stack_.back(); }
// Returns whether lexical lookup currently has any load errors.
@@ -227,6 +265,15 @@ class ScopeStack {
scope_stack_.back().lexical_lookup_has_load_error;
}
// If inside a return scope, marks a nested scope (see `nested_scope_index`).
// Called after pushing the new scope.
auto MarkNestingIfInReturnScope() -> void {
if (!return_scope_stack_.empty() &&
!return_scope_stack_.back().nested_scope_index.has_value()) {
return_scope_stack_.back().nested_scope_index = scope_stack_.back().index;
}
}
// Checks that the provided scope's `next_compile_time_bind_index` matches the
// full size of the current `compile_time_binding_stack_`. The values should
// always match, and this is used to validate the correspondence during
@@ -246,8 +293,8 @@ class ScopeStack {
// A stack for scope context.
llvm::SmallVector<ScopeStackEntry> scope_stack_;
// A stack of `destroy` functions to call. This only has entries for lexical
// scopes, because non-lexical scopes don't have destruction on scope exit.
// A stack of `destroy` functions to call. This only has entries inside of
// function bodies, where destruction on scope exit is required.
ArrayStack<SemIR::InstId> destroy_id_stack_;
// Information about non-lexical scopes. This is a subset of the entries and
+73 -15
View File
@@ -8,35 +8,93 @@
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/alias/fail_control_flow.carbon
// CHECK:STDERR: fail_control_flow.carbon:[[@LINE+16]]:11: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_simple.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_simple.carbon:[[@LINE+8]]:11: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: alias a = true or false;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_control_flow.carbon:[[@LINE+12]]:11: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: alias a = true or false;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_control_flow.carbon:[[@LINE+8]]:11: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: alias a = true or false;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_control_flow.carbon:[[@LINE+4]]:11: error: alias initializer must be a name reference [AliasRequiresNameRef]
// CHECK:STDERR: fail_simple.carbon:[[@LINE+4]]:11: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: alias a = true or false;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
alias a = true or false;
// CHECK:STDOUT: --- fail_control_flow.carbon
// --- fail_nested.carbon
library "[[@TEST_NAME]]";
base class C(B:! bool) {}
fn F() {
class B {
// CHECK:STDERR: fail_nested.carbon:[[@LINE+4]]:20: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: extend base: C(true or false);
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
extend base: C(true or false);
}
}
// CHECK:STDOUT: --- fail_simple.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_nested.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %B.7dd: bool = bind_symbolic_name B, 0 [symbolic]
// CHECK:STDOUT: %B.patt: bool = symbolic_binding_pattern B, 0 [symbolic]
// CHECK:STDOUT: %C.type: type = generic_class_type @C [concrete]
// CHECK:STDOUT: %C.generic: %C.type = struct_value () [concrete]
// CHECK:STDOUT: %C: type = class_type @C, @C(%B.7dd) [symbolic]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
// CHECK:STDOUT: %B.d97: type = class_type @B [concrete]
// CHECK:STDOUT: %true: bool = bool_literal true [concrete]
// CHECK:STDOUT: %false: bool = bool_literal false [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: generic class @C(<unexpected>.inst27.loc4_14: bool) {
// CHECK:STDOUT: %B: bool = bind_symbolic_name B, 0 [symbolic = %B (constants.%B.7dd)]
// CHECK:STDOUT: %B.patt.loc4_14.2: bool = symbolic_binding_pattern B, 0 [symbolic = %B.patt.loc4_14.2 (constants.%B.patt)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT:
// CHECK:STDOUT: class {
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: %.loc27: bool = block_arg <unexpected instblockref inst_block5> [concrete = constants.%true]
// CHECK:STDOUT: %a: <error> = bind_alias a, <error> [concrete = <error>]
// CHECK:STDOUT: class @B {
// CHECK:STDOUT: %C.ref: %C.type = name_ref C, <unexpected>.inst32.loc4_24 [concrete = constants.%C.generic]
// CHECK:STDOUT: %true.loc12_20: bool = bool_literal true [concrete = constants.%true]
// CHECK:STDOUT: %.loc12: bool = not %true.loc12_20 [concrete = constants.%false]
// CHECK:STDOUT: %true.loc12_25: bool = bool_literal true [concrete = constants.%true]
// CHECK:STDOUT: if %.loc12 br !or.rhs else br !or.result(%true.loc12_25)
// CHECK:STDOUT: complete_type_witness = invalid
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%B.d97
// CHECK:STDOUT: .C = <poisoned>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F();
// CHECK:STDOUT:
// CHECK:STDOUT: specific @C(constants.%B.7dd) {
// CHECK:STDOUT: %B => constants.%B.7dd
// CHECK:STDOUT: %B.patt.loc4_14.2 => constants.%B.patt
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -48,7 +48,6 @@ fn F() {
var explicit_return: ExplicitReturn;
var with_addr: WithAddr;
if (true) {
// TODO: Destroy in nested scope.
var in_scope: NoAddr;
}
}
@@ -476,22 +475,24 @@ fn G() { F({}); }
// CHECK:STDOUT: !if.then:
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %in_scope.patt: %NoAddr = binding_pattern in_scope
// CHECK:STDOUT: %.loc11: %NoAddr = var_pattern %in_scope.patt
// CHECK:STDOUT: %.loc10_5.1: %NoAddr = var_pattern %in_scope.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %in_scope.var: ref %NoAddr = var in_scope
// CHECK:STDOUT: %destroy.ref.4: %destroy.type.bc5 = name_ref destroy, imports.%Main.import_ref.7fe [concrete = constants.%destroy.60f]
// CHECK:STDOUT: %destroy.bound.4: <bound method> = bound_method %in_scope.var, %destroy.ref.4
// CHECK:STDOUT: %NoAddr.ref.loc11: type = name_ref NoAddr, imports.%Main.NoAddr [concrete = constants.%NoAddr]
// CHECK:STDOUT: %NoAddr.ref.loc10: type = name_ref NoAddr, imports.%Main.NoAddr [concrete = constants.%NoAddr]
// CHECK:STDOUT: %in_scope: ref %NoAddr = bind_name in_scope, %in_scope.var
// CHECK:STDOUT: br !if.else
// CHECK:STDOUT:
// CHECK:STDOUT: !if.else:
// CHECK:STDOUT: %.loc10_5.2: %NoAddr = bind_value %in_scope.var
// CHECK:STDOUT: %destroy.call.1: init %empty_tuple.type = call %destroy.bound.4(%.loc10_5.2)
// CHECK:STDOUT: %addr: %ptr.b4e = addr_of %with_addr.var
// CHECK:STDOUT: %destroy.call.1: init %empty_tuple.type = call %destroy.bound.3(%addr)
// CHECK:STDOUT: %destroy.call.2: init %empty_tuple.type = call %destroy.bound.3(%addr)
// CHECK:STDOUT: %.loc7_3.2: %ExplicitReturn = bind_value %explicit_return.var
// CHECK:STDOUT: %destroy.call.2: init %empty_tuple.type = call %destroy.bound.2(%.loc7_3.2)
// CHECK:STDOUT: %destroy.call.3: init %empty_tuple.type = call %destroy.bound.2(%.loc7_3.2)
// CHECK:STDOUT: %.loc6_3.2: %NoAddr = bind_value %no_addr.var
// CHECK:STDOUT: %destroy.call.3: init %empty_tuple.type = call %destroy.bound.1(%.loc6_3.2)
// CHECK:STDOUT: %destroy.call.4: init %empty_tuple.type = call %destroy.bound.1(%.loc6_3.2)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
+110 -77
View File
@@ -8,133 +8,166 @@
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/if_expr/fail_not_in_function.carbon
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+16]]:14: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_basic.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_basic.carbon:[[@LINE+12]]:14: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: let x: i32 = if true then 1 else 0;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+12]]:22: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_basic.carbon:[[@LINE+8]]:22: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: let x: i32 = if true then 1 else 0;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+8]]:14: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_basic.carbon:[[@LINE+4]]:14: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: let x: i32 = if true then 1 else 0;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+4]]:14: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: let x: i32 = if true then 1 else 0;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
let x: i32 = if true then 1 else 0;
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+8]]:8: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_types.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_types.carbon:[[@LINE+4]]:8: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var y: if true then i32 else f64;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+4]]:8: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var y: if true then i32 else f64;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
var y: if true then i32 else f64;
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+8]]:9: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_in_param.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_in_param.carbon:[[@LINE+4]]:9: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fn F(a: if true then i32 else f64);
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+4]]:9: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fn F(a: if true then i32 else f64);
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
fn F(a: if true then i32 else f64);
// --- fail_class.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+16]]:10: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_class.carbon:[[@LINE+12]]:10: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var n: if true then i32 else f64;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+12]]:18: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_class.carbon:[[@LINE+8]]:18: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var n: if true then i32 else f64;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+8]]:10: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_class.carbon:[[@LINE+4]]:10: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var n: if true then i32 else f64;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_not_in_function.carbon:[[@LINE+4]]:10: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var n: if true then i32 else f64;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
var n: if true then i32 else f64;
}
// CHECK:STDOUT: --- fail_not_in_function.carbon
// --- fail_nested_class.carbon
library "[[@TEST_NAME]]";
base class C(T:! type) {}
fn F() {
class B {
// CHECK:STDERR: fail_nested_class.carbon:[[@LINE+4]]:20: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: extend base: C(if true then i32 else i32);
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
extend base: C(if true then i32 else i32);
}
}
// CHECK:STDOUT: --- fail_basic.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_types.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_in_param.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_class.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %true: bool = bool_literal true [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %true: bool = bool_literal true [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
// CHECK:STDOUT: .Int = %Core.Int
// CHECK:STDOUT: .ImplicitAs = %Core.ImplicitAs
// CHECK:STDOUT: .Float = %Core.Float
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .Core = imports.%Core
// CHECK:STDOUT: .x = %x
// CHECK:STDOUT: .y = %y
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %x.patt: %i32 = binding_pattern x
// CHECK:STDOUT: }
// CHECK:STDOUT: %.loc27: type = splice_block %i32 [concrete = constants.%i32] {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x: %i32 = bind_name x, <unexpected>.inst1317.loc27_14
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %y.patt: %i32 = binding_pattern y
// CHECK:STDOUT: %.loc37: %i32 = var_pattern %y.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %y.var: ref %i32 = var y
// CHECK:STDOUT: %y: ref %i32 = bind_name y, %y.var
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
// CHECK:STDOUT: %a.patt: %i32 = binding_pattern a
// CHECK:STDOUT: %a.param_patt: %i32 = value_param_pattern %a.patt, call_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %a.param: %i32 = value_param call_param0
// CHECK:STDOUT: %a: %i32 = bind_name a, %a.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %true: bool = bool_literal true [concrete = constants.%true]
// CHECK:STDOUT: if %true br !if.expr.then else br !if.expr.else
// CHECK:STDOUT: complete_type_witness = <unexpected>.inst1384.loc67_1
// CHECK:STDOUT: complete_type_witness = invalid
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: .n = <unexpected>.inst1381.loc66_8
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F(%a.param: %i32);
// CHECK:STDOUT: --- fail_nested_class.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic]
// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic]
// CHECK:STDOUT: %C.type: type = generic_class_type @C [concrete]
// CHECK:STDOUT: %C.generic: %C.type = struct_value () [concrete]
// CHECK:STDOUT: %C: type = class_type @C, @C(%T) [symbolic]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
// CHECK:STDOUT: %B: type = class_type @B [concrete]
// CHECK:STDOUT: %true: bool = bool_literal true [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: generic class @C(<unexpected>.inst17.loc4_14: type) {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %T.patt.loc4_14.2: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_14.2 (constants.%T.patt)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT:
// CHECK:STDOUT: class {
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type.357]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @B {
// CHECK:STDOUT: %C.ref: %C.type = name_ref C, <unexpected>.inst21.loc4_24 [concrete = constants.%C.generic]
// CHECK:STDOUT: %true: bool = bool_literal true [concrete = constants.%true]
// CHECK:STDOUT: if %true br !if.expr.then else br !if.expr.else
// CHECK:STDOUT: complete_type_witness = invalid
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%B
// CHECK:STDOUT: .C = <poisoned>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F();
// CHECK:STDOUT:
// CHECK:STDOUT: specific @C(constants.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT: %T.patt.loc4_14.2 => constants.%T.patt
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -8,155 +8,80 @@
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/operators/builtin/fail_and_or_not_in_function.carbon
// --- fail_and.carbon
library "[[@TEST_NAME]]";
// TODO: Make this a compile-time function.
fn F(b: bool) -> type {
return if b then i32 else f64;
}
// TODO: Short-circuit operators should be permitted outside functions.
// CHECK:STDERR: fail_and_or_not_in_function.carbon:[[@LINE+10]]:13: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_and.carbon:[[@LINE+4]]:13: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var and_: F(true and true);
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_and_or_not_in_function.carbon:[[@LINE+6]]:11: error: cannot evaluate type expression [TypeExprEvaluationFailure]
// CHECK:STDERR: var and_: F(true and true);
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_and_or_not_in_function.carbon: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR:
var and_: F(true and true);
// CHECK:STDERR: fail_and_or_not_in_function.carbon:[[@LINE+12]]:21: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_and_val.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_and_val.carbon:[[@LINE+8]]:21: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var and_val: bool = true and true;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_and_or_not_in_function.carbon:[[@LINE+8]]:21: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var and_val: bool = true and true;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_and_or_not_in_function.carbon:[[@LINE+4]]:21: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_and_val.carbon:[[@LINE+4]]:21: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var and_val: bool = true and true;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
var and_val: bool = true and true;
// CHECK:STDERR: fail_and_or_not_in_function.carbon:[[@LINE+10]]:12: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_or.carbon
library "[[@TEST_NAME]]";
// TODO: Make this a compile-time function.
fn F(b: bool) -> type {
return if b then i32 else f64;
}
// CHECK:STDERR: fail_or.carbon:[[@LINE+4]]:12: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var or_: F(true or true);
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_and_or_not_in_function.carbon:[[@LINE+6]]:10: error: cannot evaluate type expression [TypeExprEvaluationFailure]
// CHECK:STDERR: var or_: F(true or true);
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_and_or_not_in_function.carbon: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR:
var or_: F(true or true);
// CHECK:STDERR: fail_and_or_not_in_function.carbon:[[@LINE+12]]:20: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_or_val.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_or_val.carbon:[[@LINE+8]]:20: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var or_val: bool = true or true;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_and_or_not_in_function.carbon:[[@LINE+8]]:20: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var or_val: bool = true or true;
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_and_or_not_in_function.carbon:[[@LINE+4]]:20: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_or_val.carbon:[[@LINE+4]]:20: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var or_val: bool = true or true;
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR:
var or_val: bool = true or true;
// CHECK:STDOUT: --- fail_and_or_not_in_function.carbon
// CHECK:STDOUT: --- fail_and.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Bool.type: type = fn_type @Bool [concrete]
// CHECK:STDOUT: %Bool: %Bool.type = struct_value () [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete]
// CHECK:STDOUT: %Float.type: type = fn_type @Float [concrete]
// CHECK:STDOUT: %Float: %Float.type = struct_value () [concrete]
// CHECK:STDOUT: %true: bool = bool_literal true [concrete]
// CHECK:STDOUT: %false: bool = bool_literal false [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
// CHECK:STDOUT: .Bool = %Core.Bool
// CHECK:STDOUT: .Int = %Core.Int
// CHECK:STDOUT: .Float = %Core.Float
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .Core = imports.%Core
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: .and_ = %and_
// CHECK:STDOUT: .and_val = %and_val
// CHECK:STDOUT: .or_ = %or_
// CHECK:STDOUT: .or_val = %or_val
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
// CHECK:STDOUT: %b.patt: bool = binding_pattern b
// CHECK:STDOUT: %b.param_patt: bool = value_param_pattern %b.patt, call_param0
// CHECK:STDOUT: %return.patt: type = return_slot_pattern
// CHECK:STDOUT: %return.param_patt: type = out_param_pattern %return.patt, call_param1
// CHECK:STDOUT: } {
// CHECK:STDOUT: %b.param: bool = value_param call_param0
// CHECK:STDOUT: %.loc12_9.1: type = splice_block %.loc12_9.3 [concrete = bool] {
// CHECK:STDOUT: %bool.make_type: init type = call constants.%Bool() [concrete = bool]
// CHECK:STDOUT: %.loc12_9.2: type = value_of_initializer %bool.make_type [concrete = bool]
// CHECK:STDOUT: %.loc12_9.3: type = converted %bool.make_type, %.loc12_9.2 [concrete = bool]
// CHECK:STDOUT: }
// CHECK:STDOUT: %b: bool = bind_name b, %b.param
// CHECK:STDOUT: %return.param: ref type = out_param call_param1
// CHECK:STDOUT: %return: ref type = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %and_.patt: <error> = binding_pattern and_
// CHECK:STDOUT: %.loc27: <error> = var_pattern %and_.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %and_.var: ref <error> = var and_
// CHECK:STDOUT: %and_: <error> = bind_name and_, <error>
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %and_val.patt: bool = binding_pattern and_val
// CHECK:STDOUT: %.loc41_1: bool = var_pattern %and_val.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %and_val.var: ref bool = var and_val
// CHECK:STDOUT: %.loc41_14.1: type = splice_block %.loc41_14.3 [concrete = bool] {
// CHECK:STDOUT: %bool.make_type.loc41: init type = call constants.%Bool() [concrete = bool]
// CHECK:STDOUT: %.loc41_14.2: type = value_of_initializer %bool.make_type.loc41 [concrete = bool]
// CHECK:STDOUT: %.loc41_14.3: type = converted %bool.make_type.loc41, %.loc41_14.2 [concrete = bool]
// CHECK:STDOUT: }
// CHECK:STDOUT: %and_val: ref bool = bind_name and_val, %and_val.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %or_.patt: <error> = binding_pattern or_
// CHECK:STDOUT: %.loc53: <error> = var_pattern %or_.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %or_.var: ref <error> = var or_
// CHECK:STDOUT: %or_: <error> = bind_name or_, <error>
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %or_val.patt: bool = binding_pattern or_val
// CHECK:STDOUT: %.loc67_1: bool = var_pattern %or_val.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %or_val.var: ref bool = var or_val
// CHECK:STDOUT: %.loc67_13.1: type = splice_block %.loc67_13.3 [concrete = bool] {
// CHECK:STDOUT: %bool.make_type.loc67: init type = call constants.%Bool() [concrete = bool]
// CHECK:STDOUT: %.loc67_13.2: type = value_of_initializer %bool.make_type.loc67 [concrete = bool]
// CHECK:STDOUT: %.loc67_13.3: type = converted %bool.make_type.loc67, %.loc67_13.2 [concrete = bool]
// CHECK:STDOUT: }
// CHECK:STDOUT: %or_val: ref bool = bind_name or_val, %or_val.var
// CHECK:STDOUT: }
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F(%b.param: bool) -> type {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %b.ref: bool = name_ref b, %b
// CHECK:STDOUT: %b.ref: bool = name_ref b, <unexpected>.inst27.loc5_6
// CHECK:STDOUT: if %b.ref br !if.expr.then else br !if.expr.else
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then:
@@ -167,19 +92,60 @@ var or_val: bool = true or true;
// CHECK:STDOUT: !if.expr.else:
// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete = constants.%int_64]
// CHECK:STDOUT: %float.make_type: init type = call constants.%Float(%int_64) [concrete = f64]
// CHECK:STDOUT: %.loc13_24.1: type = value_of_initializer %float.make_type [concrete = f64]
// CHECK:STDOUT: %.loc13_24.2: type = converted %float.make_type, %.loc13_24.1 [concrete = f64]
// CHECK:STDOUT: br !if.expr.result(%.loc13_24.2)
// CHECK:STDOUT: %.loc6_24.1: type = value_of_initializer %float.make_type [concrete = f64]
// CHECK:STDOUT: %.loc6_24.2: type = converted %float.make_type, %.loc6_24.1 [concrete = f64]
// CHECK:STDOUT: br !if.expr.result(%.loc6_24.2)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.result:
// CHECK:STDOUT: %.loc13_10: type = block_arg !if.expr.result
// CHECK:STDOUT: return %.loc13_10
// CHECK:STDOUT: %.loc6_10: type = block_arg !if.expr.result
// CHECK:STDOUT: return %.loc6_10
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: --- fail_and_val.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_or.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete]
// CHECK:STDOUT: %Float.type: type = fn_type @Float [concrete]
// CHECK:STDOUT: %Float: %Float.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F(%b.param: bool) -> type {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %true: bool = bool_literal true [concrete = constants.%true]
// CHECK:STDOUT: %false: bool = bool_literal false [concrete = constants.%false]
// CHECK:STDOUT: if %true br !and.rhs else br !and.result(%false)
// CHECK:STDOUT: %b.ref: bool = name_ref b, <unexpected>.inst27.loc5_6
// CHECK:STDOUT: if %b.ref br !if.expr.then else br !if.expr.else
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.then:
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: br !if.expr.result(%i32)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.else:
// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete = constants.%int_64]
// CHECK:STDOUT: %float.make_type: init type = call constants.%Float(%int_64) [concrete = f64]
// CHECK:STDOUT: %.loc6_24.1: type = value_of_initializer %float.make_type [concrete = f64]
// CHECK:STDOUT: %.loc6_24.2: type = converted %float.make_type, %.loc6_24.1 [concrete = f64]
// CHECK:STDOUT: br !if.expr.result(%.loc6_24.2)
// CHECK:STDOUT:
// CHECK:STDOUT: !if.expr.result:
// CHECK:STDOUT: %.loc6_10: type = block_arg !if.expr.result
// CHECK:STDOUT: return %.loc6_10
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_or_val.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
@@ -8,143 +8,95 @@
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/var/fail_todo_control_flow_init.carbon
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+16]]:13: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_if_true.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_if_true.carbon:[[@LINE+12]]:13: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var x: () = if true then () else ();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+12]]:21: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_if_true.carbon:[[@LINE+8]]:21: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var x: () = if true then () else ();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+8]]:13: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_if_true.carbon:[[@LINE+4]]:13: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var x: () = if true then () else ();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+4]]:13: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var x: () = if true then () else ();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
var x: () = if true then () else ();
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+16]]:14: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_if_false.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_if_false.carbon:[[@LINE+12]]:14: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var x2: () = if false then () else ();
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+12]]:23: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_if_false.carbon:[[@LINE+8]]:23: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var x2: () = if false then () else ();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+8]]:14: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_if_false.carbon:[[@LINE+4]]:14: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var x2: () = if false then () else ();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+4]]:14: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var x2: () = if false then () else ();
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
var x2: () = if false then () else ();
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+12]]:15: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_true_or_false.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_true_or_false.carbon:[[@LINE+8]]:15: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var y: bool = true or false;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+8]]:15: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var y: bool = true or false;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+4]]:15: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_true_or_false.carbon:[[@LINE+4]]:15: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var y: bool = true or false;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
var y: bool = true or false;
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+12]]:16: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// --- fail_false_or_true.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_false_or_true.carbon:[[@LINE+8]]:16: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var y2: bool = false or true;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+8]]:16: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var y2: bool = false or true;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_todo_control_flow_init.carbon:[[@LINE+4]]:16: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: fail_false_or_true.carbon:[[@LINE+4]]:16: error: semantics TODO: `Control flow expressions are currently only supported inside functions.` [SemanticsTodo]
// CHECK:STDERR: var y2: bool = false or true;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
var y2: bool = false or true;
// CHECK:STDOUT: --- fail_todo_control_flow_init.carbon
// CHECK:STDOUT: --- fail_if_true.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %true: bool = bool_literal true [concrete]
// CHECK:STDOUT: %Bool.type: type = fn_type @Bool [concrete]
// CHECK:STDOUT: %Bool: %Bool.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
// CHECK:STDOUT: .Bool = %Core.Bool
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_if_false.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .Core = imports.%Core
// CHECK:STDOUT: .x = %x
// CHECK:STDOUT: .x2 = %x2
// CHECK:STDOUT: .y = %y
// CHECK:STDOUT: .y2 = %y2
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %x.patt: %empty_tuple.type = binding_pattern x
// CHECK:STDOUT: %.loc27_1: %empty_tuple.type = var_pattern %x.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %x.var: ref %empty_tuple.type = var x
// CHECK:STDOUT: %.loc27_9.1: type = splice_block %.loc27_9.3 [concrete = constants.%empty_tuple.type] {
// CHECK:STDOUT: %.loc27_9.2: %empty_tuple.type = tuple_literal ()
// CHECK:STDOUT: %.loc27_9.3: type = converted %.loc27_9.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x: ref %empty_tuple.type = bind_name x, %x.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %x2.patt: %empty_tuple.type = binding_pattern x2
// CHECK:STDOUT: %.loc45_1: %empty_tuple.type = var_pattern %x2.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %x2.var: ref %empty_tuple.type = var x2
// CHECK:STDOUT: %.loc45_10.1: type = splice_block %.loc45_10.3 [concrete = constants.%empty_tuple.type] {
// CHECK:STDOUT: %.loc45_10.2: %empty_tuple.type = tuple_literal ()
// CHECK:STDOUT: %.loc45_10.3: type = converted %.loc45_10.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x2: ref %empty_tuple.type = bind_name x2, %x2.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %y.patt: bool = binding_pattern y
// CHECK:STDOUT: %.loc59_1: bool = var_pattern %y.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %y.var: ref bool = var y
// CHECK:STDOUT: %.loc59_8.1: type = splice_block %.loc59_8.3 [concrete = bool] {
// CHECK:STDOUT: %bool.make_type.loc59: init type = call constants.%Bool() [concrete = bool]
// CHECK:STDOUT: %.loc59_8.2: type = value_of_initializer %bool.make_type.loc59 [concrete = bool]
// CHECK:STDOUT: %.loc59_8.3: type = converted %bool.make_type.loc59, %.loc59_8.2 [concrete = bool]
// CHECK:STDOUT: }
// CHECK:STDOUT: %y: ref bool = bind_name y, %y.var
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %y2.patt: bool = binding_pattern y2
// CHECK:STDOUT: %.loc73_1: bool = var_pattern %y2.patt
// CHECK:STDOUT: }
// CHECK:STDOUT: %y2.var: ref bool = var y2
// CHECK:STDOUT: %.loc73_9.1: type = splice_block %.loc73_9.3 [concrete = bool] {
// CHECK:STDOUT: %bool.make_type.loc73: init type = call constants.%Bool() [concrete = bool]
// CHECK:STDOUT: %.loc73_9.2: type = value_of_initializer %bool.make_type.loc73 [concrete = bool]
// CHECK:STDOUT: %.loc73_9.3: type = converted %bool.make_type.loc73, %.loc73_9.2 [concrete = bool]
// CHECK:STDOUT: }
// CHECK:STDOUT: %y2: ref bool = bind_name y2, %y2.var
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_true_or_false.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %true: bool = bool_literal true [concrete = constants.%true]
// CHECK:STDOUT: if %true br !if.expr.then else br !if.expr.else
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_false_or_true.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT: