-
Notifications
You must be signed in to change notification settings - Fork 803
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
Improve Error Reporting: "could not be generalized because it would escape its scope" #3302
Comments
Here is another case of this error message (on
Edit, six years later, accidentally coming across this old post of mine.
|
Same with the following function: let draw<'T when 'T : (member Draw : unit -> unit)> (x: 'T) =
x.Draw() or let draw (x: 'T when 'T : (member Draw : unit -> unit)) =
x.Draw() Bonus question/suggestion: maybe the language could be improved to not require inlining in these cases? Maybe the compiler could generate proxy functions or types that would be "inlined" under the hood to satisfy Statically Resolved Type Parameters, but allow us to use non-inlined functions as well? Inlining may not always be desirable. Consider this example: // Business logic processors
type FirstTypeThatCanDraw() =
member x.Draw() = printfn "I'm drawing!"
type AntherTypeThatCanDraw() =
member x.Draw() = printfn "I'm drawing, too!"
member x.Bark() = printfn "Barking!"
let o = new FirstTypeThatCanDraw()
let p = new AntherTypeThatCanDraw()
// The new features in question (not working today without "inline")
// let draw (x: 'T when 'T : (member Draw : unit -> unit)) =
// x.Draw()
// The new compiler would generate this under the hood (not inlined),
// one for each concrete argument type.
let ``draw$generated_proxy_for_FirstTypeThatCanDraw`` (x: 'T when 'T : (member Draw : unit -> unit)) =
x.Draw();
let ``draw$generated_proxy_for_AntherTypeThatCanDraw`` (x: 'T when 'T : (member Draw : unit -> unit)) =
x.Draw();
// my code would be:
// draw o
// draw p
// but under the hood it would get converted to:
``draw$generated_proxy_for_FirstTypeThatCanDraw`` o
``draw$generated_proxy_for_AntherTypeThatCanDraw`` p The difference is that we would have one body of the function per type instead of one body per call site. Maybe we could use an attribute on the function with constraints to hint compiler about our intent? I'm not sure. The above code generates 2 warnings of the kind: "Warning: this construct causes code to be less generic than indicated by the type annotations. The type variable 'T has been constrained to FirstTypeThatCanDraw." but I hope compiler could handle that, too. Thanks. |
What
This error crops up when creating SRTP members but forgetting to inline them (example here taken from this SO question): -
leads to
error FS0670: This code is not sufficiently generic. The type variable ^T when ^T : (static member ( + ) : ^T * ^T -> ^T) could not be generalized because it would escape its scope.
Why
It seems that the error
could not be generalized because it would escape its scope
normally can be solved by inlining the member definition. There are a few posts / questions out there on SO etc. regarding this, all with that answer.I know that SRTP is a somewhat advanced F# topic but nonetheless the error could be improved since there's often the same fix that can be applied. Also, the current error message could explain itself a little better - what does "it would escape its scope" mean in this context? Why would inlining fix it? etc.
How
I'm not entirely sure, but perhaps a start would be to at least offer the solution: -
error FS0670: This code is not sufficiently generic. The type variable ^T when ^T : (static member ( + ) : ^T * ^T -> ^T) could not be generalized because it would escape its scope. Consider inlining the member to fix this error e.g. "member inline this.F" ...
.However, this still doesn't clearly explain the "why"; someone seeing this for the first (or second!) time won't know why the error is occuring, but rather than a tried-and-tested solution that makes the error go away. Other ideas include: -
"Member constrains need statically resolved type parameters. But statically resolved type parameters are not allowed on types, only for inline functions and inline methods.". This at least tries to address the why the error occurs, although it could still be improved upon IMHO.
The text was updated successfully, but these errors were encountered: