/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Semantic/Semantics/ValueTupleTests.cs
847 строк
42 KB
DoctorKrolic
Do not convert tuple expression with error to a bad expression too early (#78645)
28 май 2025, 19:31
Не верифицирован
28 май 2025, 19:31
e2b26ff
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.UnitTests; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.Semantics { public class ValueTupleTests : CompilingTestBase { [Fact] public void TestWellKnownMembersForValueTuple() { var source = @" namespace System { struct ValueTuple<T1> { public T1 Item1; } struct ValueTuple<T1, T2> { public T1 Item1; public T2 Item2; } struct ValueTuple<T1, T2, T3> { public T1 Item1; public T2 Item2; public T3 Item3; } struct ValueTuple<T1, T2, T3, T4> { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; } struct ValueTuple<T1, T2, T3, T4, T5> { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; } struct ValueTuple<T1, T2, T3, T4, T5, T6> { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; } struct ValueTuple<T1, T2, T3, T4, T5, T6, T7> { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; } struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; } }"; var comp = CreateCompilation(source); Assert.Equal("T1 System.ValueTuple<T1>.Item1", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T1__Item1).ToTestDisplayString()); Assert.Equal("T1 (T1, T2).Item1", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T2__Item1).ToTestDisplayString()); Assert.Equal("T2 (T1, T2).Item2", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T2__Item2).ToTestDisplayString()); Assert.Equal("T1 (T1, T2, T3).Item1", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T3__Item1).ToTestDisplayString()); Assert.Equal("T2 (T1, T2, T3).Item2", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T3__Item2).ToTestDisplayString()); Assert.Equal("T3 (T1, T2, T3).Item3", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T3__Item3).ToTestDisplayString()); Assert.Equal("T1 (T1, T2, T3, T4).Item1", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T4__Item1).ToTestDisplayString()); Assert.Equal("T2 (T1, T2, T3, T4).Item2", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T4__Item2).ToTestDisplayString()); Assert.Equal("T3 (T1, T2, T3, T4).Item3", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T4__Item3).ToTestDisplayString()); Assert.Equal("T4 (T1, T2, T3, T4).Item4", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T4__Item4).ToTestDisplayString()); Assert.Equal("T1 (T1, T2, T3, T4, T5).Item1", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__Item1).ToTestDisplayString()); Assert.Equal("T2 (T1, T2, T3, T4, T5).Item2", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__Item2).ToTestDisplayString()); Assert.Equal("T3 (T1, T2, T3, T4, T5).Item3", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__Item3).ToTestDisplayString()); Assert.Equal("T4 (T1, T2, T3, T4, T5).Item4", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__Item4).ToTestDisplayString()); Assert.Equal("T5 (T1, T2, T3, T4, T5).Item5", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__Item5).ToTestDisplayString()); Assert.Equal("T1 (T1, T2, T3, T4, T5, T6).Item1", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item1).ToTestDisplayString()); Assert.Equal("T2 (T1, T2, T3, T4, T5, T6).Item2", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item2).ToTestDisplayString()); Assert.Equal("T3 (T1, T2, T3, T4, T5, T6).Item3", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item3).ToTestDisplayString()); Assert.Equal("T4 (T1, T2, T3, T4, T5, T6).Item4", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item4).ToTestDisplayString()); Assert.Equal("T5 (T1, T2, T3, T4, T5, T6).Item5", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item5).ToTestDisplayString()); Assert.Equal("T6 (T1, T2, T3, T4, T5, T6).Item6", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item6).ToTestDisplayString()); Assert.Equal("T1 (T1, T2, T3, T4, T5, T6, T7).Item1", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item1).ToTestDisplayString()); Assert.Equal("T2 (T1, T2, T3, T4, T5, T6, T7).Item2", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item2).ToTestDisplayString()); Assert.Equal("T3 (T1, T2, T3, T4, T5, T6, T7).Item3", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item3).ToTestDisplayString()); Assert.Equal("T4 (T1, T2, T3, T4, T5, T6, T7).Item4", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item4).ToTestDisplayString()); Assert.Equal("T5 (T1, T2, T3, T4, T5, T6, T7).Item5", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item5).ToTestDisplayString()); Assert.Equal("T6 (T1, T2, T3, T4, T5, T6, T7).Item6", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item6).ToTestDisplayString()); Assert.Equal("T7 (T1, T2, T3, T4, T5, T6, T7).Item7", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item7).ToTestDisplayString()); Assert.Equal("T1 System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Item1", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item1).ToTestDisplayString()); Assert.Equal("T2 System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Item2", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item2).ToTestDisplayString()); Assert.Equal("T3 System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Item3", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item3).ToTestDisplayString()); Assert.Equal("T4 System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Item4", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item4).ToTestDisplayString()); Assert.Equal("T5 System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Item5", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item5).ToTestDisplayString()); Assert.Equal("T6 System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Item6", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item6).ToTestDisplayString()); Assert.Equal("T7 System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Item7", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item7).ToTestDisplayString()); Assert.Equal("TRest System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Rest", comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Rest).ToTestDisplayString()); } [Fact] public void TestMissingWellKnownMembersForValueTuple() { var comp = CreateCompilationWithMscorlib40(""); Assert.True(comp.GetWellKnownType(WellKnownType.System_ValueTuple_T1).IsErrorType()); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T1__Item1)); Assert.True(comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).IsErrorType()); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T2__Item1)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T2__Item2)); Assert.True(comp.GetWellKnownType(WellKnownType.System_ValueTuple_T3).IsErrorType()); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T3__Item1)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T3__Item2)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T3__Item3)); Assert.True(comp.GetWellKnownType(WellKnownType.System_ValueTuple_T4).IsErrorType()); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T4__Item1)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T4__Item2)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T4__Item3)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T4__Item4)); Assert.True(comp.GetWellKnownType(WellKnownType.System_ValueTuple_T5).IsErrorType()); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__Item1)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__Item2)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__Item3)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__Item4)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__Item5)); Assert.True(comp.GetWellKnownType(WellKnownType.System_ValueTuple_T6).IsErrorType()); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item1)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item2)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item3)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item4)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__Item6)); Assert.True(comp.GetWellKnownType(WellKnownType.System_ValueTuple_T7).IsErrorType()); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item1)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item2)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item3)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item4)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item6)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__Item7)); Assert.True(comp.GetWellKnownType(WellKnownType.System_ValueTuple_TRest).IsErrorType()); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item1)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item2)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item3)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item4)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item6)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Item7)); Assert.Null(comp.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__Rest)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60961")] public void MissingRest() { var source = """ (int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8) tuple = (1, 2, 3, 4, 5, 6, 7, 8); (_, _, _, _, _, _, _, int x) = tuple; System.Console.WriteLine(x); namespace System { public struct ValueTuple<T1> { public T1 Item1; public ValueTuple(T1 item1) { Item1 = item1; } } public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; // public TRest Rest; public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) { Item1 = item1; Item2 = item2; Item3 = item3; Item4 = item4; Item5 = item5; Item6 = item6; Item7 = item7; // Rest = rest; } } } """; var comp = CreateCompilation(source, assemblyName: "comp"); comp.VerifyDiagnostics(); comp.VerifyEmitDiagnostics( // (2,32): error CS8128: Member 'Rest' was not found on type 'ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (_, _, _, _, _, _, _, int x) = tuple; Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "tuple").WithArguments("Rest", "System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 32)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60961")] public void ExplicitInterfaceImplementation_Indexer_Partial() { var source = """ namespace System { public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> : System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)> where TRest : struct { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; object System.Runtime.CompilerServices.ITuple.this[int index] => throw null; } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,67): error CS0535: 'ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>' does not implement interface member 'IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>.Equals((T1, T2, T3, T4, T5, T6, T7, TRest))' // public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> : System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)> where TRest : struct Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>").WithArguments("System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>", "System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>.Equals((T1, T2, T3, T4, T5, T6, T7, TRest))").WithLocation(3, 67), // (13,16): error CS0540: 'ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>.ITuple.this[int]': containing type does not implement interface 'ITuple' // object System.Runtime.CompilerServices.ITuple.this[int index] => throw null; Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "System.Runtime.CompilerServices.ITuple").WithArguments("System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>.System.Runtime.CompilerServices.ITuple.this[int]", "System.Runtime.CompilerServices.ITuple").WithLocation(13, 16)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60961")] public void ExplicitInterfaceImplementation_Indexer() { var source = """ namespace System { public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> : System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>, System.Runtime.CompilerServices.ITuple where TRest : struct { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; public int Length => throw null; object System.Runtime.CompilerServices.ITuple.this[int index] => throw null; bool System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>.Equals((T1, T2, T3, T4, T5, T6, T7, TRest) other) => false; } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60961")] public void ExplicitInterfaceImplementation_Property() { var source = """ namespace System { public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> : System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>, System.Runtime.CompilerServices.ITuple where TRest : struct { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; int System.Runtime.CompilerServices.ITuple.Length => throw null; public object this[int index] => throw null; bool System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>.Equals((T1, T2, T3, T4, T5, T6, T7, TRest) other) => false; } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); } private const string Stubs = """ namespace System { public class Object { } public class ValueType { } public class String { } public struct Void { } public struct Boolean { } public struct Int32 { } public struct IntPtr { } public class Exception { } public class MulticastDelegate { } public struct ValueTuple<T> { } public class Enum { } public class Attribute { } public enum AttributeTargets { } public class AttributeUsageAttribute { public AttributeUsageAttribute(AttributeTargets validOn) { } public bool AllowMultiple { get; set; } public bool Inherited { get; set; } } namespace Reflection { public class DefaultMemberAttribute { public DefaultMemberAttribute(string memberName) { } } } } """; [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60961")] public void ExplicitInterfaceImplementation_Event() { var source = """ namespace System { public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> : System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>, System.Runtime.CompilerServices.ITuple where TRest : struct { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; public int Length => throw null; public object this[int index] => throw null; public bool Equals((T1, T2, T3, T4, T5, T6, T7, TRest) other) => throw null; event D System.Runtime.CompilerServices.ITuple.Tupled { add => throw null; remove => throw null; } } public interface IEquatable<T> { bool Equals(T other); } namespace Runtime.CompilerServices { public interface ITuple { event D Tupled; int Length { get; } object this[int index] { get; } } } public delegate void D(); } """; var comp = CreateEmptyCompilation(new[] { source, Stubs }); comp.VerifyEmitDiagnostics(EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60961")] public void ExplicitInterfaceImplementation_Operator() { var source = """ namespace System { public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> : System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>, System.Runtime.CompilerServices.ITuple where TRest : struct { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; public int Length => throw null; public object this[int index] => throw null; public bool Equals((T1, T2, T3, T4, T5, T6, T7, TRest) other) => throw null; static System.Runtime.CompilerServices.ITuple System.Runtime.CompilerServices.ITuple.operator +(System.Runtime.CompilerServices.ITuple a, System.Runtime.CompilerServices.ITuple b) => throw null; } public interface IEquatable<T> { bool Equals(T other); } namespace Runtime.CompilerServices { public interface ITuple { abstract static ITuple operator +(ITuple a, ITuple b); int Length { get; } object this[int index] { get; } } public static class RuntimeFeature { public const string VirtualStaticsInInterfaces = nameof(VirtualStaticsInInterfaces); } } } """; var comp = CreateEmptyCompilation(new[] { source, Stubs }); comp.VerifyEmitDiagnostics(EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60961")] public void ExplicitInterfaceImplementation_ConversionOperator() { var source = """ namespace System { public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> : System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>, System.Runtime.CompilerServices.ITuple<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>> where TRest : struct { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; public int Length => throw null; public object this[int index] => throw null; public bool Equals((T1, T2, T3, T4, T5, T6, T7, TRest) other) => throw null; static explicit System.Runtime.CompilerServices.ITuple<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>>.operator string(ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> x) => throw null; } public interface IEquatable<T> { bool Equals(T other); } namespace Runtime.CompilerServices { public interface ITuple<T> where T : ITuple<T> { abstract static explicit operator string(T x); int Length { get; } object this[int index] { get; } } public static class RuntimeFeature { public const string VirtualStaticsInInterfaces = nameof(VirtualStaticsInInterfaces); } } } """; var comp = CreateEmptyCompilation(new[] { source, Stubs }); comp.VerifyEmitDiagnostics(EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60961")] public void ExplicitInterfaceImplementation_GenericProperty() { var source = """ namespace System { public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> : System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>, System.Runtime.CompilerServices.ITuple<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>> where TRest : struct { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; int System.Runtime.CompilerServices.ITuple<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>>.Length => throw null; ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> System.Runtime.CompilerServices.ITuple<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>>.Self => throw null; object System.Runtime.CompilerServices.ITuple<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>>.this[int index] => throw null; ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> System.Runtime.CompilerServices.ITuple<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>>.this[ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> self, int index] => throw null; bool System.IEquatable<(T1, T2, T3, T4, T5, T6, T7, TRest)>.Equals((T1, T2, T3, T4, T5, T6, T7, TRest) other) => false; } public interface IEquatable<T> { bool Equals(T other); } namespace Runtime.CompilerServices { public interface ITuple<T> where T : ITuple<T> { int Length { get; } T Self { get; } object this[int index] { get; } T this[T self, int index] { get; } } } } """; var comp = CreateEmptyCompilation(new[] { source, Stubs }); comp.VerifyEmitDiagnostics(EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60961")] public void ExplicitInterfaceImplementation_TupleInSignatureOnly() { var source = """ namespace System { public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> : System.Runtime.CompilerServices.ITuple<T1, T2, T3, T4, T5, T6, T7, TRest> where TRest : struct { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; int System.Runtime.CompilerServices.ITuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Length => throw null; (T1, T2, T3, T4, T5, T6, T7, TRest) System.Runtime.CompilerServices.ITuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Self => throw null; object System.Runtime.CompilerServices.ITuple<T1, T2, T3, T4, T5, T6, T7, TRest>.this[int index] => throw null; (T1, T2, T3, T4, T5, T6, T7, TRest) System.Runtime.CompilerServices.ITuple<T1, T2, T3, T4, T5, T6, T7, TRest>.this[(T1, T2, T3, T4, T5, T6, T7, TRest) self, int index] => throw null; bool System.Runtime.CompilerServices.ITuple<T1, T2, T3, T4, T5, T6, T7, TRest>.Equals((T1, T2, T3, T4, T5, T6, T7, TRest) other) => false; } namespace Runtime.CompilerServices { public interface ITuple<T1, T2, T3, T4, T5, T6, T7, TRest> { int Length { get; } (T1, T2, T3, T4, T5, T6, T7, TRest) Self { get; } object this[int index] { get; } (T1, T2, T3, T4, T5, T6, T7, TRest) this[(T1, T2, T3, T4, T5, T6, T7, TRest) self, int index] { get; } bool Equals((T1, T2, T3, T4, T5, T6, T7, TRest) other); } } } """; var comp = CreateEmptyCompilation(new[] { source, Stubs }); comp.VerifyEmitDiagnostics(EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78627")] public void TargetTypedTupleErrorRecovery_Return() { var source = """ class C { public C(int i, string s) { } (object, C) M() { return (default, new(1,)); } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,32): error CS1525: Invalid expression term ')' // return (default, new(1,)); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(7, 32)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var tupleExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType<TupleExpressionSyntax>().Single(); var tupleTypeInfo = model.GetTypeInfo(tupleExpression); Assert.Null(tupleTypeInfo.Type); Assert.Equal("(System.Object, C)", tupleTypeInfo.ConvertedType.ToTestDisplayString()); var firstTupleArgExpr = tupleExpression.Arguments[0].Expression; var firstTupleArgInfo = model.GetTypeInfo(firstTupleArgExpr); Assert.Equal("System.Object", firstTupleArgInfo.Type.ToTestDisplayString()); Assert.Equal("System.Object", firstTupleArgInfo.ConvertedType.ToTestDisplayString()); var secondTupleArgExpr = tupleExpression.Arguments[1].Expression; var secondTupleArgInfo = model.GetTypeInfo(secondTupleArgExpr); Assert.Equal("C", secondTupleArgInfo.Type.ToTestDisplayString()); Assert.Equal("C", secondTupleArgInfo.ConvertedType.ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78627")] public void TargetTypedTupleErrorRecovery_VariableDeclaration() { var source = """ class C { public C(int i, string s) { } void M() { (C, long) t = (new(3,), 89); } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,30): error CS1525: Invalid expression term ')' // (C, long) t = (new(3,), 89); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(7, 30)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var tupleExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType<TupleExpressionSyntax>().Single(); var tupleTypeInfo = model.GetTypeInfo(tupleExpression); Assert.Null(tupleTypeInfo.Type); Assert.Equal("(C, System.Int64)", tupleTypeInfo.ConvertedType.ToTestDisplayString()); var firstTupleArgExpr = tupleExpression.Arguments[0].Expression; var firstTupleArgInfo = model.GetTypeInfo(firstTupleArgExpr); Assert.Equal("C", firstTupleArgInfo.Type.ToTestDisplayString()); Assert.Equal("C", firstTupleArgInfo.ConvertedType.ToTestDisplayString()); var secondTupleArgExpr = tupleExpression.Arguments[1].Expression; var secondTupleArgInfo = model.GetTypeInfo(secondTupleArgExpr); Assert.Equal("System.Int32", secondTupleArgInfo.Type.ToTestDisplayString()); Assert.Equal("System.Int64", secondTupleArgInfo.ConvertedType.ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78627")] public void TargetTypedTupleErrorRecovery_Assignment() { var source = """ class C { public C(int i, string s) { } void M() { (C, object) t; t = (new(3,), ""); } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (8,20): error CS1525: Invalid expression term ')' // t = (new(3,), ""); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(8, 20)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var tupleExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType<TupleExpressionSyntax>().Single(); var tupleTypeInfo = model.GetTypeInfo(tupleExpression); Assert.Null(tupleTypeInfo.Type); Assert.Equal("(C, System.Object)", tupleTypeInfo.ConvertedType.ToTestDisplayString()); var firstTupleArgExpr = tupleExpression.Arguments[0].Expression; var firstTupleArgInfo = model.GetTypeInfo(firstTupleArgExpr); Assert.Equal("C", firstTupleArgInfo.Type.ToTestDisplayString()); Assert.Equal("C", firstTupleArgInfo.ConvertedType.ToTestDisplayString()); var secondTupleArgExpr = tupleExpression.Arguments[1].Expression; var secondTupleArgInfo = model.GetTypeInfo(secondTupleArgExpr); Assert.Equal("System.String", secondTupleArgInfo.Type.ToTestDisplayString()); Assert.Equal("System.Object", secondTupleArgInfo.ConvertedType.ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78627")] public void TargetTypedTupleErrorRecovery_Call() { var source = """ class C { public C(int i, string s) { } void M() { N((8, new(9,))); } void N((int?, C) arg) { } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,21): error CS1525: Invalid expression term ')' // N((8, new(9,))); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(7, 21)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var tupleExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType<TupleExpressionSyntax>().Single(); var tupleTypeInfo = model.GetTypeInfo(tupleExpression); Assert.Null(tupleTypeInfo.Type); Assert.Equal("(System.Int32?, C)", tupleTypeInfo.ConvertedType.ToTestDisplayString()); var firstTupleArgExpr = tupleExpression.Arguments[0].Expression; var firstTupleArgInfo = model.GetTypeInfo(firstTupleArgExpr); Assert.Equal("System.Int32", firstTupleArgInfo.Type.ToTestDisplayString()); Assert.Equal("System.Int32?", firstTupleArgInfo.ConvertedType.ToTestDisplayString()); var secondTupleArgExpr = tupleExpression.Arguments[1].Expression; var secondTupleArgInfo = model.GetTypeInfo(secondTupleArgExpr); Assert.Equal("C", secondTupleArgInfo.Type.ToTestDisplayString()); Assert.Equal("C", secondTupleArgInfo.ConvertedType.ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78627")] public void TargetTypedTupleErrorRecovery_Cast() { var source = """ class C { public C(int i, string s) { } void M() { var t = ((object, C))(null, new(47,)); } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,44): error CS1525: Invalid expression term ')' // var t = ((object, C))(null, new(47,)); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(7, 44)); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var tupleExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType<TupleExpressionSyntax>().Single(); var tupleTypeInfo = model.GetTypeInfo(tupleExpression); Assert.Null(tupleTypeInfo.Type); Assert.Equal("(System.Object, C)", tupleTypeInfo.ConvertedType.ToTestDisplayString()); var firstTupleArgExpr = tupleExpression.Arguments[0].Expression; var firstTupleArgInfo = model.GetTypeInfo(firstTupleArgExpr); Assert.Null(firstTupleArgInfo.Type); Assert.Equal("System.Object", firstTupleArgInfo.ConvertedType.ToTestDisplayString()); var secondTupleArgExpr = tupleExpression.Arguments[1].Expression; var secondTupleArgInfo = model.GetTypeInfo(secondTupleArgExpr); Assert.Equal("C", secondTupleArgInfo.Type.ToTestDisplayString()); Assert.Equal("C", secondTupleArgInfo.ConvertedType.ToTestDisplayString()); } } }