Skip to content

Commit

Permalink
Unify types: field patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Nov 25, 2024
1 parent 72ad08d commit 361c540
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 46 deletions.
66 changes: 32 additions & 34 deletions src/phase/type-bound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { opFnIdMap } from '../semantic/op'
import {
InferredType,
addBounds,
boundFromCall,
makeCallTypeFromArgs,
instantiateType,
makeErrorType,
makeFieldPatternType,
Expand Down Expand Up @@ -100,35 +100,6 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
// TODO
break
}
case 'match-clause': {
node.type = makeInferredType()
node.patterns.forEach(p => collectTypeBounds(p, ctx, parentBound))
collectTypeBounds(node.block, ctx)
addBounds(node.type!, [node.block.type!])
// TODO
break
}
case 'pattern': {
collectTypeBounds(node.expr, ctx, parentBound)
break
}
case 'con-pattern': {
node.fieldPatterns.forEach(fp => collectTypeBounds(fp, ctx, parentBound))
break
}
case 'field-pattern': {
assert(!!parentBound)
node.name.type = makeFieldPatternType(parentBound!, node)
break
}
case 'list-pattern': {
// TODO
break
}
case 'hole': {
// TODO
break
}
case 'identifier':
case 'name': {
if (node.def) {
Expand All @@ -140,8 +111,7 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
break
} else {
// no def means it *is* the definition
assert(!!parentBound)
node.type = parentBound
node.type = parentBound ?? makeErrorType('no def', 'no-def')
}
break
}
Expand All @@ -156,7 +126,7 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
case 'call-op': {
const fnType = makeInferredType([instantiateType(node.operand.type!, ctx)])
node.op.args.forEach(a => collectTypeBounds(a, ctx))
addBounds(fnType, [boundFromCall(node.op.args)])
addBounds(fnType, [makeCallTypeFromArgs(node.op.args)])
node.type = makeReturnType(fnType)
break
}
Expand Down Expand Up @@ -185,7 +155,7 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
const opFnDef = findById(opFn!, ctx, ['value'])
assert(!!opFnDef, `${idToString(opFn!)} not found`)
const fnType = makeInferredType([instantiateType(opFnDef!.type!, ctx)])
addBounds(fnType, [boundFromCall([node.lOperand, node.rOperand])])
addBounds(fnType, [makeCallTypeFromArgs([node.lOperand, node.rOperand])])
node.type = makeReturnType(fnType)
break
}
Expand All @@ -210,6 +180,34 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
)
break
}
case 'match-clause': {
node.type = makeInferredType()
node.patterns.forEach(p => collectTypeBounds(p, ctx, parentBound))
collectTypeBounds(node.block, ctx)
addBounds(node.type!, [node.block.type!])
break
}
case 'pattern': {
collectTypeBounds(node.expr, ctx, parentBound)
break
}
case 'con-pattern': {
node.fieldPatterns.forEach(fp => collectTypeBounds(fp, ctx, parentBound))
break
}
case 'field-pattern': {
assert(!!parentBound)
node.name.type = makeFieldPatternType(parentBound!, node)
break
}
case 'list-pattern': {
// TODO
break
}
case 'hole': {
// TODO
break
}
case 'var-def': {
if (node.expr) {
collectTypeBounds(node.expr, ctx, node.varType ? node.varType : undefined)
Expand Down
27 changes: 16 additions & 11 deletions src/phase/type-unify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
InferredType,
inferredTypeToString,
instantiateType,
makeCallTypeFromArgTypes,
makeErrorType,
makeInferredType,
makeReturnType
} from '../typecheck'
import { dedup, zip } from '../util/array'
Expand Down Expand Up @@ -50,10 +52,6 @@ export const unifyTypeBounds = (node: AstNode, ctx: Context, report = true): voi
// TODO
break
}
case 'match-clause': {
// TODO
break
}
case 'pattern': {
unifyTypeBounds(node.expr, ctx)
break
Expand Down Expand Up @@ -119,7 +117,16 @@ export const unifyTypeBounds = (node: AstNode, ctx: Context, report = true): voi
break
}
case 'match-expr': {
// TODO
unifyTypeBounds(node.expr, ctx)
node.clauses.forEach(clause => unifyTypeBounds(clause, ctx))
break
}
case 'match-clause': {
node.patterns.forEach(p => unifyTypeBounds(p, ctx))
if (node.guard) {
unifyTypeBounds(node.guard, ctx)
}
unifyTypeBounds(node.block, ctx)
break
}
case 'var-def': {
Expand All @@ -140,10 +147,6 @@ export const unifyTypeBounds = (node: AstNode, ctx: Context, report = true): voi
node.block.statements.forEach(s => unifyTypeBounds(s, ctx))
break
}
case 'compose-op': {
// TODO
break
}
}
if (node.type && report) {
reportTypeErrors(ctx, node, node.type)
Expand Down Expand Up @@ -172,8 +175,10 @@ export const unifyType = (type: InferredType, ctx: Context): void => {
break
}
assert(!!f.type, `field has no type: ${inferredTypeToString(type.operandType)}.${f.name.value}`)
const fType = makeReturnType(instantiateType(f.type!, ctx))
const u = unify(type.operandType, fType!, ctx)
const u = makeReturnType(
makeInferredType([makeCallTypeFromArgTypes([type.operandType]), instantiateType(f.type!, ctx)])
)
unifyType(u, ctx)
assign(type, u)
break
}
Expand Down
11 changes: 10 additions & 1 deletion src/typecheck/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export const addBounds = (type: InferredType, bounds: InferredType[]): void => {
assert(false, `adding bounds to kind ${type.kind}`)
}

export const boundFromCall = (args: AstNode[]): InferredType => {
export const makeCallTypeFromArgs = (args: AstNode[]): InferredType => {
return {
kind: 'inferred-fn',
typeParams: [],
Expand All @@ -199,3 +199,12 @@ export const boundFromCall = (args: AstNode[]): InferredType => {
returnType: { kind: 'hole' }
}
}

export const makeCallTypeFromArgTypes = (args: InferredType[]): InferredType => {
return {
kind: 'inferred-fn',
typeParams: [],
params: args.map(type => ({ type })),
returnType: { kind: 'hole' }
}
}

0 comments on commit 361c540

Please sign in to comment.