-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Prototype: target typed "default" #13603
Conversation
e8ebe81
to
78446ac
Compare
78446ac
to
14592f6
Compare
@@ -918,6 +918,21 @@ | |||
<summary>Creates an DefaultExpressionSyntax node.</summary> | |||
</FactoryComment> | |||
</Node> | |||
<Node Name="TargetTypedDefaultExpressionSyntax" Base="ExpressionSyntax"> |
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.
TargetTypedDefaultExpressionSyntax [](start = 14, length = 34)
I suggest a more likely name in the grammar is "default literal". #Resolved
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.
That sounds better ;-) I was just hesitant to use the term literal. #Resolved
These cases should be unified. The problem is that the left-hand-side doesn't have a type. Use BoundExpression.Display for the string form of the problematic expression. Refers to: src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs:4864 in 14592f6. [](commit_id = 14592f6, deletion_comment = False) |
@@ -114,7 +114,7 @@ private static ImmutableArray<MethodSymbol> GetOriginalMethods(OverloadResolutio | |||
boundExpression.WasCompilerGenerated = true; | |||
|
|||
var analyzedArguments = AnalyzedArguments.GetInstance(); | |||
Debug.Assert(!args.Any(e => e.Kind == BoundKind.OutVarLocalPendingInference || e.Kind == BoundKind.OutDeconstructVarPendingInference)); | |||
Debug.Assert(!args.Any(e => e.Kind == BoundKind.OutVarLocalPendingInference || e.Kind == BoundKind.OutDeconstructVarPendingInference || e.Kind == BoundKind.DefaultPendingInference)); | |||
analyzedArguments.Arguments.AddRange(args); |
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.
In a bad invocation, it should be capable of remaining in the bound tree. #Resolved
4d9a6ca
to
3a0e1a2
Compare
@@ -4830,6 +4835,15 @@ private bool IsUsingAliasInScope(string name) | |||
return BadExpression(node, boundLeft); | |||
} | |||
|
|||
// PROTOTYPE(default) unify with case above | |||
// No member accesses on 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.
I would expect this case (and the following one handling UnboundLambda) to be handled in the call to MakeMemberAccessValue
. That call should never return a typeless expression.
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 looked into this and it was thorny.
What I tried was to have MakeMemberAccessValue
return a BadExpression
and report an error for those two cases. But it made the diagnostics significantly worse in a number of cases (especially lambda). I'll stop by to discuss tomorrow.
201c702
to
d89b2e9
Compare
@AlekseyTs @cston If you had some time, would you mind doing a second code review. This is going to features/default branch. |
if (boundLeft.IsLiteralDefault()) | ||
{ | ||
DiagnosticInfo diagnosticInfo = new CSDiagnosticInfo(ErrorCode.ERR_BadUnaryOp, SyntaxFacts.GetText(operatorToken.Kind()), "default"); | ||
diagnostics.Add(new CSDiagnostic(diagnosticInfo, operatorToken.GetLocation())); |
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.
diagnostics.Add(ErrorCode.ERR_BadUnaryOp, ...);
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.
Fixed
// return; | ||
//} | ||
|
||
if (!targetType.IsStructType() || targetType.IsNullableType()) |
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.
Would targetType.IsReferenceType
cover both type parameters and actual types?
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 not support default
for reference types?
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.
Whether default
should be allowed on reference types is listed as an open LDM question. But the more I discuss with folks and the clearer it is that folks want to allow it. I'll remove this check.
return Conversion.DefaultLiteral; | ||
} | ||
|
||
return Conversion.NoConversion; |
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 are valid conversions limited to struct types?
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 idea was that you should use null
for ref types and default
for struct types. But there is also an argument that default
should be allowed anywhere default(type)
was previous allowed.
I'll remove
@@ -14,6 +14,11 @@ public static bool IsLiteralNull(this BoundExpression node) | |||
return node.Kind == BoundKind.Literal && node.ConstantValue.Discriminator == ConstantValueTypeDiscriminator.Null; | |||
} | |||
|
|||
public static bool IsLiteralDefault(this BoundExpression node) | |||
{ | |||
return node.Kind == BoundKind.DefaultOperator && (object)node.Type == 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.
Will node.Type == null
in error situations such as default(System)
? Should this method check syntax instead?
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 tried that and found that node.Type
will be ErrorType
in that scenario.
"; | ||
var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); | ||
comp.VerifyEmitDiagnostics(); | ||
CompileAndVerify(comp, expectedOutput: "0"); |
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.
What is the type of default
in int x = (short)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.
Good question. I expect it should be short
. I'll put a PROTOTYPE test to remind to check that once semantic model work is done.
782cb20
to
b56e513
Compare
@cston Would you have time to finish the review? The review feedback so far was addressed :-) |
// No member accesses on default | ||
if (boundLeft.IsLiteralDefault()) | ||
{ | ||
DiagnosticInfo diagnosticInfo = new CSDiagnosticInfo(ErrorCode.ERR_BadUnaryOp, SyntaxFacts.GetText(operatorToken.Kind()), "default"); | ||
diagnostics.Add(new CSDiagnostic(diagnosticInfo, operatorToken.GetLocation())); |
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.
diagnostics.Add(ErrorCode.ERR_BadUnaryOp, ...);
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.
Fixed. Thanks
<summary>Class which represents the syntax node for a default literal.</summary> | ||
</TypeComment> | ||
<FactoryComment> | ||
<summary>Creates an DefaultLiteralSyntax node.</summary> |
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.
Creates a ...
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.
Fixed this one and others
} | ||
|
||
[Fact] | ||
public void ReturnRefType() |
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.
Minor point: int?
is not a reference type.
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.
Renamed
// default.ToString(); | ||
Diagnostic(ErrorCode.ERR_BadUnaryOp, ".").WithArguments(".", "default").WithLocation(6, 16) | ||
); | ||
} |
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: default[0]
, nameof(default)
, throw 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.
I always love test ideas :-) Added!
LGTM |
Oh yeah |
Conflicts: src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionKind.cs src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionKindExtensions.cs src/Compilers/CSharp/Portable/Errors/MessageID.cs src/Compilers/CSharp/Portable/Parser/LanguageParser.cs src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt src/Compilers/CSharp/Portable/Syntax/Syntax.xml src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs src/Compilers/CSharp/Test/Semantic/CSharpCompilerSemanticTest.csproj src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs src/Test/Utilities/Desktop/TestResource.resx src/Test/Utilities/Shared/Traits/CompilerFeature.cs
Allow
int x = default;
andM(default);
where the type ofdefault
is inferred.Design notes (updated):
BoundDefaultOperator
without a type.DefaultLiteral
). "default" can convert to any struct and non-nullable type.BoundDefaultOperator
with the target type of the conversion.CC @dotnet/roslyn-compiler for review. This is low-pri (not for C# 7).