-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Refactor missing reference errors to allow not throwing for all cases #50437
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,5 +40,6 @@ public enum ExceptionStringID | |
|
|
||
| // BadImageFormatException | ||
| BadImageFormatGeneric, | ||
| BadImageFormatSpecific, | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| namespace Internal.TypeSystem | ||
| { | ||
| public enum NotFoundBehavior | ||
| { | ||
| Throw, | ||
| ReturnNull, | ||
| ReturnResolutionFailure | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| namespace Internal.TypeSystem | ||
| { | ||
| public sealed class ResolutionFailure | ||
| { | ||
| private enum FailureType | ||
| { | ||
| TypeLoadException1, | ||
| TypeLoadException2, | ||
| TypeLoadException3, | ||
| MissingMethodException1, | ||
| MissingFieldException1, | ||
| MissingAssemblyException1, | ||
| } | ||
|
|
||
| private ResolutionFailure() { } | ||
|
|
||
| private FailureType _failureType; | ||
| private string _namespace; | ||
| private string _name; | ||
| private string _moduleName; | ||
| private ModuleDesc _module; | ||
| private TypeDesc _owningType; | ||
| private MethodSignature _methodSignature; | ||
|
|
||
|
|
||
| public static ResolutionFailure GetTypeLoadResolutionFailure(string nestedTypeName, ModuleDesc module) | ||
| { | ||
| ResolutionFailure failure = new ResolutionFailure(); | ||
| failure._failureType = FailureType.TypeLoadException1; | ||
| failure._name = nestedTypeName; | ||
| failure._module = module; | ||
| return failure; | ||
| } | ||
|
|
||
| public static ResolutionFailure GetTypeLoadResolutionFailure(string @namespace, string name, ModuleDesc module) | ||
| { | ||
| ResolutionFailure failure = new ResolutionFailure(); | ||
| failure._failureType = FailureType.TypeLoadException2; | ||
| failure._namespace = @namespace; | ||
| failure._name = name; | ||
| failure._module = module; | ||
| return failure; | ||
| } | ||
|
|
||
| public static ResolutionFailure GetTypeLoadResolutionFailure(string @namespace, string name, string moduleName) | ||
| { | ||
| ResolutionFailure failure = new ResolutionFailure(); | ||
| failure._failureType = FailureType.TypeLoadException3; | ||
| failure._namespace = @namespace; | ||
| failure._name = name; | ||
| failure._moduleName = moduleName; | ||
| return failure; | ||
| } | ||
|
|
||
| public static ResolutionFailure GetMissingMethodFailure(TypeDesc owningType, string methodName, MethodSignature signature) | ||
| { | ||
| ResolutionFailure failure = new ResolutionFailure(); | ||
| failure._failureType = FailureType.MissingMethodException1; | ||
| failure._methodSignature = signature; | ||
| failure._name = methodName; | ||
| failure._owningType = owningType; | ||
| return failure; | ||
| } | ||
|
|
||
| public static ResolutionFailure GetMissingFieldFailure(TypeDesc owningType, string fieldName) | ||
| { | ||
| ResolutionFailure failure = new ResolutionFailure(); | ||
| failure._failureType = FailureType.MissingMethodException1; | ||
| failure._name = fieldName; | ||
| failure._owningType = owningType; | ||
| return failure; | ||
| } | ||
|
|
||
| public static ResolutionFailure GetAssemblyResolutionFailure(string simpleName) | ||
| { | ||
| ResolutionFailure failure = new ResolutionFailure(); | ||
| failure._failureType = FailureType.MissingAssemblyException1; | ||
| failure._name = simpleName; | ||
| return failure; | ||
| } | ||
|
|
||
| public void Throw() | ||
| { | ||
| switch(_failureType) | ||
| { | ||
| case FailureType.TypeLoadException1: | ||
| ThrowHelper.ThrowTypeLoadException(_name, _module); | ||
| break; | ||
| case FailureType.TypeLoadException2: | ||
| ThrowHelper.ThrowTypeLoadException(_namespace, _name, _module); | ||
| break; | ||
| case FailureType.TypeLoadException3: | ||
| ThrowHelper.ThrowTypeLoadException(_namespace, _name, _moduleName); | ||
| break; | ||
| case FailureType.MissingMethodException1: | ||
| ThrowHelper.ThrowMissingMethodException(_owningType, _name, _methodSignature); | ||
| break; | ||
| case FailureType.MissingFieldException1: | ||
| ThrowHelper.ThrowMissingFieldException(_owningType, _name); | ||
| break; | ||
| case FailureType.MissingAssemblyException1: | ||
| ThrowHelper.ThrowFileNotFoundException(ExceptionStringID.FileLoadErrorGeneric, _name); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -276,7 +276,7 @@ private static MetadataType GetType(this ModuleDesc module, string fullName, boo | |
| namespaceName = fullName.Substring(0, split); | ||
| typeName = fullName.Substring(split + 1); | ||
| } | ||
| return module.GetType(namespaceName, typeName, throwIfNotFound); | ||
| return module.GetType(namespaceName, typeName, throwIfNotFound ? NotFoundBehavior.Throw : NotFoundBehavior.ReturnNull); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to propagate the new enum up the call graph instead of decoding the bool "in the middle"?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Plausibly, but this change is already quite large enough, and very few components other than the internals of the typesystem actually can do anything useful with ResolutionFailure objects. So I don't think we need to perturb the api of the typesystem more than I already have. |
||
| } | ||
|
|
||
| private static AssemblyName FindAssemblyIfNamePresent(string name) | ||
|
|
||
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.
Wondering if it would be easier to just have a single field in this that is the exception instance.
We would need to update ThrowHelper so that we have
CreateXXXmethods along withThrowXXXmethods on it.Then the usage is "new ResolutionFailure(ThrowHelper.CreateFileNotFoundException(...));`
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.
I considered that, but unfortunately, as these ResolutionFailure objects are persistent, it can result in multiple throws with the exact same exception in them. While this does work, it results in stack traces in the exception being somewhat nondeterministic, which I very much disapprove of.