Skip to content

Commit aff0e2f

Browse files
GearsDatapackslpil
authored andcommitted
Revert Erlang pattern matching change
1 parent ae782cf commit aff0e2f

19 files changed

+44
-739
lines changed

compiler-core/src/erlang.rs

Lines changed: 13 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,49 +1232,22 @@ fn let_assert<'a>(
12321232
};
12331233

12341234
let mut guards = vec![];
1235-
let mut assignments = vec![];
1236-
let pattern_document = pattern::to_doc(pattern, &mut vars, env, &mut guards, &mut assignments);
1235+
let pattern_document = pattern::to_doc(pattern, &mut vars, env, &mut guards);
12371236
let clause_guard = optional_clause_guard(None, guards, env);
12381237

12391238
let message = match message {
12401239
Some(message) => expr(message, env),
12411240
None => string("Pattern match failed, no pattern matched the value."),
12421241
};
12431242

1244-
let mut variable_value = |name| {
1245-
for assignment in assignments.iter() {
1246-
// If we are compiling a pattern match such as the following:
1247-
// ```gleam
1248-
// let assert <<"Hello" as m:utf16>> = x
1249-
// ```
1250-
//
1251-
// We could do the same thing as we do in `case` expressions:
1252-
// ```erlang
1253-
// M@2 = case X of
1254-
// <<M:10/binary>> when M =:= <<"Hello"/utf16>> ->
1255-
// M@1 = <<"Hello"/utf8>>,
1256-
// M@1;
1257-
// _ -> erlang:error(...)
1258-
// end
1259-
// ```
1260-
//
1261-
// However, since we are always immediately returning the value
1262-
// assigned to this temporary variable, it is simpler to just return
1263-
// the value itself, rather then assigning then returning.
1264-
//
1265-
if assignment.variable == name {
1266-
return assignment.value.clone();
1267-
}
1268-
}
1269-
env.local_var_name(name)
1270-
};
1271-
12721243
let value = match vars.as_slice() {
12731244
_ if is_tail => subject.clone(),
12741245
[] => "nil".to_doc(),
1275-
[variable] => variable_value(variable),
1246+
[variable] => env.local_var_name(variable),
12761247
variables => {
1277-
let variables = variables.iter().map(|name| variable_value(name));
1248+
let variables = variables
1249+
.iter()
1250+
.map(|variable| env.local_var_name(variable));
12781251
docvec![
12791252
break_("{", "{"),
12801253
join(variables, break_(",", ", ")).nest(INDENT),
@@ -1338,10 +1311,7 @@ fn let_assert<'a>(
13381311
fn let_<'a>(value: &'a TypedExpr, pat: &'a TypedPattern, env: &mut Env<'a>) -> Document<'a> {
13391312
let body = maybe_block_expr(value, env).group();
13401313
let mut guards = vec![];
1341-
let mut assignments = vec![];
1342-
pattern(pat, env, &mut guards, &mut assignments)
1343-
.append(" = ")
1344-
.append(body)
1314+
pattern(pat, env, &mut guards).append(" = ").append(body)
13451315
}
13461316

13471317
fn float<'a>(value: &str) -> Document<'a> {
@@ -1548,46 +1518,30 @@ fn clause<'a>(clause: &'a TypedClause, env: &mut Env<'a>) -> Document<'a> {
15481518
.chain(alternative_patterns)
15491519
.map(|patterns| {
15501520
let mut additional_guards = vec![];
1551-
let mut assignments = vec![];
15521521
env.erl_function_scope_vars = initial_erlang_vars.clone();
15531522

15541523
let patterns_doc = if patterns.len() == 1 {
15551524
let p = patterns.first().expect("Single pattern clause printing");
1556-
pattern(p, env, &mut additional_guards, &mut assignments)
1525+
pattern(p, env, &mut additional_guards)
15571526
} else {
15581527
tuple(
15591528
patterns
15601529
.iter()
1561-
.map(|p| pattern(p, env, &mut additional_guards, &mut assignments)),
1530+
.map(|p| pattern(p, env, &mut additional_guards)),
15621531
)
15631532
};
15641533

15651534
let guard = optional_clause_guard(guard.as_ref(), additional_guards, env);
1566-
1567-
let assignments = assignments
1568-
.into_iter()
1569-
.map(|assignment| {
1570-
docvec![
1571-
line(),
1572-
env.next_local_var_name(assignment.variable),
1573-
" = ",
1574-
assignment.value,
1575-
","
1576-
]
1577-
.nest(INDENT)
1578-
})
1579-
.collect_vec();
1580-
15811535
if then_doc.is_none() {
15821536
then_doc = Some(clause_consequence(then, env));
15831537
end_erlang_vars = env.erl_function_scope_vars.clone();
15841538
}
15851539

1586-
patterns_doc
1587-
.append(guard)
1588-
.append(" ->")
1589-
.append(assignments)
1590-
.append(line().append(then_doc.clone()).nest(INDENT).group())
1540+
patterns_doc.append(
1541+
guard
1542+
.append(" ->")
1543+
.append(line().append(then_doc.clone()).nest(INDENT).group()),
1544+
)
15911545
}),
15921546
";".to_doc().append(lines(2)),
15931547
);

compiler-core/src/erlang/pattern.rs

Lines changed: 30 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,33 @@ use crate::analyse::Inferred;
66

77
use super::*;
88

9-
pub(super) struct PatternAssignment<'a> {
10-
pub variable: &'a EcoString,
11-
pub value: Document<'a>,
12-
}
13-
149
pub(super) fn pattern<'a>(
1510
p: &'a TypedPattern,
1611
env: &mut Env<'a>,
1712
guards: &mut Vec<Document<'a>>,
18-
assignments: &mut Vec<PatternAssignment<'a>>,
1913
) -> Document<'a> {
2014
let mut vars = vec![];
21-
to_doc(p, &mut vars, env, guards, assignments)
15+
to_doc(p, &mut vars, env, guards)
2216
}
2317

