Skip to content

Commit

Permalink
Implement pattern-matching in the nullable walker
Browse files Browse the repository at this point in the history
  • Loading branch information
Neal Gafter authored and gafter committed Mar 19, 2019
1 parent fb51650 commit ebe1e7f
Show file tree
Hide file tree
Showing 49 changed files with 2,576 additions and 1,746 deletions.
12 changes: 7 additions & 5 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,8 @@ private BoundExpression BindTypeOf(TypeOfExpressionSyntax node, DiagnosticBag di

TypeofBinder typeofBinder = new TypeofBinder(typeSyntax, this); //has special handling for unbound types
AliasSymbol alias;
TypeSymbol type = typeofBinder.BindType(typeSyntax, diagnostics, out alias).Type;
TypeWithAnnotations typeWithAnnotations = typeofBinder.BindType(typeSyntax, diagnostics, out alias);
TypeSymbol type = typeWithAnnotations.Type;

bool hasError = false;

Expand All @@ -1133,19 +1134,20 @@ private BoundExpression BindTypeOf(TypeOfExpressionSyntax node, DiagnosticBag di
hasError = true;
}

BoundTypeExpression boundType = new BoundTypeExpression(typeSyntax, alias, type, type.IsErrorType());
BoundTypeExpression boundType = new BoundTypeExpression(typeSyntax, alias, typeWithAnnotations, type.IsErrorType());
return new BoundTypeOfOperator(node, boundType, null, this.GetWellKnownType(WellKnownType.System_Type, diagnostics, node), hasError);
}

private BoundExpression BindSizeOf(SizeOfExpressionSyntax node, DiagnosticBag diagnostics)
{
ExpressionSyntax typeSyntax = node.Type;
AliasSymbol alias;
TypeSymbol type = this.BindType(typeSyntax, diagnostics, out alias).Type;
TypeWithAnnotations typeWithAnnotations = this.BindType(typeSyntax, diagnostics, out alias);
TypeSymbol type = typeWithAnnotations.Type;

bool typeHasErrors = type.IsErrorType() || CheckManagedAddr(type, node, diagnostics);

BoundTypeExpression boundType = new BoundTypeExpression(typeSyntax, alias, type, typeHasErrors);
BoundTypeExpression boundType = new BoundTypeExpression(typeSyntax, alias, typeWithAnnotations, typeHasErrors);
ConstantValue constantValue = GetConstantSizeOf(type);
bool hasErrors = ReferenceEquals(constantValue, null) && ReportUnsafeIfNotAllowed(node, diagnostics, type);
return new BoundSizeOfOperator(node, boundType, constantValue,
Expand Down Expand Up @@ -5716,7 +5718,7 @@ private BoundExpression BindMemberAccessWithBoundLeft(
Error(diagnostics, lookupResult.Error, right);

return new BoundTypeExpression(node, null,
new ExtendedErrorTypeSymbol(GetContainingNamespaceOrType(symbols[0]), symbols.ToImmutable(), lookupResult.Kind, lookupResult.Error, rightArity));
new ExtendedErrorTypeSymbol(GetContainingNamespaceOrType(symbols[0]), symbols.ToImmutable(), lookupResult.Kind, lookupResult.Error, rightArity));
}
else if (lookupResult.Kind == LookupResultKind.Empty)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2783,7 +2783,7 @@ private BoundExpression BindIsOperator(BinaryExpressionSyntax node, DiagnosticBa
operandHasErrors = true;
}

var typeExpression = new BoundTypeExpression(node.Right, alias, targetType);
var typeExpression = new BoundTypeExpression(node.Right, alias, targetTypeWithAnnotations);
var targetTypeKind = targetType.TypeKind;
if (operandHasErrors || IsOperatorErrors(node, operand.Type, typeExpression, diagnostics))
{
Expand Down Expand Up @@ -3151,7 +3151,7 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa
AliasSymbol alias;
TypeWithAnnotations targetTypeWithAnnotations = BindType(node.Right, diagnostics, out alias);
TypeSymbol targetType = targetTypeWithAnnotations.Type;
var typeExpression = new BoundTypeExpression(node.Right, alias, targetType);
var typeExpression = new BoundTypeExpression(node.Right, alias, targetTypeWithAnnotations);
var targetTypeKind = targetType.TypeKind;
var resultType = targetType;

Expand Down
33 changes: 18 additions & 15 deletions src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ private BoundPattern BindDeclarationPattern(
TypeSymbol declType = boundDeclType.Type;
inputValEscape = GetValEscape(declType, inputValEscape);
BindPatternDesignation(
node.Designation, boundDeclType.Type, inputValEscape, typeSyntax, diagnostics,
node.Designation, boundDeclType.TypeWithAnnotations, inputValEscape, typeSyntax, diagnostics,
ref hasErrors, out Symbol variableSymbol, out BoundExpression variableAccess);
return new BoundDeclarationPattern(node, variableSymbol, variableAccess, boundDeclType, isVar: false, inputType, hasErrors);
}
Expand All @@ -379,14 +379,14 @@ private BoundTypeExpression BindPatternType(
TypeWithAnnotations declType = BindType(typeSyntax, diagnostics, out AliasSymbol aliasOpt);
Debug.Assert(declType.HasType);
Debug.Assert(typeSyntax.Kind() != SyntaxKind.NullableType); // the syntax does not permit nullable annotations
BoundTypeExpression boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: false, type: declType.Type);
BoundTypeExpression boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: false, type: declType);
hasErrors |= CheckValidPatternType(typeSyntax, inputType, declType.Type, patternTypeWasInSource: true, diagnostics: diagnostics);
return boundDeclType;
}

