From f3aca9d6fb3d65f851fd18eb230aa3f11d7531c0 Mon Sep 17 00:00:00 2001 From: Marcin Wachulski Date: Tue, 26 Jun 2018 13:20:16 +0200 Subject: [PATCH 01/45] Fix 'else without if' parsing - better error msg Instead of a general syntax error } expected message we want sth like Syntax error 'if' expected. Fixes dotnet/roslyn#27866 --- .../CSharp/Portable/Parser/LanguageParser.cs | 14 +- .../IOperationTests_IIfStatement.cs | 208 +++++++++++++++++ .../Syntax/Parsing/StatementParsingTests.cs | 213 ++++++++++++++++++ 3 files changed, 431 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index a0443c0d9df3a..b97d551fe46e7 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -6613,6 +6613,7 @@ private StatementSyntax ParseStatementNoDeclaration(bool allowAnyExpression) case SyntaxKind.GotoKeyword: return this.ParseGotoStatement(); case SyntaxKind.IfKeyword: + case SyntaxKind.ElseKeyword: return this.ParseIfStatement(); case SyntaxKind.LockKeyword: return this.ParseLockStatement(); @@ -7250,6 +7251,7 @@ private bool IsPossibleStatement(bool acceptAccessibilityMods) case SyntaxKind.ForEachKeyword: case SyntaxKind.GotoKeyword: case SyntaxKind.IfKeyword: + case SyntaxKind.ElseKeyword: case SyntaxKind.LockKeyword: case SyntaxKind.ReturnKeyword: case SyntaxKind.SwitchKeyword: @@ -7845,14 +7847,17 @@ private GotoStatementSyntax ParseGotoStatement() private IfStatementSyntax ParseIfStatement() { - Debug.Assert(this.CurrentToken.Kind == SyntaxKind.IfKeyword); + Debug.Assert(this.CurrentToken.Kind == SyntaxKind.IfKeyword || this.CurrentToken.Kind == SyntaxKind.ElseKeyword); + var @if = this.EatToken(SyntaxKind.IfKeyword); var openParen = this.EatToken(SyntaxKind.OpenParenToken); var condition = this.ParseExpressionCore(); var closeParen = this.EatToken(SyntaxKind.CloseParenToken); - var statement = this.ParseEmbeddedStatement(); - var elseClause = ParseElseClauseOpt(); - + // when 'if' is missing, then we parse an expression statement in a standard way (which adds missing syntax properly) + // parsing embedded one expects non-null statement to be present + var statement = this.CurrentToken.Kind == SyntaxKind.ElseKeyword ? this.ParseExpressionStatement() : this.ParseEmbeddedStatement(); + var elseClause = this.ParseElseClauseOpt(); + return _syntaxFactory.IfStatement(@if, openParen, condition, closeParen, statement, elseClause); } @@ -8687,6 +8692,7 @@ private static bool IsInvalidSubExpression(SyntaxKind kind) case SyntaxKind.ForEachKeyword: case SyntaxKind.GotoKeyword: case SyntaxKind.IfKeyword: + case SyntaxKind.ElseKeyword: case SyntaxKind.LockKeyword: case SyntaxKind.ReturnKeyword: case SyntaxKind.SwitchKeyword: diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs index 7c4245c103ff6..c5cbdf006e197 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs @@ -869,6 +869,214 @@ private static void A(bool flag, int number) VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] + [Fact, WorkItem(27866, "https://github.com/dotnet/roslyn/issues/27866")] + public void IIfstatementWithIfMissing() + { + string source = @" +using System; + +class P +{ + private void M() + { + /**/else + { + Console.WriteLine(new string('a', 5)); + } +/**/ } +} +"; + string expectedOperationTree = @" +IConditionalOperation (OperationKind.Conditional, Type: null) (Syntax: '/**/e ... }') + Condition: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenTrue: + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') + Expression: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenFalse: + IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Wri ... g('a', 5));') + Expression: + IInvocationOperation (void System.Console.WriteLine(System.String value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Wri ... ng('a', 5))') + Instance Receiver: + null + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'new string('a', 5)') + IObjectCreationOperation (Constructor: System.String..ctor(System.Char c, System.Int32 count)) (OperationKind.ObjectCreation, Type: System.String) (Syntax: 'new string('a', 5)') + Arguments(2): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: c) (OperationKind.Argument, Type: null) (Syntax: ''a'') + ILiteralOperation (OperationKind.Literal, Type: System.Char, Constant: a) (Syntax: ''a'') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: count) (OperationKind.Argument, Type: null) (Syntax: '5') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 5) (Syntax: '5') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Initializer: + null + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) +"; + var expectedDiagnostics = new DiagnosticDescription[] { + // file.cs(7,6): error CS1003: Syntax error, 'if' expected + // { + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(7, 6), + // file.cs(7,6): error CS1003: Syntax error, '(' expected + // { + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(7, 6), + // file.cs(7,6): error CS1525: Invalid expression term 'else' + // { + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(7, 6), + // file.cs(7,6): error CS1026: ) expected + // { + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 6), + // file.cs(7,6): error CS1525: Invalid expression term 'else' + // { + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(7, 6), + // file.cs(7,6): error CS1002: ; expected + // { + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(7, 6) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [CompilerTrait(CompilerFeature.IOperation)] + [Fact, WorkItem(27866, "https://github.com/dotnet/roslyn/issues/27866")] + public void IIfstatementWithDoubleElse() + { + string source = @" +using System; + +class P +{ + private void Op() + { + } + + private void M(bool flag) + { + /**/if (flag) + { + Op(); + } + else + { + Console.WriteLine(flag); + } + else + { + Console.WriteLine(!flag); + } +/**/ } +} +"; + string expectedOperationTree = @" +IConditionalOperation (OperationKind.Conditional, Type: null, IsInvalid) (Syntax: 'if (flag) ... }') + Condition: + IParameterReferenceOperation: flag (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'flag') + WhenTrue: + IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Op();') + Expression: + IInvocationOperation ( void P.Op()) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Op()') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: P, IsImplicit) (Syntax: 'Op') + Arguments(0) + WhenFalse: + IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.WriteLine(flag);') + Expression: + IInvocationOperation (void System.Console.WriteLine(System.Boolean value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.WriteLine(flag)') + Instance Receiver: + null + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'flag') + IParameterReferenceOperation: flag (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'flag') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) +"; + var expectedDiagnostics = new DiagnosticDescription[] { + // file.cs(19,10): error CS1003: Syntax error, 'if' expected + // } + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(19, 10), + // file.cs(19,10): error CS1003: Syntax error, '(' expected + // } + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(19, 10), + // file.cs(19,10): error CS1525: Invalid expression term 'else' + // } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(19, 10), + // file.cs(19,10): error CS1026: ) expected + // } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(19, 10), + // file.cs(19,10): error CS1525: Invalid expression term 'else' + // } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(19, 10), + // file.cs(19,10): error CS1002: ; expected + // } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(19, 10) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [CompilerTrait(CompilerFeature.IOperation)] + [Fact, WorkItem(27866, "https://github.com/dotnet/roslyn/issues/27866")] + public void IIfstatementWithElseKeywordPlacedAsIfEmbeddedStatement() + { + string source = @" +using System; + +class P +{ + private void Op() + { + } + + private void M(bool flag) + { + /**/if (flag) + else + { + Op(); + } +/**/ } +} +"; + string expectedOperationTree = @" +IConditionalOperation (OperationKind.Conditional, Type: null, IsInvalid) (Syntax: 'if (flag) ... }') + Condition: + IParameterReferenceOperation: flag (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'flag') + WhenTrue: + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') + Expression: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenFalse: + IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Op();') + Expression: + IInvocationOperation ( void P.Op()) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Op()') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: P, IsImplicit) (Syntax: 'Op') + Arguments(0) +"; + var expectedDiagnostics = new DiagnosticDescription[] { + // file.cs(12,28): error CS1525: Invalid expression term 'else' + // /**/if (flag) + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(12, 28), + // file.cs(12,28): error CS1002: ; expected + // /**/if (flag) + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(12, 28) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + [CompilerTrait(CompilerFeature.IOperation)] [Fact, WorkItem(17601, "https://github.com/dotnet/roslyn/issues/17601")] public void IIfstatementWithElseMissing() diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs index 84e07dc89f181..e47050fc67602 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs @@ -2053,6 +2053,40 @@ public void TestIfElse() Assert.NotNull(ss.Else.Statement); } + [Fact] + public void TestIfElseIf() + { + var text = "if (a) { } else if (b) { }"; + var statement = this.ParseStatement(text); + + Assert.NotNull(statement); + Assert.Equal(SyntaxKind.IfStatement, statement.Kind()); + Assert.Equal(text, statement.ToString()); + Assert.Equal(0, statement.Errors().Length); + + var ss = (IfStatementSyntax)statement; + Assert.NotNull(ss.IfKeyword); + Assert.Equal(SyntaxKind.IfKeyword, ss.IfKeyword.Kind()); + Assert.NotNull(ss.OpenParenToken); + Assert.NotNull(ss.Condition); + Assert.Equal("a", ss.Condition.ToString()); + Assert.NotNull(ss.CloseParenToken); + Assert.NotNull(ss.Statement); + + Assert.NotNull(ss.Else); + Assert.NotNull(ss.Else.ElseKeyword); + Assert.Equal(SyntaxKind.ElseKeyword, ss.Else.ElseKeyword.Kind()); + Assert.NotNull(ss.Else.Statement); + + var subIf = (IfStatementSyntax) ss.Else.Statement; + Assert.NotNull(subIf.IfKeyword); + Assert.Equal(SyntaxKind.IfKeyword, subIf.IfKeyword.Kind()); + Assert.NotNull(subIf.Condition); + Assert.Equal("b", subIf.Condition.ToString()); + Assert.NotNull(subIf.CloseParenToken); + Assert.NotNull(subIf.Statement); + } + [Fact] public void TestLock() { @@ -2740,6 +2774,185 @@ public void NullExceptionInLabeledStatement() ); } + [WorkItem(27866, "https://github.com/dotnet/roslyn/issues/27866")] + [Fact] + public void ParseElseWithoutPrecedingIfStatement() + { + UsingStatement("else {}", + // (1,1): error CS1003: Syntax error, 'if' expected + // else {} + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("if", "else").WithLocation(1, 1), + // (1,1): error CS1003: Syntax error, '(' expected + // else {} + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(", "else").WithLocation(1, 1), + // (1,1): error CS1525: Invalid expression term 'else' + // else {} + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 1), + // (1,1): error CS1026: ) expected + // else {} + Diagnostic(ErrorCode.ERR_CloseParenExpected, "else").WithLocation(1, 1), + // (1,1): error CS1525: Invalid expression term 'else' + // else {} + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 1), + // (1,1): error CS1002: ; expected + // else {} + Diagnostic(ErrorCode.ERR_SemicolonExpected, "else").WithLocation(1, 1) + ); + N(SyntaxKind.IfStatement); + { + M(SyntaxKind.IfKeyword); + M(SyntaxKind.OpenParenToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CloseParenToken); + M(SyntaxKind.ExpressionStatement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ElseClause); + { + N(SyntaxKind.ElseKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + EOF(); + } + + [WorkItem(27866, "https://github.com/dotnet/roslyn/issues/27866")] + [Fact] + public void ParseSubsequentElseWithoutPrecedingIfStatement() + { + UsingStatement("{ if (a) { } else { } else { } }", + // (1,23): error CS1003: Syntax error, 'if' expected + // { if (a) { } else { } else { } } + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("if", "else").WithLocation(1, 23), + // (1,23): error CS1003: Syntax error, '(' expected + // { if (a) { } else { } else { } } + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(", "else").WithLocation(1, 23), + // (1,23): error CS1525: Invalid expression term 'else' + // { if (a) { } else { } else { } } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 23), + // (1,23): error CS1026: ) expected + // { if (a) { } else { } else { } } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "else").WithLocation(1, 23), + // (1,23): error CS1525: Invalid expression term 'else' + // { if (a) { } else { } else { } } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 23), + // (1,23): error CS1002: ; expected + // { if (a) { } else { } else { } } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "else").WithLocation(1, 23) + ); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IfStatement); + { + N(SyntaxKind.IfKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "a"); + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ElseClause); + { + N(SyntaxKind.ElseKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.IfStatement); + { + M(SyntaxKind.IfKeyword); + M(SyntaxKind.OpenParenToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CloseParenToken); + M(SyntaxKind.ExpressionStatement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ElseClause); + { + N(SyntaxKind.ElseKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [WorkItem(27866, "https://github.com/dotnet/roslyn/issues/27866")] + [Fact] + public void ParseElseKeywordPlacedAsIfEmbeddedStatement() + { + UsingStatement("if (a) else {}", + // (1,8): error CS1525: Invalid expression term 'else' + // if (a) else {} + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 8), + // (1,8): error CS1002: ; expected + // if (a) else {} + Diagnostic(ErrorCode.ERR_SemicolonExpected, "else").WithLocation(1, 8) + ); + N(SyntaxKind.IfStatement); + { + N(SyntaxKind.IfKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "a"); + } + N(SyntaxKind.CloseParenToken); + M(SyntaxKind.ExpressionStatement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ElseClause); + { + N(SyntaxKind.ElseKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + EOF(); + } + private sealed class TokenAndTriviaWalker : CSharpSyntaxWalker { public int Tokens; From 549a2bbf4122e2355d9857134f10d3b8a2068b7f Mon Sep 17 00:00:00 2001 From: Marcin Wachulski Date: Fri, 29 Jun 2018 12:17:33 +0200 Subject: [PATCH 02/45] Add ParseElseAndElseWithoutPrecedingIfStatement unit test. Also for IOperationTests: IIfstatementWithIfKeywordMissingAndDoubleElseKeywordsPresent --- .../IOperationTests_IIfStatement.cs | 81 ++++++++++++++ .../Syntax/Parsing/StatementParsingTests.cs | 104 ++++++++++++++++++ 2 files changed, 185 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs index c5cbdf006e197..f9a7a5ed397d2 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs @@ -1077,6 +1077,87 @@ private void M(bool flag) VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] + [Fact, WorkItem(27866, "https://github.com/dotnet/roslyn/issues/27866")] + public void IIfstatementWithIfKeywordMissingAndDoubleElseKeywordsPresent() + { + string source = @" +using System; + +class P +{ + private void Op() + { + } + + private void M() + { + /**/else + { + } + else + { + Op(); + } +/**/ } +} +"; + string expectedOperationTree = @" +IConditionalOperation (OperationKind.Conditional, Type: null, IsInvalid) (Syntax: '/**/e ... }') + Condition: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenTrue: + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') + Expression: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenFalse: + IBlockOperation (0 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') +"; + var expectedDiagnostics = new DiagnosticDescription[] { + + // file.cs(11,6): error CS1003: Syntax error, 'if' expected + // { + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(11, 6), + // file.cs(11,6): error CS1003: Syntax error, '(' expected + // { + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(11, 6), + // file.cs(11,6): error CS1525: Invalid expression term 'else' + // { + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(11, 6), + // file.cs(11,6): error CS1026: ) expected + // { + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(11, 6), + // file.cs(11,6): error CS1525: Invalid expression term 'else' + // { + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(11, 6), + // file.cs(11,6): error CS1002: ; expected + // { + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(11, 6), + // file.cs(14,10): error CS1003: Syntax error, 'if' expected + // } + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(14, 10), + // file.cs(14,10): error CS1003: Syntax error, '(' expected + // } + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(14, 10), + // file.cs(14,10): error CS1525: Invalid expression term 'else' + // } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(14, 10), + // file.cs(14,10): error CS1026: ) expected + // } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(14, 10), + // file.cs(14,10): error CS1525: Invalid expression term 'else' + // } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(14, 10), + // file.cs(14,10): error CS1002: ; expected + // } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(14, 10) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + [CompilerTrait(CompilerFeature.IOperation)] [Fact, WorkItem(17601, "https://github.com/dotnet/roslyn/issues/17601")] public void IIfstatementWithElseMissing() diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs index e47050fc67602..7f89c30db4e2d 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs @@ -2828,6 +2828,110 @@ public void ParseElseWithoutPrecedingIfStatement() EOF(); } + [WorkItem(27866, "https://github.com/dotnet/roslyn/issues/27866")] + [Fact] + public void ParseElseAndElseWithoutPrecedingIfStatement() + { + UsingStatement("{ else {} else {} }", + // (1,3): error CS1003: Syntax error, 'if' expected + // { else {} else {} } + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("if", "else").WithLocation(1, 3), + // (1,3): error CS1003: Syntax error, '(' expected + // { else {} else {} } + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(", "else").WithLocation(1, 3), + // (1,3): error CS1525: Invalid expression term 'else' + // { else {} else {} } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 3), + // (1,3): error CS1026: ) expected + // { else {} else {} } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "else").WithLocation(1, 3), + // (1,3): error CS1525: Invalid expression term 'else' + // { else {} else {} } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 3), + // (1,3): error CS1002: ; expected + // { else {} else {} } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "else").WithLocation(1, 3), + // (1,11): error CS1003: Syntax error, 'if' expected + // { else {} else {} } + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("if", "else").WithLocation(1, 11), + // (1,11): error CS1003: Syntax error, '(' expected + // { else {} else {} } + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(", "else").WithLocation(1, 11), + // (1,11): error CS1525: Invalid expression term 'else' + // { else {} else {} } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 11), + // (1,11): error CS1026: ) expected + // { else {} else {} } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "else").WithLocation(1, 11), + // (1,11): error CS1525: Invalid expression term 'else' + // { else {} else {} } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 11), + // (1,11): error CS1002: ; expected + // { else {} else {} } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "else").WithLocation(1, 11) + ); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IfStatement); + { + M(SyntaxKind.IfKeyword); + M(SyntaxKind.OpenParenToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CloseParenToken); + M(SyntaxKind.ExpressionStatement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ElseClause); + { + N(SyntaxKind.ElseKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.IfStatement); + { + M(SyntaxKind.IfKeyword); + M(SyntaxKind.OpenParenToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CloseParenToken); + M(SyntaxKind.ExpressionStatement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ElseClause); + { + N(SyntaxKind.ElseKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + [WorkItem(27866, "https://github.com/dotnet/roslyn/issues/27866")] [Fact] public void ParseSubsequentElseWithoutPrecedingIfStatement() From 1e7c18f6d92b5ca415aaff9224d118816c1bbf40 Mon Sep 17 00:00:00 2001 From: Marcin Wachulski Date: Thu, 19 Jul 2018 15:24:37 +0200 Subject: [PATCH 03/45] Fix unit test operation tree omissions - bind block Bind block operation instead of a sequence of two IF operations as the second IF is not included in operation tree construction. --- .../IOperationTests_IIfStatement.cs | 267 ++++++++++-------- 1 file changed, 156 insertions(+), 111 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs index f9a7a5ed397d2..67b4b0d0e7ce8 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IIfStatement.cs @@ -960,68 +960,94 @@ private void Op() private void M(bool flag) { - /**/if (flag) - { - Op(); - } - else - { - Console.WriteLine(flag); - } - else - { - Console.WriteLine(!flag); - } -/**/ } + /**/{ + if (flag) + { + Op(); + } + else + { + Console.WriteLine(flag); + } + else + { + Console.WriteLine(!flag); + } + }/**/ + } } "; string expectedOperationTree = @" -IConditionalOperation (OperationKind.Conditional, Type: null, IsInvalid) (Syntax: 'if (flag) ... }') - Condition: - IParameterReferenceOperation: flag (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'flag') - WhenTrue: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Op();') - Expression: - IInvocationOperation ( void P.Op()) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Op()') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: P, IsImplicit) (Syntax: 'Op') - Arguments(0) - WhenFalse: - IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.WriteLine(flag);') +IBlockOperation (2 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') + IConditionalOperation (OperationKind.Conditional, Type: null, IsInvalid) (Syntax: 'if (flag) ... }') + Condition: + IParameterReferenceOperation: flag (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'flag') + WhenTrue: + IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Op();') + Expression: + IInvocationOperation ( void P.Op()) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Op()') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: P, IsImplicit) (Syntax: 'Op') + Arguments(0) + WhenFalse: + IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.WriteLine(flag);') + Expression: + IInvocationOperation (void System.Console.WriteLine(System.Boolean value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.WriteLine(flag)') + Instance Receiver: + null + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'flag') + IParameterReferenceOperation: flag (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'flag') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IConditionalOperation (OperationKind.Conditional, Type: null) (Syntax: 'else ... }') + Condition: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenTrue: + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') Expression: - IInvocationOperation (void System.Console.WriteLine(System.Boolean value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.WriteLine(flag)') - Instance Receiver: - null - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'flag') - IParameterReferenceOperation: flag (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'flag') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenFalse: + IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Wri ... ine(!flag);') + Expression: + IInvocationOperation (void System.Console.WriteLine(System.Boolean value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.WriteLine(!flag)') + Instance Receiver: + null + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '!flag') + IUnaryOperation (UnaryOperatorKind.Not) (OperationKind.UnaryOperator, Type: System.Boolean) (Syntax: '!flag') + Operand: + IParameterReferenceOperation: flag (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'flag') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) "; var expectedDiagnostics = new DiagnosticDescription[] { - // file.cs(19,10): error CS1003: Syntax error, 'if' expected - // } - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(19, 10), - // file.cs(19,10): error CS1003: Syntax error, '(' expected - // } - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(19, 10), - // file.cs(19,10): error CS1525: Invalid expression term 'else' - // } - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(19, 10), - // file.cs(19,10): error CS1026: ) expected - // } - Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(19, 10), - // file.cs(19,10): error CS1525: Invalid expression term 'else' - // } - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(19, 10), - // file.cs(19,10): error CS1002: ; expected - // } - Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(19, 10) + // file.cs(20,14): error CS1003: Syntax error, 'if' expected + // } + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(20, 14), + // file.cs(20,14): error CS1003: Syntax error, '(' expected + // } + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(20, 14), + // file.cs(20,14): error CS1525: Invalid expression term 'else' + // } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(20, 14), + // file.cs(20,14): error CS1026: ) expected + // } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(20, 14), + // file.cs(20,14): error CS1525: Invalid expression term 'else' + // } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(20, 14), + // file.cs(20,14): error CS1002: ; expected + // } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(20, 14) }; - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] @@ -1092,70 +1118,89 @@ private void Op() private void M() { - /**/else - { - } - else - { - Op(); - } -/**/ } + /**/{ + else + { + } + else + { + Op(); + } + }/**/ + } } "; string expectedOperationTree = @" -IConditionalOperation (OperationKind.Conditional, Type: null, IsInvalid) (Syntax: '/**/e ... }') - Condition: - IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') - Children(0) - WhenTrue: - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') - Expression: - IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') - Children(0) - WhenFalse: - IBlockOperation (0 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') +IBlockOperation (2 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') + IConditionalOperation (OperationKind.Conditional, Type: null, IsInvalid) (Syntax: 'else ... }') + Condition: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenTrue: + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') + Expression: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenFalse: + IBlockOperation (0 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') + IConditionalOperation (OperationKind.Conditional, Type: null) (Syntax: 'else ... }') + Condition: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenTrue: + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') + Expression: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenFalse: + IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Op();') + Expression: + IInvocationOperation ( void P.Op()) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Op()') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: P, IsImplicit) (Syntax: 'Op') + Arguments(0) "; var expectedDiagnostics = new DiagnosticDescription[] { - - // file.cs(11,6): error CS1003: Syntax error, 'if' expected - // { - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(11, 6), - // file.cs(11,6): error CS1003: Syntax error, '(' expected - // { - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(11, 6), - // file.cs(11,6): error CS1525: Invalid expression term 'else' - // { - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(11, 6), - // file.cs(11,6): error CS1026: ) expected - // { - Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(11, 6), - // file.cs(11,6): error CS1525: Invalid expression term 'else' - // { - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(11, 6), - // file.cs(11,6): error CS1002: ; expected - // { - Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(11, 6), - // file.cs(14,10): error CS1003: Syntax error, 'if' expected - // } - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(14, 10), - // file.cs(14,10): error CS1003: Syntax error, '(' expected - // } - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(14, 10), - // file.cs(14,10): error CS1525: Invalid expression term 'else' - // } - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(14, 10), - // file.cs(14,10): error CS1026: ) expected - // } - Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(14, 10), - // file.cs(14,10): error CS1525: Invalid expression term 'else' - // } - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(14, 10), - // file.cs(14,10): error CS1002: ; expected - // } - Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(14, 10) + // file.cs(12,20): error CS1003: Syntax error, 'if' expected + // /**/{ + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(12, 20), + // file.cs(12,20): error CS1003: Syntax error, '(' expected + // /**/{ + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(12, 20), + // file.cs(12,20): error CS1525: Invalid expression term 'else' + // /**/{ + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(12, 20), + // file.cs(12,20): error CS1026: ) expected + // /**/{ + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(12, 20), + // file.cs(12,20): error CS1525: Invalid expression term 'else' + // /**/{ + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(12, 20), + // file.cs(12,20): error CS1002: ; expected + // /**/{ + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(12, 20), + // file.cs(15,14): error CS1003: Syntax error, 'if' expected + // } + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(15, 14), + // file.cs(15,14): error CS1003: Syntax error, '(' expected + // } + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(15, 14), + // file.cs(15,14): error CS1525: Invalid expression term 'else' + // } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(15, 14), + // file.cs(15,14): error CS1026: ) expected + // } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(15, 14), + // file.cs(15,14): error CS1525: Invalid expression term 'else' + // } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(15, 14), + // file.cs(15,14): error CS1002: ; expected + // } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(15, 14) }; - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] From 7117081586e16e890455341b272b557c975b0b97 Mon Sep 17 00:00:00 2001 From: Marcin Wachulski Date: Wed, 31 Oct 2018 21:23:25 +0100 Subject: [PATCH 04/45] Add a comment for ElseKeyword case and replace comments with a local var. --- src/Compilers/CSharp/Portable/Parser/LanguageParser.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 897d09093f8ab..bb3774b049a83 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -6678,7 +6678,7 @@ private StatementSyntax ParseStatementNoDeclaration(bool allowAnyExpression) case SyntaxKind.GotoKeyword: return this.ParseGotoStatement(); case SyntaxKind.IfKeyword: - case SyntaxKind.ElseKeyword: + case SyntaxKind.ElseKeyword: // Including 'else' keyword to handle 'else without if' error cases return this.ParseIfStatement(); case SyntaxKind.LockKeyword: return this.ParseLockStatement(); @@ -7937,13 +7937,12 @@ private IfStatementSyntax ParseIfStatement() { Debug.Assert(this.CurrentToken.Kind == SyntaxKind.IfKeyword || this.CurrentToken.Kind == SyntaxKind.ElseKeyword); + bool firstTokenIsElse = this.CurrentToken.Kind == SyntaxKind.ElseKeyword; var @if = this.EatToken(SyntaxKind.IfKeyword); var openParen = this.EatToken(SyntaxKind.OpenParenToken); var condition = this.ParseExpressionCore(); var closeParen = this.EatToken(SyntaxKind.CloseParenToken); - // when 'if' is missing, then we parse an expression statement in a standard way (which adds missing syntax properly) - // parsing embedded one expects non-null statement to be present - var statement = this.CurrentToken.Kind == SyntaxKind.ElseKeyword ? this.ParseExpressionStatement() : this.ParseEmbeddedStatement(); + var statement = firstTokenIsElse ? this.ParseExpressionStatement() : this.ParseEmbeddedStatement(); var elseClause = this.ParseElseClauseOpt(); return _syntaxFactory.IfStatement(@if, openParen, condition, closeParen, statement, elseClause); From ed8a00de45d50e39adfcb9a3b16665ad8cf5f9d7 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Mon, 5 Nov 2018 15:14:00 -0800 Subject: [PATCH 05/45] Disallow ref structs in expression trees (#30871) * Expression tree reflike checks WIP * Move test from emit to semantics * Fix ExpressionTreeRefLikeWalker * Fix label indent * Add more tests * Move ExpressionTreeRefLikeWalker logic to DiagnosticsPass * Resolve TODOs in IsExpressionTree * Ignore BoundConversion when checking for ref structs in expression trees * Comment on the purpose of `!(node is BoundConversion)` * Add ErrorCode.ERR_ExpressionTreeCantContainRefStruct * Use new error code in DiagnosticsPass * Update tests * Add TypedReference tests * Replace IsByRefLikeType check with IsRestrictedType() check * Simplify VisitLambda * Add new diagnostics to ArglistTests.ExpressionTreeTest --- .../Portable/CSharpResources.Designer.cs | 9 + .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/Errors/ErrorCode.cs | 1 + .../DiagnosticsPass_ExpressionTrees.cs | 39 ++-- .../Portable/Symbols/TypeSymbolExtensions.cs | 5 +- .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../Test/Semantic/Semantics/ArglistTests.cs | 17 +- .../Test/Semantic/Semantics/LambdaTests.cs | 202 ++++++++++++++++++ 20 files changed, 321 insertions(+), 20 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 8bbea1e9fa336..454b87eeb4a61 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -4426,6 +4426,15 @@ internal static string ERR_ExpressionOrDeclarationExpected { } } + /// + /// Looks up a localized string similar to Expression tree cannot contain value of ref struct or restricted type '{0}'.. + /// + internal static string ERR_ExpressionTreeCantContainRefStruct { + get { + return ResourceManager.GetString("ERR_ExpressionTreeCantContainRefStruct", resourceCulture); + } + } + /// /// Looks up a localized string similar to An expression tree may not contain an anonymous method expression. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 226c7ce46201d..138e3b4b6daa9 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5628,4 +5628,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Expected enable or disable + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 274f681d72dc3..d07211415b16d 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1633,6 +1633,7 @@ internal enum ErrorCode ERR_NullableDirectiveQualifierExpected = 8637, WRN_CantInferNullabilityOfMethodTypeArgs = 8638, WRN_NoBestNullabilityArrayElements = 8639, + ERR_ExpressionTreeCantContainRefStruct = 8640 #endregion diagnostics introduced for C# 8.0 diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs index d6d75a26b50a4..5318f2561c7c3 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs @@ -211,6 +211,20 @@ private void VisitCall( } } + public override BoundNode Visit(BoundNode node) + { + if (_inExpressionLambda && + // Ignoring BoundConversion nodes prevents redundant diagnostics + !(node is BoundConversion) && + node is BoundExpression expr && + expr.Type is TypeSymbol type && + type.IsRestrictedType()) + { + Error(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, node, type.Name); + } + return base.Visit(node); + } + public override BoundNode VisitRefTypeOperator(BoundRefTypeOperator node) { if (_inExpressionLambda) @@ -342,6 +356,19 @@ public override BoundNode VisitLambda(BoundLambda node) { if (_inExpressionLambda) { + var lambda = node.Symbol; + foreach (var p in lambda.Parameters) + { + if (p.RefKind != RefKind.None && p.Locations.Length != 0) + { + _diagnostics.Add(ErrorCode.ERR_ByRefParameterInExpressionTree, p.Locations[0]); + } + if (p.Type.IsRestrictedType()) + { + _diagnostics.Add(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, p.Locations[0], p.Type.Name); + } + } + switch (node.Syntax.Kind()) { case SyntaxKind.ParenthesizedLambdaExpression: @@ -359,18 +386,6 @@ public override BoundNode VisitLambda(BoundLambda node) { Error(ErrorCode.ERR_BadRefReturnExpressionTree, node); } - - var lambda = node.ExpressionSymbol as MethodSymbol; - if ((object)lambda != null) - { - foreach (var p in lambda.Parameters) - { - if (p.RefKind != RefKind.None && p.Locations.Length != 0) - { - _diagnostics.Add(ErrorCode.ERR_ByRefParameterInExpressionTree, p.Locations[0]); - } - } - } } break; diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index 58a3bbe0c0718..245f7c42b6261 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -331,10 +331,7 @@ public static NamedTypeSymbol GetDelegateType(this TypeSymbol type) /// public static bool IsExpressionTree(this TypeSymbol _type) { - // TODO: there must be a better way! - var type = _type.OriginalDefinition as NamedTypeSymbol; - return - (object)type != null && + return _type.OriginalDefinition is NamedTypeSymbol type && type.Arity == 1 && type.MangleName && type.Name == "Expression" && diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 5006fc4daf299..bcb68c314abf7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 9099769cb3456..0d3502db707f7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 6a9f6fa6af82a..abf07c7499e34 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index b39ce306aebfc..b67c1f9c5529d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index b8e466c065aa9..33920b5a68f79 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 0f1dad78ff915..aff69cae1fd04 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index d3bb10beadb4a..f4b1af1923e99 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 4e8f0cb57c7da..0b338d3bb355b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index f359298c23b5d..54cb03b570ee5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 1f9c5d8bb2367..2343a9d0f3298 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index f4ce33fd42507..250a11a338681 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index edf298d6ba8f7..3ab0e475ad0ea 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 51d33850990f6..e3c3bc2035917 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -62,6 +62,11 @@ The given expression cannot be used in a fixed statement + + Expression tree cannot contain value of ref struct or restricted type '{0}'. + Expression tree cannot contain value of ref struct or restricted type '{0}'. + + An expression tree may not contain a tuple == or != operator An expression tree may not contain a tuple == or != operator diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs index 3354edc3b8e68..1fe34b58adb69 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs @@ -130,18 +130,27 @@ static void Main() var comp = CreateCompilationWithMscorlib40AndSystemCore(text); comp.VerifyDiagnostics( +// (8,44): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'TypedReference'. +// Expression> ex1 = ()=>M(__makeref(S)); // CS7053 +Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "__makeref(S)").WithArguments("TypedReference").WithLocation(8, 44), // (8,44): error CS7053: An expression tree may not contain '__makeref' // Expression> ex1 = ()=>M(__makeref(S)); // CS7053 -Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "__makeref(S)").WithArguments("__makeref"), +Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "__makeref(S)").WithArguments("__makeref").WithLocation(8, 44), // (9,42): error CS7053: An expression tree may not contain '__reftype' // Expression> ex2 = ()=>__reftype(default(TypedReference)); -Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "__reftype(default(TypedReference))").WithArguments("__reftype"), +Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "__reftype(default(TypedReference))").WithArguments("__reftype").WithLocation(9, 42), +// (9,52): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'TypedReference'. +// Expression> ex2 = ()=>__reftype(default(TypedReference)); +Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "default(TypedReference)").WithArguments("TypedReference").WithLocation(9, 52), // (10,41): error CS7053: An expression tree may not contain '__refvalue' // Expression> ex3 = ()=>__refvalue(default(TypedReference), int); -Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "__refvalue(default(TypedReference), int)").WithArguments("__refvalue"), +Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "__refvalue(default(TypedReference), int)").WithArguments("__refvalue").WithLocation(10, 41), +// (10,52): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'TypedReference'. +// Expression> ex3 = ()=>__refvalue(default(TypedReference), int); +Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "default(TypedReference)").WithArguments("TypedReference").WithLocation(10, 52), // (11,44): error CS1952: An expression tree lambda may not contain a method with variable arguments // Expression> ex4 = ()=>N(__arglist()); -Diagnostic(ErrorCode.ERR_VarArgsInExpressionTree, "__arglist()") +Diagnostic(ErrorCode.ERR_VarArgsInExpressionTree, "__arglist()").WithLocation(11, 44) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 279565b0f6b04..e65ce1c3bbfd1 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -1533,6 +1533,208 @@ static void Main() Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "y = y").WithLocation(9, 45)); } + [Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")] + public void RefStructExpressionTree() + { + var text = @" +using System; +using System.Linq.Expressions; +public class Class1 +{ + public void Method1() + { + Method((Class1 c) => c.Method2(default(Struct1))); + } + + public void Method2(Struct1 s1) { } + + public static void Method(Expression> expression) { } +} + +public ref struct Struct1 { } +"; + var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( + // (8,40): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'Struct1'. + // Method((Class1 c) => c.Method2(default(Struct1))); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "default(Struct1)").WithArguments("Struct1").WithLocation(8, 40)); + } + + [Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")] + public void RefStructDefaultExpressionTree() + { + var text = @" +using System; +using System.Linq.Expressions; +public class Class1 +{ + public void Method1() + { + Method((Class1 c) => c.Method2(default)); + } + + public void Method2(Struct1 s1) { } + + public static void Method(Expression> expression) { } +} + +public ref struct Struct1 { } +"; + var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( + // (8,40): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'Struct1'. + // Method((Class1 c) => c.Method2(default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "default").WithArguments("Struct1").WithLocation(8, 40)); + } + + [Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")] + public void RefStructDefaultCastExpressionTree() + { + var text = @" +using System; +using System.Linq.Expressions; +public class Class1 +{ + public void Method1() + { + Method((Class1 c) => c.Method2((Struct1) default)); + } + + public void Method2(Struct1 s1) { } + + public static void Method(Expression> expression) { } +} + +public ref struct Struct1 { } +"; + var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( + // (8,50): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'Struct1'. + // Method((Class1 c) => c.Method2((Struct1) default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "default").WithArguments("Struct1").WithLocation(8, 50)); + } + + [Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")] + public void RefStructNewExpressionTree() + { + var text = @" +using System; +using System.Linq.Expressions; +public class Class1 +{ + public void Method1() + { + Method((Class1 c) => c.Method2(new Struct1())); + } + + public void Method2(Struct1 s1) { } + + public static void Method(Expression> expression) { } +} + +public ref struct Struct1 { } +"; + var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( + // (8,40): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'Struct1'. + // Method((Class1 c) => c.Method2(new Struct1())); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "new Struct1()").WithArguments("Struct1").WithLocation(8, 40)); + } + + [Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")] + public void RefStructParamExpressionTree() + { + var text = @" +using System.Linq.Expressions; + +public delegate void Delegate1(Struct1 s); +public class Class1 +{ + public void Method1() + { + Method((Struct1 s) => Method2()); + } + + public void Method2() { } + + public static void Method(Expression expression) { } +} + +public ref struct Struct1 { } +"; + var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( + // (9,25): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'Struct1'. + // Method((Struct1 s) => Method2()); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "s").WithArguments("Struct1").WithLocation(9, 25)); + } + + [Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")] + public void RefStructParamLambda() + { + var text = @" +public delegate void Delegate1(Struct1 s); +public class Class1 +{ + public void Method1() + { + Method((Struct1 s) => Method2()); + } + + public void Method2() { } + + public static void Method(Delegate1 expression) { } +} + +public ref struct Struct1 { } +"; + var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics(); + } + + [Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")] + public void TypedReferenceExpressionTree() + { + var text = @" +using System; +using System.Linq.Expressions; +public class Class1 +{ + public void Method1() + { + Method(() => Method2(default)); + } + + public void Method2(TypedReference tr) { } + + public static void Method(Expression expression) { } +} +"; + var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( + // (8,30): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'TypedReference'. + // Method(() => Method2(default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "default").WithArguments("TypedReference").WithLocation(8, 30)); + } + + [Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")] + public void TypedReferenceParamExpressionTree() + { + var text = @" +using System; +using System.Linq.Expressions; +public delegate void Delegate1(TypedReference tr); +public class Class1 +{ + public void Method1() + { + Method((TypedReference tr) => Method2()); + } + + public void Method2() { } + + public static void Method(Expression expression) { } +} +"; + var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( + // (9,32): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'TypedReference'. + // Method((TypedReference tr) => Method2()); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "tr").WithArguments("TypedReference").WithLocation(9, 32)); + } + [Fact, WorkItem(5363, "https://github.com/dotnet/roslyn/issues/5363")] public void ReturnInferenceCache_Dynamic_vs_Object_01() { From 862dcc7073d4cd252dd86f2f965ed8ace7ac2c7c Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Mon, 5 Nov 2018 16:46:51 -0800 Subject: [PATCH 06/45] Specify type inference rules for nullability annotations (#30670) Fixes #30433 --- docs/features/nullable-reference-types.md | 58 +++++++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/docs/features/nullable-reference-types.md b/docs/features/nullable-reference-types.md index d9ceb402e2584..aa9a438a78165 100644 --- a/docs/features/nullable-reference-types.md +++ b/docs/features/nullable-reference-types.md @@ -164,11 +164,61 @@ var z = (IEnumerable)x; // no warning ``` ### Method type inference -_Describe details_ -_Open issue: C# spec should include rule for lower, upper, and exact bounds: -If V is a nullable reference type V1? and U is a nullable reference type U1? -then an exact inference is made from U1 to V1._ +We modify the spec rule for [Fixing](https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#fixing "Fixing") to take account of types that may be equivalent (i.e. have an identity conversion) yet may not be identical in the set of bounds. The existing spec says (third bullet) + +> If among the remaining candidate types `Uj` there is a unique type `V` from which there is an implicit conversion to all the other candidate types, then `Xi` is fixed to `V`. + +This is not correct for C# 5 (i.e., it is a bug in the language specification), as it fails to handle bounds such as `Dictionary` and `Dictionary`, which are merged to `Dictionary`. This is [an open issue](https://github.com/ECMA-TC49-TG2/spec/issues/951) that we anticipate will be addressed in the next iteration of the ECMA specification. Handling nullability properly will require additional changes beyond those in that next iteration of the ECMA spec. + +When adding to the set of exact bounds of a type parameter, types that are equivalent (i.e. have an identity conversion) but not identical are merged using *invariant* rules. When adding to the set of lower bounds of a type parameter, types that are equivalent but not identical are merged using *covariant* rules. When adding to the set of upper bounds of a type parameter, types that are equivalent but not identical are merged using *contravariant* rules. In the final fixing step, types that are equivalent but not identical are merged using *covariant* rules. + +Merging equivalent but not identical types is done as follows: + +#### Invariant merging rules + +- Merging `dynamic` and `object` results in the type `dynamic`. +- Merging tuple types that differ in element names is specified elsewhere. +- Merging equivalent types that differ in nullability is performed as follows: merging the types `Tn` and `Um` (where `n` and `m` are differing nullability annotations) results in the type `Vk` where `V` is the result of merging `T` and `U` using the invariant rule, and `k` is as follows: + - if either `n` or `m` are non-nullable, non-nullable. In this case, if the other is nullable, a warning should be produced. + - if either `n` or `m` are nullable, nullable. + - otherwise oblivious. +- Merging constructed generic types is performed as follows: Merging the types `K` and `K` results in the type `K` where `Ci` is the result of merging `Ai` and `Bi` by the invariant rule. +- Merging the array types `T[]` and `U[]` results in the type `V[]` where `V` is the result of merging `T` and `U` by the invariant rule. + +#### Covariant merging rules + +- Merging `dynamic` and `object` results in the type `dynamic`. +- Merging tuple types that differ in element names is specified elsewhere. +- Merging equivalent types that differ in nullability is performed as follows: merging the types `Tn` and `Um` (where `n` and `m` are differing nullability annotations) results in the type `Vk` where `V` is the result of merging `T` and `U` using the covariant rule, and `k` is as follows: + - if either `n` or `m` are nullable, nullable. + - if either `n` or `m` are oblivious, oblivious. + - otherwise non-nullable. +- Merging constructed generic types is performed as follows: Merging the types `K` and `K` results in the type `K` where `Ci` is the result of merging `Ai` and `Bi` by + - the invariant rule if `K`'s type parameter in the `i` position is invariant. + - the covariant rule if `K`'s type parameter in the `i` position is declared `out`. + - the contravariant rule if the `K`'s type parameter in the `i` position is declared `in`. +- Merging the array types `T[]` and `U[]` results in the type `V[]` where `V` is the result of merging `T` and `U` by the invariant rule. + +#### Contravariant merging rules + +- Merging `dynamic` and `object` results in the type `dynamic`. +- Merging tuple types that differ in element names is specified elsewhere. +- Merging equivalent types that differ in nullability is performed as follows: merging the types `Tn` and `Um` (where `n` and `m` are differing nullability annotations) results in the type `Vk` where `V` is the result of merging `T` and `U` using the contravariant rule, and `k` is as follows: + - if either `n` or `m` are non-nullable, non-nullable. + - if either `n` or `m` are oblivious, oblivious. + - otherwise nullable. +- Merging constructed generic types is performed as follows: Merging the types `K` and `K` results in the type `K` where `Ci` is the result of merging `Ai` and `Bi` by + - the invariant rule if `K`'s type parameter in the `i` position is invariant. + - the covariant rule if `K`'s type parameter in the `i` position is declared `in`. + - the contravariant rule if `K`'s type parameter in the `i` position is declared `out`. +- Merging the array types `T[]` and `U[]` results in the type `V[]` where `V` is the result of merging `T` and `U` by the invariant rule. + +It is intended that these merging rules are associative and commutative, so that a compiler may merge a set of equivalent types pairwise in any order to compute the final result. + +> ***Open issue***: these rules do not describe the handling of merging a nested generic type `K.L` with `K.L`. That should be handled the same as a hypothetical type `KL` would be merged with `KL`. + +> ***Open issue***: these rules do not describe the handling of merging pointer types. ### Array creation The calculation of the _best type_ element nullability uses the Conversions rules above. From f406af89f57c77bc93b0802190654ee5dd3572f1 Mon Sep 17 00:00:00 2001 From: Marcin Wachulski Date: Tue, 6 Nov 2018 09:19:17 +0100 Subject: [PATCH 07/45] Fix failing tests for edge case 'if' parsing --- .../IOperationTests_IIfStatement.cs | 76 ++++++++++++++----- .../Syntax/Parsing/StatementParsingTests.cs | 40 +++++++--- 2 files changed, 88 insertions(+), 28 deletions(-) diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs index 67b4b0d0e7ce8..2201f0babc97e 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs @@ -1078,20 +1078,39 @@ private void M(bool flag) Condition: IParameterReferenceOperation: flag (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'flag') WhenTrue: - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') - Expression: + IConditionalOperation (OperationKind.Conditional, Type: null) (Syntax: 'else ... }') + Condition: IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') Children(0) + WhenTrue: + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') + Expression: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenFalse: + IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Op();') + Expression: + IInvocationOperation ( void P.Op()) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Op()') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: P, IsImplicit) (Syntax: 'Op') + Arguments(0) WhenFalse: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Op();') - Expression: - IInvocationOperation ( void P.Op()) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Op()') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: P, IsImplicit) (Syntax: 'Op') - Arguments(0) + null "; var expectedDiagnostics = new DiagnosticDescription[] { + // file.cs(12,28): error CS1003: Syntax error, 'if' expected + // /**/if (flag) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(12, 28), + // file.cs(12,28): error CS1003: Syntax error, '(' expected + // /**/if (flag) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(12, 28), + // file.cs(12,28): error CS1525: Invalid expression term 'else' + // /**/if (flag) + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(12, 28), + // file.cs(12,28): error CS1026: ) expected + // /**/if (flag) + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(12, 28), // file.cs(12,28): error CS1525: Invalid expression term 'else' // /**/if (flag) Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(12, 28), @@ -1349,27 +1368,46 @@ private void M() Right: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') WhenTrue: - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') - Expression: + IConditionalOperation (OperationKind.Conditional, Type: null, IsInvalid) (Syntax: ' else') + Condition: IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') Children(0) + WhenTrue: + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') + Expression: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) + WhenFalse: + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') + Expression: + IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') + Children(0) WhenFalse: - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') - Expression: - IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') - Children(0) + null "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS1525: Invalid expression term 'else' + // file.cs(10,30): error CS1003: Syntax error, 'if' expected + // /**/if (a == 1) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("if", "else").WithLocation(10, 30), + // file.cs(10,30): error CS1003: Syntax error, '(' expected + // /**/if (a == 1) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(10, 30), + // file.cs(10,30): error CS1525: Invalid expression term 'else' // /**/if (a == 1) Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(10, 30), - // CS1002: ; expected + // file.cs(10,30): error CS1026: ) expected + // /**/if (a == 1) + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(10, 30), + // file.cs(10,30): error CS1525: Invalid expression term 'else' + // /**/if (a == 1) + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(10, 30), + // file.cs(10,30): error CS1002: ; expected // /**/if (a == 1) Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(10, 30), - // CS1525: Invalid expression term '}' + // file.cs(11,13): error CS1525: Invalid expression term '}' // else Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("}").WithLocation(11, 13), - // CS1002: ; expected + // file.cs(11,13): error CS1002: ; expected // else Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(11, 13) }; diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs index 440386bdcf66a..b6202650c4a5d 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs @@ -3021,6 +3021,18 @@ public void ParseSubsequentElseWithoutPrecedingIfStatement() public void ParseElseKeywordPlacedAsIfEmbeddedStatement() { UsingStatement("if (a) else {}", + // (1,8): error CS1003: Syntax error, 'if' expected + // if (a) else {} + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("if", "else").WithLocation(1, 8), + // (1,8): error CS1003: Syntax error, '(' expected + // if (a) else {} + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(", "else").WithLocation(1, 8), + // (1,8): error CS1525: Invalid expression term 'else' + // if (a) else {} + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 8), + // (1,8): error CS1026: ) expected + // if (a) else {} + Diagnostic(ErrorCode.ERR_CloseParenExpected, "else").WithLocation(1, 8), // (1,8): error CS1525: Invalid expression term 'else' // if (a) else {} Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 8), @@ -3037,21 +3049,31 @@ public void ParseElseKeywordPlacedAsIfEmbeddedStatement() N(SyntaxKind.IdentifierToken, "a"); } N(SyntaxKind.CloseParenToken); - M(SyntaxKind.ExpressionStatement); + N(SyntaxKind.IfStatement); { + M(SyntaxKind.IfKeyword); + M(SyntaxKind.OpenParenToken); M(SyntaxKind.IdentifierName); { M(SyntaxKind.IdentifierToken); } - M(SyntaxKind.SemicolonToken); - } - N(SyntaxKind.ElseClause); - { - N(SyntaxKind.ElseKeyword); - N(SyntaxKind.Block); + M(SyntaxKind.CloseParenToken); + M(SyntaxKind.ExpressionStatement); { - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ElseClause); + { + N(SyntaxKind.ElseKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } } } } From 1abe9656700bc7b8021d13154545354b30b2dde2 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 6 Nov 2018 10:51:49 -0800 Subject: [PATCH 08/45] Add regression test for attribute with async delegate parameter (#30969) * Add regression test for attribute consuming async Task-returning delegate * Add corresponding VB test --- .../Test/Emit/Attributes/AttributeTests.cs | 38 +++++++++++++++++++ .../Test/Emit/Attributes/AttributeTests.vb | 34 +++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs index e7629daf79b19..f7699530d0b07 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs @@ -8913,6 +8913,44 @@ internal sealed class CSharpCompilerDiagnosticAnalyzer ); } + [Fact, WorkItem(30833, "https://github.com/dotnet/roslyn/issues/30833")] + public void AttributeWithTaskDelegateParameter() + { + string code = @" +using System; +using System.Threading.Tasks; + +namespace a +{ + class Class1 + { + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + class CommandAttribute : Attribute + { + public delegate Task FxCommand(); + + public CommandAttribute(FxCommand Fx) + { + this.Fx = Fx; + } + + public FxCommand Fx { get; set; } + } + + [Command(UserInfo)] + public static async Task UserInfo() + { + await Task.CompletedTask; + } + } +} +"; + CreateCompilationWithMscorlib46(code).VerifyDiagnostics( + // (22,4): error CS0181: Attribute constructor parameter 'Fx' has type 'Class1.CommandAttribute.FxCommand', which is not a valid attribute parameter type + // [Command(UserInfo)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "Command").WithArguments("Fx", "a.Class1.CommandAttribute.FxCommand").WithLocation(22, 4)); + } + #endregion } } diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb index 5f3d5960a3b1e..96e46612edfaa 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb @@ -4618,5 +4618,39 @@ End Class Assert.NotNull(compilation2.GetTypeByMetadataName("TestReference2")) End Sub + + Public Sub AttributeWithTaskDelegateParameter() + Dim code = " +Imports System +Imports System.Threading.Tasks + +Namespace a + Public Class Class1 + + Public Class CommandAttribute + Inherits Attribute + + Public Delegate Function FxCommand() As Task + + Public Sub New(Fx As FxCommand) + Me.Fx = Fx + End Sub + + Public Property Fx As FxCommand + End Class + + + Public Shared Async Function UserInfo() As Task + Await New Task( + Sub() + End Sub) + End Function + End Class +End Namespace +" + CreateCompilationWithMscorlib45(code).VerifyDiagnostics( + Diagnostic(ERRID.ERR_BadAttributeConstructor1, "Command").WithArguments("a.Class1.CommandAttribute.FxCommand").WithLocation(20, 10), + Diagnostic(ERRID.ERR_RequiredConstExpr, "AddressOf UserInfo").WithLocation(20, 18)) + End Sub End Class End Namespace From f47188696d128e2e300498f8c696422933f60abe Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 7 Nov 2018 08:58:15 -0600 Subject: [PATCH 09/45] Remove unused method SerializableBytes.CreateReadableStream --- .../Portable/Utilities/SerializableBytes.cs | 44 ------------------- .../UtilityTest/SerializableBytesTests.cs | 14 +++--- 2 files changed, 7 insertions(+), 51 deletions(-) diff --git a/src/Workspaces/Core/Portable/Utilities/SerializableBytes.cs b/src/Workspaces/Core/Portable/Utilities/SerializableBytes.cs index 68b5c2968b4dd..be4d43faa45ee 100644 --- a/src/Workspaces/Core/Portable/Utilities/SerializableBytes.cs +++ b/src/Workspaces/Core/Portable/Utilities/SerializableBytes.cs @@ -28,50 +28,6 @@ internal static PooledStream CreateReadableStream(byte[] bytes, int length) return stream; } - internal static PooledStream CreateReadableStream(Stream stream, CancellationToken cancellationToken) - { - long length = stream.Length; - - long chunkCount = (length + ChunkSize - 1) / ChunkSize; - byte[][] chunks = new byte[chunkCount][]; - - try - { - for (long i = 0, c = 0; i < length; i += ChunkSize, c++) - { - int count = (int)Math.Min(ChunkSize, length - i); - var chunk = SharedPools.ByteArray.Allocate(); - - int chunkOffset = 0; - while (count > 0) - { - cancellationToken.ThrowIfCancellationRequested(); - - int bytesRead = stream.Read(chunk, chunkOffset, count); - if (bytesRead > 0) - { - count = count - bytesRead; - chunkOffset += bytesRead; - } - else - { - break; - } - } - - chunks[c] = chunk; - } - - var result = new ReadStream(length, chunks); - chunks = null; - return result; - } - finally - { - BlowChunks(chunks); - } - } - internal async static Task CreateReadableStreamAsync(Stream stream, CancellationToken cancellationToken) { long length = stream.Length; diff --git a/src/Workspaces/CoreTest/UtilityTest/SerializableBytesTests.cs b/src/Workspaces/CoreTest/UtilityTest/SerializableBytesTests.cs index 69e245e243de4..5694b5127d640 100644 --- a/src/Workspaces/CoreTest/UtilityTest/SerializableBytesTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/SerializableBytesTests.cs @@ -3,7 +3,7 @@ using System; using System.IO; using System.Threading; -using Roslyn.Utilities; +using System.Threading.Tasks; using Xunit; namespace Microsoft.CodeAnalysis.UnitTests @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.UnitTests public class SerializableBytesTests { [Fact] - public void ReadableStreamTestReadAByteAtATime() + public async Task ReadableStreamTestReadAByteAtATime() { using (var expected = new MemoryStream()) { @@ -21,7 +21,7 @@ public void ReadableStreamTestReadAByteAtATime() } expected.Position = 0; - using (var stream = SerializableBytes.CreateReadableStream(expected, CancellationToken.None)) + using (var stream = await SerializableBytes.CreateReadableStreamAsync(expected, CancellationToken.None)) { Assert.Equal(expected.Length, stream.Length); @@ -36,7 +36,7 @@ public void ReadableStreamTestReadAByteAtATime() } [Fact] - public void ReadableStreamTestReadChunks() + public async Task ReadableStreamTestReadChunks() { using (var expected = new MemoryStream()) { @@ -46,7 +46,7 @@ public void ReadableStreamTestReadChunks() } expected.Position = 0; - using (var stream = SerializableBytes.CreateReadableStream(expected, CancellationToken.None)) + using (var stream = await SerializableBytes.CreateReadableStreamAsync(expected, CancellationToken.None)) { Assert.Equal(expected.Length, stream.Length); @@ -71,7 +71,7 @@ public void ReadableStreamTestReadChunks() } [Fact] - public void ReadableStreamTestReadRandomBytes() + public async Task ReadableStreamTestReadRandomBytes() { using (var expected = new MemoryStream()) { @@ -81,7 +81,7 @@ public void ReadableStreamTestReadRandomBytes() } expected.Position = 0; - using (var stream = SerializableBytes.CreateReadableStream(expected, CancellationToken.None)) + using (var stream = await SerializableBytes.CreateReadableStreamAsync(expected, CancellationToken.None)) { Assert.Equal(expected.Length, stream.Length); From f1dd31022000a98f687697f0cdfbcd484b60d945 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Wed, 7 Nov 2018 11:20:24 -0800 Subject: [PATCH 10/45] Set master prerelease version to beta3 --- build/Targets/Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Targets/Packages.props b/build/Targets/Packages.props index 502f31d1efae8..b4aaba0820c83 100644 --- a/build/Targets/Packages.props +++ b/build/Targets/Packages.props @@ -11,7 +11,7 @@ --> 2.11.0 - beta1 + beta3 true