Async postconditions in generic methods#278
Async postconditions in generic methods#278SergeyTeplyakov merged 6 commits intomicrosoft:masterfrom
Conversation
Add type mapping to change generic type reference in async closure that is called from generic async methods.
Conflicts: Foxtrot/Tests/FoxtrotTests10.csproj
Add additional logic for type comparison to cover generic async methods.
There was a problem hiding this comment.
This delegate seems not to be used anywhere else so the calculation can be performed without it.
There was a problem hiding this comment.
You're right. I thought to extract method but left with "local" function. Will extract function.
There was a problem hiding this comment.
What if method is generic, but returned task uses declaring type generic parameter?
Something like this:
class DeclaringType<T> where T : class {
public async Task<T> MethodAsync<U>() {
Contract.Ensures(Contract.Result<T>() != null);
}
}or scenario with nested type:
class DeclaringType<T> where T : class {
private class NestedType<U> where U : class {
public async Task<T> MethodAsync<V>() {
Contract.Ensures(Contract.Result<T>() != null);
}
}
}Will this also work?
There was a problem hiding this comment.
Not sure. I'll test this code.
|
Any other comments on this stuff? The change was relatively major, so I would like to get additional feedback on this... /cc @sharwell |
There was a problem hiding this comment.
Just out of curiosity. Why do you used CDATA here? is there any difference in just plain text in ?
There was a problem hiding this comment.
I assume, that the would be parsed as xml tag otherwise.
There was a problem hiding this comment.
@hubuk Yep, @AlexanderTaeschner is right. Otherwise we would have to encode all this < with < which is annoying...
|
@SergeyTeplyakov I have found a few cases for which BadImageFormatException is thrown. EDIT: I was able to narrow down all the failing cases to the following two: public class Outer<T> {
public class Inner {
public static Task<T> OuterClassTypeArgument(T obj) {
Contract.Ensures(Contract.Result<T>() != null);
return Task.FromResult(obj);
}
}
}
public static Task<T> DefaultValue<T>(T obj) {
// Does not throw when null is used instead of default(T)
Contract.Ensures(!object.Equals(Contract.Result<T>(), default(T)));
return Task.FromResult(obj);
}// Constraint on Outer<T> class does not matter.
// Reproducible also before fix.
// System.BadImageFormatException thrown for:
// Program.Outer`1.Inner.OuterClassTypeArgument(T obj) method
Outer<object>.Inner.OuterClassTypeArgument(new object()).Wait();
// Constraint on method does not matter.
// Reproducible also before fix.
// Also fails (but only after the fix) when made async.
// Aggregated System.BadImageFormatException thrown for
// Program.<DefaultValue>AsyncContractClosure_0`1.CheckPost(Task`1 task)
DefaultValue(new object()).Wait(); |
|
There is also some questionable behavior for closure class generation. public class OuterClassGeneric<T0> where T0 : class {
public class InnerGeneric<T1> {
public static async Task<T0> AsyncTest1(T0 v0, T1 v1) {
Contract.Ensures(Contract.Result<T0>() != null);
return await Task.FromResult(v0);
}
}
}rewriter generates the following closure class for the method above: .class nested private auto ansi '<AsyncTest1>AsyncContractClosure_0`1'<class T0, T1, T1>
extends [mscorlib]System.ObjectSecond T1 generic type parameter is probably not needed. |
|
Previously CheckPost method content was: TaskStatus status = task.Status;
if (status == TaskStatus.RanToCompletion && __ContractsRuntime.insideContractEvaluation <= 4)
{
try
{
__ContractsRuntime.insideContractEvaluation++;
__ContractsRuntime.Ensures(task.Result != null, null, "Contract.Result<T0>() != null");
}
finally
{
__ContractsRuntime.insideContractEvaluation--;
}
}
return task;now it looks like: TaskStatus status = task.Status;
if (status == TaskStatus.RanToCompletion)
{
__ContractsRuntime.Ensures(task.Result != null, null, "Contract.Result<T0>() != null");
}
return task;Is it intended change? |
|
@hubuk About last comment: the chnage is intented, because async postconditions are all about multi threading where thread static checks like |
|
@hubuk Thanks a lot for clear test cases, I'll fix them and will update PR before pushing it to master. |
|
@hubuk FIxed everything that you've mentioned. Including two test cases that you've provde. Once you'll sign off I'll move forward and will prepare new release of the CodeContracts. |
|
It seems that issue with |
|
@hubuk Great. Moving forward to 1.10 release! |
Async postconditions in generic methods
This PR contains fixes for #235 and #275. Main change in this PR was made in
EmitAsyncClosureclass.Special generic type mapping was added to correlate potentially different generic arguments from enclosing generic method to closure generic class.