Skip to content

Commit

Permalink
Codegen: upcasting for super methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Mar 12, 2024
1 parent 0959a76 commit 53b1c14
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 5 deletions.
17 changes: 15 additions & 2 deletions src/codegen/js/statement.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { emitLines, indent, jsRelName, jsString, jsVariable, nextVariable } from '.'
import { emitLines, emitUpcasts, indent, jsRelName, jsString, jsVariable, nextVariable } from '.'
import { Module } from '../../ast'
import { Block, BreakStmt, FnDef, ImplDef, ReturnStmt, Statement, TraitDef, VarDef } from '../../ast/statement'
import { TypeDef, Variant } from '../../ast/type-def'
Expand Down Expand Up @@ -82,8 +82,21 @@ export const emitBreakStmt = (breakStmt: BreakStmt, module: Module, ctx: Context
export const emitInstance = (instance: ImplDef | TraitDef, module: Module, ctx: Context): EmitExpr => {
const superMethods = instance.kind === 'impl-def' ? instance.superMethods ?? [] : []
const ms = superMethods.map(m => {
const params = m.fn.params.map((p, i) => {
const pVar = nextVariable(ctx)
const upcastMap = m.paramUpcasts ? m.paramUpcasts[i] : undefined
if (upcastMap) {
return { emit: emitUpcasts(pVar, upcastMap), resultVar: pVar }
} else {
return { emit: '', resultVar: pVar }
}
})
const mName = m.fn.name.value
return `${mName}: ${jsRelName(m.rel)}().${mName}`
const block = emitLines([
...params.map(p => p.emit),
`return ${jsRelName(m.rel)}().${mName}(${params.map(p => p.resultVar).join(', ')})`
])
return `${mName}: function(${params.map(p => p.resultVar).join(', ')}) {\n${indent(block)}\n}`
})
const fns = instance.block.statements
.map(s => <FnDef>s)
Expand Down
3 changes: 1 addition & 2 deletions src/scope/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { AstNode, Module } from '../ast'
import { Module } from '../ast'
import { ClosureExpr, Operand } from '../ast/operand'
import { FnDef, ImplDef, TraitDef } from '../ast/statement'
import { TypeDef } from '../ast/type-def'
import { Config } from '../config'
import { Package } from '../package'
import { Typed } from '../semantic'
import { SemanticError } from '../semantic/error'
import { VirtualType } from '../typecheck'
import { InstanceRelation } from './trait'
Expand Down
2 changes: 2 additions & 0 deletions src/scope/vid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ 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 { Upcast } from '../semantic/upcast'
import { selfType } from '../typecheck/type'
import { unreachable } from '../util/todo'
import { Context, Scope, instanceScope } from './index'
Expand Down Expand Up @@ -63,6 +64,7 @@ export interface MethodDef {
kind: 'method-def'
fn: FnDef
rel: InstanceRelation
paramUpcasts?: (Map<string, Upcast> | undefined)[]
}

export interface VirtualIdentifierMatch<D = Definition> {
Expand Down
10 changes: 9 additions & 1 deletion src/semantic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { notFoundError, semanticError, typeError, unknownTypeError } from './err
import { checkClosureExpr, checkExpr } from './expr'
import { checkPattern } from './match'
import { typeNames } from './type-def'
import { Upcast, upcast } from './upcast'
import { Upcast, makeUpcastMap, upcast } from './upcast'
import { useExprToVids } from './use-expr'

export interface Checked {
Expand Down Expand Up @@ -451,6 +451,14 @@ const checkImplDef = (implDef: ImplDef, ctx: Context) => {
implDef.superMethods = traitMethods.filter(
m => m.fn.block && !implMethods.find(im => im.name.value === m.fn.name.value)
)
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 resolvedType = resolveType(p.type!, genericMaps, ctx)
return makeUpcastMap(resolvedType, m.rel.forType, ctx)
})
}
module.relImports.push(...implDef.superMethods.map(i => i.rel))
} else {
addError(ctx, semanticError(ctx, implDef.forTrait, `expected \`trait-def\`, got \`${ref.def.kind}\``))
Expand Down

0 comments on commit 53b1c14

Please sign in to comment.