ReducedFrom should return constructed generic method

Topics: APIs
May 5, 2014 at 3:20 PM
I'm not sure if this should be considered a bug or by design, but the IMethodSymbol.ReducedFrom property currently returns the original definition of the method. However, it seems like it should return a constructed generic method if the original method was a constructed generic method. For example, if I analyze a Where method invocation on an IEnumerable<double> type, I will get a method with this signature:
public IEnumerable<double> Where<double>(Func<double, bool> predicate)
But if I ask for the ReducedFrom of that method, I would get a method with this signature:
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
When I would think it should instead return a method with this signature:
public static IEnumerable<double> Where<double>(this IEnumerable<double> source, Func<double, bool> predicate)
Because in the current implementation, if I want to treat an extension method symbol as its associated static method symbol, I would have to do something like this:
if (extensionMethodInvoke)
{
    var reducedFrom = methodSymbol.ReducedFrom;

    if (methodSymbol.TypeArguments.Length != 0)
    {
        reducedFrom = reducedFrom.Construct(methodSymbol.TypeArguments.ToArray());
    }

    methodSymbol = reducedFrom;
}
And it would be much nicer to be able to do this:
if (extensionMethodInvoke)
{
    methodSymbol = methodSymbol.ReducedFrom;
}
Also, I would think that in code such as this, the first Debug.Assert would pass, but it fails and only the second assert passes:
var extensionMethod = staticMethod.ReduceExtensionMethod(receiverType);
Debug.Assert(extensionMethod.ReducedFrom.Equals(staticMethod));
Debug.Assert(extensionMethod.ReducedFrom.Construct(staticMethod.TypeArguments.ToArray()).Equals(staticMethod));
Developer
May 6, 2014 at 9:16 PM
There is a method you can call to get what you want.

methodSymbol.GetConstructedReducedFrom()
Marked as answer by mdour on 5/6/2014 at 2:49 PM
May 6, 2014 at 9:48 PM
Great, thank you very much. I'm not sure how I missed that one. However, I still feel like there is a slight problem with naming here. Like I said, I would assume this assert would pass:
var extensionMethod = staticMethod.ReduceExtensionMethod(receiverType);
Debug.Assert(extensionMethod.ReducedFrom.Equals(staticMethod));
Maybe a different name should be used for ReducedFrom so as not to imply that you'll get back the symbol on which ReduceExtensionMethod was called.
Developer
May 6, 2014 at 11:24 PM
mattwar wrote:
There is a method you can call to get what you want.

methodSymbol.GetConstructedReducedFrom()
Perhaps the current GetConstructedReducedFrom should be ReducedFrom, and ReducedFrom should be ReducedFromOriginal?
May 7, 2014 at 12:03 AM
nmgafter wrote:
mattwar wrote:
There is a method you can call to get what you want.

methodSymbol.GetConstructedReducedFrom()
Perhaps the current GetConstructedReducedFrom should be ReducedFrom, and ReducedFrom should be ReducedFromOriginal?
I haven't used Infragistics controls in a while but they used to use Resolved for calculated properties. For example Enabled and EnabledResolved.
May 7, 2014 at 2:10 AM
PauloMorgado wrote:
I haven't used Infragistics controls in a while but they used to use Resolved for calculated properties. For example Enabled and EnabledResolved.
I'm actually a developer at Infragistics so I can offer some insight here. We typically use the ...Resolved pattern for a setting that can optionally be set at multiple levels. For example, in the XamDataGrid's fields, you can set field settings on a single field to affect that one field, on a field layout to affect all field in that layout, or on the XamDataGrid itself to affect all fields in the grid. There are associated ...Resolved properties defined on the field so you can get the effective value of a particular setting on a particular field. It will walk the chain from highest priority setting to lowest and return the first that is non-default, or some ultimate default if no value was provided at any level.

However, this is a different kind of scenario. Nothing really needs to be resolved in this sense.

nmgafter - I like ReducedFrom and ReducedFromOriginal. But will the former need to stay an extension method? I assume it was not a member of the interface for a reason. If that's the case and it will stay a method, it might seem a little odd:
var staticMethod = extensionMethod.ReducedFrom();
Maybe GetReducedFrom or GetReducedStaticMethod:
var staticMethod = extensionMethod.GetReducedStaticMethod();