Skip to content
This repository was archived by the owner on Jul 15, 2023. It is now read-only.
This repository was archived by the owner on Jul 15, 2023. It is now read-only.

Contract.Requires not rewritten in async methods compiled by Roslyn #51

@danielcweber

Description

@danielcweber

There already are some open issues that deal with the rewriter missing Asserts/Assumes in async methods/iterators (notably #41), however, these are concerned with rather complex conditions in these Asserts.

This issue is about Contract.Requires with simple conditions (such as param != null) in async methods compiled by Roslyn (VS 2015).

Simple working example (class library project):

using System.Diagnostics.Contracts;
using System.Threading.Tasks;

namespace RewriterWithRoslynRepro
{
    public class Class
    {
        public async Task<int> AsyncMethod(string str)
        {
            Contract.Requires(str != null);

            await Task.Delay(100);

            return 0;
        }
    }
}

After some investigation (I am not familiar with these sources), the rewriter seems to do the following steps upon encountering an async method (i.e. a method that sets up a state machine and so on)

  • it looks up the MoveNext method of the state machine that is generated by the compiler
  • it simulates what MoveNext would do when it's called for the first time
  • it finds an IL block "B" that possibly contains a Contract.Requires statement
  • it looks up the last Contract.Requires statement that occurs after or in "B". By last, I mean highest in terms of the IL offset of the statement.

The lookup of such a block "B" succeeds for IL compiled with the native compiler but fails for Roslyn compiled IL. Upon further investigation, i found this assumption in the code.

From my experiments with Roslyn compiled code, this does not hold (any more?). The initial state is still -1. Changing this line to var initialState = isAsync ? -1 : 0; lets the rewriter find the block.

Can someone with insight into Roslyn confirm that the initial state of an async state machine is indeed -1 and not 0 ?

EDIT: According to the Roslyn sources (here and here) the initial state is indeed -1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions