--- /dev/null
+// CS0127: `C.GetValue()': A return keyword must not be followed by any expression when method returns void
+// Line: 11
+
+using System;
+using System.Threading.Tasks;
+
+class C
+{
+ public async void GetValue()
+ {
+ return await Task.FromResult(100);
+ }
+}
-// CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
+// CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// Line: 7
class T {
-// CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
+// CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// Line: 7
class T {
-// CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
+// CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// Line: 8
class MainClass
-// CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
+// CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// Line: 10
class TestClass
-// CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
+// CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// Line: 13
class C<T>
-// CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
+// CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// Line: 10
using System.Linq;
-// CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
+// CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// Line: 11
using System;
-// CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
+// CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// Line: 11
using System;
-// CS1977: Query expression with a source or join sequence of type `dynamic' is not allowed
+// CS1979: Query expressions with a source or join sequence of type `dynamic' are not allowed
// Line: 11
using System.Linq;
--- /dev/null
+// CS1989: Async lambda expressions cannot be converted to expression trees
+// Line: 17
+
+using System;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+
+class C
+{
+ static Task Method ()
+ {
+ return null;
+ }
+
+ public static void Main ()
+ {
+ Expression<Action<int>> a = async l => Method ();
+ }
+}
-// CS1989: An expression tree cannot contain an await operator
+// CS1989: Async lambda expressions cannot be converted to expression trees
// Line: 17
using System;
+++ /dev/null
-// CS1992: The `await' operator can only be used when its containing method or lambda expression is marked with the `async' modifier
-// Line: 10
-
-using System.Threading.Tasks;
-
-class Tester
-{
- void Test ()
- {
- Task<int> x = null;
- var a = await x;
- }
-}
--- /dev/null
+// CS1995: The `await' operator may only be used in a query expression within the first collection expression of the initial `from' clause or within the collection expression of a `join' clause
+// Line: 12
+
+using System.Linq;
+using System.Threading.Tasks;
+
+class C
+{
+ public static async void Test ()
+ {
+ Task<int>[] d = null;
+ var r = from x in d select await x;
+ }
+}
-// CS1997: `C.Test()': A return keyword must not be followed by an expression when async method returns Task. Consider using Task<T>
+// CS1997: `C.Test()': A return keyword must not be followed by an expression when async method returns `Task'. Consider using `Task<T>' return type
// Line: 12
using System;
--- /dev/null
+// CS4008: Cannot await void method `X.Foo()'. Consider changing method return type to `Task'
+// Line: 10
+
+using System.Threading.Tasks;
+
+class X
+{
+ static async void Test ()
+ {
+ await Foo ();
+ }
+
+ static async void Foo ()
+ {
+ await Task.FromResult (1);
+ }
+}
--- /dev/null
+// CS4014: The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator
+// Line: 17
+// Compiler options: -warnaserror
+
+using System;
+using System.Threading.Tasks;
+
+class C
+{
+ static Task Method ()
+ {
+ return Task.FromResult (1);
+ }
+
+ static void TestAsync ()
+ {
+ Func<Task> a = async () => {
+ await Method ();
+ Method ();
+ };
+ }
+}
--- /dev/null
+// CS4014: The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator
+// Line: 18
+// Compiler options: -warnaserror
+
+using System;
+using System.Threading.Tasks;
+
+class C
+{
+ static async Task<int> TestAsync ()
+ {
+ Func<Task> f = null;
+ f ();
+ return await Task.FromResult (2);
+ }
+}
--- /dev/null
+// CS4014: The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator
+// Line: 12
+// Compiler options: -warnaserror
+
+using System;
+using System.Threading.Tasks;
+
+class C
+{
+ static async Task<int> TestAsync ()
+ {
+ new Task (() => {});
+ return await Task.FromResult (2);
+ }
+}
--- /dev/null
+// CS4014: The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator
+// Line: 18
+// Compiler options: -warnaserror
+
+using System;
+using System.Threading.Tasks;
+
+class C
+{
+ static Task Method ()
+ {
+ return Task.FromResult (1);
+ }
+
+ static async Task<int> TestAsync ()
+ {
+ Method ();
+ return await Task.FromResult (2);
+ }
+}
--- /dev/null
+// CS4015: `C.SynchronousCall(int)': Async methods cannot use `MethodImplOptions.Synchronized'
+// Line: 9
+
+using System.Threading.Tasks;
+using System.Runtime.CompilerServices;
+
+class C
+{
+ [MethodImplAttribute(MethodImplOptions.Synchronized)]
+ public static async Task SynchronousCall (int arg)
+ {
+ await Task.FromResult (1);
+ }
+}
--- /dev/null
+// CS4016: `C.GetValue()': The return expression type of async method must be `int' rather than `Task<int>'
+// Line: 12
+
+using System;
+using System.Threading.Tasks;
+
+class C
+{
+ public async Task<int> GetValue()
+ {
+ await Task.FromResult (0);
+ return Task.FromResult (1);
+ }
+}
--- /dev/null
+// CS4033: The `await' operator can only be used when its containing method is marked with the `async' modifier
+// Line: 11
+
+using System.Threading.Tasks;
+
+class Tester
+{
+ void Test ()
+ {
+ Task<int> x = null;
+ var a = await x;
+ }
+}
--- /dev/null
+// CS4034: The `await' operator can only be used when its containing lambda expression is marked with the `async' modifier
+// Line: 11
+
+using System;
+using System.Threading.Tasks;
+
+class C
+{
+ public void Test ()
+ {
+ Action a = () => await Task.FromResult (1);
+ }
+}
--- /dev/null
+// CS4035: The `await' operator can only be used when its containing anonymous method is marked with the `async' modifier
+// Line: 11
+
+using System;
+using System.Threading.Tasks;
+
+class C
+{
+ public void Test ()
+ {
+ Action a = delegate { await Task.FromResult (1); };
+ }
+}
# Operators
cs0457-2.cs
cs0457.cs
-
-# all the following are from bug #628673
-cs1979.cs
} else {
int errors = ec.Report.Errors;
+ if (Block.IsAsync) {
+ ec.Report.Error (1989, loc, "Async lambda expressions cannot be converted to expression trees");
+ }
+
using (ec.Set (ResolveContext.Options.ExpressionTreeConversion)) {
am = body.Compatible (ec);
}
"The `await' operator cannot be used in the body of a lock statement");
}
- if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
- rc.Report.Error (1989, loc, "An expression tree cannot contain an await operator");
- return null;
- }
-
if (rc.IsUnsafe) {
rc.Report.Error (4004, loc,
"The `await' operator cannot be used in an unsafe context");
protected override void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
{
- rc.Report.Error (4001, loc, "Cannot await `{0}' expression", type.GetSignatureForError ());
+ var invocation = LeftExpression as Invocation;
+ if (invocation != null && invocation.MethodGroup != null && (invocation.MethodGroup.BestCandidate.Modifiers & Modifiers.ASYNC) != 0) {
+ rc.Report.Error (4008, loc, "Cannot await void method `{0}'. Consider changing method return type to `Task'",
+ invocation.GetSignatureForError ());
+ } else {
+ rc.Report.Error (4001, loc, "Cannot await `{0}' expression", type.GetSignatureForError ());
+ }
}
}
public override bool Resolve (BlockContext bc)
{
+ if (bc.CurrentBlock is Linq.QueryBlock) {
+ bc.Report.Error (1995, loc,
+ "The `await' operator may only be used in a query expression within the first collection expression of the initial `from' clause or within the collection expression of a `join' clause");
+ return false;
+ }
+
if (!base.Resolve (bc))
return false;
// Returns true for MethodImplAttribute with MethodImplOptions.InternalCall value
//
public bool IsInternalCall ()
+ {
+ return (GetMethodImplOptions () & MethodImplOptions.InternalCall) != 0;
+ }
+
+ public MethodImplOptions GetMethodImplOptions ()
{
MethodImplOptions options = 0;
if (pos_args.Count == 1) {
options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), named.GetValue ().ToString ());
}
- return (options & MethodImplOptions.InternalCall) != 0;
+ return options;
}
//
// or it's a parameter
//
if (CurrentAnonymousMethod is AsyncInitializer)
- return CurrentBlock.Explicit.HasAwait;
+ return local.IsParameter || CurrentBlock.Explicit.HasAwait;
return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
}
| AWAIT prefixed_unary_expression
{
if (!async_block) {
- report.Error (1992, GetLocation ($1),
- "The `await' operator can only be used when its containing method or lambda expression is marked with the `async' modifier");
+ if (current_anonymous_method is LambdaExpression) {
+ report.Error (4034, GetLocation ($1),
+ "The `await' operator can only be used when its containing lambda expression is marked with the `async' modifier");
+ } else if (current_anonymous_method is AnonymousMethodExpression) {
+ report.Error (4035, GetLocation ($1),
+ "The `await' operator can only be used when its containing anonymous method is marked with the `async' modifier");
+ } else {
+ report.Error (4033, GetLocation ($1),
+ "The `await' operator can only be used when its containing method is marked with the `async' modifier");
+ }
} else {
current_block.Explicit.RegisterAsyncAwait ();
}
public static void Error_InvalidExpressionStatement (Report Report, Location loc)
{
- Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
- "expressions can be used as a statement");
+ Report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
}
public void Error_InvalidExpressionStatement (BlockContext ec)
if (es == null)
Error_InvalidExpressionStatement (ec);
+ if (ec.CurrentAnonymousMethod is AsyncInitializer && !(e is Assign) &&
+ (e.Type.IsGenericTask || e.Type == ec.Module.PredefinedTypes.Task.TypeSpec)) {
+ ec.Report.Warning (4014, 1, e.Location,
+ "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
+ }
+
return es;
}
return expr;
}
}
+
+ public MethodGroupExpr MethodGroup {
+ get {
+ return mg;
+ }
+ }
#endregion
protected override void CloneTo (CloneContext clonectx, Expression t)
return rmg;
}
+ protected override Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
+ {
+ ec.Report.Error (1979, loc,
+ "Query expressions with a source or join sequence of type `dynamic' are not allowed");
+ return null;
+ }
+
#region IErrorHandler Members
bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter)
{
-/*
- expr = expr.Resolve (ec);
- if (expr == null)
- return null;
-
- if (expr.Type == InternalType.Dynamic || expr.Type == TypeManager.void_type) {
- ec.Report.Error (1979, expr.Location,
- "Query expression with a source or join sequence of type `{0}' is not allowed",
- TypeManager.CSharpName (expr.Type));
- return null;
- }
-*/
-
if (IdentifierType != null)
expr = CreateCastExpression (expr);
using System.Text;
using System.Linq;
using Mono.CompilerServices.SymbolWriter;
+using System.Runtime.CompilerServices;
#if NET_2_1
using XmlElement = System.Object;
}
if (a.Type == pa.MethodImpl) {
- is_external_implementation = a.IsInternalCall ();
- }
+ if ((ModFlags & Modifiers.ASYNC) != 0 && (a.GetMethodImplOptions () & MethodImplOptions.Synchronized) != 0) {
+ Report.Error (4015, a.Location, "`{0}': Async methods cannot use `MethodImplOptions.Synchronized'",
+ GetSignatureForError ());
+ }
- if (a.Type == pa.DllImport) {
+ is_external_implementation = a.IsInternalCall ();
+ } else if (a.Type == pa.DllImport) {
const Modifiers extern_static = Modifiers.EXTERN | Modifiers.STATIC;
if ((ModFlags & extern_static) != extern_static) {
Report.Error (601, a.Location, "The DllImport attribute must be specified on a method marked `static' and `extern'");
2002, 2023, 2029,
3000, 3001, 3002, 3003, 3005, 3006, 3007, 3008, 3009,
3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019,
- 3021, 3022, 3023, 3024, 3026, 3027
+ 3021, 3022, 3023, 3024, 3026, 3027,
+ 4014
};
static HashSet<int> AllWarningsHashSet;
ec.Report.Error (127, loc,
"`{0}': A return keyword must not be followed by any expression when method returns void",
ec.GetSignatureForError ());
+
+ return false;
}
} else {
if (am.IsIterator) {
return true;
}
+ // TODO: Better error message
+ if (async_type.Kind == MemberKind.Void) {
+ ec.Report.Error (127, loc,
+ "`{0}': A return keyword must not be followed by any expression when method returns void",
+ ec.GetSignatureForError ());
+
+ return false;
+ }
+
if (!async_type.IsGenericTask) {
if (this is ContextualReturn)
return true;
ec.Report.Error (1997, loc,
- "`{0}': A return keyword must not be followed by an expression when async method returns Task. Consider using Task<T>",
+ "`{0}': A return keyword must not be followed by an expression when async method returns `Task'. Consider using `Task<T>' return type",
ec.GetSignatureForError ());
return false;
}
//
// The return type is actually Task<T> type argument
//
- block_return_type = async_type.TypeArguments[0];
+ if (expr.Type == async_type) {
+ ec.Report.Error (4016, loc,
+ "`{0}': The return expression type of async method must be `{1}' rather than `Task<{1}>'",
+ ec.GetSignatureForError (), async_type.TypeArguments[0].GetSignatureForError ());
+ } else {
+ block_return_type = async_type.TypeArguments[0];
+ }
}
} else {
var l = am as AnonymousMethodBody;
-// Compiler options: -langversion:future
-
-using System;
-using System.Linq.Expressions;
using System.Threading.Tasks;
class C
{
- static Task Method ()
+ public async Task SynchronousCall (int arg)
+ {
+ AnotherTask (arg);
+ }
+
+ Task AnotherTask (int arg)
{
- return null;
+ return Task.FromResult (arg);
}
public static void Main ()
{
- Expression<Action<int>> a = async l => Method ();
- a.Compile () (1);
+ new C ().SynchronousCall (1);
}
-}
+}
\ No newline at end of file
</test>
<test name="test-async-05.cs">
<type name="C">
- <method name="System.Threading.Tasks.Task Method()" attrs="145">
- <size>10</size>
- </method>
<method name="Void Main()" attrs="150">
- <size>72</size>
+ <size>14</size>
</method>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="System.Threading.Tasks.Task SynchronousCall(Int32)" attrs="134">
+ <size>38</size>
+ </method>
+ <method name="System.Threading.Tasks.Task AnotherTask(Int32)" attrs="129">
+ <size>15</size>
+ </method>
+ </type>
+ <type name="C+<SynchronousCall>c__async0">
+ <method name="Void MoveNext()" attrs="134">
+ <size>49</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>18</size>
+ </method>
</type>
</test>
<test name="test-async-06.cs">
</method>
</type>
</test>
+ <test name="test-async-28.cs">
+ <type name="C">
+ <method name="System.Threading.Tasks.Task Test()" attrs="150">
+ <size>24</size>
+ </method>
+ <method name="Void Main()" attrs="150">
+ <size>12</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="C+<Test>c__async0">
+ <method name="Void MoveNext()" attrs="134">
+ <size>275</size>
+ </method>
+ <method name="Int32 <>m__0(Int32)" attrs="145">
+ <size>10</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>18</size>
+ </method>
+ </type>
+ </test>
<test name="test-cls-00.cs">
<type name="CLSCLass_6">
<method name="Void add_Disposed(Delegate)" attrs="2182">