@@ -9,6 +9,7 @@ import {CompilerError} from '../CompilerError';
9
9
import {
10
10
BasicBlock ,
11
11
BlockId ,
12
+ DeclarationId ,
12
13
HIRFunction ,
13
14
Identifier ,
14
15
InstructionKind ,
@@ -27,6 +28,118 @@ import {
27
28
terminalFallthrough ,
28
29
} from '../HIR/visitors' ;
29
30
31
+ export function leaveSSA ( fn : HIRFunction ) : void {
32
+ const declarations = new Map < DeclarationId , LValue | LValuePattern > ( ) ;
33
+ for ( const param of fn . params ) {
34
+ let place : Place = param . kind === 'Identifier' ? param : param . place ;
35
+ if ( place . identifier . name !== null ) {
36
+ declarations . set ( place . identifier . declarationId , {
37
+ kind : InstructionKind . Let ,
38
+ place,
39
+ } ) ;
40
+ }
41
+ }
42
+ for ( const [ , block ] of fn . body . blocks ) {
43
+ for ( const instr of block . instructions ) {
44
+ const { value} = instr ;
45
+ switch ( value . kind ) {
46
+ case 'DeclareContext' :
47
+ case 'DeclareLocal' : {
48
+ const lvalue = value . lvalue ;
49
+ CompilerError . invariant (
50
+ ! declarations . has ( lvalue . place . identifier . declarationId ) ,
51
+ {
52
+ reason : `Expected variable not to be defined prior to declaration` ,
53
+ description : `${ printPlace ( lvalue . place ) } was already defined` ,
54
+ loc : lvalue . place . loc ,
55
+ } ,
56
+ ) ;
57
+ declarations . set ( lvalue . place . identifier . declarationId , lvalue ) ;
58
+ if ( lvalue . kind === InstructionKind . Let ) {
59
+ lvalue . kind = InstructionKind . Const ;
60
+ }
61
+ break ;
62
+ }
63
+ case 'StoreContext' :
64
+ case 'StoreLocal' : {
65
+ const lvalue = value . lvalue ;
66
+ if ( lvalue . place . identifier . name !== null ) {
67
+ if ( lvalue . kind === InstructionKind . Reassign ) {
68
+ const declaration = declarations . get (
69
+ lvalue . place . identifier . declarationId ,
70
+ ) ;
71
+ CompilerError . invariant ( declaration !== undefined , {
72
+ reason : `Expected variable to have been defined` ,
73
+ description : `No declaration for ${ printPlace ( lvalue . place ) } ` ,
74
+ loc : lvalue . place . loc ,
75
+ } ) ;
76
+ declaration . kind = InstructionKind . Let ;
77
+ } else {
78
+ CompilerError . invariant (
79
+ ! declarations . has ( lvalue . place . identifier . declarationId ) ,
80
+ {
81
+ reason : `Expected variable not to be defined prior to declaration` ,
82
+ description : `${ printPlace ( lvalue . place ) } was already defined` ,
83
+ loc : lvalue . place . loc ,
84
+ } ,
85
+ ) ;
86
+ declarations . set ( lvalue . place . identifier . declarationId , lvalue ) ;
87
+ if ( lvalue . kind === InstructionKind . Let ) {
88
+ lvalue . kind = InstructionKind . Const ;
89
+ }
90
+ }
91
+ }
92
+ break ;
93
+ }
94
+ case 'Destructure' : {
95
+ const lvalue = value . lvalue ;
96
+ if ( lvalue . kind === InstructionKind . Reassign ) {
97
+ for ( const place of eachPatternOperand ( lvalue . pattern ) ) {
98
+ const declaration = declarations . get (
99
+ place . identifier . declarationId ,
100
+ ) ;
101
+ CompilerError . invariant ( declaration !== undefined , {
102
+ reason : `Expected variable to have been defined` ,
103
+ description : `No declaration for ${ printPlace ( place ) } ` ,
104
+ loc : place . loc ,
105
+ } ) ;
106
+ declaration . kind = InstructionKind . Let ;
107
+ }
108
+ } else {
109
+ for ( const place of eachPatternOperand ( lvalue . pattern ) ) {
110
+ CompilerError . invariant (
111
+ ! declarations . has ( place . identifier . declarationId ) ,
112
+ {
113
+ reason : `Expected variable not to be defined prior to declaration` ,
114
+ description : `${ printPlace ( place ) } was already defined` ,
115
+ loc : place . loc ,
116
+ } ,
117
+ ) ;
118
+ declarations . set ( place . identifier . declarationId , lvalue ) ;
119
+ }
120
+ if ( lvalue . kind === InstructionKind . Let ) {
121
+ lvalue . kind = InstructionKind . Const ;
122
+ }
123
+ }
124
+ break ;
125
+ }
126
+ case 'PostfixUpdate' :
127
+ case 'PrefixUpdate' : {
128
+ const lvalue = value . lvalue ;
129
+ const declaration = declarations . get ( lvalue . identifier . declarationId ) ;
130
+ CompilerError . invariant ( declaration !== undefined , {
131
+ reason : `Expected variable to have been defined` ,
132
+ description : `No declaration for ${ printPlace ( lvalue ) } ` ,
133
+ loc : lvalue . loc ,
134
+ } ) ;
135
+ declaration . kind = InstructionKind . Let ;
136
+ break ;
137
+ }
138
+ }
139
+ }
140
+ }
141
+ }
142
+
30
143
/*
31
144
* Removes SSA form by converting all phis into explicit bindings and assignments. There are two main categories
32
145
* of phis:
@@ -89,7 +202,7 @@ import {
89
202
* )
90
203
* ```
91
204
*/
92
- export function leaveSSA ( fn : HIRFunction ) : void {
205
+ export function _leaveSSA ( fn : HIRFunction ) : void {
93
206
// Maps identifier names to their original declaration.
94
207
const declarations : Map <
95
208
string ,
0 commit comments