2418
fn print<'a>(
2519
p: &'a TypedPattern,
2620
vars: &mut Vec<&'a str>,
2721
env: &mut Env<'a>,
2822
guards: &mut Vec<Document<'a>>,
29-
assignments: &mut Vec<PatternAssignment<'a>>,
3023
) -> Document<'a> {
3124
match p {
3225
Pattern::Assign {
3326
name, pattern: p, ..
3427
} => {
3528
vars.push(name);
36-
print(p, vars, env, guards, assignments)
29+
print(p, vars, env, guards)
3730
.append(" = ")
3831
.append(env.next_local_var_name(name))
3932
}
4033

4134
Pattern::List { elements, tail, .. } => {
42-
pattern_list(elements, tail.as_deref(), vars, env, guards, assignments)
35+
pattern_list(elements, tail.as_deref(), vars, env, guards)
4336
}
4437

4538
Pattern::Discard { .. } => "_".to_doc(),
@@ -74,7 +67,7 @@ fn print<'a>(
7467
arguments: args,
7568
constructor: Inferred::Known(PatternConstructor { name, .. }),
7669
..
77-
} => tag_tuple_pattern(name, args, vars, env, guards, assignments),
70+
} => tag_tuple_pattern(name, args, vars, env, guards),
7871

7972
Pattern::Constructor {
8073
constructor: Inferred::Unknown,
@@ -83,16 +76,14 @@ fn print<'a>(
8376
panic!("Erlang generation performed with uninferred pattern constructor")
8477
}
8578

86-
Pattern::Tuple { elements, .. } => tuple(
87-
elements
88-
.iter()
89-
.map(|p| print(p, vars, env, guards, assignments)),
90-
),
79+
Pattern::Tuple { elements, .. } => {
80+
tuple(elements.iter().map(|p| print(p, vars, env, guards)))
81+
}
9182

9283
Pattern::BitArray { segments, .. } => bit_array(
9384
segments
9485
.iter()
95-
.map(|s| pattern_segment(s, vars, env, guards, assignments)),
86+
.map(|s| pattern_segment(&s.value, &s.options, vars, env, guards)),
9687
),
9788

9889
Pattern::StringPrefix {
@@ -156,9 +147,8 @@ pub(super) fn to_doc<'a>(
156147
vars: &mut Vec<&'a str>,
157148
env: &mut Env<'a>,
158149
guards: &mut Vec<Document<'a>>,
159-
assignments: &mut Vec<PatternAssignment<'a>>,
160150
) -> Document<'a> {
161-
print(p, vars, env, guards, assignments)
151+
print(p, vars, env, guards)
162152
}
163153

164154
fn tag_tuple_pattern<'a>(
@@ -167,62 +157,39 @@ fn tag_tuple_pattern<'a>(
167157
vars: &mut Vec<&'a str>,
168158
env: &mut Env<'a>,
169159
guards: &mut Vec<Document<'a>>,
170-
assignments: &mut Vec<PatternAssignment<'a>>,
171160
) -> Document<'a> {
172161
if args.is_empty() {
173162
atom_string(to_snake_case(name))
174163
} else {
175164
tuple(
176-
[atom_string(to_snake_case(name))].into_iter().chain(
177-
args.iter()
178-
.map(|p| print(&p.value, vars, env, guards, assignments)),
179-
),
165+
[atom_string(to_snake_case(name))]
166+
.into_iter()
167+
.chain(args.iter().map(|p| print(&p.value, vars, env, guards))),
180168
)
181169
}
182170
}
183171

