Skip to content

Tupled Type Test Pattern Matching caused exponential IL growth #5212

@manofstick

Description

@manofstick

The following functions demonstrate the affect:

let f (a:obj) (b:obj) =
    match a, b with
    | :? char, :? char -> 0
    | :? int,  :? int  -> 1
    | _ -> -1

let g (a:obj) (b:obj) =
    match a, b with
    | :? char, :? char -> 0
    | :? int,  :? int  -> 1
    | :? byte, :? byte -> 2
    | _ -> -1

let h (a:obj) (b:obj) =
    match a, b with
    | :? char,  :? char  -> 0
    | :? int,   :? int   -> 1
    | :? byte,  :? byte  -> 2
    | :? float, :? float -> 3
    | _ -> -1

So type size of the Il generated from those functions is 60, 143, 337 bytes respectively.

The array checking code in prim_types.fs in the funciton GenericEqualityObj which has 8 type-checks creates IL which is around 8K.

Expected behavior

This should be a linear increase.

Actual behavior

The exponential behaviour is due to the AST duplicating the remaining code in both the first and second failing check.

Known workarounds

You can work around this by putting a catch all, and then matching again.

In the prim_types code this would look like this:

match arr1,yobj with 
| (:? (obj[]) as arr1),    (:? (obj[]) as arr2)      -> GenericEqualityObjArray er iec arr1 arr2
| _ ->
match arr1,yobj with 
| (:? (byte[]) as arr1),    (:? (byte[]) as arr2)     -> GenericEqualityByteArray arr1 arr2
| _ ->
match arr1,yobj with 
| (:? (int32[]) as arr1),   (:? (int32[]) as arr2)   -> GenericEqualityInt32Array arr1 arr2
| _ ->
match arr1,yobj with 
| (:? (int64[]) as arr1),   (:? (int64[]) as arr2)   -> GenericEqualityInt64Array arr1 arr2
| _ ->
match arr1,yobj with 
| (:? (char[]) as arr1),    (:? (char[]) as arr2)     -> GenericEqualityCharArray arr1 arr2
| _ ->
match arr1,yobj with 
| (:? (float32[]) as arr1), (:? (float32[]) as arr2) -> GenericEqualitySingleArray er arr1 arr2
| _ ->
match arr1,yobj with 
| (:? (float[]) as arr1),   (:? (float[]) as arr2)     -> GenericEqualityDoubleArray er arr1 arr2
| _ ->
match arr1,yobj with 
| _                   ,    (:? System.Array as arr2) -> GenericEqualityArbArray er iec arr1 arr2
| _ -> xobj.Equals(yobj)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions