refactor: track all the 'prior types' of a type as types are installed

These are exactly the types that might match before the given type, and
  hence which require to have their template instantiations defined when
  an instantiation with the given type is made.
This commit is contained in:
Glen Whitney 2022-07-31 00:17:36 -07:00
parent 883a351aa8
commit d4a4d8f331
1 changed files with 23 additions and 6 deletions

View File

@ -31,6 +31,13 @@ export default class PocomathInstance {
*/
this.Types = {any: anySpec, T: anySpec}
this._subtypes = {} // For each type, gives all of its (in)direct subtypes
/* The following gives for each type, a set of all types that could
* match in typed-function's dispatch algorithm before the given type.
* This is important because if we instantiate a template, we must
* instantiate it for all prior types as well, or else the wrong instance
* might match.
*/
this._priorTypes = {}
this._usedTypes = new Set() // all types that have occurred in a signature
this._doomed = new Set() // for detecting circular reference
this._config = {predictable: false}
@ -170,7 +177,12 @@ export default class PocomathInstance {
const mod = await import(modName)
this.install(mod)
} catch (err) {
// No such module, but that's OK
if (!(err.message.includes('find'))) {
// Not just a error because module doesn't exist
// So take it seriously
throw err
}
// We don't care if a module doesn't exist, so merely proceed
}
}
doneSet.add(name)
@ -235,6 +247,7 @@ export default class PocomathInstance {
}
this._typed.addTypes([{name: type, test: testFn}], beforeType)
this.Types[type] = spec
this._priorTypes[type] = new Set()
/* Now add conversions to this type */
for (const from in (spec.from || {})) {
if (from in this.Types) {
@ -243,6 +256,7 @@ export default class PocomathInstance {
while (nextSuper) {
this._typed.addConversion(
{from, to: nextSuper, convert: spec.from[from]})
this._priorTypes[nextSuper].add(from)
nextSuper = this.Types[nextSuper].refines
}
}
@ -261,21 +275,24 @@ export default class PocomathInstance {
to: nextSuper,
convert: this.Types[to].from[type]
})
this._priorTypes[nextSuper].add(type)
nextSuper = this.Types[nextSuper].refines
}
}
}
if (spec.refines) {
this._typed.addConversion(
{from: type, to: spec.refines, convert: x => x})
}
// Update all the subtype sets of supertypes up the chain, and
// while we are at it add trivial conversions from subtypes to supertypes
// to help typed-function match signatures properly:
this._subtypes[type] = new Set()
// Update all the subtype sets of supertypes up the chain:
let nextSuper = spec.refines
while (nextSuper) {
this._typed.addConversion(
{from: type, to: nextSuper, convert: x => x})
this._priorTypes[nextSuper].add(type)
this._subtypes[nextSuper].add(type)
nextSuper = this.Types[nextSuper].refines
}
// rebundle anything that uses the new type:
this._invalidateDependents(':' + type)
}