private void BindPatternDesignation(
VariableDesignationSyntax designation,
TypeSymbol declType,
TypeWithAnnotations declType,
uint inputValEscape,
TypeSyntax typeSyntax,
DiagnosticBag diagnostics,
Expand All @@ -405,18 +405,18 @@ private void BindPatternDesignation(
if ((InConstructorInitializer || InFieldInitializer) && ContainingMemberOrLambda.ContainingSymbol.Kind == SymbolKind.NamedType)
CheckFeatureAvailability(designation, MessageID.IDS_FeatureExpressionVariablesInQueriesAndInitializers, diagnostics);

localSymbol.SetTypeWithAnnotations(TypeWithAnnotations.Create(declType));
localSymbol.SetValEscape(GetValEscape(declType, inputValEscape));
localSymbol.SetTypeWithAnnotations(declType);
localSymbol.SetValEscape(GetValEscape(declType.Type, inputValEscape));

// Check for variable declaration errors.
hasErrors |= localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics);

if (!hasErrors)
hasErrors = CheckRestrictedTypeInAsync(this.ContainingMemberOrLambda, declType, diagnostics, typeSyntax ?? (SyntaxNode)designation);
hasErrors = CheckRestrictedTypeInAsync(this.ContainingMemberOrLambda, declType.Type, diagnostics, typeSyntax ?? (SyntaxNode)designation);

variableSymbol = localSymbol;
variableAccess = new BoundLocal(
syntax: designation, localSymbol: localSymbol, constantValueOpt: null, type: declType);
syntax: designation, localSymbol: localSymbol, constantValueOpt: null, type: declType.Type);
return;
}
else
Expand All @@ -425,7 +425,7 @@ private void BindPatternDesignation(
Debug.Assert(designation.SyntaxTree.Options.Kind != SourceCodeKind.Regular);
GlobalExpressionVariable expressionVariableField = LookupDeclaredField(singleVariableDesignation);
DiagnosticBag tempDiagnostics = DiagnosticBag.GetInstance();
expressionVariableField.SetTypeWithAnnotations(TypeWithAnnotations.Create(declType), tempDiagnostics);
expressionVariableField.SetTypeWithAnnotations(declType, tempDiagnostics);
tempDiagnostics.Free();
BoundExpression receiver = SynthesizeReceiver(designation, expressionVariableField, diagnostics);

Expand Down Expand Up @@ -454,7 +454,7 @@ private static uint GetValEscape(TypeSymbol type, uint possibleValEscape)
return type.IsRefLikeType ? possibleValEscape : Binder.ExternalScope;
}

