Skip to content

Commit

Permalink
Semantic: set type of trait-statement; update operatorImplMap
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Nov 22, 2024
1 parent 3d9c140 commit 3006098
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 40 deletions.
4 changes: 2 additions & 2 deletions src/phase/impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FnDef } from '../ast/statement'
import { emitParseNode } from '../codegen/declaration'
import { Context, addError, idToString } from '../scope'
import { genericError, typeError } from '../semantic/error'
import { instantiateDefType } from '../typecheck'
import { instantiateType } from '../typecheck'
import { assert } from '../util/todo'
import { findTypeErrors, unify } from './type-unify'

Expand Down Expand Up @@ -45,7 +45,7 @@ export const checkImpl = (node: AstNode, ctx: Context): void => {
assert(!!im.type)
assert(!!traitMethod.type)
// TODO: handle unify of 'fn-type's specifically for this case (get rid of `instantiateDefType`)
const t = unify(instantiateDefType(im.type!, ctx), instantiateDefType(traitMethod.type!, ctx), ctx)
const t = unify(instantiateType(im.type!, ctx), instantiateType(traitMethod.type!, ctx), ctx)
findTypeErrors(t).forEach(e => {
if (e.error.reported) return
// TODO: don't print method body
Expand Down
2 changes: 0 additions & 2 deletions src/phase/sugar.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { AstNode } from '../ast'
import { UnaryExpr } from '../ast/expr'
import { printAst } from '../debug'
import { Context, addError, idFromString } from '../scope'
import { genericError } from '../semantic/error'
import { assign } from '../util/object'
Expand Down Expand Up @@ -196,7 +195,6 @@ export const desugarComposeOp = (node: UnaryExpr, ctx: Context) => {
}
assign(node, newNode)
} else {
printAst(node)
addError(ctx, genericError(ctx, node, 'unknown `compose-op` structure'), true)
}
}
17 changes: 14 additions & 3 deletions src/phase/top-scope-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ export const setTopScopeType = (node: AstNode, ctx: Context) => {
case 'fn-def': {
node.typeParams.forEach(g => setTopScopeType(g, ctx))
node.params.forEach(p => setTopScopeType(p, ctx))
assert(!!node.returnType)
setTopScopeType(node.returnType!, ctx)
if (node.returnType) {
setTopScopeType(node.returnType!, ctx)
}
node.type = {
kind: 'fn-type',
typeParams: node.typeParams,
paramTypes: node.params.map(paramToParamType),
returnType: node.returnType!
returnType: node.returnType ?? ctx.stdTypeIds.unit!
}
break
}
Expand Down Expand Up @@ -102,6 +103,11 @@ export const setTopScopeType = (node: AstNode, ctx: Context) => {
node.block.statements.forEach(s => setTopScopeType(s, ctx))
break
}
case 'trait-statement': {
setTopScopeType(node.expr, ctx)
node.type = node.expr.type
break
}
case 'param': {
assert(!!node.paramType)
setTopScopeType(node.paramType!, ctx)
Expand All @@ -127,6 +133,11 @@ export const setTopScopeType = (node: AstNode, ctx: Context) => {
node.type = node
break
}
case 'param-type': {
setTopScopeType(node.paramType, ctx)
node.type = node.paramType.type
break
}
case 'hole': {
node.type = { kind: 'hole' }
break
Expand Down
31 changes: 15 additions & 16 deletions src/phase/type-bound.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { inspect } from 'util'
import { AstNode } from '../ast'
import { FnDef } from '../ast/operand'
import { Context } from '../scope'
import { Context, idToString } from '../scope'
import { operatorImplMap } from '../semantic/op'
import {
InferredType,
addBounds,
boundFromCall,
instantiateDefType as instantiateType,
instantiateType,
makeErrorType,
makeFieldPatternType,
makeInferredType,
Expand Down Expand Up @@ -93,7 +92,8 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
break
}
case 'param': {
collectTypeBounds(node.pattern, ctx, instantiateType(node.paramType!.type!, ctx))
const type = node.paramType ? node.paramType.type! : makeInferredType()
collectTypeBounds(node.pattern, ctx, instantiateType(type, ctx))
break
}
case 'type-param': {
Expand Down Expand Up @@ -132,8 +132,11 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
case 'identifier':
case 'name': {
if (node.def) {
assert(!!node.def.type, `no def type ${inspect(node.def)}`)
node.type = instantiateType(node.def.type!, ctx)
if (node.def.type) {
node.type = instantiateType(node.def.type, ctx)
} else {
node.type = node
}
break
} else {
node.type = makeInferredType()
Expand Down Expand Up @@ -178,11 +181,11 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
}
collectTypeBounds(node.lOperand, ctx)
collectTypeBounds(node.rOperand, ctx)
const methodId = operatorImplMap.get(node.op.kind)
assert(!!methodId)
const methodDef = findById(methodId!, ctx)
assert(!!methodDef)
const fnType = instantiateType(methodDef!.type!, ctx)
const opFn = operatorImplMap.get(node.op.kind)
assert(!!opFn)
const opFnDef = findById(opFn!, ctx)
assert(!!opFnDef, `${idToString(opFn!)} not found`)
const fnType = makeInferredType([instantiateType(opFnDef!.type!, ctx)])
addBounds(fnType, [boundFromCall([node.lOperand.type!, node.rOperand.type!])])
node.type = makeReturnType(fnType)
break
Expand Down Expand Up @@ -220,11 +223,7 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
node.typeParams.forEach(g => collectTypeBounds(g, ctx))
node.params.forEach(p => collectTypeBounds(p, ctx))
if (node.block) {
if (node.type?.kind !== 'fn-type') {
unreachable()
break
}
collectTypeBounds(node.block, ctx, node.type.returnType.type)
collectTypeBounds(node.block, ctx, makeReturnType(node.type!))
}
break
}
Expand Down
8 changes: 2 additions & 6 deletions src/phase/type-unify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const unifyTypeBounds = (node: AstNode, ctx: Context, report = true): voi
unifyTypeBounds(node.pattern, ctx)
break
}
case 'generic': {
case 'type-param': {
// TODO
break
}
Expand Down Expand Up @@ -99,10 +99,6 @@ export const unifyTypeBounds = (node: AstNode, ctx: Context, report = true): voi
unifyTypeBounds(node.rOperand, ctx)
break
}
case 'closure-expr': {
// TODO
break
}
case 'list-expr': {
// TODO
break
Expand Down Expand Up @@ -252,7 +248,7 @@ const unify_ = (a: InferredType, b: InferredType, ctx: Context): InferredType =>
const t: InferredType = {
kind: 'inferred-fn',
// TODO
generics: [],
typeParams: [],
params: zip(a.params, b.params, (a_, b_) => unify(a_, b_, ctx)),
returnType: unify(a.returnType, b.returnType, ctx)
}
Expand Down
17 changes: 9 additions & 8 deletions src/semantic/op.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ import { Identifier } from '../ast/operand'
import { idFromString } from '../scope'

export const operatorImplMap: Map<AstNodeKind, Identifier> = new Map([
['add-op', idFromString('Int::add')],
['sub-op', idFromString('Int::sub')],
['mult-op', idFromString('Int::mult')],
['div-op', idFromString('Int::div')],
['exp-op', idFromString('Int::exp')],
['mod-op', idFromString('Int::mod')],
['add-op', idFromString('Num::add')],
['sub-op', idFromString('Num::sub')],
['mult-op', idFromString('Num::mult')],
['div-op', idFromString('Num::div')],
['exp-op', idFromString('Num::exp')],
['eq-op', idFromString('Eq::eq')],
['ne-op', idFromString('Eq::ne')],
['ge-op', idFromString('Ord::ge')],
['le-op', idFromString('Ord::le')],
['gt-op', idFromString('Ord::gt')],
['lt-op', idFromString('Ord::lt')],
['and-op', idFromString('Bool::and')],
['or-op', idFromString('Bool::or')]

['mod-op', idFromString('int::mod')],
['and-op', idFromString('bool::and')],
['or-op', idFromString('bool::or')]
])
9 changes: 6 additions & 3 deletions src/typecheck/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,17 @@ export const makeErrorType = (message?: string, errorKind: ErrorTypeKind = 'othe
}
})

export const instantiateDefType = <T extends InferredType>(t: T, ctx: Context): T => {
export const instantiateType = <T extends InferredType>(t: T, ctx: Context): T => {
switch (t.kind) {
case 'fn-type': {
const inst: FnType = {
kind: 'fn-type',
typeParams: t.typeParams.map(tp => ({ ...tp })),
paramTypes: t.paramTypes.map(pt => ({ ...pt, type: instantiateDefType(pt.type!, ctx) })),
returnType: instantiateDefType(t.returnType ?? ctx.stdTypeIds.unit, ctx)
paramTypes: t.paramTypes.map(pt => {
assert(!!pt.type)
return { ...pt, type: instantiateType(pt.type!, ctx) }
}),
returnType: instantiateType(t.returnType ?? ctx.stdTypeIds.unit, ctx)
}
return inst as any
}
Expand Down

0 comments on commit 3006098

Please sign in to comment.