提交 79b2bc6e 编写于 作者: J Julien Couvreur 提交者: GitHub

Fix crash with typeless tuple in "as" operator (#18416)

上级 956b17ef
......@@ -94,7 +94,7 @@ internal partial class Binder
}
if (conversion.IsTupleLiteralConversion ||
(conversion.Kind == ConversionKind.ImplicitNullable && conversion.UnderlyingConversions[0].IsTupleLiteralConversion))
(conversion.IsNullable && conversion.UnderlyingConversions[0].IsTupleLiteralConversion))
{
return CreateTupleLiteralConversion(syntax, (BoundTupleLiteral)source, conversion, isCast, destination, diagnostics);
}
......@@ -343,12 +343,12 @@ private BoundExpression CreateTupleLiteralConversion(SyntaxNode syntax, BoundTup
{
// We have a successful tuple conversion; rather than producing a separate conversion node
// which is a conversion on top of a tuple literal, tuple conversion is an element-wise conversion of arguments.
Debug.Assert((conversion.Kind == ConversionKind.ImplicitNullable) == destination.IsNullableType());
Debug.Assert(conversion.IsNullable == destination.IsNullableType());
var destinationWithoutNullable = destination;
var conversionWithoutNullable = conversion;
if (conversion.Kind == ConversionKind.ImplicitNullable)
if (conversion.IsNullable)
{
destinationWithoutNullable = destination.GetNullableUnderlyingType();
conversionWithoutNullable = conversion.UnderlyingConversions[0];
......
......@@ -3009,6 +3009,14 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa
}
return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
case BoundKind.TupleLiteral:
if ((object)operand.Type == null)
{
Error(diagnostics, ErrorCode.ERR_TypelessTupleInAs, node);
return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
}
break;
}
if (operand.HasAnyErrors || targetTypeKind == TypeKind.Error)
......@@ -3073,12 +3081,6 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa
type: GetSpecialType(SpecialType.System_Object, diagnostics, node));
}
if (operand.Kind == BoundKind.MethodGroup)
{
Error(diagnostics, ErrorCode.ERR_NoExplicitBuiltinConv, node, MessageID.IDS_MethodGroup.Localize(), targetType);
return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
}
var operandType = operand.Type;
Debug.Assert((object)operandType != null);
var operandTypeKind = operandType.TypeKind;
......
......@@ -9151,6 +9151,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to The first operand of an &apos;as&apos; operator may not be a tuple literal without a natural type..
/// </summary>
internal static string ERR_TypelessTupleInAs {
get {
return ResourceManager.GetString("ERR_TypelessTupleInAs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type parameter declaration must be an identifier not a type.
/// </summary>
......
......@@ -2165,6 +2165,9 @@ If such a class is used as a base class and if the deriving class defines a dest
<data name="ERR_LambdaInIsAs" xml:space="preserve">
<value>The first operand of an 'is' or 'as' operator may not be a lambda expression, anonymous method, or method group.</value>
</data>
<data name="ERR_TypelessTupleInAs" xml:space="preserve">
<value>The first operand of an 'as' operator may not be a tuple literal without a natural type.</value>
</data>
<data name="ERR_ExpressionTreeContainsMultiDimensionalArrayInitializer" xml:space="preserve">
<value>An expression tree may not contain a multidimensional array initializer</value>
</data>
......
......@@ -1475,6 +1475,7 @@ internal enum ErrorCode
ERR_CompilerAndLanguageVersion = 8304,
WRN_Experimental = 8305,
ERR_TupleInferredNamesNotAvailable = 8306,
ERR_TypelessTupleInAs = 8307,
#region diagnostics for C# 7.1
......
......@@ -6605,6 +6605,176 @@ static void Main()
);
}
[Fact]
public void TupleExplicitNullableConversionWithTypelessTuple()
{
var source = @"
class C
{
static void Main()
{
var x = ((int, string)?) (1, null);
System.Console.Write(x);
}
}
";
var comp = CreateStandardCompilation(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, expectedOutput: "(1, )");
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var declaration = tree.GetRoot().DescendantNodes().OfType<LocalDeclarationStatementSyntax>().First();
var value = declaration.Declaration.Variables.First().Initializer.Value;
Assert.Equal("((int, string)?) (1, null)", value.ToString());
var castConversion = model.GetConversion(value);
Assert.Equal(ConversionKind.Identity, castConversion.Kind);
var tuple = ((CastExpressionSyntax)value).Expression;
Assert.Equal("(1, null)", tuple.ToString());
var tupleConversion = model.GetConversion(tuple);
Assert.Equal(ConversionKind.ExplicitNullable, tupleConversion.Kind);
Assert.Equal(1, tupleConversion.UnderlyingConversions.Length);
Assert.Equal(ConversionKind.ExplicitTupleLiteral, tupleConversion.UnderlyingConversions[0].Kind);
}
[Fact]
public void TupleImplicitNullableConversionWithTypelessTuple()
{
var source = @"
class C
{
static void Main()
{
(int, string)? x = (1, null);
System.Console.Write(x);
}
}
";
var comp = CreateStandardCompilation(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, expectedOutput: "(1, )");
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var declaration = tree.GetRoot().DescendantNodes().OfType<LocalDeclarationStatementSyntax>().First();
var value = declaration.Declaration.Variables.First().Initializer.Value;
Assert.Equal("(1, null)", value.ToString());
var tupleConversion = model.GetConversion(value);
Assert.Equal(ConversionKind.ImplicitNullable, tupleConversion.Kind);
Assert.Equal(1, tupleConversion.UnderlyingConversions.Length);
Assert.Equal(ConversionKind.ImplicitTupleLiteral, tupleConversion.UnderlyingConversions[0].Kind);
}
[Fact]
public void TupleImplicitNullableAndCustomConversionsWithTypelessTuple()
{
var source = @"
struct C
{
static void Main()
{
C? x = (1, null);
System.Console.Write(x);
var x2 = (C)(2, null);
System.Console.Write(x2);
var x3 = (C?)(3, null);
System.Console.Write(x3);
}
public static implicit operator C((int, string) x)
{
return new C();
}
}
";
var comp = CreateStandardCompilation(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, expectedOutput: "CCC");
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var tuples = tree.GetRoot().DescendantNodes().OfType<TupleExpressionSyntax>();
var tuple1 = tuples.ElementAt(0);
Assert.Equal("(1, null)", tuple1.ToString());
Assert.Null(model.GetTypeInfo(tuple1).Type);
Assert.Equal("C?", model.GetTypeInfo(tuple1).ConvertedType.ToTestDisplayString());
var conversion1 = model.GetConversion(tuple1);
Assert.Equal(ConversionKind.ImplicitUserDefined, conversion1.Kind);
Assert.True(conversion1.UnderlyingConversions.IsDefault);
var tuple2 = tuples.ElementAt(1);
Assert.Equal("(2, null)", tuple2.ToString());
Assert.Null(model.GetTypeInfo(tuple2).Type);
Assert.Equal("(System.Int32, System.String)", model.GetTypeInfo(tuple2).ConvertedType.ToTestDisplayString());
var conversion2 = model.GetConversion(tuple2);
Assert.Equal(ConversionKind.ImplicitTupleLiteral, conversion2.Kind);
Assert.False(conversion2.UnderlyingConversions.IsDefault);
var tuple3 = tuples.ElementAt(2);
Assert.Equal("(3, null)", tuple3.ToString());
Assert.Null(model.GetTypeInfo(tuple3).Type);
Assert.Equal("(System.Int32, System.String)", model.GetTypeInfo(tuple3).ConvertedType.ToTestDisplayString());
var conversion3 = model.GetConversion(tuple3);
Assert.Equal(ConversionKind.ImplicitTupleLiteral, conversion3.Kind);
Assert.False(conversion3.UnderlyingConversions.IsDefault);
}
[Fact]
public void TupleImplicitNullableAndCustomConversionsWithTypelessTupleInAsOperator()
{
var source = @"
struct C
{
static void Main()
{
var x4 = (1, null) as C;
System.Console.Write(x4);
var x5 = (2, null) as C?;
System.Console.Write(x5);
}
public static implicit operator C((int, string) x)
{
return new C();
}
}
";
var comp = CreateStandardCompilation(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe);
comp.VerifyEmitDiagnostics(
// (6,18): error CS8305: The first operand of an 'as' operator may not be a tuple literal without a natural type.
// var x4 = (1, null) as C;
Diagnostic(ErrorCode.ERR_TypelessTupleInAs, "(1, null) as C").WithLocation(6, 18),
// (8,18): error CS8305: The first operand of an 'as' operator may not be a tuple literal without a natural type.
// var x5 = (2, null) as C?;
Diagnostic(ErrorCode.ERR_TypelessTupleInAs, "(2, null) as C?").WithLocation(8, 18)
);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var tuples = tree.GetRoot().DescendantNodes().OfType<TupleExpressionSyntax>();
verifyTuple("(1, null)", tuples.ElementAt(0));
verifyTuple("(2, null)", tuples.ElementAt(1));
void verifyTuple(string expected, TupleExpressionSyntax tuple)
{
Assert.Equal(expected, tuple.ToString());
Assert.Null(model.GetTypeInfo(tuple).Type);
Assert.Null(model.GetTypeInfo(tuple).ConvertedType);
var conversion = model.GetConversion(tuple);
Assert.Equal(ConversionKind.Identity, conversion.Kind);
Assert.True(conversion.UnderlyingConversions.IsDefault);
}
}
[Fact]
public void TupleTargetTypeLambda()
{
......@@ -7069,8 +7239,8 @@ static void Main()
Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString());
Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString());
Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString());
Assert.Equal(Conversion.Identity, model.GetConversion(node));
Assert.Equal("(System.Int16 c, System.String d)?", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString());
Assert.Equal(ConversionKind.ExplicitNullable, model.GetConversion(node).Kind);
// semantic model returns topmost conversion from the sequence of conversions for
// ((short c, string d)?)(e: 1, f: ""hello"")
......@@ -7295,8 +7465,8 @@ static void Main()
Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString());
Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString());
Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString());
Assert.Equal(Conversion.Identity, model.GetConversion(node));
Assert.Equal("(System.Int32 c, System.String d)?", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString());
Assert.Equal(ConversionKind.ExplicitNullable, model.GetConversion(node).Kind);
// semantic model returns topmost conversion from the sequence of conversions for
// ((int c, string d)?)(e: 1, f: ""hello"")
......@@ -22680,5 +22850,27 @@ public struct ValueTuple<T1, T2>
Assert.False(tuple3.IsErrorType());
Assert.Equal(libWithVTRef.Display, tuple3.ContainingAssembly.MetadataName.ToString());
}
[Fact]
[WorkItem(17962, "https://github.com/dotnet/roslyn/issues/17962")]
public void TupleWithAsOperator()
{
var source = @"
class C
{
void M<T>()
{
var x = (0, null) as (int, T)?;
System.Console.WriteLine(x == null);
}
}";
var comp = CreateStandardCompilation(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (6,17): error CS8304: The first operand of an 'as' operator may not be a tuple literal without a natural type.
// var x = (0, null) as (int, T)?;
Diagnostic(ErrorCode.ERR_TypelessTupleInAs, "(0, null) as (int, T)?").WithLocation(6, 17)
);
}
}
}
\ No newline at end of file
......@@ -7863,6 +7863,336 @@ BC30512: Option Strict On disallows implicit conversions from 'Double' to 'Strin
End Sub
<Fact>
Public Sub TupleCTypeNullableConversionWithTypelessTuple()
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
<file name="a.vb"><![CDATA[
Option Strict On
Imports System
Class C
Shared Sub Main()
Dim x As (Integer, String)? = CType((1, Nothing), (Integer, String)?)
Console.Write(x)
End Sub
End Class
]]></file>
</compilation>, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
comp.AssertNoDiagnostics()
CompileAndVerify(comp, expectedOutput:="(1, )")
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim node = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().Single()
Assert.Equal("(1, Nothing)", node.ToString())
Assert.Null(model.GetTypeInfo(node).Type)
Assert.Equal("System.Nullable(Of (System.Int32, System.String))", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningNullableTuple, model.GetConversion(node).Kind)
Assert.Equal("System.Nullable(Of (System.Int32, System.String))", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString())
Assert.Equal("System.Nullable(Of (System.Int32, System.String))", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString())
End Sub
<Fact>
Public Sub TupleDirectCastNullableConversionWithTypelessTuple()
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
<file name="a.vb"><![CDATA[
Option Strict On
Imports System
Class C
Shared Sub Main()
Dim x As (Integer, String)? = DirectCast((1, Nothing), (Integer, String)?)
Console.Write(x)
End Sub
End Class
]]></file>
</compilation>, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
comp.AssertNoDiagnostics()
CompileAndVerify(comp, expectedOutput:="(1, )")
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim node = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().Single()
Assert.Equal("(1, Nothing)", node.ToString())
Assert.Null(model.GetTypeInfo(node).Type)
Assert.Equal("System.Nullable(Of (System.Int32, System.String))", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningNullableTuple, model.GetConversion(node).Kind)
Assert.Equal("System.Nullable(Of (System.Int32, System.String))", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString())
Assert.Equal("System.Nullable(Of (System.Int32, System.String))", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString())
End Sub
<Fact>
Public Sub TupleTryCastNullableConversionWithTypelessTuple()
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
<file name="a.vb"><![CDATA[
Option Strict On
Imports System
Class C
Shared Sub Main()
Dim x As (Integer, String)? = TryCast((1, Nothing), (Integer, String)?)
Console.Write(x)
End Sub
End Class
]]></file>
</compilation>, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
comp.AssertTheseDiagnostics(<errors>
BC30792: 'TryCast' operand must be reference type, but '(Integer, String)?' is a value type.
Dim x As (Integer, String)? = TryCast((1, Nothing), (Integer, String)?)
~~~~~~~~~~~~~~~~~~
</errors>)
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim node = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().Single()
Assert.Equal("(1, Nothing)", node.ToString())
Assert.Null(model.GetTypeInfo(node).Type)
Assert.Equal("(System.Int32, System.Object)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningTuple, model.GetConversion(node).Kind)
Assert.Equal("System.Nullable(Of (System.Int32, System.String))", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString())
Assert.Equal("System.Nullable(Of (System.Int32, System.String))", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString())
End Sub
<Fact>
Public Sub TupleTryCastNullableConversionWithTypelessTuple2()
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
<file name="a.vb"><![CDATA[
Option Strict On
Imports System
Class C
Shared Sub M(Of T)()
Dim x = TryCast((0, Nothing), C(Of Integer, T))
Console.Write(x)
End Sub
End Class
Class C(Of T, U)
End Class
]]></file>
</compilation>, additionalRefs:=s_valueTupleRefs)
comp.AssertTheseDiagnostics(<errors>
BC30311: Value of type '(Integer, Object)' cannot be converted to 'C(Of Integer, T)'.
Dim x = TryCast((0, Nothing), C(Of Integer, T))
~~~~~~~~~~~~
</errors>)
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim node = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().Single()
Assert.Equal("(0, Nothing)", node.ToString())
Assert.Null(model.GetTypeInfo(node).Type)
Assert.Equal("(System.Int32, System.Object)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningTuple, model.GetConversion(node).Kind)
Assert.Equal("C(Of System.Int32, T)", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString())
Assert.Equal("C(Of System.Int32, T)", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString())
End Sub
<Fact>
Public Sub TupleImplicitNullableConversionWithTypelessTuple()
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
<file name="a.vb"><![CDATA[
Option Strict On
Class C
Shared Sub Main()
Dim x As (Integer, String)? = (1, Nothing)
System.Console.Write(x)
End Sub
End Class
]]></file>
</compilation>, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
comp.AssertNoDiagnostics()
CompileAndVerify(comp, expectedOutput:="(1, )")
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim node = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().Single()
Assert.Equal("(1, Nothing)", node.ToString())
Assert.Null(model.GetTypeInfo(node).Type)
Assert.Equal("System.Nullable(Of (System.Int32, System.String))", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningNullableTuple, model.GetConversion(node).Kind)
End Sub
<Fact>
Public Sub ImplicitConversionOnTypelessTupleWithUserConversion()
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
<file name="a.vb"><![CDATA[
Option Strict Off
Structure C
Shared Sub Main()
Dim x As C = (1, Nothing)
Dim y As C? = (2, Nothing)
End Sub
Public Shared Widening Operator CType(ByVal d As (Integer, String)) As C
Return New C()
End Operator
End Structure
]]></file>
</compilation>, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
comp.AssertTheseDiagnostics(<errors>
BC30311: Value of type '(Integer, Object)' cannot be converted to 'C?'.
Dim y As C? = (2, Nothing)
~~~~~~~~~~~~
</errors>)
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim firstTuple = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().ElementAt(0)
Assert.Equal("(1, Nothing)", firstTuple.ToString())
Assert.Null(model.GetTypeInfo(firstTuple).Type)
Assert.Equal("C", model.GetTypeInfo(firstTuple).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.Narrowing Or ConversionKind.UserDefined, model.GetConversion(firstTuple).Kind)
Dim secondTuple = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().ElementAt(1)
Assert.Equal("(2, Nothing)", secondTuple.ToString())
Assert.Null(model.GetTypeInfo(secondTuple).Type)
Assert.Equal("System.Nullable(Of C)", model.GetTypeInfo(secondTuple).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.DelegateRelaxationLevelNone, model.GetConversion(secondTuple).Kind)
End Sub
<Fact>
Public Sub DirectCastOnTypelessTupleWithUserConversion()
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
<file name="a.vb"><![CDATA[
Option Strict Off
Structure C
Shared Sub Main()
Dim x = DirectCast((1, Nothing), C)
Dim y = DirectCast((2, Nothing), C?)
End Sub
Public Shared Widening Operator CType(ByVal d As (Integer, String)) As C
Return New C()
End Operator
End Structure
]]></file>
</compilation>, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
comp.AssertTheseDiagnostics(<errors>
BC30311: Value of type '(Integer, Object)' cannot be converted to 'C'.
Dim x = DirectCast((1, Nothing), C)
~~~~~~~~~~~~
BC30311: Value of type '(Integer, Object)' cannot be converted to 'C?'.
Dim y = DirectCast((2, Nothing), C?)
~~~~~~~~~~~~
</errors>)
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim firstTuple = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().ElementAt(0)
Assert.Equal("(1, Nothing)", firstTuple.ToString())
Assert.Null(model.GetTypeInfo(firstTuple).Type)
Assert.Equal("(System.Int32, System.Object)", model.GetTypeInfo(firstTuple).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningTuple, model.GetConversion(firstTuple).Kind)
Dim secondTuple = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().ElementAt(1)
Assert.Equal("(2, Nothing)", secondTuple.ToString())
Assert.Null(model.GetTypeInfo(secondTuple).Type)
Assert.Equal("(System.Int32, System.Object)", model.GetTypeInfo(secondTuple).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningTuple, model.GetConversion(secondTuple).Kind)
End Sub
<Fact>
Public Sub TryCastOnTypelessTupleWithUserConversion()
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
<file name="a.vb"><![CDATA[
Option Strict Off
Structure C
Shared Sub Main()
Dim x = TryCast((1, Nothing), C)
Dim y = TryCast((2, Nothing), C?)
End Sub
Public Shared Widening Operator CType(ByVal d As (Integer, String)) As C
Return New C()
End Operator
End Structure
]]></file>
</compilation>, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
comp.AssertTheseDiagnostics(<errors>
BC30792: 'TryCast' operand must be reference type, but 'C' is a value type.
Dim x = TryCast((1, Nothing), C)
~
BC30792: 'TryCast' operand must be reference type, but 'C?' is a value type.
Dim y = TryCast((2, Nothing), C?)
~~
</errors>)
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim firstTuple = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().ElementAt(0)
Assert.Equal("(1, Nothing)", firstTuple.ToString())
Assert.Null(model.GetTypeInfo(firstTuple).Type)
Assert.Equal("(System.Int32, System.Object)", model.GetTypeInfo(firstTuple).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningTuple, model.GetConversion(firstTuple).Kind)
Dim secondTuple = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().ElementAt(1)
Assert.Equal("(2, Nothing)", secondTuple.ToString())
Assert.Null(model.GetTypeInfo(secondTuple).Type)
Assert.Equal("(System.Int32, System.Object)", model.GetTypeInfo(secondTuple).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningTuple, model.GetConversion(secondTuple).Kind)
End Sub
<Fact>
Public Sub CTypeOnTypelessTupleWithUserConversion()
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
<file name="a.vb"><![CDATA[
Option Strict Off
Structure C
Shared Sub Main()
Dim x = CType((1, Nothing), C)
Dim y = CType((2, Nothing), C?)
End Sub
Public Shared Widening Operator CType(ByVal d As (Integer, String)) As C
Return New C()
End Operator
End Structure
]]></file>
</compilation>, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
comp.AssertTheseDiagnostics(<errors>
BC30311: Value of type '(Integer, Object)' cannot be converted to 'C?'.
Dim y = CType((2, Nothing), C?)
~~~~~~~~~~~~
</errors>)
Dim tree = comp.SyntaxTrees.Single()
Dim model = comp.GetSemanticModel(tree)
Dim firstTuple = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().ElementAt(0)
Assert.Equal("(1, Nothing)", firstTuple.ToString())
Assert.Null(model.GetTypeInfo(firstTuple).Type)
Assert.Equal("(System.Int32, System.Object)", model.GetTypeInfo(firstTuple).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningTuple, model.GetConversion(firstTuple).Kind)
Dim secondTuple = tree.GetRoot().DescendantNodes().OfType(Of TupleExpressionSyntax)().ElementAt(1)
Assert.Equal("(2, Nothing)", secondTuple.ToString())
Assert.Null(model.GetTypeInfo(secondTuple).Type)
Assert.Equal("(System.Int32, System.Object)", model.GetTypeInfo(secondTuple).ConvertedType.ToTestDisplayString())
Assert.Equal(ConversionKind.WideningTuple, model.GetConversion(secondTuple).Kind)
End Sub
<Fact>
Public Sub TupleTargetTypeLambda()
......@@ -8261,6 +8591,35 @@ End Module
End Sub
<Fact(Skip:="See bug 16697")>
<WorkItem(16697, "https://github.com/dotnet/roslyn/issues/16697")>
Public Sub GetSymbolInfo_01()
Dim source = "
Class C
Shared Sub Main()
Dim x1 = (Alice:=1, ""hello"")
Dim Alice = x1.Alice
End Sub
End Class
"
Dim tree = Parse(source, options:=TestOptions.Regular)
Dim comp = CreateCompilationWithMscorlib(tree)
Dim model = comp.GetSemanticModel(tree, ignoreAccessibility:=False)
Dim nodes = tree.GetCompilationUnitRoot().DescendantNodes()
Dim nc = nodes.OfType(Of NameColonEqualsSyntax)().ElementAt(0)
Dim sym = model.GetSymbolInfo(nc.Name)
Assert.Equal("Alice", sym.Symbol.Name)
Assert.Equal(SymbolKind.Field, sym.Symbol.Kind) ' Incorrectly returns Local
Assert.Equal(nc.Name.GetLocation(), sym.Symbol.Locations(0)) ' Incorrect location
End Sub
<Fact>
Public Sub RetargetTupleErrorType()
Dim libComp = CreateCompilationWithMscorlibAndVBRuntime(
......
......@@ -4397,6 +4397,29 @@ Class C
}
End Sub
End Class
"
Await TestInRegularAndScriptAsync(code, expected, ignoreTrivia:=False)
End Function
<Fact(Skip:="InvalidCastException"), Trait(Traits.Feature, Traits.Features.CodeActionsInlineTemporary)>
<WorkItem(16697, "https://github.com/dotnet/roslyn/issues/16697")>
Public Async Function TupleElementNameIsNotReplaced() As Task
' The name of the named element has bad symbol info and gets replaced with (1 + 2)
Dim code = "
Class C
Sub M()
Dim [||]i = 1 + 2
Dim t = (i, i:=3)
End Sub
End Class
"
Dim expected = "
Class C
Sub M()
Dim t = (1 + 2, i:=3)
End Sub
End Class
"
Await TestInRegularAndScriptAsync(code, expected, ignoreTrivia:=False)
End Function
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册