Report better error for misused await operator
authorMarek Safar <marek.safar@gmail.com>
Wed, 5 Oct 2011 14:41:01 +0000 (15:41 +0100)
committerMarek Safar <marek.safar@gmail.com>
Wed, 5 Oct 2011 14:41:38 +0000 (15:41 +0100)
mcs/errors/cs1992.cs [new file with mode: 0644]
mcs/errors/cs4003.cs [new file with mode: 0644]
mcs/mcs/cs-parser.jay
mcs/mcs/cs-tokenizer.cs
mcs/tests/gtest-exmethod-23.cs

diff --git a/mcs/errors/cs1992.cs b/mcs/errors/cs1992.cs
new file mode 100644 (file)
index 0000000..7314b7c
--- /dev/null
@@ -0,0 +1,14 @@
+// CS1992: The `await' operator can only be used when its containing method or lambda expression is marked with the `async' modifier
+// Line: 10
+// Compiler options: -langversion:future
+
+using System.Threading.Tasks;
+
+class Tester
+{
+       void Test ()
+       {
+               Task<int> x = null;
+               var a = await x;
+       }
+}
diff --git a/mcs/errors/cs4003.cs b/mcs/errors/cs4003.cs
new file mode 100644 (file)
index 0000000..9de8f87
--- /dev/null
@@ -0,0 +1,11 @@
+// CS4003: `await' cannot be used as an identifier within an async method or lambda expression
+// Line: 8
+// Compiler options: -langversion:future
+
+class Tester
+{
+       async void Test ()
+       {
+               int await = 1;
+       }
+}
index 6000a67390e13d4118d3db0b327f41bd463d0071..821b44873b8ffdf489a3e86b753591fab9240006 100644 (file)
@@ -75,6 +75,8 @@ namespace Mono.CSharp
                ParametersCompiled current_local_parameters;
 
                bool parsing_anonymous_method;
+               
+               bool async_block;
 
                ///
                /// An out-of-band stack.
@@ -823,7 +825,7 @@ named_attribute_argument
        ;
        
 named_argument
