+15
-5
compiler-core/src/ast/typed.rs
+15
-5
compiler-core/src/ast/typed.rs
···
164
164
RecordUpdate {
165
165
location: SrcSpan,
166
166
type_: Arc<Type>,
167
-
record: Box<TypedAssignment>,
167
+
/// If the record is an expression that is not a variable we will need to assign to a
168
+
/// variable so it can be referred multiple times.
169
+
record_assignment: Option<Box<TypedAssignment>>,
168
170
constructor: Box<Self>,
169
171
args: Vec<CallArg<Self>>,
170
172
},
···
371
373
.or_else(|| self.self_if_contains_location(byte_index)),
372
374
373
375
Self::RecordUpdate {
374
-
record,
376
+
record_assignment: record,
375
377
constructor,
376
378
args,
377
379
..
···
379
381
.iter()
380
382
.filter(|arg| arg.implicit.is_none())
381
383
.find_map(|arg| arg.find_node(byte_index, constructor, args))
382
-
.or_else(|| record.find_node(byte_index))
384
+
.or_else(|| record.as_ref().and_then(|r| r.find_node(byte_index)))
383
385
.or_else(|| self.self_if_contains_location(byte_index)),
384
386
}
385
387
}
···
509
511
.iter()
510
512
.find_map(|arg| arg.value.find_statement(byte_index)),
511
513
512
-
Self::RecordUpdate { record, args, .. } => args
514
+
Self::RecordUpdate {
515
+
record_assignment: record,
516
+
args,
517
+
..
518
+
} => args
513
519
.iter()
514
520
.filter(|arg| arg.implicit.is_none())
515
521
.find_map(|arg| arg.find_statement(byte_index))
516
-
.or_else(|| record.value.find_statement(byte_index)),
522
+
.or_else(|| {
523
+
record
524
+
.as_ref()
525
+
.and_then(|r| r.value.find_statement(byte_index))
526
+
}),
517
527
}
518
528
}
519
529
+6
-4
compiler-core/src/ast/visit.rs
+6
-4
compiler-core/src/ast/visit.rs
···
299
299
&mut self,
300
300
location: &'ast SrcSpan,
301
301
type_: &'ast Arc<Type>,
302
-
record: &'ast TypedAssignment,
302
+
record: &'ast Option<Box<TypedAssignment>>,
303
303
constructor: &'ast TypedExpr,
304
304
args: &'ast [TypedCallArg],
305
305
) {
···
843
843
TypedExpr::RecordUpdate {
844
844
location,
845
845
type_,
846
-
record,
846
+
record_assignment: record,
847
847
constructor,
848
848
args,
849
849
} => v.visit_typed_expr_record_update(location, type_, record, constructor, args),
···
1133
1133
v: &mut V,
1134
1134
_location: &'a SrcSpan,
1135
1135
_type: &'a Arc<Type>,
1136
-
record: &'a TypedAssignment,
1136
+
record: &'a Option<Box<TypedAssignment>>,
1137
1137
constructor: &'a TypedExpr,
1138
1138
args: &'a [TypedCallArg],
1139
1139
) where
1140
1140
V: Visit<'a> + ?Sized,
1141
1141
{
1142
1142
v.visit_typed_expr(constructor);
1143
-
v.visit_typed_assignment(record);
1143
+
if let Some(record) = record {
1144
+
v.visit_typed_assignment(record);
1145
+
}
1144
1146
for arg in args {
1145
1147
v.visit_typed_call_arg(arg);
1146
1148
}
+11
-8
compiler-core/src/erlang.rs
+11
-8
compiler-core/src/erlang.rs
···
1948
1948
}
1949
1949
1950
1950
fn record_update<'a>(
1951
-
record: &'a TypedAssignment,
1951
+
record: &'a Option<Box<TypedAssignment>>,
1952
1952
constructor: &'a TypedExpr,
1953
1953
args: &'a [TypedCallArg],
1954
1954
env: &mut Env<'a>,
1955
1955
) -> Document<'a> {
1956
1956
let vars = env.current_scope_vars.clone();
1957
1957
1958
-
let document = docvec![
1959
-
assignment(record, env, Position::NotTail),
1960
-
",",
1961
-
line(),
1962
-
call(constructor, args, env)
1963
-
];
1958
+
let document = match record.as_ref() {
1959
+
Some(record) => docvec![
1960
+
assignment(record, env, Position::NotTail),
1961
+
",",
1962
+
line(),
1963
+
call(constructor, args, env)
1964
+
],
1965
+
None => call(constructor, args, env),
1966
+
};
1964
1967
1965
1968
env.current_scope_vars = vars;
1966
1969
···
2155
2158
TypedExpr::RecordAccess { record, index, .. } => tuple_index(record, index + 1, env),
2156
2159
2157
2160
TypedExpr::RecordUpdate {
2158
-
record,
2161
+
record_assignment: record,
2159
2162
constructor,
2160
2163
args,
2161
2164
..
+1
-2
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__record_update_printed_by_echo_is_wrapped_in_begin_end_block.snap
+1
-2
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__record_update_printed_by_echo_is_wrapped_in_begin_end_block.snap
+1
-2
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_record_update.snap
+1
-2
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_record_update.snap
+4
-5
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update.snap
+4
-5
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update.snap
···
33
33
-spec main() -> wibble().
34
34
main() ->
35
35
Base = {wibble, 1, {wobble, 2, 3}, 4},
36
-
_record = Base,
37
36
{wibble,
38
-
erlang:element(2, _record),
37
+
erlang:element(2, Base),
39
38
begin
40
-
_record@1 = erlang:element(3, Base),
41
-
{wobble, erlang:element(2, _record@1), 5}
39
+
_record = erlang:element(3, Base),
40
+
{wobble, erlang:element(2, _record), 5}
42
41
end,
43
-
erlang:element(4, _record)}.
42
+
erlang:element(4, Base)}.
+2
-3
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update_with_blocks.snap
+2
-3
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update_with_blocks.snap
···
33
33
-file("project/test/my/mod.gleam", 5).
34
34
-spec main(a()) -> a().
35
35
main(A) ->
36
-
_record = A,
37
36
{a,
38
37
begin
39
-
_record@1 = erlang:element(2, A),
38
+
_record = erlang:element(2, A),
40
39
{b,
41
40
begin
42
-
_record@2 = erlang:element(2, erlang:element(2, A)),
41
+
_record@1 = erlang:element(2, erlang:element(2, A)),
43
42
{c, 0}
44
43
end}
45
44
end}.
+1
-2
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates.snap
+1
-2
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates.snap
+1
-2
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates1.snap
+1
-2
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates1.snap
-1
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates2.snap
-1
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates2.snap
+10
-7
compiler-core/src/javascript/expression.rs
+10
-7
compiler-core/src/javascript/expression.rs
···
312
312
313
313
TypedExpr::RecordAccess { record, label, .. } => self.record_access(record, label),
314
314
TypedExpr::RecordUpdate {
315
-
record,
315
+
record_assignment: record,
316
316
constructor,
317
317
args,
318
318
..
···
1443
1443
1444
1444
fn record_update(
1445
1445
&mut self,
1446
-
record: &'a TypedAssignment,
1446
+
record: &'a Option<Box<TypedAssignment>>,
1447
1447
constructor: &'a TypedExpr,
1448
1448
args: &'a [TypedCallArg],
1449
1449
) -> Output<'a> {
1450
-
Ok(docvec![
1451
-
self.not_in_tail_position(None, |this| this.assignment(record))?,
1452
-
line(),
1453
-
self.call(constructor, args)?,
1454
-
])
1450
+
match record.as_ref() {
1451
+
Some(record) => Ok(docvec![
1452
+
self.not_in_tail_position(None, |this| this.assignment(record))?,
1453
+
line(),
1454
+
self.call(constructor, args)?,
1455
+
]),
1456
+
None => self.call(constructor, args),
1457
+
}
1455
1458
}
1456
1459
1457
1460
fn tuple_index(&mut self, tuple: &'a TypedExpr, index: u64) -> Output<'a> {
+2
-4
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__record_update_in_pipeline_in_case_clause.snap
+2
-4
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__record_update_in_pipeline_in_case_clause.snap
···
44
44
let $ = x.wibble;
45
45
if ($ === 1) {
46
46
let _block;
47
-
let _record = x;
48
-
_block = new Wibble(4, _record.wobble);
47
+
_block = new Wibble(4, x.wobble);
49
48
let _pipe = _block;
50
49
return identity(_pipe);
51
50
} else {
52
51
let $1 = x.wobble;
53
52
if ($1 === 3) {
54
53
let _block;
55
-
let _record = x;
56
-
_block = new Wibble(_record.wibble, 10);
54
+
_block = new Wibble(x.wibble, 10);
57
55
let _pipe = _block;
58
56
return identity(_pipe);
59
57
} else {
+6
-11
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__custom_type_with_named_fields.snap
+6
-11
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__custom_type_with_named_fields.snap
···
73
73
}
74
74
75
75
export function update(cat) {
76
-
let _record = cat;
77
-
new Cat("Sid", _record.cuteness)
78
-
let _record$1 = cat;
79
-
new Cat(
80
-
"Bartholemew Wonder Puss the Fourth !!!!!!!!!!!!!!!!",
81
-
_record$1.cuteness,
82
-
)
83
-
let _record$2 = new_cat();
84
-
new Cat("Molly", _record$2.cuteness)
76
+
new Cat("Sid", cat.cuteness)
77
+
new Cat("Bartholemew Wonder Puss the Fourth !!!!!!!!!!!!!!!!", cat.cuteness)
78
+
let _record = new_cat();
79
+
new Cat("Molly", _record.cuteness)
85
80
let box = new Box(cat);
86
-
let _record$3 = box.occupant;
87
-
return new Cat(_record$3.name, box.occupant.cuteness + 1);
81
+
let _record$1 = box.occupant;
82
+
return new Cat(_record$1.name, box.occupant.cuteness + 1);
88
83
}
89
84
90
85
export const felix = /* @__PURE__ */ new Cat("Felix", 12);
+2
-1
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__record_with_field_named_constructor.snap
+2
-1
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__record_with_field_named_constructor.snap
···
1
1
---
2
2
source: compiler-core/src/javascript/tests/custom_types.rs
3
+
assertion_line: 605
3
4
expression: "\npub type Thing {\n Thing(constructor: Nil)\n}\n\npub fn main() {\n let a = Thing(constructor: Nil)\n let b = Thing(..a, constructor: Nil)\n b.constructor\n}\n"
5
+
snapshot_kind: text
4
6
---
5
7
----- SOURCE CODE
6
8
···
28
30
export function main() {
29
31
let a = new Thing(undefined);
30
32
let _block;
31
-
let _record = a;
32
33
_block = new Thing(undefined);
33
34
let b = _block;
34
35
return b.constructor$;
+2
-1
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__record_with_field_named_then.snap
+2
-1
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__custom_types__record_with_field_named_then.snap
···
1
1
---
2
2
source: compiler-core/src/javascript/tests/custom_types.rs
3
+
assertion_line: 622
3
4
expression: "\npub type Thing {\n Thing(then: Nil)\n}\n\npub fn main() {\n let a = Thing(then: Nil)\n let b = Thing(..a, then: Nil)\n b.then\n}\n"
5
+
snapshot_kind: text
4
6
---
5
7
----- SOURCE CODE
6
8
···
28
30
export function main() {
29
31
let a = new Thing(undefined);
30
32
let _block;
31
-
let _record = a;
32
33
_block = new Thing(undefined);
33
34
let b = _block;
34
35
return b.then$;
+30
-25
compiler-core/src/type_/expression.rs
+30
-25
compiler-core/src/type_/expression.rs
···
3037
3037
let record_location = record.location();
3038
3038
let record_type = record.type_();
3039
3039
3040
-
// We create an Assignment for the old record expression and will use a Var expression
3041
-
// to refer back to it while constructing the arguments.
3042
-
let record_assignment = Assignment {
3043
-
location: record_location,
3044
-
pattern: Pattern::Variable {
3040
+
let (record_var, record_assignment) = if record.is_var() {
3041
+
(record, None)
3042
+
} else {
3043
+
// We create an Assignment for the old record expression and will use a Var expression
3044
+
// to refer back to it while constructing the arguments.
3045
+
let record_assignment = Assignment {
3045
3046
location: record_location,
3046
-
name: RECORD_UPDATE_VARIABLE.into(),
3047
-
type_: record_type.clone(),
3048
-
origin: VariableOrigin::generated(),
3049
-
},
3050
-
annotation: None,
3051
-
compiled_case: CompiledCase::failure(),
3052
-
kind: AssignmentKind::Generated,
3053
-
value: record,
3054
-
};
3055
-
3056
-
let record_var = TypedExpr::Var {
3057
-
location: record_location,
3058
-
constructor: ValueConstructor {
3059
-
publicity: Publicity::Private,
3060
-
deprecation: Deprecation::NotDeprecated,
3061
-
type_: record_type,
3062
-
variant: ValueConstructorVariant::LocalVariable {
3047
+
pattern: Pattern::Variable {
3063
3048
location: record_location,
3049
+
name: RECORD_UPDATE_VARIABLE.into(),
3050
+
type_: record_type.clone(),
3064
3051
origin: VariableOrigin::generated(),
3065
3052
},
3066
-
},
3067
-
name: RECORD_UPDATE_VARIABLE.into(),
3053
+
annotation: None,
3054
+
compiled_case: CompiledCase::failure(),
3055
+
kind: AssignmentKind::Generated,
3056
+
value: record,
3057
+
};
3058
+
3059
+
let record_var = TypedExpr::Var {
3060
+
location: record_location,
3061
+
constructor: ValueConstructor {
3062
+
publicity: Publicity::Private,
3063
+
deprecation: Deprecation::NotDeprecated,
3064
+
type_: record_type,
3065
+
variant: ValueConstructorVariant::LocalVariable {
3066
+
location: record_location,
3067
+
origin: VariableOrigin::generated(),
3068
+
},
3069
+
},
3070
+
name: RECORD_UPDATE_VARIABLE.into(),
3071
+
};
3072
+
(record_var, Some(Box::new(record_assignment)))
3068
3073
};
3069
3074
3070
3075
// infer the fields of the variant we want to update
···
3076
3081
Ok(TypedExpr::RecordUpdate {
3077
3082
location,
3078
3083
type_: variant.retn,
3079
-
record: Box::new(record_assignment),
3084
+
record_assignment,
3080
3085
constructor: Box::new(typed_constructor),
3081
3086
args,
3082
3087
})