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

Support open delegate for Nullable<> #42837

Merged
merged 2 commits into from
Mar 19, 2021

Conversation

amos402
Copy link
Contributor

@amos402 amos402 commented Sep 29, 2020

Because of the boxing behavior specialization for Nullable<>, after the boxing, a nullable object may be boxed by the type it referred to or just null, the original type information lost.
For example,

int? num1 = 123;
object box = num1;
// box.GetType() == typeof(int);

int? num2= null;
object box = num2;
// box is null

Thus it's reasonable that a closed delegate binding for Nullable<> such as Delegate.CreateDelegate(invokeType, boxedNullable, method) is prohibited.
However, if for an open delegate case for Nullable<>, the invokeType must point to a delegate in which the first parameter is ref Nullable<XXX>, so it's no need to worry about the type information lost.
Currently, there's a special check for nullable type:

// we don't allow you to bind to methods on Nullable<T> because the unboxing stubs don't know how to
// handle this case.
if (!pTargetMethod->IsStatic() && Nullable::IsNullableType(pTargetMethod->GetMethodTable()))
return FALSE;

This specialized check is unnecessary, we can just remove it.
case 1: a closed delegate with boxed nullable value, no matter which type it would be, it just can't pass the type validation because the type won't match the nullable type.
case 2: an open delegate targeted by xx Func(ref Nullable<XXX> self), the self type for the target method would use its reference type, the fromHandle and toHandle pass to IsLocationAssignable would be the same one.
It makes the code like as follow can't be used on .NetCore(.Net framework as well), on the other side, mono can.
The present version throws an ArgumentException for these cases.

delegate bool HasValueDelegate(ref int? obj);
delegate int GetValueDelegate(ref int? obj);
delegate string ToStringDelegate(ref int? obj);

static void Main(string[] args)
{
    int? num = 123;
    Type type = typeof(int?);
    {
        var mHasValue = typeof(int?).GetProperty("HasValue").GetMethod;
        var HasValue = (HasValueDelegate)Delegate.CreateDelegate(typeof(HasValueDelegate), mHasValue);
        Console.WriteLine("HasValue: {0}", HasValue(ref num));
    }

    {
        var t2 = (GetValueDelegate)Delegate.CreateDelegate(typeof(GetValueDelegate), type.GetProperty("Value").GetMethod);
        int value = t2(ref num);
        Console.WriteLine("Value: {0}", value);
    }

    {
        const BindingFlags MethodFlag = BindingFlags.Public | BindingFlags.Instance;
        var mGetValueOrDefault = typeof(int?).GetMethods(MethodFlag)
            .Single(m => m.Name == "GetValueOrDefault" && m.GetParameters().Length == 0);
        var GetValueOrDefault = (GetValueDelegate)Delegate.CreateDelegate(typeof(GetValueDelegate), mGetValueOrDefault);
        Console.WriteLine("GetValueOrDefault: {0}", GetValueOrDefault(ref num));
    }

    {
        var mToString = type.GetMethod("ToString");
        var ToString = (ToStringDelegate)Delegate.CreateDelegate(typeof(ToStringDelegate), mToString);
        Console.WriteLine("ToString: {0}", ToString(ref num));
    }
}

@ghost
Copy link

ghost commented Sep 29, 2020

Tagging subscribers to this area: @safern, @ViktorHofer
See info in area-owners.md if you want to be subscribed.

@dnfadmin
Copy link

dnfadmin commented Sep 29, 2020

CLA assistant check
All CLA requirements met.

@davidwrighton
Copy link
Member

/azp list

@davidwrighton
Copy link
Member

/azp run runtime

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@ViktorHofer
Copy link
Member

// Auto-generated message

69e114c which was merged 12/7 removed the intermediate src/coreclr/src/ folder. This PR needs to be updated as it touches files in that directory which causes conflicts.

To update your commits you can use this bash script: https://gist.github.com/ViktorHofer/6d24f62abdcddb518b4966ead5ef3783. Feel free to use the comment section of the gist to improve the script for others.

@mangod9
Copy link
Member

mangod9 commented Feb 23, 2021

@davidwrighton and @lambdageek will follow up on this.

Base automatically changed from master to main March 1, 2021 09:07
@davidwrighton
Copy link
Member

@lambdageek This change looks good from the coreclr point of view, but I'm not prepared to merge with a comment about what you'd like done for the mono interpreter. I could disable the test for the interpreter runs and for wasm, or either you or @amos402 could look into fixing the interpreter.

@lambdageek
Copy link
Member

@davidwrighton Please disable the test and ping me with the issue. The interpreter has a separate path through our (convoluted) delegate code and I don't think it's necessary to hold up this PR.

Copy link
Member

@davidwrighton davidwrighton left a comment

Choose a reason for hiding this comment

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

This is a good change. I'd like to apologize for how long it took for us to get started on review of it.

@davidwrighton davidwrighton merged commit ef6c694 into dotnet:main Mar 19, 2021
MichalStrehovsky added a commit to MichalStrehovsky/runtimelab that referenced this pull request Mar 25, 2021
Port of dotnet/runtime#42837.

Won't win any perf prizes, but will do for now. I don't think the amount of work required for good support will ever meet the bar.
MichalStrehovsky added a commit to dotnet/runtimelab that referenced this pull request Mar 26, 2021
Port of dotnet/runtime#42837.

Won't win any perf prizes, but will do for now. I don't think the amount of work required for good support will ever meet the bar.
@ghost ghost locked as resolved and limited conversation to collaborators Apr 18, 2021
@karelz karelz added this to the 6.0.0 milestone May 20, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants