Skip to content

Commit 0ad674d

Browse files
GearsDatapackslpil
authored andcommitted
Properly infer variants when echo is present
1 parent b496b88 commit 0ad674d

File tree

3 files changed

+47
-20
lines changed

3 files changed

+47
-20
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,3 +339,7 @@
339339
- Fixed a bug where renaming a variable used in a record update would produce
340340
invalid code in certain situations.
341341
([Surya Rose](https://github.com/GearsDatapacks))
342+
343+
- Fixed a bug where adding `echo` to the subject of a `case` expression would
344+
prevent variant inference from working correctly.
345+
([Surya Rose](https://github.com/GearsDatapacks))

compiler-core/src/type_/pattern.rs

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -315,20 +315,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
315315
// Unify each pattern in the multi-pattern with the corresponding subject
316316
let mut typed_multi = Vec::with_capacity(multi_pattern.len());
317317
for (pattern, subject) in multi_pattern.into_iter().zip(subjects) {
318-
let subject_variable = match subject {
319-
TypedExpr::Var {
320-
constructor:
321-
ValueConstructor {
322-
// Records should not be considered local variables
323-
// See: https://github.com/gleam-lang/gleam/issues/3861
324-
variant: ValueConstructorVariant::Record { .. },
325-
..
326-
},
327-
..
328-
} => None,
329-
TypedExpr::Var { name, .. } => Some(name.clone()),
330-
_ => None,
331-
};
318+
let subject_variable = Self::subject_variable(subject);
332319

333320
let pattern = self.unify(pattern, subject.type_(), subject_variable);
334321
typed_multi.push(pattern);
@@ -344,7 +331,15 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
344331
pattern: UntypedPattern,
345332
subject: &TypedExpr,
346333
) -> TypedPattern {
347-
let subject_variable = match subject {
334+
let subject_variable = Self::subject_variable(subject);
335+
336+
let typed_pattern = self.unify(pattern, subject.type_(), subject_variable);
337+
self.register_variables();
338+
typed_pattern
339+
}
340+
341+
fn subject_variable(subject: &TypedExpr) -> Option<EcoString> {
342+
match subject {
348343
TypedExpr::Var {
349344
constructor:
350345
ValueConstructor {
@@ -356,12 +351,15 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
356351
..
357352
} => None,
358353
TypedExpr::Var { name, .. } => Some(name.clone()),
354+
// If the subject of a `case` expression is something like
355+
// `echo some_variable`, we still want to narrow the variant for
356+
// `some_variable`.
357+
TypedExpr::Echo {
358+
expression: Some(subject),
359+
..
360+
} => Self::subject_variable(subject),
359361
_ => None,
360-
};
361-
362-
let typed_pattern = self.unify(pattern, subject.type_(), subject_variable);
363-
self.register_variables();
364-
typed_pattern
362+
}
365363
}
366364

367365
/// Register the variables bound in this pattern in the environment

compiler-core/src/type_/tests.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3228,3 +3228,28 @@ pub fn main() {
32283228
vec![("main", "fn() -> Nil")]
32293229
);
32303230
}
3231+
3232+
// https://github.com/gleam-lang/gleam/issues/4883
3233+
#[test]
3234+
fn variant_inference_ignores_echo() {
3235+
assert_module_infer!(
3236+
"
3237+
pub type Wibble {
3238+
Wibble(wibble: Int, wobble: String)
3239+
Wobble(a: String, b: Int)
3240+
}
3241+
3242+
pub fn get_int(w: Wibble) {
3243+
case echo w {
3244+
Wibble(..) -> w.wibble
3245+
Wobble(..) -> w.b
3246+
}
3247+
}
3248+
",
3249+
vec![
3250+
("Wibble", "fn(Int, String) -> Wibble"),
3251+
("Wobble", "fn(String, Int) -> Wibble"),
3252+
("get_int", "fn(Wibble) -> Int"),
3253+
]
3254+
);
3255+
}

0 commit comments

Comments
 (0)