diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
index eadedbb2740344fafc537c36182794267398be63..42648bd0353c2b8a2a65e3ce422072171cbe01d6 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
@@ -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];
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
index c783ac88ae433760caf2553c81a73eb8831d7c3e..d50de799103477460982da7e0403f09d5c22aad2 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
@@ -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;
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
index 7a1975a98f5f2d5aeee3a9d91c2534093fdd1bde..65d87f9cc823228c76954abaf9d7e029e827d251 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
+++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
@@ -9151,6 +9151,15 @@ internal class CSharpResources {
}
}
+ ///
+ /// Looks up a localized string similar to The first operand of an 'as' operator may not be a tuple literal without a natural type..
+ ///
+ internal static string ERR_TypelessTupleInAs {
+ get {
+ return ResourceManager.GetString("ERR_TypelessTupleInAs", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Type parameter declaration must be an identifier not a type.
///
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index 9227afe9d86e806e4369852a1c8969cfe97905ce..13a64ea0367ed764d5afcdf8f17fbad8b500037d 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -2165,6 +2165,9 @@ If such a class is used as a base class and if the deriving class defines a dest
The first operand of an 'is' or 'as' operator may not be a lambda expression, anonymous method, or method group.
+
+ The first operand of an 'as' operator may not be a tuple literal without a natural type.
+
An expression tree may not contain a multidimensional array initializer
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index 40cbe2de7be995367e407f34fbe9648f2ba005a5..6c6cbeb3ee268f32307f12d3cfb496b61dcaecc4 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -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
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
index 2032304befd1c88b3141c3bced54078db05e3594..4448de074facf0ec05df2ced93b5ba0151eb9848 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
@@ -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().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().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();
+
+ 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();
+ 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
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()
+ {
+ 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
diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb
index 05b2da99f587c9bf61cb25069814970419763204..63170568905e5d2e4130fb3dde3bbc24cfc2b438 100644
--- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb
+++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb
@@ -7863,6 +7863,336 @@ BC30512: Option Strict On disallows implicit conversions from 'Double' to 'Strin
End Sub
+
+ Public Sub TupleCTypeNullableConversionWithTypelessTuple()
+ Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
+
+
+, 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
+
+
+ Public Sub TupleDirectCastNullableConversionWithTypelessTuple()
+ Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
+
+
+, 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
+
+
+ Public Sub TupleTryCastNullableConversionWithTypelessTuple()
+ Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
+
+
+, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
+
+ comp.AssertTheseDiagnostics(
+BC30792: 'TryCast' operand must be reference type, but '(Integer, String)?' is a value type.
+ Dim x As (Integer, String)? = TryCast((1, Nothing), (Integer, String)?)
+ ~~~~~~~~~~~~~~~~~~
+ )
+
+ 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
+
+
+ Public Sub TupleTryCastNullableConversionWithTypelessTuple2()
+ Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
+
+
+, additionalRefs:=s_valueTupleRefs)
+
+ comp.AssertTheseDiagnostics(
+BC30311: Value of type '(Integer, Object)' cannot be converted to 'C(Of Integer, T)'.
+ Dim x = TryCast((0, Nothing), C(Of Integer, T))
+ ~~~~~~~~~~~~
+ )
+
+ 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
+
+
+ Public Sub TupleImplicitNullableConversionWithTypelessTuple()
+ Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
+
+
+, 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
+
+
+ Public Sub ImplicitConversionOnTypelessTupleWithUserConversion()
+ Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
+
+
+, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
+
+ comp.AssertTheseDiagnostics(
+BC30311: Value of type '(Integer, Object)' cannot be converted to 'C?'.
+ Dim y As C? = (2, Nothing)
+ ~~~~~~~~~~~~
+ )
+
+ 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
+
+
+ Public Sub DirectCastOnTypelessTupleWithUserConversion()
+ Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
+
+
+, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
+
+ comp.AssertTheseDiagnostics(
+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?)
+ ~~~~~~~~~~~~
+ )
+
+ 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
+
+
+ Public Sub TryCastOnTypelessTupleWithUserConversion()
+ Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
+
+
+, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
+
+ comp.AssertTheseDiagnostics(
+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?)
+ ~~
+ )
+
+ 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
+
+
+ Public Sub CTypeOnTypelessTupleWithUserConversion()
+ Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
+
+
+, additionalRefs:=s_valueTupleRefs, options:=TestOptions.DebugExe)
+
+ comp.AssertTheseDiagnostics(
+BC30311: Value of type '(Integer, Object)' cannot be converted to 'C?'.
+ Dim y = CType((2, Nothing), C?)
+ ~~~~~~~~~~~~
+ )
+
+ 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
+
Public Sub TupleTargetTypeLambda()
@@ -8261,6 +8591,35 @@ End Module
End Sub
+
+
+
+ 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
+
Public Sub RetargetTupleErrorType()
Dim libComp = CreateCompilationWithMscorlibAndVBRuntime(
diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/InlineTemporary/InlineTemporaryTests.vb b/src/EditorFeatures/VisualBasicTest/CodeActions/InlineTemporary/InlineTemporaryTests.vb
index ee0735d40dc86a7abd4fcc9ec35be7c49f4204d6..5d369567f276e7f47111f89c0631f07de3a45201 100644
--- a/src/EditorFeatures/VisualBasicTest/CodeActions/InlineTemporary/InlineTemporaryTests.vb
+++ b/src/EditorFeatures/VisualBasicTest/CodeActions/InlineTemporary/InlineTemporaryTests.vb
@@ -4397,6 +4397,29 @@ Class C
}
End Sub
End Class
+"
+ Await TestInRegularAndScriptAsync(code, expected, ignoreTrivia:=False)
+ End Function
+
+
+
+ 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