-
Notifications
You must be signed in to change notification settings - Fork 859
Compiler allows non-functions to be bound to active pattern names #17190
Copy link
Copy link
Labels
Area-Compiler-CheckingType checking, attributes and all aspects of logic checkingType checking, attributes and all aspects of logic checkingArea-Compiler-PatternMatchingpattern compilation, active patterns, performance, codegenpattern compilation, active patterns, performance, codegenBugImpact-Low(Internal MS Team use only) Describes an issue with limited impact on existing code.(Internal MS Team use only) Describes an issue with limited impact on existing code.help wanted
Milestone
Metadata
Metadata
Labels
Area-Compiler-CheckingType checking, attributes and all aspects of logic checkingType checking, attributes and all aspects of logic checkingArea-Compiler-PatternMatchingpattern compilation, active patterns, performance, codegenpattern compilation, active patterns, performance, codegenBugImpact-Low(Internal MS Team use only) Describes an issue with limited impact on existing code.(Internal MS Team use only) Describes an issue with limited impact on existing code.help wanted
Type
Fields
Give feedbackNo fields configured for Bug.
Projects
Status
New
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.