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

View File

@ -31,6 +31,13 @@ export default class PocomathInstance {
*/ */
this.Types = {any: anySpec, T: anySpec} this.Types = {any: anySpec, T: anySpec}
this._subtypes = {} // For each type, gives all of its (in)direct subtypes 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._usedTypes = new Set() // all types that have occurred in a signature
this._doomed = new Set() // for detecting circular reference this._doomed = new Set() // for detecting circular reference
this._config = {predictable: false} this._config = {predictable: false}
@ -170,7 +177,12 @@ export default class PocomathInstance {
const mod = await import(modName) const mod = await import(modName)
this.install(mod) this.install(mod)
} catch (err) { } 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) doneSet.add(name)
@ -235,6 +247,7 @@ export default class PocomathInstance {
} }
this._typed.addTypes([{name: type, test: testFn}], beforeType) this._typed.addTypes([{name: type, test: testFn}], beforeType)
this.Types[type] = spec this.Types[type] = spec
this._priorTypes[type] = new Set()
/* Now add conversions to this type */ /* Now add conversions to this type */
for (const from in (spec.from || {})) { for (const from in (spec.from || {})) {
if (from in this.Types) { if (from in this.Types) {
@ -243,6 +256,7 @@ export default class PocomathInstance {
while (nextSuper) { while (nextSuper) {
this._typed.addConversion( this._typed.addConversion(
{from, to: nextSuper, convert: spec.from[from]}) {from, to: nextSuper, convert: spec.from[from]})
this._priorTypes[nextSuper].add(from)
nextSuper = this.Types[nextSuper].refines nextSuper = this.Types[nextSuper].refines
} }
} }
@ -261,21 +275,24 @@ export default class PocomathInstance {
to: nextSuper, to: nextSuper,
convert: this.Types[to].from[type] convert: this.Types[to].from[type]
}) })
this._priorTypes[nextSuper].add(type)
nextSuper = this.Types[nextSuper].refines nextSuper = this.Types[nextSuper].refines
} }
} }
} }
if (spec.refines) { // Update all the subtype sets of supertypes up the chain, and
this._typed.addConversion( // while we are at it add trivial conversions from subtypes to supertypes
{from: type, to: spec.refines, convert: x => x}) // to help typed-function match signatures properly:
}
this._subtypes[type] = new Set() this._subtypes[type] = new Set()
// Update all the subtype sets of supertypes up the chain:
let nextSuper = spec.refines let nextSuper = spec.refines
while (nextSuper) { while (nextSuper) {
this._typed.addConversion(
{from: type, to: nextSuper, convert: x => x})
this._priorTypes[nextSuper].add(type)
this._subtypes[nextSuper].add(type) this._subtypes[nextSuper].add(type)
nextSuper = this.Types[nextSuper].refines nextSuper = this.Types[nextSuper].refines
} }
// rebundle anything that uses the new type: // rebundle anything that uses the new type:
this._invalidateDependents(':' + type) this._invalidateDependents(':' + type)
} }