Fix partial function prototypes not sharing their instances

This also made it necessary to extend the internal per-function instances map by one level for the respective class instance key so functions on differnt class instances with the same own type arguments don't collide.
This commit is contained in:
dcodeIO 2018-12-01 19:46:10 +01:00
parent 0e33806cf6
commit 4c35dd6f7c
4 changed files with 29 additions and 17 deletions

View File

@ -551,13 +551,15 @@ export class Compiler extends DiagnosticEmitter {
// skip prototype and export instances
case ElementKind.FUNCTION_PROTOTYPE: {
for (let instance of (<FunctionPrototype>element).instances.values()) {
let instanceName = name;
if (instance.is(CommonFlags.GENERIC)) {
let fullName = instance.internalName;
instanceName += fullName.substring(fullName.lastIndexOf("<"));
for (let instances of (<FunctionPrototype>element).instances.values()) {
for (let instance of instances.values()) {
let instanceName = name;
if (instance.is(CommonFlags.GENERIC)) {
let fullName = instance.internalName;
instanceName += fullName.substring(fullName.lastIndexOf("<"));
}
this.makeModuleExport(instanceName, instance, prefix);
}
this.makeModuleExport(instanceName, instance, prefix);
}
break;
}

View File

@ -105,8 +105,10 @@ abstract class ExportsWalker {
}
private visitFunctionInstances(element: FunctionPrototype): void {
for (let instance of element.instances.values()) {
if (instance.is(CommonFlags.COMPILED)) this.visitFunction(<Function>instance);
for (let instances of element.instances.values()) {
for (let instance of instances.values()) {
if (instance.is(CommonFlags.COMPILED)) this.visitFunction(<Function>instance);
}
}
}
@ -516,8 +518,10 @@ function hasCompiledMember(element: Element): bool {
for (let member of members.values()) {
switch (member.kind) {
case ElementKind.FUNCTION_PROTOTYPE: {
for (let instance of (<FunctionPrototype>member).instances.values()) {
if (instance.is(CommonFlags.COMPILED)) return true;
for (let instances of (<FunctionPrototype>member).instances.values()) {
for (let instance of instances.values()) {
if (instance.is(CommonFlags.COMPILED)) return true;
}
}
break;
}

View File

@ -2391,8 +2391,8 @@ export class FunctionPrototype extends Element {
declaration: FunctionDeclaration;
/** If an instance method, the class prototype reference. */
classPrototype: ClassPrototype | null;
/** Resolved instances. */
instances: Map<string,Function> = new Map();
/** Resolved instances by class type arguments and function type arguments. */
instances: Map<string,Map<string,Function>> = new Map();
/** Class type arguments, if a partially resolved method of a generic class. Not set otherwise. */
classTypeArguments: Type[] | null = null;
/** Operator kind, if an overload. */

View File

@ -713,9 +713,14 @@ export class Resolver extends DiagnosticEmitter {
contextualTypeArguments: Map<string,Type> | null = null,
reportMode: ReportMode = ReportMode.REPORT
): Function | null {
var classTypeArguments = prototype.classTypeArguments;
var classInstanceKey = classTypeArguments ? typesToString(classTypeArguments) : "";
var instanceKey = typeArguments ? typesToString(typeArguments) : "";
var instance = prototype.instances.get(instanceKey);
if (instance) return instance;
var classInstances = prototype.instances.get(classInstanceKey);
if (classInstances) {
let instance = classInstances.get(instanceKey);
if (instance) return instance;
}
var declaration = prototype.declaration;
var isInstance = prototype.is(CommonFlags.INSTANCE);
@ -734,7 +739,6 @@ export class Resolver extends DiagnosticEmitter {
}
// override with class type arguments if a partially resolved instance method
var classTypeArguments = prototype.classTypeArguments;
if (classTypeArguments) { // set only if partially resolved
assert(prototype.is(CommonFlags.INSTANCE));
let classDeclaration = assert(classPrototype).declaration;
@ -818,7 +822,7 @@ export class Resolver extends DiagnosticEmitter {
var internalName = prototype.internalName;
if (instanceKey.length) internalName += "<" + instanceKey + ">";
instance = new Function(
var instance = new Function(
prototype,
internalName,
signature,
@ -827,7 +831,8 @@ export class Resolver extends DiagnosticEmitter {
: classPrototype,
contextualTypeArguments
);
prototype.instances.set(instanceKey, instance);
if (!classInstances) prototype.instances.set(classInstanceKey, classInstances = new Map());
classInstances.set(instanceKey, instance);
this.program.instancesLookup.set(internalName, instance);
return instance;
}
@ -856,6 +861,7 @@ export class Resolver extends DiagnosticEmitter {
partialPrototype.flags = prototype.flags;
partialPrototype.operatorKind = prototype.operatorKind;
partialPrototype.classTypeArguments = typeArguments;
partialPrototype.instances = prototype.instances;
return partialPrototype;
}