Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make "default" a literal and other tweaks from recent LDM #18213

Merged
merged 9 commits into from
Apr 4, 2017

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Mar 27, 2017

  • Using LiteralExpressionSyntax instead of introducing a new syntax node
  • Disallow in expression trees (filed Expression tree support for default literal #18212 for enabling at some point)
  • Attaching to C# 7.1 instead of a feature flag
  • disallow default is T, allow x is default, allow default as RefType (with always-null warning)

@cston @gafter @dotnet/roslyn-compiler for review.

Fixes #17478
Relates to #13602

@jcouv jcouv force-pushed the default-LDM branch 3 times, most recently from 732750c to 86928ce Compare March 28, 2017 04:42
@@ -5012,49 +5012,6 @@ static void Main(string[] args)
expectedOutput: expectedOutput);
}

[Fact]
public void EnumEqualityWithDefault()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This is replaced by a test in TargetTypedDefaultTests.cs below.

if (operand.IsLiteralDefault())
{
var defaultLiteral = (BoundDefaultLiteral)operand;
Debug.Assert((object)defaultLiteral.Type == null && (object)defaultLiteral.ConstantValueOpt == null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider splitting into two asserts.

@@ -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;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the second condition needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BoundKind.DefaultLiteral used to be BoundKind.DefaultOperator. Maybe I will rename it back.
But to answer your question, IsLiteralDefault should return false for default(int). It should only return true for the default literal.

@@ -1475,5 +1475,6 @@ internal enum ErrorCode

ERR_BadDynamicMethodArgDefault = 9000,
ERR_DefaultNotValid = 9001,
ERR_ExpressionTreeContainsDefaultLiteral = 9002,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the previous two values be renamed to use the term DefaultLiteral?

@@ -16,7 +16,7 @@ public static bool IsLiteralNull(this BoundExpression node)

public static bool IsLiteralDefault(this BoundExpression node)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps IsDefaultLiteral.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I used this seemingly strange name is because it matches IsLiteralNull (a few lines above).


public override BoundNode VisitDefaultLiteral(BoundDefaultLiteral node)
{
if (_inExpressionLambda && node.IsLiteralDefault())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to earlier question: When will node.IsLiteralDefault() return false?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is default not allowed in an expression lambda?

string source = @"
enum E
{
Entry = default
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps test Entry = default + 1 as well.

{
System.Console.Write(default as long);
System.Console.Write(default as T);
}
}";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we testing default as T with constraints on T?

enum E
{
DefaultEntry = default,
OneEntry = default + 1
Copy link
Member Author

@jcouv jcouv Mar 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chuck asked why this works. I'll follow up.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to guess that overload resolution finds a most specific overload of operator + that is applicable, and the result is a constant.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, overload resolution succeeds, then the left and right operands get converted, which gives default an int type.

@cston
Copy link
Member

cston commented Mar 29, 2017

LGTM

@jcouv
Copy link
Member Author

jcouv commented Mar 31, 2017

@gafter @dotnet/roslyn-compiler for a second review. Thanks

@jcouv jcouv force-pushed the default-LDM branch 2 times, most recently from 248f8a4 to 9bf3a6e Compare March 31, 2017 03:07
@@ -773,11 +773,6 @@ private BoundExpression BindDeclarationVariables(TypeSymbol declType, VariableDe
}
}

private static BoundExpression BindDefaultLiteral(DefaultLiteralSyntax node)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private static BoundExpression BindDefaultLiteral(DefaultLiteralSyntax node) [](start = 8, length = 76)

I would keep this method.

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSharp7_1 [](start = 141, length = 9)

Should we simply use Latest here?

@@ -3540,8 +3540,7 @@ public void TestTargetTypedDefault()
var expr = this.ParseExpression(text, TestOptions.ExperimentalParseOptions);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExperimentalParseOptions [](start = 62, length = 24)

This is the only test in this file that is using ExperimentalParseOptions. Consider changing it to use CSharp7 and have have a test with 7.1 next to other default tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to use 7.1 explicitly (instead of Experimental, which now means Latest). But I didn't move it because this parsing test relies on base type (ParsingTests) for some infrastructure.

I already had a test for diagnostics in 7.0 scenario:

   [Fact]
        public void TestCSharp7()
        {
            string source = @"
class C
{
    static void Main()
    {
        int x = default;
    }
}
";
            var comp = CreateCompilationWithMscorlib(source);
            comp.VerifyDiagnostics(
                // (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_FeatureNotAvailableInVersion7, "default").WithArguments("default literal", "7.1").WithLocation(6, 17)
                );
        }

Let me know if that addresses your concern.

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@AlekseyTs
Copy link
Contributor

Still LGTM

@jcouv
Copy link
Member Author

jcouv commented Apr 4, 2017

Thanks :-)

@jcouv jcouv merged commit cc1aeba into dotnet:features/default Apr 4, 2017
@jcouv jcouv deleted the default-LDM branch April 4, 2017 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants