Skip to content

Commit

Permalink
Unify type bounds: basics
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Aug 16, 2024
1 parent 7208d33 commit cddf807
Show file tree
Hide file tree
Showing 9 changed files with 365 additions and 66 deletions.
6 changes: 4 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import { buildPackage } from './package/io'
import { resolveImports, setExports } from './phase/import-resolve'
import { resolveModuleScope } from './phase/module-resolve'
import { resolveName } from './phase/name-resolve'
import { setTopScopeType } from './phase/pub-type'
import { desugar1 } from './phase/sugar'
import { setTopScopeType } from './phase/top-scope-type'
import { collectTypeBounds } from './phase/type-bound'
import { unifyTypeBounds } from './phase/type-unify'
import { Context, eachModule, pathToId } from './scope'
import { Source } from './source'
import { assert } from './util/todo'
Expand Down Expand Up @@ -133,7 +134,8 @@ const phases = [
desugar1,
resolveName,
setTopScopeType,
collectTypeBounds
collectTypeBounds,
unifyTypeBounds
]
phases.forEach(f => eachModule(f, ctx))

Expand Down
5 changes: 3 additions & 2 deletions src/phase/name-resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { FnDef } from '../ast/statement'
import { Generic } from '../ast/type'
import { Context, Definition, DefinitionMap, addError, defKey, idToString } from '../scope'
import { duplicateDefError, genericError, notFoundError } from '../semantic/error'
import { makeConstType } from '../typecheck'
import { unreachable } from '../util/todo'

