Skip to content

Commit

Permalink
* Permit the use of ITuple when Deconstruct exists but is ambiguous.
Browse files Browse the repository at this point in the history
* Permit 0-element and 1-element tuple patterns
Fixes dotnet#30962
Replaces dotnet#31027

* Handle null and nullable input for a var pattern with a tuple designation
Fixes dotnet#30906
Replaces dotnet#30935

* Don't report missing Deconstruct when there is more than one applicable Deconstruct
Fixes dotnet#31031
  • Loading branch information
gafter committed Nov 8, 2018
1 parent 69c39ed commit 102de2f
Show file tree
Hide file tree
Showing 31 changed files with 1,994 additions and 549 deletions.
20 changes: 9 additions & 11 deletions src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ private bool MakeDeconstructionConversion(

var inputPlaceholder = new BoundDeconstructValuePlaceholder(syntax, this.LocalScopeDepth, type);
BoundExpression deconstructInvocation = MakeDeconstructInvocationExpression(variables.Count,
inputPlaceholder, rightSyntax, diagnostics, outPlaceholders: out ImmutableArray<BoundDeconstructValuePlaceholder> outPlaceholders);
inputPlaceholder, rightSyntax, diagnostics, outPlaceholders: out ImmutableArray<BoundDeconstructValuePlaceholder> outPlaceholders, out _);

