-
Notifications
You must be signed in to change notification settings - Fork 788
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compiler allows non-functions to be bound to active pattern names #17190
Comments
A warning behind a lang feature like we have done in other cases might work here ? |
Yeah, I think that would probably be the best we could do. |
It turns out that members with active pattern names are also allowed (SharpLab) and are not treated as patterns at all by the tooling: [<AutoOpen>]
type Foo =
static member (|P|) = 3
static member (|Q|_|) = 3
static member (|R|_|) = None
static member (|S|_|) = ValueNone
static member (|T|U|) = 3 Anonymous records, too: let x = {| (|P|) = 3 |} (Parens are gone in tooling, though) And constraint calls: let inline f x = (^a : (member (|P|) : int) x)
f {| (|P|) = 3 |} And lambdas: let f : int -> int = fun (|P|) -> (|P|) + (|P|) Or any other pattern-matching context: match 3 with
| (|P|) -> (|P|) + (|P|) Also unions: [<RequireQualifiedAccess>]
type T =
| (|P|) of int
| (|Q|) I guess it's a similar phenomenon to the one that allows you to bind operator names to values: let y = {| (||) = 3 |}
let f (>*^*<) x y = x >*^*< y
They're all just being lexed as |
Yes. from F#'s standpoint, these are just I vaguely remember bringing this up ages ago, but I cannot remember the resolution at the time. We could (should?) issue a warning perhaps, instead of an error? |
I think we should prevent users from using active patterns that are not functions. |
@vzarytovskii Would be ok to create a new language preview flag e.g. |
I suppose, but I will still need to re-read the whole thread to freshen my memory |
@vzarytovskii I think we can start with let (|P|) = 3 // This compiles now. But should show `FS1209: Active pattern '|P|' is not a function` Why:
|
There are a couple of ways in which it is possible to define "active patterns" that are (from the F# perspective) values, not functions. While the tooling treats them as active patterns, it is impossible to actually use them as patterns in any pattern-matching position.
Expected behavior
The compiler disallows defining a multi-case active pattern that is not a function:
I would expect the same for single-case and partial active patterns.
Actual behavior
(|P|)
A value bound to what looks like a single-case active pattern name is actually compiled as a property with a getter (when a module-bound value):
(|P|_|)
An option or value option value bound to a partial active pattern name is compiled to the exact same .NET method as it would be if it were defined as a function, but from the F# perspective it is a value (or a type function, even though you cannot give it explicit type arguments), not a function, although the tooling again treats it as an active pattern.
Unfortunately, updating the compiler to disallow these scenarios would be a breaking change — someone could be passing values so defined around qua values (
f (|P|)
,let r = (|P|) + (|Q|)
, etc.) — although I doubt anyone actually intentionally binds values to active pattern names like this in normal code.The text was updated successfully, but these errors were encountered: