Skip to content

Commit

Permalink
Or patterns (#1916)
Browse files Browse the repository at this point in the history
This commit introduces or-patterns, which allows to express alternatives
within patterns, 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 of or-patterns can be done following the same 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 the complexity of this commit comes from the fact that we don't
want to make `or` a reserved language keyword, which would break
backward compatibility. This is possible, because `or` in pattern can't
be confused with an identifier, but it requires some tweaking to make
our LALR(1) parser accept this.
  • Loading branch information
yannham authored May 25, 2024
1 parent 928cf14 commit ca0f78f
Show file tree
Hide file tree
Showing 15 changed files with 650 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 ca0f78f

Please sign in to comment.