Skip to content

Commit 3ca3271

Browse files
committed
Add tests and do some refactoring
1 parent 5a3ee45 commit 3ca3271

18 files changed

+572
-212
lines changed

compiler-core/src/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub mod visit;
99
pub use self::typed::{InvalidExpression, TypedExpr};
1010
pub use self::untyped::{FunctionLiteralKind, UntypedExpr};
1111

12-
pub use self::constant::{Constant, TypedConstant, UntypedConstant};
12+
pub use self::constant::{Constant, ConstantRecordUpdateArg, TypedConstant, UntypedConstant};
1313

1414
use crate::analyse::Inferred;
1515
use crate::ast::typed::pairwise_all;

compiler-core/src/ast/constant.rs

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,23 @@ pub enum Constant<T, RecordTag> {
4040
module: Option<(EcoString, SrcSpan)>,
4141
name: EcoString,
4242
arguments: Vec<CallArg<Self>>,
43-
spread: Option<Box<Self>>,
4443
tag: RecordTag,
4544
type_: T,
4645
field_map: Option<FieldMap>,
4746
record_constructor: Option<Box<ValueConstructor>>,
4847
},
4948

49+
RecordUpdate {
50+
location: SrcSpan,
51+
module: Option<(EcoString, SrcSpan)>,
52+
name: EcoString,
53+
record: Box<Self>,
54+
arguments: Vec<ConstantRecordUpdateArg<Self>>,
55+
tag: RecordTag,
56+
type_: T,
57+
field_map: Option<FieldMap>,
58+
},
59+
5060
BitArray {
5161
location: SrcSpan,
5262
segments: Vec<BitArraySegment<Self, T>>,
@@ -86,6 +96,7 @@ impl TypedConstant {
8696
}
8797
Constant::List { type_, .. }
8898
| Constant::Record { type_, .. }
99+
| Constant::RecordUpdate { type_, .. }
89100
| Constant::Var { type_, .. }
90101
| Constant::Invalid { type_, .. } => type_.clone(),
91102
}
@@ -105,12 +116,19 @@ impl TypedConstant {
105116
.iter()
106117
.find_map(|element| element.find_node(byte_index))
107118
.unwrap_or(Located::Constant(self)),
108-
Constant::Record {
109-
arguments, spread, ..
110-
} => arguments
119+
Constant::Record { arguments, .. } => arguments
111120
.iter()
112121
.find_map(|argument| argument.find_node(byte_index))
113-
.or_else(|| spread.as_ref().and_then(|s| s.find_node(byte_index)))
122+
.unwrap_or(Located::Constant(self)),
123+
Constant::RecordUpdate {
124+
record, arguments, ..
125+
} => record
126+
.find_node(byte_index)
127+
.or_else(|| {
128+
arguments
129+
.iter()
130+
.find_map(|arg| arg.value.find_node(byte_index))
131+
})
114132
.unwrap_or(Located::Constant(self)),
115133
Constant::BitArray { segments, .. } => segments
116134
.iter()
@@ -143,6 +161,7 @@ impl TypedConstant {
143161
} => value_constructor
144162
.as_ref()
145163
.map(|constructor| constructor.definition_location()),
164+
Constant::RecordUpdate { .. } => None,
146165
}
147166
}
148167

