未验证 提交 2c5e11c3 编写于 作者: C Charles Stoner 提交者: GitHub

Consider nullability in conversion to constraint type (#46405)

上级 e79e45e0
......@@ -6263,7 +6263,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi
break;
case ConversionKind.Boxing:
resultState = getBoxingConversionResultState(operandType);
resultState = getBoxingConversionResultState(targetTypeWithNullability, operandType);
break;
case ConversionKind.Unboxing:
......@@ -6473,10 +6473,19 @@ static NullableFlowState getReferenceConversionResultState(TypeWithAnnotations t
switch (state)
{
case NullableFlowState.MaybeNull:
if (operandType.Type?.IsTypeParameterDisallowingAnnotationInCSharp8() != true &&
targetType.Type?.IsTypeParameterDisallowingAnnotationInCSharp8() == true)
if (targetType.Type?.IsTypeParameterDisallowingAnnotationInCSharp8() == true)
{
return NullableFlowState.MaybeDefault;
var type = operandType.Type;
if (type is null || !type.IsTypeParameterDisallowingAnnotationInCSharp8())
{
return NullableFlowState.MaybeDefault;
}
else if (targetType.NullableAnnotation.IsNotAnnotated() &&
type is TypeParameterSymbol typeParameter1 &&
dependsOnTypeParameter(typeParameter1, (TypeParameterSymbol)targetType.Type, NullableAnnotation.NotAnnotated, out var annotation))
{
return (annotation == NullableAnnotation.Annotated) ? NullableFlowState.MaybeDefault : NullableFlowState.MaybeNull;
}
}
break;
case NullableFlowState.MaybeDefault:
......@@ -6490,11 +6499,31 @@ static NullableFlowState getReferenceConversionResultState(TypeWithAnnotations t
}
// Converting to a less-derived type (object, interface, type parameter).
// If the operand is MaybeNull or MaybeDefault, the result should be
// If the operand is MaybeNull, the result should be
// MaybeNull (if the target type allows) or MaybeDefault otherwise.
static NullableFlowState getBoxingConversionResultState(TypeWithState operandType)
static NullableFlowState getBoxingConversionResultState(TypeWithAnnotations targetType, TypeWithState operandType)
{
return getConversionResultState(operandType);
var state = operandType.State;
if (state == NullableFlowState.MaybeNull)
{
var type = operandType.Type;
if (type is null || !type.IsTypeParameterDisallowingAnnotationInCSharp8())
{
return NullableFlowState.MaybeDefault;
}
else if (targetType.NullableAnnotation.IsNotAnnotated() &&
type is TypeParameterSymbol typeParameter1 &&
targetType.Type is TypeParameterSymbol typeParameter2)
{
bool dependsOn = dependsOnTypeParameter(typeParameter1, typeParameter2, NullableAnnotation.NotAnnotated, out var annotation);
Debug.Assert(dependsOn); // If this case fails, add a corresponding test.
if (dependsOn)
{
return (annotation == NullableAnnotation.Annotated) ? NullableFlowState.MaybeDefault : NullableFlowState.MaybeNull;
}
}
}
return state;
}
// Converting to a more-derived type (struct, class, type parameter).
......@@ -6515,13 +6544,39 @@ static NullableFlowState getConversionResultState(TypeWithState operandType)
var state = operandType.State;
if (state == NullableFlowState.MaybeNull)
{
var type = operandType.Type;
if (type is null || !type.IsTypeParameterDisallowingAnnotationInCSharp8())
return NullableFlowState.MaybeDefault;
}
return state;
}
// If type parameter 1 depends on type parameter 2 (that is, if type parameter 2 appears
// in the constraint types of type parameter 1), returns the effective annotation on
// type parameter 2 in the constraints of type parameter 1.
static bool dependsOnTypeParameter(TypeParameterSymbol typeParameter1, TypeParameterSymbol typeParameter2, NullableAnnotation typeParameter1Annotation, out NullableAnnotation annotation)
{
if (typeParameter1.Equals(typeParameter2, TypeCompareKind.AllIgnoreOptions))
{
annotation = typeParameter1Annotation;
return true;
}
bool dependsOn = false;
var combinedAnnotation = NullableAnnotation.Annotated;
foreach (var constraintType in typeParameter1.ConstraintTypesNoUseSiteDiagnostics)
{
if (constraintType.Type is TypeParameterSymbol constraintTypeParameter &&
dependsOnTypeParameter(constraintTypeParameter, typeParameter2, constraintType.NullableAnnotation, out var constraintAnnotation))
{
return NullableFlowState.MaybeDefault;
dependsOn = true;
combinedAnnotation = combinedAnnotation.Meet(constraintAnnotation);
}
}
return state;
if (dependsOn)
{
annotation = combinedAnnotation.Join(typeParameter1Annotation);
return true;
}
annotation = default;
return false;
}
}
......
......@@ -991,7 +991,7 @@ static NullableFlowState getTypeArgumentState(in TypeWithAnnotations typeWithAnn
}
if (type.IsValueType)
{
return type.IsNullableType() ? NullableFlowState.MaybeNull : NullableFlowState.NotNull;
return type.IsNullableTypeOrTypeParameter() ? NullableFlowState.MaybeNull : NullableFlowState.NotNull;
}
switch (typeWithAnnotations.NullableAnnotation)
{
......@@ -1015,7 +1015,7 @@ static NullableFlowState getTypeArgumentState(in TypeWithAnnotations typeWithAnn
}
else
{
result = (NullableFlowState)Math.Min((int)result.Value, (int)constraintState);
result = result.Value.Meet(constraintState);
}
}
return result ?? NullableFlowState.MaybeNull;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册