Skip to content
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

Better warning messages on quotations of "large" disjunctive pattern matches #7589

Open
kevmal opened this issue Sep 18, 2019 · 4 comments
Open
Assignees
Labels
Area-Quotations Quotations (compiler support or library). See also "queries" Bug Impact-Medium (Internal MS Team use only) Describes an issue with moderate impact on existing code.
Milestone

Comments

@kevmal
Copy link
Contributor

kevmal commented Sep 18, 2019

With
F# Interactive version 10.6.0.0 for F# 4.7 and
F# Interactive version 10.5.0.0 for F# 4.6

type MyType = 
    {
        A : bool
        B : double
        C : double
    }
let (|Q|_|) (x : double) : unit option = None
let q =
    <@@
        match None, None, Unchecked.defaultof<_> with
        | None, Some p, {A = true; B = Q; C = Q}  -> ()
        | None, Some p, {A = true; B = x; C = Q}  -> ()
        | None, Some p, {A = true; B = Q; C = x}  -> ()
        | Some o, None, {A = true; B = Q; C = Q}  -> ()
        | Some o, None, {A = true; B = x; C = Q}  -> ()
        | Some o, None, {A = true; B = x; C = Q}  -> ()
        | Some o, None, {A = true; B = Q; C = x}  -> ()
        | Some o, None, {A = true; B = Q; C = x}  -> ()
        | _ -> printfn ""
        ()    
    @@>

Produces the error:

error FS0193: internal error: Data size must be > 0 and < 0x3f0000

This also compiles fine to a 23MB release build binary. It seems the Expr expansion of a match is not feasible. Each condition is causing a full branch which includes all cases below it. For example consider:

open FSharp.Quotations

let count n q =
    let rec loop q = 
        match q with
        | Patterns.Value((:? uint64 as x),_) when x = n -> 1
        | ExprShape.ShapeCombination(a, args) -> args |> List.sumBy loop
        | ExprShape.ShapeLambda(v, body) -> loop body
        | ExprShape.ShapeVar(v) -> 0
    loop q


<@
    match None, Unchecked.defaultof<_> with
    | None, {A = true; B = Q; C = Q} -> 1UL
    | _ -> 100UL
@>
|> count 100UL

Here the 100UL branch gets counted 4 times, With

<@
    match None, Unchecked.defaultof<_> with
    | None, {A = true; B = Q; C = Q} -> 1UL
    | None, {A = true; B = Q; C = Q} -> 2UL
    | _ -> 100UL
@>

the 2UL branch now counts to 4 and the 100UL branch is now at 16. This quickly explodes with relatively simple match blocks.

@cartermp cartermp added this to the Backlog milestone Sep 18, 2019
@cartermp
Copy link
Contributor

This could very well be related to #4691

@kevmal
Copy link
Contributor Author

kevmal commented Sep 19, 2019

It may partially be related. With quotations the situation is much worse though, the above when compiled (not quoted) the 100UL in all cases appears exactly once since instead of expanding repeating else branches the compiled code simply returns early. Here it's just a simple value but whatever the code block is gets repeated however many times (easily thousands of times).

For example, the compiled code above translates to 128 lines of C#. The quotation translates to well over 50000 lines (actual quote takes too long to decompile, ~50000 lines is actually from a slightly simpler case)

@TIHan TIHan self-assigned this Sep 26, 2019
@TIHan
Copy link
Contributor

TIHan commented Sep 26, 2019

Yea, that is a bit of a problem. I will try take on both this problem and the other one posted (#4691). I've been looking at pattern matching lately anyway so I have some context.

@dsyme
Copy link
Contributor

dsyme commented Aug 31, 2020

As @TIHan and I have discussed, this is to some extent intrinsic in the design of quotations - quotations are an expression form and large disjunctive pattern matches can result in arbitrarily large expressions, and require an intermediate representation that includes some forms of goto/tree/branch/local-function structure to capture the possible code paths in a non-exponential way

So as things stand this is by-design, but a warning message indicating the approach of the problem ("your quotation is getting large") would be appropriate

Fixing the problem more generally is tricky and would require significant adjustments to quotations

@dsyme dsyme changed the title Quotation causes: 'FS0193: internal error: Data size must be > 0 and < 0x3f0000' Better error message on quotations of "large" disjunctive pattern matches Aug 31, 2020
@dsyme dsyme changed the title Better error message on quotations of "large" disjunctive pattern matches Better warning messages on quotations of "large" disjunctive pattern matches Aug 31, 2020
@dsyme dsyme added the Impact-Medium (Internal MS Team use only) Describes an issue with moderate impact on existing code. label Aug 31, 2020
@dsyme dsyme added Area-Compiler-PatternMatching pattern compilation, active patterns, performance, codegen and removed Area-Compiler labels Mar 31, 2022
@dsyme dsyme added Area-Quotations Quotations (compiler support or library). See also "queries" and removed Area-Compiler-PatternMatching pattern compilation, active patterns, performance, codegen labels Apr 20, 2022
@vzarytovskii vzarytovskii moved this to Not Planned in F# Compiler and Tooling Jun 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Quotations Quotations (compiler support or library). See also "queries" Bug Impact-Medium (Internal MS Team use only) Describes an issue with moderate impact on existing code.
Projects
Status: New
Development

No branches or pull requests

5 participants