Skip to content

Commit

Permalink
Fix "match" not incrementing certain bindings
Browse files Browse the repository at this point in the history
When matching against patterns such as `Foo(Bar(var))`, if the
outer-most variable was a reference, the pattern matching compiler
would generate match variables with an incorrect type. This would then
result in the MIR code moving a value into `var` _without_ an increment,
instead of performing an increment and moving the reference into the
variable. This would then manifest itself as a reference counting error
when dropping an owned value matched against.

This fixes #580.

Changelog: fixed
  • Loading branch information
yorickpeterse committed Jun 20, 2023
1 parent 31a8a17 commit 20fa7f6
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
9 changes: 8 additions & 1 deletion compiler/src/mir/pattern_matching.rs
Expand Up @@ -798,7 +798,14 @@ impl<'a> Compiler<'a> {
types: Vec<TypeRef>,
) -> Vec<Variable> {
if !instance.instance_of().is_generic(self.db()) {
return types.into_iter().map(|t| self.new_variable(t)).collect();
return types
.into_iter()
.map(|t| {
self.new_variable(
t.cast_according_to(source_variable_type, self.db()),
)
})
.collect();
}

let args = TypeArguments::for_class(self.db_mut(), instance);
Expand Down
16 changes: 16 additions & 0 deletions std/test/compiler/test_pattern_matching.inko
Expand Up @@ -12,6 +12,13 @@ class enum State {
case Button(State)
}

class Dummy {}

class enum Transition {
case Empty(Dummy)
case Split(Transition)
}

fn pub tests(t: mut Tests) {
# https://github.com/inko-lang/inko/issues/363
t.test('match with OR patterns and a guard') fn (t) {
Expand Down Expand Up @@ -50,4 +57,13 @@ fn pub tests(t: mut Tests) {
case _ -> false
}
}

t.no_panic("match doesn't drop deeply nested bindings prematurely") fn {
let trans = Transition.Split(Transition.Empty(Dummy {}))

match ref trans {
case Split(Empty(state1)) -> {}
case _ -> {}
}
}
}

0 comments on commit 20fa7f6

Please sign in to comment.