mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 06:44:46 +01:00
Make the AST mutable (#849)
The code is pretty intertwined: having the AST be truly mutable means (to me) changing parser.ypp to return non-const values, but then the way things are passed around between objects should be non-const (particularly an issue with lists), which then creates issues with construction of lists in the TypeChecker, which then TypeChecker needs to mostly be non-const. Due to the difficulties in breaking this apart, whereas I'd previously considering refactoring accessor naming in the same PR, I've largely avoided doing so. The intent is then that this PR focuses mainly on const -> non-const AST behavior. call_main moves out of interpreter.cpp so that interpreter.cpp can receive a fully const AST.
This commit is contained in:
@@ -15,9 +15,8 @@ namespace Carbon {
|
||||
|
||||
// Adds builtins, currently only Print(). Note Print() is experimental, not
|
||||
// standardized, but is made available for printing state in tests.
|
||||
static void AddIntrinsics(
|
||||
Nonnull<Arena*> arena,
|
||||
std::vector<Nonnull<const Declaration*>>* declarations) {
|
||||
static void AddIntrinsics(Nonnull<Arena*> arena,
|
||||
std::vector<Nonnull<Declaration*>>* declarations) {
|
||||
SourceLocation loc("<intrinsic>", 0);
|
||||
std::vector<TuplePattern::Field> print_fields = {TuplePattern::Field(
|
||||
"0",
|
||||
@@ -47,7 +46,7 @@ void ExecProgram(Nonnull<Arena*> arena, AST ast) {
|
||||
llvm::outs() << "********** type checking **********\n";
|
||||
}
|
||||
TypeChecker type_checker(arena);
|
||||
TypeChecker::TypeCheckContext p = type_checker.TopLevel(ast.declarations);
|
||||
TypeChecker::TypeCheckContext p = type_checker.TopLevel(&ast.declarations);
|
||||
TypeEnv top = p.types;
|
||||
Env ct_top = p.values;
|
||||
std::vector<Nonnull<const Declaration*>> new_decls;
|
||||
@@ -62,7 +61,12 @@ void ExecProgram(Nonnull<Arena*> arena, AST ast) {
|
||||
}
|
||||
llvm::outs() << "********** starting execution **********\n";
|
||||
}
|
||||
int result = Interpreter(arena).InterpProgram(new_decls);
|
||||
|
||||
SourceLocation loc("<main()>", 0);
|
||||
Nonnull<Expression*> call_main = arena->New<CallExpression>(
|
||||
loc, arena->New<IdentifierExpression>(loc, "main"),
|
||||
arena->New<TupleLiteral>(loc));
|
||||
int result = Interpreter(arena).InterpProgram(new_decls, call_main);
|
||||
llvm::outs() << "result: " << result << "\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -1133,7 +1133,8 @@ void Interpreter::Step() {
|
||||
}
|
||||
|
||||
auto Interpreter::InterpProgram(
|
||||
const std::vector<Nonnull<const Declaration*>>& fs) -> int {
|
||||
const std::vector<Nonnull<const Declaration*>>& fs,
|
||||
Nonnull<const Expression*> call_main) -> int {
|
||||
// Check that the interpreter is in a clean state.
|
||||
CHECK(globals.IsEmpty());
|
||||
CHECK(stack.IsEmpty());
|
||||
@@ -1144,11 +1145,6 @@ auto Interpreter::InterpProgram(
|
||||
}
|
||||
InitGlobals(fs);
|
||||
|
||||
SourceLocation loc("<InterpProgram()>", 0);
|
||||
|
||||
Nonnull<const Expression*> arg = arena->New<TupleLiteral>(loc);
|
||||
Nonnull<const Expression*> call_main = arena->New<CallExpression>(
|
||||
loc, arena->New<IdentifierExpression>(loc, "main"), arg);
|
||||
auto todo = Stack<Nonnull<Action*>>(arena->New<ExpressionAction>(call_main));
|
||||
auto scopes = Stack<Nonnull<Scope*>>(arena->New<Scope>(globals));
|
||||
stack = Stack<Nonnull<Frame*>>(arena->New<Frame>("top", scopes, todo));
|
||||
|
||||
@@ -28,7 +28,8 @@ class Interpreter {
|
||||
: arena(arena), globals(arena), heap(arena) {}
|
||||
|
||||
// Interpret the whole program.
|
||||
auto InterpProgram(const std::vector<Nonnull<const Declaration*>>& fs) -> int;
|
||||
auto InterpProgram(const std::vector<Nonnull<const Declaration*>>& fs,
|
||||
Nonnull<const Expression*> call_main) -> int;
|
||||
|
||||
// Interpret an expression at compile-time.
|
||||
auto InterpExp(Env values, Nonnull<const Expression*> e)
|
||||
|
||||
@@ -52,7 +52,7 @@ static void ExpectPointerType(SourceLocation loc, const std::string& context,
|
||||
}
|
||||
|
||||
auto TypeChecker::ReifyType(Nonnull<const Value*> t, SourceLocation loc)
|
||||
-> Nonnull<const Expression*> {
|
||||
-> Nonnull<Expression*> {
|
||||
switch (t->Tag()) {
|
||||
case Value::Kind::IntType:
|
||||
return arena->New<IntTypeLiteral>(loc);
|
||||
@@ -83,7 +83,7 @@ auto TypeChecker::ReifyType(Nonnull<const Value*> t, SourceLocation loc)
|
||||
case Value::Kind::PointerType:
|
||||
return arena->New<PrimitiveOperatorExpression>(
|
||||
loc, Operator::Ptr,
|
||||
std::vector<Nonnull<const Expression*>>(
|
||||
std::vector<Nonnull<Expression*>>(
|
||||
{ReifyType(cast<PointerType>(*t).Type(), loc)}));
|
||||
case Value::Kind::VariableType:
|
||||
return arena->New<IdentifierExpression>(loc,
|
||||
@@ -248,7 +248,7 @@ auto TypeChecker::Substitute(TypeEnv dict, Nonnull<const Value*> type)
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e, TypeEnv types,
|
||||
Env values) -> TCExpression {
|
||||
if (tracing_output) {
|
||||
llvm::outs() << "checking expression " << *e << "\ntypes: ";
|
||||
@@ -259,7 +259,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
}
|
||||
switch (e->Tag()) {
|
||||
case Expression::Kind::IndexExpression: {
|
||||
const auto& index = cast<IndexExpression>(*e);
|
||||
auto& index = cast<IndexExpression>(*e);
|
||||
auto res = TypeCheckExp(index.Aggregate(), types, values);
|
||||
auto t = res.type;
|
||||
switch (t->Tag()) {
|
||||
@@ -298,7 +298,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
return TCExpression(tuple_e, tuple_t, new_types);
|
||||
}
|
||||
case Expression::Kind::FieldAccessExpression: {
|
||||
const auto& access = cast<FieldAccessExpression>(*e);
|
||||
auto& access = cast<FieldAccessExpression>(*e);
|
||||
auto res = TypeCheckExp(access.Aggregate(), types, values);
|
||||
auto t = res.type;
|
||||
switch (t->Tag()) {
|
||||
@@ -307,18 +307,16 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
// Search for a field
|
||||
for (auto& field : t_class.Fields()) {
|
||||
if (access.Field() == field.first) {
|
||||
Nonnull<const Expression*> new_e =
|
||||
arena->New<FieldAccessExpression>(e->SourceLoc(), res.exp,
|
||||
access.Field());
|
||||
Nonnull<Expression*> new_e = arena->New<FieldAccessExpression>(
|
||||
e->SourceLoc(), res.exp, access.Field());
|
||||
return TCExpression(new_e, field.second, res.types);
|
||||
}
|
||||
}
|
||||
// Search for a method
|
||||
for (auto& method : t_class.Methods()) {
|
||||
if (access.Field() == method.first) {
|
||||
Nonnull<const Expression*> new_e =
|
||||
arena->New<FieldAccessExpression>(e->SourceLoc(), res.exp,
|
||||
access.Field());
|
||||
Nonnull<Expression*> new_e = arena->New<FieldAccessExpression>(
|
||||
e->SourceLoc(), res.exp, access.Field());
|
||||
return TCExpression(new_e, method.second, res.types);
|
||||
}
|
||||
}
|
||||
@@ -343,9 +341,8 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
const auto& choice = cast<ChoiceType>(*t);
|
||||
for (const auto& vt : choice.Alternatives()) {
|
||||
if (access.Field() == vt.first) {
|
||||
Nonnull<const Expression*> new_e =
|
||||
arena->New<FieldAccessExpression>(e->SourceLoc(), res.exp,
|
||||
access.Field());
|
||||
Nonnull<Expression*> new_e = arena->New<FieldAccessExpression>(
|
||||
e->SourceLoc(), res.exp, access.Field());
|
||||
auto fun_ty = arena->New<FunctionType>(
|
||||
std::vector<GenericBinding>(), vt.second, t);
|
||||
return TCExpression(new_e, fun_ty, res.types);
|
||||
@@ -377,10 +374,10 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
return TCExpression(e, arena->New<BoolType>(), types);
|
||||
case Expression::Kind::PrimitiveOperatorExpression: {
|
||||
const auto& op = cast<PrimitiveOperatorExpression>(*e);
|
||||
std::vector<Nonnull<const Expression*>> es;
|
||||
std::vector<Nonnull<Expression*>> es;
|
||||
std::vector<Nonnull<const Value*>> ts;
|
||||
auto new_types = types;
|
||||
for (Nonnull<const Expression*> argument : op.Arguments()) {
|
||||
for (Nonnull<Expression*> argument : op.Arguments()) {
|
||||
auto res = TypeCheckExp(argument, types, values);
|
||||
new_types = res.types;
|
||||
es.push_back(res.exp);
|
||||
@@ -435,7 +432,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
break;
|
||||
}
|
||||
case Expression::Kind::CallExpression: {
|
||||
const auto& call = cast<CallExpression>(*e);
|
||||
auto& call = cast<CallExpression>(*e);
|
||||
auto fun_res = TypeCheckExp(call.Function(), types, values);
|
||||
switch (fun_res.type->Tag()) {
|
||||
case Value::Kind::FunctionType: {
|
||||
@@ -499,7 +496,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types,
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckPattern(
|
||||
Nonnull<const Pattern*> p, TypeEnv types, Env values,
|
||||
Nonnull<Pattern*> p, TypeEnv types, Env values,
|
||||
std::optional<Nonnull<const Value*>> expected) -> TCPattern {
|
||||
if (tracing_output) {
|
||||
llvm::outs() << "checking pattern " << *p;
|
||||
@@ -517,7 +514,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
return {.pattern = p, .type = arena->New<TypeType>(), .types = types};
|
||||
}
|
||||
case Pattern::Kind::BindingPattern: {
|
||||
const auto& binding = cast<BindingPattern>(*p);
|
||||
auto& binding = cast<BindingPattern>(*p);
|
||||
TCPattern binding_type_result =
|
||||
TypeCheckPattern(binding.Type(), types, values, std::nullopt);
|
||||
Nonnull<const Value*> type =
|
||||
@@ -543,7 +540,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
return {.pattern = new_p, .type = type, .types = types};
|
||||
}
|
||||
case Pattern::Kind::TuplePattern: {
|
||||
const auto& tuple = cast<TuplePattern>(*p);
|
||||
auto& tuple = cast<TuplePattern>(*p);
|
||||
std::vector<TuplePattern::Field> new_fields;
|
||||
std::vector<TupleElement> field_types;
|
||||
auto new_types = types;
|
||||
@@ -556,7 +553,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
<< "tuples of different length";
|
||||
}
|
||||
for (size_t i = 0; i < tuple.Fields().size(); ++i) {
|
||||
const TuplePattern::Field& field = tuple.Fields()[i];
|
||||
TuplePattern::Field& field = tuple.Fields()[i];
|
||||
std::optional<Nonnull<const Value*>> expected_field_type;
|
||||
if (expected) {
|
||||
const TupleElement& expected_element =
|
||||
@@ -580,7 +577,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
return {.pattern = new_tuple, .type = tuple_t, .types = new_types};
|
||||
}
|
||||
case Pattern::Kind::AlternativePattern: {
|
||||
const auto& alternative = cast<AlternativePattern>(*p);
|
||||
auto& alternative = cast<AlternativePattern>(*p);
|
||||
Nonnull<const Value*> choice_type =
|
||||
interpreter.InterpExp(values, alternative.ChoiceType());
|
||||
if (choice_type->Tag() != Value::Kind::ChoiceType) {
|
||||
@@ -603,8 +600,8 @@ auto TypeChecker::TypeCheckPattern(
|
||||
values, *parameter_types);
|
||||
// TODO: Think about a cleaner way to cast between Ptr types.
|
||||
// (multiple TODOs)
|
||||
auto arguments = Nonnull<const TuplePattern*>(
|
||||
cast<const TuplePattern>(arg_results.pattern));
|
||||
auto arguments =
|
||||
Nonnull<TuplePattern*>(cast<const TuplePattern>(arg_results.pattern));
|
||||
return {.pattern = arena->New<AlternativePattern>(
|
||||
alternative.SourceLoc(),
|
||||
ReifyType(choice_type, alternative.SourceLoc()),
|
||||
@@ -623,26 +620,26 @@ auto TypeChecker::TypeCheckPattern(
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckCase(Nonnull<const Value*> expected,
|
||||
Nonnull<const Pattern*> pat,
|
||||
Nonnull<const Statement*> body, TypeEnv types,
|
||||
Env values, Nonnull<const Value*>& ret_type,
|
||||
Nonnull<Pattern*> pat, Nonnull<Statement*> body,
|
||||
TypeEnv types, Env values,
|
||||
Nonnull<const Value*>& ret_type,
|
||||
bool is_omitted_ret_type)
|
||||
-> std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>> {
|
||||
-> std::pair<Nonnull<Pattern*>, Nonnull<Statement*>> {
|
||||
auto pat_res = TypeCheckPattern(pat, types, values, expected);
|
||||
auto res =
|
||||
TypeCheckStmt(body, pat_res.types, values, ret_type, is_omitted_ret_type);
|
||||
return std::make_pair(pat, res.stmt);
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s, TypeEnv types,
|
||||
Env values, Nonnull<const Value*>& ret_type,
|
||||
bool is_omitted_ret_type) -> TCStatement {
|
||||
switch (s->Tag()) {
|
||||
case Statement::Kind::Match: {
|
||||
const auto& match = cast<Match>(*s);
|
||||
auto& match = cast<Match>(*s);
|
||||
auto res = TypeCheckExp(match.Exp(), types, values);
|
||||
auto res_type = res.type;
|
||||
std::vector<std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>>
|
||||
std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>>
|
||||
new_clauses;
|
||||
for (auto& clause : match.Clauses()) {
|
||||
new_clauses.push_back(TypeCheckCase(res_type, clause.first,
|
||||
@@ -653,7 +650,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
return TCStatement(new_s, types);
|
||||
}
|
||||
case Statement::Kind::While: {
|
||||
const auto& while_stmt = cast<While>(*s);
|
||||
auto& while_stmt = cast<While>(*s);
|
||||
auto cnd_res = TypeCheckExp(while_stmt.Cond(), types, values);
|
||||
ExpectType(s->SourceLoc(), "condition of `while`", arena->New<BoolType>(),
|
||||
cnd_res.type);
|
||||
@@ -667,7 +664,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
case Statement::Kind::Continue:
|
||||
return TCStatement(s, types);
|
||||
case Statement::Kind::Block: {
|
||||
const auto& block = cast<Block>(*s);
|
||||
auto& block = cast<Block>(*s);
|
||||
if (block.Stmt()) {
|
||||
auto stmt_res = TypeCheckStmt(*block.Stmt(), types, values, ret_type,
|
||||
is_omitted_ret_type);
|
||||
@@ -678,7 +675,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
}
|
||||
}
|
||||
case Statement::Kind::VariableDefinition: {
|
||||
const auto& var = cast<VariableDefinition>(*s);
|
||||
auto& var = cast<VariableDefinition>(*s);
|
||||
auto res = TypeCheckExp(var.Init(), types, values);
|
||||
Nonnull<const Value*> rhs_ty = res.type;
|
||||
auto lhs_res = TypeCheckPattern(var.Pat(), types, values, rhs_ty);
|
||||
@@ -687,11 +684,11 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
return TCStatement(new_s, lhs_res.types);
|
||||
}
|
||||
case Statement::Kind::Sequence: {
|
||||
const auto& seq = cast<Sequence>(*s);
|
||||
auto& seq = cast<Sequence>(*s);
|
||||
auto stmt_res = TypeCheckStmt(seq.Stmt(), types, values, ret_type,
|
||||
is_omitted_ret_type);
|
||||
auto checked_types = stmt_res.types;
|
||||
std::optional<Nonnull<const Statement*>> next_stmt;
|
||||
std::optional<Nonnull<Statement*>> next_stmt;
|
||||
if (seq.Next()) {
|
||||
auto next_res = TypeCheckStmt(*seq.Next(), checked_types, values,
|
||||
ret_type, is_omitted_ret_type);
|
||||
@@ -703,7 +700,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
checked_types);
|
||||
}
|
||||
case Statement::Kind::Assign: {
|
||||
const auto& assign = cast<Assign>(*s);
|
||||
auto& assign = cast<Assign>(*s);
|
||||
auto rhs_res = TypeCheckExp(assign.Rhs(), types, values);
|
||||
auto rhs_t = rhs_res.type;
|
||||
auto lhs_res = TypeCheckExp(assign.Lhs(), types, values);
|
||||
@@ -719,13 +716,13 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
return TCStatement(new_s, types);
|
||||
}
|
||||
case Statement::Kind::If: {
|
||||
const auto& if_stmt = cast<If>(*s);
|
||||
auto& if_stmt = cast<If>(*s);
|
||||
auto cnd_res = TypeCheckExp(if_stmt.Cond(), types, values);
|
||||
ExpectType(s->SourceLoc(), "condition of `if`", arena->New<BoolType>(),
|
||||
cnd_res.type);
|
||||
auto then_res = TypeCheckStmt(if_stmt.ThenStmt(), types, values, ret_type,
|
||||
is_omitted_ret_type);
|
||||
std::optional<Nonnull<const Statement*>> else_stmt;
|
||||
std::optional<Nonnull<Statement*>> else_stmt;
|
||||
if (if_stmt.ElseStmt()) {
|
||||
auto else_res = TypeCheckStmt(*if_stmt.ElseStmt(), types, values,
|
||||
ret_type, is_omitted_ret_type);
|
||||
@@ -736,7 +733,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
return TCStatement(new_s, types);
|
||||
}
|
||||
case Statement::Kind::Return: {
|
||||
const auto& ret = cast<Return>(*s);
|
||||
auto& ret = cast<Return>(*s);
|
||||
auto res = TypeCheckExp(ret.Exp(), types, values);
|
||||
if (ret_type->Tag() == Value::Kind::AutoType) {
|
||||
// The following infers the return type from the first 'return'
|
||||
@@ -756,7 +753,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
types);
|
||||
}
|
||||
case Statement::Kind::Continuation: {
|
||||
const auto& cont = cast<Continuation>(*s);
|
||||
auto& cont = cast<Continuation>(*s);
|
||||
TCStatement body_result = TypeCheckStmt(cont.Body(), types, values,
|
||||
ret_type, is_omitted_ret_type);
|
||||
auto new_continuation = arena->New<Continuation>(
|
||||
@@ -780,8 +777,8 @@ auto TypeChecker::TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types,
|
||||
}
|
||||
|
||||
auto TypeChecker::CheckOrEnsureReturn(
|
||||
std::optional<Nonnull<const Statement*>> opt_stmt, bool omitted_ret_type,
|
||||
SourceLocation loc) -> Nonnull<const Statement*> {
|
||||
std::optional<Nonnull<Statement*>> opt_stmt, bool omitted_ret_type,
|
||||
SourceLocation loc) -> Nonnull<Statement*> {
|
||||
if (!opt_stmt) {
|
||||
if (omitted_ret_type) {
|
||||
return arena->New<Return>(arena, loc);
|
||||
@@ -791,11 +788,11 @@ auto TypeChecker::CheckOrEnsureReturn(
|
||||
"type without reaching a return statement";
|
||||
}
|
||||
}
|
||||
Nonnull<const Statement*> stmt = *opt_stmt;
|
||||
Nonnull<Statement*> stmt = *opt_stmt;
|
||||
switch (stmt->Tag()) {
|
||||
case Statement::Kind::Match: {
|
||||
const auto& match = cast<Match>(*stmt);
|
||||
std::vector<std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>>
|
||||
auto& match = cast<Match>(*stmt);
|
||||
std::vector<std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>>
|
||||
new_clauses;
|
||||
for (const auto& clause : match.Clauses()) {
|
||||
auto s = CheckOrEnsureReturn(clause.second, omitted_ret_type,
|
||||
@@ -810,7 +807,7 @@ auto TypeChecker::CheckOrEnsureReturn(
|
||||
CheckOrEnsureReturn(cast<Block>(*stmt).Stmt(), omitted_ret_type,
|
||||
stmt->SourceLoc()));
|
||||
case Statement::Kind::If: {
|
||||
const auto& if_stmt = cast<If>(*stmt);
|
||||
auto& if_stmt = cast<If>(*stmt);
|
||||
return arena->New<If>(
|
||||
stmt->SourceLoc(), if_stmt.Cond(),
|
||||
CheckOrEnsureReturn(if_stmt.ThenStmt(), omitted_ret_type,
|
||||
@@ -821,7 +818,7 @@ auto TypeChecker::CheckOrEnsureReturn(
|
||||
case Statement::Kind::Return:
|
||||
return stmt;
|
||||
case Statement::Kind::Sequence: {
|
||||
const auto& seq = cast<Sequence>(*stmt);
|
||||
auto& seq = cast<Sequence>(*stmt);
|
||||
if (seq.Next()) {
|
||||
return arena->New<Sequence>(
|
||||
stmt->SourceLoc(), seq.Stmt(),
|
||||
@@ -857,9 +854,8 @@ auto TypeChecker::CheckOrEnsureReturn(
|
||||
// a function.
|
||||
// TODO: Add checking to function definitions to ensure that
|
||||
// all deduced type parameters will be deduced.
|
||||
auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
|
||||
Env values)
|
||||
-> Nonnull<const FunctionDefinition*> {
|
||||
auto TypeChecker::TypeCheckFunDef(FunctionDefinition* f, TypeEnv types,
|
||||
Env values) -> Nonnull<FunctionDefinition*> {
|
||||
// Bring the deduced parameters into scope
|
||||
for (const auto& deduced : f->deduced_parameters()) {
|
||||
// auto t = interpreter.InterpExp(values, deduced.type);
|
||||
@@ -877,7 +873,7 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
|
||||
return_type);
|
||||
// TODO: Check that main doesn't have any parameters.
|
||||
}
|
||||
std::optional<Nonnull<const Statement*>> body_stmt;
|
||||
std::optional<Nonnull<Statement*>> body_stmt;
|
||||
if (f->body()) {
|
||||
auto res = TypeCheckStmt(*f->body(), param_res.types, values, return_type,
|
||||
f->is_omitted_return_type());
|
||||
@@ -892,7 +888,7 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeOfFunDef(TypeEnv types, Env values,
|
||||
const FunctionDefinition* fun_def)
|
||||
FunctionDefinition* fun_def)
|
||||
-> Nonnull<const Value*> {
|
||||
// Bring the deduced parameters into scope
|
||||
for (const auto& deduced : fun_def->deduced_parameters()) {
|
||||
@@ -961,9 +957,8 @@ static auto GetName(const Declaration& d) -> const std::string& {
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeChecker::MakeTypeChecked(const Nonnull<const Declaration*> d,
|
||||
const TypeEnv& types, const Env& values)
|
||||
-> Nonnull<const Declaration*> {
|
||||
auto TypeChecker::MakeTypeChecked(Nonnull<Declaration*> d, const TypeEnv& types,
|
||||
const Env& values) -> Nonnull<Declaration*> {
|
||||
switch (d->Tag()) {
|
||||
case Declaration::Kind::FunctionDeclaration:
|
||||
return arena->New<FunctionDeclaration>(TypeCheckFunDef(
|
||||
@@ -990,7 +985,7 @@ auto TypeChecker::MakeTypeChecked(const Nonnull<const Declaration*> d,
|
||||
return d;
|
||||
|
||||
case Declaration::Kind::VariableDeclaration: {
|
||||
const auto& var = cast<VariableDeclaration>(*d);
|
||||
auto& var = cast<VariableDeclaration>(*d);
|
||||
// Signals a type error if the initializing expression does not have
|
||||
// the declared type of the variable, otherwise returns this
|
||||
// declaration with annotated types.
|
||||
@@ -1012,19 +1007,19 @@ auto TypeChecker::MakeTypeChecked(const Nonnull<const Declaration*> d,
|
||||
}
|
||||
}
|
||||
|
||||
void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
switch (d.Tag()) {
|
||||
void TypeChecker::TopLevel(Nonnull<Declaration*> d, TypeCheckContext* tops) {
|
||||
switch (d->Tag()) {
|
||||
case Declaration::Kind::FunctionDeclaration: {
|
||||
const FunctionDefinition& func_def =
|
||||
cast<FunctionDeclaration>(d).Definition();
|
||||
FunctionDefinition& func_def = cast<FunctionDeclaration>(*d).Definition();
|
||||
auto t = TypeOfFunDef(tops->types, tops->values, &func_def);
|
||||
tops->types.Set(func_def.name(), t);
|
||||
interpreter.InitEnv(d, &tops->values);
|
||||
interpreter.InitEnv(*d, &tops->values);
|
||||
break;
|
||||
}
|
||||
|
||||
case Declaration::Kind::ClassDeclaration: {
|
||||
const ClassDefinition& class_def = cast<ClassDeclaration>(d).Definition();
|
||||
const ClassDefinition& class_def =
|
||||
cast<ClassDeclaration>(*d).Definition();
|
||||
auto st = TypeOfClassDef(&class_def, tops->types, tops->values);
|
||||
Address a = interpreter.AllocateValue(st);
|
||||
tops->values.Set(class_def.name, a); // Is this obsolete?
|
||||
@@ -1041,7 +1036,7 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
}
|
||||
|
||||
case Declaration::Kind::ChoiceDeclaration: {
|
||||
const auto& choice = cast<ChoiceDeclaration>(d);
|
||||
const auto& choice = cast<ChoiceDeclaration>(*d);
|
||||
VarValues alts;
|
||||
for (const auto& alternative : choice.Alternatives()) {
|
||||
auto t = interpreter.InterpExp(tops->values, &alternative.signature());
|
||||
@@ -1055,10 +1050,10 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
}
|
||||
|
||||
case Declaration::Kind::VariableDeclaration: {
|
||||
const auto& var = cast<VariableDeclaration>(d);
|
||||
auto& var = cast<VariableDeclaration>(*d);
|
||||
// Associate the variable name with it's declared type in the
|
||||
// compile-time symbol table.
|
||||
Nonnull<const Expression*> type =
|
||||
Nonnull<Expression*> type =
|
||||
cast<ExpressionPattern>(*var.Binding()->Type()).Expression();
|
||||
Nonnull<const Value*> declared_type =
|
||||
interpreter.InterpExp(tops->values, type);
|
||||
@@ -1068,16 +1063,16 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeChecker::TopLevel(const std::vector<Nonnull<const Declaration*>>& fs)
|
||||
auto TypeChecker::TopLevel(std::vector<Nonnull<Declaration*>>* fs)
|
||||
-> TypeCheckContext {
|
||||
TypeCheckContext tops(arena);
|
||||
bool found_main = false;
|
||||
|
||||
for (auto const& d : fs) {
|
||||
for (auto const& d : *fs) {
|
||||
if (GetName(*d) == "main") {
|
||||
found_main = true;
|
||||
}
|
||||
TopLevel(*d, &tops);
|
||||
TopLevel(d, &tops);
|
||||
}
|
||||
|
||||
if (found_main == false) {
|
||||
|
||||
@@ -32,35 +32,31 @@ class TypeChecker {
|
||||
Env values;
|
||||
};
|
||||
|
||||
auto MakeTypeChecked(const Nonnull<const Declaration*> d,
|
||||
const TypeEnv& types, const Env& values)
|
||||
-> Nonnull<const Declaration*>;
|
||||
auto MakeTypeChecked(Nonnull<Declaration*> d, const TypeEnv& types,
|
||||
const Env& values) -> Nonnull<Declaration*>;
|
||||
|
||||
auto TopLevel(const std::vector<Nonnull<const Declaration*>>& fs)
|
||||
-> TypeCheckContext;
|
||||
auto TopLevel(std::vector<Nonnull<Declaration*>>* fs) -> TypeCheckContext;
|
||||
|
||||
private:
|
||||
struct TCExpression {
|
||||
TCExpression(Nonnull<const Expression*> e, Nonnull<const Value*> t,
|
||||
TypeEnv types)
|
||||
TCExpression(Nonnull<Expression*> e, Nonnull<const Value*> t, TypeEnv types)
|
||||
: exp(e), type(t), types(types) {}
|
||||
|
||||
Nonnull<const Expression*> exp;
|
||||
Nonnull<Expression*> exp;
|
||||
Nonnull<const Value*> type;
|
||||
TypeEnv types;
|
||||
};
|
||||
|
||||
struct TCPattern {
|
||||
Nonnull<const Pattern*> pattern;
|
||||
Nonnull<Pattern*> pattern;
|
||||
Nonnull<const Value*> type;
|
||||
TypeEnv types;
|
||||
};
|
||||
|
||||
struct TCStatement {
|
||||
TCStatement(Nonnull<const Statement*> s, TypeEnv types)
|
||||
: stmt(s), types(types) {}
|
||||
TCStatement(Nonnull<Statement*> s, TypeEnv types) : stmt(s), types(types) {}
|
||||
|
||||
Nonnull<const Statement*> stmt;
|
||||
Nonnull<Statement*> stmt;
|
||||
TypeEnv types;
|
||||
};
|
||||
|
||||
@@ -75,14 +71,14 @@ class TypeChecker {
|
||||
// types maps variable names to the type of their run-time value.
|
||||
// values maps variable names to their compile-time values. It is not
|
||||
// directly used in this function but is passed to InterExp.
|
||||
auto TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types, Env values)
|
||||
auto TypeCheckExp(Nonnull<Expression*> e, TypeEnv types, Env values)
|
||||
-> TCExpression;
|
||||
|
||||
// Equivalent to TypeCheckExp, but operates on Patterns instead of
|
||||
// Expressions. `expected` is the type that this pattern is expected to have,
|
||||
// if the surrounding context gives us that information. Otherwise, it is
|
||||
// nullopt.
|
||||
auto TypeCheckPattern(Nonnull<const Pattern*> p, TypeEnv types, Env values,
|
||||
auto TypeCheckPattern(Nonnull<Pattern*> p, TypeEnv types, Env values,
|
||||
std::optional<Nonnull<const Value*>> expected)
|
||||
-> TCPattern;
|
||||
|
||||
@@ -93,33 +89,32 @@ class TypeChecker {
|
||||
// declared return type of the enclosing function definition. If the return
|
||||
// type is "auto", then the return type is inferred from the first return
|
||||
// statement.
|
||||
auto TypeCheckStmt(Nonnull<const Statement*> s, TypeEnv types, Env values,
|
||||
auto TypeCheckStmt(Nonnull<Statement*> s, TypeEnv types, Env values,
|
||||
Nonnull<const Value*>& ret_type, bool is_omitted_ret_type)
|
||||
-> TCStatement;
|
||||
|
||||
auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, Env values)
|
||||
-> Nonnull<const FunctionDefinition*>;
|
||||
auto TypeCheckFunDef(FunctionDefinition* f, TypeEnv types, Env values)
|
||||
-> Nonnull<FunctionDefinition*>;
|
||||
|
||||
auto TypeCheckCase(Nonnull<const Value*> expected,
|
||||
Nonnull<const Pattern*> pat,
|
||||
Nonnull<const Statement*> body, TypeEnv types, Env values,
|
||||
auto TypeCheckCase(Nonnull<const Value*> expected, Nonnull<Pattern*> pat,
|
||||
Nonnull<Statement*> body, TypeEnv types, Env values,
|
||||
Nonnull<const Value*>& ret_type, bool is_omitted_ret_type)
|
||||
-> std::pair<Nonnull<const Pattern*>, Nonnull<const Statement*>>;
|
||||
-> std::pair<Nonnull<Pattern*>, Nonnull<Statement*>>;
|
||||
|
||||
auto TypeOfFunDef(TypeEnv types, Env values,
|
||||
const FunctionDefinition* fun_def) -> Nonnull<const Value*>;
|
||||
auto TypeOfFunDef(TypeEnv types, Env values, FunctionDefinition* fun_def)
|
||||
-> Nonnull<const Value*>;
|
||||
auto TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/, Env ct_top)
|
||||
-> Nonnull<const Value*>;
|
||||
|
||||
void TopLevel(const Declaration& d, TypeCheckContext* tops);
|
||||
void TopLevel(Nonnull<Declaration*> d, TypeCheckContext* tops);
|
||||
|
||||
auto CheckOrEnsureReturn(std::optional<Nonnull<const Statement*>> opt_stmt,
|
||||
auto CheckOrEnsureReturn(std::optional<Nonnull<Statement*>> opt_stmt,
|
||||
bool omitted_ret_type, SourceLocation loc)
|
||||
-> Nonnull<const Statement*>;
|
||||
-> Nonnull<Statement*>;
|
||||
|
||||
// Reify type to type expression.
|
||||
auto ReifyType(Nonnull<const Value*> t, SourceLocation loc)
|
||||
-> Nonnull<const Expression*>;
|
||||
-> Nonnull<Expression*>;
|
||||
|
||||
auto Substitute(TypeEnv dict, Nonnull<const Value*> type)
|
||||
-> Nonnull<const Value*>;
|
||||
|
||||
Reference in New Issue
Block a user