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

Can't raise exceptions when returning byref or IsByRefLike types #7606

Closed
amongonz opened this issue Sep 20, 2019 · 4 comments
Closed

Can't raise exceptions when returning byref or IsByRefLike types #7606

amongonz opened this issue Sep 20, 2019 · 4 comments

Comments

@amongonz
Copy link

When a function returns a byref or IsByRefLike type, raise : exn -> 'a can't be called because that instantiates 'a as the byref type. This issue thus extends to any function returning 'a to signal non termination, such as failwith or even exit.

Repro steps

[<Struct; System.Runtime.CompilerServices.IsByRefLike>]
type Resource = Resource of Handle: nativeint

let obtainHandle () = 0n

let createResource () =
    match obtainHandle () with
    | 0n -> failwith "Error creating resource."
    | handle -> Resource handle

Expected behavior

The code above compiles.

Actual behavior

The compiler marks failwith with error FS0412:

A type instantiation involves a byref type. This is not permitted by the rules of Common IL.

Known workarounds

Ignoring the return value and returning instead a dummy value; this path would never be reached.

    | 0n -> failwith "Error creating resource."; Resource 0n

Another workaround, inspired by #6607 and #6133, is to alias the IsByRefLike type and constraint 'a to the alias.

type Res = Resource
    | 0n -> failwith "Error creating resource." : Res

This can be used even if you don't have access to a constructor or function that returns the IsByRefLike type, but seems fragile to future compiler versions.

Related information

Tested on .NET Core 3.0.100-preview7-012821.

@cartermp
Copy link
Contributor

See here: #5776

This is by design, as failwith is a generic function that would imply boxing.

@amongonz
Copy link
Author

Sorry for the duplicate! I didn't find that issue in my first search.

I understand why this is by design for byref types, but I'm surprised this affects IsByRefLike types too, unless they have some unnecessary CLR limitations. I'll take a deep look at this.

@cartermp
Copy link
Contributor

@debugnik In this case, ByRefLike structs have the same semantics as byrefs. They're stack-only types that cannot be boxed.

@amongonz
Copy link
Author

amongonz commented Sep 21, 2019

@cartermp I understand the limitations of byrefs. I just think it would be safe to instantiate a generic method with a byref-like when it appears only in the return position (or not at all, like the phantom type in typeof). The method can't box a byref-like or store it in an object if doesn't have one in the first place.

But I've learned that this is enforced at the CLR level, so don't mind me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants