|
@@ -657,9 +657,9 @@ auto TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types, Env values,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static auto TypecheckCase(const Value* expected, Ptr<const Pattern> pat,
|
|
static auto TypecheckCase(const Value* expected, Ptr<const Pattern> pat,
|
|
|
- const Statement* body, TypeEnv types, Env values,
|
|
|
|
|
|
|
+ Ptr<const Statement> body, TypeEnv types, Env values,
|
|
|
const Value*& ret_type, bool is_omitted_ret_type)
|
|
const Value*& ret_type, bool is_omitted_ret_type)
|
|
|
- -> std::pair<Ptr<const Pattern>, const Statement*> {
|
|
|
|
|
|
|
+ -> std::pair<Ptr<const Pattern>, Ptr<const Statement>> {
|
|
|
auto pat_res = TypeCheckPattern(pat, types, values, expected);
|
|
auto pat_res = TypeCheckPattern(pat, types, values, expected);
|
|
|
auto res =
|
|
auto res =
|
|
|
TypeCheckStmt(body, pat_res.types, values, ret_type, is_omitted_ret_type);
|
|
TypeCheckStmt(body, pat_res.types, values, ret_type, is_omitted_ret_type);
|
|
@@ -673,26 +673,23 @@ static auto TypecheckCase(const Value* expected, Ptr<const Pattern> pat,
|
|
|
// It is the declared return type of the enclosing function definition.
|
|
// It is the declared return type of the enclosing function definition.
|
|
|
// If the return type is "auto", then the return type is inferred from
|
|
// If the return type is "auto", then the return type is inferred from
|
|
|
// the first return statement.
|
|
// the first return statement.
|
|
|
-auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values,
|
|
|
|
|
|
|
+auto TypeCheckStmt(Ptr<const Statement> s, TypeEnv types, Env values,
|
|
|
const Value*& ret_type, bool is_omitted_ret_type)
|
|
const Value*& ret_type, bool is_omitted_ret_type)
|
|
|
-> TCStatement {
|
|
-> TCStatement {
|
|
|
- if (!s) {
|
|
|
|
|
- return TCStatement(s, types);
|
|
|
|
|
- }
|
|
|
|
|
switch (s->Tag()) {
|
|
switch (s->Tag()) {
|
|
|
case Statement::Kind::Match: {
|
|
case Statement::Kind::Match: {
|
|
|
const auto& match = cast<Match>(*s);
|
|
const auto& match = cast<Match>(*s);
|
|
|
auto res = TypeCheckExp(match.Exp(), types, values);
|
|
auto res = TypeCheckExp(match.Exp(), types, values);
|
|
|
auto res_type = res.type;
|
|
auto res_type = res.type;
|
|
|
auto new_clauses = global_arena->RawNew<
|
|
auto new_clauses = global_arena->RawNew<
|
|
|
- std::list<std::pair<Ptr<const Pattern>, const Statement*>>>();
|
|
|
|
|
|
|
+ std::list<std::pair<Ptr<const Pattern>, Ptr<const Statement>>>>();
|
|
|
for (auto& clause : *match.Clauses()) {
|
|
for (auto& clause : *match.Clauses()) {
|
|
|
new_clauses->push_back(TypecheckCase(res_type, clause.first,
|
|
new_clauses->push_back(TypecheckCase(res_type, clause.first,
|
|
|
clause.second, types, values,
|
|
clause.second, types, values,
|
|
|
ret_type, is_omitted_ret_type));
|
|
ret_type, is_omitted_ret_type));
|
|
|
}
|
|
}
|
|
|
- const Statement* new_s =
|
|
|
|
|
- global_arena->RawNew<Match>(s->SourceLoc(), res.exp, new_clauses);
|
|
|
|
|
|
|
+ auto new_s =
|
|
|
|
|
+ global_arena->New<Match>(s->SourceLoc(), res.exp, new_clauses);
|
|
|
return TCStatement(new_s, types);
|
|
return TCStatement(new_s, types);
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::While: {
|
|
case Statement::Kind::While: {
|
|
@@ -702,39 +699,48 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values,
|
|
|
global_arena->RawNew<BoolType>(), cnd_res.type);
|
|
global_arena->RawNew<BoolType>(), cnd_res.type);
|
|
|
auto body_res = TypeCheckStmt(while_stmt.Body(), types, values, ret_type,
|
|
auto body_res = TypeCheckStmt(while_stmt.Body(), types, values, ret_type,
|
|
|
is_omitted_ret_type);
|
|
is_omitted_ret_type);
|
|
|
- auto new_s = global_arena->RawNew<While>(s->SourceLoc(), cnd_res.exp,
|
|
|
|
|
- body_res.stmt);
|
|
|
|
|
|
|
+ auto new_s =
|
|
|
|
|
+ global_arena->New<While>(s->SourceLoc(), cnd_res.exp, body_res.stmt);
|
|
|
return TCStatement(new_s, types);
|
|
return TCStatement(new_s, types);
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::Break:
|
|
case Statement::Kind::Break:
|
|
|
case Statement::Kind::Continue:
|
|
case Statement::Kind::Continue:
|
|
|
return TCStatement(s, types);
|
|
return TCStatement(s, types);
|
|
|
case Statement::Kind::Block: {
|
|
case Statement::Kind::Block: {
|
|
|
- auto stmt_res = TypeCheckStmt(cast<Block>(*s).Stmt(), types, values,
|
|
|
|
|
- ret_type, is_omitted_ret_type);
|
|
|
|
|
- return TCStatement(
|
|
|
|
|
- global_arena->RawNew<Block>(s->SourceLoc(), stmt_res.stmt), types);
|
|
|
|
|
|
|
+ const auto& block = cast<Block>(*s);
|
|
|
|
|
+ if (block.Stmt()) {
|
|
|
|
|
+ auto stmt_res = TypeCheckStmt(*block.Stmt(), types, values, ret_type,
|
|
|
|
|
+ is_omitted_ret_type);
|
|
|
|
|
+ return TCStatement(
|
|
|
|
|
+ global_arena->New<Block>(s->SourceLoc(), stmt_res.stmt), types);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return TCStatement(s, types);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::VariableDefinition: {
|
|
case Statement::Kind::VariableDefinition: {
|
|
|
const auto& var = cast<VariableDefinition>(*s);
|
|
const auto& var = cast<VariableDefinition>(*s);
|
|
|
auto res = TypeCheckExp(var.Init(), types, values);
|
|
auto res = TypeCheckExp(var.Init(), types, values);
|
|
|
const Value* rhs_ty = res.type;
|
|
const Value* rhs_ty = res.type;
|
|
|
auto lhs_res = TypeCheckPattern(var.Pat(), types, values, rhs_ty);
|
|
auto lhs_res = TypeCheckPattern(var.Pat(), types, values, rhs_ty);
|
|
|
- const Statement* new_s = global_arena->RawNew<VariableDefinition>(
|
|
|
|
|
- s->SourceLoc(), var.Pat(), res.exp);
|
|
|
|
|
|
|
+ auto new_s = global_arena->New<VariableDefinition>(s->SourceLoc(),
|
|
|
|
|
+ var.Pat(), res.exp);
|
|
|
return TCStatement(new_s, lhs_res.types);
|
|
return TCStatement(new_s, lhs_res.types);
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::Sequence: {
|
|
case Statement::Kind::Sequence: {
|
|
|
const auto& seq = cast<Sequence>(*s);
|
|
const auto& seq = cast<Sequence>(*s);
|
|
|
auto stmt_res = TypeCheckStmt(seq.Stmt(), types, values, ret_type,
|
|
auto stmt_res = TypeCheckStmt(seq.Stmt(), types, values, ret_type,
|
|
|
is_omitted_ret_type);
|
|
is_omitted_ret_type);
|
|
|
- auto types2 = stmt_res.types;
|
|
|
|
|
- auto next_res = TypeCheckStmt(seq.Next(), types2, values, ret_type,
|
|
|
|
|
- is_omitted_ret_type);
|
|
|
|
|
- auto types3 = next_res.types;
|
|
|
|
|
- return TCStatement(global_arena->RawNew<Sequence>(
|
|
|
|
|
- s->SourceLoc(), stmt_res.stmt, next_res.stmt),
|
|
|
|
|
- types3);
|
|
|
|
|
|
|
+ auto checked_types = stmt_res.types;
|
|
|
|
|
+ std::optional<Ptr<const Statement>> next_stmt;
|
|
|
|
|
+ if (seq.Next()) {
|
|
|
|
|
+ auto next_res = TypeCheckStmt(*seq.Next(), checked_types, values,
|
|
|
|
|
+ ret_type, is_omitted_ret_type);
|
|
|
|
|
+ next_stmt = next_res.stmt;
|
|
|
|
|
+ checked_types = next_res.types;
|
|
|
|
|
+ }
|
|
|
|
|
+ return TCStatement(
|
|
|
|
|
+ global_arena->New<Sequence>(s->SourceLoc(), stmt_res.stmt, next_stmt),
|
|
|
|
|
+ checked_types);
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::Assign: {
|
|
case Statement::Kind::Assign: {
|
|
|
const auto& assign = cast<Assign>(*s);
|
|
const auto& assign = cast<Assign>(*s);
|
|
@@ -743,15 +749,15 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values,
|
|
|
auto lhs_res = TypeCheckExp(assign.Lhs(), types, values);
|
|
auto lhs_res = TypeCheckExp(assign.Lhs(), types, values);
|
|
|
auto lhs_t = lhs_res.type;
|
|
auto lhs_t = lhs_res.type;
|
|
|
ExpectType(s->SourceLoc(), "assign", lhs_t, rhs_t);
|
|
ExpectType(s->SourceLoc(), "assign", lhs_t, rhs_t);
|
|
|
- auto new_s = global_arena->RawNew<Assign>(s->SourceLoc(), lhs_res.exp,
|
|
|
|
|
- rhs_res.exp);
|
|
|
|
|
|
|
+ auto new_s =
|
|
|
|
|
+ global_arena->New<Assign>(s->SourceLoc(), lhs_res.exp, rhs_res.exp);
|
|
|
return TCStatement(new_s, lhs_res.types);
|
|
return TCStatement(new_s, lhs_res.types);
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::ExpressionStatement: {
|
|
case Statement::Kind::ExpressionStatement: {
|
|
|
auto res =
|
|
auto res =
|
|
|
TypeCheckExp(cast<ExpressionStatement>(*s).Exp(), types, values);
|
|
TypeCheckExp(cast<ExpressionStatement>(*s).Exp(), types, values);
|
|
|
auto new_s =
|
|
auto new_s =
|
|
|
- global_arena->RawNew<ExpressionStatement>(s->SourceLoc(), res.exp);
|
|
|
|
|
|
|
+ global_arena->New<ExpressionStatement>(s->SourceLoc(), res.exp);
|
|
|
return TCStatement(new_s, types);
|
|
return TCStatement(new_s, types);
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::If: {
|
|
case Statement::Kind::If: {
|
|
@@ -761,10 +767,14 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values,
|
|
|
global_arena->RawNew<BoolType>(), cnd_res.type);
|
|
global_arena->RawNew<BoolType>(), cnd_res.type);
|
|
|
auto then_res = TypeCheckStmt(if_stmt.ThenStmt(), types, values, ret_type,
|
|
auto then_res = TypeCheckStmt(if_stmt.ThenStmt(), types, values, ret_type,
|
|
|
is_omitted_ret_type);
|
|
is_omitted_ret_type);
|
|
|
- auto else_res = TypeCheckStmt(if_stmt.ElseStmt(), types, values, ret_type,
|
|
|
|
|
- is_omitted_ret_type);
|
|
|
|
|
- auto new_s = global_arena->RawNew<If>(s->SourceLoc(), cnd_res.exp,
|
|
|
|
|
- then_res.stmt, else_res.stmt);
|
|
|
|
|
|
|
+ std::optional<Ptr<const Statement>> else_stmt;
|
|
|
|
|
+ if (if_stmt.ElseStmt()) {
|
|
|
|
|
+ auto else_res = TypeCheckStmt(*if_stmt.ElseStmt(), types, values,
|
|
|
|
|
+ ret_type, is_omitted_ret_type);
|
|
|
|
|
+ else_stmt = else_res.stmt;
|
|
|
|
|
+ }
|
|
|
|
|
+ auto new_s = global_arena->New<If>(s->SourceLoc(), cnd_res.exp,
|
|
|
|
|
+ then_res.stmt, else_stmt);
|
|
|
return TCStatement(new_s, types);
|
|
return TCStatement(new_s, types);
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::Return: {
|
|
case Statement::Kind::Return: {
|
|
@@ -783,15 +793,15 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values,
|
|
|
<< *s << " should" << (is_omitted_ret_type ? " not" : "")
|
|
<< *s << " should" << (is_omitted_ret_type ? " not" : "")
|
|
|
<< " provide a return value, to match the function's signature.";
|
|
<< " provide a return value, to match the function's signature.";
|
|
|
}
|
|
}
|
|
|
- return TCStatement(global_arena->RawNew<Return>(s->SourceLoc(), res.exp,
|
|
|
|
|
- ret.IsOmittedExp()),
|
|
|
|
|
|
|
+ return TCStatement(global_arena->New<Return>(s->SourceLoc(), res.exp,
|
|
|
|
|
+ ret.IsOmittedExp()),
|
|
|
types);
|
|
types);
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::Continuation: {
|
|
case Statement::Kind::Continuation: {
|
|
|
const auto& cont = cast<Continuation>(*s);
|
|
const auto& cont = cast<Continuation>(*s);
|
|
|
TCStatement body_result = TypeCheckStmt(cont.Body(), types, values,
|
|
TCStatement body_result = TypeCheckStmt(cont.Body(), types, values,
|
|
|
ret_type, is_omitted_ret_type);
|
|
ret_type, is_omitted_ret_type);
|
|
|
- const Statement* new_continuation = global_arena->RawNew<Continuation>(
|
|
|
|
|
|
|
+ auto new_continuation = global_arena->New<Continuation>(
|
|
|
s->SourceLoc(), cont.ContinuationVariable(), body_result.stmt);
|
|
s->SourceLoc(), cont.ContinuationVariable(), body_result.stmt);
|
|
|
types.Set(cont.ContinuationVariable(),
|
|
types.Set(cont.ContinuationVariable(),
|
|
|
global_arena->RawNew<ContinuationType>());
|
|
global_arena->RawNew<ContinuationType>());
|
|
@@ -803,8 +813,8 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values,
|
|
|
ExpectType(s->SourceLoc(), "argument of `run`",
|
|
ExpectType(s->SourceLoc(), "argument of `run`",
|
|
|
global_arena->RawNew<ContinuationType>(),
|
|
global_arena->RawNew<ContinuationType>(),
|
|
|
argument_result.type);
|
|
argument_result.type);
|
|
|
- const Statement* new_run =
|
|
|
|
|
- global_arena->RawNew<Run>(s->SourceLoc(), argument_result.exp);
|
|
|
|
|
|
|
+ auto new_run =
|
|
|
|
|
+ global_arena->New<Run>(s->SourceLoc(), argument_result.exp);
|
|
|
return TCStatement(new_run, types);
|
|
return TCStatement(new_run, types);
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::Await: {
|
|
case Statement::Kind::Await: {
|
|
@@ -814,38 +824,40 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values,
|
|
|
} // switch
|
|
} // switch
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static auto CheckOrEnsureReturn(const Statement* stmt, bool omitted_ret_type,
|
|
|
|
|
- SourceLocation loc) -> const Statement* {
|
|
|
|
|
- if (!stmt) {
|
|
|
|
|
|
|
+static auto CheckOrEnsureReturn(std::optional<Ptr<const Statement>> opt_stmt,
|
|
|
|
|
+ bool omitted_ret_type, SourceLocation loc)
|
|
|
|
|
+ -> Ptr<const Statement> {
|
|
|
|
|
+ if (!opt_stmt) {
|
|
|
if (omitted_ret_type) {
|
|
if (omitted_ret_type) {
|
|
|
- return global_arena->RawNew<Return>(loc);
|
|
|
|
|
|
|
+ return global_arena->New<Return>(loc);
|
|
|
} else {
|
|
} else {
|
|
|
FATAL_COMPILATION_ERROR(loc)
|
|
FATAL_COMPILATION_ERROR(loc)
|
|
|
<< "control-flow reaches end of function that provides a `->` return "
|
|
<< "control-flow reaches end of function that provides a `->` return "
|
|
|
"type without reaching a return statement";
|
|
"type without reaching a return statement";
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ Ptr<const Statement> stmt = *opt_stmt;
|
|
|
switch (stmt->Tag()) {
|
|
switch (stmt->Tag()) {
|
|
|
case Statement::Kind::Match: {
|
|
case Statement::Kind::Match: {
|
|
|
const auto& match = cast<Match>(*stmt);
|
|
const auto& match = cast<Match>(*stmt);
|
|
|
auto new_clauses = global_arena->RawNew<
|
|
auto new_clauses = global_arena->RawNew<
|
|
|
- std::list<std::pair<Ptr<const Pattern>, const Statement*>>>();
|
|
|
|
|
|
|
+ std::list<std::pair<Ptr<const Pattern>, Ptr<const Statement>>>>();
|
|
|
for (const auto& clause : *match.Clauses()) {
|
|
for (const auto& clause : *match.Clauses()) {
|
|
|
auto s = CheckOrEnsureReturn(clause.second, omitted_ret_type,
|
|
auto s = CheckOrEnsureReturn(clause.second, omitted_ret_type,
|
|
|
stmt->SourceLoc());
|
|
stmt->SourceLoc());
|
|
|
new_clauses->push_back(std::make_pair(clause.first, s));
|
|
new_clauses->push_back(std::make_pair(clause.first, s));
|
|
|
}
|
|
}
|
|
|
- return global_arena->RawNew<Match>(stmt->SourceLoc(), match.Exp(),
|
|
|
|
|
- new_clauses);
|
|
|
|
|
|
|
+ return global_arena->New<Match>(stmt->SourceLoc(), match.Exp(),
|
|
|
|
|
+ new_clauses);
|
|
|
}
|
|
}
|
|
|
case Statement::Kind::Block:
|
|
case Statement::Kind::Block:
|
|
|
- return global_arena->RawNew<Block>(
|
|
|
|
|
|
|
+ return global_arena->New<Block>(
|
|
|
stmt->SourceLoc(),
|
|
stmt->SourceLoc(),
|
|
|
CheckOrEnsureReturn(cast<Block>(*stmt).Stmt(), omitted_ret_type,
|
|
CheckOrEnsureReturn(cast<Block>(*stmt).Stmt(), omitted_ret_type,
|
|
|
stmt->SourceLoc()));
|
|
stmt->SourceLoc()));
|
|
|
case Statement::Kind::If: {
|
|
case Statement::Kind::If: {
|
|
|
const auto& if_stmt = cast<If>(*stmt);
|
|
const auto& if_stmt = cast<If>(*stmt);
|
|
|
- return global_arena->RawNew<If>(
|
|
|
|
|
|
|
+ return global_arena->New<If>(
|
|
|
stmt->SourceLoc(), if_stmt.Cond(),
|
|
stmt->SourceLoc(), if_stmt.Cond(),
|
|
|
CheckOrEnsureReturn(if_stmt.ThenStmt(), omitted_ret_type,
|
|
CheckOrEnsureReturn(if_stmt.ThenStmt(), omitted_ret_type,
|
|
|
stmt->SourceLoc()),
|
|
stmt->SourceLoc()),
|
|
@@ -857,7 +869,7 @@ static auto CheckOrEnsureReturn(const Statement* stmt, bool omitted_ret_type,
|
|
|
case Statement::Kind::Sequence: {
|
|
case Statement::Kind::Sequence: {
|
|
|
const auto& seq = cast<Sequence>(*stmt);
|
|
const auto& seq = cast<Sequence>(*stmt);
|
|
|
if (seq.Next()) {
|
|
if (seq.Next()) {
|
|
|
- return global_arena->RawNew<Sequence>(
|
|
|
|
|
|
|
+ return global_arena->New<Sequence>(
|
|
|
stmt->SourceLoc(), seq.Stmt(),
|
|
stmt->SourceLoc(), seq.Stmt(),
|
|
|
CheckOrEnsureReturn(seq.Next(), omitted_ret_type,
|
|
CheckOrEnsureReturn(seq.Next(), omitted_ret_type,
|
|
|
stmt->SourceLoc()));
|
|
stmt->SourceLoc()));
|
|
@@ -877,8 +889,8 @@ static auto CheckOrEnsureReturn(const Statement* stmt, bool omitted_ret_type,
|
|
|
case Statement::Kind::Continue:
|
|
case Statement::Kind::Continue:
|
|
|
case Statement::Kind::VariableDefinition:
|
|
case Statement::Kind::VariableDefinition:
|
|
|
if (omitted_ret_type) {
|
|
if (omitted_ret_type) {
|
|
|
- return global_arena->RawNew<Sequence>(
|
|
|
|
|
- stmt->SourceLoc(), stmt, global_arena->RawNew<Return>(loc));
|
|
|
|
|
|
|
+ return global_arena->New<Sequence>(stmt->SourceLoc(), stmt,
|
|
|
|
|
+ global_arena->New<Return>(loc));
|
|
|
} else {
|
|
} else {
|
|
|
FATAL_COMPILATION_ERROR(stmt->SourceLoc())
|
|
FATAL_COMPILATION_ERROR(stmt->SourceLoc())
|
|
|
<< "control-flow reaches end of function that provides a `->` "
|
|
<< "control-flow reaches end of function that provides a `->` "
|
|
@@ -909,9 +921,13 @@ static auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
|
|
|
global_arena->RawNew<IntType>(), return_type);
|
|
global_arena->RawNew<IntType>(), return_type);
|
|
|
// TODO: Check that main doesn't have any parameters.
|
|
// TODO: Check that main doesn't have any parameters.
|
|
|
}
|
|
}
|
|
|
- auto res = TypeCheckStmt(f->body, param_res.types, values, return_type,
|
|
|
|
|
- f->is_omitted_return_type);
|
|
|
|
|
- auto body = CheckOrEnsureReturn(res.stmt, f->is_omitted_return_type,
|
|
|
|
|
|
|
+ std::optional<Ptr<const Statement>> body_stmt;
|
|
|
|
|
+ if (f->body) {
|
|
|
|
|
+ auto res = TypeCheckStmt(*f->body, param_res.types, values, return_type,
|
|
|
|
|
+ f->is_omitted_return_type);
|
|
|
|
|
+ body_stmt = res.stmt;
|
|
|
|
|
+ }
|
|
|
|
|
+ auto body = CheckOrEnsureReturn(body_stmt, f->is_omitted_return_type,
|
|
|
f->source_location);
|
|
f->source_location);
|
|
|
return global_arena->New<FunctionDefinition>(
|
|
return global_arena->New<FunctionDefinition>(
|
|
|
f->source_location, f->name, f->deduced_parameters, f->param_pattern,
|
|
f->source_location, f->name, f->deduced_parameters, f->param_pattern,
|