Skip to content

Commit 7ef91ef

Browse files
GearsDatapackslpil
authored andcommitted
Fix bug when inlining record updates
1 parent 157111d commit 7ef91ef

File tree

5 files changed

+143
-17
lines changed

5 files changed

+143
-17
lines changed

compiler-core/src/erlang/tests/inlining.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,24 @@ fn divide(a, b) {
312312
"
313313
);
314314
}
315+
316+
// https://github.com/gleam-lang/gleam/issues/4852
317+
#[test]
318+
fn inlining_works_properly_with_record_updates() {
319+
assert_erl!(
320+
("gleam_stdlib", "gleam/result", RESULT_MODULE),
321+
"
322+
import gleam/result
323+
324+
pub type Wibble {
325+
Wibble(a: Int, b: Int)
326+
}
327+
328+
pub fn main() {
329+
let w = Wibble(1, 2)
330+
use b <- result.map(Ok(3))
331+
Wibble(..w, b:)
332+
}
333+
"
334+
);
335+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
source: compiler-core/src/erlang/tests/inlining.rs
3+
expression: "\nimport gleam/result\n\npub type Wibble {\n Wibble(a: Int, b: Int)\n}\n\npub fn main() {\n let w = Wibble(1, 2)\n use b <- result.map(Ok(3))\n Wibble(..w, b:)\n}\n"
4+
---
5+
----- SOURCE CODE
6+
7+
import gleam/result
8+
9+
pub type Wibble {
10+
Wibble(a: Int, b: Int)
11+
}
12+
13+
pub fn main() {
14+
let w = Wibble(1, 2)
15+
use b <- result.map(Ok(3))
16+
Wibble(..w, b:)
17+
}
18+
19+
20+
----- COMPILED ERLANG
21+
-module(my@mod).
22+
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
23+
-define(FILEPATH, "project/test/my/mod.gleam").
24+
-export([main/0]).
25+
-export_type([wibble/0]).
26+
27+
-type wibble() :: {wibble, integer(), integer()}.
28+
29+
-file("project/test/my/mod.gleam", 8).
30+
-spec main() -> {ok, wibble()} | {error, any()}.
31+
main() ->
32+
W = {wibble, 1, 2},
33+
case {ok, 3} of
34+
{ok, Value} ->
35+
{ok, {wibble, erlang:element(2, W), Value}};
36+
37+
{error, Error} ->
38+
{error, Error}
39+
end.

compiler-core/src/inline.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -479,11 +479,30 @@ impl Inliner<'_> {
479479
record_assignment: record_assignment
480480
.map(|assignment| Box::new(self.assignment(*assignment))),
481481
constructor: self.boxed_expression(constructor),
482-
arguments,
482+
arguments: self.arguments(arguments),
483483
},
484484
}
485485
}
486486

487+
fn arguments(&mut self, arguments: Vec<TypedCallArg>) -> Vec<TypedCallArg> {
488+
arguments
489+
.into_iter()
490+
.map(
491+
|TypedCallArg {
492+
label,
493+
location,
494+
value,
495+
implicit,
496+
}| TypedCallArg {
497+
label,
498+
location,
499+
value: self.expression(value),
500+
implicit,
501+
},
502+
)
503+
.collect()
504+
}
505+
487506
/// Where the magic happens. First, we check the left-hand side of the call
488507
/// to see if it's something we can inline. If not, we continue to walk the
489508
/// tree like all the other expressions do. If it can be inlined, we follow
@@ -561,22 +580,7 @@ impl Inliner<'_> {
561580
function: Box<TypedExpr>,
562581
arguments: Vec<TypedCallArg>,
563582
) -> TypedExpr {
564-
let arguments = arguments
565-
.into_iter()
566-
.map(
567-
|TypedCallArg {
568-
label,
569-
location,
570-
value,
571-
implicit,
572-
}| TypedCallArg {
573-
label,
574-
location,
575-
value: self.expression(value),
576-
implicit,
577-
},
578-
)
579-
.collect();
583+
let arguments = self.arguments(arguments);
580584

581585
// First, we traverse the left-hand side of this call. If this is called
582586
// inside another inlined function, this could potentially inline an

compiler-core/src/javascript/tests/inlining.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,24 @@ fn divide(a, b) {
312312
"
313313
);
314314
}
315+
316+
// https://github.com/gleam-lang/gleam/issues/4852
317+
#[test]
318+
fn inlining_works_properly_with_record_updates() {
319+
assert_js!(
320+
("gleam_stdlib", "gleam/result", RESULT_MODULE),
321+
"
322+
import gleam/result
323+
324+
pub type Wibble {
325+
Wibble(a: Int, b: Int)
326+
}
327+
328+
pub fn main() {
329+
let w = Wibble(1, 2)
330+
use b <- result.map(Ok(3))
331+
Wibble(..w, b:)
332+
}
333+
"
334+
);
335+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
source: compiler-core/src/javascript/tests/inlining.rs
3+
expression: "\nimport gleam/result\n\npub type Wibble {\n Wibble(a: Int, b: Int)\n}\n\npub fn main() {\n let w = Wibble(1, 2)\n use b <- result.map(Ok(3))\n Wibble(..w, b:)\n}\n"
4+
---
5+
----- SOURCE CODE
6+
7+
import gleam/result
8+
9+
pub type Wibble {
10+
Wibble(a: Int, b: Int)
11+
}
12+
13+
pub fn main() {
14+
let w = Wibble(1, 2)
15+
use b <- result.map(Ok(3))
16+
Wibble(..w, b:)
17+
}
18+
19+
20+
----- COMPILED JAVASCRIPT
21+
import * as $result from "../../gleam_stdlib/gleam/result.mjs";
22+
import { Ok, CustomType as $CustomType } from "../gleam.mjs";
23+
24+
export class Wibble extends $CustomType {
25+
constructor(a, b) {
26+
super();
27+
this.a = a;
28+
this.b = b;
29+
}
30+
}
31+
32+
export function main() {
33+
let w = new Wibble(1, 2);
34+
let $ = new Ok(3);
35+
if ($ instanceof Ok) {
36+
let value = $[0];
37+
return new Ok(new Wibble(w.a, value));
38+
} else {
39+
return $;
40+
}
41+
}

0 commit comments

Comments
 (0)