This PR adds a special pattern that match any value but doesn't bind anything, the wildcard pattern _.
This subsumes the previously special case of the catch-all case of match expression _ => default_value. Now a match expression is simply a list of patterns, and _ is just one of them.
This addition allows to use _ anywhere in a nested pattern, like 'Foo ('Bar _), which is especially useful when matching on enum variants. The ideas introduced for the typechecking of the catch-all case _ => of match expressions naturally extend to wildcards pattern: if somewhere in a nested pattern, there is a wildcard which is in the same position as an enum variant in a sibling pattern, like match { {foo = 'Bar} => something, {foo = _} => something_else}, this makes the corresponding enum type open: the above match expression has type forall r. {foo : [| 'Bar; r |]} -> SomeType.
A wildcard pattern doesn't force the value being matched on, following the idea that it's equivalent to let _x = value in body (but without binding _x). In general, from now on, we'll try to follow the idea that the semantics of destructuring let <pattern> = value in body should be equivalent to value |> match { <pattern> => body, _ => <NonExhaustiveDestructuringError> }. Following this guideline, it confirms that let _ shouldn't force the matched value. One last argument for this behavior is that fun _ => body is desugared to fun fresh_var => let _ = fresh_var in body, which means that making let _ strict would make fun _ => body strict in its argument, which is arguably very surprising (for reviewers, this contradicts what I said today earlier in the weekly meeting, because I made a mistake with wildcard patterns specifically - the "destructuring should force" is still valid for other patterns though, and it agrees with everything said here)
This PR adds a special pattern that match any value but doesn't bind anything, the wildcard pattern
_
.This subsumes the previously special case of the catch-all case of match expression
_ => default_value
. Now a match expression is simply a list of patterns, and_
is just one of them.This addition allows to use
_
anywhere in a nested pattern, like'Foo ('Bar _)
, which is especially useful when matching on enum variants. The ideas introduced for the typechecking of the catch-all case_ =>
of match expressions naturally extend to wildcards pattern: if somewhere in a nested pattern, there is a wildcard which is in the same position as an enum variant in a sibling pattern, likematch { {foo = 'Bar} => something, {foo = _} => something_else}
, this makes the corresponding enum type open: the above match expression has typeforall r. {foo : [| 'Bar; r |]} -> SomeType
.A wildcard pattern doesn't force the value being matched on, following the idea that it's equivalent to
let _x = value in body
(but without binding_x
). In general, from now on, we'll try to follow the idea that the semantics of destructuringlet <pattern> = value in body
should be equivalent tovalue |> match { <pattern> => body, _ => <NonExhaustiveDestructuringError> }
. Following this guideline, it confirms thatlet _
shouldn't force the matched value. One last argument for this behavior is thatfun _ => body
is desugared tofun fresh_var => let _ = fresh_var in body
, which means that makinglet _
strict would makefun _ => body
strict in its argument, which is arguably very surprising (for reviewers, this contradicts what I said today earlier in the weekly meeting, because I made a mistake with wildcard patterns specifically - the "destructuring should force" is still valid for other patterns though, and it agrees with everything said here)