Skip to content

Commit

Permalink
Semantic: use generic key for generic maps; relations refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Mar 31, 2024
1 parent 294ae83 commit 7d90306
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/ast/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const buildTypeBounds = (node: ParseNode): TypeBounds => {

export interface Generic extends AstNode<'generic'> {
name: Name
key?: string
bounds: Identifier[]
}

Expand Down
1 change: 1 addition & 0 deletions src/scope/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type DefinitionMap = Map<string, Definition>
export interface InstanceScope {
kind: 'instance'
definitions: DefinitionMap
def: TraitDef | ImplDef
rel?: InstanceRelation
}

Expand Down
19 changes: 12 additions & 7 deletions src/scope/trait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const buildInstanceRelations = (ctx: Context): InstanceRelation[] => {
)
return impls.flatMap(([module, impl]) => {
ctx.moduleStack.push(module)
const implRel = getImplRel(impl, ctx)
const implRel = getRel(impl, ctx)
ctx.moduleStack.pop()
return implRel ? [implRel] : []
})
Expand All @@ -76,19 +76,23 @@ export const buildInstanceRelations = (ctx: Context): InstanceRelation[] => {
/**
* Construct instance relation from instance definition
*/
const getImplRel = (instance: TraitDef | ImplDef, ctx: Context): InstanceRelation | undefined => {
const getRel = (instance: TraitDef | ImplDef, ctx: Context): InstanceRelation | undefined => {
const module = ctx.moduleStack.at(-1)!
module.scopeStack.push({ kind: 'instance', definitions: new Map(instance.generics.map(g => [defKey(g), g])) })
module.scopeStack.push({
kind: 'instance',
def: instance,
definitions: new Map(instance.generics.map(g => [defKey(g), g]))
})

const implRel =
instance.kind === 'trait-def' ? getTraitImplRel(instance, module, ctx) : getImplImplRel(instance, module, ctx)
instance.kind === 'trait-def' ? getTraitRel(instance, module, ctx) : getImplRel(instance, module, ctx)

module.scopeStack.pop()

return implRel
}

const getTraitImplRel = (instance: TraitDef, module: Module, ctx: Context): InstanceRelation | undefined => {
const getTraitRel = (instance: TraitDef, module: Module, ctx: Context): InstanceRelation | undefined => {
const generics = instance.generics.filter(g => g.name.value !== 'Self').map(g => genericToVirtual(g, ctx))
const traitType: VirtualType = {
kind: 'vid-type',
Expand All @@ -111,7 +115,8 @@ const getTraitImplRel = (instance: TraitDef, module: Module, ctx: Context): Inst
}
}

const getImplImplRel = (instance: ImplDef, module: Module, ctx: Context): InstanceRelation | undefined => {
const getImplRel = (instance: ImplDef, module: Module, ctx: Context): InstanceRelation | undefined => {
const generics = instance.generics.filter(g => g.name.value !== 'Self').map(g => genericToVirtual(g, ctx))
const implVid = idToVid(instance.identifier)
const ref = resolveVid(implVid, ctx, ['trait-def', 'type-def'])
if (!ref || (ref.def.kind !== 'trait-def' && ref.def.kind !== 'type-def')) {
Expand Down Expand Up @@ -140,7 +145,7 @@ const getImplImplRel = (instance: ImplDef, module: Module, ctx: Context): Instan
implDef: <VirtualIdentifierMatch<TypeDef | TraitDef>>ref,
forDef: forDef,
instanceDef: instance,
generics: instance.generics.map(g => genericToVirtual(g, ctx)),
generics,
inherent: !instance.forTrait
}
}
Expand Down
1 change: 0 additions & 1 deletion src/semantic/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,4 +292,3 @@ export const unexpectedRefutablePatternError = (ctx: Context, patternExpr: Patte
const msg = `unexpected refutable pattern`
return semanticError(41, ctx, patternExpr, msg)
}

4 changes: 3 additions & 1 deletion src/semantic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ const checkTraitDef = (traitDef: TraitDef, ctx: Context) => {

const scope: InstanceScope = {
kind: 'instance',
def: rel.instanceDef,
rel,
definitions: new Map(traitDef.generics.map(g => [defKey(g), g]))
}
Expand Down Expand Up @@ -448,7 +449,7 @@ const checkImplDef = (implDef: ImplDef, ctx: Context) => {

const scope: InstanceScope = {
kind: 'instance',
rel: implDef.rel,
def: implDef,
definitions: new Map(implDef.generics.map(g => [defKey(g), g]))
}
module.scopeStack.push(scope)
Expand Down Expand Up @@ -699,6 +700,7 @@ export const checkIdentifier = (identifier: Identifier, ctx: Context): void => {
const instScope: InstanceScope = {
kind: 'instance',
rel: ref.def.rel,
def: ref.def.rel.instanceDef,
definitions: new Map(ref.def.rel.instanceDef.generics.map(g => [defKey(g), g]))
}

Expand Down
2 changes: 1 addition & 1 deletion src/semantic/upcast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const makeUpcast = (type: VirtualType, traitType: VirtualType, ctx: Conte
const upcast: Upcast = { self: { [relTypeName(res.trait)]: res.impl }, generics: [] }
for (const g of res.impl.generics) {
const gUpcast: Upcast = { self: {}, generics: [] }
const concreteG = genericMap.get(g.name)
const concreteG = genericMap.get(g.key)
if (concreteG) {
for (const b of g.bounds) {
const gUp = makeUpcast(concreteG, b, ctx)
Expand Down
7 changes: 4 additions & 3 deletions src/typecheck/generic.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Context, InstanceScope } from '../scope'
import { getInstanceForType } from '../scope/trait'
import { fold } from '../util/array'
import { merge } from '../util/map'
import { assert, unreachable } from '../util/todo'
Expand Down Expand Up @@ -43,7 +44,7 @@ export const makeGenericMapOverStructure = (arg: VirtualType, param: VirtualType
break
}
}
map.set(param.name, arg)
map.set(param.key, arg)
return map
}
if (arg.kind === 'unknown-type' || param.kind === 'unknown-type') {
Expand Down Expand Up @@ -146,7 +147,7 @@ export const getTypeParams = (virtualType: VirtualType): VirtualType[] => {
}

export const instanceGenericMap = (instScope: InstanceScope, ctx: Context): Map<string, VirtualType> => {
return new Map([[selfType.name, instScope.rel!.forType]])
return new Map([[selfType.key, getInstanceForType(instScope.def, ctx)]])
}

/**
Expand Down Expand Up @@ -174,7 +175,7 @@ const resolveGenericMap = (
typeArgs: virtualType.typeArgs.map(g => resolveGenericMap(g, genericMap, ctx))
}
case 'generic':
const mapped = genericMap.get(virtualType.name)
const mapped = genericMap.get(virtualType.key)
const res = mapped ?? virtualType
if (res.kind === 'generic') {
return {
Expand Down
18 changes: 11 additions & 7 deletions src/typecheck/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Operand } from '../ast/operand'
import { Generic, Type } from '../ast/type'
import { jsRelName } from '../codegen/js'
import { Context, addError } from '../scope'
import { InstanceRelation, findSuperRelChains, getConcreteTrait } from '../scope/trait'
import { idToVid, vidEq, vidToString } from '../scope/util'
Expand Down Expand Up @@ -127,10 +126,13 @@ export const typeToVirtual = (type: Type, ctx: Context): VirtualType => {
}

export const genericToVirtual = (generic: Generic, ctx: Context): VirtualGeneric => {
if (!generic.key) {
generic.key = genericKey(generic, ctx)
}
return {
kind: 'generic',
name: generic.name.value,
key: genericKey(generic, ctx),
key: generic.key,
bounds: generic.bounds.map(b => typeToVirtual(b, ctx))
}
}
Expand All @@ -151,21 +153,23 @@ export const genericKey = (generic: Generic, ctx: Context): string => {
return `closure`
}
case 'instance':
if (s.rel) {
return `instance_${jsRelName(s.rel)}`
} else {
return `instance`
switch (s.def.kind) {
case 'trait-def':
return `trait_${s.def.name.value}`
case 'impl-def':
return `impl`
}
default:
return undefined
}
})
.filter(s => !!s)
.join('_')
return `${scopeName}_${generic}`
return `${scopeName}_${generic.name.value}`
}

export const isAssignable = (t: VirtualType, target: VirtualType, ctx: Context): boolean => {
if (t === target) return true
if (t.kind === 'unknown-type' || target.kind === 'unknown-type') return true
if (t.kind === 'hole-type' || target.kind === 'hole-type') return true
if (t.kind === 'vid-type' && vidToString(t.identifier) === 'std::never::Never') return true
Expand Down

0 comments on commit 7d90306

Please sign in to comment.