6
*/
7
8
import {CompilerError} from '../CompilerError';
9
-import {AliasingSignature} from '../Inference/AliasingEffects';
9
+import {AliasingEffect, AliasingSignature} from '../Inference/AliasingEffects';
10
+import {assertExhaustive} from '../Utils/utils';
11
import {
12
Effect,
13
GeneratedSource,
14
+ Hole,
15
makeDeclarationId,
16
makeIdentifierId,
17
makeInstructionId,
18
Place,
19
+ SourceLocation,
20
+ SpreadPattern,
21
ValueKind,
22
ValueReason,
23
} from './HIR';
29
PolyType,
30
PrimitiveType,
31
} from './Types';
32
+import {AliasingEffectConfig, AliasingSignatureConfig} from './TypeSchema';
33
34
/*
35
* This file exports types and defaults for JavaScript object shapes. These are
58
export function addFunction(
59
registry: ShapeRegistry,
60
properties: Iterable<[string, BuiltInType | PolyType]>,
56
- fn: Omit<FunctionSignature, 'hookKind'>,
61
+ fn: Omit<FunctionSignature, 'hookKind' | 'aliasing'> & {
62
+ aliasing?: AliasingSignatureConfig | null | undefined;
63
+ },
64
id: string | null = null,
65
isConstructor: boolean = false,
66
): FunctionType {
67
const shapeId = id ?? createAnonId();
68
+ const aliasing =
69
+ fn.aliasing != null
70
+ ? parseAliasingSignatureConfig(fn.aliasing, '<builtin>', GeneratedSource)
71
+ : null;
72
addShape(registry, shapeId, properties, {
73
...fn,
74
+ aliasing,
75
hookKind: null,
76
});
77
return {
89
*/
90
export function addHook(
91
registry: ShapeRegistry,
80
- fn: FunctionSignature & {hookKind: HookKind},
92
+ fn: Omit<FunctionSignature, 'aliasing'> & {
93
+ hookKind: HookKind;
94
+ aliasing?: AliasingSignatureConfig | null | undefined;
95
+ },
96
id: string | null = null,
97
): FunctionType {
98
const shapeId = id ?? createAnonId();
84
- addShape(registry, shapeId, [], fn);
99
+ const aliasing =
100
+ fn.aliasing != null
101
+ ? parseAliasingSignatureConfig(fn.aliasing, '<builtin>', GeneratedSource)
102
+ : null;
103
+ addShape(registry, shapeId, [], {...fn, aliasing});
104
return {
105
kind: 'Function',
106
return: fn.returnType,
109
};
110
}
111
112
+function parseAliasingSignatureConfig(
113
+ typeConfig: AliasingSignatureConfig,
114
+ moduleName: string,
115
+ loc: SourceLocation,
116
+): AliasingSignature {
117
+ const lifetimes = new Map<string, Place>();
118
+ function define(temp: string): Place {
119
+ CompilerError.invariant(!lifetimes.has(temp), {
120
+ reason: `Invalid type configuration for module`,
121
+ description: `Expected aliasing signature to have unique names for receiver, params, rest, returns, and temporaries in module '${moduleName}'`,
122
+ loc,
123
+ });
124
+ const place = signatureArgument(lifetimes.size);
125
+ lifetimes.set(temp, place);
126
+ return place;
127
+ }
128
+ function lookup(temp: string): Place {
129
+ const place = lifetimes.get(temp);
130
+ CompilerError.invariant(place != null, {
131
+ reason: `Invalid type configuration for module`,
132
+ description: `Expected aliasing signature effects to reference known names from receiver/params/rest/returns/temporaries, but '${temp}' is not a known name in '${moduleName}'`,
133
+ loc,
134
+ });
135
+ return place;
136
+ }
137
+ const receiver = define(typeConfig.receiver);
138
+ const params = typeConfig.params.map(define);
139
+ const rest = typeConfig.rest != null ? define(typeConfig.rest) : null;
140
+ const returns = define(typeConfig.returns);
141
+ const temporaries = typeConfig.temporaries.map(define);
142
+ const effects = typeConfig.effects.map(
143
+ (effect: AliasingEffectConfig): AliasingEffect => {
144
+ switch (effect.kind) {
145
+ case 'CreateFrom':
146
+ case 'Capture':
147
+ case 'Alias':
148
+ case 'Assign': {
149
+ const from = lookup(effect.from);
150
+ const into = lookup(effect.into);
151
+ return {
152
+ kind: effect.kind,
153
+ from,
154
+ into,
155
+ };
156
+ }
157
+ case 'Mutate':
158
+ case 'MutateTransitiveConditionally': {
159
+ const value = lookup(effect.value);
160
+ return {kind: effect.kind, value};
161
+ }
162
+ case 'Create': {
163
+ const into = lookup(effect.into);
164
+ return {
165
+ kind: 'Create',
166
+ into,
167
+ reason: effect.reason,
168
+ value: effect.value,
169
+ };
170
+ }
171
+ case 'Freeze': {
172
+ const value = lookup(effect.value);
173
+ return {
174
+ kind: 'Freeze',
175
+ value,
176
+ reason: effect.reason,
177
+ };
178
+ }
179
+ case 'Impure': {
180
+ const place = lookup(effect.place);
181
+ return {
182
+ kind: 'Impure',
183
+ place,
184
+ error: CompilerError.throwTodo({
185
+ reason: 'Support impure effect declarations',
186
+ loc: GeneratedSource,
187
+ }),
188
+ };
189
+ }
190
+ case 'Apply': {
191
+ const receiver = lookup(effect.receiver);
192
+ const fn = lookup(effect.function);
193
+ const args: Array<Place | SpreadPattern | Hole> = effect.args.map(
194
+ arg => {
195
+ if (typeof arg === 'string') {
196
+ return lookup(arg);
197
+ } else if (arg.kind === 'Spread') {
198
+ return {kind: 'Spread', place: lookup(arg.place)};
199
+ } else {
200
+ return arg;
201
+ }
202
+ },
203
+ );
204
+ const into = lookup(effect.into);
205
+ return {
206
+ kind: 'Apply',
207
+ receiver,
208
+ function: fn,
209
+ mutatesFunction: effect.mutatesFunction,
210
+ args,
211
+ into,
212
+ loc,
213
+ signature: null,
214
+ };
215
+ }
216
+ default: {
217
+ assertExhaustive(
218
+ effect,
219
+ `Unexpected effect kind '${(effect as any).kind}'`,
220
+ );
221
+ }
222
+ }
223
+ },
224
+ );
225
+ return {
226
+ receiver: receiver.identifier.id,
227
+ params: params.map(p => p.identifier.id),
228
+ rest: rest != null ? rest.identifier.id : null,
229
+ returns: returns.identifier.id,
230
+ temporaries,
231
+ effects,
232
+ };
233
+}
234
+
235
/*
236
* Add an object to an existing ShapeRegistry.
237
*
334
335
canonicalName?: string;
336
195
- aliasing?: AliasingSignature | null;
196
- todo_aliasing?: AliasingSignature | null;
337
+ aliasing?: AliasingSignature | null | undefined;
338
};
339
340
/*
461
calleeEffect: Effect.Store,
462
returnValueKind: ValueKind.Primitive,
463
aliasing: {
323
- receiver: makeIdentifierId(0),
464
+ receiver: '@receiver',
465
params: [],
325
- rest: makeIdentifierId(1),
326
- returns: makeIdentifierId(2),
466
+ rest: '@rest',
467
+ returns: '@returns',
468
temporaries: [],
469
effects: [
470
// Push directly mutates the array itself
330
- {kind: 'Mutate', value: signatureArgument(0)},
471
+ {kind: 'Mutate', value: '@receiver'},
472
// The arguments are captured into the array
473
{
474
kind: 'Capture',
334
- from: signatureArgument(1),
335
- into: signatureArgument(0),
475
+ from: '@rest',
476
+ into: '@receiver',
477
},
478
// Returns the new length, a primitive
479
{
480
kind: 'Create',
340
- into: signatureArgument(2),
481
+ into: '@returns',
482
value: ValueKind.Primitive,
483
reason: ValueReason.KnownReturnSignature,
484
},
515
noAlias: true,
516
mutableOnlyIfOperandsAreMutable: true,
517
aliasing: {
377
- receiver: makeIdentifierId(0),
378
- params: [makeIdentifierId(1)],
518
+ receiver: '@receiver',
519
+ params: ['@callback'],
520
rest: null,
380
- returns: makeIdentifierId(2),
521
+ returns: '@returns',
522
temporaries: [
523
// Temporary representing captured items of the receiver
383
- signatureArgument(3),
524
+ '@item',
525
// Temporary representing the result of the callback
385
- signatureArgument(4),
526
+ '@callbackReturn',
527
/*
528
* Undefined `this` arg to the callback. Note the signature does not
529
* support passing an explicit thisArg second param
530
*/
390
- signatureArgument(5),
531
+ '@thisArg',
532
],
533
effects: [
534
// Map creates a new mutable array
535
{
536
kind: 'Create',
396
- into: signatureArgument(2),
537
+ into: '@returns',
538
value: ValueKind.Mutable,
539
reason: ValueReason.KnownReturnSignature,
540
},
541
// The first arg to the callback is an item extracted from the receiver array
542
{
543
kind: 'CreateFrom',
403
- from: signatureArgument(0),
404
- into: signatureArgument(3),
544
+ from: '@receiver',
545
+ into: '@item',
546
},
547
// The undefined this for the callback
548
{
549
kind: 'Create',
409
- into: signatureArgument(5),
550
+ into: '@thisArg',
551
value: ValueKind.Primitive,
552
reason: ValueReason.KnownReturnSignature,
553
},
554
// calls the callback, returning the result into a temporary
555
{
556
kind: 'Apply',
416
- receiver: signatureArgument(5),
417
- args: [signatureArgument(3), {kind: 'Hole'}, signatureArgument(0)],
418
- function: signatureArgument(1),
419
- into: signatureArgument(4),
420
- signature: null,
557
+ receiver: '@thisArg',
558
+ args: ['@item', {kind: 'Hole'}, '@receiver'],
559
+ function: '@callback',
560
+ into: '@callbackReturn',
561
mutatesFunction: false,
422
- loc: GeneratedSource,
562
},
563
// captures the result of the callback into the return array
564
{
565
kind: 'Capture',
427
- from: signatureArgument(4),
428
- into: signatureArgument(2),
566
+ from: '@callbackReturn',
567
+ into: '@returns',
568
},
569
],
570
},
716
// returnValueKind is technically dependent on the ValueKind of the set itself
717
returnValueKind: ValueKind.Mutable,
718
aliasing: {
580
- receiver: makeIdentifierId(0),
719
+ receiver: '@receiver',
720
params: [],
582
- rest: makeIdentifierId(1),
583
- returns: makeIdentifierId(2),
721
+ rest: '@rest',
722
+ returns: '@returns',
723
temporaries: [],
724
effects: [
725
// Set.add returns the receiver Set
726
{
727
kind: 'Assign',
589
- from: signatureArgument(0),
590
- into: signatureArgument(2),
728
+ from: '@receiver',
729
+ into: '@returns',
730
},
731
// Set.add mutates the set itself
732
{
733
kind: 'Mutate',
595
- value: signatureArgument(0),
734
+ value: '@receiver',
735
},
736
// Captures the rest params into the set
737
{
738
kind: 'Capture',
600
- from: signatureArgument(1),
601
- into: signatureArgument(0),
739
+ from: '@rest',
740
+ into: '@receiver',
741
},
742
],
743
},
1442
hookKind: 'Custom',
1443
returnValueKind: ValueKind.Frozen,
1444
aliasing: {
1306
- receiver: makeIdentifierId(0),
1445
+ receiver: '@receiver',
1446
params: [],
1308
- rest: makeIdentifierId(1),
1309
- returns: makeIdentifierId(2),
1447
+ rest: '@rest',
1448
+ returns: '@returns',
1449
temporaries: [],
1450
effects: [
1451
// Freeze the arguments
1452
{
1453
kind: 'Freeze',
1315
- value: signatureArgument(1),
1454
+ value: '@rest',
1455
reason: ValueReason.HookCaptured,
1456
},
1457
// Returns a frozen value
1458
{
1459
kind: 'Create',
1321
- into: signatureArgument(2),
1460
+ into: '@returns',
1461
value: ValueKind.Frozen,
1462
reason: ValueReason.HookReturn,
1463
},
1464
// May alias any arguments into the return
1465
{
1466
kind: 'Alias',
1328
- from: signatureArgument(1),
1329
- into: signatureArgument(2),
1467
+ from: '@rest',
1468
+ into: '@returns',
1469
},
1470
],
1471
},