@samitouri / QOS-React-2 / commits / 4335f69987

[compiler] More readable alias signature declarations (#33530)

Now that we have support for defining aliasing signatures in moduleTypeProvider, which uses string names for receiver/args/returns/etc, we can reuse that same form for builtin declarations. The declarations are written in the unparsed form and than parsed/validated when registered (in the addFunction/addHook call). This also required flushing out configs/schemas for more effect types. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33530). * #33571 * #33558 * #33547 * #33543 * #33533 * #33532 * __->__ #33530

Joseph Savona committed Jun 18, 2025 at 15:47 UTC 4335f699870920932c8f30b6ad52173c3d819d16
4 files changed +327 -166
compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts
+13 -118
@@ -5,14 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {
9 - Effect,
10 - GeneratedSource,
11 - makeIdentifierId,
12 - Place,
13 - ValueKind,
14 - ValueReason,
15 -} from './HIR';
8 +import {Effect, ValueKind, ValueReason} from './HIR';
9 import {
10 BUILTIN_SHAPES,
11 BuiltInArrayId,
@@ -41,18 +34,12 @@ import {
34 addFunction,
35 addHook,
36 addObject,
44 - signatureArgument,
37 } from './ObjectShape';
38 import {BuiltInType, ObjectType, PolyType} from './Types';
47 -import {
48 - AliasingEffectConfig,
49 - AliasingSignatureConfig,
50 - TypeConfig,
51 -} from './TypeSchema';
39 +import {TypeConfig} from './TypeSchema';
40 import {assertExhaustive} from '../Utils/utils';
41 import {isHookName} from './Environment';
42 import {CompilerError, SourceLocation} from '..';
55 -import {AliasingEffect, AliasingSignature} from '../Inference/AliasingEffects';
43
44 /*
45 * This file exports types and defaults for JavaScript global objects.
@@ -658,35 +645,35 @@ const REACT_APIS: Array<[string, BuiltInType]> = [
645 hookKind: 'useEffect',
646 returnValueKind: ValueKind.Frozen,
647 aliasing: {
661 - receiver: makeIdentifierId(0),
648 + receiver: '@receiver',
649 params: [],
663 - rest: makeIdentifierId(1),
664 - returns: makeIdentifierId(2),
665 - temporaries: [signatureArgument(3)],
650 + rest: '@rest',
651 + returns: '@returns',
652 + temporaries: ['@effect'],
653 effects: [
654 // Freezes the function and deps
655 {
656 kind: 'Freeze',
670 - value: signatureArgument(1),
657 + value: '@rest',
658 reason: ValueReason.Effect,
659 },
660 // Internally creates an effect object that captures the function and deps
661 {
662 kind: 'Create',
676 - into: signatureArgument(3),
663 + into: '@effect',
664 value: ValueKind.Frozen,
665 reason: ValueReason.KnownReturnSignature,
666 },
667 // The effect stores the function and dependencies
668 {
669 kind: 'Capture',
683 - from: signatureArgument(1),
684 - into: signatureArgument(3),
670 + from: '@rest',
671 + into: '@effect',
672 },
673 // Returns undefined
674 {
675 kind: 'Create',
689 - into: signatureArgument(2),
676 + into: '@returns',
677 value: ValueKind.Primitive,
678 reason: ValueReason.KnownReturnSignature,
679 },
@@ -903,10 +890,6 @@ export function installTypeConfig(
890 }
891 }
892 case 'function': {
906 - const aliasing =
907 - typeConfig.aliasing != null
908 - ? parseAliasingSignatureConfig(typeConfig.aliasing, moduleName, loc)
909 - : null;
893 return addFunction(shapes, [], {
894 positionalParams: typeConfig.positionalParams,
895 restParam: typeConfig.restParam,
@@ -922,14 +905,10 @@ export function installTypeConfig(
905 noAlias: typeConfig.noAlias === true,
906 mutableOnlyIfOperandsAreMutable:
907 typeConfig.mutableOnlyIfOperandsAreMutable === true,
925 - aliasing,
908 + aliasing: typeConfig.aliasing,
909 });
910 }
911 case 'hook': {
929 - const aliasing =
930 - typeConfig.aliasing != null
931 - ? parseAliasingSignatureConfig(typeConfig.aliasing, moduleName, loc)
932 - : null;
912 return addHook(shapes, {
913 hookKind: 'Custom',
914 positionalParams: typeConfig.positionalParams ?? [],
@@ -944,7 +923,7 @@ export function installTypeConfig(
923 ),
924 returnValueKind: typeConfig.returnValueKind ?? ValueKind.Frozen,
925 noAlias: typeConfig.noAlias === true,
947 - aliasing,
926 + aliasing: typeConfig.aliasing,
927 });
928 }
929 case 'object': {
@@ -987,90 +966,6 @@ export function installTypeConfig(
966 }
967 }
968
990 -function parseAliasingSignatureConfig(
991 - typeConfig: AliasingSignatureConfig,
992 - moduleName: string,
993 - loc: SourceLocation,
994 -): AliasingSignature {
995 - const lifetimes = new Map<string, Place>();
996 - function define(temp: string): Place {
997 - CompilerError.invariant(!lifetimes.has(temp), {
998 - reason: `Invalid type configuration for module`,
999 - description: `Expected aliasing signature to have unique names for receiver, params, rest, returns, and temporaries in module '${moduleName}'`,
1000 - loc,
1001 - });
1002 - const place = signatureArgument(lifetimes.size);
1003 - lifetimes.set(temp, place);
1004 - return place;
1005 - }
1006 - function lookup(temp: string): Place {
1007 - const place = lifetimes.get(temp);
1008 - CompilerError.invariant(place != null, {
1009 - reason: `Invalid type configuration for module`,
1010 - description: `Expected aliasing signature effects to reference known names from receiver/params/rest/returns/temporaries, but '${temp}' is not a known name in '${moduleName}'`,
1011 - loc,
1012 - });
1013 - return place;
1014 - }
1015 - const receiver = define(typeConfig.receiver);
1016 - const params = typeConfig.params.map(define);
1017 - const rest = typeConfig.rest != null ? define(typeConfig.rest) : null;
1018 - const returns = define(typeConfig.returns);
1019 - const temporaries = typeConfig.temporaries.map(define);
1020 - const effects = typeConfig.effects.map(
1021 - (effect: AliasingEffectConfig): AliasingEffect => {
1022 - switch (effect.kind) {
1023 - case 'Assign': {
1024 - return {
1025 - kind: 'Assign',
1026 - from: lookup(effect.from),
1027 - into: lookup(effect.into),
1028 - };
1029 - }
1030 - case 'Create': {
1031 - return {
1032 - kind: 'Create',
1033 - into: lookup(effect.into),
1034 - reason: ValueReason.KnownReturnSignature,
1035 - value: effect.value,
1036 - };
1037 - }
1038 - case 'Freeze': {
1039 - return {
1040 - kind: 'Freeze',
1041 - value: lookup(effect.value),
1042 - reason: ValueReason.KnownReturnSignature,
1043 - };
1044 - }
1045 - case 'Impure': {
1046 - return {
1047 - kind: 'Impure',
1048 - place: lookup(effect.place),
1049 - error: CompilerError.throwTodo({
1050 - reason: 'Support impure effect declarations',
1051 - loc: GeneratedSource,
1052 - }),
1053 - };
1054 - }
1055 - default: {
1056 - assertExhaustive(
1057 - effect,
1058 - `Unexpected effect kind '${(effect as any).kind}'`,
1059 - );
1060 - }
1061 - }
1062 - },
1063 - );
1064 - return {
1065 - receiver: receiver.identifier.id,
1066 - params: params.map(p => p.identifier.id),
1067 - rest: rest != null ? rest.identifier.id : null,
1068 - returns: returns.identifier.id,
1069 - temporaries,
1070 - effects,
1071 - };
1072 -}
1073 -
969 export function getReanimatedModuleType(registry: ShapeRegistry): ObjectType {
970 // hooks that freeze args and return frozen value
971 const frozenHooks = [
compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts
+14
@@ -1453,6 +1453,20 @@ export const ValueKindSchema = z.enum([
1453 ValueKind.Context,
1454 ]);
1455
1456 +export const ValueReasonSchema = z.enum([
1457 + ValueReason.Context,
1458 + ValueReason.Effect,
1459 + ValueReason.Global,
1460 + ValueReason.HookCaptured,
1461 + ValueReason.HookReturn,
1462 + ValueReason.JsxCaptured,
1463 + ValueReason.KnownReturnSignature,
1464 + ValueReason.Other,
1465 + ValueReason.ReactiveFunctionArgument,
1466 + ValueReason.ReducerState,
1467 + ValueReason.State,
1468 +]);
1469 +
1470 // The effect with which a value is modified.
1471 export enum Effect {
1472 // Default value: not allowed after lifetime inference
compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts
+185 -46
@@ -6,14 +6,18 @@
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';
@@ -25,6 +29,7 @@ import {
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
@@ -53,13 +58,20 @@ function createAnonId(): string {
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 {
@@ -77,11 +89,18 @@ export function addFunction(
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,
@@ -90,6 +109,129 @@ export function addHook(
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 *
@@ -192,8 +334,7 @@ export type FunctionSignature = {
334
335 canonicalName?: string;
336
195 - aliasing?: AliasingSignature | null;
196 - todo_aliasing?: AliasingSignature | null;
337 + aliasing?: AliasingSignature | null | undefined;
338 };
339
340 /*
@@ -320,24 +461,24 @@ addObject(BUILTIN_SHAPES, BuiltInArrayId, [
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 },
@@ -374,58 +515,56 @@ addObject(BUILTIN_SHAPES, BuiltInArrayId, [
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 },
@@ -577,28 +716,28 @@ addObject(BUILTIN_SHAPES, BuiltInSetId, [
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 },
@@ -1303,30 +1442,30 @@ export const DefaultNonmutatingHook = addHook(
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 },
compiler/packages/babel-plugin-react-compiler/src/HIR/TypeSchema.ts
+115 -2
@@ -8,7 +8,12 @@
8 import {isValidIdentifier} from '@babel/types';
9 import {z} from 'zod';
10 import {Effect, ValueKind} from '..';
11 -import {EffectSchema, ValueKindSchema} from './HIR';
11 +import {
12 + EffectSchema,
13 + ValueKindSchema,
14 + ValueReason,
15 + ValueReasonSchema,
16 +} from './HIR';
17
18 export type ObjectPropertiesConfig = {[key: string]: TypeConfig};
19 export const ObjectPropertiesSchema: z.ZodType<ObjectPropertiesConfig> = z
@@ -38,23 +43,48 @@ export const LifetimeIdSchema = z.string().refine(id => id.startsWith('@'), {
43 export type FreezeEffectConfig = {
44 kind: 'Freeze';
45 value: string;
46 + reason: ValueReason;
47 };
48
49 export const FreezeEffectSchema: z.ZodType<FreezeEffectConfig> = z.object({
50 kind: z.literal('Freeze'),
51 value: LifetimeIdSchema,
52 + reason: ValueReasonSchema,
53 });
54
55 +export type MutateEffectConfig = {
56 + kind: 'Mutate';
57 + value: string;
58 +};
59 +
60 +export const MutateEffectSchema: z.ZodType<MutateEffectConfig> = z.object({
61 + kind: z.literal('Mutate'),
62 + value: LifetimeIdSchema,
63 +});
64 +
65 +export type MutateTransitiveConditionallyConfig = {
66 + kind: 'MutateTransitiveConditionally';
67 + value: string;
68 +};
69 +
70 +export const MutateTransitiveConditionallySchema: z.ZodType<MutateTransitiveConditionallyConfig> =
71 + z.object({
72 + kind: z.literal('MutateTransitiveConditionally'),
73 + value: LifetimeIdSchema,
74 + });
75 +
76 export type CreateEffectConfig = {
77 kind: 'Create';
78 into: string;
79 value: ValueKind;
80 + reason: ValueReason;
81 };
82
83 export const CreateEffectSchema: z.ZodType<CreateEffectConfig> = z.object({
84 kind: z.literal('Create'),
85 into: LifetimeIdSchema,
86 value: ValueKindSchema,
87 + reason: ValueReasonSchema,
88 });
89
90 export type AssignEffectConfig = {
@@ -69,6 +99,77 @@ export const AssignEffectSchema: z.ZodType<AssignEffectConfig> = z.object({
99 into: LifetimeIdSchema,
100 });
101
102 +export type AliasEffectConfig = {
103 + kind: 'Alias';
104 + from: string;
105 + into: string;
106 +};
107 +
108 +export const AliasEffectSchema: z.ZodType<AliasEffectConfig> = z.object({
109 + kind: z.literal('Alias'),
110 + from: LifetimeIdSchema,
111 + into: LifetimeIdSchema,
112 +});
113 +
114 +export type CaptureEffectConfig = {
115 + kind: 'Capture';
116 + from: string;
117 + into: string;
118 +};
119 +
120 +export const CaptureEffectSchema: z.ZodType<CaptureEffectConfig> = z.object({
121 + kind: z.literal('Capture'),
122 + from: LifetimeIdSchema,
123 + into: LifetimeIdSchema,
124 +});
125 +
126 +export type CreateFromEffectConfig = {
127 + kind: 'CreateFrom';
128 + from: string;
129 + into: string;
130 +};
131 +
132 +export const CreateFromEffectSchema: z.ZodType<CreateFromEffectConfig> =
133 + z.object({
134 + kind: z.literal('CreateFrom'),
135 + from: LifetimeIdSchema,
136 + into: LifetimeIdSchema,
137 + });
138 +
139 +export type ApplyArgConfig =
140 + | string
141 + | {kind: 'Spread'; place: string}
142 + | {kind: 'Hole'};
143 +
144 +export const ApplyArgSchema: z.ZodType<ApplyArgConfig> = z.union([
145 + LifetimeIdSchema,
146 + z.object({
147 + kind: z.literal('Spread'),
148 + place: LifetimeIdSchema,
149 + }),
150 + z.object({
151 + kind: z.literal('Hole'),
152 + }),
153 +]);
154 +
155 +export type ApplyEffectConfig = {
156 + kind: 'Apply';
157 + receiver: string;
158 + function: string;
159 + mutatesFunction: boolean;
160 + args: Array<ApplyArgConfig>;
161 + into: string;
162 +};
163 +
164 +export const ApplyEffectSchema: z.ZodType<ApplyEffectConfig> = z.object({
165 + kind: z.literal('Apply'),
166 + receiver: LifetimeIdSchema,
167 + function: LifetimeIdSchema,
168 + mutatesFunction: z.boolean(),
169 + args: z.array(ApplyArgSchema),
170 + into: LifetimeIdSchema,
171 +});
172 +
173 export type ImpureEffectConfig = {
174 kind: 'Impure';
175 place: string;
@@ -82,14 +183,26 @@ export const ImpureEffectSchema: z.ZodType<ImpureEffectConfig> = z.object({
183 export type AliasingEffectConfig =
184 | FreezeEffectConfig
185 | CreateEffectConfig
186 + | CreateFromEffectConfig
187 | AssignEffectConfig
86 - | ImpureEffectConfig;
188 + | AliasEffectConfig
189 + | CaptureEffectConfig
190 + | ImpureEffectConfig
191 + | MutateEffectConfig
192 + | MutateTransitiveConditionallyConfig
193 + | ApplyEffectConfig;
194
195 export const AliasingEffectSchema: z.ZodType<AliasingEffectConfig> = z.union([
196 FreezeEffectSchema,
197 CreateEffectSchema,
198 + CreateFromEffectSchema,
199 AssignEffectSchema,
200 + AliasEffectSchema,
201 + CaptureEffectSchema,
202 ImpureEffectSchema,
203 + MutateEffectSchema,
204 + MutateTransitiveConditionallySchema,
205 + ApplyEffectSchema,
206 ]);
207
208 export type AliasingSignatureConfig = {