未验证 提交 f4402e76 编写于 作者: N Neal Gafter 提交者: GitHub

Fix `is` and pattern-matching behavior in presence of implicit UD conversion (#24547)

* Fix `is` and pattern-matching behavior in presence of implicit UD conversion
and also an explicit reference conversion. User-defined conversions should
never be considered for `is` and pattern-matching.
Fixes #24522
上级 ac3739ba
......@@ -2751,7 +2751,7 @@ private BoundExpression BindIsOperator(BinaryExpressionSyntax node, DiagnosticBa
operandType = GetSpecialType(SpecialType.System_Object, diagnostics, node);
}
Conversion conversion = Conversions.ClassifyConversionFromType(operandType, targetType, ref useSiteDiagnostics);
Conversion conversion = Conversions.ClassifyBuiltInConversion(operandType, targetType, ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
ReportIsOperatorConstantWarnings(node, diagnostics, operandType, targetType, conversion.Kind, operand.ConstantValue);
return new BoundIsOperator(node, operand, typeExpression, conversion, resultType);
......
......@@ -224,7 +224,7 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
expressionType = conversions.CorLibrary.GetSpecialType(SpecialType.System_Object);
}
conversion = conversions.ClassifyConversionFromType(expressionType, patternType, ref useSiteDiagnostics);
conversion = conversions.ClassifyBuiltInConversion(expressionType, patternType, ref useSiteDiagnostics);
var result = Binder.GetIsOperatorConstantResult(expressionType, patternType, conversion.Kind, operandConstantValue, operandCouldBeNull);
return
(result == null) ? (bool?)null :
......
......@@ -164,7 +164,7 @@ private BoundExpression CompareWithConstant(BoundExpression input, BoundExpressi
// use site diagnostics will already have been reported during binding.
HashSet<DiagnosticInfo> ignoredDiagnostics = null;
var sourceType = source.Type.IsDynamic() ? _compilation.GetSpecialType(SpecialType.System_Object) : source.Type;
var conversionKind = _compilation.Conversions.ClassifyConversionFromType(sourceType, targetType, ref ignoredDiagnostics).Kind;
var conversionKind = _compilation.Conversions.ClassifyBuiltInConversion(sourceType, targetType, ref ignoredDiagnostics).Kind;
var constantResult = Binder.GetIsOperatorConstantResult(sourceType, targetType, conversionKind, source.ConstantValue, requiredNullTest);
return
constantResult == ConstantValue.True ? true :
......
......@@ -504,7 +504,9 @@ public BoundAsOperator As(BoundExpression operand, TypeSymbol type)
public BoundIsOperator Is(BoundExpression operand, TypeSymbol type)
{
HashSet<DiagnosticInfo> discarded = null;
Conversion c = Compilation.Conversions.ClassifyConversionFromExpression(operand, type, ref discarded);
// Because compiler-generated nodes are not lowered, this conversion is not used later in the compiler.
// But it is a required part of the `BoundIsOperator` node, so we compute a conversion here.
Conversion c = Compilation.Conversions.ClassifyBuiltInConversion(operand.Type, type, ref discarded);
return new BoundIsOperator(this.Syntax, operand, Type(type), c, SpecialType(Microsoft.CodeAnalysis.SpecialType.System_Boolean)) { WasCompilerGenerated = true };
}
......
......@@ -270,6 +270,102 @@ .maxstack 3
IL_003a: nop
IL_003b: nop
IL_003c: ret
}");
}
[Fact, WorkItem(24522, "https://github.com/dotnet/roslyn/issues/24522")]
public void IgnoreDeclaredConversion_01()
{
var source =
@"class Base<T>
{
public static implicit operator Derived(Base<T> obj)
{
return new Derived();
}
}
class Derived : Base<object>
{
}
class Program
{
static void Main(string[] args)
{
Base<object> x = new Derived();
System.Console.WriteLine(x is Derived);
System.Console.WriteLine(x is Derived y);
switch (x)
{
case Derived z: System.Console.WriteLine(true); break;
}
System.Console.WriteLine(null != (x as Derived));
}
}";
var compilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, references: new[] { LinqAssemblyRef });
compilation.VerifyDiagnostics();
var expectedOutput =
@"True
True
True
True";
var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
compVerifier.VerifyIL("Program.Main",
@"{
// Code size 94 (0x5e)
.maxstack 2
.locals init (Base<object> V_0, //x
Derived V_1, //y
Base<object> V_2,
Derived V_3,
Derived V_4, //z
Base<object> V_5)
IL_0000: nop
IL_0001: newobj ""Derived..ctor()""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: isinst ""Derived""
IL_000d: ldnull
IL_000e: cgt.un
IL_0010: call ""void System.Console.WriteLine(bool)""
IL_0015: nop
IL_0016: ldloc.0
IL_0017: isinst ""Derived""
IL_001c: dup
IL_001d: stloc.1
IL_001e: ldnull
IL_001f: cgt.un
IL_0021: call ""void System.Console.WriteLine(bool)""
IL_0026: nop
IL_0027: ldloc.0
IL_0028: stloc.s V_5
IL_002a: ldloc.s V_5
IL_002c: stloc.2
IL_002d: ldloc.2
IL_002e: brtrue.s IL_0032
IL_0030: br.s IL_003e
IL_0032: ldloc.2
IL_0033: isinst ""Derived""
IL_0038: dup
IL_0039: stloc.3
IL_003a: brfalse.s IL_003e
IL_003c: br.s IL_0040
IL_003e: br.s IL_004e
IL_0040: ldloc.3
IL_0041: stloc.s V_4
IL_0043: br.s IL_0045
IL_0045: ldc.i4.1
IL_0046: call ""void System.Console.WriteLine(bool)""
IL_004b: nop
IL_004c: br.s IL_004e
IL_004e: ldloc.0
IL_004f: isinst ""Derived""
IL_0054: ldnull
IL_0055: cgt.un
IL_0057: call ""void System.Console.WriteLine(bool)""
IL_005c: nop
IL_005d: ret
}");
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册