-       : IDENTIFIER COLON opt_named_modifier expression
+       : identifier_inside_body COLON opt_named_modifier expression
          {
                if (lang_version <= LanguageVersion.V_3)
                        FeatureIsNotAvailable (GetLocation ($1), "named argument");
@@ -1187,14 +1189,14 @@ method_declaration
 
                // Add it early in the case of body being eof for full ast
                Method m = (Method) $1;
-               lexer.async_block = (m.ModFlags & Modifiers.ASYNC) != 0;
+               async_block = (m.ModFlags & Modifiers.ASYNC) != 0;
                current_container.AddMethod (m);
          }
          method_body
          {
                Method method = (Method) $1;
                method.Block = (ToplevelBlock) $3;
-               lexer.async_block = false;
+               async_block = false;
                
                if (method.Block == null) {
                        method.ParameterInfo.CheckParameters (method);
@@ -3579,32 +3581,32 @@ typeof_type_expression
        ;
        
 unbound_type_name
-       : IDENTIFIER generic_dimension
+       : identifier_inside_body generic_dimension
          {  
                var lt = (Tokenizer.LocatedToken) $1;
 
                $$ = new SimpleName (lt.Value, (int) $2, lt.Location);
          }
-       | qualified_alias_member IDENTIFIER generic_dimension
+       | qualified_alias_member identifier_inside_body generic_dimension
          {
                var lt1 = (Tokenizer.LocatedToken) $1;
                var lt2 = (Tokenizer.LocatedToken) $2;
 
                $$ = new QualifiedAliasMember (lt1.Value, lt2.Value, (int) $3, lt1.Location);
          }
-       | unbound_type_name DOT IDENTIFIER
+       | unbound_type_name DOT identifier_inside_body
          {
                var lt = (Tokenizer.LocatedToken) $3;
                
                $$ = new MemberAccess ((Expression) $1, lt.Value, lt.Location);         
          }
-       | unbound_type_name DOT IDENTIFIER generic_dimension
+       | unbound_type_name DOT identifier_inside_body generic_dimension
          {
                var lt = (Tokenizer.LocatedToken) $3;
                
                $$ = new MemberAccess ((Expression) $1, lt.Value, (int) $4, lt.Location);               
          }
-       | namespace_or_type_name DOT IDENTIFIER generic_dimension
+       | namespace_or_type_name DOT identifier_inside_body generic_dimension
          {
                var te = ((MemberName) $1).GetTypeExpression ();
                if (te.HasTypeArguments)
@@ -3728,22 +3730,20 @@ unary_expression
          {
                $$ = new Unary (Unary.Operator.OnesComplement, (Expression) $2, GetLocation ($1));
          }
-       | cast_expression
-       | await_expression
-       ;
-
-cast_expression
-       : OPEN_PARENS_CAST type CLOSE_PARENS prefixed_unary_expression
+       | OPEN_PARENS_CAST type CLOSE_PARENS prefixed_unary_expression
          {
                $$ = new Cast ((FullNamedExpression) $2, (Expression) $4, GetLocation ($1));
                lbag.AddLocation ($$, GetLocation ($3));
          }
-       ;
-       
-await_expression
-       : AWAIT unary_expression
+       | AWAIT prefixed_unary_expression
          {
-               current_block.ParametersBlock.IsAsync = true;
+               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");
+               } else {
+                       current_block.ParametersBlock.IsAsync = true;
+               }
+               
                $$ = new Await ((Expression) $2, GetLocation ($1));
          }
        ;
@@ -4021,13 +4021,13 @@ lambda_parameter_list
        ;
 
 lambda_parameter
-       : parameter_modifier parameter_type IDENTIFIER
+       : parameter_modifier parameter_type identifier_inside_body
          {
                var lt = (Tokenizer.LocatedToken) $3;
 
                $$ = new Parameter ((FullNamedExpression) $2, lt.Value, (Parameter.Modifier) $1, null, lt.Location);
          }
-       | parameter_type IDENTIFIER
+       | parameter_type identifier_inside_body
          {
                var lt = (Tokenizer.LocatedToken) $2;
 
@@ -4086,7 +4086,7 @@ lambda_expression
                $$ = end_anonymous ((ParametersBlock) $4);
                lbag.AddLocation ($$, GetLocation ($2));
          }
-       | ASYNC IDENTIFIER ARROW
+       | ASYNC identifier_inside_body ARROW
          {
                var lt = (Tokenizer.LocatedToken) $2;
                Parameter p = new ImplicitLambdaParameter (lt.Value, lt.Location);
@@ -4639,7 +4639,7 @@ empty_statement
        ;
 
 labeled_statement
-       : IDENTIFIER COLON 
+       : identifier_inside_body COLON 
          {
                var lt = (Tokenizer.LocatedToken) $1;
                LabeledStatement labeled = new LabeledStatement (lt.Value, current_block, lt.Location);
@@ -4747,8 +4747,19 @@ pointer_star
          }
        ;
 
+identifier_inside_body
+       : IDENTIFIER
+       | AWAIT
+         {
+               if (async_block) {
+                       report.Error (4003, GetLocation ($1), "`await' cannot be used as an identifier within an async method or lambda expression");
+                       $$ = Tokenizer.LocatedToken.Create ("await", GetLocation ($1));
+               }
+         }
+       ;
+
 block_variable_declaration
-       : variable_type IDENTIFIER
+       : variable_type identifier_inside_body
          {
                var lt = (Tokenizer.LocatedToken) $2;
                var li = new LocalVariable (current_block, lt.Value, lt.Location);
@@ -4761,7 +4772,7 @@ block_variable_declaration
                current_variable = null;
                lbag.AddLocation ($$, GetLocation ($6));
          }
-       | CONST variable_type IDENTIFIER
+       | CONST variable_type identifier_inside_body
          {
                var lt = (Tokenizer.LocatedToken) $3;
                var li = new LocalVariable (current_block, lt.Value, LocalVariable.Flags.Constant, lt.Location);
@@ -4816,7 +4827,7 @@ variable_declarators
        ;
        
 variable_declarator
-       : COMMA IDENTIFIER
+       : COMMA identifier_inside_body
          {
                var lt = (Tokenizer.LocatedToken) $2;     
                var li = new LocalVariable (current_variable.Variable, lt.Value, lt.Location);
@@ -4825,7 +4836,7 @@ variable_declarator
                current_block.AddLocalName (li);
                lbag.AddLocation (d, GetLocation ($1));
          }
-       | COMMA IDENTIFIER ASSIGN block_variable_initializer
+       | COMMA identifier_inside_body ASSIGN block_variable_initializer
          {
                var lt = (Tokenizer.LocatedToken) $2;     
                var li = new LocalVariable (current_variable.Variable, lt.Value, lt.Location);
@@ -4858,7 +4869,7 @@ const_declarators
        ;
        
 const_declarator
-       : COMMA IDENTIFIER ASSIGN constant_initializer_expr
+       : COMMA identifier_inside_body ASSIGN constant_initializer_expr
          {
                var lt = (Tokenizer.LocatedToken) $2;     
                var li = new LocalVariable (current_block, lt.Value, LocalVariable.Flags.Constant, lt.Location);
@@ -5111,7 +5122,7 @@ opt_for_initializer
        ;
 
 for_initializer
-       : variable_type IDENTIFIER
+       : variable_type identifier_inside_body
          {
                var lt = (Tokenizer.LocatedToken) $2;
                var li = new LocalVariable (current_block, lt.Value, lt.Location);
@@ -5163,7 +5174,7 @@ foreach_statement
                report.Error (230, GetLocation ($1), "Type and identifier are both required in a foreach statement");
                $$ = null;
          }
-       | FOREACH open_parens_any type IDENTIFIER IN expression CLOSE_PARENS 
+       | FOREACH open_parens_any type identifier_inside_body IN expression CLOSE_PARENS 
          {
                start_block (GetLocation ($2));
                current_block.IsCompilerGenerated = true;
@@ -5212,7 +5223,7 @@ continue_statement
        ;
 
 goto_statement
-       : GOTO IDENTIFIER SEMICOLON 
+       : GOTO identifier_inside_body SEMICOLON 
          {
                var lt = (Tokenizer.LocatedToken) $2;
                $$ = new Goto (lt.Value, lt.Location);
@@ -5247,7 +5258,7 @@ throw_statement
        ;
 
 yield_statement 
-       : IDENTIFIER RETURN opt_expression SEMICOLON
+       : identifier_inside_body RETURN opt_expression SEMICOLON
          {
                var lt = (Tokenizer.LocatedToken) $1;
                string s = lt.Value;
@@ -5263,7 +5274,7 @@ yield_statement
                $$ = new Yield ((Expression) $3, lt.Location);
                lbag.AddStatement ($$, GetLocation ($2), GetLocation ($4));
          }
-       | IDENTIFIER BREAK SEMICOLON
+       | identifier_inside_body BREAK SEMICOLON
          {
                var lt = (Tokenizer.LocatedToken) $1;
                string s = lt.Value;
@@ -5334,7 +5345,7 @@ catch_clauses
 
 opt_identifier
        : /* empty */
-       | IDENTIFIER
+       | identifier_inside_body
        ;
 
 catch_clause 
@@ -5410,7 +5421,7 @@ lock_statement
        ;
 
 fixed_statement
-       : FIXED open_parens_any variable_type IDENTIFIER
+       : FIXED open_parens_any variable_type identifier_inside_body
          {
            start_block (GetLocation ($2));
            
@@ -5437,7 +5448,7 @@ fixed_statement
        ;
 
 using_statement
-       : USING open_parens_any variable_type IDENTIFIER
+       : USING open_parens_any variable_type identifier_inside_body
          {
            start_block (GetLocation ($2));
            
@@ -5527,7 +5538,7 @@ query_expression
        ;
        
 first_from_clause
-       : FROM_FIRST IDENTIFIER IN expression
+       : FROM_FIRST identifier_inside_body IN expression
          {
                current_block = new Linq.QueryBlock (current_block, lexer.Location);
          
@@ -5535,7 +5546,7 @@ first_from_clause
                var rv = new Linq.RangeVariable (lt.Value, lt.Location);
                $$ = new Linq.QueryExpression (new Linq.QueryStartClause ((Linq.QueryBlock)current_block, (Expression)$4, rv, GetLocation ($1)));
          }
-       | FROM_FIRST type IDENTIFIER IN expression
+       | FROM_FIRST type identifier_inside_body IN expression
          {
                current_block = new Linq.QueryBlock (current_block, lexer.Location);
          
@@ -5550,7 +5561,7 @@ first_from_clause
        ;
 
 nested_from_clause
-       : FROM IDENTIFIER IN expression
+       : FROM identifier_inside_body IN expression
          {
                current_block = new Linq.QueryBlock (current_block, lexer.Location);
          
@@ -5558,7 +5569,7 @@ nested_from_clause
                var rv = new Linq.RangeVariable (lt.Value, lt.Location);
                $$ = new Linq.QueryExpression (new Linq.QueryStartClause ((Linq.QueryBlock)current_block, (Expression)$4, rv, GetLocation ($1)));
          }
-       | FROM type IDENTIFIER IN expression
+       | FROM type identifier_inside_body IN expression
          {
                current_block = new Linq.QueryBlock (current_block, lexer.Location);
          
@@ -5573,7 +5584,7 @@ nested_from_clause
        ;
        
 from_clause
-       : FROM IDENTIFIER IN
+       : FROM identifier_inside_body IN
          {
                current_block = new Linq.QueryBlock (current_block, lexer.Location);
          }
@@ -5588,7 +5599,7 @@ from_clause
                
                ((Linq.QueryBlock)current_block).AddRangeVariable (sn);
          }       
-       | FROM type IDENTIFIER IN
+       | FROM type identifier_inside_body IN
          {
                current_block = new Linq.QueryBlock (current_block, lexer.Location);
          }
@@ -5691,7 +5702,7 @@ query_body_clause
        ;
        
 let_clause
-       : LET IDENTIFIER ASSIGN 
+       : LET identifier_inside_body ASSIGN 
          {
                current_block = new Linq.QueryBlock (current_block, lexer.Location);
          }
@@ -5723,7 +5734,7 @@ where_clause
        ;
        
 join_clause
-       : JOIN IDENTIFIER IN
+       : JOIN identifier_inside_body IN
          {
                if (linq_clause_blocks == null)
                        linq_clause_blocks = new Stack<Linq.QueryBlock> ();
@@ -5783,7 +5794,7 @@ join_clause
                current_block = block.Parent;
                ((Linq.QueryBlock)current_block).AddRangeVariable (into);
          }
-       | JOIN type IDENTIFIER IN
+       | JOIN type identifier_inside_body IN
          {
                if (linq_clause_blocks == null)
                        linq_clause_blocks = new Stack<Linq.QueryBlock> ();
@@ -5851,7 +5862,7 @@ join_clause
        
 opt_join_into
        : /* empty */
-       | INTO IDENTIFIER
+       | INTO identifier_inside_body
          {
                $$ = $2;
          }
@@ -5936,7 +5947,7 @@ then_by
 
 opt_query_continuation
        : /* empty */
-       | INTO IDENTIFIER
+       | INTO identifier_inside_body
          {
                // query continuation block is not linked with query block but with block
                // before. This means each query can use same range variable names for
@@ -6457,7 +6468,7 @@ void start_anonymous (bool isLambda, ParametersCompiled parameters, bool isAsync
        oob_stack.Push (current_anonymous_method);
        oob_stack.Push (current_local_parameters);
        oob_stack.Push (current_variable);
-       oob_stack.Push (lexer.async_block);
+       oob_stack.Push (async_block);
 
        current_local_parameters = parameters;
        if (isLambda) {
@@ -6472,7 +6483,7 @@ void start_anonymous (bool isLambda, ParametersCompiled parameters, bool isAsync
                current_anonymous_method = new AnonymousMethodExpression (isAsync, loc);
        }
 
-       lexer.async_block = isAsync;
+       async_block = isAsync;
        // Force the next block to be created as a ToplevelBlock
        parsing_anonymous_method = true;
 }
@@ -6488,7 +6499,7 @@ AnonymousMethodExpression end_anonymous (ParametersBlock anon_block)
        current_anonymous_method.Block = anon_block;
        retval = current_anonymous_method;
 
-       lexer.async_block = (bool) oob_stack.Pop ();
+       async_block = (bool) oob_stack.Pop ();
        current_variable = (BlockVariableDeclaration) oob_stack.Pop ();
        current_local_parameters = (ParametersCompiled) oob_stack.Pop ();
        current_anonymous_method = (AnonymousMethodExpression) oob_stack.Pop ();
@@ -6707,8 +6718,6 @@ static string GetTokenName (int token)
                return "add";
        case Token.ASYNC:
                return "async";
-       case Token.AWAIT:
-               return "await";         
        case Token.BASE:
                return "base";
        case Token.BREAK:
@@ -6970,6 +6979,7 @@ static string GetTokenName (int token)
        case Token.LITERAL:
                return "value";
        case Token.IDENTIFIER:
+       case Token.AWAIT:
                return "identifier";
 
        case Token.EOF:
index 39ecfd02d238805613dca0332785f118a747b8f2..6caeacbc3dfc80bf87d746efe5b1707fbce1e886 100644 (file)
@@ -87,6 +87,11 @@ namespace Mono.CSharp
                        {
                                return Create (null, row, column);
                        }
+
+                       public static LocatedToken Create (string value, Location loc)
+                       {
+                               return Create (value, loc.Row, loc.Column);
+                       }
                        
                        public static LocatedToken Create (string value, int row, int column)
                        {
@@ -211,8 +216,6 @@ namespace Mono.CSharp
 
                public bool parsing_modifiers;
 
-               public bool async_block;
-
                //
                // The special characters to inject on streams to run the unit parser
                // in the special expression mode. Using private characters from
@@ -836,7 +839,7 @@ namespace Mono.CSharp
                                break;
 
                        case Token.AWAIT:
-                               if (!async_block)
+                               if (parsing_block == 0)
                                        res = -1;
 
                                break;
@@ -2855,7 +2858,7 @@ namespace Mono.CSharp
                        if (id_builder [0] >= '_' && !quoted) {
                                int keyword = GetKeyword (id_builder, pos);
                                if (keyword != -1) {
-                                       val = LocatedToken.Create (null, ref_line, column);
+                                       val = LocatedToken.Create (keyword == Token.AWAIT ? "await" : null, ref_line, column);
                                        return keyword;
                                }
                        }
index fcd27f2b73a21859dab60322409c81ffa6fd00d3..1bc927517ac375456791c1595c6dc60c3a76397a 100644 (file)
@@ -1,4 +1,4 @@
-// Compiler options: -nostdlib -noconfig -r:mscorlib.dll -r:System.Core.dll
+// Compiler options: -nostdlib -noconfig -r:mscorlib.dll -r:System.Core.dll -lib:../class/lib/net_4_5
 
 public static class T
 {