Skip to content

Commit 4c35dd6

Browse files
committed
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.
1 parent 0e33806 commit 4c35dd6

File tree

4 files changed

+29
-17
lines changed

4 files changed

+29
-17
lines changed

src/compiler.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -551,13 +551,15 @@ export class Compiler extends DiagnosticEmitter {
551551

552552
// skip prototype and export instances
553553
case ElementKind.FUNCTION_PROTOTYPE: {
554-
for (let instance of (<FunctionPrototype>element).instances.values()) {
555-
let instanceName = name;
556-
if (instance.is(CommonFlags.GENERIC)) {
557-
let fullName = instance.internalName;
558-
instanceName += fullName.substring(fullName.lastIndexOf("<"));
554+
for (let instances of (<FunctionPrototype>element).instances.values()) {
555+
for (let instance of instances.values()) {
556+
let instanceName = name;
557+
if (instance.is(CommonFlags.GENERIC)) {
558+
let fullName = instance.internalName;
559+
instanceName += fullName.substring(fullName.lastIndexOf("<"));
560+
}
561+
this.makeModuleExport(instanceName, instance, prefix);
559562
}
560-
this.makeModuleExport(instanceName, instance, prefix);
561563
}
562564
break;
563565
}

src/definitions.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,10 @@ abstract class ExportsWalker {
105105
}
106106

107107
private visitFunctionInstances(element: FunctionPrototype): void {
108-
for (let instance of element.instances.values()) {
109-
if (instance.is(CommonFlags.COMPILED)) this.visitFunction(<Function>instance);
108+
for (let instances of element.instances.values()) {
109+
for (let instance of instances.values()) {
110+
if (instance.is(CommonFlags.COMPILED)) this.visitFunction(<Function>instance);
111+
}
110112
}
111113
}
112114

@@ -516,8 +518,10 @@ function hasCompiledMember(element: Element): bool {
516518
for (let member of members.values()) {
517519
switch (member.kind) {
518520
case ElementKind.FUNCTION_PROTOTYPE: {
519-
for (let instance of (<FunctionPrototype>member).instances.values()) {
520-
if (instance.is(CommonFlags.COMPILED)) return true;
521+
for (let instances of (<FunctionPrototype>member).instances.values()) {
522+
for (let instance of instances.values()) {
523+
if (instance.is(CommonFlags.COMPILED)) return true;
524+
}
521525
}
522526
break;
523527
}

src/program.ts

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

src/resolver.ts

+11-5
Original file line numberDiff line numberDiff line change
@@ -713,9 +713,14 @@ export class Resolver extends DiagnosticEmitter {
713713
contextualTypeArguments: Map<string,Type> | null = null,
714714
reportMode: ReportMode = ReportMode.REPORT
715715
): Function | null {
716+
var classTypeArguments = prototype.classTypeArguments;
717+
var classInstanceKey = classTypeArguments ? typesToString(classTypeArguments) : "";
716718
var instanceKey = typeArguments ? typesToString(typeArguments) : "";
717-
var instance = prototype.instances.get(instanceKey);
718-
if (instance) return instance;
719+
var classInstances = prototype.instances.get(classInstanceKey);
720+
if (classInstances) {
721+
let instance = classInstances.get(instanceKey);
722+
if (instance) return instance;
723+
}
719724

720725
var declaration = prototype.declaration;
721726
var isInstance = prototype.is(CommonFlags.INSTANCE);
@@ -734,7 +739,6 @@ export class Resolver extends DiagnosticEmitter {
734739
}
735740

736741
// override with class type arguments if a partially resolved instance method
737-
var classTypeArguments = prototype.classTypeArguments;
738742
if (classTypeArguments) { // set only if partially resolved
739743
assert(prototype.is(CommonFlags.INSTANCE));
740744
let classDeclaration = assert(classPrototype).declaration;
@@ -818,7 +822,7 @@ export class Resolver extends DiagnosticEmitter {
818822

819823
var internalName = prototype.internalName;
820824
if (instanceKey.length) internalName += "<" + instanceKey + ">";
821-
instance = new Function(
825+
var instance = new Function(
822826
prototype,
823827
internalName,
824828
signature,
@@ -827,7 +831,8 @@ export class Resolver extends DiagnosticEmitter {
827831
: classPrototype,
828832
contextualTypeArguments
829833
);
830-
prototype.instances.set(instanceKey, instance);
834+
if (!classInstances) prototype.instances.set(classInstanceKey, classInstances = new Map());
835+
classInstances.set(instanceKey, instance);
831836
this.program.instancesLookup.set(internalName, instance);
832837
return instance;
833838
}
@@ -856,6 +861,7 @@ export class Resolver extends DiagnosticEmitter {
856861
partialPrototype.flags = prototype.flags;
857862
partialPrototype.operatorKind = prototype.operatorKind;
858863
partialPrototype.classTypeArguments = typeArguments;
864+
partialPrototype.instances = prototype.instances;
859865
return partialPrototype;
860866
}
861867

0 commit comments

Comments
 (0)