Skip to content

Commit

Permalink
TypeScript: turn on strictNullChecks
Browse files Browse the repository at this point in the history
  • Loading branch information
joews committed Mar 13, 2017
1 parent 0f6d66a commit d3b8dc4
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type Visitor = (node: TypedNode, env: RuntimeEnv) => InterpreterResult
// Visit each of `nodes` in order, returning the result
// and environment of the last node.
function visitSerial (nodes: TypedNode[], rootEnv: RuntimeEnv): InterpreterResult {
const initialState: [TypedNode, RuntimeEnv] = [null, rootEnv]
const initialState: [TypedNode, RuntimeEnv] = [nodes[0], rootEnv]
return nodes.reduce(([, env], node) => (
visit(node, env)
), initialState)
Expand Down
16 changes: 16 additions & 0 deletions src/node-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type AstNode
| AstFunctionNode
| AstFunctionClauseNode
| AstIfNode
| AstDefPreValueNode

// Typed*: type checker output. AST nodes augmented with Peach static types.
export type TypedNode
Expand All @@ -40,6 +41,7 @@ export type TypedNode
| TypedFunctionNode
| TypedFunctionClauseNode
| TypedIfNode
| TypedDefPreValueNode

export interface Typed {
exprType: Type
Expand Down Expand Up @@ -156,6 +158,20 @@ export interface TypedIfNode extends AstIfNode, Typed {
elseBranch: TypedNode
}

//
// Pseudo-node types
//

// A special marker pseudo-node used to represent the value of a
// `Def` node during type checking, before descending into the value itself.
// We only need the Typed variant, but the Ast*Node is required to maintain
// the AstNode -> TypedNode mapping.
export interface AstDefPreValueNode {
type: 'DefPreValue'
}

export interface TypedDefPreValueNode extends Typed, AstDefPreValueNode { }

//
// Nodes with shared traits
//
Expand Down
20 changes: 14 additions & 6 deletions src/type-checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
AstDestructuredArrayNode, AstFunctionNode, AstIfNode,
TypedAst, TypedNode, TypedProgramNode, TypedDefNode, TypedNameNode,
TypedNumeralNode, TypedBooleanNode, TypedStringNode, TypedCallNode, TypedArrayNode,
TypedDestructuredArrayNode, TypedFunctionNode, TypedFunctionClauseNode, TypedIfNode
TypedDestructuredArrayNode, TypedFunctionNode, TypedFunctionClauseNode, TypedIfNode,
TypedDefPreValueNode
} from './node-types'

import {
Expand Down Expand Up @@ -89,12 +90,17 @@ function visitDef (node: AstDefNode, env: TypeEnv, nonGeneric: Set<Type>): TypeC
throw new PeachError(`${node.name} has already been defined`)
}

// allow for recursive binding by binding ahead of evaluating the child
// analogous to Lisp's letrec, but in the enclosing scope. We don't know
// the value or concrete type yet.
// TODO immutable env
// Allow for recursive binding by binding ahead of evaluating the child
// analogous to Lisp's letrec, but in the enclosing scope. We don't know
// the value or concrete type yet.
// The binding must be created before visiting the value (in case the value
// is a recursive function). We can't create a TypedEnv value for the def
// value without visiting it, so bind a temporary value with a new TypeVariable.
// Once the value is visited, unify the placeholder type and the concrete value
// type. The TypeEnv only really cares about the type of its values so we can
// continue to use the typed stub.
const t = new TypeVariable()
const typedStubNode: TypedDefNode = { ...node, value: null, exprType: t }
const typedStubNode: TypedDefPreValueNode = { type: 'DefPreValue', exprType: t }
env[node.name] = typedStubNode

// if we are defining a function, mark the new identifier as
Expand Down Expand Up @@ -294,6 +300,8 @@ function fresh (type: Type, nonGeneric: Set<Type>) {

// FIXME find out how to do this with type safety, given type erasure.
return (pruned.constructor as any).of(pruned.name, freshTypeArgs)
} else {
return t
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export class TypeVariable extends Type {
instance: Type

constructor () {
super(null)
super('')
this.id = TypeVariable.nextId ++
}

Expand Down
6 changes: 3 additions & 3 deletions src/unify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { isArray, isEqual } from './array'
import { zip } from './util'
import { AstNode, AstLiteralNode, AstDestructuredArrayNode, Value, isAstLiteralNode } from './node-types'

// FIXME tagged union - with didMatch: false, there are never bindings.
// FIXME tagged union - with didMatch: false, there are never bindings (hence binding | null return types)
type binding = { [name: string]: Value }

interface unification {
Expand All @@ -29,7 +29,7 @@ export default function unify (patterns: AstNode[], values: Value[]): unificatio
return didMatch(bindings)
}

function unifyOne (pattern: AstNode, value: Value): binding {
function unifyOne (pattern: AstNode, value: Value): binding | null {
if (isAstLiteralNode(pattern) && pattern.value === value) {
// the pattern matched, but there is nothing to bind
return {}
Expand All @@ -54,7 +54,7 @@ function unifyOne (pattern: AstNode, value: Value): binding {
}

// TODO this will need to change when Array is a wrapped type
function destructure ({ head, tail }: AstDestructuredArrayNode, values: Value[]): binding {
function destructure ({ head, tail }: AstDestructuredArrayNode, values: Value[]): binding | null {
if (values.length === 0) {
throw new PeachError(`Empty arrays cannot be destructured because they don't have a head`)
}
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"target": "es2017",
"sourceMap": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true
},
Expand Down

0 comments on commit d3b8dc4

Please sign in to comment.