-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Conversation
732750c
to
86928ce
Compare
@@ -5012,49 +5012,6 @@ static void Main(string[] args) | |||
expectedOutput: expectedOutput); | |||
} | |||
|
|||
[Fact] | |||
public void EnumEqualityWithDefault() |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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; | |||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps IsDefaultLiteral
.
There was a problem hiding this comment.
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()) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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); | ||
} | ||
}"; |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
LGTM |
@gafter @dotnet/roslyn-compiler for a second review. Thanks |
248f8a4
to
9bf3a6e
Compare
@@ -773,11 +773,6 @@ private BoundExpression BindDeclarationVariables(TypeSymbol declType, VariableDe | |||
} | |||
} | |||
|
|||
private static BoundExpression BindDefaultLiteral(DefaultLiteralSyntax node) |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Still LGTM |
Thanks :-) |
LiteralExpressionSyntax
instead of introducing a new syntax nodedefault is T
, allowx is default
, allowdefault as RefType
(with always-null warning)@cston @gafter @dotnet/roslyn-compiler for review.
Fixes #17478
Relates to #13602