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

Prototype: target typed "default" #13603

Merged
merged 9 commits into from
Sep 21, 2016
Merged

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Sep 4, 2016

Allow int x = default; and M(default); where the type of default is inferred.

Design notes (updated):

  • Introduces a new syntax node for target-typed default.
  • During initial binding, this is represented by a BoundDefaultOperator without a type.
  • A new kind of conversion is introduced (DefaultLiteral). "default" can convert to any struct and non-nullable type.
  • During lowering, this conversion produces a BoundDefaultOperator with the target type of the conversion.
  • "default" contributes to overload resolution, by excluding parameters that are nullable.
  • Some language question recorded in Prototype: target typed "default" #13602

CC @dotnet/roslyn-compiler for review. This is low-pri (not for C# 7).

@@ -918,6 +918,21 @@
<summary>Creates an DefaultExpressionSyntax node.</summary>
</FactoryComment>
</Node>
<Node Name="TargetTypedDefaultExpressionSyntax" Base="ExpressionSyntax">
Copy link
Member

@gafter gafter Sep 5, 2016

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

Copy link
Member Author

@jcouv jcouv Sep 5, 2016

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

@gafter
Copy link
Member

gafter commented Sep 5, 2016

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

@gafter gafter Sep 5, 2016

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

@@ -4830,6 +4835,15 @@ private bool IsUsingAliasInScope(string name)
return BadExpression(node, boundLeft);
}

// PROTOTYPE(default) unify with case above
// No member accesses on default
Copy link
Member

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.

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 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.

@gafter
Copy link
Member

gafter commented Sep 12, 2016

:shipit:

@gafter gafter removed their assignment Sep 12, 2016
@jcouv jcouv force-pushed the features/default branch 2 times, most recently from 201c702 to d89b2e9 Compare September 13, 2016 19:49
@jcouv
Copy link
Member Author

jcouv commented Sep 16, 2016

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

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, ...);

Copy link
Member Author

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())
Copy link
Member

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?

Copy link
Member

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?

Copy link
Member Author

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

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?

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

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?

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

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;?

Copy link
Member Author

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.

@jcouv
Copy link
Member Author

jcouv commented Sep 20, 2016

@gafter @cston, I removed the constraint that default should only work on struct types.

@jcouv
Copy link
Member Author

jcouv commented Sep 20, 2016

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

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, ...);

Copy link
Member Author

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>
Copy link
Member

Choose a reason for hiding this comment

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

Creates a ...

Copy link
Member Author

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()
Copy link
Member

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.

Copy link
Member Author

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)
);
}
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: default[0], nameof(default), throw default;

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 always love test ideas :-) Added!

@cston
Copy link
Member

cston commented Sep 21, 2016

LGTM

@jcouv jcouv merged commit 4ecd4cd into dotnet:features/default Sep 21, 2016
@jcouv jcouv deleted the features/default branch September 21, 2016 19:40
@jcouv
Copy link
Member Author

jcouv commented Feb 2, 2017

@gafter This is the first part of the prototype on "default", which you had reviewed. The second part is #16425

@gafter
Copy link
Member

gafter commented Feb 3, 2017

Oh yeah

jcouv added a commit to jcouv/roslyn that referenced this pull request Mar 11, 2017
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
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.

4 participants