未验证 提交 b8c54ca9 编写于 作者: F Fred Silberberg 提交者: GitHub

Merge pull request #35544 from 333fred/visit-conversion

Refactor ApplyConversion into VisitConversion
......@@ -191,7 +191,7 @@ private BoundExpression CreateUserDefinedConversion(SyntaxNode syntax, BoundExpr
conversion: conversion.UserDefinedFromConversion,
isCast: false,
conversionGroup,
wasCompilerGenerated: true,
wasCompilerGenerated: false,
destination: conversion.BestUserDefinedConversionAnalysis.FromType,
diagnostics: diagnostics);
......
......@@ -498,7 +498,6 @@ public override BoundNode VisitSwitchExpression(BoundSwitchExpression node)
conversions.Add(conversion);
var armType = VisitRvalueWithState(expression);
resultTypes.Add(armType);
TrackInferredTypesThroughConversions(arm.Value, expression, _visitResult);
Join(ref endState, ref this.State);
// Build placeholders for inference in order to preserve annotations.
......@@ -516,7 +515,7 @@ public override BoundNode VisitSwitchExpression(BoundSwitchExpression node)
for (int i = 0; i < numSwitchArms; i++)
{
var expression = expressions[i];
resultTypes[i] = ApplyConversion(expression, expression, conversions[i], inferredTypeWithAnnotations, resultTypes[i], checkConversion: true,
resultTypes[i] = VisitConversion(conversionOpt: null, expression, conversions[i], inferredTypeWithAnnotations, resultTypes[i], checkConversion: true,
fromExplicitCast: false, useLegacyWarnings: false, AssignmentKind.Assignment, reportRemainingWarnings: true, reportTopLevelWarnings: false);
}
......@@ -527,8 +526,9 @@ public override BoundNode VisitSwitchExpression(BoundSwitchExpression node)
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
_ = ApplyConversion(nodeForSyntax, operandOpt: nodeForSyntax, conversions[i], targetTypeWithNullability: inferredTypeWithAnnotations, operandType: resultTypes[i],
_ = VisitConversion(conversionOpt, conversionOperand: nodeForSyntax, conversions[i], targetTypeWithNullability: inferredTypeWithAnnotations, operandType: resultTypes[i],
checkConversion: true, fromExplicitCast: false, useLegacyWarnings: false, AssignmentKind.Assignment, reportRemainingWarnings: false, reportTopLevelWarnings: true);
}
......
......@@ -727,5 +727,97 @@ public override void Initialize(AnalysisContext context)
}, SyntaxKind.IdentifierName);
}
}
[Fact]
public void MultipleConversions()
{
var source = @"
class A { public static explicit operator C(A a) => new D(); }
class B : A { }
class C { }
class D : C { }
class E
{
void M()
{
var d = (D)(C?)new B();
}
}";
var comp = CreateCompilation(source, options: WithNonNullTypesTrue(), parseOptions: TestOptions.Regular8WithNullableAnalysis);
comp.VerifyDiagnostics(
// (10,17): warning CS8600: Converting null literal or possible null value to non-nullable type.
// var d = (D)(C?)new B();
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "(D)(C?)new B()").WithLocation(10, 17));
var syntaxTree = comp.SyntaxTrees[0];
var root = syntaxTree.GetRoot();
var model = comp.GetSemanticModel(syntaxTree);
var aType = comp.GetTypeByMetadataName("A");
var bType = comp.GetTypeByMetadataName("B");
var cType = comp.GetTypeByMetadataName("C");
var dType = comp.GetTypeByMetadataName("D");
var nullable = new NullabilityInfo(PublicNullableAnnotation.Annotated, PublicNullableFlowState.MaybeNull);
var notNullable = new NullabilityInfo(PublicNullableAnnotation.NotAnnotated, PublicNullableFlowState.NotNull);
var dCast = (CastExpressionSyntax)root.DescendantNodes().OfType<EqualsValueClauseSyntax>().Single().Value;
var dInfo = model.GetTypeInfo(dCast);
Assert.Equal(dType, dInfo.Type);
Assert.Equal(dType, dInfo.ConvertedType);
Assert.Equal(nullable, dInfo.Nullability);
Assert.Equal(nullable, dInfo.ConvertedNullability);
var cCast = (CastExpressionSyntax)dCast.Expression;
var cInfo = model.GetTypeInfo(cCast);
Assert.Equal(cType, cInfo.Type);
Assert.Equal(cType, cInfo.ConvertedType);
Assert.Equal(nullable, cInfo.Nullability);
Assert.Equal(nullable, cInfo.ConvertedNullability);
var objectCreation = cCast.Expression;
var creationInfo = model.GetTypeInfo(objectCreation);
Assert.Equal(bType, creationInfo.Type);
Assert.Equal(aType, creationInfo.ConvertedType);
Assert.Equal(notNullable, creationInfo.Nullability);
Assert.Equal(nullable, creationInfo.ConvertedNullability);
}
[Fact]
public void ConditionalOperator_InvalidType()
{
var source = @"
class C
{
void M()
{
var x = new Undefined() ? new object() : null;
}
}";
var comp = CreateCompilation(source, options: WithNonNullTypesTrue(), parseOptions: TestOptions.Regular8WithNullableAnalysis);
comp.VerifyDiagnostics(
// (6,21): error CS0246: The type or namespace name 'Undefined' could not be found (are you missing a using directive or an assembly reference?)
// var x = new Undefined() ? new object() : null;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Undefined").WithArguments("Undefined").WithLocation(6, 21));
var syntaxTree = comp.SyntaxTrees[0];
var root = syntaxTree.GetRoot();
var model = comp.GetSemanticModel(syntaxTree);
var conditional = root.DescendantNodes().OfType<ConditionalExpressionSyntax>().Single();
var notNull = new NullabilityInfo(PublicNullableAnnotation.NotAnnotated, PublicNullableFlowState.NotNull);
var @null = new NullabilityInfo(PublicNullableAnnotation.Annotated, PublicNullableFlowState.MaybeNull);
var leftInfo = model.GetTypeInfo(conditional.WhenTrue);
var rightInfo = model.GetTypeInfo(conditional.WhenFalse);
Assert.Equal(notNull, leftInfo.Nullability);
Assert.Equal(notNull, leftInfo.ConvertedNullability);
Assert.Equal(@null, rightInfo.Nullability);
Assert.Equal(notNull, rightInfo.ConvertedNullability);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册