Skip to content

Commit d652620

Browse files
feat: support 'this' type on methods and properties
1 parent 9a7a6e0 commit d652620

File tree

5 files changed

+4508
-8
lines changed

5 files changed

+4508
-8
lines changed

src/resolver.ts

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ export class Resolver extends DiagnosticEmitter {
748748
}
749749

750750
// otherwise resolve the non-generic call as usual
751-
return this.resolveFunction(prototype, null, new Map(), reportMode);
751+
return this.resolveFunction(prototype, null, new Map(), reportMode, ctxFlow);
752752
}
753753

754754
private inferGenericTypeArguments(
@@ -1515,7 +1515,10 @@ export class Resolver extends DiagnosticEmitter {
15151515
let member = classLikeTarget.getMember(propertyName);
15161516
if (member) {
15171517
if (member.kind == ElementKind.PropertyPrototype) {
1518-
let propertyInstance = this.resolveProperty(<PropertyPrototype>member, reportMode);
1518+
if (!member.is(CommonFlags.Static)) {
1519+
this.currentThisExpression = targetNode;
1520+
}
1521+
let propertyInstance = this.resolveProperty(<PropertyPrototype>member, reportMode, ctxFlow);
15191522
if (!propertyInstance) return null;
15201523
member = propertyInstance;
15211524
if (propertyInstance.is(CommonFlags.Static)) {
@@ -2851,14 +2854,25 @@ export class Resolver extends DiagnosticEmitter {
28512854
/** Contextual types, i.e. `T`. */
28522855
ctxTypes: Map<string,Type> = new Map(),
28532856
/** How to proceed with eventual diagnostics. */
2854-
reportMode: ReportMode = ReportMode.Report
2857+
reportMode: ReportMode = ReportMode.Report,
2858+
/** Contextual flow. */
2859+
ctxFlow?: Flow,
28552860
): Function | null {
28562861
let classInstance: Class | null = null; // if an instance method
28572862
let instanceKey = typeArguments ? typesToString(typeArguments) : "";
28582863

28592864
// Instance method prototypes are pre-bound to their concrete class as their parent
28602865
if (prototype.is(CommonFlags.Instance)) {
2861-
classInstance = assert(prototype.getBoundClassOrInterface());
2866+
2867+
if (this.currentThisExpression && ctxFlow) {
2868+
let element = this.lookupExpression(this.currentThisExpression, ctxFlow);
2869+
if (element?.kind == ElementKind.Class) {
2870+
classInstance = <Class>element;
2871+
}
2872+
}
2873+
if (!classInstance) {
2874+
classInstance = assert(prototype.getBoundClassOrInterface());
2875+
}
28622876

28632877
// check if this exact concrete class and function combination is known already
28642878
let resolvedInstance = prototype.getResolvedInstance(instanceKey);
@@ -2998,7 +3012,8 @@ export class Resolver extends DiagnosticEmitter {
29983012
prototype.setResolvedInstance(instanceKey, instance);
29993013

30003014
// check against overridden base member
3001-
if (classInstance) {
3015+
if (prototype.is(CommonFlags.Instance)) {
3016+
let classInstance = assert(prototype.getBoundClassOrInterface());
30023017
let methodOrPropertyName = instance.declaration.name.text;
30033018
let baseClass = classInstance.base;
30043019
if (baseClass) {
@@ -3492,6 +3507,14 @@ export class Resolver extends DiagnosticEmitter {
34923507
);
34933508
break;
34943509
}
3510+
if (boundPrototype.typeNode?.kind == NodeKind.NamedType && (<NamedTypeNode>boundPrototype.typeNode).name.identifier.text == CommonNames.this_) {
3511+
this.error(
3512+
DiagnosticCode.Not_implemented_0,
3513+
assert(boundPrototype.typeNode).range,
3514+
"Polymorphic 'this' typed fields"
3515+
);
3516+
break;
3517+
}
34953518
let needsLayout = true;
34963519
if (base) {
34973520
let existingMember = base.getMember(boundPrototype.name);
@@ -3749,7 +3772,9 @@ export class Resolver extends DiagnosticEmitter {
37493772
/** The prototype of the property. */
37503773
prototype: PropertyPrototype,
37513774
/** How to proceed with eventual diagnostics. */
3752-
reportMode: ReportMode = ReportMode.Report
3775+
reportMode: ReportMode = ReportMode.Report,
3776+
/** Contextual flow. */
3777+
ctxFlow?: Flow,
37533778
): Property | null {
37543779
let instance = prototype.instance;
37553780
if (instance) return instance;
@@ -3763,7 +3788,8 @@ export class Resolver extends DiagnosticEmitter {
37633788
getterPrototype,
37643789
null,
37653790
new Map(),
3766-
reportMode
3791+
reportMode,
3792+
ctxFlow
37673793
);
37683794
if (getterInstance) {
37693795
instance.getterInstance = getterInstance;
@@ -3776,7 +3802,8 @@ export class Resolver extends DiagnosticEmitter {
37763802
setterPrototype,
37773803
null,
37783804
new Map(),
3779-
reportMode
3805+
reportMode,
3806+
ctxFlow
37803807
);
37813808
if (setterInstance) {
37823809
instance.setterInstance = setterInstance;

0 commit comments

Comments
 (0)