184172
fn pattern_segment<'a>(
185-
segment: &'a TypedPatternBitArraySegment,
173+
value: &'a TypedPattern,
174+
options: &'a [BitArrayOption<TypedPattern>],
186175
vars: &mut Vec<&'a str>,
187176
env: &mut Env<'a>,
188177
guards: &mut Vec<Document<'a>>,
189-
assignments: &mut Vec<PatternAssignment<'a>>,
190178
) -> Document<'a> {
191-
let value = segment.value.as_ref();
192-
193-
let pattern_is_a_string_literal = match value {
194-
Pattern::String { .. } => true,
195-
Pattern::Assign { pattern, .. } => pattern.is_string(),
196-
Pattern::Int { .. }
197-
| Pattern::Float { .. }
198-
| Pattern::Variable { .. }
199-
| Pattern::VarUsage { .. }
200-
| Pattern::Discard { .. }
201-
| Pattern::List { .. }
202-
| Pattern::Constructor { .. }
203-
| Pattern::Tuple { .. }
204-
| Pattern::BitArray { .. }
205-
| Pattern::StringPrefix { .. }
206-
| Pattern::Invalid { .. } => false,
207-
};
179+
let pattern_is_a_string_literal = matches!(value, Pattern::String { .. });
208180
let pattern_is_a_discard = matches!(value, Pattern::Discard { .. });
209181

210182
let vars = RefCell::new(vars);
211183
let guards = RefCell::new(guards);
212-
let assignments = RefCell::new(assignments);
213184

214185
let create_document = |env: &mut Env<'a>| match value {
215186
Pattern::String { value, .. } => value.to_doc().surround("\"", "\""),
216187
Pattern::Discard { .. }
217188
| Pattern::Variable { .. }
218189
| Pattern::Int { .. }
219-
| Pattern::Float { .. } => print(
220-
value,
221-
&mut vars.borrow_mut(),
222-
env,
223-
&mut guards.borrow_mut(),
224-
&mut assignments.borrow_mut(),
225-
),
190+
| Pattern::Float { .. } => {
191+
print(value, &mut vars.borrow_mut(), env, &mut guards.borrow_mut())
192+
}
226193

227194
Pattern::Assign { name, pattern, .. } => {
228195
vars.borrow_mut().push(name);
@@ -244,24 +211,16 @@ fn pattern_segment<'a>(
244211
variable_name
245212
}
246213

247-
// If we are assigning to a string which is UTF-16 or UTF-32, we cannot simply use
248-
// variable patterns and guards like we do with other segments. Gleam strings are
249-
// UTF-8 so we must anyway bind the correct value to the variable. We generate code
250-
// that looks like this:
251-
//
252-
// ```erlang
253-
// case X of
254-
// <<"Hello"/utf16>> ->
255-
// Message = <<"Hello"/utf8>>,
256-
// <clause body>
257-
// end.
258-
// ```
214+
// Here we do the same as for floats and ints, but we must calculate the size of
215+
// the string first, so we can correctly match the bit array segment then compare
216+
// it afterwards.
259217
Pattern::String { value, .. } => {
260-
assignments.borrow_mut().push(PatternAssignment {
261-
variable: name,
262-
value: string(value),
263-
});
264-
value.to_doc().surround("\"", "\"")
218+
guards.borrow_mut().push(docvec![
219+
variable_name.clone(),
220+
" =:= ",
221+
string(value)
222+
]);
223+
docvec![variable_name, ":", string_length_utf8_bytes(value)]
265224
}
266225

267226
// Doing a pattern such as `<<_ as a>>` is the same as just `<<a>>`, so we treat it
@@ -283,15 +242,14 @@ fn pattern_segment<'a>(
283242
&mut vars.borrow_mut(),
284243
env,
285244
&mut guards.borrow_mut(),
286-
&mut assignments.borrow_mut(),
287245
)))
288246
};
289247

290248
let unit = |value: &'a u8| Some(eco_format!("unit:{value}").to_doc());
291249

292250
bit_array_segment(
293251
create_document,
294-
&segment.options,
252+
options,
295253
size,
296254
unit,
297255
pattern_is_a_string_literal,
@@ -306,14 +264,13 @@ fn pattern_list<'a>(
306264
vars: &mut Vec<&'a str>,
307265
env: &mut Env<'a>,
308266
guards: &mut Vec<Document<'a>>,
309-
assignments: &mut Vec<PatternAssignment<'a>>,
310267
) -> Document<'a> {
311268
let elements = join(
312269
elements
313270
.iter()
314-
.map(|element| print(element, vars, env, guards, assignments)),
271+
.map(|element| print(element, vars, env, guards)),
315272
break_(",", ", "),
316273
);
317-
let tail = tail.map(|tail| print(tail, vars, env, guards, assignments));
274+
let tail = tail.map(|tail| print(tail, vars, env, guards));
318275
list(elements, tail)
319276
}

0 commit comments

Comments
 (0)