-
Notifications
You must be signed in to change notification settings - Fork 477
Make default value replication of optional parameters more tolerant of type-mismatched default values #375
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
Make default value replication of optional parameters more tolerant of type-mismatched default values #375
Conversation
a8f5062
to
3eb77a7
Compare
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].
3eb77a7
to
25a06af
Compare
{ | ||
CopyDefaultValueConstant(from: parameter, to: parameterBuilder); | ||
} | ||
catch |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
bdd8122
to
c4eeabd
Compare
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. |
This should resolve #371 by making two changes:
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.)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.