未验证 提交 87f4c9df 编写于 作者: J Julien Couvreur 提交者: GitHub

Typeless expressions should contribute nullability to lambda return (#47581)

上级 1d69a1dc
...@@ -505,8 +505,6 @@ private BoundExpression CreateMethodGroupConversion(SyntaxNode syntax, BoundExpr ...@@ -505,8 +505,6 @@ private BoundExpression CreateMethodGroupConversion(SyntaxNode syntax, BoundExpr
_ => throw ExceptionUtilities.UnexpectedValue(source), _ => throw ExceptionUtilities.UnexpectedValue(source),
}; };
BoundMethodGroup group = FixMethodGroupWithTypeOrValue(originalGroup, conversion, diagnostics); BoundMethodGroup group = FixMethodGroupWithTypeOrValue(originalGroup, conversion, diagnostics);
BoundExpression? receiverOpt = group.ReceiverOpt;
MethodSymbol? method = conversion.Method;
bool hasErrors = false; bool hasErrors = false;
if (MethodGroupConversionHasErrors(syntax, conversion, group.ReceiverOpt, conversion.IsExtensionMethod, destination, diagnostics)) if (MethodGroupConversionHasErrors(syntax, conversion, group.ReceiverOpt, conversion.IsExtensionMethod, destination, diagnostics))
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.PooledObjects;
...@@ -14,11 +15,17 @@ internal static class BestTypeInferrer ...@@ -14,11 +15,17 @@ internal static class BestTypeInferrer
{ {
public static NullableAnnotation GetNullableAnnotation(ArrayBuilder<TypeWithAnnotations> types) public static NullableAnnotation GetNullableAnnotation(ArrayBuilder<TypeWithAnnotations> types)
{ {
#if DEBUG
var example = types.FirstOrDefault(t => t.HasType);
#endif
var result = NullableAnnotation.NotAnnotated; var result = NullableAnnotation.NotAnnotated;
foreach (var type in types) foreach (var type in types)
{ {
Debug.Assert(type.HasType); #if DEBUG
Debug.Assert(type.Equals(types[0], TypeCompareKind.AllIgnoreOptions)); Debug.Assert(!type.HasType || type.Equals(example, TypeCompareKind.AllIgnoreOptions));
#endif
// This uses the covariant merging rules. // This uses the covariant merging rules.
result = result.Join(type.NullableAnnotation); result = result.Join(type.NullableAnnotation);
} }
......
...@@ -2842,11 +2842,9 @@ protected override void VisitStatement(BoundStatement statement) ...@@ -2842,11 +2842,9 @@ protected override void VisitStatement(BoundStatement statement)
public override BoundNode? VisitUnconvertedObjectCreationExpression(BoundUnconvertedObjectCreationExpression node) public override BoundNode? VisitUnconvertedObjectCreationExpression(BoundUnconvertedObjectCreationExpression node)
{ {
var discardedDiagnostics = new DiagnosticBag(); // This method is only involved in method inference with unbound lambdas.
var expr = _binder!.BindObjectCreationForErrorRecovery(node, discardedDiagnostics); // The diagnostics on arguments are reported by VisitObjectCreationExpression.
discardedDiagnostics.Free(); SetResultType(node, TypeWithState.Create(null, NullableFlowState.NotNull));
Visit(expr);
SetResultType(node, TypeWithState.Create(expr.Type, NullableFlowState.NotNull));
return null; return null;
} }
...@@ -4108,8 +4106,6 @@ private static TypeWithState GetNullCoalescingResultType(TypeWithState rightResu ...@@ -4108,8 +4106,6 @@ private static TypeWithState GetNullCoalescingResultType(TypeWithState rightResu
BoundExpression originalConsequence, BoundExpression originalConsequence,
BoundExpression originalAlternative) BoundExpression originalAlternative)
{ {
Debug.Assert(node.Type is object);
VisitCondition(condition); VisitCondition(condition);
var consequenceState = this.StateWhenTrue; var consequenceState = this.StateWhenTrue;
var alternativeState = this.StateWhenFalse; var alternativeState = this.StateWhenFalse;
...@@ -4127,7 +4123,7 @@ private static TypeWithState GetNullCoalescingResultType(TypeWithState rightResu ...@@ -4127,7 +4123,7 @@ private static TypeWithState GetNullCoalescingResultType(TypeWithState rightResu
(alternativeLValue, alternativeRValue) = visitConditionalRefOperand(alternativeState, originalAlternative); (alternativeLValue, alternativeRValue) = visitConditionalRefOperand(alternativeState, originalAlternative);
Join(ref this.State, ref consequenceState); Join(ref this.State, ref consequenceState);
TypeSymbol refResultType = node.Type.SetUnknownNullabilityForReferenceTypes(); TypeSymbol? refResultType = node.Type?.SetUnknownNullabilityForReferenceTypes();
if (IsNullabilityMismatch(consequenceLValue, alternativeLValue)) if (IsNullabilityMismatch(consequenceLValue, alternativeLValue))
{ {
// l-value types must match // l-value types must match
...@@ -4204,8 +4200,8 @@ private static TypeWithState GetNullCoalescingResultType(TypeWithState rightResu ...@@ -4204,8 +4200,8 @@ private static TypeWithState GetNullCoalescingResultType(TypeWithState rightResu
NullableFlowState resultState; NullableFlowState resultState;
if (resultType is null) if (resultType is null)
{ {
resultType = node.Type.SetUnknownNullabilityForReferenceTypes(); resultType = node.Type?.SetUnknownNullabilityForReferenceTypes();
resultState = NullableFlowState.NotNull; resultState = consequenceRValue.State.Join(alternativeRValue.State);
var resultTypeWithState = TypeWithState.Create(resultType, resultState); var resultTypeWithState = TypeWithState.Create(resultType, resultState);
...@@ -6541,9 +6537,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi ...@@ -6541,9 +6537,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi
case ConversionKind.ObjectCreation: case ConversionKind.ObjectCreation:
case ConversionKind.SwitchExpression: case ConversionKind.SwitchExpression:
case ConversionKind.ConditionalExpression: case ConversionKind.ConditionalExpression:
// These are not represented as a separate conversion in the bound tree. return operandType;
// Instead they are folded into the operand.
throw ExceptionUtilities.UnexpectedValue(conversion.Kind);
case ConversionKind.ExplicitUserDefined: case ConversionKind.ExplicitUserDefined:
case ConversionKind.ImplicitUserDefined: case ConversionKind.ImplicitUserDefined:
...@@ -8795,9 +8789,9 @@ private TypeWithState InferResultNullabilityOfBinaryLogicalOperator(BoundExpress ...@@ -8795,9 +8789,9 @@ private TypeWithState InferResultNullabilityOfBinaryLogicalOperator(BoundExpress
public override BoundNode? VisitDefaultLiteral(BoundDefaultLiteral node) public override BoundNode? VisitDefaultLiteral(BoundDefaultLiteral node)
{ {
// Can occur in error scenarios // Can occur in error scenarios and lambda scenarios
var result = base.VisitDefaultLiteral(node); var result = base.VisitDefaultLiteral(node);
SetUnknownResultNullability(node); SetResultType(node, TypeWithState.Create(node.Type, NullableFlowState.MaybeDefault));
return result; return result;
} }
......
...@@ -566,6 +566,7 @@ public override BoundNode VisitConvertedSwitchExpression(BoundConvertedSwitchExp ...@@ -566,6 +566,7 @@ public override BoundNode VisitConvertedSwitchExpression(BoundConvertedSwitchExp
public override BoundNode VisitUnconvertedSwitchExpression(BoundUnconvertedSwitchExpression node) public override BoundNode VisitUnconvertedSwitchExpression(BoundUnconvertedSwitchExpression node)
{ {
// This method is only involved in method inference with unbound lambdas.
VisitSwitchExpressionCore(node, inferType: true); VisitSwitchExpressionCore(node, inferType: true);
return null; return null;
} }
...@@ -632,34 +633,40 @@ private void VisitSwitchExpressionCore(BoundSwitchExpression node, bool inferTyp ...@@ -632,34 +633,40 @@ private void VisitSwitchExpressionCore(BoundSwitchExpression node, bool inferTyp
TypeSymbol inferredType = TypeSymbol inferredType =
(inferType ? BestTypeInferrer.InferBestType(placeholders, _conversions, ref useSiteDiagnostics) : null) (inferType ? BestTypeInferrer.InferBestType(placeholders, _conversions, ref useSiteDiagnostics) : null)
?? node.Type?.SetUnknownNullabilityForReferenceTypes() ?? node.Type?.SetUnknownNullabilityForReferenceTypes();
?? new ExtendedErrorTypeSymbol(this.compilation, "", arity: 0, errorInfo: null, unreported: false);
var inferredTypeWithAnnotations = TypeWithAnnotations.Create(inferredType); var inferredTypeWithAnnotations = TypeWithAnnotations.Create(inferredType);
// Convert elements to best type to determine element top-level nullability and to report nested nullability warnings // Convert elements to best type to determine element top-level nullability and to report nested nullability warnings
for (int i = 0; i < numSwitchArms; i++) if (inferredType is not null)
{ {
var expression = expressions[i]; for (int i = 0; i < numSwitchArms; i++)
resultTypes[i] = VisitConversion(conversionOpt: null, expression, conversions[i], inferredTypeWithAnnotations, resultTypes[i], checkConversion: true, {
fromExplicitCast: false, useLegacyWarnings: false, AssignmentKind.Assignment, reportRemainingWarnings: true, reportTopLevelWarnings: false); var expression = expressions[i];
resultTypes[i] = VisitConversion(conversionOpt: null, expression, conversions[i], inferredTypeWithAnnotations, resultTypes[i], checkConversion: true,
fromExplicitCast: false, useLegacyWarnings: false, AssignmentKind.Assignment, reportRemainingWarnings: true, reportTopLevelWarnings: false);
}
} }
var inferredState = BestTypeInferrer.GetNullableState(resultTypes); var inferredState = BestTypeInferrer.GetNullableState(resultTypes);
var resultType = TypeWithState.Create(inferredType, inferredState); var resultType = TypeWithState.Create(inferredType, inferredState);
inferredTypeWithAnnotations = resultType.ToTypeWithAnnotations(compilation);
if (resultType.State == NullableFlowState.MaybeDefault)
{
inferredTypeWithAnnotations = inferredTypeWithAnnotations.AsAnnotated();
}
for (int i = 0; i < numSwitchArms; i++) if (inferredType is not null)
{ {
var nodeForSyntax = expressions[i]; inferredTypeWithAnnotations = resultType.ToTypeWithAnnotations(compilation);
var conversionOpt = node.SwitchArms[i].Value switch { BoundConversion c when c != nodeForSyntax => c, _ => null }; if (resultType.State == NullableFlowState.MaybeDefault)
// Report top-level warnings {
_ = VisitConversion(conversionOpt, conversionOperand: nodeForSyntax, conversions[i], targetTypeWithNullability: inferredTypeWithAnnotations, operandType: resultTypes[i], inferredTypeWithAnnotations = inferredTypeWithAnnotations.AsAnnotated();
checkConversion: true, fromExplicitCast: false, useLegacyWarnings: false, AssignmentKind.Assignment, reportRemainingWarnings: false, reportTopLevelWarnings: true); }
for (int i = 0; i < numSwitchArms; i++)
{
var nodeForSyntax = expressions[i];
var conversionOpt = node.SwitchArms[i].Value switch { BoundConversion c when c != nodeForSyntax => c, _ => null };
// Report top-level warnings
_ = VisitConversion(conversionOpt, conversionOperand: nodeForSyntax, conversions[i], targetTypeWithNullability: inferredTypeWithAnnotations, operandType: resultTypes[i],
checkConversion: true, fromExplicitCast: false, useLegacyWarnings: false, AssignmentKind.Assignment, reportRemainingWarnings: false, reportTopLevelWarnings: true);
}
} }
conversions.Free(); conversions.Free();
......
...@@ -782,7 +782,7 @@ static NullableFlowState getFlowState(TypeSymbol type, NullableAnnotation annota ...@@ -782,7 +782,7 @@ static NullableFlowState getFlowState(TypeSymbol type, NullableAnnotation annota
{ {
if (type is null) if (type is null)
{ {
return annotation.IsAnnotated() ? NullableFlowState.MaybeNull : NullableFlowState.NotNull; return annotation.IsAnnotated() ? NullableFlowState.MaybeDefault : NullableFlowState.NotNull;
} }
if (type.IsPossiblyNullableReferenceTypeTypeParameter()) if (type.IsPossiblyNullableReferenceTypeTypeParameter())
{ {
......
...@@ -1268,7 +1268,7 @@ void M() ...@@ -1268,7 +1268,7 @@ void M()
Assert.Equal(notNull, leftInfo.Nullability); Assert.Equal(notNull, leftInfo.Nullability);
Assert.Equal(notNull, leftInfo.ConvertedNullability); Assert.Equal(notNull, leftInfo.ConvertedNullability);
Assert.Equal(@null, rightInfo.Nullability); Assert.Equal(@null, rightInfo.Nullability);
Assert.Equal(notNull, rightInfo.ConvertedNullability); Assert.Equal(@null, rightInfo.ConvertedNullability);
} }
[Fact] [Fact]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册