-
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
More tests and suggestions on default literal #18604
Conversation
"; | ||
|
||
var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); | ||
comp.VerifyDiagnostics(); // Should give an error. Follow-up issue: https://github.com/dotnet/roslyn/issues/18609 |
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.
using (null) { }
and using (default(System.IDisposable)) { }
do not generate errors.
// F(async () => await default); | ||
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("C.F<T>(System.Threading.Tasks.Task<T>)").WithLocation(8, 9) | ||
); | ||
} |
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 testing:
using System.Threading.Tasks;
class C
{
static async Task<T> F<T>()
{
await Task.Delay(0);
return default;
}
}
LGTM |
@dotnet/roslyn-compiler for review. This is mostly adding tests from discussion with Chuck so that I can merge "default" back into master. |
"; | ||
var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); | ||
comp.VerifyDiagnostics(); | ||
CompileAndVerify(comp, expectedOutput: "reached"); |
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 add Console.WriteLine
to operator==
.
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.
A couple of issues noted in this review:
// (14,17): error CS1031: Type expected | ||
// default(); | ||
Diagnostic(ErrorCode.ERR_TypeExpected, ")").WithLocation(14, 17), | ||
// (6,17): error CS8119: The switch expression must be a value; found 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 think the word default in this diagnostic should have some kind of quotes around it. It isn't a word of the sentence, it is referring to syntax in the source. #Resolved
// (16,19): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer | ||
// int i = ++default; | ||
Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "default"), | ||
// (17,26): error CS0828: Cannot assign default to anonymous type property |
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.
Here too. #Resolved
"; | ||
var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); | ||
comp.VerifyDiagnostics( | ||
// (11,13): error CS0023: Operator '!' cannot be applied to operand of type '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.
Looking at the specification, this is incorrect:
For an operation of the form
!x
, unary operator overload resolution (§13.4.4) is applied to select a specific operator implementation. The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. Only one predefined logical negation operator exists:bool operator !(bool x);This operator computes the logical negation of the operand: If the operand is true, the result is false. If the operand is false, the result is true.
Lifted (§13.4.8) forms of the unlifted predefined logical negation operator defined above are also predefined.
#Resolved
{ | ||
M(); | ||
} | ||
static void M(System.Threading.CancellationToken x = 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.
YES! #Resolved
@cston This is ready for review. |
@@ -2180,7 +2180,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper | |||
{ | |||
UnaryOperatorKind kind = SyntaxKindToUnaryOperatorKind(node.Kind()); | |||
|
|||
bool isOperandTypeNull = (object)operand.Type == null; | |||
bool isOperandTypeNull = operand.IsLiteralNull(); | |||
if (isOperandTypeNull) |
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 reporting an error for an operand with no type, for instance BoundMethodGroup
?
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, added test for method group and null
.
Assert.Equal(default(DkmEvaluationResultCategory), resultProperties.Category); // Not Data | ||
Assert.Equal(default(DkmEvaluationResultAccessType), resultProperties.AccessType); // Not Public | ||
Assert.Equal(default(DkmEvaluationResultStorageType), resultProperties.StorageType); | ||
Assert.Equal(default(DkmEvaluationResultTypeModifierFlags), resultProperties.ModifierFlags); // Not Virtual |
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.
Please call VerifyIL()
.
|
||
var testData3 = new CompilationTestData(); | ||
context.CompileExpression("default", DkmEvaluationFlags.None, ImmutableArray<Alias>.Empty, out error, testData3); | ||
Assert.Null(error); |
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 target 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.
It's object
.
The reason is that the EE adds a conversion:
private static BoundStatement BindExpression(Binder binder, ExpressionSyntax syntax, DiagnosticBag diagnostics, out ResultProperties resultProperties)
{
...
var expressionType = expression.Type;
if ((object)expressionType == null)
{
expression = binder.CreateReturnConversion(
syntax,
diagnostics,
expression,
RefKind.None,
binder.Compilation.GetSpecialType(SpecialType.System_Object));
if (diagnostics.HasAnyErrors())
{
resultProperties = default(ResultProperties);
return 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.
Thanks. Consider adding Assert.Equal(SpecialType.Object, method.ReturnType.SpecialType);
here in that case.
@@ -3766,6 +3766,65 @@ static void Main() | |||
}); | |||
} | |||
|
|||
[Fact] | |||
public void AssignDefaultToLocal() |
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 moving to ExpressionCompilerTests
. LocalsTests
was, at least initially, intended for testing CompileGetLocals
.
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
@@ -210,7 +210,7 @@ private static InternalSyntax.ExpressionSyntax ParseDebuggerExpressionInternal(S | |||
private static StatementSyntax ParseDebuggerStatement(string text) | |||
{ | |||
var source = SourceText.From(text); | |||
using (var lexer = new InternalSyntax.Lexer(source, CSharpParseOptions.Default)) | |||
using (var lexer = new InternalSyntax.Lexer(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest))) |
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.
Please create a helper method for ParseOptions
.
}"); | ||
|
||
testData = new CompilationTestData(); | ||
context.CompileExpression("a = default;", DkmEvaluationFlags.None, ImmutableArray<Alias>.Empty, out error, testData); |
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 testing a non-expression statement (perhaps "int b = default;") to avoid having these succeed by falling back to expression parsing.
@@ -194,9 +194,11 @@ private static ExpressionSyntax ParseDebuggerExpression(string text, bool consum | |||
return expression.MakeDebuggerExpression(source); | |||
} | |||
|
|||
static CSharpParseOptions GetCSharpParseOptions() => CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest); |
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 making this a static readonly
field.
LGTM |
@cston I'll stop by to discuss