@@ -160,17 +179,20 @@ impl TypedConstant {
160179
.map(|element| element.referenced_variables())
161180
.fold(im::hashset![], im::HashSet::union),
162181

163-
Constant::Record {
164-
arguments, spread, ..
182+
Constant::Record { arguments, .. } => arguments
183+
.iter()
184+
.map(|argument| argument.value.referenced_variables())
185+
.fold(im::hashset![], im::HashSet::union),
186+
187+
Constant::RecordUpdate {
188+
record, arguments, ..
165189
} => {
190+
let record_vars = record.referenced_variables();
166191
let arg_vars = arguments
167192
.iter()
168-
.map(|argument| argument.value.referenced_variables())
193+
.map(|arg| arg.value.referenced_variables())
169194
.fold(im::hashset![], im::HashSet::union);
170-
match spread {
171-
Some(spread) => arg_vars.union(spread.referenced_variables()),
172-
None => arg_vars,
173-
}
195+
record_vars.union(arg_vars)
174196
}
175197

176198
Constant::BitArray { segments, .. } => segments
@@ -258,6 +280,37 @@ impl TypedConstant {
258280
}
259281
(Constant::Record { .. }, _) => false,
260282

283+
(
284+
Constant::RecordUpdate {
285+
module,
286+
name,
287+
record,
288+
arguments,
289+
..
290+
},
291+
Constant::RecordUpdate {
292+
module: other_module,
293+
name: other_name,
294+
record: other_record,
295+
arguments: other_arguments,
296+
..
297+
},
298+
) => {
299+
let modules_are_equal = match (module, other_module) {
300+
(None, None) => true,
301+
(None, Some(_)) | (Some(_), None) => false,
302+
(Some((one, _)), Some((other, _))) => one == other,
303+
};
304+
305+
modules_are_equal
306+
&& name == other_name
307+
&& record.syntactically_eq(other_record)
308+
&& pairwise_all(arguments, other_arguments, |(one, other)| {
309+
one.label == other.label && one.value.syntactically_eq(&other.value)
310+
})
311+
}
312+
(Constant::RecordUpdate { .. }, _) => false,
313+
261314
(
262315
Constant::BitArray { segments, .. },
263316
Constant::BitArray {
@@ -317,6 +370,7 @@ impl<A, B> Constant<A, B> {
317370
| Constant::Tuple { location, .. }
318371
| Constant::String { location, .. }
319372
| Constant::Record { location, .. }
373+
| Constant::RecordUpdate { location, .. }
320374
| Constant::BitArray { location, .. }
321375
| Constant::Var { location, .. }
322376
| Constant::Invalid { location, .. }
@@ -335,6 +389,7 @@ impl<A, B> Constant<A, B> {
335389
Constant::Tuple { .. }
336390
| Constant::List { .. }
337391
| Constant::Record { .. }
392+
| Constant::RecordUpdate { .. }
338393
| Constant::BitArray { .. }
339394
| Constant::StringConcatenation { .. }
340395
| Constant::Invalid { .. } => false,
@@ -357,3 +412,26 @@ impl<A, B> bit_array::GetLiteralValue for Constant<A, B> {
357412
}
358413
}
359414
}
415+
416+
#[derive(Debug, Clone, PartialEq, Eq)]
417+
pub struct ConstantRecordUpdateArg<Constant> {
418+
pub label: EcoString,
419+
pub location: SrcSpan,
420+
pub value: Constant,
421+
}
422+
423+
impl<Constant> ConstantRecordUpdateArg<Constant> {
424+
#[must_use]
425+
pub fn uses_label_shorthand(&self) -> bool
426+
where
427+
Constant: HasLocation,
428+
{
429+
self.value.location() == self.location
430+
}
431+
}
432+
433+
impl<Constant> HasLocation for ConstantRecordUpdateArg<Constant> {
434+
fn location(&self) -> SrcSpan {
435+
self.location
436+
}
437+
}

compiler-core/src/ast_folder.rs

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ use vec1::Vec1;
66
use crate::{
77
analyse::Inferred,
88
ast::{
9-
Assert, AssignName, Assignment, BinOp, BitArraySize, CallArg, Constant, Definition,
10-
FunctionLiteralKind, Pattern, RecordBeingUpdated, SrcSpan, Statement, TailPattern,
11-
TargetedDefinition, TodoKind, TypeAst, TypeAstConstructor, TypeAstFn, TypeAstHole,
12-
TypeAstTuple, TypeAstVar, UntypedArg, UntypedAssert, UntypedAssignment, UntypedClause,
13-
UntypedConstant, UntypedConstantBitArraySegment, UntypedCustomType, UntypedDefinition,
14-
UntypedExpr, UntypedExprBitArraySegment, UntypedFunction, UntypedImport, UntypedModule,
15-
UntypedModuleConstant, UntypedPattern, UntypedPatternBitArraySegment,
16-
UntypedRecordUpdateArg, UntypedStatement, UntypedTailPattern, UntypedTypeAlias, UntypedUse,
17-
UntypedUseAssignment, Use, UseAssignment,
9+
Assert, AssignName, Assignment, BinOp, BitArraySize, CallArg, Constant,
10+
ConstantRecordUpdateArg, Definition, FunctionLiteralKind, Pattern, RecordBeingUpdated,
11+
SrcSpan, Statement, TailPattern, TargetedDefinition, TodoKind, TypeAst, TypeAstConstructor,
12+
TypeAstFn, TypeAstHole, TypeAstTuple, TypeAstVar, UntypedArg, UntypedAssert,
13+
UntypedAssignment, UntypedClause, UntypedConstant, UntypedConstantBitArraySegment,
14+
UntypedCustomType, UntypedDefinition, UntypedExpr, UntypedExprBitArraySegment,
15+
UntypedFunction, UntypedImport, UntypedModule, UntypedModuleConstant, UntypedPattern,
16+
UntypedPatternBitArraySegment, UntypedRecordUpdateArg, UntypedStatement,
17+
UntypedTailPattern, UntypedTypeAlias, UntypedUse, UntypedUseAssignment, Use, UseAssignment,
1818
},
1919
build::Target,
2020
parse::LiteralFloatValue,
@@ -972,12 +972,22 @@ pub trait UntypedConstantFolder {
972972
module,
973973
name,
974974
arguments,
975-
spread,
976975
tag: (),
977976
type_: (),
978977
field_map: _,
979978
record_constructor: _,
980-
} => self.fold_constant_record(location, module, name, arguments, spread),
979+
} => self.fold_constant_record(location, module, name, arguments),
980+
981+
Constant::RecordUpdate {
982+
location,
983+
module,
984+
name,
985+
record,
986+
arguments,
987+
tag: (),
988+
type_: (),
989+
field_map: _,
990+
} => self.fold_constant_record_update(location, module, name, record, arguments),
981991

982992
Constant::BitArray { location, segments } => {
983993
self.fold_constant_bit_array(location, segments)
@@ -1060,21 +1070,39 @@ pub trait UntypedConstantFolder {
10601070
module: Option<(EcoString, SrcSpan)>,
10611071
name: EcoString,
10621072
arguments: Vec<CallArg<UntypedConstant>>,
1063-
spread: Option<Box<UntypedConstant>>,
10641073
) -> UntypedConstant {
10651074
Constant::Record {
10661075
location,
10671076
module,
10681077
name,
10691078
arguments,
1070-
spread,
10711079
tag: (),
10721080
type_: (),
10731081
field_map: None,
10741082
record_constructor: None,
10751083
}
10761084
}
10771085

1086+
fn fold_constant_record_update(
1087+
&mut self,
1088+
location: SrcSpan,
1089+
module: Option<(EcoString, SrcSpan)>,
1090+
name: EcoString,
1091+
record: Box<UntypedConstant>,
1092+
arguments: Vec<ConstantRecordUpdateArg<UntypedConstant>>,
1093+
) -> UntypedConstant {
1094+
Constant::RecordUpdate {
1095+
location,
1096+
module,
1097+
name,
1098+
record,
1099+
arguments,
1100+
tag: (),
1101+
type_: (),
1102+
field_map: None,
1103+
}
1104+
}
1105+
10781106
fn fold_constant_bit_array(
10791107
&mut self,
10801108
location: SrcSpan,
@@ -1149,7 +1177,6 @@ pub trait UntypedConstantFolder {
11491177
module,
11501178
name,
11511179
arguments,
1152-
spread,
11531180
tag,
11541181
type_,
11551182
field_map,
@@ -1162,20 +1189,49 @@ pub trait UntypedConstantFolder {
11621189
argument
11631190
})
11641191
.collect();
1165-
let spread = spread.map(|s| Box::new(self.fold_constant(*s)));
11661192
Constant::Record {
11671193
location,
11681194
module,
11691195
name,
11701196
arguments,
1171-
spread,
11721197
tag,
11731198
type_,
11741199
field_map,
11751200
record_constructor,
11761201
}
11771202
}
11781203

1204+
Constant::RecordUpdate {
1205+
location,
1206+
module,
1207+
name,
1208+
record,
1209+
arguments,
1210+
tag,
1211+
type_,
1212+
field_map,
1213+
} => {
1214+
let record = Box::new(self.fold_constant(*record));
1215+
let arguments = arguments
1216+
.into_iter()
1217+
.map(|arg| ConstantRecordUpdateArg {
1218+
label: arg.label,
1219+
location: arg.location,
1220+
value: self.fold_constant(arg.value),
1221+
})
1222+
.collect();
1223+
Constant::RecordUpdate {
1224+
location,
1225+
module,
1226+
name,
1227+
record,
1228+
arguments,
1229+
tag,
1230+
type_,
1231+
field_map,
1232+
}
1233+
}
1234+
11791235
Constant::BitArray { location, segments } => {
11801236
let segments = segments
11811237
.into_iter()

compiler-core/src/call_graph.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,17 @@ impl<'a> CallGraphBuilder<'a> {
494494
}
495495
}
496496

497+
Constant::RecordUpdate {
498+
record, arguments, ..
499+
} => {
500+
// Visit the record being updated
501+
self.constant(record);
502+
// Visit the update arguments
503+
for argument in arguments {
504+
self.constant(&argument.value);
505+
}
506+
}
507+
497508
Constant::Var {
498509
module: None, name, ..
499510
} => self.referenced(name),

compiler-core/src/erlang.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,13 @@ fn const_inline<'a>(literal: &'a TypedConstant, env: &mut Env<'a>) -> Document<'
15141514
tuple(std::iter::once(tag).chain(arguments_doc))
15151515
}
15161516

1517+
Constant::RecordUpdate { .. } => {
1518+
// RecordUpdate should be expanded to Record during type checking, so this should never happen
1519+
panic!(
1520+
"Encountered RecordUpdate in code generation - this should have been expanded during type checking"
1521+
)
1522+
}
1523+
15171524
Constant::Var {
15181525
name, constructor, ..
15191526
} => var(
@@ -3268,6 +3275,12 @@ fn find_referenced_private_functions(
32683275
.iter()
32693276
.for_each(|argument| find_referenced_private_functions(&argument.value, already_found)),
32703277

3278+
TypedConstant::RecordUpdate { .. } => {
3279+
panic!(
3280+
"Encountered RecordUpdate in code generation - this should have been expanded during type checking"
3281+
)
3282+
}
3283+
32713284
TypedConstant::StringConcatenation { left, right, .. } => {
32723285
find_referenced_private_functions(left, already_found);
32733286
find_referenced_private_functions(right, already_found);

compiler-core/src/format.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,12 @@ impl<'comments> Formatter<'comments> {
543543
.group()
544544
}
545545

546+
Constant::RecordUpdate { .. } => {
547+
panic!(
548+
"Encountered RecordUpdate in code generation - this should have been expanded during type checking"
549+
)
550+
}
551+
546552
Constant::Var {
547553
name, module: None, ..
548554
} => name.to_doc(),

0 commit comments

Comments
 (0)