From 666a27399d4e71858ead7d413c48acbcb9f55b20 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 27 Mar 2017 11:52:54 -0700 Subject: [PATCH 1/9] Fix error for missing feature --- src/Compilers/CSharp/Portable/CSharpResources.Designer.cs | 2 +- src/Compilers/CSharp/Portable/CSharpResources.resx | 2 +- src/Compilers/CSharp/Portable/Errors/MessageID.cs | 6 ++++-- .../Test/Semantic/Semantics/TargetTypedDefaultTests.cs | 4 ++-- src/Compilers/Test/Utilities/CSharp/TestOptions.cs | 4 ++-- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index ab6cfba10662f..f6bf1b046d4d2 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -9945,7 +9945,7 @@ internal static string IDS_FeatureDefault { } /// - /// Looks up a localized string similar to target-typed default operator. + /// Looks up a localized string similar to default literal. /// internal static string IDS_FeatureDefaultLiteral { get { diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index ef16bdfdec0ab..25d004af1dabc 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -208,7 +208,7 @@ default operator - target-typed default operator + default literal nullable types diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 5b5336cd68617..fa798c7c8cb2c 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -173,8 +173,6 @@ internal static string RequiredFeature(this MessageID feature) { case MessageID.IDS_FeatureIOperation: return "IOperation"; - case MessageID.IDS_FeatureDefaultLiteral: - return "defaultLiteral"; default: return null; } @@ -186,6 +184,10 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) // Checks are in the LanguageParser unless otherwise noted. switch (feature) { + // C# 7.1 features. + case MessageID.IDS_FeatureDefaultLiteral: + return LanguageVersion.CSharp7_1; + // C# 7 features. case MessageID.IDS_FeatureBinaryLiteral: case MessageID.IDS_FeatureDigitSeparator: diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs index d3e4e01b12bd5..9f679235c539a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs @@ -25,9 +25,9 @@ static void Main() "; var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( - // (6,17): error CS8058: Feature 'target-typed default operator' is experimental and unsupported; use '/features:defaultLiteral' to enable. + // (6,17): error CS8107: Feature 'default literal' is not available in C# 7. Please use language version 7.1 or greater. // int x = default; - Diagnostic(ErrorCode.ERR_FeatureIsExperimental, "default").WithArguments("target-typed default operator", "defaultLiteral").WithLocation(6, 17) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "default").WithArguments("default literal", "7.1").WithLocation(6, 17) ); } diff --git a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs index 8f44de3260e42..f721a83ca2c82 100644 --- a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs +++ b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs @@ -16,9 +16,9 @@ public static class TestOptions public static readonly CSharpParseOptions Regular6 = Regular.WithLanguageVersion(LanguageVersion.CSharp6); public static readonly CSharpParseOptions RegularWithDocumentationComments = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Diagnose); - private static readonly SmallDictionary s_experimentalFeatures = new SmallDictionary { { "defaultLiteral", "true" } }; + private static readonly SmallDictionary s_experimentalFeatures = new SmallDictionary { }; public static readonly CSharpParseOptions ExperimentalParseOptions = - new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None, languageVersion: LanguageVersion.CSharp7).WithFeatures(s_experimentalFeatures); + new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None, languageVersion: LanguageVersion.CSharp7_1).WithFeatures(s_experimentalFeatures); // Enable pattern-switch translation even for switches that use no new syntax. This is used // to help ensure compatibility of the semantics of the new switch binder with the old switch From fe08789b88d3fad878b5c97aefa6e5ede17e2d5d Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 27 Mar 2017 13:05:46 -0700 Subject: [PATCH 2/9] Disallow default literal in expression tree --- .../BoundTree/BoundExpressionExtensions.cs | 2 +- .../Portable/CSharpResources.Designer.cs | 9 ++++ .../CSharp/Portable/CSharpResources.resx | 3 ++ .../CSharp/Portable/Errors/ErrorCode.cs | 1 + .../DiagnosticsPass_ExpressionTrees.cs | 9 ++++ .../Emit/CodeGen/CodeGenExprLambdaTests.cs | 43 ------------------- .../Semantics/TargetTypedDefaultTests.cs | 32 +++++++++++++- 7 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs index 506c18f927825..7ba9d166ef664 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs @@ -16,7 +16,7 @@ public static bool IsLiteralNull(this BoundExpression node) public static bool IsLiteralDefault(this BoundExpression node) { - return node.Kind == BoundKind.DefaultLiteral && (object)node.Type == null; + return node.Kind == BoundKind.DefaultLiteral && node.Syntax.Kind() == SyntaxKind.DefaultLiteralExpression; } // returns true when expression has no side-effects and produces diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index f6bf1b046d4d2..650b8afcb9664 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -4192,6 +4192,15 @@ internal static string ERR_ExpressionTreeContainsBaseAccess { } } + /// + /// Looks up a localized string similar to An expression tree may not contain a default literal.. + /// + internal static string ERR_ExpressionTreeContainsDefaultLiteral { + get { + return ResourceManager.GetString("ERR_ExpressionTreeContainsDefaultLiteral", resourceCulture); + } + } + /// /// Looks up a localized string similar to An expression tree may not contain a discard.. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 25d004af1dabc..c7f27f1164b5e 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4969,6 +4969,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ An expression tree may not contain a tuple conversion. + + An expression tree may not contain a default literal. + /sourcelink switch is only supported when emitting Portable PDB (/debug:portable or /debug:embedded must be specified). diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 60605232dacb5..85d27778611a7 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1475,5 +1475,6 @@ internal enum ErrorCode ERR_BadDynamicMethodArgDefault = 9000, ERR_DefaultNotValid = 9001, + ERR_ExpressionTreeContainsDefaultLiteral = 9002, } } diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs index f59bb4bd9bac7..6a78fdc4bcb3e 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs @@ -700,5 +700,14 @@ public override BoundNode VisitThrowExpression(BoundThrowExpression node) return base.VisitThrowExpression(node); } + + public override BoundNode VisitDefaultLiteral(BoundDefaultLiteral node) + { + if (_inExpressionLambda && node.IsLiteralDefault()) + { + Error(ErrorCode.ERR_ExpressionTreeContainsDefaultLiteral, node); + } + return base.VisitDefaultLiteral(node); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs index a289fd1afa541..8808db84a476e 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs @@ -5012,49 +5012,6 @@ static void Main(string[] args) expectedOutput: expectedOutput); } - [Fact] - public void EnumEqualityWithDefault() - { - string source = -@" -using System; -using System.Linq.Expressions; - -namespace ConsoleApplication1 -{ - enum YesNo - { - Yes, - No - } - - class MyType - { - public string Name { get; set; } - public YesNo? YesNo { get; set; } - - public int? Age { get; set; } - } - - class Program - { - static void Main(string[] args) - { - - Expression> expr = (MyType x) => x.YesNo == (YesNo?)default; - Console.WriteLine(expr.Dump()); - } - } - -}"; - string expectedOutput = "Equal(Convert(MemberAccess(Parameter(x Type:ConsoleApplication1.MyType).YesNo Type:System.Nullable`1[ConsoleApplication1.YesNo]) Lifted LiftedToNull Type:System.Nullable`1[System.Int32]) Convert(Convert(Constant(null Type:System.Object) Lifted LiftedToNull Type:System.Nullable`1[ConsoleApplication1.YesNo]) Lifted LiftedToNull Type:System.Nullable`1[System.Int32]) Lifted Type:System.Boolean)"; - CompileAndVerify( - new[] { source, ExpressionTestLibrary }, - new[] { ExpressionAssemblyRef }, - expectedOutput: expectedOutput, - parseOptions: TestOptions.ExperimentalParseOptions); - } - [WorkItem(546618, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546618")] [Fact] public void TildeNullableEnum() diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs index 9f679235c539a..3ec9bd40be2b2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs @@ -838,7 +838,10 @@ class Program comp.VerifyDiagnostics( // (6,47): error CS0845: An expression tree lambda may not contain a coalescing operator with a null or default literal left-hand side // Expression> testExpr = () => default ?? "hello"; - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsBadCoalesce, "default").WithLocation(6, 47) + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsBadCoalesce, "default"), + // (6,47): error CS9002: An expression tree may not contain a default literal. + // Expression> testExpr = () => default ?? "hello"; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsDefaultLiteral, "default").WithLocation(6, 47) ); } @@ -1107,5 +1110,32 @@ static void Main() Diagnostic(ErrorCode.ERR_BadSKknown, "System").WithArguments("System", "namespace", "type").WithLocation(6, 17) ); } + + [Fact] + public void DefaultLiteralDisallowedInExpressionTree() + { + string source = +@" +using System; +using System.Linq.Expressions; + +class Program +{ + static void M() + { + Expression> expr1 = (int x) => x == (int)default; + Expression> expr2 = (int x) => x == default; + } +}"; + var comp = CreateCompilationWithMscorlib(new[] { source }, new[] { ExpressionAssemblyRef }, parseOptions: TestOptions.ExperimentalParseOptions); + comp.VerifyDiagnostics( + // (9,66): error CS9002: An expression tree may not contain a default literal. + // Expression> expr1 = (int x) => x == (int)default; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsDefaultLiteral, "default").WithLocation(9, 66), + // (10,61): error CS9002: An expression tree may not contain a default literal. + // Expression> expr2 = (int x) => x == default; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsDefaultLiteral, "default").WithLocation(10, 61) + ); + } } } From 178e5d5edf2b1e2f003af121ea4f6923fb8dedf3 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 27 Mar 2017 13:31:23 -0700 Subject: [PATCH 3/9] Use syntax akin of other literals --- .../Portable/Binder/Binder_Expressions.cs | 11 +++-------- .../CSharp/Portable/Parser/LanguageParser.cs | 2 +- .../CSharp/Portable/PublicAPI.Unshipped.txt | 13 +------------ src/Compilers/CSharp/Portable/Syntax/Syntax.xml | 17 ++--------------- .../CSharp/Portable/Syntax/SyntaxKind.cs | 2 +- .../Semantics/TargetTypedDefaultTests.cs | 16 +++++++++------- .../Syntax/Parsing/ExpressionParsingTests.cs | 3 +-- 7 files changed, 18 insertions(+), 46 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 15d6d483cdf5f..2b78c8590a7bf 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -540,6 +540,9 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, Diagnostic case SyntaxKind.NullLiteralExpression: return BindLiteralConstant((LiteralExpressionSyntax)node, diagnostics); + case SyntaxKind.DefaultLiteralExpression: + return new BoundDefaultLiteral(node, constantValueOpt: null, type: null); + case SyntaxKind.ParenthesizedExpression: // Parenthesis tokens are ignored, and operand is bound in the context of parent // expression. @@ -552,9 +555,6 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, Diagnostic case SyntaxKind.DefaultExpression: return BindDefaultExpression((DefaultExpressionSyntax)node, diagnostics); - case SyntaxKind.DefaultLiteral: - return BindDefaultLiteral((DefaultLiteralSyntax)node); - case SyntaxKind.TypeOfExpression: return BindTypeOf((TypeOfExpressionSyntax)node, diagnostics); @@ -773,11 +773,6 @@ private BoundExpression BindDeclarationVariables(TypeSymbol declType, VariableDe } } - private static BoundExpression BindDefaultLiteral(DefaultLiteralSyntax node) - { - return new BoundDefaultLiteral(node, constantValueOpt: null, type: null); - } - private BoundExpression BindTupleExpression(TupleExpressionSyntax node, DiagnosticBag diagnostics) { SeparatedSyntaxList arguments = node.Arguments; diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index a7e8a40dc1c15..39c75a16762ef 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -9781,7 +9781,7 @@ private ExpressionSyntax ParseDefaultExpression() else { keyword = CheckFeatureAvailability(keyword, MessageID.IDS_FeatureDefaultLiteral); - return _syntaxFactory.DefaultLiteral(keyword); + return _syntaxFactory.LiteralExpression(SyntaxKind.DefaultLiteralExpression, keyword); } } diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index a8e23808af2bd..f3ae7c0c0116d 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -47,10 +47,6 @@ Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax.Type.get -> Micros Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax.WithDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax.WithType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax.Keyword.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken keyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax.WithKeyword(Microsoft.CodeAnalysis.SyntaxToken keyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken tildeToken, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax.WithExpressionBody(Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax Microsoft.CodeAnalysis.CSharp.Syntax.DiscardDesignationSyntax @@ -168,7 +164,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.ConflictMarkerTrivia = 8564 -> Microsof Microsoft.CodeAnalysis.CSharp.SyntaxKind.ConstantPattern = 9002 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.DeclarationExpression = 9040 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.DeclarationPattern = 9000 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -Microsoft.CodeAnalysis.CSharp.SyntaxKind.DefaultLiteral = 9053 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.DefaultLiteralExpression = 8755 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.DiscardDesignation = 9014 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ForEachVariableStatement = 8929 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.IsPatternExpression = 8657 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -196,7 +192,6 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitCasePatternSwit override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitConstantPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ConstantPatternSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitDeclarationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationExpressionSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitDeclarationPattern(Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitDefaultLiteral(Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitDiscardDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.DiscardDesignationSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitForEachVariableStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ForEachVariableStatementSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitIsPatternExpression(Microsoft.CodeAnalysis.CSharp.Syntax.IsPatternExpressionSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode @@ -222,8 +217,6 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationExpressionSyntax.Accept override Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult override Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult -override Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void -override Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult override Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax override Microsoft.CodeAnalysis.CSharp.Syntax.DiscardDesignationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.DiscardDesignationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult @@ -289,8 +282,6 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConstructorDeclaration(Micros static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConstructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax initializer, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DeclarationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DeclarationPattern(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DefaultLiteral() -> Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DefaultLiteral(Microsoft.CodeAnalysis.SyntaxToken keyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DestructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DestructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DestructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken tildeToken, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax @@ -326,7 +317,6 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitCasePatternSwitch virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitConstantPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ConstantPatternSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitDeclarationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationExpressionSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitDeclarationPattern(Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax node) -> void -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitDefaultLiteral(Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitDiscardDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.DiscardDesignationSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitForEachVariableStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ForEachVariableStatementSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitIsPatternExpression(Microsoft.CodeAnalysis.CSharp.Syntax.IsPatternExpressionSyntax node) -> void @@ -344,7 +334,6 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitCasePatt virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitConstantPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ConstantPatternSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitDeclarationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationExpressionSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitDeclarationPattern(Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax node) -> TResult -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitDefaultLiteral(Microsoft.CodeAnalysis.CSharp.Syntax.DefaultLiteralSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitDiscardDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.DiscardDesignationSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitForEachVariableStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ForEachVariableStatementSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitIsPatternExpression(Microsoft.CodeAnalysis.CSharp.Syntax.IsPatternExpressionSyntax node) -> TResult diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index 75acadb828615..7c0a378deab94 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -726,6 +726,7 @@ + @@ -734,6 +735,7 @@ + SyntaxToken representing the keyword corresponding to the kind of the literal expression. @@ -918,21 +920,6 @@ Creates a DefaultExpressionSyntax node. - - - - - - SyntaxToken representing the DefaultKeyword. - - - - Class which represents the syntax node for a default literal. - - - Creates a DefaultLiteralSyntax node. - - diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index 0685843ca2ed6..34f006a9866a4 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -398,6 +398,7 @@ public enum SyntaxKind : ushort TrueLiteralExpression = 8752, FalseLiteralExpression = 8753, NullLiteralExpression = 8754, + DefaultLiteralExpression = 8755, // primary function expressions TypeOfExpression = 8760, @@ -562,6 +563,5 @@ public enum SyntaxKind : ushort RefExpression = 9050, RefType = 9051, ThrowExpression = 9052, - DefaultLiteral = 9053, } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs index 3ec9bd40be2b2..a73d919a6da05 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs @@ -52,7 +52,7 @@ static void Main() var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); - var def = nodes.OfType().Single(); + var def = nodes.OfType().Single(); Assert.Equal("System.Int32", model.GetTypeInfo(def).Type.ToTestDisplayString()); Assert.Equal("System.Int32", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); Assert.Null(model.GetSymbolInfo(def).Symbol); @@ -122,7 +122,7 @@ static void M() var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); - var def = nodes.OfType().Single(); + var def = nodes.OfType().Single(); Assert.Equal("S", model.GetTypeInfo(def).Type.ToTestDisplayString()); Assert.Equal("S", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); Assert.Null(model.GetSymbolInfo(def).Symbol); @@ -150,7 +150,7 @@ static void M() var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); - var def = nodes.OfType().Single(); + var def = nodes.OfType().Single(); Assert.Equal("T", model.GetTypeInfo(def).Type.ToTestDisplayString()); Assert.Equal("T", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); Assert.Null(model.GetSymbolInfo(def).Symbol); @@ -388,7 +388,8 @@ static void Main() var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); - var def = nodes.OfType().Single(); + var def = nodes.OfType().ElementAt(1); + Assert.Equal("default", def.ToString()); Assert.Equal("System.Int32", model.GetTypeInfo(def).Type.ToTestDisplayString()); Assert.Equal("System.Int32", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); Assert.Null(model.GetSymbolInfo(def).Symbol); @@ -491,7 +492,8 @@ static void Main() var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); - var def = nodes.OfType().Single(); + var def = nodes.OfType().ElementAt(1); + Assert.Equal("default", def.ToString()); Assert.Equal("System.Int32", model.GetTypeInfo(def).Type.ToTestDisplayString()); Assert.Null(model.GetSymbolInfo(def).Symbol); Assert.Null(model.GetDeclaredSymbol(def)); @@ -864,7 +866,7 @@ static void Main() var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); - var def = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single(); + var def = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single(); Assert.Equal("System.Int32?", model.GetTypeInfo(def).Type.ToTestDisplayString()); Assert.Equal("System.Int32?", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); Assert.Null(model.GetSymbolInfo(def).Symbol); @@ -1071,7 +1073,7 @@ static void Main() var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); - var def = nodes.OfType().Single(); + var def = nodes.OfType().Single(); Assert.Equal("System.Int16", model.GetTypeInfo(def).Type.ToTestDisplayString()); Assert.Null(model.GetSymbolInfo(def).Symbol); Assert.Null(model.GetDeclaredSymbol(def)); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs index 98e966ef3af5f..38aab9dc8e8b7 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs @@ -3540,8 +3540,7 @@ public void TestTargetTypedDefault() var expr = this.ParseExpression(text, TestOptions.ExperimentalParseOptions); Assert.NotNull(expr); - Assert.Equal(SyntaxKind.DefaultLiteral, expr.Kind()); - Assert.False(((DefaultLiteralSyntax)expr).Keyword.IsMissing); + Assert.Equal(SyntaxKind.DefaultLiteralExpression, expr.Kind()); Assert.Equal(text, expr.ToString()); Assert.Equal(0, expr.Errors().Length); } From 14a504c5de5664a654b962ffd1843660435cfc03 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 27 Mar 2017 15:05:07 -0700 Subject: [PATCH 4/9] Update behavior for as and is --- .../Portable/Binder/Binder_Operators.cs | 9 ++ .../Semantics/TargetTypedDefaultTests.cs | 96 +++++++++++++++++-- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs index 6f4fa586535a8..3fa1883777741 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs @@ -3063,6 +3063,15 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa return new BoundAsOperator(node, operand, typeExpression, Conversion.DefaultOrNullLiteral, resultType); } + if (operand.IsLiteralDefault()) + { + var defaultLiteral = (BoundDefaultLiteral)operand; + Debug.Assert((object)defaultLiteral.Type == null && (object)defaultLiteral.ConstantValueOpt == null); + + operand = new BoundDefaultLiteral(defaultLiteral.Syntax, constantValueOpt: ConstantValue.Null, + type: GetSpecialType(SpecialType.System_Object, diagnostics, node)); + } + if (operand.Kind == BoundKind.MethodGroup) { Error(diagnostics, ErrorCode.ERR_NoExplicitBuiltinConv, node, MessageID.IDS_MethodGroup.Localize(), targetType); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs index a73d919a6da05..3b07ac87f4a90 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs @@ -515,6 +515,27 @@ static int M() comp.VerifyDiagnostics(); } + [Fact] + public void DefaultInEnum() + { + string source = @" +enum E +{ + Entry = default +} +class C +{ + static void Main() + { + System.Console.Write((int)E.Entry); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "0"); + } + [Fact] public void YieldReturn() { @@ -753,40 +774,103 @@ public void DefaultInAsOperator() var text = @" class C { - static void Main() + static void M() { System.Console.Write(default as long); + System.Console.Write(default as T); } }"; - var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (6,30): error CS0077: The as operator must be used with a reference type or nullable type ('long' is a non-nullable value type) // System.Console.Write(default as long); - Diagnostic(ErrorCode.ERR_AsMustHaveReferenceType, "default as long").WithArguments("long").WithLocation(6, 30) + Diagnostic(ErrorCode.ERR_AsMustHaveReferenceType, "default as long").WithArguments("long").WithLocation(6, 30), + // (7,30): error CS0413: The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint + // System.Console.Write(default as T); + Diagnostic(ErrorCode.ERR_AsWithTypeVar, "default as T").WithArguments("T").WithLocation(7, 30) ); } [Fact] - public void DefaultInIsPattern() + public void DefaultInAsOperatorWithReferenceType() { var text = @" class C { static void Main() + { + System.Console.Write($""{default as C == null} {default as string == null}""); + } +}"; + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (6,33): warning CS0458: The result of the expression is always 'null' of type 'C' + // System.Console.Write($"{default as C == null} {default as string == null}"); + Diagnostic(ErrorCode.WRN_AlwaysNull, "default as C").WithArguments("C").WithLocation(6, 33), + // (6,56): warning CS0458: The result of the expression is always 'null' of type 'string' + // System.Console.Write($"{default as C == null} {default as string == null}"); + Diagnostic(ErrorCode.WRN_AlwaysNull, "default as string").WithArguments("string").WithLocation(6, 56) + ); + CompileAndVerify(comp, expectedOutput: "True True"); + } + + [Fact] + public void DefaultInputToConstantPattern() + { + var text = @" +class C +{ + static void M() { System.Console.Write(default is long); + System.Console.Write(default is string); + System.Console.Write(default is default); + System.Console.Write(default is T); } }"; - var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (6,30): error CS0023: Operator 'is' cannot be applied to operand of type 'default' // System.Console.Write(default is long); - Diagnostic(ErrorCode.ERR_BadUnaryOp, "default is long").WithArguments("is", "default").WithLocation(6, 30) + Diagnostic(ErrorCode.ERR_BadUnaryOp, "default is long").WithArguments("is", "default").WithLocation(6, 30), + // (7,30): error CS0023: Operator 'is' cannot be applied to operand of type 'default' + // System.Console.Write(default is string); + Diagnostic(ErrorCode.ERR_BadUnaryOp, "default is string").WithArguments("is", "default").WithLocation(7, 30), + // (8,30): error CS0023: Operator 'is' cannot be applied to operand of type 'default' + // System.Console.Write(default is default); + Diagnostic(ErrorCode.ERR_BadUnaryOp, "default is default").WithArguments("is", "default").WithLocation(8, 30), + // (8,41): error CS0150: A constant value is expected + // System.Console.Write(default is default); + Diagnostic(ErrorCode.ERR_ConstantExpected, "default").WithLocation(8, 41), + // (9,30): error CS0023: Operator 'is' cannot be applied to operand of type 'default' + // System.Console.Write(default is T); + Diagnostic(ErrorCode.ERR_BadUnaryOp, "default is T").WithArguments("is", "default").WithLocation(9, 30) ); } + [Fact] + public void DefaultInConstantPattern() + { + var text = @" +class C +{ + static void Main() + { + string hello = ""hello""; + string nullString = null; + int two = 2; + int zero = 0; + System.Console.Write($""{hello is default} {nullString is default} {two is default} {zero is default}""); + } +}"; + + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "False True False True"); + } + [Fact] public void TypeVarCanBeDefault() { From 61cf9eaa87e7dfa09e6071e297012ca72527fb7d Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Tue, 28 Mar 2017 13:10:14 -0700 Subject: [PATCH 5/9] Allow default in expression tree again --- .../Portable/CSharpResources.Designer.cs | 9 ---- .../CSharp/Portable/CSharpResources.resx | 3 -- .../CSharp/Portable/Errors/ErrorCode.cs | 1 - .../DiagnosticsPass_ExpressionTrees.cs | 9 ---- .../Emit/CodeGen/CodeGenExprLambdaTests.cs | 43 +++++++++++++++++++ .../Semantics/TargetTypedDefaultTests.cs | 32 +------------- 6 files changed, 44 insertions(+), 53 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 650b8afcb9664..f6bf1b046d4d2 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -4192,15 +4192,6 @@ internal static string ERR_ExpressionTreeContainsBaseAccess { } } - /// - /// Looks up a localized string similar to An expression tree may not contain a default literal.. - /// - internal static string ERR_ExpressionTreeContainsDefaultLiteral { - get { - return ResourceManager.GetString("ERR_ExpressionTreeContainsDefaultLiteral", resourceCulture); - } - } - /// /// Looks up a localized string similar to An expression tree may not contain a discard.. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index c7f27f1164b5e..25d004af1dabc 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4969,9 +4969,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ An expression tree may not contain a tuple conversion. - - An expression tree may not contain a default literal. - /sourcelink switch is only supported when emitting Portable PDB (/debug:portable or /debug:embedded must be specified). diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 85d27778611a7..60605232dacb5 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1475,6 +1475,5 @@ internal enum ErrorCode ERR_BadDynamicMethodArgDefault = 9000, ERR_DefaultNotValid = 9001, - ERR_ExpressionTreeContainsDefaultLiteral = 9002, } } diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs index 6a78fdc4bcb3e..f59bb4bd9bac7 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs @@ -700,14 +700,5 @@ public override BoundNode VisitThrowExpression(BoundThrowExpression node) return base.VisitThrowExpression(node); } - - public override BoundNode VisitDefaultLiteral(BoundDefaultLiteral node) - { - if (_inExpressionLambda && node.IsLiteralDefault()) - { - Error(ErrorCode.ERR_ExpressionTreeContainsDefaultLiteral, node); - } - return base.VisitDefaultLiteral(node); - } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs index 8808db84a476e..a289fd1afa541 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs @@ -5012,6 +5012,49 @@ static void Main(string[] args) expectedOutput: expectedOutput); } + [Fact] + public void EnumEqualityWithDefault() + { + string source = +@" +using System; +using System.Linq.Expressions; + +namespace ConsoleApplication1 +{ + enum YesNo + { + Yes, + No + } + + class MyType + { + public string Name { get; set; } + public YesNo? YesNo { get; set; } + + public int? Age { get; set; } + } + + class Program + { + static void Main(string[] args) + { + + Expression> expr = (MyType x) => x.YesNo == (YesNo?)default; + Console.WriteLine(expr.Dump()); + } + } + +}"; + string expectedOutput = "Equal(Convert(MemberAccess(Parameter(x Type:ConsoleApplication1.MyType).YesNo Type:System.Nullable`1[ConsoleApplication1.YesNo]) Lifted LiftedToNull Type:System.Nullable`1[System.Int32]) Convert(Convert(Constant(null Type:System.Object) Lifted LiftedToNull Type:System.Nullable`1[ConsoleApplication1.YesNo]) Lifted LiftedToNull Type:System.Nullable`1[System.Int32]) Lifted Type:System.Boolean)"; + CompileAndVerify( + new[] { source, ExpressionTestLibrary }, + new[] { ExpressionAssemblyRef }, + expectedOutput: expectedOutput, + parseOptions: TestOptions.ExperimentalParseOptions); + } + [WorkItem(546618, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546618")] [Fact] public void TildeNullableEnum() diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs index 3b07ac87f4a90..631e5e6ca936f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs @@ -924,10 +924,7 @@ class Program comp.VerifyDiagnostics( // (6,47): error CS0845: An expression tree lambda may not contain a coalescing operator with a null or default literal left-hand side // Expression> testExpr = () => default ?? "hello"; - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsBadCoalesce, "default"), - // (6,47): error CS9002: An expression tree may not contain a default literal. - // Expression> testExpr = () => default ?? "hello"; - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsDefaultLiteral, "default").WithLocation(6, 47) + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsBadCoalesce, "default").WithLocation(6, 47) ); } @@ -1196,32 +1193,5 @@ static void Main() Diagnostic(ErrorCode.ERR_BadSKknown, "System").WithArguments("System", "namespace", "type").WithLocation(6, 17) ); } - - [Fact] - public void DefaultLiteralDisallowedInExpressionTree() - { - string source = -@" -using System; -using System.Linq.Expressions; - -class Program -{ - static void M() - { - Expression> expr1 = (int x) => x == (int)default; - Expression> expr2 = (int x) => x == default; - } -}"; - var comp = CreateCompilationWithMscorlib(new[] { source }, new[] { ExpressionAssemblyRef }, parseOptions: TestOptions.ExperimentalParseOptions); - comp.VerifyDiagnostics( - // (9,66): error CS9002: An expression tree may not contain a default literal. - // Expression> expr1 = (int x) => x == (int)default; - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsDefaultLiteral, "default").WithLocation(9, 66), - // (10,61): error CS9002: An expression tree may not contain a default literal. - // Expression> expr2 = (int x) => x == default; - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsDefaultLiteral, "default").WithLocation(10, 61) - ); - } } } From 580a972e21347211c17c5a94c8c6167cc52fa58a Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Tue, 28 Mar 2017 13:26:25 -0700 Subject: [PATCH 6/9] Addressing PR feedback --- .../Portable/Binder/Binder_Conversions.cs | 6 ++--- .../Portable/Binder/Binder_Expressions.cs | 6 ++--- .../Portable/Binder/Binder_Invocation.cs | 2 +- .../Portable/Binder/Binder_Operators.cs | 7 ++--- .../CSharp/Portable/Binder/Binder_Query.cs | 2 +- .../Portable/Binder/Binder_Statements.cs | 4 +-- .../Portable/Binder/ForEachLoopBinder.cs | 4 +-- .../Semantics/Conversions/ConversionsBase.cs | 4 +-- .../Portable/BoundTree/BoundExpression.cs | 2 +- .../BoundTree/BoundExpressionExtensions.cs | 4 +-- .../CSharp/Portable/BoundTree/BoundNodes.xml | 2 +- .../Portable/BoundTree/BoundTreeVisitors.cs | 4 +-- .../CSharp/Portable/BoundTree/Constructors.cs | 6 ++--- .../CSharp/Portable/BoundTree/Expression.cs | 2 +- .../CSharp/Portable/BoundTree/Formatting.cs | 2 +- .../Portable/CSharpResources.Designer.cs | 18 ++++++------- .../CSharp/Portable/CSharpResources.resx | 8 +++--- .../CSharp/Portable/CodeGen/EmitExpression.cs | 6 ++--- .../CSharp/Portable/CodeGen/Optimizer.cs | 2 +- .../CSharp/Portable/Errors/ErrorCode.cs | 4 +-- .../Portable/FlowAnalysis/DataFlowPass.cs | 2 +- .../Portable/FlowAnalysis/FlowAnalysisPass.cs | 2 +- .../FlowAnalysis/PreciseAbstractFlowPass.cs | 2 +- .../CSharp/Portable/Lowering/Extensions.cs | 2 +- .../ExpressionLambdaRewriter.cs | 2 +- .../Lowering/LambdaRewriter/LambdaRewriter.cs | 2 +- .../LocalRewriter/LocalRewriter_AsOperator.cs | 2 +- .../LocalRewriter_BinaryOperator.cs | 12 ++++----- .../LocalRewriter/LocalRewriter_Call.cs | 10 +++---- .../LocalRewriter/LocalRewriter_Conversion.cs | 20 +++++++------- .../LocalRewriter_ObjectCreationExpression.cs | 4 +-- .../LocalRewriter_UnaryOperator.cs | 8 +++--- .../MethodToStateMachineRewriter.cs | 2 +- .../Lowering/SyntheticBoundNodeFactory.cs | 2 +- .../Symbols/Source/ParameterHelpers.cs | 2 +- .../Semantics/TargetTypedDefaultTests.cs | 27 +++++++++++-------- 36 files changed, 101 insertions(+), 95 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 54c74493f1d1f..eadedbb274034 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -105,9 +105,9 @@ protected BoundExpression CreateConversion( } ConstantValue constantValue = this.FoldConstantConversion(syntax, source, conversion, destination, diagnostics); - if (conversion.Kind == ConversionKind.DefaultOrNullLiteral && source.Kind == BoundKind.DefaultLiteral) + if (conversion.Kind == ConversionKind.DefaultOrNullLiteral && source.Kind == BoundKind.DefaultExpression) { - source = ((BoundDefaultLiteral)source).Update(constantValue, destination); + source = ((BoundDefaultExpression)source).Update(constantValue, destination); } return new BoundConversion( @@ -904,7 +904,7 @@ public ConstantValue FoldConstantConversion( var sourceConstantValue = source.ConstantValue; if (sourceConstantValue == null) { - if (conversion.Kind == ConversionKind.DefaultOrNullLiteral && source.Kind == BoundKind.DefaultLiteral) + if (conversion.Kind == ConversionKind.DefaultOrNullLiteral && source.Kind == BoundKind.DefaultExpression) { return destination.GetDefaultValue(); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 2b78c8590a7bf..49c203a927be5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -541,7 +541,7 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, Diagnostic return BindLiteralConstant((LiteralExpressionSyntax)node, diagnostics); case SyntaxKind.DefaultLiteralExpression: - return new BoundDefaultLiteral(node, constantValueOpt: null, type: null); + return new BoundDefaultExpression(node, constantValueOpt: null, type: null); case SyntaxKind.ParenthesizedExpression: // Parenthesis tokens are ignored, and operand is bound in the context of parent @@ -1057,7 +1057,7 @@ internal static ConstantValue GetConstantSizeOf(TypeSymbol type) private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, DiagnosticBag diagnostics) { TypeSymbol type = this.BindType(node.Type, diagnostics); - return new BoundDefaultLiteral(node, type); + return new BoundDefaultExpression(node, type); } /// @@ -5213,7 +5213,7 @@ private BoundExpression BindMemberAccessWithBoundLeft( private static void WarnOnAccessOfOffDefault(SyntaxNode node, BoundExpression boundLeft, DiagnosticBag diagnostics) { - if (boundLeft != null && boundLeft.Kind == BoundKind.DefaultLiteral && boundLeft.ConstantValue == ConstantValue.Null) + if (boundLeft != null && boundLeft.Kind == BoundKind.DefaultExpression && boundLeft.ConstantValue == ConstantValue.Null) { Error(diagnostics, ErrorCode.WRN_DotOnDefault, node, boundLeft.Type); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index c482a4a645b99..01444f1e0d683 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -411,7 +411,7 @@ private static bool ReportBadDynamicArguments( } else if (arg.IsLiteralDefault()) { - Error(diagnostics, ErrorCode.ERR_BadDynamicMethodArgDefault, arg.Syntax); + Error(diagnostics, ErrorCode.ERR_BadDynamicMethodArgDefaultLiteral, arg.Syntax); hasErrors = true; } else diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs index 3fa1883777741..ab1d4354b280a 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs @@ -3065,10 +3065,11 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa if (operand.IsLiteralDefault()) { - var defaultLiteral = (BoundDefaultLiteral)operand; - Debug.Assert((object)defaultLiteral.Type == null && (object)defaultLiteral.ConstantValueOpt == null); + var defaultLiteral = (BoundDefaultExpression)operand; + Debug.Assert((object)defaultLiteral.Type == null); + Debug.Assert((object)defaultLiteral.ConstantValueOpt == null); - operand = new BoundDefaultLiteral(defaultLiteral.Syntax, constantValueOpt: ConstantValue.Null, + operand = new BoundDefaultExpression(defaultLiteral.Syntax, constantValueOpt: ConstantValue.Null, type: GetSpecialType(SpecialType.System_Object, diagnostics, node)); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs index 5802982f0ab1b..50e03a7967902 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs @@ -726,7 +726,7 @@ protected BoundCall MakeQueryInvocation(CSharpSyntaxNode node, BoundExpression r } else if (ultimateReceiver.IsLiteralDefault()) { - diagnostics.Add(ErrorCode.ERR_DefaultNotValid, node.Location); + diagnostics.Add(ErrorCode.ERR_DefaultLiteralNotValid, node.Location); } else if (ultimateReceiver.Kind == BoundKind.NamespaceExpression) { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index cc53afb7a5905..9ea1b30555cf6 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -1007,7 +1007,7 @@ private bool IsValidFixedVariableInitializer(TypeSymbol declType, SourceLocalSym { Debug.Assert(initializerOpt.Kind == BoundKind.Conversion && (((BoundConversion)initializerOpt).Operand.IsLiteralNull() || - ((BoundConversion)initializerOpt).Operand.Kind == BoundKind.DefaultLiteral), + ((BoundConversion)initializerOpt).Operand.Kind == BoundKind.DefaultExpression), "All other typeless expressions should have conversion errors"); // CONSIDER: this is a very confusing error message, but it's what Dev10 reports. @@ -3204,7 +3204,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, DiagnosticBag di var interactiveInitializerMethod = this.ContainingMemberOrLambda as SynthesizedInteractiveInitializerMethod; if (interactiveInitializerMethod != null) { - arg = new BoundDefaultLiteral(interactiveInitializerMethod.GetNonNullSyntaxNode(), interactiveInitializerMethod.ResultType); + arg = new BoundDefaultExpression(interactiveInitializerMethod.GetNonNullSyntaxNode(), interactiveInitializerMethod.ResultType); } } diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs index 0931b3001d07f..6ad80bf2c5be4 100644 --- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs @@ -512,9 +512,9 @@ private bool GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder builder, BoundE if ((object)collectionExprType == null) // There's no way to enumerate something without a type. { - if (collectionExpr.Kind == BoundKind.DefaultLiteral && (object)collectionExpr.Type == null) + if (collectionExpr.Kind == BoundKind.DefaultExpression && (object)collectionExpr.Type == null) { - diagnostics.Add(ErrorCode.ERR_DefaultNotValid, _syntax.Expression.Location); + diagnostics.Add(ErrorCode.ERR_DefaultLiteralNotValid, _syntax.Expression.Location); } else { diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index 0097a04a0ec52..d09ff8b156be1 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs @@ -802,8 +802,8 @@ private Conversion ClassifyImplicitBuiltInConversionFromExpression(BoundExpressi } break; - case BoundKind.DefaultLiteral: - var defaultExpression = (BoundDefaultLiteral)sourceExpression; + case BoundKind.DefaultExpression: + var defaultExpression = (BoundDefaultExpression)sourceExpression; if ((object)defaultExpression.Type == null) { return Conversion.DefaultOrNullLiteral; diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs index 410fa8b8643c0..f02545f32360b 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs @@ -460,7 +460,7 @@ public override Symbol ExpressionSymbol } } - internal partial class BoundDefaultLiteral + internal partial class BoundDefaultExpression { public override ConstantValue ConstantValue { diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs index 7ba9d166ef664..78f0a2bb44e26 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs @@ -16,7 +16,7 @@ public static bool IsLiteralNull(this BoundExpression node) public static bool IsLiteralDefault(this BoundExpression node) { - return node.Kind == BoundKind.DefaultLiteral && node.Syntax.Kind() == SyntaxKind.DefaultLiteralExpression; + return node.Kind == BoundKind.DefaultExpression && node.Syntax.Kind() == SyntaxKind.DefaultLiteralExpression; } // returns true when expression has no side-effects and produces @@ -27,7 +27,7 @@ public static bool IsLiteralDefault(this BoundExpression node) // after some folding/propagation/algebraic transformations. public static bool IsDefaultValue(this BoundExpression node) { - if (node.Kind == BoundKind.DefaultLiteral) + if (node.Kind == BoundKind.DefaultExpression) { return true; } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index b981d780376c9..b2185dc49e35d 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -517,7 +517,7 @@ - + diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeVisitors.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeVisitors.cs index 03e52f0af7d24..13143445ad4d8 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeVisitors.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeVisitors.cs @@ -48,8 +48,8 @@ public virtual R Visit(BoundNode node, A arg) return VisitArrayAccess(node as BoundArrayAccess, arg); case BoundKind.TypeOfOperator: return VisitTypeOfOperator(node as BoundTypeOfOperator, arg); - case BoundKind.DefaultLiteral: - return VisitDefaultLiteral(node as BoundDefaultLiteral, arg); + case BoundKind.DefaultExpression: + return VisitDefaultExpression(node as BoundDefaultExpression, arg); case BoundKind.IsOperator: return VisitIsOperator(node as BoundIsOperator, arg); case BoundKind.AsOperator: diff --git a/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs b/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs index f7abc3820b93f..ba88cfda819cc 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs @@ -523,14 +523,14 @@ public static BoundBlock SynthesizedNoLocals(SyntaxNode syntax, params BoundStat } } - internal partial class BoundDefaultLiteral + internal partial class BoundDefaultExpression { - public BoundDefaultLiteral(SyntaxNode syntax, TypeSymbol type, bool hasErrors = false) + public BoundDefaultExpression(SyntaxNode syntax, TypeSymbol type, bool hasErrors = false) : this(syntax, type.GetDefaultValue(), type, hasErrors) { } - public BoundDefaultLiteral(SyntaxNode syntax) + public BoundDefaultExpression(SyntaxNode syntax) : this(syntax, constantValueOpt: null, type: null, hasErrors: false) { } diff --git a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs index 8c51e21392fe8..57a1a76082ecc 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs @@ -939,7 +939,7 @@ public override TResult Accept(OperationVisitor OperationKind.DefaultValueExpression; diff --git a/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs b/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs index 93727a2511e6c..279c29f1f8d3f 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs @@ -136,7 +136,7 @@ public override object Display } } - internal partial class BoundDefaultLiteral + internal partial class BoundDefaultExpression { public override object Display { diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index f6bf1b046d4d2..6b22c9fff6a34 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -1358,11 +1358,11 @@ internal static string ERR_BadDynamicMethodArg { } /// - /// Looks up a localized string similar to Cannot use a type-inferred default operator as an argument to a dynamically dispatched operation.. + /// Looks up a localized string similar to Cannot use a default literal as an argument to a dynamically dispatched operation.. /// - internal static string ERR_BadDynamicMethodArgDefault { + internal static string ERR_BadDynamicMethodArgDefaultLiteral { get { - return ResourceManager.GetString("ERR_BadDynamicMethodArgDefault", resourceCulture); + return ResourceManager.GetString("ERR_BadDynamicMethodArgDefaultLiteral", resourceCulture); } } @@ -3212,20 +3212,20 @@ internal static string ERR_DeconstructWrongCardinality { } /// - /// Looks up a localized string similar to Cannot specify the DefaultMember attribute on a type containing an indexer. + /// Looks up a localized string similar to Use of default literal is not valid in this context. /// - internal static string ERR_DefaultMemberOnIndexedType { + internal static string ERR_DefaultLiteralNotValid { get { - return ResourceManager.GetString("ERR_DefaultMemberOnIndexedType", resourceCulture); + return ResourceManager.GetString("ERR_DefaultLiteralNotValid", resourceCulture); } } /// - /// Looks up a localized string similar to Use of default is not valid in this context. + /// Looks up a localized string similar to Cannot specify the DefaultMember attribute on a type containing an indexer. /// - internal static string ERR_DefaultNotValid { + internal static string ERR_DefaultMemberOnIndexedType { get { - return ResourceManager.GetString("ERR_DefaultNotValid", resourceCulture); + return ResourceManager.GetString("ERR_DefaultMemberOnIndexedType", resourceCulture); } } diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 25d004af1dabc..8817f63fb7817 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -849,8 +849,8 @@ Use of null is not valid in this context - - Use of default is not valid in this context + + Use of default literal is not valid in this context The 'this' object cannot be used before all of its fields are assigned to @@ -5026,8 +5026,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ It is not legal to use the type 'dynamic' in a pattern. - - Cannot use a type-inferred default operator as an argument to a dynamically dispatched operation. + + Cannot use a default literal as an argument to a dynamically dispatched operation. Provided documentation mode is unsupported or invalid: '{0}'. diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 108df5b512c7a..1c2d421f538fe 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -191,8 +191,8 @@ private void EmitExpressionCore(BoundExpression expression, bool used) EmitAsExpression((BoundAsOperator)expression, used); break; - case BoundKind.DefaultLiteral: - EmitDefaultExpression((BoundDefaultLiteral)expression, used); + case BoundKind.DefaultExpression: + EmitDefaultExpression((BoundDefaultExpression)expression, used); break; case BoundKind.TypeOfOperator: @@ -2637,7 +2637,7 @@ private void EmitDefaultValue(TypeSymbol type, bool used, SyntaxNode syntaxNode) } } - private void EmitDefaultExpression(BoundDefaultLiteral expression, bool used) + private void EmitDefaultExpression(BoundDefaultExpression expression, bool used) { Debug.Assert(expression.Type.SpecialType == SpecialType.System_Decimal || expression.Type.GetDefaultValue() == null, "constant should be set on this expression"); diff --git a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs index dac4488b2ad9b..d847d9967a144 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs @@ -1426,7 +1426,7 @@ public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) if (node.OperatorKind.IsChecked() && node.OperatorKind.Operator() == UnaryOperatorKind.UnaryMinus) { var origStack = StackDepth(); - PushEvalStack(new BoundDefaultLiteral(node.Syntax, node.Operand.Type), ExprContext.Value); + PushEvalStack(new BoundDefaultExpression(node.Syntax, node.Operand.Type), ExprContext.Value); BoundExpression operand = (BoundExpression)this.Visit(node.Operand); return node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, node.Type); } diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 60605232dacb5..d13ab9f7377c8 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1473,7 +1473,7 @@ internal enum ErrorCode ERR_LanguageVersionCannotHaveLeadingZeroes = 8303, ERR_CompilerAndLanguageVersion = 8304, - ERR_BadDynamicMethodArgDefault = 9000, - ERR_DefaultNotValid = 9001, + ERR_BadDynamicMethodArgDefaultLiteral = 9000, + ERR_DefaultLiteralNotValid = 9001, } } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs index 8fd4dfa1e7149..6a3d21995d5ec 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs @@ -608,7 +608,7 @@ internal static bool WriteConsideredUse(TypeSymbol type, BoundExpression value) } return WriteConsideredUse(null, boundConversion.Operand); } - case BoundKind.DefaultLiteral: + case BoundKind.DefaultExpression: return false; case BoundKind.ObjectCreationExpression: var init = (BoundObjectCreationExpression)value; diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs index 5b3a8a67bded9..275b6e303a4c6 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs @@ -56,7 +56,7 @@ public static BoundBlock Rewrite( { Debug.Assert(submissionResultType.SpecialType != SpecialType.System_Void); - var trailingExpression = new BoundDefaultLiteral(method.GetNonNullSyntaxNode(), submissionResultType); + var trailingExpression = new BoundDefaultExpression(method.GetNonNullSyntaxNode(), submissionResultType); var newStatements = block.Statements.Add(new BoundReturnStatement(trailingExpression.Syntax, RefKind.None, trailingExpression)); block = new BoundBlock(block.Syntax, ImmutableArray.Empty, newStatements) { WasCompilerGenerated = true }; #if DEBUG diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs index 7163eac53a29a..d8c5da4691e78 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs @@ -2497,7 +2497,7 @@ public override BoundNode VisitYieldReturnStatement(BoundYieldReturnStatement no return null; } - public override BoundNode VisitDefaultLiteral(BoundDefaultLiteral node) + public override BoundNode VisitDefaultExpression(BoundDefaultExpression node) { return null; } diff --git a/src/Compilers/CSharp/Portable/Lowering/Extensions.cs b/src/Compilers/CSharp/Portable/Lowering/Extensions.cs index 12b91720e384c..1947753eed507 100644 --- a/src/Compilers/CSharp/Portable/Lowering/Extensions.cs +++ b/src/Compilers/CSharp/Portable/Lowering/Extensions.cs @@ -84,7 +84,7 @@ public static bool NullableNeverHasValue(this BoundExpression expr) } // "default(int?)" never has a value. - if (expr.Kind == BoundKind.DefaultLiteral) + if (expr.Kind == BoundKind.DefaultExpression) { return true; } diff --git a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/ExpressionLambdaRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/ExpressionLambdaRewriter.cs index 52298c3ead876..06ebf7fb9e5a0 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/ExpressionLambdaRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/ExpressionLambdaRewriter.cs @@ -231,7 +231,7 @@ private BoundExpression VisitExpressionWithoutStackGuard(BoundExpression node) case BoundKind.UnaryOperator: return VisitUnaryOperator((BoundUnaryOperator)node); - case BoundKind.DefaultLiteral: + case BoundKind.DefaultExpression: case BoundKind.HostObjectMemberReference: case BoundKind.Literal: case BoundKind.Local: diff --git a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs index 01034e59e37ac..1bd8cd71c15bc 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs @@ -639,7 +639,7 @@ private BoundNode IntroduceFrame(BoundNode node, LambdaFrame frame, Func.Empty, sideEffects: ImmutableArray.Create(sideEffect), - value: new BoundDefaultLiteral(syntax, null, type), + value: new BoundDefaultExpression(syntax, null, type), type: type); } @@ -1302,7 +1302,7 @@ private BoundExpression LowerLiftedBinaryArithmeticOperator( BoundExpression consequence = MakeLiftedBinaryOperatorConsequence(syntax, kind, callX_GetValueOrDefault, callY_GetValueOrDefault, type, method); // default(R?) - BoundExpression alternative = new BoundDefaultLiteral(syntax, null, type); + BoundExpression alternative = new BoundDefaultExpression(syntax, null, type); // tempX.HasValue & tempY.HasValue ? // new R?(tempX.GetValueOrDefault() OP tempY.GetValueOrDefault()) : @@ -1478,7 +1478,7 @@ private BoundExpression MakeNewNullableBoolean(SyntaxNode syntax, bool? value) NamedTypeSymbol nullableBoolType = nullableType.Construct(boolType); if (value == null) { - return new BoundDefaultLiteral(syntax, null, nullableBoolType); + return new BoundDefaultExpression(syntax, null, nullableBoolType); } return new BoundObjectCreationExpression( @@ -1521,7 +1521,7 @@ private BoundExpression OptimizeLiftedBooleanOperatorOneNull( BoundExpression alwaysNull = leftAlwaysNull ? left : right; BoundExpression notAlwaysNull = leftAlwaysNull ? right : left; BoundExpression neverNull = NullableAlwaysHasValue(notAlwaysNull); - BoundExpression nullBool = new BoundDefaultLiteral(syntax, null, alwaysNull.Type); + BoundExpression nullBool = new BoundDefaultExpression(syntax, null, alwaysNull.Type); if (neverNull != null) { diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs index bbc01c9370594..3ee96a545797e 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs @@ -994,14 +994,14 @@ private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSym else { // The argument to M([Optional] int x) becomes default(int) - defaultValue = new BoundDefaultLiteral(syntax, parameterType); + defaultValue = new BoundDefaultExpression(syntax, parameterType); } } else if (defaultConstantValue.IsNull && parameterType.IsValueType) { // We have something like M(int? x = null) or M(S x = default(S)), // so replace the argument with default(int?). - defaultValue = new BoundDefaultLiteral(syntax, parameterType); + defaultValue = new BoundDefaultExpression(syntax, parameterType); } else if (parameterType.IsNullableType()) { @@ -1057,20 +1057,20 @@ private BoundExpression GetDefaultParameterSpecial(SyntaxNode syntax, ParameterS if (parameter.IsMarshalAsObject) { // default(object) - defaultValue = new BoundDefaultLiteral(syntax, parameter.Type); + defaultValue = new BoundDefaultExpression(syntax, parameter.Type); } else if (parameter.IsIUnknownConstant) { // new UnknownWrapper(default(object)) var methodSymbol = (MethodSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_UnknownWrapper__ctor); - var argument = new BoundDefaultLiteral(syntax, parameter.Type); + var argument = new BoundDefaultExpression(syntax, parameter.Type); defaultValue = new BoundObjectCreationExpression(syntax, methodSymbol, argument); } else if (parameter.IsIDispatchConstant) { // new DispatchWrapper(default(object)) var methodSymbol = (MethodSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_DispatchWrapper__ctor); - var argument = new BoundDefaultLiteral(syntax, parameter.Type); + var argument = new BoundDefaultExpression(syntax, parameter.Type); defaultValue = new BoundObjectCreationExpression(syntax, methodSymbol, argument); } else diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs index cc8fe5c99c1d8..c41c45f47f30e 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs @@ -175,7 +175,7 @@ private BoundExpression MakeConversionNode( if (NullableNeverHasValue(rewrittenOperand)) { - return new BoundDefaultLiteral(syntax, rewrittenType); + return new BoundDefaultExpression(syntax, rewrittenType); } BoundExpression nullableValue = NullableAlwaysHasValue(rewrittenOperand); @@ -190,7 +190,7 @@ private BoundExpression MakeConversionNode( case ConversionKind.DefaultOrNullLiteral: if (!_inExpressionLambda || !explicitCastInCode) { - return new BoundDefaultLiteral(syntax, rewrittenType); + return new BoundDefaultExpression(syntax, rewrittenType); } break; @@ -199,7 +199,7 @@ private BoundExpression MakeConversionNode( case ConversionKind.ExplicitReference: if (rewrittenOperand.IsDefaultValue() && (!_inExpressionLambda || !explicitCastInCode)) { - return new BoundDefaultLiteral(syntax, rewrittenType); + return new BoundDefaultExpression(syntax, rewrittenType); } break; @@ -217,7 +217,7 @@ private BoundExpression MakeConversionNode( case ConversionKind.ExplicitNumeric: if (rewrittenOperand.IsDefaultValue() && (!_inExpressionLambda || !explicitCastInCode)) { - return new BoundDefaultLiteral(syntax, rewrittenType); + return new BoundDefaultExpression(syntax, rewrittenType); } if (rewrittenType.SpecialType == SpecialType.System_Decimal || rewrittenOperand.Type.SpecialType == SpecialType.System_Decimal) @@ -277,7 +277,7 @@ private BoundExpression MakeConversionNode( rewrittenOperand.IsDefaultValue() && (!_inExpressionLambda || !explicitCastInCode)) { - return new BoundDefaultLiteral(syntax, rewrittenType); + return new BoundDefaultExpression(syntax, rewrittenType); } if (rewrittenType.SpecialType == SpecialType.System_Decimal) @@ -679,7 +679,7 @@ private static bool NullableNeverHasValue(BoundExpression expression) } // default(int?) never has a value. - if (expression.Kind == BoundKind.DefaultLiteral) + if (expression.Kind == BoundKind.DefaultExpression) { return true; } @@ -852,7 +852,7 @@ private BoundExpression RewriteFullyLiftedBuiltInConversion( conversion.UnderlyingConversions[0], type.GetNullableUnderlyingType(), @checked)); - BoundExpression alternative = new BoundDefaultLiteral(syntax, null, type); + BoundExpression alternative = new BoundDefaultExpression(syntax, null, type); BoundExpression conditionalExpression = RewriteConditionalOperator( syntax: syntax, rewrittenCondition: condition, @@ -880,7 +880,7 @@ private BoundExpression OptimizeLiftedUserDefinedConversion( if (NullableNeverHasValue(operand)) { - return new BoundDefaultLiteral(syntax, type); + return new BoundDefaultExpression(syntax, type); } // If the converted expression is known to never be null then we can return @@ -909,7 +909,7 @@ private BoundExpression OptimizeLiftedBuiltInConversion( if (NullableNeverHasValue(operand)) { - return new BoundDefaultLiteral(syntax, null, type); + return new BoundDefaultExpression(syntax, null, type); } // Second, a trickier optimization. If the conversion is "(T?)(new S?(x))" then @@ -1089,7 +1089,7 @@ private BoundExpression RewriteLiftedUserDefinedConversion( BoundExpression consequence = MakeLiftedUserDefinedConversionConsequence(userDefinedCall, rewrittenType); // default(R?) - BoundExpression alternative = new BoundDefaultLiteral(syntax, rewrittenType); + BoundExpression alternative = new BoundDefaultExpression(syntax, rewrittenType); // temp.HasValue ? new R?(op_Whatever(temp.GetValueOrDefault())) : default(R?) BoundExpression conditionalExpression = RewriteConditionalOperator( diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectCreationExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectCreationExpression.cs index 60a20a60eca65..2d958c4f4e912 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectCreationExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectCreationExpression.cs @@ -63,7 +63,7 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre // replace "new S()" with a default struct ctor with "default(S)" if (node.Constructor.IsDefaultValueTypeConstructor()) { - rewrittenObjectCreation = new BoundDefaultLiteral(rewrittenObjectCreation.Syntax, rewrittenObjectCreation.Type); + rewrittenObjectCreation = new BoundDefaultExpression(rewrittenObjectCreation.Syntax, rewrittenObjectCreation.Type); } if (!temps.IsDefaultOrEmpty) @@ -185,7 +185,7 @@ private BoundExpression MakeNewT(SyntaxNode syntax, TypeParameterSymbol typePara if (!this.TryGetWellKnownTypeMember(syntax, WellKnownMember.System_Activator__CreateInstance_T, out method)) { - return new BoundDefaultLiteral(syntax, null, type: typeParameter, hasErrors: true); + return new BoundDefaultExpression(syntax, null, type: typeParameter, hasErrors: true); } Debug.Assert((object)method != null); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs index cc0b044148663..b3c64901f9383 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs @@ -199,7 +199,7 @@ private BoundExpression LowerLiftedUnaryOperator( BoundExpression consequence = GetLiftedUnaryOperatorConsequence(kind, syntax, method, type, call_GetValueOrDefault); // default(R?) - BoundExpression alternative = new BoundDefaultLiteral(syntax, null, type); + BoundExpression alternative = new BoundDefaultExpression(syntax, null, type); // temp.HasValue ? // new R?(OP(temp.GetValueOrDefault())) : @@ -233,7 +233,7 @@ private BoundExpression OptimizeLiftedUnaryOperator( { if (NullableNeverHasValue(loweredOperand)) { - return new BoundDefaultLiteral(syntax, null, type); + return new BoundDefaultExpression(syntax, null, type); } // Second, another simple optimization. If we know that the operand is never null @@ -636,7 +636,7 @@ private BoundExpression MakeUserDefinedIncrementOperator(BoundIncrementOperator BoundExpression consequence = new BoundObjectCreationExpression(syntax, ctor, userDefinedCall); // default(S?) - BoundExpression alternative = new BoundDefaultLiteral(syntax, null, type); + BoundExpression alternative = new BoundDefaultExpression(syntax, null, type); // temp.HasValue ? // new S?(op_Increment(temp.GetValueOrDefault())) : @@ -802,7 +802,7 @@ private BoundExpression MakeLiftedDecimalIncDecOperator(SyntaxNode syntax, Binar // new decimal?(op_Inc(x.GetValueOrDefault())) BoundExpression consequence = new BoundObjectCreationExpression(syntax, ctor, methodCall); // default(decimal?) - BoundExpression alternative = new BoundDefaultLiteral(syntax, null, operand.Type); + BoundExpression alternative = new BoundDefaultExpression(syntax, null, operand.Type); // x.HasValue ? new decimal?(op_Inc(x.GetValueOrDefault())) : default(decimal?) return RewriteConditionalOperator(syntax, condition, consequence, alternative, ConstantValue.NotAvailable, operand.Type); diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs index 0d3606c7a2980..76e1736722688 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs @@ -549,7 +549,7 @@ private BoundExpression HoistExpression( case BoundKind.ThisReference: case BoundKind.BaseReference: - case BoundKind.DefaultLiteral: + case BoundKind.DefaultExpression: return expr; default: diff --git a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs index fad6a0dd6c0a7..eed2ad5be92af 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs @@ -1176,7 +1176,7 @@ public BoundExpression Array(TypeSymbol elementType, BoundExpression length) internal BoundExpression Default(TypeSymbol type) { - return new BoundDefaultLiteral(Syntax, type) { WasCompilerGenerated = true }; + return new BoundDefaultExpression(Syntax, type) { WasCompilerGenerated = true }; } internal BoundStatement Try( diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs index 28e744d4439f5..e467d3d7930ca 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs @@ -429,7 +429,7 @@ private static bool IsValidDefaultValue(BoundExpression expression) // Also when valuetype S has a parameterless constructor, // new S() is clearly not a constant expression and should produce an error return (expression.ConstantValue != null) || - (expression.Kind == BoundKind.DefaultLiteral) || + (expression.Kind == BoundKind.DefaultExpression) || (expression.Kind == BoundKind.ObjectCreationExpression && IsValidDefaultValue((BoundObjectCreationExpression)expression)); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs index 631e5e6ca936f..bdc68a6f92464 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs @@ -521,19 +521,20 @@ public void DefaultInEnum() string source = @" enum E { - Entry = default + DefaultEntry = default, + OneEntry = default + 1 } class C { static void Main() { - System.Console.Write((int)E.Entry); + System.Console.Write($""{(int)E.DefaultEntry} {(int)E.OneEntry}""); } } "; var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); - CompileAndVerify(comp, expectedOutput: "0"); + CompileAndVerify(comp, expectedOutput: "0 1"); } [Fact] @@ -609,9 +610,9 @@ static void M1() var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); comp.VerifyDiagnostics( - // (7,14): error CS9000: Cannot use a type-inferred default operator as an argument to a dynamically dispatched operation. + // (7,14): error CS9000: Cannot use a default literal as an argument to a dynamically dispatched operation. // d.M2(default); - Diagnostic(ErrorCode.ERR_BadDynamicMethodArgDefault, "default").WithLocation(7, 14) + Diagnostic(ErrorCode.ERR_BadDynamicMethodArgDefaultLiteral, "default").WithLocation(7, 14) ); } @@ -677,9 +678,9 @@ static void Main() var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); comp.VerifyDiagnostics( - // (6,27): error CS9001: Use of default is not valid in this context + // (6,27): error CS9001: Use of default literal is not valid in this context // foreach (int x in default) { } - Diagnostic(ErrorCode.ERR_DefaultNotValid, "default").WithLocation(6, 27), + Diagnostic(ErrorCode.ERR_DefaultLiteralNotValid, "default").WithLocation(6, 27), // (7,27): error CS0186: Use of null is not valid in this context // foreach (int x in null) { } Diagnostic(ErrorCode.ERR_NullNotValid, "null").WithLocation(7, 27) @@ -700,9 +701,9 @@ static void Main() "; var compilation = CreateCompilationWithMscorlibAndSystemCore(source, parseOptions: TestOptions.ExperimentalParseOptions); compilation.VerifyDiagnostics( - // (5,35): error CS9001: Use of default is not valid in this context + // (5,35): error CS9001: Use of default literal is not valid in this context // var q = from x in default select x; - Diagnostic(ErrorCode.ERR_DefaultNotValid, "select x").WithLocation(5, 35) + Diagnostic(ErrorCode.ERR_DefaultLiteralNotValid, "select x").WithLocation(5, 35) ); } @@ -774,10 +775,11 @@ public void DefaultInAsOperator() var text = @" class C { - static void M() + static void M() where TClass : class { System.Console.Write(default as long); System.Console.Write(default as T); + System.Console.Write(default as TClass); } }"; @@ -788,7 +790,10 @@ static void M() Diagnostic(ErrorCode.ERR_AsMustHaveReferenceType, "default as long").WithArguments("long").WithLocation(6, 30), // (7,30): error CS0413: The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint // System.Console.Write(default as T); - Diagnostic(ErrorCode.ERR_AsWithTypeVar, "default as T").WithArguments("T").WithLocation(7, 30) + Diagnostic(ErrorCode.ERR_AsWithTypeVar, "default as T").WithArguments("T").WithLocation(7, 30), + // (8,30): warning CS0458: The result of the expression is always 'null' of type 'TClass' + // System.Console.Write(default as TClass); + Diagnostic(ErrorCode.WRN_AlwaysNull, "default as TClass").WithArguments("TClass").WithLocation(8, 30) ); } From 363a70e99f36c3c56581107181ad0340051453f6 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Tue, 28 Mar 2017 17:18:59 -0700 Subject: [PATCH 7/9] Fixing EE code to use renamed bound node --- src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs | 2 +- .../ExpressionCompiler/Rewriters/LocalDeclarationRewriter.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 8400c72a1df50..8ff338b4a71dd 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -1853,7 +1853,7 @@ S MakeS() No, ObjectCreationExpression 'new S()' is not a non-moveable variable No, Conversion 'default(S).i' is not a non-moveable variable No, FieldAccess 'default(S).i' is not a non-moveable variable -No, DefaultLiteral 'default(S)' is not a non-moveable variable +No, DefaultExpression 'default(S)' is not a non-moveable variable No, Conversion 'MakeS().i' is not a non-moveable variable No, FieldAccess 'MakeS().i' is not a non-moveable variable No, Call 'MakeS()' is not a non-moveable variable diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/LocalDeclarationRewriter.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/LocalDeclarationRewriter.cs index bda934d99bb56..f02eea5112eca 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/LocalDeclarationRewriter.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/LocalDeclarationRewriter.cs @@ -118,7 +118,7 @@ private static BoundExpression GetCustomTypeInfoPayloadId(SyntaxNode syntax, Met { if (!hasCustomTypeInfoPayload) { - return new BoundDefaultLiteral(syntax, guidConstructor.ContainingType); + return new BoundDefaultExpression(syntax, guidConstructor.ContainingType); } var value = ConstantValue.Create(CustomTypeInfo.PayloadTypeId.ToString()); From 8d5e082c817bc48453b2b0f26e72419c18ab129b Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 30 Mar 2017 19:38:03 -0700 Subject: [PATCH 8/9] Add warning for "case default:" --- .../Portable/Binder/PatternSwitchBinder.cs | 5 + .../CSharp/Portable/Binder/SwitchBinder.cs | 5 + .../Portable/CSharpResources.Designer.cs | 18 ++++ .../CSharp/Portable/CSharpResources.resx | 6 ++ .../CSharp/Portable/Errors/ErrorCode.cs | 1 + .../CSharp/Portable/Errors/ErrorFacts.cs | 1 + .../Semantics/TargetTypedDefaultTests.cs | 97 ++++++++++++++++++- 7 files changed, 132 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Binder/PatternSwitchBinder.cs b/src/Compilers/CSharp/Portable/Binder/PatternSwitchBinder.cs index b57087d4e38ac..aa86e537ce024 100644 --- a/src/Compilers/CSharp/Portable/Binder/PatternSwitchBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/PatternSwitchBinder.cs @@ -195,6 +195,11 @@ private BoundPatternSwitchLabel BindPatternSwitchSectionLabel( hasErrors = true; } + if (caseLabelSyntax.Value.Kind() == SyntaxKind.DefaultLiteralExpression) + { + diagnostics.Add(ErrorCode.WRN_DefaultInSwitch, caseLabelSyntax.Value.Location); + } + // Until we've determined whether or not the switch label is reachable, we assume it // is. The caller updates isReachable after determining if the label is subsumed. const bool isReachable = true; diff --git a/src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs b/src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs index 1cfc4fa769c11..7f10445f52ce8 100644 --- a/src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs @@ -608,6 +608,11 @@ private BoundSwitchLabel BindSwitchSectionLabel(SwitchLabelSyntax node, Binder s hasErrors = true; } + if (caseLabelSyntax.Value.Kind() == SyntaxKind.DefaultLiteralExpression) + { + diagnostics.Add(ErrorCode.WRN_DefaultInSwitch, caseLabelSyntax.Value.Location); + } + // LabelSymbols for all the switch case labels are created by BuildLabels(). // Fetch the matching switch case label symbols break; diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 6b22c9fff6a34..eaae9af0c7f51 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -12185,6 +12185,24 @@ internal static string WRN_DebugFullNameTooLong_Title { } } + /// + /// Looks up a localized string similar to Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate.. + /// + internal static string WRN_DefaultInSwitch { + get { + return ResourceManager.GetString("WRN_DefaultInSwitch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate.. + /// + internal static string WRN_DefaultInSwitch_Title { + get { + return ResourceManager.GetString("WRN_DefaultInSwitch_Title", resourceCulture); + } + } + /// /// Looks up a localized string similar to The default value specified for parameter '{0}' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 8817f63fb7817..d2e3acc46d80d 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5053,4 +5053,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Compiler version: '{0}'. Language version: {1}. + + Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate. + + + Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate. + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index d13ab9f7377c8..3a73e161bdf63 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1475,5 +1475,6 @@ internal enum ErrorCode ERR_BadDynamicMethodArgDefaultLiteral = 9000, ERR_DefaultLiteralNotValid = 9001, + WRN_DefaultInSwitch = 9002, } } diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 553f5efba4b5c..d6e49bb9177b8 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -317,6 +317,7 @@ internal static int GetWarningLevel(ErrorCode code) case ErrorCode.WRN_AlignmentMagnitude: case ErrorCode.WRN_AttributeIgnoredWhenPublicSigning: case ErrorCode.WRN_TupleLiteralNameMismatch: + case ErrorCode.WRN_DefaultInSwitch: return 1; default: return 0; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs index bdc68a6f92464..50737b151d9b5 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs @@ -1002,7 +1002,7 @@ static System.Func M() } [Fact] - public void Switch() + public void V6SwitchWarns() { string source = @" class C @@ -1023,6 +1023,101 @@ static void M(int x) } } } +"; + + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (12,18): warning CS9002: Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate. + // case default: + Diagnostic(ErrorCode.WRN_DefaultInSwitch, "default").WithLocation(12, 18) + ); + CompileAndVerify(comp, expectedOutput: "default"); + } + + [Fact] + public void V7SwitchWarns() + { + string source = @" +class C +{ + static void Main() + { + M(null); + } + static void M(object x) + { + switch (x) + { + case default: + System.Console.Write(""default""); + break; + default: + break; + } + } +} +"; + + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (12,18): warning CS9002: Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate. + // case default: + Diagnostic(ErrorCode.WRN_DefaultInSwitch, "default").WithLocation(12, 18) + ); + CompileAndVerify(comp, expectedOutput: "default"); + } + + [Fact] + public void V6SwitchWarningWorkaround() + { + string source = @" +class C +{ + static void Main() + { + M(0); + } + static void M(int x) + { + switch (x) + { + case (default): + System.Console.Write(""default""); + break; + default: + break; + } + } +} +"; + + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "default"); + } + + [Fact] + public void V7SwitchWarningWorkaround() + { + string source = @" +class C +{ + static void Main() + { + M(null); + } + static void M(object x) + { + switch (x) + { + case (default): + System.Console.Write(""default""); + break; + default: + break; + } + } +} "; var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); From a39beb2745e5b89d14a21056b6bdae49d7a5eac5 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Tue, 4 Apr 2017 12:38:53 -0700 Subject: [PATCH 9/9] Address Aleksey's feedback --- src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs | 7 ++++++- .../CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs | 4 ++-- src/Compilers/Test/Utilities/CSharp/TestOptions.cs | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 49c203a927be5..b16b6429bd3eb 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -541,7 +541,7 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, Diagnostic return BindLiteralConstant((LiteralExpressionSyntax)node, diagnostics); case SyntaxKind.DefaultLiteralExpression: - return new BoundDefaultExpression(node, constantValueOpt: null, type: null); + return BindDefaultLiteral(node); case SyntaxKind.ParenthesizedExpression: // Parenthesis tokens are ignored, and operand is bound in the context of parent @@ -652,6 +652,11 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, Diagnostic } } + private static BoundExpression BindDefaultLiteral(ExpressionSyntax node) + { + return new BoundDefaultExpression(node, constantValueOpt: null, type: null); + } + private BoundExpression BindRefExpression(ExpressionSyntax node, DiagnosticBag diagnostics) { var firstToken = node.GetFirstToken(); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs index 38aab9dc8e8b7..d4d8756f7777b 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs @@ -3534,10 +3534,10 @@ void M() } [Fact] - public void TestTargetTypedDefault() + public void TestTargetTypedDefaultWithCSharp7_1() { var text = "default"; - var expr = this.ParseExpression(text, TestOptions.ExperimentalParseOptions); + var expr = this.ParseExpression(text, TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); Assert.NotNull(expr); Assert.Equal(SyntaxKind.DefaultLiteralExpression, expr.Kind()); diff --git a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs index f721a83ca2c82..19741fb25395f 100644 --- a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs +++ b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs @@ -18,7 +18,7 @@ public static class TestOptions private static readonly SmallDictionary s_experimentalFeatures = new SmallDictionary { }; public static readonly CSharpParseOptions ExperimentalParseOptions = - new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None, languageVersion: LanguageVersion.CSharp7_1).WithFeatures(s_experimentalFeatures); + new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None, languageVersion: LanguageVersion.Latest).WithFeatures(s_experimentalFeatures); // Enable pattern-switch translation even for switches that use no new syntax. This is used // to help ensure compatibility of the semantics of the new switch binder with the old switch