Skip to content

Conversation

stakx
Copy link
Member

@stakx stakx commented Jun 13, 2018

This should resolve #371 by making two changes:

  1. If MethodEmitter.CopyDefaultValueConstant fails to set the default value for a parameter, it tries a second time but with a default value that's been coerced to the parameter's type. (Because the type coercion can itself fail, it's not done right away, but only when there's a chance that it might help resolve a previous problem.)

  2. Default value replication is turned into a nice-to-have feature that allows silent failure.

Regarding (2), we've been discussing this before (IIRC, in #291), and @jonorossi's opinion was that we should not fail silently because we want to learn about potential problems in default value replication. That discussion was based on the premise that we only need to deal with metadata that's been generated by the .NET Roslyn compilers. As it turns out now, we forgot about the possibility that there are other code generators out there which might not follow the same strict rules of the .NET compilers, and do things that we cannot easily write test cases for from C#'s end.

Since ECMA-335 doesn't require metadata constants to match their associated parameters' types (they're recorded for purely informative purposes), we shouldn't throw errors when we fail to interpret such default values.

@stakx stakx force-pushed the default-parameter-values branch from a8f5062 to 3eb77a7 Compare June 14, 2018 09:32
It is possible to produce metadata constants whose type does not
exactly match that of an optional parameter, but might be coercible.
Add some tests for this scenario using [DefaultParameterValue].
@stakx stakx force-pushed the default-parameter-values branch from 3eb77a7 to 25a06af Compare June 14, 2018 10:38
@stakx stakx changed the title WIP: Try coercing default value to parameter type as a last resort Make default value replication of optional parameters more tolerant of type-mismatched default values Jun 14, 2018
{
CopyDefaultValueConstant(from: parameter, to: parameterBuilder);
}
catch
Copy link
Member Author

Choose a reason for hiding this comment

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

Note that I'm intentionally wrapping CopyDefaultValueConstant with a catch-all instead of rewriting it so that it never throws. Why? Because adding catch-all clauses inside CopyDefaultValueConstant (two of them, one for reading the default value, one for writing it) would make it less obvious why we're going to great lengths catching specific exceptions first. A later maintainer might say, let's just eliminate all these superfluous catch (...) clauses and just keep the catch-all. While that would be a operationally correct optimization (less catching and throwing overall), it would also remove much valuable information from the source code about what can possibly go wrong.

Copy link

@ghost ghost Jun 14, 2018

Choose a reason for hiding this comment

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

Have not reviewed this PR properly yet but I am liking this approach. It formalises ones understanding as a snapshot or point in time. Things change and I am a firm believer in fail and fail hard. Don’t hide things. Like it!

// might produce such metadata. Make a final attempt to coerce it to the required type:
try
{
var coercedDefaultValue = Convert.ChangeType(defaultValue, parameterNonNullableType);
Copy link
Member Author

Choose a reason for hiding this comment

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

Should probably explicitly specify the invariant culture here, otherwise this performs a conversion using the thread's current culture.

@stakx stakx force-pushed the default-parameter-values branch from bdd8122 to c4eeabd Compare June 14, 2018 15:55
@stakx stakx added this to the vNext milestone Jun 14, 2018
@jonorossi
Copy link
Member

Looks great. I kinda knew something would pop up that we missed adding the default value stuff back, but this is a pretty niche problem and a sensible fix.

@jonorossi jonorossi merged commit b689f5d into castleproject:master Jun 15, 2018
@stakx stakx deleted the default-parameter-values branch June 15, 2018 15:07
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

Successfully merging this pull request may close these issues.

ArgumentException in MethodEmitter
2 participants