Require names where we expect binding patterns (#2782)

This also clusters the various `var` tests. This tests similar patterns for a few syntaxes, but `fn f(x: i32, i32) {}` and local variables `var (x: i32, i32);` and `var i32;` were the crashers I found.

In `fn`, the `x: i32,` is helpful to convince the parser that this is valid syntax.

Fixes #2778
This commit is contained in:
Jon Ross-Perkins
2023-04-20 10:58:03 -07:00
committed by GitHub
parent ac10b36595
commit c9f0ef9e2c
39 changed files with 188 additions and 75 deletions
+68 -51
View File
@@ -4128,9 +4128,9 @@ auto TypeChecker::TypeCheckWhereClause(Nonnull<WhereClause*> clause,
}
auto TypeChecker::TypeCheckPattern(
Nonnull<Pattern*> p, std::optional<Nonnull<const Value*>> expected,
ImplScope& impl_scope, ExpressionCategory enclosing_expression_category)
-> ErrorOr<Success> {
Nonnull<Pattern*> p, bool require_irrefutable,
std::optional<Nonnull<const Value*>> expected, ImplScope& impl_scope,
ExpressionCategory enclosing_expression_category) -> ErrorOr<Success> {
if (trace_stream_->is_enabled()) {
*trace_stream_ << "checking " << p->kind() << " " << *p;
if (expected) {
@@ -4138,6 +4138,17 @@ auto TypeChecker::TypeCheckPattern(
}
*trace_stream_ << "\n";
}
if (require_irrefutable) {
switch (p->kind()) {
case PatternKind::AutoPattern:
case PatternKind::ExpressionPattern:
return ProgramError(p->source_loc())
<< "An irrefutable pattern is required, but `" << *p
<< "` is refutable.";
default:
break;
}
}
switch (p->kind()) {
case PatternKind::AutoPattern: {
p->set_static_type(arena_->New<TypeType>());
@@ -4152,9 +4163,9 @@ auto TypeChecker::TypeCheckPattern(
return ProgramError(binding.type().source_loc())
<< "the type of a binding pattern cannot contain bindings";
}
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&binding.type(), expected,
impl_scope,
enclosing_expression_category));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&binding.type(), /*require_irrefutable=*/false, expected, impl_scope,
enclosing_expression_category));
Nonnull<const Value*> type = &binding.type().value();
// Convert to a type.
// TODO: Convert the pattern before interpreting it rather than doing
@@ -4232,8 +4243,8 @@ auto TypeChecker::TypeCheckPattern(
if (expected) {
expected_field_type = cast<TupleType>(**expected).elements()[i];
}
CARBON_RETURN_IF_ERROR(TypeCheckPattern(field, expected_field_type,
impl_scope,
CARBON_RETURN_IF_ERROR(TypeCheckPattern(field, require_irrefutable,
expected_field_type, impl_scope,
enclosing_expression_category));
if (trace_stream_->is_enabled()) {
*trace_stream_ << "finished checking tuple pattern field " << *field
@@ -4277,9 +4288,9 @@ auto TypeChecker::TypeCheckPattern(
Nonnull<const Value*> parameter_type,
Substitute(choice_type.bindings(),
*(*signature)->parameters_static_type()));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&alternative.arguments(),
parameter_type, impl_scope,
enclosing_expression_category));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&alternative.arguments(), require_irrefutable, parameter_type,
impl_scope, enclosing_expression_category));
alternative.set_static_type(&choice_type);
alternative.set_value(arena_->New<AlternativeValue>(
&choice_type, *signature,
@@ -4299,9 +4310,9 @@ auto TypeChecker::TypeCheckPattern(
case PatternKind::VarPattern: {
auto& var_pattern = cast<VarPattern>(*p);
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(&var_pattern.pattern(), expected, impl_scope,
var_pattern.expression_category()));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&var_pattern.pattern(), require_irrefutable, expected, impl_scope,
var_pattern.expression_category()));
var_pattern.set_static_type(&var_pattern.pattern().static_type());
var_pattern.set_value(&var_pattern.pattern().value());
return Success();
@@ -4312,9 +4323,9 @@ auto TypeChecker::TypeCheckPattern(
if (expected) {
expected_ptr = arena_->New<PointerType>(expected.value());
}
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&addr_pattern.binding(),
expected_ptr, impl_scope,
enclosing_expression_category));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&addr_pattern.binding(), require_irrefutable, expected_ptr,
impl_scope, enclosing_expression_category));
if (const auto* inner_binding_type =
dyn_cast<PointerType>(&addr_pattern.binding().static_type())) {
@@ -4432,9 +4443,10 @@ auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
ImplScope clause_scope(&impl_scope);
// TODO: Should user-defined conversions be permitted in `match`
// statements? When would we run them? See #1283.
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&clause.pattern(), &match.expression().static_type(), clause_scope,
ExpressionCategory::Value));
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(&clause.pattern(), /*require_irrefutable=*/false,
&match.expression().static_type(), clause_scope,
ExpressionCategory::Value));
if (expected_type.has_value()) {
// TODO: For now, we require all patterns to have the same type. If
// that's not the same type as the scrutinee, we will convert the
@@ -4485,10 +4497,10 @@ auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
const Value& rhs = for_stmt.loop_target().static_type();
if (rhs.kind() == Value::Kind::StaticArrayType) {
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(&for_stmt.variable_declaration(),
&cast<StaticArrayType>(rhs).element_type(),
inner_impl_scope, ExpressionCategory::Reference));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&for_stmt.variable_declaration(), /*require_irrefutable=*/true,
&cast<StaticArrayType>(rhs).element_type(), inner_impl_scope,
ExpressionCategory::Reference));
CARBON_RETURN_IF_ERROR(ExpectExactType(
for_stmt.source_loc(), "`for` pattern",
&cast<StaticArrayType>(rhs).element_type(),
@@ -4532,8 +4544,9 @@ auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
var.init().source_loc(), &var.init().static_type()));
init_type = &var.init().static_type();
}
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&var.pattern(), init_type, var_scope, var.expression_category()));
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(&var.pattern(), /*require_irrefutable=*/true,
init_type, var_scope, var.expression_category()));
CARBON_RETURN_IF_ERROR(ExpectCompleteType(
var.source_loc(), "type of variable", &var.pattern().static_type()));
CARBON_RETURN_IF_ERROR(
@@ -4739,23 +4752,24 @@ auto TypeChecker::DeclareCallableDeclaration(Nonnull<CallableDeclaration*> f,
std::vector<Nonnull<const ImplBinding*>> impl_bindings;
// Bring the deduced parameters into scope.
for (Nonnull<GenericBinding*> deduced : f->deduced_parameters()) {
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
deduced, std::nullopt, function_scope, ExpressionCategory::Value));
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(deduced, /*require_irrefutable=*/true, std::nullopt,
function_scope, ExpressionCategory::Value));
CollectAndNumberGenericBindingsInPattern(deduced, all_bindings);
CollectImplBindingsInPattern(deduced, impl_bindings);
}
// Type check the receiver pattern.
if (f->is_method()) {
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&f->self_pattern(), std::nullopt,
function_scope,
ExpressionCategory::Value));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&f->self_pattern(), /*require_irrefutable=*/true, std::nullopt,
function_scope, ExpressionCategory::Value));
CollectAndNumberGenericBindingsInPattern(&f->self_pattern(), all_bindings);
CollectImplBindingsInPattern(&f->self_pattern(), impl_bindings);
}
// Type check the parameter pattern.
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&f->param_pattern(), std::nullopt,
function_scope,
ExpressionCategory::Value));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&f->param_pattern(), /*require_irrefutable=*/true, std::nullopt,
function_scope, ExpressionCategory::Value));
CollectImplBindingsInPattern(&f->param_pattern(), impl_bindings);
// All bindings we've seen so far in this scope are our deduced bindings.
@@ -4915,8 +4929,9 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
std::vector<Nonnull<const GenericBinding*>> bindings = scope_info.bindings;
if (class_decl->type_params().has_value()) {
Nonnull<TuplePattern*> type_params = *class_decl->type_params();
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
type_params, std::nullopt, class_scope, ExpressionCategory::Value));
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(type_params, /*require_irrefutable=*/true,
std::nullopt, class_scope, ExpressionCategory::Value));
CollectAndNumberGenericBindingsInPattern(type_params, bindings);
if (trace_stream_->is_enabled()) {
*trace_stream_ << class_scope;
@@ -5084,9 +5099,9 @@ auto TypeChecker::DeclareMixinDeclaration(Nonnull<MixinDeclaration*> mixin_decl,
ImplScope mixin_scope(scope_info.innermost_scope);
if (mixin_decl->params().has_value()) {
CARBON_RETURN_IF_ERROR(TypeCheckPattern(*mixin_decl->params(), std::nullopt,
mixin_scope,
ExpressionCategory::Value));
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(*mixin_decl->params(), /*require_irrefutable=*/true,
std::nullopt, mixin_scope, ExpressionCategory::Value));
if (trace_stream_->is_enabled()) {
*trace_stream_ << mixin_scope;
}
@@ -5104,9 +5119,9 @@ auto TypeChecker::DeclareMixinDeclaration(Nonnull<MixinDeclaration*> mixin_decl,
}
// Process the Self parameter.
CARBON_RETURN_IF_ERROR(TypeCheckPattern(mixin_decl->self(), std::nullopt,
mixin_scope,
ExpressionCategory::Value));
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(mixin_decl->self(), /*require_irrefutable=*/true,
std::nullopt, mixin_scope, ExpressionCategory::Value));
ScopeInfo mixin_scope_info = ScopeInfo::ForNonClassScope(&mixin_scope);
for (Nonnull<Declaration*> m : mixin_decl->members()) {
@@ -5214,9 +5229,9 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
// Type-check the parameters and find the set of bindings that are in scope.
std::vector<Nonnull<const GenericBinding*>> bindings = scope_info.bindings;
if (constraint_decl->params().has_value()) {
CARBON_RETURN_IF_ERROR(TypeCheckPattern(*constraint_decl->params(),
std::nullopt, constraint_scope,
ExpressionCategory::Value));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
*constraint_decl->params(), /*require_irrefutable=*/true, std::nullopt,
constraint_scope, ExpressionCategory::Value));
if (trace_stream_->is_enabled()) {
*trace_stream_ << constraint_scope;
}
@@ -5589,8 +5604,9 @@ auto TypeChecker::DeclareImplDeclaration(Nonnull<ImplDeclaration*> impl_decl,
// Bring the deduced parameters into scope.
for (Nonnull<GenericBinding*> deduced : impl_decl->deduced_parameters()) {
generic_bindings.push_back(deduced);
CARBON_RETURN_IF_ERROR(TypeCheckPattern(deduced, std::nullopt, impl_scope,
ExpressionCategory::Value));
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(deduced, /*require_irrefutable=*/true, std::nullopt,
impl_scope, ExpressionCategory::Value));
CollectImplBindingsInPattern(deduced, impl_bindings);
}
impl_decl->set_impl_bindings(impl_bindings);
@@ -5784,7 +5800,8 @@ auto TypeChecker::DeclareChoiceDeclaration(Nonnull<ChoiceDeclaration*> choice,
if (choice->type_params().has_value()) {
Nonnull<TuplePattern*> type_params = *choice->type_params();
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
type_params, std::nullopt, choice_scope, ExpressionCategory::Value));
type_params, /*require_irrefutable=*/false, std::nullopt, choice_scope,
ExpressionCategory::Value));
CollectAndNumberGenericBindingsInPattern(type_params, bindings);
if (trace_stream_->is_enabled()) {
*trace_stream_ << choice_scope;
@@ -6107,9 +6124,9 @@ auto TypeChecker::DeclareDeclaration(Nonnull<Declaration*> d,
return ProgramError(var.binding().type().source_loc())
<< "Expected expression for variable type";
}
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&var.binding(), std::nullopt,
*scope_info.innermost_scope,
var.expression_category()));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&var.binding(), /*require_irrefutable=*/true, std::nullopt,
*scope_info.innermost_scope, var.expression_category()));
CARBON_RETURN_IF_ERROR(ExpectCompleteType(
var.source_loc(), "type of variable", &var.binding().static_type()));
CARBON_RETURN_IF_ERROR(
+1 -1
View File
@@ -196,7 +196,7 @@ class TypeChecker {
// Implicit conversions from `expected` to the pattern's type are permitted.
//
// `impl_scope` is extended with all implementations implied by the pattern.
auto TypeCheckPattern(Nonnull<Pattern*> p,
auto TypeCheckPattern(Nonnull<Pattern*> p, bool require_irrefutable,
std::optional<Nonnull<const Value*>> expected,
ImplScope& impl_scope,
ExpressionCategory enclosing_expression_category)
@@ -0,0 +1,16 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// RUN: %{not} %{explorer-run}
// RUN: %{not} %{explorer-run-trace}
package ExplorerTest api;
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_parameter_type_only.carbon:[[@LINE+1]]: An irrefutable pattern is required, but `i32` is refutable.
fn f(x: i32, i32) {}
fn Main() -> i32 {
return 0;
}
@@ -0,0 +1,18 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// RUN: %{not} %{explorer-run}
// RUN: %{not} %{explorer-run-trace}
package ExplorerTest api;
class C {}
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/generic_function/fail_type_only.carbon:[[@LINE+1]]: syntax error, unexpected RIGHT_SQUARE_BRACKET, expecting COLON
fn f[x:! i32, addr C]() {}
fn Main() -> i32 {
return 0;
}
@@ -10,7 +10,7 @@ package ExplorerTest api;
// Test type checking of global variable. Error expected.
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/global_variable/fail_init_type_mismatch.carbon:[[@LINE+1]]: type error in initializer of variable: 'bool' is not implicitly convertible to 'i32'
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/global/fail_init_type_mismatch.carbon:[[@LINE+1]]: type error in initializer of variable: 'bool' is not implicitly convertible to 'i32'
var flag: i32 = true;
fn Main() -> i32 {
@@ -11,7 +11,7 @@ package ExplorerTest api;
abstract class B {
}
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/global_variable/fail_instantiate_global_abstract.carbon:[[@LINE+1]]: Cannot instantiate abstract class B
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/global/fail_instantiate_global_abstract.carbon:[[@LINE+1]]: Cannot instantiate abstract class B
var b: B = {};
fn Main() -> i32 {
@@ -8,7 +8,7 @@
package ExplorerTest api;
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_var_expression.carbon:[[@LINE+1]]: Expected expression for variable type
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/global/fail_invalid_var_expression.carbon:[[@LINE+1]]: Expected expression for variable type
var a: auto;
fn Main() -> i32 { return 0; }
@@ -13,7 +13,7 @@ var n: i32 = 0;
fn F() -> type {
// TODO: This isn't a very good description of the problem, which is that
// compile-time evaluation doesn't have a mutable `n` value available.
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/global_variable/fail_modify_in_constant_expr.carbon:[[@LINE+1]]: could not find `n: i32`
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/global/fail_modify_in_constant_expr.carbon:[[@LINE+1]]: could not find `n: i32`
n = 1;
return i32;
}
@@ -9,7 +9,7 @@
package ExplorerTest api;
// Error: global variable may not be named with keyword `Self`.
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/global_variable/fail_named_self.carbon:[[@LINE+1]]: syntax error, unexpected SELF, expecting identifier
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/var/global/fail_named_self.carbon:[[@LINE+1]]: syntax error, unexpected SELF, expecting identifier
var Self: i32 = 0;
fn Main() -> i32 {
+19
View File
@@ -0,0 +1,19 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// RUN: %{not} %{explorer-run}
// RUN: %{not} %{explorer-run-trace}
package ExplorerTest api;
// If support for this is added, it'll be necessary to verify that either the
// implementation is shared with locals or that tests are copied over for edge
// cases.
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/var/global/fail_nested_binding.carbon:[[@LINE+1]]: syntax error, unexpected LEFT_PARENTHESIS, expecting identifier
var (x: i32,);
fn Main() -> i32 {
return 0;
}
+16
View File
@@ -0,0 +1,16 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// RUN: %{not} %{explorer-run}
// RUN: %{not} %{explorer-run-trace}
package ExplorerTest api;
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/var/global/fail_type_only.carbon:[[@LINE+1]]: syntax error, unexpected sized_type_literal, expecting identifier
var i32;
fn Main() -> i32 {
return 0;
}
@@ -9,8 +9,7 @@
package ExplorerTest api;
fn Main() -> i32 {
// error
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_missing_var.carbon:[[@LINE+1]]: syntax error, unexpected COLON
x : i32;
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/var/local/fail_missing_intro.carbon:[[@LINE+1]]: syntax error, unexpected COLON
x: i32;
return 1;
}
@@ -12,7 +12,7 @@ fn Main() -> i32 {
// Error: can't use keyword `Self` as the name of a variable.
// TODO: Current error message is unclear, better would be to say
// something like: unexpected `Self`, expecting identifier
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_var_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting EQUAL or SEMICOLON
var Self : i32 = 0;
return Self;
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/var/local/fail_named_self_type.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting EQUAL or SEMICOLON
var Self: i32 = 0;
return 0;
}
@@ -9,7 +9,7 @@
package ExplorerTest api;
fn Main() -> i32 {
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_nested_binding.carbon:[[@LINE+1]]: the type of a binding pattern cannot contain bindings
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/local/fail_nested_binding_in_type.carbon:[[@LINE+1]]: the type of a binding pattern cannot contain bindings
var x: (T: type) = 1;
return 1;
}
@@ -0,0 +1,15 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// RUN: %{not} %{explorer-run}
// RUN: %{not} %{explorer-run-trace}
package ExplorerTest api;
fn Main() -> i32 {
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/local/fail_nested_type_only.carbon:[[@LINE+1]]: An irrefutable pattern is required, but `i32` is refutable.
var (x: i32, i32);
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// RUN: %{not} %{explorer-run}
// RUN: %{not} %{explorer-run-trace}
package ExplorerTest api;
fn Main() -> i32 {
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/local/fail_type_only.carbon:[[@LINE+1]]: An irrefutable pattern is required, but `i32` is refutable.
var i32;
return 0;
}
@@ -8,10 +8,9 @@
package ExplorerTest api;
fn Main () -> i32
{
fn Main() -> i32 {
// 42 cannot be used as the type of a variable.
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_var_type.carbon:[[@LINE+1]]: type error in type of name binding: 'i32' is not implicitly convertible to 'type'
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/local/fail_value_as_type.carbon:[[@LINE+1]]: type error in type of name binding: 'i32' is not implicitly convertible to 'type'
var x: 42 = 0;
return x;
}
@@ -9,8 +9,7 @@
package ExplorerTest api;
fn Main () -> i32
{
fn Main() -> i32 {
var x: i32 = 0;
return x;
}
@@ -11,7 +11,7 @@ package ExplorerTest api;
fn AddInt(a: i32, b: i32) -> i32 {
returned var ret: i32 = a + b;
if (a == b) {
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/returned_var/fail_duplicate_return_var.carbon:[[@LINE+1]]: Duplicate definition of returned var also found at {{.*}}/explorer/testdata/returned_var/fail_duplicate_return_var.carbon:[[@LINE-2]]
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/returned/fail_duplicate_return_var.carbon:[[@LINE+1]]: Duplicate definition of returned var also found at {{.*}}/explorer/testdata/var/returned/fail_duplicate_return_var.carbon:[[@LINE-2]]
returned var ret2: i32 = a + b;
}
return var;
@@ -10,7 +10,7 @@ package ExplorerTest api;
fn AddInt(a: i32, b: i32) -> i32 {
var ret: i32 = a + b;
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/returned_var/fail_missing_declaration.carbon:[[@LINE+1]]: `return var` is not allowed without a returned var defined in scope.
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/returned/fail_missing_declaration.carbon:[[@LINE+1]]: `return var` is not allowed without a returned var defined in scope.
return var;
}
@@ -10,7 +10,7 @@ package ExplorerTest api;
fn AddInt(a: i32, b: i32) -> i32 {
returned var ret: i32 = a + b;
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/returned_var/fail_missing_return.carbon:[[@LINE+1]]: `return <expression>` is not allowed with a returned var defined in scope: {{.*}}/explorer/testdata/returned_var/fail_missing_return.carbon:[[@LINE-1]]
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/returned/fail_missing_return.carbon:[[@LINE+1]]: `return <expression>` is not allowed with a returned var defined in scope: {{.*}}/explorer/testdata/var/returned/fail_missing_return.carbon:[[@LINE-1]]
return ret;
}
@@ -10,7 +10,7 @@ package ExplorerTest api;
fn Foo() {
returned var x: () = ();
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/returned_var/fail_returned_var_mismatch_signature.carbon:[[@LINE+1]]: return var; should not provide a return value, to match the function's signature.
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/returned/fail_returned_var_mismatch_signature.carbon:[[@LINE+1]]: return var; should not provide a return value, to match the function's signature.
return var;
}
@@ -15,7 +15,7 @@ fn Foo(a: i32, b: i32) -> auto {
return var;
}
ret = a - b;
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/returned_var/fail_returned_var_multi_auto.carbon:[[@LINE+1]]: Only one return is allowed in a function with an `auto` return type.
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/returned/fail_returned_var_multi_auto.carbon:[[@LINE+1]]: Only one return is allowed in a function with an `auto` return type.
return var;
}
@@ -9,7 +9,7 @@
package ExplorerTest api;
fn AddInt(a: i32, b: i32) -> i32 {
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/returned_var/fail_returned_var_type_mismatch.carbon:[[@LINE+1]]: type of returned var `bool` does not match return type `i32`
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/var/returned/fail_returned_var_type_mismatch.carbon:[[@LINE+1]]: type of returned var `bool` does not match return type `i32`
returned var ret: bool = true;
return var;
}