Skip to content

Commit

Permalink
Type bounds: get rid of def type
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Sep 10, 2024
1 parent 76b50b2 commit 903d278
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 52 deletions.
3 changes: 1 addition & 2 deletions src/phase/std-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Identifier } from '../ast/operand'
import { findName } from '../phase/name-resolve'
import { Context, addError, idFromString } from '../scope'
import { notFoundError } from '../semantic/error'
import { makeDefType } from '../typecheck'

export type StdTypeIds = {
unit?: Identifier
Expand Down Expand Up @@ -55,7 +54,7 @@ export const setStdTypeIds = (node: AstNode, ctx: Context): void => {
return
}
id.def = def
id.type = makeDefType(def)
id.type = id
ctx.stdTypeIds[name] = id
})
}
11 changes: 7 additions & 4 deletions src/phase/top-scope-type.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AstNode } from '../ast'
import { Identifier } from '../ast/operand'
import { Context } from '../scope'
import { makeDefType, makeErrorType, makeTypeParam } from '../typecheck'
import { makeErrorType, makeTypeParam } from '../typecheck'
import { assert, todo, unreachable } from '../util/todo'

/**
Expand All @@ -14,12 +14,10 @@ export const setTopScopeDefType = (node: AstNode, ctx: Context) => {
break
}
case 'trait-def': {
node.type = makeDefType(node)
node.generics.forEach(g => setTopScopeDefType(g, ctx))
break
}
case 'type-def': {
node.type = makeDefType(node)
node.generics.forEach(g => setTopScopeDefType(g, ctx))
break
}
Expand Down Expand Up @@ -72,7 +70,12 @@ export const setTopScopeType = (node: AstNode, ctx: Context) => {
kind: 'identifier',
parseNode: node.parseNode,
names: [node.typeDef!.name],
typeArgs: node.typeDef!.generics.map(g => ({ kind: 'identifier', names: [g.name], typeArgs: [] })),
typeArgs: node.typeDef!.generics.map(g => ({
kind: 'identifier',
names: [g.name],
typeArgs: [],
def: g
})),
def: node.typeDef
}
const fnType = {
Expand Down
56 changes: 20 additions & 36 deletions src/phase/type-unify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '../typecheck'
import { zip } from '../util/array'
import { assign } from '../util/object'
import { todo, unreachable } from '../util/todo'
import { unreachable } from '../util/todo'

/**
* Unify type bounds
Expand Down Expand Up @@ -256,8 +256,7 @@ export const unifyType = (type: InferredType, ctx: Context): void => {
break
}
case 'identifier':
if (type.def?.type && type.typeArgs.length === 0) {
type.typeArgs.forEach(ta => unifyType(ta, ctx))
if (type.def?.type?.kind === 'type-param') {
assign(type, type.def.type)
break
}
Expand All @@ -266,7 +265,6 @@ export const unifyType = (type: InferredType, ctx: Context): void => {
case 'name':
case 'type-param':
case 'hole':
case 'def':
case 'error':
break
}
Expand Down Expand Up @@ -307,19 +305,31 @@ const unify_ = (a: InferredType, b: InferredType, ctx: Context, stack: [string,
}
break
}
case 'def': {
case 'identifier': {
if (a.def === ctx.stdTypeIds.never?.def) {
return b
}
switch (b.kind) {
// biome-ignore lint:
case 'def':
// TODO: respect def's trait impls
if (b.kind === 'def' && a.def === b.def) {
return a
case 'identifier': {
if (a.def && a.def === b.def) {
if (a.typeArgs.length === b.typeArgs.length) {
const typeArgs = <Identifier[]>(
zip(a.typeArgs, b.typeArgs, (ta, tb) => unify(ta, tb, ctx, stack))
)
const u: Identifier = {
kind: 'identifier',
parseNode: a.parseNode,
names: a.names,
typeArgs
}
assign(a, u)
assign(b, u)
return u
}
}
}
case 'inferred-fn':
case 'identifier':
case 'fn-type':
case 'name':
const e = makeErrorType(
Expand Down Expand Up @@ -353,24 +363,6 @@ const unify_ = (a: InferredType, b: InferredType, ctx: Context, stack: [string,
}
case 'name':
break
case 'identifier':
if (b.kind === 'identifier') {
if (b.def?.type?.kind === 'type-param') {
return unify(b.def.type, a, ctx, stack)
}
if (a.def && a.def === b.def) {
if (a.typeArgs.length !== b.typeArgs.length) {
todo()
break
}
const typeArgs = <Identifier[]>zip(a.typeArgs, b.typeArgs, (ta, tb) => unify(ta, tb, ctx, stack))
const u: Identifier = { kind: 'identifier', parseNode: a.parseNode, names: a.names, typeArgs }
assign(a, u)
assign(b, u)
return u
}
}
break
case 'hole':
return b
case 'error':
Expand Down Expand Up @@ -407,12 +399,6 @@ const extractReturnType = (type: InferredType, ctx: Context): InferredType | und
return undefined
case 'error':
return type
case 'def':
if (type.def.kind === 'fn-def') {
unreachable()
return type.def.returnType!
}
return undefined
case 'method-call':
case 'fn-type':
case 'return':
Expand Down Expand Up @@ -447,8 +433,6 @@ const extractDefs = (t: InferredType): Definition[] => {
return [t.def]
}
break
case 'def':
return [t.def]
case 'type-param':
return <TypeDef[]>t.type.bounds.map(b => b.def)
}
Expand Down
2 changes: 1 addition & 1 deletion src/semantic/impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const findMethodDefForMethodCall = (type: InferredType, ctx: Context): Fn
assert(false, type.kind)
return unreachable()
}
if (type.operandType.kind === 'def') {
if (type.operandType.kind === 'identifier') {
const def = type.operandType.def
const impls = ctx.packages.flatMap(p =>
p.modules.flatMap(m => m.impls).filter(impl => impl.forTrait && impl.forTrait.def === def)
Expand Down
10 changes: 1 addition & 9 deletions src/typecheck/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { UnaryExpr } from '../ast/expr'
import { FieldAccessOp, MethodCallOp } from '../ast/op'
import { Name } from '../ast/operand'
import { Generic, Type } from '../ast/type'
import { Context, Definition, defKey, idToString } from '../scope'
import { Context, idToString } from '../scope'
import { assert, unreachable } from '../util/todo'

export type InferredType =
Expand All @@ -23,7 +23,6 @@ export type InferredType =
}
| { kind: 'field-access'; operandType: InferredType; fieldName: Name }
| { kind: 'method-call'; operandType: InferredType; op: MethodCallOp }
| { kind: 'def'; def: Definition }
| Type
| { kind: 'return'; type: InferredType }
| ErrorType
Expand Down Expand Up @@ -71,8 +70,6 @@ export const makeMethodCallType = (expr: UnaryExpr) => ({

export const makeReturnType = (type: InferredType) => ({ kind: <const>'return', type })

export const makeDefType = (def: Definition) => ({ kind: <const>'def', def })

export const makeErrorType = (message?: string, errorKind: ErrorTypeKind = 'other') => ({
kind: <const>'error',
error: {
Expand All @@ -99,9 +96,6 @@ export const instantiateDefType = (t: InferredType, ctx: Context): InferredType
}
])
}
case 'def': {
return makeInferredType([t])
}
default:
return t
}
Expand All @@ -126,8 +120,6 @@ export const inferredTypeToString = (t: InferredType, depth = 0): string => {
)}`
case 'return':
return `ret(${inferredTypeToString(t.type, depth + 1)})`
case 'def':
return `def(${t.def.kind} ${defKey(t.def)})`
case 'field-access':
return `(${inferredTypeToString(t.operandType, depth + 1)}).${t.fieldName.value}`
case 'method-call':
Expand Down

0 comments on commit 903d278

Please sign in to comment.