mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Add support for return; (#678)
This creates a ReturnExpression. A separate change should enforce that an implicit return of `()` is only allowed in functions that have an implicit return type of `()`, and I think the structure taken here should ease that.
This commit is contained in:
@@ -100,12 +100,17 @@ auto Expression::MakeContinuationTypeLiteral(int line_num)
|
||||
return type;
|
||||
}
|
||||
|
||||
auto Expression::MakeFunctionTypeLiteral(int line_num, const Expression* param,
|
||||
const Expression* ret)
|
||||
auto Expression::MakeFunctionTypeLiteral(int line_num,
|
||||
const Expression* parameter,
|
||||
const Expression* return_type,
|
||||
bool is_omitted_return_type)
|
||||
-> const Expression* {
|
||||
auto* t = global_arena->New<Expression>();
|
||||
t->line_num = line_num;
|
||||
t->value = FunctionTypeLiteral({.parameter = param, .return_type = ret});
|
||||
t->value =
|
||||
FunctionTypeLiteral({.parameter = parameter,
|
||||
.return_type = return_type,
|
||||
.is_omitted_return_type = is_omitted_return_type});
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ struct FunctionTypeLiteral {
|
||||
static constexpr ExpressionKind Kind = ExpressionKind::FunctionTypeLiteral;
|
||||
const Expression* parameter;
|
||||
const Expression* return_type;
|
||||
bool is_omitted_return_type;
|
||||
};
|
||||
|
||||
struct BoolTypeLiteral {
|
||||
@@ -162,8 +163,9 @@ struct Expression {
|
||||
static auto MakeTypeTypeLiteral(int line_num) -> const Expression*;
|
||||
static auto MakeIntTypeLiteral(int line_num) -> const Expression*;
|
||||
static auto MakeBoolTypeLiteral(int line_num) -> const Expression*;
|
||||
static auto MakeFunctionTypeLiteral(int line_num, const Expression* param,
|
||||
const Expression* ret)
|
||||
static auto MakeFunctionTypeLiteral(int line_num, const Expression* parameter,
|
||||
const Expression* return_type,
|
||||
bool is_omitted_return_type)
|
||||
-> const Expression*;
|
||||
static auto MakeContinuationTypeLiteral(int line_num) -> const Expression*;
|
||||
|
||||
|
||||
@@ -21,7 +21,10 @@ void FunctionDefinition::PrintDepth(int depth, llvm::raw_ostream& out) const {
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
out << *param_pattern << " -> " << *return_type;
|
||||
out << *param_pattern;
|
||||
if (!is_omitted_return_type) {
|
||||
out << " -> " << *return_type;
|
||||
}
|
||||
if (body) {
|
||||
out << " {\n";
|
||||
body->PrintDepth(depth, out);
|
||||
|
||||
@@ -25,12 +25,14 @@ struct FunctionDefinition {
|
||||
FunctionDefinition(int line_num, std::string name,
|
||||
std::vector<GenericBinding> deduced_params,
|
||||
const TuplePattern* param_pattern,
|
||||
const Pattern* return_type, const Statement* body)
|
||||
const Pattern* return_type, bool is_omitted_return_type,
|
||||
const Statement* body)
|
||||
: line_num(line_num),
|
||||
name(std::move(name)),
|
||||
deduced_parameters(deduced_params),
|
||||
param_pattern(param_pattern),
|
||||
return_type(return_type),
|
||||
is_omitted_return_type(is_omitted_return_type),
|
||||
body(body) {}
|
||||
|
||||
void Print(llvm::raw_ostream& out) const { PrintDepth(-1, out); }
|
||||
@@ -42,6 +44,7 @@ struct FunctionDefinition {
|
||||
std::vector<GenericBinding> deduced_parameters;
|
||||
const TuplePattern* param_pattern;
|
||||
const Pattern* return_type;
|
||||
bool is_omitted_return_type;
|
||||
const Statement* body;
|
||||
};
|
||||
|
||||
|
||||
@@ -117,11 +117,15 @@ auto Statement::MakeContinue(int line_num) -> const Statement* {
|
||||
return s;
|
||||
}
|
||||
|
||||
auto Statement::MakeReturn(int line_num, const Expression* e)
|
||||
-> const Statement* {
|
||||
auto Statement::MakeReturn(int line_num, const Expression* exp,
|
||||
bool is_omitted_exp) -> const Statement* {
|
||||
auto* s = global_arena->New<Statement>();
|
||||
s->line_num = line_num;
|
||||
s->value = Return({.exp = e});
|
||||
if (exp == nullptr) {
|
||||
CHECK(is_omitted_exp);
|
||||
exp = Expression::MakeTupleLiteral(line_num, {});
|
||||
}
|
||||
s->value = Return({.exp = exp, .is_omitted_exp = is_omitted_exp});
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -230,7 +234,11 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const {
|
||||
}
|
||||
break;
|
||||
case StatementKind::Return:
|
||||
out << "return " << *GetReturn().exp << ";";
|
||||
if (GetReturn().is_omitted_exp) {
|
||||
out << "return;";
|
||||
} else {
|
||||
out << "return " << *GetReturn().exp << ";";
|
||||
}
|
||||
break;
|
||||
case StatementKind::Sequence:
|
||||
GetSequence().stmt->PrintDepth(depth, out);
|
||||
|
||||
@@ -60,6 +60,7 @@ struct If {
|
||||
struct Return {
|
||||
static constexpr StatementKind Kind = StatementKind::Return;
|
||||
const Expression* exp;
|
||||
bool is_omitted_exp;
|
||||
};
|
||||
|
||||
struct Sequence {
|
||||
@@ -120,7 +121,8 @@ struct Statement {
|
||||
static auto MakeIf(int line_num, const Expression* cond,
|
||||
const Statement* then_stmt, const Statement* else_stmt)
|
||||
-> const Statement*;
|
||||
static auto MakeReturn(int line_num, const Expression* e) -> const Statement*;
|
||||
static auto MakeReturn(int line_num, const Expression* exp,
|
||||
bool is_omitted_exp) -> const Statement*;
|
||||
static auto MakeSequence(int line_num, const Statement* s1,
|
||||
const Statement* s2) -> const Statement*;
|
||||
static auto MakeBlock(int line_num, const Statement* s) -> const Statement*;
|
||||
|
||||
@@ -1093,8 +1093,9 @@ void StepStmt() {
|
||||
Stack<Scope*> scopes;
|
||||
scopes.Push(scope);
|
||||
Stack<Action*> todo;
|
||||
todo.Push(Action::MakeStatementAction(Statement::MakeReturn(
|
||||
stmt->line_num, Expression::MakeTupleLiteral(stmt->line_num, {}))));
|
||||
todo.Push(Action::MakeStatementAction(
|
||||
Statement::MakeReturn(stmt->line_num, nullptr,
|
||||
/*is_omitted_exp=*/true)));
|
||||
todo.Push(Action::MakeStatementAction(stmt->GetContinuation().body));
|
||||
Frame* continuation_frame =
|
||||
global_arena->New<Frame>("__continuation", scopes, todo);
|
||||
|
||||
@@ -56,7 +56,8 @@ auto ReifyType(const Value* t, int line_num) -> const Expression* {
|
||||
case ValKind::FunctionType:
|
||||
return Expression::MakeFunctionTypeLiteral(
|
||||
0, ReifyType(t->GetFunctionType().param, line_num),
|
||||
ReifyType(t->GetFunctionType().ret, line_num));
|
||||
ReifyType(t->GetFunctionType().ret, line_num),
|
||||
/*is_omitted_return_type=*/false);
|
||||
case ValKind::TupleValue: {
|
||||
std::vector<FieldInitializer> args;
|
||||
for (const TupleElement& field : t->GetTupleValue().elements) {
|
||||
@@ -454,7 +455,8 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values)
|
||||
auto pt = InterpExp(values, e->GetFunctionTypeLiteral().parameter);
|
||||
auto rt = InterpExp(values, e->GetFunctionTypeLiteral().return_type);
|
||||
auto new_e = Expression::MakeFunctionTypeLiteral(
|
||||
e->line_num, ReifyType(pt, e->line_num), ReifyType(rt, e->line_num));
|
||||
e->line_num, ReifyType(pt, e->line_num), ReifyType(rt, e->line_num),
|
||||
/*is_omitted_return_type=*/false);
|
||||
return TCExpression(new_e, Value::MakeTypeType(), types);
|
||||
}
|
||||
case ExpressionKind::IntTypeLiteral:
|
||||
@@ -710,7 +712,9 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values,
|
||||
} else {
|
||||
ExpectType(s->line_num, "return", ret_type, res.type);
|
||||
}
|
||||
return TCStatement(Statement::MakeReturn(s->line_num, res.exp), types);
|
||||
return TCStatement(Statement::MakeReturn(s->line_num, res.exp,
|
||||
s->GetReturn().is_omitted_exp),
|
||||
types);
|
||||
}
|
||||
case StatementKind::Continuation: {
|
||||
TCStatement body_result =
|
||||
@@ -742,8 +746,8 @@ auto CheckOrEnsureReturn(const Statement* stmt, bool void_return, int line_num)
|
||||
-> const Statement* {
|
||||
if (!stmt) {
|
||||
if (void_return) {
|
||||
return Statement::MakeReturn(line_num,
|
||||
Expression::MakeTupleLiteral(line_num, {}));
|
||||
return Statement::MakeReturn(line_num, nullptr,
|
||||
/*is_omitted_exp=*/true);
|
||||
} else {
|
||||
FATAL_COMPILATION_ERROR(line_num)
|
||||
<< "control-flow reaches end of non-void function without a return";
|
||||
@@ -798,8 +802,8 @@ auto CheckOrEnsureReturn(const Statement* stmt, bool void_return, int line_num)
|
||||
if (void_return) {
|
||||
return Statement::MakeSequence(
|
||||
stmt->line_num, stmt,
|
||||
Statement::MakeReturn(stmt->line_num, Expression::MakeTupleLiteral(
|
||||
stmt->line_num, {})));
|
||||
Statement::MakeReturn(line_num, nullptr,
|
||||
/*is_omitted_exp=*/true));
|
||||
} else {
|
||||
FATAL_COMPILATION_ERROR(stmt->line_num)
|
||||
<< "control-flow reaches end of non-void function without a return";
|
||||
@@ -835,7 +839,7 @@ auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, Env values)
|
||||
return global_arena->New<FunctionDefinition>(
|
||||
f->line_num, f->name, f->deduced_parameters, f->param_pattern,
|
||||
global_arena->New<ExpressionPattern>(ReifyType(return_type, f->line_num)),
|
||||
body);
|
||||
/*is_omitted_return_type=*/false, body);
|
||||
}
|
||||
|
||||
auto TypeOfFunDef(TypeEnv types, Env values, const FunctionDefinition* fun_def)
|
||||
|
||||
@@ -92,6 +92,7 @@ void yy::parser::error(const location_type&, const std::string& message) {
|
||||
%type <const Carbon::Statement*> statement
|
||||
%type <const Carbon::Statement*> if_statement
|
||||
%type <const Carbon::Statement*> optional_else
|
||||
%type <std::pair<const Carbon::Expression*, bool>> return_expression
|
||||
%type <const Carbon::Statement*> block
|
||||
%type <const Carbon::Statement*> statement_list
|
||||
%type <const Carbon::Expression*> expression
|
||||
@@ -100,7 +101,7 @@ void yy::parser::error(const location_type&, const std::string& message) {
|
||||
%type <std::vector<Carbon::GenericBinding>> deduced_param_list
|
||||
%type <const Carbon::Pattern*> pattern
|
||||
%type <const Carbon::Pattern*> non_expression_pattern
|
||||
%type <const Carbon::Expression*> return_type
|
||||
%type <std::pair<const Carbon::Expression*, bool>> return_type
|
||||
%type <const Carbon::Expression*> paren_expression
|
||||
%type <const Carbon::Expression*> tuple
|
||||
%type <std::optional<std::string>> binding_lhs
|
||||
@@ -264,7 +265,8 @@ expression:
|
||||
{ $$ = Carbon::Expression::MakePrimitiveOperatorExpression(
|
||||
yylineno, Carbon::Operator::Ptr, {$1}); }
|
||||
| FNTY tuple return_type
|
||||
{ $$ = Carbon::Expression::MakeFunctionTypeLiteral(yylineno, $2, $3); }
|
||||
{ $$ = Carbon::Expression::MakeFunctionTypeLiteral(
|
||||
yylineno, $2, $3.first, $3.second); }
|
||||
;
|
||||
designator: "." identifier { $$ = $2; }
|
||||
;
|
||||
@@ -415,8 +417,8 @@ statement:
|
||||
{ $$ = Carbon::Statement::MakeBreak(yylineno); }
|
||||
| CONTINUE ";"
|
||||
{ $$ = Carbon::Statement::MakeContinue(yylineno); }
|
||||
| RETURN expression ";"
|
||||
{ $$ = Carbon::Statement::MakeReturn(yylineno, $2); }
|
||||
| RETURN return_expression ";"
|
||||
{ $$ = Carbon::Statement::MakeReturn(yylineno, $2.first, $2.second); }
|
||||
| block
|
||||
{ $$ = $1; }
|
||||
| MATCH "(" expression ")" "{" clause_list "}"
|
||||
@@ -440,6 +442,12 @@ optional_else:
|
||||
| ELSE block
|
||||
{ $$ = $2; }
|
||||
;
|
||||
return_expression:
|
||||
// Empty
|
||||
{ $$ = {Carbon::Expression::MakeTupleLiteral(yylineno, {}), true}; }
|
||||
| expression
|
||||
{ $$ = {$1, false}; }
|
||||
;
|
||||
statement_list:
|
||||
// Empty
|
||||
{ $$ = 0; }
|
||||
@@ -452,9 +460,9 @@ block:
|
||||
;
|
||||
return_type:
|
||||
// Empty
|
||||
{ $$ = Carbon::Expression::MakeTupleLiteral(yylineno, {}); }
|
||||
{ $$ = {Carbon::Expression::MakeTupleLiteral(yylineno, {}), true}; }
|
||||
| ARROW expression %prec FNARROW
|
||||
{ $$ = $2; }
|
||||
{ $$ = {$2, false}; }
|
||||
;
|
||||
generic_binding:
|
||||
identifier ":!" expression
|
||||
@@ -486,21 +494,25 @@ function_definition:
|
||||
FN identifier deduced_params maybe_empty_tuple_pattern return_type block
|
||||
{
|
||||
$$ = Carbon::FunctionDefinition(
|
||||
yylineno, $2, $3, $4, Carbon::global_arena->New<Carbon::ExpressionPattern>($5), $6);
|
||||
yylineno, $2, $3, $4,
|
||||
Carbon::global_arena->New<Carbon::ExpressionPattern>($5.first),
|
||||
$5.second, $6);
|
||||
}
|
||||
| FN identifier deduced_params maybe_empty_tuple_pattern DBLARROW expression ";"
|
||||
{
|
||||
$$ = Carbon::FunctionDefinition(
|
||||
yylineno, $2, $3, $4,
|
||||
Carbon::global_arena->New<Carbon::AutoPattern>(yylineno),
|
||||
Carbon::Statement::MakeReturn(yylineno, $6));
|
||||
yylineno, $2, $3, $4,
|
||||
Carbon::global_arena->New<Carbon::AutoPattern>(yylineno), true,
|
||||
Carbon::Statement::MakeReturn(yylineno, $6, false));
|
||||
}
|
||||
;
|
||||
function_declaration:
|
||||
FN identifier deduced_params maybe_empty_tuple_pattern return_type ";"
|
||||
{
|
||||
$$ = Carbon::FunctionDefinition(
|
||||
yylineno, $2, $3, $4, Carbon::global_arena->New<Carbon::ExpressionPattern>($5), 0); }
|
||||
yylineno, $2, $3, $4,
|
||||
Carbon::global_arena->New<Carbon::ExpressionPattern>($5.first),
|
||||
$5.second, nullptr); }
|
||||
;
|
||||
variable_declaration: identifier ":" pattern
|
||||
{ $$ = Carbon::global_arena->New<Carbon::BindingPattern>(yylineno, $1, $3); }
|
||||
|
||||
@@ -66,6 +66,9 @@ TEST_LIST = [
|
||||
"pattern_variable_fail",
|
||||
"placeholder_variable",
|
||||
"record1",
|
||||
"return_empty_explicit",
|
||||
"return_empty_implicit1",
|
||||
"return_empty_implicit2",
|
||||
"star",
|
||||
"struct1",
|
||||
"struct2",
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// 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
|
||||
|
||||
fn F() -> () {
|
||||
return ();
|
||||
}
|
||||
|
||||
fn main() -> Int {
|
||||
F();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
result: 0
|
||||
@@ -0,0 +1,11 @@
|
||||
// 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
|
||||
|
||||
fn F() {
|
||||
}
|
||||
|
||||
fn main() -> Int {
|
||||
F();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
result: 0
|
||||
@@ -0,0 +1,12 @@
|
||||
// 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
|
||||
|
||||
fn F() {
|
||||
return;
|
||||
}
|
||||
|
||||
fn main() -> Int {
|
||||
F();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
result: 0
|
||||
Reference in New Issue
Block a user