/**
Expand Down Expand Up @@ -49,7 +48,6 @@ export const resolveName = (node: AstNode, ctx: Context): void => {
case 'generic': {
addDef(defKey(node), node, ctx)
node.bounds.forEach(b => resolveName(b, ctx))
node.type = makeConstType({ kind: 'identifier', typeArgs: [], names: [node.name] })
break
}
case 'match-clause': {
Expand Down Expand Up @@ -88,6 +86,9 @@ export const resolveName = (node: AstNode, ctx: Context): void => {
break
}
case 'identifier': {
node.typeArgs.forEach(ta => {
return resolveName(ta, ctx)
})
const def = findById(node, ctx)
if (!def) {
addError(ctx, notFoundError(ctx, node, idToString(node)))
Expand Down
30 changes: 16 additions & 14 deletions src/phase/pub-type.ts → src/phase/top-scope-type.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { AstNode } from '../ast'
import { Identifier } from '../ast/operand'
import { Context } from '../scope'
import { makeConstType } from '../typecheck'
import { unitId } from '../typecheck/type'
import { makeInferredFromType, makeInferredType, makeTemplateType } from '../typecheck'
import { unitType } from '../typecheck/type'

/**
* Set known types of topScope nodes
* Set inferred types of topScope nodes
*/
export const setTopScopeType = (node: AstNode, ctx: Context) => {
switch (node.kind) {
Expand All @@ -16,20 +16,19 @@ export const setTopScopeType = (node: AstNode, ctx: Context) => {
case 'var-def': {
if (node.pattern.expr.kind !== 'name') break
const def = node.pattern.expr
def.type = makeConstType(node.varType!)
def.type = makeTemplateType(makeInferredFromType(node.varType!))
break
}
case 'fn-def': {
const generics = node.generics
if (node.instance) {
generics.push(...node.instance.generics)
}
node.type = makeConstType({
kind: 'fn-type',
parseNode: node.name.parseNode,
node.type = makeTemplateType({
kind: 'inferred-fn',
generics,
paramTypes: node.params.map(p => p.paramType!),
returnType: node.returnType ?? unitId
params: node.params.map(p => makeInferredFromType(p.paramType!)),
returnType: node.returnType ? makeInferredFromType(node.returnType) : unitType
})
break
}
Expand All @@ -42,13 +41,12 @@ export const setTopScopeType = (node: AstNode, ctx: Context) => {
typeArgs: [],
def: node
}
node.type = makeConstType(nodeId)
node.type = makeInferredFromType(nodeId)
node.variants.forEach(v => {
v.type = makeConstType({
kind: 'fn-type',
parseNode: node.name.parseNode,
v.type = makeTemplateType({
kind: 'inferred-fn',
generics: node.generics,
paramTypes: v.fieldDefs.map(f => f.fieldType),
params: v.fieldDefs.map(f => makeInferredFromType(f.fieldType)),
returnType: nodeId
})
})
Expand All @@ -57,8 +55,12 @@ export const setTopScopeType = (node: AstNode, ctx: Context) => {
case 'trait-def':
case 'impl-def': {
if (node.kind === 'impl-def' && node.forTrait) break
node.generics.forEach(g => setTopScopeType(g, ctx))
node.block.statements.forEach(s => setTopScopeType(s, ctx))
break
}
case 'generic': {
node.type = makeInferredType()
}
}
}
48 changes: 26 additions & 22 deletions src/phase/type-bound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { operatorImplMap } from '../semantic/op'
import {
InferredType,
addBounds,
instantiateConstType,
makeConstType,
instantiateTemplateType,
makeInferredFromType,
makeInferredType,
makeReturnType
} from '../typecheck'
import { boolId, charId, floatId, intId, stringId } from '../typecheck/type'
import { assert } from '../util/todo'
import { boolType, charType, floatType, intType, stringType } from '../typecheck/type'
import { assert, unreachable } from '../util/todo'
import { findById, findParent } from './name-resolve'

/**
Expand Down Expand Up @@ -83,9 +83,12 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
break
}
case 'param': {
// TODO: handle self
if (!node.paramType) break
const pType = makeConstType(node.paramType!)
collectTypeBounds(node.paramType, ctx)
const pType =
node.paramType.kind === 'identifier' && node.paramType.def
? node.paramType.def.type!
: makeInferredFromType(node.paramType)
addBounds(node.type!, [pType])
collectTypeBounds(node.pattern, ctx, pType)
break
Expand Down Expand Up @@ -122,16 +125,11 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
case 'name': {
if (node.def) {
assert(!!node.def.type)
node.type = instantiateConstType(node.def.type!)
node.type = instantiateTemplateType(node.def.type!)
break
}
break
}
case 'string-interpolated': {
node.tokens.filter(t => typeof t !== 'string').forEach(t => collectTypeBounds(t, ctx))
addBounds(node.type!, [makeConstType(stringId)])
break
}
case 'operand-expr': {
collectTypeBounds(node.operand, ctx)
node.type = node.operand.type
Expand All @@ -141,7 +139,7 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
collectTypeBounds(node.operand, ctx)
switch (node.op.kind) {
case 'call-op': {
const fnType = instantiateConstType(node.operand.type!)
const fnType = instantiateTemplateType(node.operand.type!)
node.op.args.forEach(a => collectTypeBounds(a, ctx))
addBounds(fnType, [boundFromCall(node.op.args.map(a => a.type!))])
node.type = makeReturnType(fnType)
Expand All @@ -165,7 +163,7 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
assert(!!methodId)
const methodDef = findById(methodId!, ctx)
assert(!!methodDef)
const fnType = instantiateConstType(methodDef!.type!)
const fnType = instantiateTemplateType(methodDef!.type!)
addBounds(fnType, [boundFromCall([node.lOperand.type!, node.rOperand.type!])])
node.type = makeReturnType(fnType)
break
Expand All @@ -192,17 +190,18 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
}
case 'var-def': {
if (node.expr) {
collectTypeBounds(node.expr, ctx, node.varType ? makeConstType(node.varType) : undefined)
collectTypeBounds(node.expr, ctx, node.varType ? makeInferredFromType(node.varType) : undefined)
}
collectTypeBounds(node.pattern, ctx, node.expr?.type)
break
}
case 'fn-def': {
node.generics.forEach(g => collectTypeBounds(g, ctx))
node.params.forEach(p => collectTypeBounds(p, ctx))
if (node.block) {
collectTypeBounds(node.block, ctx)
if (node.type?.kind !== 'template' || node.type.type.kind !== 'inferred-fn') return unreachable()
collectTypeBounds(node.block, ctx, node.type.type.returnType)
}
// TODO
break
}
case 'trait-def': {
Expand All @@ -213,24 +212,29 @@ export const collectTypeBounds = (node: AstNode, ctx: Context, parentBound?: Inf
// TODO
break
}
case 'string-interpolated': {
node.tokens.filter(t => typeof t !== 'string').forEach(t => collectTypeBounds(t, ctx))
node.type = instantiateTemplateType(stringType)
break
}
case 'string-literal': {
node.type = makeConstType(stringId)
node.type = instantiateTemplateType(stringType)
break
}
case 'char-literal': {
node.type = makeConstType(charId)
node.type = instantiateTemplateType(charType)
break
}
case 'int-literal': {
node.type = makeConstType(intId)
node.type = instantiateTemplateType(intType)
break
}
case 'float-literal': {
node.type = makeConstType(floatId)
node.type = instantiateTemplateType(floatType)
break
}
case 'bool-literal': {
node.type = makeConstType(boolId)
node.type = instantiateTemplateType(boolType)
break
}
case 'method-call-op': {
Expand Down
Loading

0 comments on commit cddf807

Please sign in to comment.