TypeSymbol BindRecursivePatternType(
TypeWithAnnotations BindRecursivePatternType(
TypeSyntax typeSyntax,
TypeSymbol inputType,
DiagnosticBag diagnostics,
Expand All @@ -464,12 +464,13 @@ TypeSymbol BindRecursivePatternType(
if (typeSyntax != null)
{
boundDeclType = BindPatternType(typeSyntax, inputType, diagnostics, ref hasErrors);
return boundDeclType.Type;
return boundDeclType.TypeWithAnnotations;
}
else
{
boundDeclType = null;
return inputType.StrippedType(); // remove the nullable part of the input's type
// remove the nullable part of the input's type; e.g. a nullable int becomes an int in a recursive pattern
return new TypeWithState(inputType.StrippedType(), NullableFlowState.MaybeNull).ToTypeWithAnnotations();
}
}

Expand All @@ -493,7 +494,8 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbo
}

TypeSyntax typeSyntax = node.Type;
TypeSymbol declType = BindRecursivePatternType(typeSyntax, inputType, diagnostics, ref hasErrors, out BoundTypeExpression boundDeclType);
TypeWithAnnotations declTypeWithAnnotations = BindRecursivePatternType(typeSyntax, inputType, diagnostics, ref hasErrors, out BoundTypeExpression boundDeclType);
TypeSymbol declType = declTypeWithAnnotations.Type;
inputValEscape = GetValEscape(declType, inputValEscape);

MethodSymbol deconstructMethod = null;
Expand Down Expand Up @@ -553,7 +555,7 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbo
}

BindPatternDesignation(
node.Designation, declType, inputValEscape, typeSyntax, diagnostics,
node.Designation, declTypeWithAnnotations, inputValEscape, typeSyntax, diagnostics,
ref hasErrors, out Symbol variableSymbol, out BoundExpression variableAccess);
return new BoundRecursivePattern(
syntax: node, declaredType: boundDeclType, inputType: inputType, deconstructMethod: deconstructMethod,
Expand Down Expand Up @@ -839,10 +841,11 @@ private BoundPattern BindVarDesignation(
}
case SyntaxKind.SingleVariableDesignation:
{
var declType = new TypeWithState(inputType, NullableFlowState.MaybeNull).ToTypeWithAnnotations();
BindPatternDesignation(
designation: node, declType: inputType, inputValEscape: inputValEscape, typeSyntax: null, diagnostics: diagnostics, hasErrors: ref hasErrors,
designation: node, declType: declType, inputValEscape: inputValEscape, typeSyntax: null, diagnostics: diagnostics, hasErrors: ref hasErrors,
variableSymbol: out Symbol variableSymbol, variableAccess: out BoundExpression variableAccess);
var boundOperandType = new BoundTypeExpression(syntax: node, aliasOpt: null, type: inputType); // fake a type expression for the variable's type
var boundOperandType = new BoundTypeExpression(syntax: node, aliasOpt: null, type: declType); // fake a type expression for the variable's type
// We continue to use a BoundDeclarationPattern for the var pattern, as they have more in common.
return new BoundDeclarationPattern(
node.Parent.Kind() == SyntaxKind.VarPattern ? node.Parent : node, // for `var x` use whole pattern, otherwise use designation for the syntax
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,7 @@ protected BoundLocalDeclaration BindVariableDeclaration(
}

diagnostics.AddRangeAndFree(localDiagnostics);
var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declTypeOpt.Type);
var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declTypeOpt);
return new BoundLocalDeclaration(associatedSyntaxNode, localSymbol, boundDeclType, initializerOpt, arguments, hasErrors);
}

Expand Down
Loading

0 comments on commit ebe1e7f

Please sign in to comment.