From 2f15a64a6be8b557eec6f148b3801ef51823819b Mon Sep 17 00:00:00 2001 From: Jon Meow <46229924+jonmeow@users.noreply.github.com> Date: Wed, 3 Nov 2021 10:36:12 -0700 Subject: [PATCH] Move a little logic into TypeChecker to narrow what's exposed. (#938) --- executable_semantics/interpreter/BUILD | 1 + .../interpreter/exec_program.cpp | 8 +---- .../interpreter/type_checker.cpp | 28 +++++++++-------- .../interpreter/type_checker.h | 30 ++++++++++++++----- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/executable_semantics/interpreter/BUILD b/executable_semantics/interpreter/BUILD index 52bc69821248..0fda71102108 100644 --- a/executable_semantics/interpreter/BUILD +++ b/executable_semantics/interpreter/BUILD @@ -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", diff --git a/executable_semantics/interpreter/exec_program.cpp b/executable_semantics/interpreter/exec_program.cpp index ee5deb61aac4..a282a8475918 100644 --- a/executable_semantics/interpreter/exec_program.cpp +++ b/executable_semantics/interpreter/exec_program.cpp @@ -50,13 +50,7 @@ void ExecProgram(Nonnull 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"; diff --git a/executable_semantics/interpreter/type_checker.cpp b/executable_semantics/interpreter/type_checker.cpp index 634edde6290b..7e70c36ce26a 100644 --- a/executable_semantics/interpreter/type_checker.cpp +++ b/executable_semantics/interpreter/type_checker.cpp @@ -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 param, - Nonnull arg) -> TypeEnv { +auto TypeChecker::ArgumentDeduction(SourceLocation source_loc, TypeEnv deduced, + Nonnull param, + Nonnull arg) -> TypeEnv { switch (param->kind()) { case Value::Kind::VariableType: { const auto& var_type = cast(*param); @@ -1140,8 +1134,18 @@ static auto GetName(const Declaration& d) -> const std::string& { } } -void TypeChecker::TypeCheck(Nonnull 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 d, + const TypeEnv& types, + const Env& values) { switch (d->kind()) { case Declaration::Kind::FunctionDeclaration: TypeCheckFunDef(&cast(*d), types, values); diff --git a/executable_semantics/interpreter/type_checker.h b/executable_semantics/interpreter/type_checker.h index ab82888fbabc..467c430f66f2 100644 --- a/executable_semantics/interpreter/type_checker.h +++ b/executable_semantics/interpreter/type_checker.h @@ -8,6 +8,7 @@ #include #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>; - class TypeChecker { public: explicit TypeChecker(Nonnull arena, bool trace) : arena_(arena), interpreter_(arena, trace), trace_(trace) {} + void TypeCheck(AST& ast); + + private: + using TypeEnv = Dictionary>; + struct TypeCheckContext { explicit TypeCheckContext(Nonnull arena) : types(arena), values(arena) {} @@ -33,12 +37,6 @@ class TypeChecker { Env values; }; - void TypeCheck(Nonnull d, const TypeEnv& types, - const Env& values); - - auto TopLevel(std::vector>* 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 param, + Nonnull 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> expected) -> TCResult; + void TypeCheckDeclaration(Nonnull 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; + auto TopLevel(std::vector>* fs) -> TypeCheckContext; void TopLevel(Nonnull d, TypeCheckContext* tops); // Verifies that opt_stmt holds a statement, and it is structurally impossible