Skip to content

Commit

Permalink
Semantic: check implDef & typeDef fast path
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Mar 14, 2024
1 parent d6b2626 commit bf3637b
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 11 deletions.
4 changes: 3 additions & 1 deletion src/ast/statement.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ParseNode, filterNonAstNodes } from '../parser'
import { InstanceRelation } from '../scope/trait'
import { MethodDef } from '../scope/vid'
import { Checked, Typed } from '../semantic'
import { assert } from '../util/todo'
Expand Down Expand Up @@ -130,12 +131,13 @@ export const buildTraitDef = (node: ParseNode): TraitDef => {
return { kind: 'trait-def', parseNode: node, name, generics, block, pub }
}

export interface ImplDef extends AstNode<'impl-def'> {
export interface ImplDef extends AstNode<'impl-def'>, Partial<Checked> {
identifier: Identifier
generics: Generic[]
forTrait?: Identifier
block: Block
superMethods?: MethodDef[]
rel?: InstanceRelation
}

export const buildImplDef = (node: ParseNode): ImplDef => {
Expand Down
3 changes: 2 additions & 1 deletion src/ast/type.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ParseNode, filterNonAstNodes } from '../parser'
import { Checked } from '../semantic'
import { AstNode } from './index'
import { Hole, buildHole } from './match'
import { Identifier, Name, buildIdentifier, buildName } from './operand'

export type Type = Identifier | TypeBounds | FnType | Hole
export type Type = (Identifier | TypeBounds | FnType | Hole) & Partial<Checked>

export const buildType = (node: ParseNode): Type => {
const n = filterNonAstNodes(node)[0]
Expand Down
6 changes: 4 additions & 2 deletions src/scope/vid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Name } from '../ast/operand'
import { FnDef, ImplDef, Statement, TraitDef } from '../ast/statement'
import { Generic } from '../ast/type'
import { TypeDef, Variant } from '../ast/type-def'
import { checkTopLevelDefinition } from '../semantic'
import { TopLevelChecked, checkTopLevelDefinition } from '../semantic'
import { Upcast } from '../semantic/upcast'
import { selfType } from '../typecheck/type'
import { unreachable } from '../util/todo'
Expand Down Expand Up @@ -32,7 +32,7 @@ export type DefinitionKind = (typeof defKinds)[number]

export const typeKinds: DefinitionKind[] = ['type-def', 'trait-def', 'generic', 'self']

export type Definition =
export type Definition = (
| Module
| NameDef
| FnDef
Expand All @@ -43,6 +43,8 @@ export type Definition =
| Generic
| SelfDef
| MethodDef
) &
Partial<TopLevelChecked>

export interface NameDef {
kind: 'name-def'
Expand Down
26 changes: 19 additions & 7 deletions src/semantic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export interface Checked {
checked: boolean
}

export interface TopLevelChecked {
topLevelChecked: boolean
}

export interface Typed {
type: VirtualType
}
Expand Down Expand Up @@ -395,9 +399,13 @@ const checkTraitDef = (traitDef: TraitDef, ctx: Context) => {
}

const checkImplDef = (implDef: ImplDef, ctx: Context) => {
// TODO: should any errors be reported?
const rel = ctx.impls.find(i => i.instanceDef === implDef)
if (!rel) return
if (implDef.checked) return

if (!implDef.rel) {
const rel = ctx.impls.find(i => i.instanceDef === implDef)
assert(!!rel)
implDef.rel = rel
}

const module = ctx.moduleStack.at(-1)!

Expand All @@ -408,8 +416,8 @@ const checkImplDef = (implDef: ImplDef, ctx: Context) => {

const scope: InstanceScope = {
kind: 'instance',
selfType: rel.forType,
rel,
selfType: implDef.rel!.forType,
rel: implDef.rel!,
definitions: new Map(implDef.generics.map(g => [defKey(g), g]))
}
module.scopeStack.push(scope)
Expand All @@ -425,6 +433,7 @@ const checkImplDef = (implDef: ImplDef, ctx: Context) => {
const ref = resolveVid(vid, ctx, ['type-def', 'trait-def'])
if (ref) {
if (module.compiled) {
implDef.checked = true
} else if (ref.def.kind === 'trait-def') {
const traitRels = [
ctx.impls.find(rel => rel.instanceDef === ref.def)!,
Expand Down Expand Up @@ -453,7 +462,7 @@ const checkImplDef = (implDef: ImplDef, ctx: Context) => {
}
checkTopLevelDefinition(traitMethod.rel.module, traitMethod.rel.instanceDef, ctx)

const traitMap = makeGenericMapOverStructure(rel.implType, traitMethod.rel.implType)
const traitMap = makeGenericMapOverStructure(implDef.rel!.implType, traitMethod.rel.implType)
const mResolvedType = resolveType(traitMethod.fn.type!, [traitMap], ctx)
if (!(isAssignable(m.type!, mResolvedType, ctx) && typeEq(m.type!, mResolvedType))) {
addError(ctx, typeError(m.name, m.type!, mResolvedType, ctx))
Expand All @@ -465,7 +474,7 @@ const checkImplDef = (implDef: ImplDef, ctx: Context) => {
implDef.superMethods.forEach(m => checkTopLevelDefinition(m.rel.module, m.rel.instanceDef, ctx))
for (const m of implDef.superMethods) {
m.paramUpcasts = m.fn.params.map(p => {
const genericMaps = [makeGenericMapOverStructure(rel.forType, p.type!)]
const genericMaps = [makeGenericMapOverStructure(implDef.rel!.forType, p.type!)]
const resolvedType = resolveType(p.type!, genericMaps, ctx)
return makeUpcastMap(resolvedType, m.rel.forType, ctx)
})
Expand Down Expand Up @@ -684,6 +693,9 @@ export const checkIdentifier = (identifier: Identifier, ctx: Context): void => {
}

export const checkType = (type: Type, ctx: Context) => {
if (type.checked) return
type.checked = true

switch (type.kind) {
case 'identifier':
const vid = idToVid(type)
Expand Down

0 comments on commit bf3637b

Please sign in to comment.