if (deconstructInvocation.HasAnyErrors)
{
Expand Down Expand Up @@ -600,8 +600,10 @@ private BoundExpression MakeDeconstructInvocationExpression(
BoundExpression receiver,
SyntaxNode rightSyntax,
DiagnosticBag diagnostics,
out ImmutableArray<BoundDeconstructValuePlaceholder> outPlaceholders)
out ImmutableArray<BoundDeconstructValuePlaceholder> outPlaceholders,
out bool anyApplicableCandidates)
{
anyApplicableCandidates = false;
var receiverSyntax = (CSharpSyntaxNode)receiver.Syntax;
if (receiver.Type.IsDynamic())
{
Expand Down Expand Up @@ -643,22 +645,18 @@ private BoundExpression MakeDeconstructInvocationExpression(
// So the generated invocation expression will contain placeholders instead of those outVar nodes.
// Those placeholders are also recorded in the outVar for easy access below, by the `SetInferredType` call on the outVar nodes.
BoundExpression result = BindMethodGroupInvocation(
rightSyntax, rightSyntax, methodName, (BoundMethodGroup)memberAccess, analyzedArguments, diagnostics, queryClause: null,
allowUnexpandedForm: true);
rightSyntax, rightSyntax, methodName, (BoundMethodGroup)memberAccess, analyzedArguments, diagnostics, queryClause: null,
allowUnexpandedForm: true, anyApplicableCandidates: out anyApplicableCandidates);

result.WasCompilerGenerated = true;

if (result.HasErrors && !receiver.HasAnyErrors)
{
return MissingDeconstruct(receiver, rightSyntax, numCheckedVariables, diagnostics, out outPlaceholders, result);
}

// Verify all the parameters (except "this" for extension methods) are out parameters
if (result.Kind != BoundKind.Call)
if (!anyApplicableCandidates)
{
return MissingDeconstruct(receiver, rightSyntax, numCheckedVariables, diagnostics, out outPlaceholders, result);
}

// Verify all the parameters (except "this" for extension methods) are out parameters.
// This prevents, for example, an unused params parameter after the out parameters.
var deconstructMethod = ((BoundCall)result).Method;
var parameters = deconstructMethod.Parameters;
for (int i = (deconstructMethod.IsExtensionMethod ? 1 : 0); i < parameters.Length; i++)
Expand Down
6 changes: 3 additions & 3 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1640,7 +1640,7 @@ protected virtual BoundExpression BindRangeVariable(SimpleNameSyntax node, Range
return Next.BindRangeVariable(node, qv, diagnostics);
}

private BoundExpression SynthesizeReceiver(CSharpSyntaxNode node, Symbol member, DiagnosticBag diagnostics)
private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, DiagnosticBag diagnostics)
{
// SPEC: Otherwise, if T is the instance type of the immediately enclosing class or
// struct type, if the lookup identifies an instance member, and if the reference occurs
Expand Down Expand Up @@ -1710,7 +1710,7 @@ internal Symbol ContainingMember()
return containingMember;
}

private BoundExpression TryBindInteractiveReceiver(CSharpSyntaxNode syntax, Symbol currentMember, NamedTypeSymbol currentType, NamedTypeSymbol memberDeclaringType)
private BoundExpression TryBindInteractiveReceiver(SyntaxNode syntax, Symbol currentMember, NamedTypeSymbol currentType, NamedTypeSymbol memberDeclaringType)
{
if (currentType.TypeKind == TypeKind.Submission && !currentMember.IsStatic)
{
Expand Down Expand Up @@ -1841,7 +1841,7 @@ private BoundThisReference BindThis(ThisExpressionSyntax node, DiagnosticBag dia
return ThisReference(node, this.ContainingType, hasErrors);
}

private BoundThisReference ThisReference(CSharpSyntaxNode node, NamedTypeSymbol thisTypeOpt, bool hasErrors = false, bool wasCompilerGenerated = false)
private BoundThisReference ThisReference(SyntaxNode node, NamedTypeSymbol thisTypeOpt, bool hasErrors = false, bool wasCompilerGenerated = false)
{
return new BoundThisReference(node, thisTypeOpt ?? CreateErrorType(), hasErrors) { WasCompilerGenerated = wasCompilerGenerated };
}
Expand Down
25 changes: 12 additions & 13 deletions src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,9 @@ private BoundExpression BindInvocationExpression(
}
else if (boundExpression.Kind == BoundKind.MethodGroup)
{
result = BindMethodGroupInvocation(node, expression, methodName, (BoundMethodGroup)boundExpression, analyzedArguments, diagnostics, queryClause, allowUnexpandedForm: allowUnexpandedForm);
result = BindMethodGroupInvocation(
node, expression, methodName, (BoundMethodGroup)boundExpression, analyzedArguments,
diagnostics, queryClause, allowUnexpandedForm: allowUnexpandedForm, anyApplicableCandidates: out _);
}
else if ((object)(delegateType = GetDelegateType(boundExpression)) != null)
{
Expand Down Expand Up @@ -555,14 +557,16 @@ private BoundExpression BindMethodGroupInvocation(
AnalyzedArguments analyzedArguments,
DiagnosticBag diagnostics,
CSharpSyntaxNode queryClause,
bool allowUnexpandedForm = true)
bool allowUnexpandedForm,
out bool anyApplicableCandidates)
{
BoundExpression result;
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
var resolution = this.ResolveMethodGroup(
methodGroup, expression, methodName, analyzedArguments, isMethodGroupConversion: false,
useSiteDiagnostics: ref useSiteDiagnostics, allowUnexpandedForm: allowUnexpandedForm);
diagnostics.Add(expression, useSiteDiagnostics);
anyApplicableCandidates = resolution.ResultKind == LookupResultKind.Viable && resolution.OverloadResolutionResult.HasAnyApplicableMember;

if (!methodGroup.HasAnyErrors) diagnostics.AddRange(resolution.Diagnostics); // Suppress cascading.

Expand Down Expand Up @@ -1105,13 +1109,8 @@ private BoundCall BindInvocationExpressionContinued(
diagnostics);
}

if ((object)delegateTypeOpt != null)
{
return new BoundCall(node, receiver, method, args, argNames, argRefKinds, isDelegateCall: true,
expanded: expanded, invokedAsExtensionMethod: invokedAsExtensionMethod,
argsToParamsOpt: argsToParams, resultKind: LookupResultKind.Viable, binderOpt: this, type: returnType, hasErrors: gotError);
}
else
bool isDelegateCall = (object)delegateTypeOpt != null;
if (!isDelegateCall)
{
if ((object)receiver != null && receiver.Kind == BoundKind.BaseReference && method.IsAbstract)
{
Expand All @@ -1127,11 +1126,11 @@ private BoundCall BindInvocationExpressionContinued(
receiver,
diagnostics);
}

return new BoundCall(node, receiver, method, args, argNames, argRefKinds, isDelegateCall: false,
expanded: expanded, invokedAsExtensionMethod: invokedAsExtensionMethod,
argsToParamsOpt: argsToParams, resultKind: LookupResultKind.Viable, binderOpt: this, type: returnType, hasErrors: gotError);
}

return new BoundCall(node, receiver, method, args, argNames, argRefKinds, isDelegateCall: isDelegateCall,
expanded: expanded, invokedAsExtensionMethod: invokedAsExtensionMethod,
argsToParamsOpt: argsToParams, resultKind: LookupResultKind.Viable, binderOpt: this, type: returnType, hasErrors: gotError);
}

private bool IsBindingModuleLevelAttribute()
Expand Down
Loading

0 comments on commit 102de2f

Please sign in to comment.