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

Add conversions spec for function pointers #3263

Merged
merged 2 commits into from
Mar 11, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions proposals/function-pointers.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,18 @@ delegate* managed<string, int>;
delegate*<delegate* managed<string, int>, delegate*<string, int>>;
```

### Function pointer conversions

In an unsafe context, the set of available implicit conversions (Implicit conversions) is extended to include the following implicit pointer conversions:
- [_Existing conversions_](https://github.com/dotnet/csharplang/blob/master/spec/unsafe-code.md#pointer-conversions)
- From _funcptr\_type_ `F0` to another _funcptr\_type_ `F1`, provided all of the following are true:
- `F0` and `F1` have the same number of parameters, and each parameter `D0n` in `F0` has the same `ref`, `out`, or `in` modifiers as the corresponding parameter `D1n` in `F1`.
- For each value parameter (a parameter with no `ref`, `out`, or `in` modifier), an identity conversion, implicit reference conversion, or implicit pointer conversion exists from the parameter type in `F0` to the corresponding parameter type in `F1`.
Copy link
Contributor

@AlekseyTs AlekseyTs Mar 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

implicit reference conversion, or implicit pointer conversion exists from the parameter type in F0 to the corresponding parameter type in F1. [](start = 109, length = 145)

Does runtime support this kind of mismatch natively, or will compiler have to generate a stub to make this work? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does runtime support this kind of mismatch natively, or will compiler have to generate a stub to make this work?

Natively. We don't even emit a cast for explicit conversions.

- For each `ref`, `out`, or `in` parameter, the parameter type in `F0` is the same as the corresponding parameter type in `F1`.
- If the return type is by value (no `ref` or `ref readonly`), an identity, implicit reference, or implicit pointer conversion exists from the return type of `F1` to the return type of `F0`.
- If the return type is by reference (`ref` or `ref readonly`), the return type and `ref` modifiers of `F1` are the same as the return type and `ref` modifiers of `F0`.
- The calling convention of `F0` is the same as the calling convention of `F1`.

### Allow address-of to target methods

Method groups will now be allowed as arguments to an address-of expression. The type of such an
Expand All @@ -151,11 +163,26 @@ unsafe class Util {
}
```

The conversion of an address-of method group to `delegate*` has roughly the same process as method group to `delegate`
conversion. There are two additional restrictions to the existing process:

- Only members of the method group that are marked as `static` will be considered.
- Only a `delegate*` with a managed calling convention can be the target of such a conversion.
In an unsafe context, a method `M` is compatible with a function pointer type `F` if all of the following are true:
- `M` and `F` have the same number of parameters, and each parameter in `D` has the same `ref`, `out`, or `in` modifiers as the corresponding parameter in `F`.
- For each value parameter (a parameter with no `ref`, `out`, or `in` modifier), an identity conversion, implicit reference conversion, or implicit pointer conversion exists from the parameter type in `M` to the corresponding parameter type in `F`.
Copy link
Contributor

@AlekseyTs AlekseyTs Mar 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

implicit reference conversion, or implicit pointer conversion exists from the parameter type in M to the corresponding parameter type in F. [](start = 105, length = 143)

Same question here. #Closed

- For each `ref`, `out`, or `in` parameter, the parameter type in `M` is the same as the corresponding parameter type in `F`.
- If the return type is by value (no `ref` or `ref readonly`), an identity, implicit reference, or implicit pointer conversion exists from the return type of `F` to the return type of `M`.
- If the return type is by reference (`ref` or `ref readonly`), the return type and `ref` modifiers of `F` are the same as the return type and `ref` modifiers of `M`.
- The calling convention of `M` is the same as the calling convention of `F`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How you determine calling convention of M ? Is this going to take into account the NativeCallable attribute?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this going to take into account the NativeCallable attribute?

I was planning on it doing so, yes, but I'm not sure if that's something that should be explicitly called out in our spec or if should be an implementation detail. @gafter for thoughts on that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not feel right to me to talk about calling convention in the spec, but not explain where it comes from.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that if the spec depends on a concept, it should define it. However, that can be left for a future refinement of this spec. Put it in an open issue?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to the open issues list.

- `M` is a static method.

In an unsafe context, an implicit conversion exists from an address-of expression whose target is a method group `E` to a compatible function pointer type `F` if `E` contains at least one method that is applicable in its normal form to an argument list constructed by use of the parameter types and modifiers of `F`, as described in the following.
- A single method `M` is selected corresponding to a method invocation of the form `E(A)` with the following modifications:
- The arguments list `A` is a list of expressions, each classified as a variable and with the type and modifier (`ref`, `out`, or `in`) of the corresponding _formal\_parameter\_list_ of `D`.
- The candidate methods are only those methods that are only those methods that are applicable in their normal form, not those applicable in their expanded form.
- If the algorithm of Method invocations produces an error, then a compile-time error occurs. Otherwise, the algorithm produces a single best method `M` having the same number of parameters as `F` and the conversion is considered to exist.
- The selected method `M` must be compatible (as defined above) with the function pointer type `F`. Otherwise, a compile-time error occurs.
- The result of the conversion is a function pointer of type `F`.

An implicit conversion exists from an address-of expression whose target is a method group `E` to `void*` if there is only one static method `M` in `E`.
If there is one static method, then the single best method from `E` is `M`.
Otherwise, a compile-time error occurs.

This means developers can depend on overload resolution rules to work in conjunction with the
address-of operator:
Expand Down