1
+ //! The intermediate representation (IR) for a Roc module that has been monomorphized.
2
+ //!
3
+ //! Monomorphization, also known as type specialization, is the process of creating a distinct copy
4
+ //! of each instance of a generic function or value based on all specific usages in a program.
5
+ //! For example; a function with the type `Num a -> Num a` may only be called in the program with a
6
+ //! `U64` and a `I64`. Specialization will then create two functions with the types `U64 -> U64` and
7
+ //! `I64 -> I64`.
8
+ //! This trades off some compile time for a much better runtime performance, since we don't need to
9
+ //! look up which implementation to call at runtime (AKA dynamic dispatch).
10
+ //!
11
+ //! Doing type specialization as the first build stage helps simplify compilation of lambda sets, or
12
+ //! values captured by closures.
13
+ //!
14
+ //! The values in this module represent all data for a single type-specialized module, except for
15
+ //! interned data which resides in the `ModuleEnv`. This IR has a very similar structure to the next
16
+ //! stage's IR (`lift_functions`), but not quite the same. For now, we have designed our compiler
17
+ //! stages to be simple and correct at the cost of not deduplicating similar code. In the future,
18
+ //! we may decide to combine the IRs of some build stages to avoid needing to convert lots of
19
+ //! equivalent data.
20
+
1
21
const std = @import ("std" );
2
22
const base = @import ("../../base.zig" );
3
23
const types_module = @import ("../../types.zig" );
@@ -13,13 +33,20 @@ const Self = @This();
13
33
env : * base.ModuleEnv ,
14
34
exposed_values : std .AutoHashMap (Ident.Idx , Expr .Idx ),
15
35
exposed_functions : std .AutoHashMap (Ident.Idx , Function ),
36
+ /// All types in the module
16
37
types : Type.List ,
38
+ /// All expressions in the module
17
39
exprs : Expr.List ,
40
+ /// All typed expressions in the module
18
41
typed_exprs : Expr.Typed.List ,
42
+ /// All patterns (for pattern matching, destructuring, var name) in the module
19
43
patterns : Pattern.List ,
44
+ /// All typed patterns in the module
20
45
typed_patterns : Pattern.Typed.List ,
46
+ /// All typed identifiers in the module
21
47
typed_idents : TypedIdent.List ,
22
- when_branches : WhenBranch.List ,
48
+ /// All match branches in the module
49
+ match_branches : MatchBranch.List ,
23
50
24
51
pub fn init (env : * base.ModuleEnv ) Self {
25
52
return Self {
@@ -32,7 +59,7 @@ pub fn init(env: *base.ModuleEnv) Self {
32
59
.patterns = .{},
33
60
.typed_patterns = .{},
34
61
.typed_idents = .{},
35
- .when_branches = .{},
62
+ .match_branches = .{},
36
63
};
37
64
}
38
65
@@ -45,209 +72,247 @@ pub fn deinit(self: *Self) void {
45
72
self .patterns .deinit (self .env .gpa );
46
73
self .typed_patterns .deinit (self .env .gpa );
47
74
self .typed_idents .deinit (self .env .gpa );
48
- self .when_branches .deinit (self .env .gpa );
75
+ self .match_branches .deinit (self .env .gpa );
49
76
}
50
77
51
- /// todo
78
+ /// Represents a concrete (no type variables,...) Roc type e.g. `U64`, `Str`, `List(U64)`.
52
79
pub const Type = union (enum ) {
80
+ /// e.g. Int, Bool, Str
53
81
primitive : types_module.Primitive ,
82
+ /// Holds unknown Roc type for use with platform or can be used to improve perf in rare cases https://www.roc-lang.org/builtins/Box
54
83
box : Type.Idx ,
84
+ /// e.g. List(U64)
55
85
list : Type.Idx ,
86
+ /// Records, tuples and tag union payload become structs
56
87
@"struct" : Type.NonEmptySlice ,
88
+ /// e.g. `[Red, Yellow, Green]`
57
89
tag_union : Type.NonEmptySlice ,
90
+ /// A function that has a return value and 0 or more arguments
58
91
func : struct {
92
+ /// A slice containing the return value followed by the arguments
59
93
ret_then_args : Type.NonEmptySlice ,
60
94
},
61
- /// todo
95
+ /// list of Type
62
96
pub const List = collections .SafeList (@This ());
63
- /// todo
97
+ /// Index into Type.List
64
98
pub const Idx = List .Idx ;
65
- /// todo
99
+ /// Sublist reference of Type.List
66
100
pub const Slice = List .Slice ;
67
- /// todo
101
+ /// Sublist reference into Type.List that is guaranteed to be non-empty
68
102
pub const NonEmptySlice = List .NonEmptySlice ;
69
103
};
70
104
71
- /// todo
105
+ /// Represents a Roc expression
72
106
pub const Expr = union (enum ) {
107
+ /// e.g. `x = 1`
73
108
let : Def ,
109
+ /// e.g. "abc"
74
110
str : StringLiteral ,
111
+ /// e.g. 123
75
112
number : base.Literal.Num ,
113
+ /// e.g. [1, 2, 3]
76
114
list : struct {
77
115
elem_type : Type.Idx ,
78
116
elems : Expr.Slice ,
79
117
},
118
+ /// e.g. `pf.Stdout` or `x`
80
119
lookup : struct {
81
120
ident : Ident.Idx ,
82
121
type : Type .Idx ,
83
122
},
84
-
123
+ /// e.g `fibo(5)`
85
124
call : struct {
86
125
fn_type : Type.Idx ,
126
+ // ???
87
127
fn_expr : Expr.Idx ,
88
128
args : Expr.Typed.Slice ,
89
129
},
90
-
130
+ /// e.g. `|x| x * 2`
91
131
lambda : struct {
92
132
fn_type : Type.Idx ,
93
133
arguments : Pattern.Typed.Slice ,
94
134
body : Expr.Idx ,
95
135
recursive : base.Recursive ,
96
136
},
97
-
137
+ /// Represents the empty record `{}`
98
138
unit ,
99
-
139
+ /// Record or tuple becomes struct
100
140
@"struct" : Expr.NonEmptySlice ,
101
-
141
+ /// Record or tuple access
102
142
struct_access : struct {
103
143
record_expr : Expr.Idx ,
104
144
record_type : Type.Idx ,
105
145
field_type : Type.Idx ,
106
146
field_id : Ident.Idx ,
107
147
},
108
-
148
+ /// e.g. `Ok(1)`
109
149
tag : struct {
150
+ /// Numeric representation of the tag variant
110
151
discriminant : u16 ,
152
+ /// e.g. `Result` for `Ok(1)`
111
153
tag_union_type : Type.Idx ,
154
+ /// e.g. `1` for `Ok(1)`
112
155
args : Expr.Typed.Slice ,
113
156
},
114
-
115
- when : struct {
116
- /// The value being matched on
157
+ /// from pattern matching with `match`
158
+ match : struct {
159
+ /// The value being matched on, e.g. `match value is`
117
160
value : Expr.Idx ,
118
161
/// The type of the value being matched on
119
162
value_type : Type.Idx ,
120
- /// The return type of all branches and thus the whole when expression
163
+ /// The return type of all branches and thus the whole match expression
121
164
branch_type : Type.Idx ,
122
- /// The branches of the when expression
123
- branches : WhenBranch .NonEmptySlice ,
165
+ /// The branches of the match expression
166
+ branches : MatchBranch .NonEmptySlice ,
124
167
},
125
168
126
169
compiler_bug : Problem.Compiler ,
127
170
128
- /// todo
171
+ /// List of Expr
129
172
pub const List = collections .SafeList (@This ());
130
- /// todo
173
+ /// Index into an Expr.List
131
174
pub const Idx = List .Idx ;
132
- /// todo
175
+ /// Sublist reference of Expr.List
133
176
pub const Slice = List .Slice ;
134
- /// todo
177
+ /// Sublist reference into Expr.List that is guaranteed to be non-empty
135
178
pub const NonEmptySlice = List .NonEmptySlice ;
136
- /// todo
179
+ /// Expression with accompanying type
137
180
pub const Typed = struct {
138
181
expr : Expr.Idx ,
139
182
type : Type .Idx ,
140
- /// todo
183
+ /// List of Expr.Typed
141
184
pub const List = collections .SafeMultiList (@This ());
142
- /// todo
185
+ /// Sublist reference into Expr.Typed.List
143
186
pub const Slice = Typed .List .Slice ;
144
187
};
145
188
};
146
189
147
190
/// A definition, e.g. `x = foo`
148
191
pub const Def = struct {
192
+ /// For what's to the left of `=`, could be a var name or destructuring
149
193
pattern : Pattern.Idx ,
150
- /// Named variables in the pattern, e.g. `a` in `Ok a -> `
194
+ /// Named variables in the pattern, e.g. `a` and `b` in `{a, b} = ... `
151
195
pattern_vars : TypedIdent.Slice ,
196
+ /// expression to the right of `=`
152
197
expr : Expr.Idx ,
198
+ /// type of the expression to the right of `=`
153
199
expr_type : Type.Idx ,
154
- /// todo
200
+ /// List of Def
155
201
pub const List = collections .SafeMultiList (@This ());
156
- /// todo
202
+ /// Sublist reference into Def.List
157
203
pub const Slice = List .Slice ;
158
204
};
159
205
160
- /// todo
161
- pub const WhenBranch = struct {
206
+ /// Branch of a `match` expression, e.g. `Green -> "green"`
207
+ pub const MatchBranch = struct {
162
208
/// The pattern(s) to match the value against
163
209
patterns : Pattern.NonEmptySlice ,
164
210
/// A boolean expression that must be true for this branch to be taken
165
211
guard : ? Expr.Idx ,
166
212
/// The expression to produce if the pattern matches
167
213
value : Expr.Idx ,
168
- /// todo
214
+ /// List of MatchBranch
169
215
pub const List = collections .SafeList (@This ());
170
- /// todo
216
+ /// Reference to non-empty sublist into MatchBranch.List
171
217
pub const NonEmptySlice = List .NonEmptySlice ;
172
218
};
173
219
174
- /// todo
220
+ /// e.g. `|x| x * 2`
175
221
pub const Function = struct {
176
222
args : Pattern.Slice ,
177
223
return_type : Type.Idx ,
224
+ /// ??? Is expr the body of the function?
178
225
expr : Expr.Idx ,
179
226
};
180
227
181
- /// todo
228
+ /// For record/tuple destructuring, e.g. `{ x, y: 123 } -> ...` contains two StructDestruct: one for `x` and one for `y`.
182
229
pub const StructDestruct = struct {
183
230
ident : Ident.Idx ,
184
231
field : Ident.Idx ,
185
232
kind : Kind ,
186
- /// todo
187
233
pub const Kind = union (enum ) {
234
+ /// e.g `x` in `{ x, y: 123 }` is required
188
235
required ,
236
+ /// e.g. .{ .num_literal = 123 } in `{ x, y: 123 }`. Keeping the value of y around is not required
189
237
guard : Pattern.Typed ,
190
238
};
191
- /// todo
239
+ /// List of StructDestruct
192
240
pub const List = collections .SafeMultiList (@This ());
193
- /// todo
241
+ /// Reference to sublist into StructDestruct.List
194
242
pub const Slice = List .Slice ;
195
243
};
196
244
197
- /// todo
245
+ /// Represents a pattern used in pattern matching e.g. `Ok x` as part of a match branch
198
246
pub const Pattern = union (enum ) {
247
+ /// e.g. `x`
199
248
identifier : Ident.Idx ,
249
+ /// e.g. `{ x, y } as data` in `{ x, y } as data -> call(data)`
200
250
as : struct {
251
+ /// e.g. `{ x, y }` in `{ x, y } as data`
201
252
pattern : Pattern.Idx ,
253
+ /// e.g. `data` in `{ x, y } as data`
202
254
ident : Ident.Idx ,
203
255
},
204
256
str_literal : StringLiteral.Idx ,
205
257
number_literal : base.Literal.Num ,
258
+ /// e.g. `Ok(x)` in `Ok(x) ->`
206
259
applied_tag : struct {
260
+ /// Type of tag union e.g. `Result`
207
261
tag_union_type : Type.Idx ,
208
262
tag_name : Ident.Idx ,
263
+ /// e.g. `x` in `Ok(x)`
209
264
args : Pattern.Slice ,
210
265
},
266
+ /// e.g. `{x, y}` in `{x, y} -> Point(x, y)`
211
267
struct_destructure : struct {
212
268
struct_type : Type.Idx ,
269
+ /// e.g. for `{ x, y: 123 } -> ...` there are two StructDestruct; one for x and one for y
213
270
destructs : StructDestruct.Slice ,
271
+ /// e.g. `..` in `{x, y, ..}`
214
272
opt_spread : ? Pattern.Typed ,
215
273
},
274
+ /// e.g. [Foo, Bar, ..]
216
275
list : struct {
217
276
elem_type : Type.Idx ,
277
+ /// e.g. Foo and Bar in `[Foo, Bar, ..]`
218
278
patterns : Pattern.Slice ,
219
-
279
+ /// refers to e.g. `..tail` in `[head, ..tail]`
220
280
opt_rest : ? struct {
281
+ /// position in list of `..`; e.g. 0 in `[.., Foo, Bar]`
221
282
offset : u16 ,
283
+ /// e.g. tail in `..tail`
222
284
name : ? Ident.Idx ,
223
285
},
224
286
},
287
+ /// _ is used as a catch-all, it matches anything
225
288
underscore ,
226
289
compiler_bug : Problem.Compiler ,
227
- /// todo
290
+ /// List of Pattern
228
291
pub const List = collections .SafeList (@This ());
229
- /// todo
292
+ /// Index into Pattern.List
230
293
pub const Idx = List .Idx ;
231
- /// todo
294
+ /// Sublist reference of Pattern.List
232
295
pub const Slice = List .Slice ;
233
- /// todo
296
+ /// Sublist reference into Pattern.List that is guaranteed to be non-empty
234
297
pub const NonEmptySlice = List .NonEmptySlice ;
235
- /// todo
298
+ /// Pattern with accompanying type
236
299
pub const Typed = struct {
237
300
pattern : Pattern.Idx ,
238
301
type : Type .Idx ,
239
- /// todo
302
+ /// List of Pattern.Typed
240
303
pub const List = collections .SafeMultiList (@This ());
241
- /// todo
304
+ /// Reference to sublist into Pattern.Typed.List
242
305
pub const Slice = Typed .List .Slice ;
243
306
};
244
307
};
245
- /// todo
308
+
309
+ /// Identifier along with its type
246
310
pub const TypedIdent = struct {
311
+ /// e.g. `x`
247
312
pattern : Pattern.Idx ,
248
313
type : Type .Idx ,
249
- /// todo
314
+ /// List of TypedIdent
250
315
pub const List = collections .SafeMultiList (@This ());
251
- /// todo
316
+ /// Reference to sublist into TypedIdent.List
252
317
pub const Slice = List .Slice ;
253
318
};
0 commit comments