From 6c222d90f8772471dad65c1e115ca7bc53833a4a Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 24 Jan 2019 19:59:25 -0800 Subject: [PATCH] Revert most code changes --- .../Portable/Binder/Binder.ValueChecks.cs | 37 +-------- .../Portable/Binder/Binder_Conversions.cs | 36 ++++---- .../Portable/Binder/Binder_Expressions.cs | 80 +++++++----------- .../Portable/Binder/Binder_Invocation.cs | 45 +++------- .../Portable/Binder/Binder_Operators.cs | 83 +++++++------------ .../CSharp/Portable/Binder/Binder_Query.cs | 17 ++-- .../Portable/Binder/Binder_QueryErrors.cs | 1 - .../Portable/Binder/Binder_Statements.cs | 9 +- .../Semantics/Conversions/ConversionsBase.cs | 13 ++- .../BinaryOperatorOverloadResolution.cs | 2 +- .../OverloadResolution/MethodTypeInference.cs | 23 ++--- .../OverloadResolution/OverloadResolution.cs | 9 +- .../OverloadResolutionResult.cs | 13 ++- .../BoundTree/BoundExpressionExtensions.cs | 31 ------- .../Portable/FlowAnalysis/AbstractFlowPass.cs | 2 +- .../Portable/FlowAnalysis/NullableWalker.cs | 16 +--- .../DiagnosticsPass_ExpressionTrees.cs | 30 +------ .../LocalRewriter/LocalRewriter_Conversion.cs | 1 + ...ocalRewriter_DelegateCreationExpression.cs | 7 +- .../LocalRewriter/LocalRewriter_IsOperator.cs | 18 +++- .../LocalRewriter_StringInterpolation.cs | 3 +- 21 files changed, 162 insertions(+), 314 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index 6f87537d6eb64..40f081b0b7e50 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -209,9 +209,8 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind { var outer = (BoundSuppressNullableWarningExpression)expr; var inner = CheckValue(outer.Expression, valueKind, diagnostics); - expr = outer.Update(inner, inner.Type); + return outer.Update(inner, inner.Type); } - break; } bool hasResolutionErrors = false; @@ -325,12 +324,8 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin return CheckEventValueKind((BoundEventAccess)expr, valueKind, diagnostics); case BoundKind.SuppressNullableWarningExpression: - if (!IsLegalSuppressionValueKind(valueKind)) - { - Error(diagnostics, ErrorCode.ERR_IllegalSuppression, node); - return false; - } - + // https://github.com/dotnet/roslyn/issues/29710 We can reach this assertion + Debug.Assert(false); return CheckValueKind(node, ((BoundSuppressNullableWarningExpression)expr).Expression, valueKind, checkingReceiver, diagnostics); } @@ -525,23 +520,6 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin return false; } - private static bool IsLegalSuppressionValueKind(BindValueKind valueKind) - { - // Need to review allowed uses of the suppression operator - // Tracked by https://github.com/dotnet/roslyn/issues/31297 - - switch (valueKind) - { - case BindValueKind.RValue: - case BindValueKind.RValueOrMethodGroup: - case BindValueKind.RefOrOut: - return true; - } - - // all others are illegal - return false; - } - private static bool CheckNotNamespaceOrType(BoundExpression expr, DiagnosticBag diagnostics) { switch (expr.Kind) @@ -2422,10 +2400,6 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin // only possible in error cases (if possible at all) return scopeOfTheContainingExpression; - case BoundKind.SuppressNullableWarningExpression: - var suppressed = (BoundSuppressNullableWarningExpression)expr; - return GetValEscape(suppressed.Expression, scopeOfTheContainingExpression); - default: // in error situations some unexpected nodes could make here // returning "scopeOfTheContainingExpression" seems safer than throwing. @@ -2757,11 +2731,6 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint // only possible in error cases (if possible at all) return false; - case BoundKind.SuppressNullableWarningExpression: - // Need to implement and test escape rules for suppression operator - // Tracked by https://github.com/dotnet/roslyn/issues/31297 - goto default; - default: // in error situations some unexpected nodes could make here // returning "false" seems safer than throwing. diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 91a5e246dd06f..a5ec34756cdce 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -68,9 +68,6 @@ protected BoundExpression CreateConversion( // nothing else changes if (source.Kind == BoundKind.TupleLiteral) { - // We need to handle suppressed tuple literals as well - // Tracked by https://github.com/dotnet/roslyn/issues/32553 - var sourceTuple = (BoundTupleLiteral)source; TupleTypeSymbol.ReportNamesMismatchesIfAny(destination, sourceTuple, diagnostics); source = new BoundConvertedTupleLiteral( @@ -96,23 +93,19 @@ protected BoundExpression CreateConversion( return CreateMethodGroupConversion(syntax, source, conversion, isCast: isCast, conversionGroupOpt, destination, diagnostics); } - if (conversion.IsAnonymousFunction && source.KindIgnoringSuppressions() == BoundKind.UnboundLambda) + if (conversion.IsAnonymousFunction && source.Kind == BoundKind.UnboundLambda) { return CreateAnonymousFunctionConversion(syntax, source, conversion, isCast: isCast, conversionGroupOpt, destination, diagnostics); } if (conversion.IsStackAlloc) { - Debug.Assert(source.Kind != BoundKind.SuppressNullableWarningExpression); return CreateStackAllocConversion(syntax, source, conversion, isCast, conversionGroupOpt, destination, diagnostics); } if (conversion.IsTupleLiteralConversion || (conversion.IsNullable && conversion.UnderlyingConversions[0].IsTupleLiteralConversion)) { - // We need to handle suppressed tuple literals as well - // Tracked by https://github.com/dotnet/roslyn/issues/32553 - return CreateTupleLiteralConversion(syntax, (BoundTupleLiteral)source, conversion, isCast: isCast, conversionGroupOpt, destination, diagnostics); } @@ -124,10 +117,9 @@ protected BoundExpression CreateConversion( } ConstantValue constantValue = this.FoldConstantConversion(syntax, source, conversion, destination, diagnostics); - if (conversion.Kind == ConversionKind.DefaultOrNullLiteral && source.KindIgnoringSuppressions() == BoundKind.DefaultExpression) + if (conversion.Kind == ConversionKind.DefaultOrNullLiteral && source.Kind == BoundKind.DefaultExpression) { - var result = ((BoundDefaultExpression)source.RemoveSuppressions()).Update(constantValue, destination); - source = result.WrapWithSuppressionsFrom(source); + source = ((BoundDefaultExpression)source).Update(constantValue, destination); } return new BoundConversion( @@ -306,15 +298,13 @@ private static BoundExpression CreateAnonymousFunctionConversion(SyntaxNode synt // UNDONE: Figure out what to do about the error case, where a lambda // UNDONE: is converted to a delegate that does not match. What to surface then? - Debug.Assert(source.KindIgnoringSuppressions() == BoundKind.UnboundLambda); - var unboundLambda = (UnboundLambda)source.RemoveSuppressions(); + var unboundLambda = (UnboundLambda)source; var boundLambda = unboundLambda.Bind((NamedTypeSymbol)destination); diagnostics.AddRange(boundLambda.Diagnostics); - Debug.Assert(unboundLambda.WasCompilerGenerated == source.WasCompilerGenerated); return new BoundConversion( syntax, - boundLambda.WrapWithSuppressionsFrom(source), + boundLambda, conversion, @checked: false, explicitCastInCode: isCast, @@ -326,7 +316,7 @@ private static BoundExpression CreateAnonymousFunctionConversion(SyntaxNode synt private BoundExpression CreateMethodGroupConversion(SyntaxNode syntax, BoundExpression source, Conversion conversion, bool isCast, ConversionGroup conversionGroup, TypeSymbol destination, DiagnosticBag diagnostics) { - BoundMethodGroup group = FixMethodGroupWithTypeOrValue((BoundMethodGroup)source.RemoveSuppressions(), conversion, diagnostics); + BoundMethodGroup group = FixMethodGroupWithTypeOrValue((BoundMethodGroup)source, conversion, diagnostics); BoundExpression receiverOpt = group.ReceiverOpt; MethodSymbol method = conversion.Method; bool hasErrors = false; @@ -342,7 +332,7 @@ private BoundExpression CreateMethodGroupConversion(SyntaxNode syntax, BoundExpr hasErrors = true; } - return new BoundConversion(syntax, group.WrapWithSuppressionsFrom(source), conversion, @checked: false, explicitCastInCode: isCast, conversionGroup, constantValueOpt: ConstantValue.NotAvailable, type: destination, hasErrors: hasErrors) { WasCompilerGenerated = source.WasCompilerGenerated }; + return new BoundConversion(syntax, group, conversion, @checked: false, explicitCastInCode: isCast, conversionGroup, constantValueOpt: ConstantValue.NotAvailable, type: destination, hasErrors: hasErrors) { WasCompilerGenerated = source.WasCompilerGenerated }; } private BoundExpression CreateStackAllocConversion(SyntaxNode syntax, BoundExpression source, Conversion conversion, bool isCast, ConversionGroup conversionGroup, TypeSymbol destination, DiagnosticBag diagnostics) @@ -478,9 +468,19 @@ private BoundExpression CreateTupleLiteralConversion(SyntaxNode syntax, BoundTup return result; } + private static bool IsMethodGroupWithTypeOrValueReceiver(BoundNode node) + { + if (node.Kind != BoundKind.MethodGroup) + { + return false; + } + + return Binder.IsTypeOrValueExpression(((BoundMethodGroup)node).ReceiverOpt); + } + private BoundMethodGroup FixMethodGroupWithTypeOrValue(BoundMethodGroup group, Conversion conversion, DiagnosticBag diagnostics) { - if (!IsTypeOrValueExpression(group.ReceiverOpt)) + if (!IsMethodGroupWithTypeOrValueReceiver(group)) { return group; } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 140888048b6eb..5f757bf562b92 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -187,33 +187,28 @@ private BoundExpression ToBadExpression(BoundExpression expr, LookupResultKind r Debug.Assert(resultKind != LookupResultKind.Viable); TypeSymbol resultType = expr.Type; - BoundKind exprKind = expr.KindIgnoringSuppressions(); + BoundKind exprKind = expr.Kind; if (expr.HasAnyErrors && ((object)resultType != null || exprKind == BoundKind.UnboundLambda)) { return expr; } - var exprWithoutSuppressions = expr.RemoveSuppressions(); if (exprKind == BoundKind.BadExpression) { - var badExpression = (BoundBadExpression)exprWithoutSuppressions; - return badExpression - .Update(resultKind, badExpression.Symbols, badExpression.ChildBoundNodes, resultType) - .WrapWithSuppressionsFrom(expr); + var badExpression = (BoundBadExpression)expr; + return badExpression.Update(resultKind, badExpression.Symbols, badExpression.ChildBoundNodes, resultType); } else { - var symbols = ArrayBuilder.GetInstance(); - exprWithoutSuppressions.GetExpressionSymbols(symbols, parent: null, binder: this); - + ArrayBuilder symbols = ArrayBuilder.GetInstance(); + expr.GetExpressionSymbols(symbols, parent: null, binder: this); return new BoundBadExpression( - exprWithoutSuppressions.Syntax, + expr.Syntax, resultKind, symbols.ToImmutableAndFree(), - ImmutableArray.Create(exprWithoutSuppressions), - resultType ?? CreateErrorType()) - .WrapWithSuppressionsFrom(expr); + ImmutableArray.Create(expr), + resultType ?? CreateErrorType()); } } @@ -2071,8 +2066,6 @@ private void GenerateExplicitConversionErrors( BoundExpression operand, TypeSymbol targetType) { - operand = operand.RemoveSuppressions(); - // Make sure that errors within the unbound lambda don't get lost. if (operand.Kind == BoundKind.UnboundLambda) { @@ -3833,7 +3826,6 @@ private BoundExpression BindDelegateCreationExpression(ObjectCreationExpressionS } BoundExpression argument = analyzedArguments.Arguments.Count >= 1 ? analyzedArguments.Arguments[0] : null; - var argumentWithoutSuppressions = argument.RemoveSuppressions(); if (hasErrors) { @@ -3842,13 +3834,14 @@ private BoundExpression BindDelegateCreationExpression(ObjectCreationExpressionS // There are four cases for a delegate creation expression (7.6.10.5): // 1. An anonymous function is treated as a conversion from the anonymous function to the delegate type. - else if (argumentWithoutSuppressions is UnboundLambda unboundLambda) + else if (argument is UnboundLambda) { // analyzedArguments.HasErrors could be true, // but here the argument is an unbound lambda, the error comes from inside // eg: new Action(x => x.) // We should try to bind it anyway in order for intellisense to work. + UnboundLambda unboundLambda = (UnboundLambda)argument; HashSet useSiteDiagnostics = null; var conversion = this.Conversions.ClassifyConversionFromExpression(unboundLambda, type, ref useSiteDiagnostics); diagnostics.Add(node, useSiteDiagnostics); @@ -3871,7 +3864,7 @@ private BoundExpression BindDelegateCreationExpression(ObjectCreationExpressionS // Just stuff the bound lambda into the delegate creation expression. When we lower the lambda to // its method form we will rewrite this expression to refer to the method. - return new BoundDelegateCreationExpression(node, boundLambda.WrapWithSuppressionsFrom(argument), methodOpt: null, isExtensionMethod: false, type: type, hasErrors: !conversion.IsImplicit); + return new BoundDelegateCreationExpression(node, boundLambda, methodOpt: null, isExtensionMethod: false, type: type, hasErrors: !conversion.IsImplicit); } else if (analyzedArguments.HasErrors) @@ -3880,12 +3873,13 @@ private BoundExpression BindDelegateCreationExpression(ObjectCreationExpressionS } // 2. A method group - else if (argumentWithoutSuppressions.Kind == BoundKind.MethodGroup) + else if (argument.Kind == BoundKind.MethodGroup) { - var methodGroup = (BoundMethodGroup)argumentWithoutSuppressions; - hasErrors = MethodGroupConversionDoesNotExistOrHasErrors(methodGroup, type, node.Location, diagnostics, out Conversion conversion); + Conversion conversion; + BoundMethodGroup methodGroup = (BoundMethodGroup)argument; + hasErrors = MethodGroupConversionDoesNotExistOrHasErrors(methodGroup, type, node.Location, diagnostics, out conversion); methodGroup = FixMethodGroupWithTypeOrValue(methodGroup, conversion, diagnostics); - return new BoundDelegateCreationExpression(node, methodGroup.WrapWithSuppressionsFrom(argument), conversion.Method, conversion.IsExtensionMethod, type, hasErrors); + return new BoundDelegateCreationExpression(node, methodGroup, conversion.Method, conversion.IsExtensionMethod, type, hasErrors); } else if ((object)argument.Type == null) @@ -4193,7 +4187,6 @@ private BoundExpression BindObjectInitializerMember( resultKind = boundMember.ResultKind; hasErrors = boundMember.HasAnyErrors || implicitReceiver.HasAnyErrors; - Debug.Assert(boundMember.Kind != BoundKind.SuppressNullableWarningExpression || boundMember.KindIgnoringSuppressions() != BoundKind.PropertyGroup); if (boundMember.Kind == BoundKind.PropertyGroup) { boundMember = BindIndexedPropertyAccess((BoundPropertyGroup)boundMember, mustHaveAllOptionalParameters: true, diagnostics: diagnostics); @@ -5583,20 +5576,19 @@ private BoundExpression BindMemberAccessWithBoundLeft( return BadExpression(node, boundLeft); } - var boundLeftWithoutSuppressions = boundLeft.RemoveSuppressions(); // No member accesses on default - if (boundLeftWithoutSuppressions.IsLiteralDefault()) + if (boundLeft.IsLiteralDefault()) { DiagnosticInfo diagnosticInfo = new CSDiagnosticInfo(ErrorCode.ERR_BadUnaryOp, SyntaxFacts.GetText(operatorToken.Kind()), "default"); diagnostics.Add(new CSDiagnostic(diagnosticInfo, operatorToken.GetLocation())); return BadExpression(node, boundLeft); } - if (boundLeftWithoutSuppressions.Kind == BoundKind.UnboundLambda) + if (boundLeft.Kind == BoundKind.UnboundLambda) { Debug.Assert((object)leftType == null); - var msgId = ((UnboundLambda)boundLeft.RemoveSuppressions()).MessageID; + var msgId = ((UnboundLambda)boundLeft).MessageID; diagnostics.Add(ErrorCode.ERR_BadUnaryOp, node.Location, SyntaxFacts.GetText(operatorToken.Kind()), msgId.Localize()); return BadExpression(node, boundLeft); } @@ -5635,16 +5627,14 @@ private BoundExpression BindMemberAccessWithBoundLeft( var rightName = right.Identifier.ValueText; var rightArity = right.Arity; - switch (boundLeftWithoutSuppressions.Kind) + switch (boundLeft.Kind) { case BoundKind.NamespaceExpression: { // If K is zero and E is a namespace and E contains a nested namespace with name I, // then the result is that namespace. - errorIfSuppression(); - - var ns = ((BoundNamespaceExpression)boundLeftWithoutSuppressions).NamespaceSymbol; + var ns = ((BoundNamespaceExpression)boundLeft).NamespaceSymbol; HashSet useSiteDiagnostics = null; this.LookupMembersWithFallback(lookupResult, ns, rightName, rightArity, ref useSiteDiagnostics, options: options); diagnostics.Add(right, useSiteDiagnostics); @@ -5701,8 +5691,6 @@ private BoundExpression BindMemberAccessWithBoundLeft( case BoundKind.TypeExpression: { Debug.Assert((object)leftType != null); - errorIfSuppression(); - if (leftType.TypeKind == TypeKind.TypeParameter) { Error(diagnostics, ErrorCode.ERR_BadSKunknown, boundLeft.Syntax, leftType, MessageID.IDS_SK_TYVAR.Localize()); @@ -5735,7 +5723,7 @@ private BoundExpression BindMemberAccessWithBoundLeft( default: { // Can't dot into the null literal or stackalloc expressions. - if ((boundLeft.KindIgnoringSuppressions() == BoundKind.Literal && ((BoundLiteral)boundLeft.RemoveSuppressions()).ConstantValueOpt == ConstantValue.Null) || + if ((boundLeft.Kind == BoundKind.Literal && ((BoundLiteral)boundLeft).ConstantValueOpt == ConstantValue.Null) || boundLeft.Kind == BoundKind.StackAllocArrayCreation) { if (!boundLeft.HasAnyErrors) @@ -5761,14 +5749,6 @@ private BoundExpression BindMemberAccessWithBoundLeft( { lookupResult.Free(); } - - void errorIfSuppression() - { - if (boundLeft.Kind == BoundKind.SuppressNullableWarningExpression) - { - Error(diagnostics, ErrorCode.ERR_IllegalSuppression, boundLeft.Syntax); - } - } } private static void WarnOnAccessOfOffDefault(SyntaxNode node, BoundExpression boundLeft, DiagnosticBag diagnostics) @@ -5786,11 +5766,11 @@ private static void WarnOnAccessOfOffDefault(SyntaxNode node, BoundExpression bo /// private BoundExpression MakeMemberAccessValue(BoundExpression expr, DiagnosticBag diagnostics) { - switch (expr.KindIgnoringSuppressions()) + switch (expr.Kind) { case BoundKind.MethodGroup: { - var methodGroup = (BoundMethodGroup)expr.RemoveSuppressions(); + var methodGroup = (BoundMethodGroup)expr; HashSet useSiteDiagnostics = null; var resolution = this.ResolveMethodGroup(methodGroup, analyzedArguments: null, isMethodGroupConversion: false, useSiteDiagnostics: ref useSiteDiagnostics); diagnostics.Add(expr.Syntax, useSiteDiagnostics); @@ -5805,14 +5785,13 @@ private BoundExpression MakeMemberAccessValue(BoundExpression expr, DiagnosticBa Error(diagnostics, ErrorCode.ERR_BadSKunknown, methodGroup.NameSyntax, method, MessageID.IDS_SK_METHOD.Localize()); } } - expr = this.BindMemberAccessBadResult(methodGroup).WrapWithSuppressionsFrom(expr); + expr = this.BindMemberAccessBadResult(methodGroup); resolution.Free(); return expr; } case BoundKind.PropertyGroup: - return BindIndexedPropertyAccess((BoundPropertyGroup)expr.RemoveSuppressions(), mustHaveAllOptionalParameters: false, diagnostics: diagnostics) - .WrapWithSuppressionsFrom(expr); + return BindIndexedPropertyAccess((BoundPropertyGroup)expr, mustHaveAllOptionalParameters: false, diagnostics: diagnostics); default: return expr; @@ -7787,13 +7766,12 @@ private BoundExpression BindConditionalAccessReceiver(ConditionalAccessExpressio var operatorToken = node.OperatorToken; - if (receiver.KindIgnoringSuppressions() == BoundKind.UnboundLambda) + if (receiver.Kind == BoundKind.UnboundLambda) { - var lambda = (UnboundLambda)receiver.RemoveSuppressions(); - var msgId = lambda.MessageID; + var msgId = ((UnboundLambda)receiver).MessageID; DiagnosticInfo diagnosticInfo = new CSDiagnosticInfo(ErrorCode.ERR_BadUnaryOp, SyntaxFacts.GetText(operatorToken.Kind()), msgId.Localize()); diagnostics.Add(new CSDiagnostic(diagnosticInfo, node.Location)); - return BadExpression(receiverSyntax, lambda).WrapWithSuppressionsFrom(receiver); + return BadExpression(receiverSyntax, receiver); } var receiverType = receiver.Type; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index 945ea13a57d6c..b59378450844d 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -231,6 +231,7 @@ private BoundExpression BindInvocationExpression( bool allowUnexpandedForm = true) { BoundExpression result; + NamedTypeSymbol delegateType; if ((object)boundExpression.Type != null && boundExpression.Type.IsDynamic()) { @@ -239,21 +240,13 @@ private BoundExpression BindInvocationExpression( // invocation and let the lowering pass sort it out. result = BindDynamicInvocation(node, boundExpression, analyzedArguments, ImmutableArray.Empty, diagnostics, queryClause); } - else if (boundExpression.KindIgnoringSuppressions() == BoundKind.MethodGroup) + else if (boundExpression.Kind == BoundKind.MethodGroup) { - if (boundExpression.Kind == BoundKind.SuppressNullableWarningExpression) - { - diagnostics.Add(new CSDiagnosticInfo(ErrorCode.ERR_IllegalSuppression), expression.Location); - result = CreateBadCall(node, boundExpression, LookupResultKind.NotInvocable, analyzedArguments); - } - else - { - result = BindMethodGroupInvocation( - node, expression, methodName, (BoundMethodGroup)boundExpression, analyzedArguments, - diagnostics, queryClause, allowUnexpandedForm: allowUnexpandedForm, anyApplicableCandidates: out _); - } + result = BindMethodGroupInvocation( + node, expression, methodName, (BoundMethodGroup)boundExpression, analyzedArguments, + diagnostics, queryClause, allowUnexpandedForm: allowUnexpandedForm, anyApplicableCandidates: out _); } - else if (GetDelegateType(boundExpression) is NamedTypeSymbol delegateType) + else if ((object)(delegateType = GetDelegateType(boundExpression)) != null) { if (ReportDelegateInvokeUseSiteDiagnostic(diagnostics, delegateType, node: node)) { @@ -290,9 +283,6 @@ private BoundExpression BindDynamicInvocation( bool hasErrors = false; if (expression.Kind == BoundKind.MethodGroup) { - // We need to decide how to handle suppression operator in the middle of dynamic invocations - // Tracked by https://github.com/dotnet/roslyn/issues/32364 - BoundMethodGroup methodGroup = (BoundMethodGroup)expression; BoundExpression receiver = methodGroup.ReceiverOpt; @@ -490,12 +480,6 @@ private static bool ReportBadDynamicArguments( Error(diagnostics, ErrorCode.ERR_BadDynamicMethodArgDefaultLiteral, arg.Syntax); hasErrors = true; } - else if (arg.Kind == BoundKind.SuppressNullableWarningExpression) - { - // https://github.com/dotnet/roslyn/issues/32364 Need to clarify behavior of dynamic and nullability - Error(diagnostics, ErrorCode.ERR_IllegalSuppression, arg.Syntax); - hasErrors = true; - } else { // Lambdas,anonymous methods and method groups are the typeless expressions that @@ -1354,7 +1338,7 @@ private ImmutableArray BuildArgumentsForErrorRecovery(AnalyzedA } int argumentCount = analyzedArguments.Arguments.Count; - var newArguments = ArrayBuilder.GetInstance(argumentCount); + ArrayBuilder newArguments = ArrayBuilder.GetInstance(argumentCount); newArguments.AddRange(analyzedArguments.Arguments); for (int i = 0; i < argumentCount; i++) { @@ -1364,12 +1348,12 @@ private ImmutableArray BuildArgumentsForErrorRecovery(AnalyzedA continue; } - switch (argument.KindIgnoringSuppressions()) + switch (argument.Kind) { case BoundKind.UnboundLambda: { // bind the argument against each applicable parameter - var unboundArgument = (UnboundLambda)argument.RemoveSuppressions(); + var unboundArgument = (UnboundLambda)argument; foreach (var parameterList in parameterListList) { var parameterType = GetCorrespondingParameterType(analyzedArguments, i, parameterList); @@ -1381,13 +1365,12 @@ private ImmutableArray BuildArgumentsForErrorRecovery(AnalyzedA } // replace the unbound lambda with its best inferred bound version - newArguments[i] = unboundArgument.BindForErrorRecovery().WrapWithSuppressionsFrom(argument); + newArguments[i] = unboundArgument.BindForErrorRecovery(); break; } case BoundKind.OutVariablePendingInference: case BoundKind.DiscardExpression: { - Debug.Assert(argument.KindIgnoringSuppressions() == argument.Kind); // no suppressions possible on out vars or discards if (argument.HasExpressionType()) { break; @@ -1440,7 +1423,6 @@ private ImmutableArray BuildArgumentsForErrorRecovery(AnalyzedA } case BoundKind.OutDeconstructVarPendingInference: { - Debug.Assert(argument.KindIgnoringSuppressions() == argument.Kind); // no suppressions possible on out vars for Deconstruct newArguments[i] = ((OutDeconstructVarPendingInference)argument).FailInference(this); break; } @@ -1498,7 +1480,7 @@ private BoundCall CreateBadCall( var args = BuildArgumentsForErrorRecovery(analyzedArguments); var argNames = analyzedArguments.GetNames(); var argRefKinds = analyzedArguments.RefKinds.ToImmutableOrNull(); - var originalMethods = (expr.KindIgnoringSuppressions() == BoundKind.MethodGroup) ? ((BoundMethodGroup)expr.RemoveSuppressions()).Methods : ImmutableArray.Empty; + var originalMethods = (expr.Kind == BoundKind.MethodGroup) ? ((BoundMethodGroup)expr).Methods : ImmutableArray.Empty; return BoundCall.ErrorCall(node, expr, method, args, argNames, argRefKinds, isDelegateCall: false, invokedAsExtensionMethod: false, originalMethods: originalMethods, resultKind: resultKind, binder: this); } @@ -1551,10 +1533,9 @@ private BoundExpression BindNameofOperatorInternal(InvocationExpressionSyntax no // We relax the instance-vs-static requirement for top-level member access expressions by creating a NameofBinder binder. var nameofBinder = new NameofBinder(argument, this); var boundArgument = nameofBinder.BindExpression(argument, diagnostics); - - if (!boundArgument.HasAnyErrors && CheckSyntaxForNameofArgument(argument, out name, diagnostics) && boundArgument.KindIgnoringSuppressions() == BoundKind.MethodGroup) + if (!boundArgument.HasAnyErrors && CheckSyntaxForNameofArgument(argument, out name, diagnostics) && boundArgument.Kind == BoundKind.MethodGroup) { - var methodGroup = (BoundMethodGroup)boundArgument.RemoveSuppressions(); + var methodGroup = (BoundMethodGroup)boundArgument; if (!methodGroup.TypeArgumentsOpt.IsDefaultOrEmpty) { // method group with type parameters not allowed diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs index 8c6bbe4defe91..926ff9f712de3 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs @@ -24,19 +24,14 @@ private BoundExpression BindCompoundAssignment(AssignmentExpressionSyntax node, // If either operand is bad, don't try to do binary operator overload resolution; that will just // make cascading errors. - if (left.KindIgnoringSuppressions() == BoundKind.EventAccess) + if (left.Kind == BoundKind.EventAccess) { - if (left.Kind == BoundKind.SuppressNullableWarningExpression) - { - Error(diagnostics, ErrorCode.ERR_IllegalSuppression, node); - } - BinaryOperatorKind kindOperator = kind.Operator(); switch (kindOperator) { case BinaryOperatorKind.Addition: case BinaryOperatorKind.Subtraction: - return BindEventAssignment(node, (BoundEventAccess)left.RemoveSuppressions(), right, kindOperator, diagnostics).WrapWithSuppressionsFrom(left); + return BindEventAssignment(node, (BoundEventAccess)left, right, kindOperator, diagnostics); // fall-through for other operators, if RHS is dynamic we produce dynamic operation, otherwise we'll report an error ... } @@ -83,7 +78,7 @@ private BoundExpression BindCompoundAssignment(AssignmentExpressionSyntax node, } } - if (left.KindIgnoringSuppressions() == BoundKind.EventAccess && !CheckEventValueKind((BoundEventAccess)left.RemoveSuppressions(), BindValueKind.Assignable, diagnostics)) + if (left.Kind == BoundKind.EventAccess && !CheckEventValueKind((BoundEventAccess)left, BindValueKind.Assignable, diagnostics)) { // If we're in a place where the event can be assigned, then continue so that we give errors // about the types and operator not lining up. Otherwise, just report that the event can't @@ -207,7 +202,7 @@ private BoundExpression BindCompoundAssignment(AssignmentExpressionSyntax node, // Any events that weren't handled above (by BindEventAssignment) are bad - we just followed this // code path for the diagnostics. Make sure we don't report success. - Debug.Assert(left.KindIgnoringSuppressions() != BoundKind.EventAccess || hasError); + Debug.Assert(left.Kind != BoundKind.EventAccess || hasError); Conversion leftConversion = best.LeftConversion; ReportDiagnosticsIfObsolete(diagnostics, leftConversion, node, hasBaseReceiver: false); @@ -664,20 +659,9 @@ private void ReportAssignmentOperatorError(AssignmentExpressionSyntax node, Diag private static void ReportBinaryOperatorError(ExpressionSyntax node, DiagnosticBag diagnostics, SyntaxToken operatorToken, BoundExpression left, BoundExpression right, LookupResultKind resultKind) { - if (left.Kind == BoundKind.SuppressNullableWarningExpression) - { - Error(diagnostics, ErrorCode.ERR_IllegalSuppression, left.Syntax); - return; - } - if (right.Kind == BoundKind.SuppressNullableWarningExpression) - { - Error(diagnostics, ErrorCode.ERR_IllegalSuppression, right.Syntax); - return; - } - bool leftDefault = left.IsLiteralDefault(); bool rightDefault = right.IsLiteralDefault(); - if (operatorToken.Kind() == SyntaxKind.EqualsEqualsToken || operatorToken.Kind() == SyntaxKind.ExclamationEqualsToken) + if ((operatorToken.Kind() == SyntaxKind.EqualsEqualsToken || operatorToken.Kind() == SyntaxKind.ExclamationEqualsToken)) { if (leftDefault && rightDefault) { @@ -1149,11 +1133,6 @@ private BinaryOperatorAnalysisResult BinaryOperatorOverloadResolution(BinaryOper private bool IsDefaultLiteralAllowedInBinaryOperator(BinaryOperatorKind kind, BoundExpression left, BoundExpression right) { - if (left.Kind == BoundKind.SuppressNullableWarningExpression || right.Kind == BoundKind.SuppressNullableWarningExpression) - { - return false; - } - bool isEquality = kind == BinaryOperatorKind.Equal || kind == BinaryOperatorKind.NotEqual; if (isEquality) { @@ -2120,7 +2099,7 @@ private BoundExpression BindAddressOfExpression(PrefixUnaryExpressionSyntax node bool hasErrors = operand.HasAnyErrors; // This would propagate automatically, but by reading it explicitly we can reduce cascading. bool isFixedStatementAddressOfExpression = SyntaxFacts.IsFixedStatementExpression(node); - switch (operand.KindIgnoringSuppressions()) + switch (operand.Kind) { case BoundKind.MethodGroup: case BoundKind.Lambda: @@ -2299,8 +2278,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper { UnaryOperatorKind kind = SyntaxKindToUnaryOperatorKind(node.Kind()); - var operandWithoutSuppressions = operand.RemoveSuppressions(); - bool isOperandTypeNull = operandWithoutSuppressions.IsLiteralNull() || operandWithoutSuppressions.IsLiteralDefault(); + bool isOperandTypeNull = operand.IsLiteralNull() || operand.IsLiteralDefault(); if (isOperandTypeNull) { // Dev10 does not allow unary prefix operators to be applied to the null literal @@ -2679,7 +2657,7 @@ private static bool IsDivisionByZero(BinaryOperatorKind kind, ConstantValue valu private bool IsOperandErrors(CSharpSyntaxNode node, ref BoundExpression operand, DiagnosticBag diagnostics) { - switch (operand.KindIgnoringSuppressions()) + switch (operand.Kind) { case BoundKind.UnboundLambda: case BoundKind.Lambda: @@ -2692,18 +2670,21 @@ private bool IsOperandErrors(CSharpSyntaxNode node, ref BoundExpression operand, operand = BadExpression(node, operand).MakeCompilerGenerated(); return true; - } - if (operand.Type is null && !operand.IsLiteralNull()) - { - if (!operand.HasAnyErrors) - { - // Operator 'is' cannot be applied to operand of type '(int, )' - Error(diagnostics, ErrorCode.ERR_BadUnaryOp, node, SyntaxFacts.GetText(SyntaxKind.IsKeyword), operand.Display); - } + default: + if ((object)operand.Type == null && !operand.IsLiteralNull()) + { + if (!operand.HasAnyErrors) + { + // Operator 'is' cannot be applied to operand of type '(int, )' + Error(diagnostics, ErrorCode.ERR_BadUnaryOp, node, SyntaxFacts.GetText(SyntaxKind.IsKeyword), operand.Display); + } - operand = BadExpression(node, operand).MakeCompilerGenerated(); - return true; + operand = BadExpression(node, operand).MakeCompilerGenerated(); + return true; + } + + break; } return operand.HasAnyErrors; @@ -2805,11 +2786,13 @@ private BoundExpression BindIsOperator(BinaryExpressionSyntax node, DiagnosticBa HashSet useSiteDiagnostics = null; if (operand.ConstantValue == ConstantValue.Null || + operand.Kind == BoundKind.MethodGroup || operand.Type.SpecialType == SpecialType.System_Void) { // warning for cases where the result is always false: // (a) "null is TYPE" OR operand evaluates to null - // (b) operand is of void type + // (b) operand is a MethodGroup + // (c) operand is of void type // NOTE: Dev10 violates the SPEC for case (c) above and generates // NOTE: an error ERR_NoExplicitBuiltinConv if the target type @@ -3160,7 +3143,7 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa // We store the conversion kind from expression's operand type to target type to enable these // optimizations during is/as operator rewrite. - switch (operand.KindIgnoringSuppressions()) + switch (operand.Kind) { case BoundKind.UnboundLambda: case BoundKind.Lambda: @@ -3174,7 +3157,7 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true); case BoundKind.TupleLiteral: - if (operand.Type is null) + if ((object)operand.Type == null) { Error(diagnostics, ErrorCode.ERR_TypelessTupleInAs, node); return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true); @@ -3229,8 +3212,7 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true); } - BoundExpression operandWithoutSuppressions = operand.RemoveSuppressions(); - if (operandWithoutSuppressions.IsLiteralNull()) + if (operand.IsLiteralNull()) { // We do not want to warn for the case "null as TYPE" where the null // is a literal, because the user might be saying it to cause overload resolution @@ -3238,15 +3220,14 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa return new BoundAsOperator(node, operand, typeExpression, Conversion.DefaultOrNullLiteral, resultType); } - if (operandWithoutSuppressions.IsLiteralDefault()) + if (operand.IsLiteralDefault()) { - var defaultLiteral = (BoundDefaultExpression)operand.RemoveSuppressions(); + var defaultLiteral = (BoundDefaultExpression)operand; Debug.Assert((object)defaultLiteral.Type == null); Debug.Assert((object)defaultLiteral.ConstantValueOpt == null); operand = new BoundDefaultExpression(defaultLiteral.Syntax, constantValueOpt: ConstantValue.Null, - type: GetSpecialType(SpecialType.System_Object, diagnostics, node)) - .WrapWithSuppressionsFrom(operand); + type: GetSpecialType(SpecialType.System_Object, diagnostics, node)); } var operandType = operand.Type; @@ -3404,7 +3385,7 @@ private BoundExpression BindNullCoalescingOperator(BinaryExpressionSyntax node, } // The specification does not permit the left hand side to be a default literal - if (leftOperand.RemoveSuppressions().IsLiteralDefault()) + if (leftOperand.IsLiteralDefault()) { Error(diagnostics, ErrorCode.ERR_BadOpOnNullOrDefault, node, node.OperatorToken.Text, "default"); @@ -3426,7 +3407,7 @@ private BoundExpression BindNullCoalescingOperator(BinaryExpressionSyntax node, // SPEC: The left hand side must be either the null literal or it must have a type. Lambdas and method groups do not have a type, // SPEC: so using one is an error. - if (leftOperand.KindIgnoringSuppressions() == BoundKind.UnboundLambda || leftOperand.KindIgnoringSuppressions() == BoundKind.MethodGroup) + if (leftOperand.Kind == BoundKind.UnboundLambda || leftOperand.Kind == BoundKind.MethodGroup) { return GenerateNullCoalescingBadBinaryOpsError(node, leftOperand, rightOperand, Conversion.NoConversion, diagnostics); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs index 9edadb9113661..a9da54975fce7 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs @@ -719,40 +719,37 @@ protected BoundCall MakeQueryInvocation(CSharpSyntaxNode node, BoundExpression r while (ultimateReceiver.Kind == BoundKind.QueryClause) ultimateReceiver = ((BoundQueryClause)ultimateReceiver).Value; if ((object)ultimateReceiver.Type == null) { - var ultimateReceiverWithoutSuppressions = ultimateReceiver.RemoveSuppressions(); - var kindIgnoringSuppressions = ultimateReceiverWithoutSuppressions.Kind; - if (ultimateReceiver.HasAnyErrors || node.HasErrors) { // report no additional errors } - else if (ultimateReceiverWithoutSuppressions.IsLiteralNull()) + else if (ultimateReceiver.IsLiteralNull()) { diagnostics.Add(ErrorCode.ERR_NullNotValid, node.Location); } - else if (ultimateReceiverWithoutSuppressions.IsLiteralDefault()) + else if (ultimateReceiver.IsLiteralDefault()) { diagnostics.Add(ErrorCode.ERR_DefaultLiteralNotValid, node.Location); } - else if (kindIgnoringSuppressions == BoundKind.NamespaceExpression) + else if (ultimateReceiver.Kind == BoundKind.NamespaceExpression) { diagnostics.Add(ErrorCode.ERR_BadSKunknown, ultimateReceiver.Syntax.Location, ultimateReceiver.Syntax, MessageID.IDS_SK_NAMESPACE.Localize()); } - else if (kindIgnoringSuppressions == BoundKind.Lambda || kindIgnoringSuppressions == BoundKind.UnboundLambda) + else if (ultimateReceiver.Kind == BoundKind.Lambda || ultimateReceiver.Kind == BoundKind.UnboundLambda) { // Could not find an implementation of the query pattern for source type '{0}'. '{1}' not found. diagnostics.Add(ErrorCode.ERR_QueryNoProvider, node.Location, MessageID.IDS_AnonMethod.Localize(), methodName); } - else if (kindIgnoringSuppressions == BoundKind.MethodGroup) + else if (ultimateReceiver.Kind == BoundKind.MethodGroup) { - var methodGroup = (BoundMethodGroup)ultimateReceiverWithoutSuppressions; + var methodGroup = (BoundMethodGroup)ultimateReceiver; HashSet useSiteDiagnostics = null; var resolution = this.ResolveMethodGroup(methodGroup, analyzedArguments: null, isMethodGroupConversion: false, useSiteDiagnostics: ref useSiteDiagnostics); diagnostics.Add(node, useSiteDiagnostics); diagnostics.AddRange(resolution.Diagnostics); if (resolution.HasAnyErrors) { - receiver = this.BindMemberAccessBadResult(methodGroup).WrapWithSuppressionsFrom(ultimateReceiver); + receiver = this.BindMemberAccessBadResult(methodGroup); } else { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_QueryErrors.cs b/src/Compilers/CSharp/Portable/Binder/Binder_QueryErrors.cs index f1deff0e1c1d6..d9dc865f4dbc2 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_QueryErrors.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_QueryErrors.cs @@ -212,7 +212,6 @@ private static bool ReportQueryInferenceFailedSelectMany(FromClauseSyntax fromCl // Estimate the return type of Select's lambda argument BoundExpression arg = arguments.Argument(arguments.IsExtensionMethodInvocation ? 1 : 0); - Debug.Assert(arg.Kind != BoundKind.SuppressNullableWarningExpression); TypeSymbol type = null; if (arg.Kind == BoundKind.UnboundLambda) { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 703c01cd902f3..f37eb52e3bfa9 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -1670,7 +1670,7 @@ internal BoundExpression GenerateConversionForAssignment(TypeSymbol targetType, // error lambdas like "Action f = x=>{ x. };" because IntelliSense // needs to know that x is of type int. - if (expression.HasAnyErrors && expression.KindIgnoringSuppressions() != BoundKind.UnboundLambda) + if (expression.HasAnyErrors && expression.Kind != BoundKind.UnboundLambda) { diagnostics = new DiagnosticBag(); } @@ -1994,8 +1994,11 @@ protected void GenerateImplicitConversionError( { return; } + while (operand.Kind == BoundKind.SuppressNullableWarningExpression) + { + operand = ((BoundSuppressNullableWarningExpression)operand).Expression; + } - operand = operand.RemoveSuppressions(); switch (operand.Kind) { case BoundKind.BadExpression: @@ -2093,7 +2096,7 @@ protected void GenerateImplicitConversionError( return; } - Debug.Assert(operand.HasAnyErrors && operand.KindIgnoringSuppressions() != BoundKind.UnboundLambda, "Missing a case in implicit conversion error reporting"); + Debug.Assert(operand.HasAnyErrors && operand.Kind != BoundKind.UnboundLambda, "Missing a case in implicit conversion error reporting"); } private void GenerateImplicitConversionErrorsForTupleLiteralArguments( diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index e25f40216c468..fd17d2a439721 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs @@ -805,9 +805,6 @@ private Conversion ClassifyImplicitBuiltInConversionFromExpression(BoundExpressi return Conversion.NoConversion; } - // There is a conversion from expression `e!` if there is a conversion from expression `e` - sourceExpression = sourceExpression.RemoveSuppressions(); - if (HasImplicitEnumerationConversion(sourceExpression, destination)) { return Conversion.ImplicitEnumeration; @@ -838,7 +835,15 @@ private Conversion ClassifyImplicitBuiltInConversionFromExpression(BoundExpressi break; case BoundKind.SuppressNullableWarningExpression: - throw ExceptionUtilities.Unreachable; + { + var innerExpression = ((BoundSuppressNullableWarningExpression)sourceExpression).Expression; + var innerConversion = ClassifyImplicitBuiltInConversionFromExpression(innerExpression, innerExpression.Type, destination, ref useSiteDiagnostics); + if (innerConversion.Exists) + { + return innerConversion; + } + break; + } case BoundKind.ExpressionWithNullability: { diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs index 3deb0d15aa278..35846697b6f76 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs @@ -224,7 +224,7 @@ private void GetDelegateOperations(BinaryOperatorKind kind, BoundExpression left BoundExpression nonDelegate = leftDelegate ? right : left; if ((kind == BinaryOperatorKind.Equal || kind == BinaryOperatorKind.NotEqual) - && nonDelegate.KindIgnoringSuppressions() == BoundKind.UnboundLambda) + && nonDelegate.Kind == BoundKind.UnboundLambda) { return; } diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs index a6ae6b9b68b9c..abd77d87393ba 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs @@ -542,16 +542,13 @@ private void MakeExplicitParameterTypeInferences(Binder binder, BoundExpression // SPEC: * Otherwise, no inference is made for this argument - if (argument.KindIgnoringSuppressions() == BoundKind.UnboundLambda) + if (argument.Kind == BoundKind.UnboundLambda) { ExplicitParameterTypeInference(argument, target, ref useSiteDiagnostics); } else if (argument.Kind != BoundKind.TupleLiteral || !MakeExplicitParameterTypeInferences(binder, (BoundTupleLiteral)argument, target, kind, ref useSiteDiagnostics)) { - // We need to handle suppressed tuple literals as well - // Tracked by https://github.com/dotnet/roslyn/issues/32553 - // Either the argument is not a tuple literal, or we were unable to do the inference from its elements, let's try to infer from argument type if (IsReallyAType(argument.Type)) { @@ -836,8 +833,7 @@ private static bool DoesInputTypeContain(BoundExpression argument, TypeSymbol fo return false; // No input types. } - BoundKind argumentKindIgnoringSuppressions = argument.KindIgnoringSuppressions(); - if (argumentKindIgnoringSuppressions != BoundKind.UnboundLambda && argumentKindIgnoringSuppressions != BoundKind.MethodGroup) + if (argument.Kind != BoundKind.UnboundLambda && argument.Kind != BoundKind.MethodGroup) { return false; // No input types. } @@ -891,8 +887,7 @@ private static bool DoesOutputTypeContain(BoundExpression argument, TypeSymbol f return false; } - BoundKind argumentKindIgnoringSuppressions = argument.KindIgnoringSuppressions(); - if (argumentKindIgnoringSuppressions != BoundKind.UnboundLambda && argumentKindIgnoringSuppressions != BoundKind.MethodGroup) + if (argument.Kind != BoundKind.UnboundLambda && argument.Kind != BoundKind.MethodGroup) { return false; } @@ -1252,7 +1247,7 @@ private bool MethodGroupReturnTypeInference(Binder binder, BoundExpression sourc // SPEC: yields a single method with return type U then a lower-bound // SPEC: inference is made from U to Tb. - if (source.KindIgnoringSuppressions() != BoundKind.MethodGroup) + if (source.Kind != BoundKind.MethodGroup) { return false; } @@ -1283,7 +1278,7 @@ private bool MethodGroupReturnTypeInference(Binder binder, BoundExpression sourc return false; } - var returnType = MethodGroupReturnType(binder, (BoundMethodGroup)source.RemoveSuppressions(), fixedDelegateParameters, delegateInvokeMethod.RefKind, ref useSiteDiagnostics); + var returnType = MethodGroupReturnType(binder, (BoundMethodGroup)source, fixedDelegateParameters, delegateInvokeMethod.RefKind, ref useSiteDiagnostics); if ((object)returnType == null || returnType.SpecialType == SpecialType.System_Void) { return false; @@ -1342,12 +1337,12 @@ private void ExplicitParameterTypeInference(BoundExpression source, TypeSymbolWi // SPEC: parameter types V1...Vk then for each Ui an exact inference is made // SPEC: from Ui to the corresponding Vi. - if (source.KindIgnoringSuppressions() != BoundKind.UnboundLambda) + if (source.Kind != BoundKind.UnboundLambda) { return; } - var anonymousFunction = (UnboundLambda)source.RemoveSuppressions(); + UnboundLambda anonymousFunction = (UnboundLambda)source; if (!anonymousFunction.HasExplicitlyTypedParameterList) { @@ -2580,12 +2575,12 @@ private TypeSymbolWithAnnotations InferReturnType(BoundExpression source, NamedT // inferred return type of F is T. // * Otherwise, a return type cannot be inferred for F. - if (source.KindIgnoringSuppressions() != BoundKind.UnboundLambda) + if (source.Kind != BoundKind.UnboundLambda) { return default; } - var anonymousFunction = (UnboundLambda)source.RemoveSuppressions(); + var anonymousFunction = (UnboundLambda)source; if (anonymousFunction.HasSignature) { // Optimization: diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs index 27bdcf769f259..8c4c296fa9213 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs @@ -2078,7 +2078,7 @@ private static BetterResult MoreSpecificType(TypeSymbol t1, TypeSymbol t2, ref H // Determine whether t1 or t2 is a better conversion target from node. private BetterResult BetterConversionFromExpression(BoundExpression node, TypeSymbol t1, TypeSymbol t2, ref HashSet useSiteDiagnostics) { - Debug.Assert(node.KindIgnoringSuppressions() != BoundKind.UnboundLambda); + Debug.Assert(node.Kind != BoundKind.UnboundLambda); bool ignore; return BetterConversionFromExpression( node, @@ -2207,9 +2207,6 @@ private bool ExpressionMatchExactly(BoundExpression node, TypeSymbol t, ref Hash if (node.Kind == BoundKind.TupleLiteral) { - // We need to handle suppressed tuple literals as well - // Tracked by https://github.com/dotnet/roslyn/issues/32553 - // Recurse into tuple constituent arguments. // Even if the tuple literal has a natural type and conversion // from that type is not identity, we still have to do this @@ -2224,12 +2221,12 @@ private bool ExpressionMatchExactly(BoundExpression node, TypeSymbol t, ref Hash MethodSymbol invoke; TypeSymbol y; - if (node.KindIgnoringSuppressions() == BoundKind.UnboundLambda && + if (node.Kind == BoundKind.UnboundLambda && (object)(d = t.GetDelegateType()) != null && (object)(invoke = d.DelegateInvokeMethod) != null && (y = invoke.ReturnType.TypeSymbol).SpecialType != SpecialType.System_Void) { - BoundLambda lambda = ((UnboundLambda)node.RemoveSuppressions()).BindForReturnTypeInference(d); + BoundLambda lambda = ((UnboundLambda)node).BindForReturnTypeInference(d); // - an inferred return type X exists for E in the context of the parameter list of D(ยง7.5.2.12), and an identity conversion exists from X to Y var x = lambda.GetInferredReturnType(ref useSiteDiagnostics); diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs index e93c6c53a1726..9c7336a61bdc8 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs @@ -984,10 +984,9 @@ private static bool HadLambdaConversionError(DiagnosticBag diagnostics, Analyzed bool hadError = false; foreach (var argument in arguments.Arguments) { - var argumentWithoutSuppressions = argument.RemoveSuppressions(); - if (argumentWithoutSuppressions.Kind == BoundKind.UnboundLambda) + if (argument.Kind == BoundKind.UnboundLambda) { - hadError |= ((UnboundLambda)argumentWithoutSuppressions).GenerateSummaryErrors(diagnostics); + hadError |= ((UnboundLambda)argument).GenerateSummaryErrors(diagnostics); } } @@ -1121,12 +1120,12 @@ private void ReportBadArgumentError( // If the problem is that a lambda isn't convertible to the given type, also report why. // The argument and parameter type might match, but may not have same in/out modifiers - if (argument.KindIgnoringSuppressions() == BoundKind.UnboundLambda && refArg == refParameter) + if (argument.Kind == BoundKind.UnboundLambda && refArg == refParameter) { - ((UnboundLambda)argument.RemoveSuppressions()).GenerateAnonymousFunctionConversionError(diagnostics, parameterType); + ((UnboundLambda)argument).GenerateAnonymousFunctionConversionError(diagnostics, parameterType); } - else if (argument.KindIgnoringSuppressions() == BoundKind.MethodGroup && parameterType.TypeKind == TypeKind.Delegate && - Conversions.ReportDelegateMethodGroupDiagnostics(binder, (BoundMethodGroup)argument.RemoveSuppressions(), parameterType, diagnostics)) + else if (argument.Kind == BoundKind.MethodGroup && parameterType.TypeKind == TypeKind.Delegate && + Conversions.ReportDelegateMethodGroupDiagnostics(binder, (BoundMethodGroup)argument, parameterType, diagnostics)) { // a diagnostic has been reported by ReportDelegateMethodGroupDiagnostics } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs index 1eb4380bbadb3..5c532a332af29 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs @@ -171,10 +171,6 @@ public static void GetExpressionSymbols(this BoundExpression node, ArrayBuilder< symbols.AddRange(originalIndexers); break; - case BoundKind.SuppressNullableWarningExpression: - // caller removed suppressions - throw ExceptionUtilities.Unreachable; - default: var symbol = node.ExpressionSymbol; if ((object)symbol != null) @@ -300,32 +296,5 @@ private static NullableAnnotation GetNullableAnnotation(this BoundExpression exp return NullableAnnotation.Unknown; } - - public static BoundKind KindIgnoringSuppressions(this BoundExpression expr) - { - return RemoveSuppressions(expr).Kind; - } - - internal static BoundExpression RemoveSuppressions(this BoundExpression expr) - { - while (expr.Kind == BoundKind.SuppressNullableWarningExpression) - { - expr = ((BoundSuppressNullableWarningExpression)expr).Expression; - } - - return expr; - } - - internal static BoundExpression WrapWithSuppressionsFrom(this BoundExpression expr, BoundExpression suppressionsSource) - { - if (suppressionsSource.Kind != BoundKind.SuppressNullableWarningExpression) - { - return expr; - } - - var suppression = (BoundSuppressNullableWarningExpression)suppressionsSource; - var nested = expr.WrapWithSuppressionsFrom(suppression.Expression); - return suppression.Update(nested, nested.Type); - } } } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index 45eda1f14a018..403db87828928 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -1361,7 +1361,7 @@ public override BoundNode VisitConversion(BoundConversion node) { if (node.IsExtensionMethod || ((object)node.SymbolOpt != null && !node.SymbolOpt.IsStatic)) { - BoundExpression receiver = ((BoundMethodGroup)node.Operand.RemoveSuppressions()).ReceiverOpt; + BoundExpression receiver = ((BoundMethodGroup)node.Operand).ReceiverOpt; // A method group's "implicit this" is only used for instance methods. if (_trackRegions) { diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 155755da03618..3cb8f4083d28d 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -2121,7 +2121,6 @@ private static NullableAnnotation GetNullableAnnotation(BoundExpression expr) return ((BoundExpressionWithNullability)expr).NullableAnnotation; case BoundKind.MethodGroup: case BoundKind.UnboundLambda: - case BoundKind.SuppressNullableWarningExpression: return NullableAnnotation.Unknown; default: Debug.Assert(false); // unexpected value @@ -3190,12 +3189,12 @@ private ImmutableArray GetArgumentsForMethodTypeInference(Immut BoundExpression getArgumentForMethodTypeInference(BoundExpression argument, TypeSymbolWithAnnotations argumentType) { - if (argument.KindIgnoringSuppressions() == BoundKind.Lambda) + if (argument.Kind == BoundKind.Lambda) { // MethodTypeInferrer must infer nullability for lambdas based on the nullability // from flow analysis rather than the declared nullability. To allow that, we need // to re-bind lambdas in MethodTypeInferrer. - return GetUnboundLambda((BoundLambda)argument.RemoveSuppressions(), GetVariableState()).WrapWithSuppressionsFrom(argument); + return GetUnboundLambda((BoundLambda)argument, GetVariableState()); } if (argumentType.IsNull) { @@ -3283,16 +3282,6 @@ private static (BoundExpression expression, Conversion conversion) RemoveConvers return (expr, group?.Conversion ?? Conversion.Identity); } - /// - /// Returns true if the expression had a suppression. - /// - bool RemoveSuppressions(ref BoundExpression expression) - { - var original = expression; - expression = expression.RemoveSuppressions(); - return expression != original; - } - // See Binder.BindNullCoalescingOperator for initial binding. private Conversion GenerateConversionForConditionalOperator(BoundExpression sourceExpression, TypeSymbol sourceType, TypeSymbol destinationType, bool reportMismatch) { @@ -3496,7 +3485,6 @@ private TypeSymbolWithAnnotations VisitOptionalImplicitConversion(BoundExpressio } (BoundExpression operand, Conversion conversion) = RemoveConversion(expr, includeExplicitConversions: false); - var operandType = VisitRvalueWithResult(operand); // If an explicit conversion was used in place of an implicit conversion, the explicit // conversion was created by initial binding after reporting "error CS0266: diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs index 8df70adec9959..64494ff7c6250 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs @@ -591,17 +591,6 @@ public override BoundNode VisitPointerIndirectionOperator(BoundPointerIndirectio return base.VisitPointerIndirectionOperator(node); } - private BoundExpression RemoveSuppressionsAndReportInExpressionTree(BoundExpression expr) - { - while (expr.Kind == BoundKind.SuppressNullableWarningExpression) - { - ReportSuppressionInExpressionTree(expr); - expr = ((BoundSuppressNullableWarningExpression)expr).Expression; - } - - return expr; - } - public override BoundNode VisitConversion(BoundConversion node) { CheckUnsafeType(node.Operand); @@ -611,8 +600,7 @@ public override BoundNode VisitConversion(BoundConversion node) switch (node.ConversionKind) { case ConversionKind.MethodGroup: - var operandWithoutSuppressions = RemoveSuppressionsAndReportInExpressionTree(node.Operand); - VisitMethodGroup((BoundMethodGroup)operandWithoutSuppressions, parentIsConversion: true); + VisitMethodGroup((BoundMethodGroup)node.Operand, parentIsConversion: true); return node; case ConversionKind.AnonymousFunction: @@ -714,22 +702,6 @@ public override BoundNode VisitNullCoalescingAssignmentOperator(BoundNullCoalesc return base.VisitNullCoalescingAssignmentOperator(node); } - public override BoundNode VisitSuppressNullableWarningExpression(BoundSuppressNullableWarningExpression node) - { - ReportSuppressionInExpressionTree(node); - - return base.VisitSuppressNullableWarningExpression(node); - } - - private void ReportSuppressionInExpressionTree(BoundExpression node) - { - Debug.Assert(node.Kind == BoundKind.SuppressNullableWarningExpression); - if (_inExpressionLambda) - { - Error(ErrorCode.ERR_ExpressionTreeCantContainSuppressNullableWarning, node); - } - } - public override BoundNode VisitDynamicInvocation(BoundDynamicInvocation node) { if (_inExpressionLambda) diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs index ba943d66bf8d6..f0ce9a3c6e115 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DelegateCreationExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DelegateCreationExpression.cs index f0fdbef59e4b1..6da8ad1a1fb47 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DelegateCreationExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DelegateCreationExpression.cs @@ -21,16 +21,15 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE return new BoundDelegateCreationExpression(node.Syntax, loweredReceiver, methodOpt: null, isExtensionMethod: false, type: node.Type); } - var argumentWithoutSuppressions = node.Argument.RemoveSuppressions(); - if (argumentWithoutSuppressions.Kind == BoundKind.MethodGroup) + if (node.Argument.Kind == BoundKind.MethodGroup) { - var mg = (BoundMethodGroup)argumentWithoutSuppressions; + var mg = (BoundMethodGroup)node.Argument; var method = node.MethodOpt; var oldSyntax = _factory.Syntax; _factory.Syntax = (mg.ReceiverOpt ?? mg).Syntax; var receiver = (method.IsStatic && !node.IsExtensionMethod) ? _factory.Type(method.ContainingType) : VisitExpression(mg.ReceiverOpt); _factory.Syntax = oldSyntax; - return node.Update(receiver.WrapWithSuppressionsFrom(node.Argument), method, node.IsExtensionMethod, node.Type); + return node.Update(receiver, method, node.IsExtensionMethod, node.Type); } return base.VisitDelegateCreationExpression(node); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsOperator.cs index c8a51555fbad7..d16e9c77910bb 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsOperator.cs @@ -3,6 +3,8 @@ using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp { @@ -25,7 +27,21 @@ private BoundExpression MakeIsOperator( Conversion conversion, TypeSymbol rewrittenType) { - Debug.Assert(rewrittenOperand.Kind != BoundKind.MethodGroup); + if (rewrittenOperand.Kind == BoundKind.MethodGroup) + { + var methodGroup = (BoundMethodGroup)rewrittenOperand; + BoundExpression receiver = methodGroup.ReceiverOpt; + if (receiver != null && receiver.Kind != BoundKind.ThisReference) + { + // possible side-effect + return RewriteConstantIsOperator(receiver.Syntax, receiver, ConstantValue.False, rewrittenType); + } + else + { + return MakeLiteral(syntax, ConstantValue.False, rewrittenType); + } + } + var operandType = rewrittenOperand.Type; var targetType = rewrittenTargetType.Type; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs index 2ecbb9b9f6eea..3490f3e540ec3 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs @@ -12,8 +12,7 @@ private BoundExpression RewriteInterpolatedStringConversion(BoundConversion conv Debug.Assert(conversion.ConversionKind == ConversionKind.InterpolatedString); BoundExpression format; ArrayBuilder expressions; - BoundExpression operand = conversion.Operand.RemoveSuppressions(); - MakeInterpolatedStringFormat((BoundInterpolatedString)operand, out format, out expressions); + MakeInterpolatedStringFormat((BoundInterpolatedString)conversion.Operand, out format, out expressions); expressions.Insert(0, format); var stringFactory = _factory.WellKnownType(WellKnownType.System_Runtime_CompilerServices_FormattableStringFactory);