Skip to content

Commit

Permalink
Or patterns
Browse files Browse the repository at this point in the history
This commit introduce or-patterns, which allows to express alternatives
within pattern matching, including in a deep subpattern.

The compilation of or-patterns is rather simple: we simply try each
alternative until one matches, and use the corresponding bindings.

Typechecking or-patterns can be done following the process as for
typechecking a whole match expression (which is also a disjunction of
patterns), although the treatment of bound variables is a bit different.

Most of thec complexity of this commit comes from the fact that we don't
want to make `or` a language keyword, which would break backward
compatibility. This is possible, because `or` in pattern can't be
confused with an identifier, but it required some tweaking to make our
LALR(1) parser accept this.
  • Loading branch information
yannham committed May 16, 2024
1 parent 0ab9793 commit 6ad281b
Show file tree
Hide file tree
Showing 15 changed files with 652 additions and 58 deletions.
27 changes: 27 additions & 0 deletions core/src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,17 @@ pub enum TypecheckError {
/// The position of the expression that was being typechecked as `type_var`.
pos: TermPos,
},
/// Invalid `or` pattern.
///
/// This error is raised when the patterns composing an `or`-pattern don't have the precise
/// same set of free variables. For example, `'Foo x or 'Bar y`.
OrPatternVarsMismatch {
/// A variable which isn't present in all the other patterns (there might be more of them,
/// this is just a sample).
var: LocIdent,
/// The position of the whole or-pattern.
pos: TermPos,
},
}

#[derive(Debug, PartialEq, Eq, Clone, Default)]
Expand Down Expand Up @@ -2516,6 +2527,22 @@ impl IntoDiagnostics<FileId> for TypecheckError {
),
])]
}
TypecheckError::OrPatternVarsMismatch { var, pos } => {
let mut labels = vec![primary_alt(var.pos.into_opt(), var.into_label(), files)
.with_message("this variable must occur in all branches")];

if let Some(span) = pos.into_opt() {
labels.push(secondary(&span).with_message("in this `or` pattern"));
}

vec![Diagnostic::error()
.with_message("`or` pattern variable mismatch".to_string())
.with_labels(labels)
.with_notes(vec![
"All branches of an `or` pattern must bind exactly the same set of variables"
.into(),
])]
}
}
}
}
Expand Down
Loading

0 comments on commit 6ad281b

Please sign in to comment.