Skip to content

Compiler allows non-functions to be bound to active pattern names #17190

Open
@brianrourkeboll

Description

@brianrourkeboll

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:

let (|P|Q|) = Choice<unit, unit>.Choice1Of2 ()
// error FS1209: Active pattern '|P|Q|' 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):

let (|P|) = 3
// val (|P|) : int = 3

image

(|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.

let (|P|_|) = None
// val (|P|_|) : 'a option

image

let (|P|_|) = ValueNone
// val (|P|_|) : 'a voption

image

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.

Metadata

Metadata

Assignees

Labels

Area-Compiler-CheckingType checking, attributes and all aspects of logic checkingBugImpact-Low(Internal MS Team use only) Describes an issue with limited impact on existing code.help wanted

Type

Projects

Status

New

Relationships

None yet

Development

No branches or pull requests

Issue actions