Move a little logic into TypeChecker to narrow what's exposed. (#938)

This commit is contained in:
Jon Meow
2021-11-03 10:36:12 -07:00
committed by GitHub
parent 27e084d37a
commit 2f15a64a6b
4 changed files with 40 additions and 27 deletions
+1
View File
@@ -155,6 +155,7 @@ cc_library(
":dictionary",
":interpreter",
"//common:ostream",
"//executable_semantics/ast",
"//executable_semantics/ast:declaration",
"//executable_semantics/ast:expression",
"//executable_semantics/ast:statement",
@@ -50,13 +50,7 @@ void ExecProgram(Nonnull<Arena*> arena, AST ast, bool trace) {
// (particularly templates) may require more passes.
ResolveNames(arena, ast);
ResolveControlFlow(ast);
TypeChecker type_checker(arena, trace);
TypeChecker::TypeCheckContext p = type_checker.TopLevel(&ast.declarations);
TypeEnv top = p.types;
Env ct_top = p.values;
for (const auto decl : ast.declarations) {
type_checker.TypeCheck(decl, top, ct_top);
}
TypeChecker(arena, trace).TypeCheck(ast);
if (trace) {
llvm::outs() << "\n";
llvm::outs() << "********** type checking complete **********\n";
@@ -75,7 +75,7 @@ TypeChecker::ReturnTypeContext::ReturnTypeContext(
: std::optional(orig_return_type)),
is_omitted_(is_omitted) {}
void PrintTypeEnv(TypeEnv types, llvm::raw_ostream& out) {
void TypeChecker::PrintTypeEnv(TypeEnv types, llvm::raw_ostream& out) {
llvm::ListSeparator sep;
for (const auto& [name, type] : types) {
out << sep << name << ": " << *type;
@@ -238,15 +238,9 @@ static void ExpectType(SourceLocation source_loc, const std::string& context,
}
}
// Perform type argument deduction, matching the parameter type `param`
// against the argument type `arg`. Whenever there is an VariableType
// in the parameter type, it is deduced to be the corresponding type
// inside the argument type.
// The `deduced` parameter is an accumulator, that is, it holds the
// results so-far.
static auto ArgumentDeduction(SourceLocation source_loc, TypeEnv deduced,
Nonnull<const Value*> param,
Nonnull<const Value*> arg) -> TypeEnv {
auto TypeChecker::ArgumentDeduction(SourceLocation source_loc, TypeEnv deduced,
Nonnull<const Value*> param,
Nonnull<const Value*> arg) -> TypeEnv {
switch (param->kind()) {
case Value::Kind::VariableType: {
const auto& var_type = cast<VariableType>(*param);
@@ -1140,8 +1134,18 @@ static auto GetName(const Declaration& d) -> const std::string& {
}
}
void TypeChecker::TypeCheck(Nonnull<Declaration*> d, const TypeEnv& types,
const Env& values) {
void TypeChecker::TypeCheck(AST& ast) {
TypeCheckContext p = TopLevel(&ast.declarations);
TypeEnv top = p.types;
Env ct_top = p.values;
for (const auto decl : ast.declarations) {
TypeCheckDeclaration(decl, top, ct_top);
}
}
void TypeChecker::TypeCheckDeclaration(Nonnull<Declaration*> d,
const TypeEnv& types,
const Env& values) {
switch (d->kind()) {
case Declaration::Kind::FunctionDeclaration:
TypeCheckFunDef(&cast<FunctionDeclaration>(*d), types, values);
@@ -8,6 +8,7 @@
#include <set>
#include "common/ostream.h"
#include "executable_semantics/ast/ast.h"
#include "executable_semantics/ast/expression.h"
#include "executable_semantics/ast/statement.h"
#include "executable_semantics/common/nonnull.h"
@@ -16,13 +17,16 @@
namespace Carbon {
using TypeEnv = Dictionary<std::string, Nonnull<const Value*>>;
class TypeChecker {
public:
explicit TypeChecker(Nonnull<Arena*> arena, bool trace)
: arena_(arena), interpreter_(arena, trace), trace_(trace) {}
void TypeCheck(AST& ast);
private:
using TypeEnv = Dictionary<std::string, Nonnull<const Value*>>;
struct TypeCheckContext {
explicit TypeCheckContext(Nonnull<Arena*> arena)
: types(arena), values(arena) {}
@@ -33,12 +37,6 @@ class TypeChecker {
Env values;
};
void TypeCheck(Nonnull<Declaration*> d, const TypeEnv& types,
const Env& values);
auto TopLevel(std::vector<Nonnull<Declaration*>>* fs) -> TypeCheckContext;
private:
// Context about the return type, which may be updated during type checking.
class ReturnTypeContext {
public:
@@ -76,6 +74,18 @@ class TypeChecker {
TypeEnv types;
};
static void PrintTypeEnv(TypeEnv types, llvm::raw_ostream& out);
// Perform type argument deduction, matching the parameter type `param`
// against the argument type `arg`. Whenever there is an VariableType
// in the parameter type, it is deduced to be the corresponding type
// inside the argument type.
// The `deduced` parameter is an accumulator, that is, it holds the
// results so-far.
static auto ArgumentDeduction(SourceLocation source_loc, TypeEnv deduced,
Nonnull<const Value*> param,
Nonnull<const Value*> arg) -> TypeEnv;
// TypeCheckExp performs semantic analysis on an expression. It returns a new
// version of the expression, its type, and an updated environment which are
// bundled into a TCResult object. The purpose of the updated environment is
@@ -98,6 +108,9 @@ class TypeChecker {
std::optional<Nonnull<const Value*>> expected)
-> TCResult;
void TypeCheckDeclaration(Nonnull<Declaration*> d, const TypeEnv& types,
const Env& values);
// TypeCheckStmt performs semantic analysis on a statement. It returns a new
// version of the statement and a new type environment.
//
@@ -122,6 +135,7 @@ class TypeChecker {
auto TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/, Env ct_top)
-> Nonnull<const Value*>;
auto TopLevel(std::vector<Nonnull<Declaration*>>* fs) -> TypeCheckContext;
void TopLevel(Nonnull<Declaration*> d, TypeCheckContext* tops);
// Verifies that opt_stmt holds a statement, and it is structurally impossible