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