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 // skip prototype and export instances
case ElementKind.FUNCTION_PROTOTYPE: { case ElementKind.FUNCTION_PROTOTYPE: {
for (let instance of (<FunctionPrototype>element).instances.values()) { for (let instances of (<FunctionPrototype>element).instances.values()) {
let instanceName = name; for (let instance of instances.values()) {
if (instance.is(CommonFlags.GENERIC)) { let instanceName = name;
let fullName = instance.internalName; if (instance.is(CommonFlags.GENERIC)) {
instanceName += fullName.substring(fullName.lastIndexOf("<")); let fullName = instance.internalName;
instanceName += fullName.substring(fullName.lastIndexOf("<"));
}
this.makeModuleExport(instanceName, instance, prefix);
} }
this.makeModuleExport(instanceName, instance, prefix);
} }
break; break;
} }

View File

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

View File

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

View File

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