11
import { lowerType } from "../HIR/BuildHIR";
12
import {
13
HIRFunction,
14
+ Identifier,
15
+ IdentifierId,
16
Instruction,
17
makeType,
18
+ PropType,
19
Type,
20
typeEquals,
21
TypeId,
27
BuiltInJsxId,
28
BuiltInObjectId,
29
BuiltInPropsId,
30
+ BuiltInRefValueId,
31
BuiltInUseRefId,
32
} from "../HIR/ObjectShape";
33
import { eachInstructionLValue, eachInstructionOperand } from "../HIR/visitors";
121
}
122
}
123
124
+ const names = new Map();
125
for (const [_, block] of func.body.blocks) {
126
for (const phi of block.phis) {
127
yield equation(phi.type, {
131
}
132
133
for (const instr of block.instructions) {
129
- yield* generateInstructionTypes(func.env, instr);
134
+ yield* generateInstructionTypes(func.env, names, instr);
135
}
136
}
137
}
138
139
+function setName(
140
+ names: Map<IdentifierId, string>,
141
+ id: IdentifierId,
142
+ name: Identifier
143
+): void {
144
+ if (name.name?.kind === "named") {
145
+ names.set(id, name.name.value);
146
+ }
147
+}
148
+
149
+function getName(names: Map<IdentifierId, string>, id: IdentifierId): string {
150
+ return names.get(id) ?? "";
151
+}
152
+
153
function* generateInstructionTypes(
154
env: Environment,
155
+ names: Map<IdentifierId, string>,
156
instr: Instruction
157
): Generator<TypeEquation, void, undefined> {
158
const { lvalue, value } = instr;
172
}
173
174
case "LoadLocal": {
175
+ setName(names, lvalue.identifier.id, value.place.identifier);
176
yield equation(left, value.place.identifier.type);
177
break;
178
}
271
case "PropertyLoad": {
272
yield equation(left, {
273
kind: "Property",
253
- object: value.object.identifier.type,
274
+ objectType: value.object.identifier.type,
275
+ objectName: getName(names, value.object.identifier.id),
276
propertyName: value.property,
277
});
278
break;
300
const propertyName = String(i);
301
yield equation(item.identifier.type, {
302
kind: "Property",
281
- object: value.value.identifier.type,
303
+ objectType: value.value.identifier.type,
304
+ objectName: getName(names, value.value.identifier.id),
305
propertyName,
306
});
307
} else {
317
) {
318
yield equation(property.place.identifier.type, {
319
kind: "Property",
297
- object: value.value.identifier.type,
320
+ objectType: value.value.identifier.type,
321
+ objectName: getName(names, value.value.identifier.id),
322
propertyName: property.key.name,
323
});
324
}
366
yield equation(left, { kind: "Object", shapeId: BuiltInJsxId });
367
break;
368
}
369
+ case "PropertyStore":
370
case "DeclareLocal":
371
case "NewExpression":
372
case "RegExpLiteral":
373
case "MetaProperty":
349
- case "PropertyStore":
374
case "ComputedStore":
375
case "ComputedLoad":
376
case "TaggedTemplateExpression":
399
400
unify(tA: Type, tB: Type): void {
401
if (tB.kind === "Property") {
378
- const objectType = this.get(tB.object);
402
+ if (
403
+ this.env.config.enableTreatRefLikeIdentifiersAsRefs &&
404
+ isRefLikeName(tB)
405
+ ) {
406
+ this.unify(tB.objectType, {
407
+ kind: "Object",
408
+ shapeId: BuiltInUseRefId,
409
+ });
410
+ this.unify(tA, {
411
+ kind: "Object",
412
+ shapeId: BuiltInRefValueId,
413
+ });
414
+ return;
415
+ }
416
+ const objectType = this.get(tB.objectType);
417
const propertyType = this.env.getPropertyType(
418
objectType,
419
tB.propertyName
521
return type;
522
}
523
}
524
+
525
+const RefLikeNameRE = /^(?:[a-zA-Z$_][a-zA-Z$_0-9]*)Ref$|^ref$/;
526
+
527
+function isRefLikeName(t: PropType): boolean {
528
+ return RefLikeNameRE.test(t.objectName) && t.propertyName === "current";
529
+}