sunnycase 6 ani în urmă
părinte
comite
72695b4cb8

+ 33 - 1
Natsu.sln

@@ -10,9 +10,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Natsu.Compiler", "src\Natsu
 		{20176878-F31F-4D92-918C-9FD58CDD7480} = {20176878-F31F-4D92-918C-9FD58CDD7480}
 		{7374FA7F-5B76-40C8-8F8F-EB9CA53A8C2F} = {7374FA7F-5B76-40C8-8F8F-EB9CA53A8C2F}
 		{C4408589-968A-43B3-83A6-AF02D1BAA293} = {C4408589-968A-43B3-83A6-AF02D1BAA293}
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B} = {357BCAA3-32A6-41E3-A616-57CE73470C1B}
 		{FE1EA2B2-2DF7-4570-9710-AF31D00DF2F6} = {FE1EA2B2-2DF7-4570-9710-AF31D00DF2F6}
 		{2C03C9E9-3EE6-4F74-8BF7-C9040E9E4A14} = {2C03C9E9-3EE6-4F74-8BF7-C9040E9E4A14}
 		{D261F7EB-5A98-4D47-B34B-D13B27A6988E} = {D261F7EB-5A98-4D47-B34B-D13B27A6988E}
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400} = {CF7D1BFB-188E-452A-B806-5BCAEBF42400}
 		{E7F325FF-7C85-4C64-8E96-E06AE3A5238D} = {E7F325FF-7C85-4C64-8E96-E06AE3A5238D}
 	EndProjectSection
 EndProject
@@ -40,7 +42,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{898F8F18-37B
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tesst", "tesst", "{1CA5CB48-2E78-4BEE-9A07-FDFA3AD6C45D}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChinoTest", "tests\ChinoTest\ChinoTest.csproj", "{12EFCA48-076F-41A2-99F0-BFEB5C249ED2}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChinoTest", "tests\ChinoTest\ChinoTest.csproj", "{12EFCA48-076F-41A2-99F0-BFEB5C249ED2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Extensions", "src\System.Runtime.Extensions\System.Runtime.Extensions.csproj", "{CF7D1BFB-188E-452A-B806-5BCAEBF42400}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Memory", "src\System.Memory\System.Memory.csproj", "{357BCAA3-32A6-41E3-A616-57CE73470C1B}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -196,6 +202,30 @@ Global
 		{12EFCA48-076F-41A2-99F0-BFEB5C249ED2}.Release|Emulator.Build.0 = Release|Any CPU
 		{12EFCA48-076F-41A2-99F0-BFEB5C249ED2}.Release|KD233.ActiveCfg = Release|Any CPU
 		{12EFCA48-076F-41A2-99F0-BFEB5C249ED2}.Release|KD233.Build.0 = Release|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Debug|Emulator.ActiveCfg = Debug|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Debug|Emulator.Build.0 = Debug|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Debug|KD233.ActiveCfg = Debug|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Debug|KD233.Build.0 = Debug|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Release|Emulator.ActiveCfg = Release|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Release|Emulator.Build.0 = Release|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Release|KD233.ActiveCfg = Release|Any CPU
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400}.Release|KD233.Build.0 = Release|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Debug|Emulator.ActiveCfg = Debug|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Debug|Emulator.Build.0 = Debug|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Debug|KD233.ActiveCfg = Debug|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Debug|KD233.Build.0 = Debug|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Release|Emulator.ActiveCfg = Release|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Release|Emulator.Build.0 = Release|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Release|KD233.ActiveCfg = Release|Any CPU
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B}.Release|KD233.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -213,6 +243,8 @@ Global
 		{E7F325FF-7C85-4C64-8E96-E06AE3A5238D} = {898F8F18-37B6-4D6C-927D-08F1FBC2672C}
 		{FE1EA2B2-2DF7-4570-9710-AF31D00DF2F6} = {898F8F18-37B6-4D6C-927D-08F1FBC2672C}
 		{12EFCA48-076F-41A2-99F0-BFEB5C249ED2} = {1CA5CB48-2E78-4BEE-9A07-FDFA3AD6C45D}
+		{CF7D1BFB-188E-452A-B806-5BCAEBF42400} = {898F8F18-37B6-4D6C-927D-08F1FBC2672C}
+		{357BCAA3-32A6-41E3-A616-57CE73470C1B} = {898F8F18-37B6-4D6C-927D-08F1FBC2672C}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {429BE0BD-F176-4959-97F3-6F657A877050}

+ 3 - 3
src/Native/chino.runtime.h

@@ -5,13 +5,13 @@
 namespace Chino_Core
 {
 template <class T>
-::natsu::gc_ref<::natsu::variable_type_t<T>> Chino::Volatile::_s_As(::System_Runtime::System::UInt32 address)
+::natsu::gc_ref<::natsu::variable_type_t<T>> Chino::IOVolatile::_s_As(::System_Runtime::System::UInt32 address)
 {
     return ::natsu::gc_ref<::natsu::variable_type_t<T>>((uintptr_t)address.m_value);
 }
 
 template <class T>
-::natsu::variable_type_t<T> Chino::Volatile::_s_Read(::natsu::gc_ref<::natsu::variable_type_t<T>> address)
+::natsu::variable_type_t<T> Chino::IOVolatile::_s_Read(::natsu::gc_ref<::natsu::variable_type_t<T>> address)
 {
     using elem_t = std::decay_t<decltype(address->Value.m_value)>;
     auto value = *reinterpret_cast<const volatile elem_t *>(&address->Value.m_value);
@@ -21,7 +21,7 @@ template <class T>
 }
 
 template <class T>
-void Chino::Volatile::_s_Write(::natsu::gc_ref<::natsu::variable_type_t<T>> address, ::natsu::variable_type_t<T> value)
+void Chino::IOVolatile::_s_Write(::natsu::gc_ref<::natsu::variable_type_t<T>> address, ::natsu::variable_type_t<T> value)
 {
     using elem_t = std::decay_t<decltype(address->Value.m_value)>;
     auto ptr = reinterpret_cast<volatile elem_t *>(&address->Value.m_value);

+ 97 - 27
src/Natsu.Compiler/Program.cs

@@ -16,14 +16,16 @@ namespace Natsu.Compiler
         {
             @"..\..\..\..\..\out\bin\netcoreapp3.0\Chino.Kernel.dll",
             @"..\..\..\..\..\out\bin\netcoreapp3.0\Chino.Core.dll",
-            //@"..\..\..\..\..\out\bin\netcoreapp3.0\Chino.Chip.K210.dll",
+            @"..\..\..\..\..\out\bin\netcoreapp3.0\Chino.Chip.K210.dll",
             @"..\..\..\..\..\out\bin\netcoreapp3.0\Chino.Chip.Emulator.dll",
             @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Private.CorLib.dll",
+            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Memory.dll",
             @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Runtime.dll",
-            //@"..\..\..\..\..\out\bin\netcoreapp3.0\System.Diagnostics.Debug.dll",
-            //@"..\..\..\..\..\out\bin\netcoreapp3.0\System.Runtime.InteropServices.dll",
+            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Runtime.Extensions.dll",
+            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Diagnostics.Debug.dll",
+            @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Runtime.InteropServices.dll",
             @"..\..\..\..\..\out\bin\netcoreapp3.0\System.Threading.dll",
-            //Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), @".nuget\packages\bitfields\0.1.0\lib\netstandard1.0\BitFields.dll")
+            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), @".nuget\packages\bitfields\0.1.0\lib\netstandard1.0\BitFields.dll")
         };
 
         static void Main(string[] args)
@@ -564,6 +566,8 @@ namespace Natsu.Compiler
             }
 
             writer.Ident(ident).WriteLine("{");
+            WriteVTableCtor(writer, type, ident + 1);
+            writer.WriteLine();
 
             foreach (var method in type.TypeDef.Methods)
             {
@@ -649,7 +653,7 @@ namespace Natsu.Compiler
                 writer.Ident(ident).Write("static " + TypeUtils.EscapeVariableTypeName(method.ReturnType) + " ");
             else
                 writer.Ident(ident);
-            writer.Write(TypeUtils.EscapeMethodName(method) + "(");
+            writer.Write(TypeUtils.EscapeMethodName(method, hasExplicit: true) + "(");
             WriteParameterList(writer, method.Parameters);
             writer.WriteLine($");");
         }
@@ -749,7 +753,7 @@ namespace Natsu.Compiler
             writer.Write(TypeUtils.EscapeTypeName(method.DeclaringType, hasModuleName: false));
             if (method.IsStaticConstructor)
                 writer.Write("::Static");
-            writer.Write("::" + TypeUtils.EscapeMethodName(method) + "(");
+            writer.Write("::" + TypeUtils.EscapeMethodName(method, hasExplicit: true) + "(");
             WriteParameterList(writer, method.Parameters);
             writer.WriteLine(")");
             writer.Ident(ident).WriteLine("{");
@@ -763,10 +767,68 @@ namespace Natsu.Compiler
             writer.Flush();
         }
 
-        private void WriteVTableMethodDeclare(TextWriter writer, int ident, MethodDef method)
+        private void WriteVTableCtor(StreamWriter writer, TypeDesc type, int ident)
         {
-            writer.Ident(ident);
+            bool firstInit = true;
+            writer.Ident(ident).WriteLine("constexpr VTable()");
+
+            foreach (var method in type.TypeDef.Methods)
+            {
+                if (!method.IsInstanceConstructor && !method.IsStatic)
+                {
+                    if (method.IsVirtual && method.IsNewSlot && !method.Name.Contains("."))
+                    {
+                        if (firstInit)
+                        {
+                            writer.Ident(ident + 1).Write(": ");
+                            firstInit = false;
+                        }
+                        else
+                        {
+                            writer.Ident(ident + 1).Write(", ");
+                        }
+
+                        writer.Write(TypeUtils.EscapeMethodName(method));
+                        writer.WriteLine("(_imp_" + TypeUtils.EscapeMethodName(method) + ")");
+                    }
+                }
+            }
+
+            writer.Ident(ident).WriteLine("{");
+
+
+            foreach (var method in type.TypeDef.Methods)
+            {
+                if (!method.IsInstanceConstructor && !method.IsStatic)
+                {
+                    if (method.IsVirtual)
+                    {
+                        if (method.Name.Contains("."))
+                        {
+                            var explict = method.Name.String;
+                            explict = explict.Substring(0, explict.LastIndexOf('.'));
+                            explict = explict.Replace(".", "::");
+                            writer.Ident(ident + 1).Write(explict);
+                            writer.Write("::VTable::");
+                            writer.Write(TypeUtils.EscapeMethodName(method));
+                            writer.Write(" = ");
+                            writer.WriteLine("_imp_" + TypeUtils.EscapeMethodName(method, hasExplicit: true) + ";");
+                        }
+                        else if (!method.IsNewSlot)
+                        {
+                            writer.Ident(ident + 1).Write(TypeUtils.EscapeMethodName(method));
+                            writer.Write(" = ");
+                            writer.WriteLine("_imp_" + TypeUtils.EscapeMethodName(method) + ";");
+                        }
+                    }
+                }
+            }
+
+            writer.Ident(ident).WriteLine("}");
+        }
 
+        private void WriteVTableMethodDeclare(TextWriter writer, int ident, MethodDef method)
+        {
             var methodGens = new List<string>();
 
             if (method.HasGenericParameters)
@@ -781,26 +843,28 @@ namespace Natsu.Compiler
                     throw new NotSupportedException("Virtual generic methods is not supported");
 
                 if (method.IsNewSlot)
-                    writer.Write("virtual ");
-            }
+                {
+                    // Explicit override
+                    if (!method.Name.Contains("."))
+                    {
+                        writer.Ident(ident).Write(TypeUtils.EscapeVariableTypeName(method.ReturnType) + " (*");
+                        writer.Write(TypeUtils.EscapeMethodName(method) + ")(");
+                        WriteParameterList(writer, method.Parameters, isVTable: true);
+                        writer.WriteLine(");");
+                    }
+                }
 
-            writer.Write(TypeUtils.EscapeVariableTypeName(method.ReturnType) + " ");
-            writer.Write(TypeUtils.EscapeMethodName(method) + "(");
-            WriteParameterList(writer, method.Parameters, isVTable: true);
-            writer.Write(") const");
-            if (method.IsAbstract)
-            {
-                writer.WriteLine(";");
+                writer.Ident(ident).Write("static " + TypeUtils.EscapeVariableTypeName(method.ReturnType) + " _imp_");
+                writer.Write(TypeUtils.EscapeMethodName(method, hasExplicit: true) + "(");
+                WriteParameterList(writer, method.Parameters, isVTable: true);
+                writer.WriteLine(");");
             }
             else
             {
-                if (method.IsVirtual)
-                {
-                    if (!method.IsNewSlot)
-                        writer.Write(" override");
-                }
-
-                writer.WriteLine(";");
+                writer.Ident(ident).Write(TypeUtils.EscapeVariableTypeName(method.ReturnType) + " ");
+                writer.Write(TypeUtils.EscapeMethodName(method) + "(");
+                WriteParameterList(writer, method.Parameters, isVTable: true);
+                writer.WriteLine(") const;");
             }
 
             writer.Flush();
@@ -824,9 +888,15 @@ namespace Natsu.Compiler
 
             writer.Write(TypeUtils.EscapeVariableTypeName(method.ReturnType) + " ");
             writer.Write(TypeUtils.EscapeTypeName(method.DeclaringType, hasModuleName: false));
-            writer.Write("::VTable::" + TypeUtils.EscapeMethodName(method) + "(");
+            writer.Write("::VTable::");
+            if (method.IsVirtual)
+                writer.Write("_imp_");
+            writer.Write(TypeUtils.EscapeMethodName(method, hasExplicit: true) + "(");
             WriteParameterList(writer, method.Parameters, isVTable: true);
-            writer.WriteLine(") const");
+            if (method.IsVirtual)
+                writer.WriteLine(")");
+            else
+                writer.WriteLine(") const");
             writer.Ident(ident).WriteLine("{");
             if (method.IsAbstract)
             {
@@ -836,7 +906,7 @@ namespace Natsu.Compiler
             {
                 writer.Ident(ident + 1).Write("return ");
                 writer.Write(TypeUtils.EscapeTypeName(method.DeclaringType));
-                writer.Write("::" + TypeUtils.EscapeMethodName(method) + "(");
+                writer.Write("::" + TypeUtils.EscapeMethodName(method, hasExplicit: true) + "(");
                 WriteParameterList(writer, method.Parameters, hasType: false, isVTable: true);
                 writer.WriteLine(");");
             }

+ 5 - 2
src/Natsu.Compiler/TypeUtils.cs

@@ -314,14 +314,17 @@ namespace Natsu.Compiler
             return name.Replace('.', '_');
         }
 
-        public static string EscapeMethodName(IMethod method)
+        public static string EscapeMethodName(IMethod method, bool hasExplicit = false)
         {
             if (method.Name == ".ctor")
                 return "_ctor";
             if (method.MethodSig.HasThis)
             {
                 var sb = new StringBuilder();
-                sb.Append(EscapeIdentifier(method.Name.String.Split('.').Last()));
+                if (hasExplicit)
+                    sb.Append(EscapeIdentifier(method.Name.String));
+                else
+                    sb.Append(EscapeIdentifier(method.Name.String.Split('.').Last()));
                 sb.Append("_");
 
                 for (int i = 0; i < method.MethodSig.Params.Count; i++)

+ 16 - 0
src/System.Memory/System.Memory.csproj

@@ -0,0 +1,16 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
+    <OutputPath>$(SolutionDir)out/bin/</OutputPath>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>$(SolutionDir)tools/Open.snk</AssemblyOriginatorKeyFile>
+    <AssemblyVersion>4.2.1.0</AssemblyVersion>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\System.Private.CorLib\System.Private.CorLib.csproj" />
+  </ItemGroup>
+
+</Project>

+ 5 - 0
src/System.Memory/TypeForwards.cs

@@ -0,0 +1,5 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: TypeForwardedTo(typeof(MemoryExtensions))]

+ 3 - 0
src/System.Private.CorLib/System/Collections/Generic/ComparerHelpers.cs

@@ -29,5 +29,8 @@ namespace System.Collections.Generic
         /// </remarks>
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal extern static Comparer<T> CreateDefaultComparer<T>();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static EqualityComparer<T> CreateDefaultEqualityComparer<T>();
     }
 }

+ 218 - 0
src/System.Private.CorLib/System/Collections/Generic/EqualityComparer.NatsuCLR.cs

@@ -0,0 +1,218 @@
+// 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.
+
+using System.Runtime.CompilerServices;
+using System.Diagnostics;
+
+namespace System.Collections.Generic
+{
+    [TypeDependencyAttribute("System.Collections.Generic.ObjectEqualityComparer`1")]
+    public abstract partial class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T>
+    {
+        // To minimize generic instantiation overhead of creating the comparer per type, we keep the generic portion of the code as small
+        // as possible and define most of the creation logic in a non-generic class.
+        public static EqualityComparer<T> Default { [Intrinsic] get; } = ComparerHelpers.CreateDefaultEqualityComparer<T>();
+
+        internal virtual int IndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            for (int i = startIndex; i < endIndex; i++)
+            {
+                if (Equals(array[i], value)) return i;
+            }
+            return -1;
+        }
+
+        internal virtual int LastIndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex - count + 1;
+            for (int i = startIndex; i >= endIndex; i--)
+            {
+                if (Equals(array[i], value)) return i;
+            }
+            return -1;
+        }
+    }
+
+    public sealed partial class GenericEqualityComparer<T> : EqualityComparer<T>
+#nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
+        where T : IEquatable<T>
+#nullable restore
+    {
+        internal override int IndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            if (value == null)
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (array[i] == null) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (array[i] != null && array[i].Equals(value)) return i;
+                }
+            }
+            return -1;
+        }
+
+        internal override int LastIndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex - count + 1;
+            if (value == null)
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (array[i] == null) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (array[i] != null && array[i].Equals(value)) return i;
+                }
+            }
+            return -1;
+        }
+    }
+
+    public sealed partial class NullableEqualityComparer<T> : EqualityComparer<T?> where T : struct,
+#nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
+        IEquatable<T>
+#nullable restore
+    {
+        internal override int IndexOf(T?[] array, T? value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            if (!value.HasValue)
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (!array[i].HasValue) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (array[i].HasValue && array[i].value.Equals(value.value)) return i;
+                }
+            }
+            return -1;
+        }
+
+        internal override int LastIndexOf(T?[] array, T? value, int startIndex, int count)
+        {
+            int endIndex = startIndex - count + 1;
+            if (!value.HasValue)
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (!array[i].HasValue) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (array[i].HasValue && array[i].value.Equals(value.value)) return i;
+                }
+            }
+            return -1;
+        }
+    }
+
+    public sealed partial class ObjectEqualityComparer<T> : EqualityComparer<T>
+    {
+        internal override int IndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            if (value == null)
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (array[i] == null) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (array[i] != null && array[i]!.Equals(value)) return i; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644)
+                }
+            }
+            return -1;
+        }
+
+        internal override int LastIndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex - count + 1;
+            if (value == null)
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (array[i] == null) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (array[i] != null && array[i]!.Equals(value)) return i; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644)
+                }
+            }
+            return -1;
+        }
+    }
+
+    public sealed partial class ByteEqualityComparer : EqualityComparer<byte>
+    {
+#if DEBUG
+        internal override int IndexOf(byte[] array, byte value, int startIndex, int count)
+        {
+            Debug.Fail("Should not get here.");
+            return -1;
+        }
+
+        internal override int LastIndexOf(byte[] array, byte value, int startIndex, int count)
+        {
+            Debug.Fail("Should not get here.");
+            return -1;
+        }
+#endif
+    }
+
+    public sealed partial class EnumEqualityComparer<T> : EqualityComparer<T> where T : struct, Enum
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override bool Equals(T x, T y)
+        {
+            return System.Runtime.CompilerServices.RuntimeHelpers.EnumEquals(x, y);
+        }
+
+        internal override int IndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            for (int i = startIndex; i < endIndex; i++)
+            {
+                if (System.Runtime.CompilerServices.RuntimeHelpers.EnumEquals(array[i], value)) return i;
+            }
+            return -1;
+        }
+
+        internal override int LastIndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex - count + 1;
+            for (int i = startIndex; i >= endIndex; i--)
+            {
+                if (System.Runtime.CompilerServices.RuntimeHelpers.EnumEquals(array[i], value)) return i;
+            }
+            return -1;
+        }
+    }
+}

+ 3 - 0
src/System.Private.CorLib/System/Runtime/CompilerServices/RuntimeHelpers.cs

@@ -27,6 +27,9 @@ namespace System.Runtime.CompilerServices
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal extern static int EnumCompareTo<T>(T x, T y) where T : struct;
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern static bool EnumEquals<T>(T x, T y) where T : struct;
+
         // Returns true iff the object has a component size;
         // i.e., is variable length like System.String or Array.
         [MethodImpl(MethodImplOptions.AggressiveInlining)]

+ 2246 - 0
src/System.Private.CorLib/System/ValueTuple.cs

@@ -0,0 +1,2246 @@
+// 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.
+
+#pragma warning disable SA1141 // explicitly not using tuple syntax in tuple implementation
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+    /// <summary>
+    /// Helper so we can call some tuple methods recursively without knowing the underlying types.
+    /// </summary>
+    internal interface IValueTupleInternal : ITuple
+    {
+        int GetHashCode(IEqualityComparer comparer);
+        string ToStringEnd();
+    }
+
+    /// <summary>
+    /// The ValueTuple types (from arity 0 to 8) comprise the runtime implementation that underlies tuples in C# and struct tuples in F#.
+    /// Aside from created via language syntax, they are most easily created via the ValueTuple.Create factory methods.
+    /// The System.ValueTuple types differ from the System.Tuple types in that:
+    /// - they are structs rather than classes,
+    /// - they are mutable rather than readonly, and
+    /// - their members (such as Item1, Item2, etc) are fields rather than properties.
+    /// </summary>
+    [Serializable]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public struct ValueTuple
+        : IEquatable<ValueTuple>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple>, IValueTupleInternal, ITuple
+    {
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple"/> instance is equal to a specified object.
+        /// </summary>
+        /// <param name="obj">The object to compare with this instance.</param>
+        /// <returns><see langword="true"/> if <paramref name="obj"/> is a <see cref="ValueTuple"/>.</returns>
+        public override bool Equals(object? obj)
+        {
+            return obj is ValueTuple;
+        }
+
+        /// <summary>Returns a value indicating whether this instance is equal to a specified value.</summary>
+        /// <param name="other">An instance to compare to this instance.</param>
+        /// <returns>true if <paramref name="other"/> has the same value as this instance; otherwise, false.</returns>
+        public bool Equals(ValueTuple other)
+        {
+            return true;
+        }
+
+        bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+        {
+            return other is ValueTuple;
+        }
+
+        int IComparable.CompareTo(object? other)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            return 0;
+        }
+
+        /// <summary>Compares this instance to a specified instance and returns an indication of their relative values.</summary>
+        /// <param name="other">An instance to compare.</param>
+        /// <returns>
+        /// A signed number indicating the relative values of this instance and <paramref name="other"/>.
+        /// Returns less than zero if this instance is less than <paramref name="other"/>, zero if this
+        /// instance is equal to <paramref name="other"/>, and greater than zero if this instance is greater
+        /// than <paramref name="other"/>.
+        /// </returns>
+        public int CompareTo(ValueTuple other)
+        {
+            return 0;
+        }
+
+        int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            return 0;
+        }
+
+        /// <summary>Returns the hash code for this instance.</summary>
+        /// <returns>A 32-bit signed integer hash code.</returns>
+        public override int GetHashCode()
+        {
+            return 0;
+        }
+
+        int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+        {
+            return 0;
+        }
+
+        int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
+        {
+            return 0;
+        }
+
+        /// <summary>
+        /// Returns a string that represents the value of this <see cref="ValueTuple"/> instance.
+        /// </summary>
+        /// <returns>The string representation of this <see cref="ValueTuple"/> instance.</returns>
+        /// <remarks>
+        /// The string returned by this method takes the form <c>()</c>.
+        /// </remarks>
+        public override string ToString()
+        {
+            return "()";
+        }
+
+        string IValueTupleInternal.ToStringEnd()
+        {
+            return ")";
+        }
+
+        /// <summary>
+        /// The number of positions in this data structure.
+        /// </summary>
+        int ITuple.Length => 0;
+
+        /// <summary>
+        /// Get the element at position <param name="index"/>.
+        /// </summary>
+        object? ITuple.this[int index] => throw new IndexOutOfRangeException();
+
+        /// <summary>Creates a new struct 0-tuple.</summary>
+        /// <returns>A 0-tuple.</returns>
+        public static ValueTuple Create() =>
+            new ValueTuple();
+
+        /// <summary>Creates a new struct 1-tuple, or singleton.</summary>
+        /// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
+        /// <param name="item1">The value of the first component of the tuple.</param>
+        /// <returns>A 1-tuple (singleton) whose value is (item1).</returns>
+        public static ValueTuple<T1> Create<T1>(T1 item1) =>
+            new ValueTuple<T1>(item1);
+
+        /// <summary>Creates a new struct 2-tuple, or pair.</summary>
+        /// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
+        /// <typeparam name="T2">The type of the second component of the tuple.</typeparam>
+        /// <param name="item1">The value of the first component of the tuple.</param>
+        /// <param name="item2">The value of the second component of the tuple.</param>
+        /// <returns>A 2-tuple (pair) whose value is (item1, item2).</returns>
+        public static ValueTuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) =>
+            new ValueTuple<T1, T2>(item1, item2);
+
+        /// <summary>Creates a new struct 3-tuple, or triple.</summary>
+        /// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
+        /// <typeparam name="T2">The type of the second component of the tuple.</typeparam>
+        /// <typeparam name="T3">The type of the third component of the tuple.</typeparam>
+        /// <param name="item1">The value of the first component of the tuple.</param>
+        /// <param name="item2">The value of the second component of the tuple.</param>
+        /// <param name="item3">The value of the third component of the tuple.</param>
+        /// <returns>A 3-tuple (triple) whose value is (item1, item2, item3).</returns>
+        public static ValueTuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3) =>
+            new ValueTuple<T1, T2, T3>(item1, item2, item3);
+
+        /// <summary>Creates a new struct 4-tuple, or quadruple.</summary>
+        /// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
+        /// <typeparam name="T2">The type of the second component of the tuple.</typeparam>
+        /// <typeparam name="T3">The type of the third component of the tuple.</typeparam>
+        /// <typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
+        /// <param name="item1">The value of the first component of the tuple.</param>
+        /// <param name="item2">The value of the second component of the tuple.</param>
+        /// <param name="item3">The value of the third component of the tuple.</param>
+        /// <param name="item4">The value of the fourth component of the tuple.</param>
+        /// <returns>A 4-tuple (quadruple) whose value is (item1, item2, item3, item4).</returns>
+        public static ValueTuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 item1, T2 item2, T3 item3, T4 item4) =>
+            new ValueTuple<T1, T2, T3, T4>(item1, item2, item3, item4);
+
+        /// <summary>Creates a new struct 5-tuple, or quintuple.</summary>
+        /// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
+        /// <typeparam name="T2">The type of the second component of the tuple.</typeparam>
+        /// <typeparam name="T3">The type of the third component of the tuple.</typeparam>
+        /// <typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
+        /// <typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
+        /// <param name="item1">The value of the first component of the tuple.</param>
+        /// <param name="item2">The value of the second component of the tuple.</param>
+        /// <param name="item3">The value of the third component of the tuple.</param>
+        /// <param name="item4">The value of the fourth component of the tuple.</param>
+        /// <param name="item5">The value of the fifth component of the tuple.</param>
+        /// <returns>A 5-tuple (quintuple) whose value is (item1, item2, item3, item4, item5).</returns>
+        public static ValueTuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) =>
+            new ValueTuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5);
+
+        /// <summary>Creates a new struct 6-tuple, or sextuple.</summary>
+        /// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
+        /// <typeparam name="T2">The type of the second component of the tuple.</typeparam>
+        /// <typeparam name="T3">The type of the third component of the tuple.</typeparam>
+        /// <typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
+        /// <typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
+        /// <typeparam name="T6">The type of the sixth component of the tuple.</typeparam>
+        /// <param name="item1">The value of the first component of the tuple.</param>
+        /// <param name="item2">The value of the second component of the tuple.</param>
+        /// <param name="item3">The value of the third component of the tuple.</param>
+        /// <param name="item4">The value of the fourth component of the tuple.</param>
+        /// <param name="item5">The value of the fifth component of the tuple.</param>
+        /// <param name="item6">The value of the sixth component of the tuple.</param>
+        /// <returns>A 6-tuple (sextuple) whose value is (item1, item2, item3, item4, item5, item6).</returns>
+        public static ValueTuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) =>
+            new ValueTuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6);
+
+        /// <summary>Creates a new struct 7-tuple, or septuple.</summary>
+        /// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
+        /// <typeparam name="T2">The type of the second component of the tuple.</typeparam>
+        /// <typeparam name="T3">The type of the third component of the tuple.</typeparam>
+        /// <typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
+        /// <typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
+        /// <typeparam name="T6">The type of the sixth component of the tuple.</typeparam>
+        /// <typeparam name="T7">The type of the seventh component of the tuple.</typeparam>
+        /// <param name="item1">The value of the first component of the tuple.</param>
+        /// <param name="item2">The value of the second component of the tuple.</param>
+        /// <param name="item3">The value of the third component of the tuple.</param>
+        /// <param name="item4">The value of the fourth component of the tuple.</param>
+        /// <param name="item5">The value of the fifth component of the tuple.</param>
+        /// <param name="item6">The value of the sixth component of the tuple.</param>
+        /// <param name="item7">The value of the seventh component of the tuple.</param>
+        /// <returns>A 7-tuple (septuple) whose value is (item1, item2, item3, item4, item5, item6, item7).</returns>
+        public static ValueTuple<T1, T2, T3, T4, T5, T6, T7> Create<T1, T2, T3, T4, T5, T6, T7>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) =>
+            new ValueTuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7);
+
+        /// <summary>Creates a new struct 8-tuple, or octuple.</summary>
+        /// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
+        /// <typeparam name="T2">The type of the second component of the tuple.</typeparam>
+        /// <typeparam name="T3">The type of the third component of the tuple.</typeparam>
+        /// <typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
+        /// <typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
+        /// <typeparam name="T6">The type of the sixth component of the tuple.</typeparam>
+        /// <typeparam name="T7">The type of the seventh component of the tuple.</typeparam>
+        /// <typeparam name="T8">The type of the eighth component of the tuple.</typeparam>
+        /// <param name="item1">The value of the first component of the tuple.</param>
+        /// <param name="item2">The value of the second component of the tuple.</param>
+        /// <param name="item3">The value of the third component of the tuple.</param>
+        /// <param name="item4">The value of the fourth component of the tuple.</param>
+        /// <param name="item5">The value of the fifth component of the tuple.</param>
+        /// <param name="item6">The value of the sixth component of the tuple.</param>
+        /// <param name="item7">The value of the seventh component of the tuple.</param>
+        /// <param name="item8">The value of the eighth component of the tuple.</param>
+        /// <returns>An 8-tuple (octuple) whose value is (item1, item2, item3, item4, item5, item6, item7, item8).</returns>
+        public static ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8>> Create<T1, T2, T3, T4, T5, T6, T7, T8>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8) =>
+            new ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8>>(item1, item2, item3, item4, item5, item6, item7, ValueTuple.Create(item8));
+    }
+
+    /// <summary>Represents a 1-tuple, or singleton, as a value type.</summary>
+    /// <typeparam name="T1">The type of the tuple's only component.</typeparam>
+    [Serializable]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public struct ValueTuple<T1>
+        : IEquatable<ValueTuple<T1>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1>>, IValueTupleInternal, ITuple
+    {
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1}"/> instance's first component.
+        /// </summary>
+        public T1 Item1;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ValueTuple{T1}"/> value type.
+        /// </summary>
+        /// <param name="item1">The value of the tuple's first component.</param>
+        public ValueTuple(T1 item1)
+        {
+            Item1 = item1;
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1}"/> instance is equal to a specified object.
+        /// </summary>
+        /// <param name="obj">The object to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified object; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="obj"/> parameter is considered to be equal to the current instance under the following conditions:
+        /// <list type="bullet">
+        ///     <item><description>It is a <see cref="ValueTuple{T1}"/> value type.</description></item>
+        ///     <item><description>Its components are of the same types as those of the current instance.</description></item>
+        ///     <item><description>Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.</description></item>
+        /// </list>
+        /// </remarks>
+        public override bool Equals(object? obj)
+        {
+            return obj is ValueTuple<T1> && Equals((ValueTuple<T1>)obj);
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1}"/>
+        /// instance is equal to a specified <see cref="ValueTuple{T1}"/>.
+        /// </summary>
+        /// <param name="other">The tuple to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified tuple; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="other"/> parameter is considered to be equal to the current instance if each of its field
+        /// is equal to that of the current instance, using the default comparer for that field's type.
+        /// </remarks>
+        public bool Equals(ValueTuple<T1> other)
+        {
+            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1);
+        }
+
+        bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+        {
+            if (other == null || !(other is ValueTuple<T1>)) return false;
+
+            var objTuple = (ValueTuple<T1>)other;
+
+            return comparer.Equals(Item1, objTuple.Item1);
+        }
+
+        int IComparable.CompareTo(object? other)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            var objTuple = (ValueTuple<T1>)other;
+
+            return Comparer<T1>.Default.Compare(Item1, objTuple.Item1);
+        }
+
+        /// <summary>Compares this instance to a specified instance and returns an indication of their relative values.</summary>
+        /// <param name="other">An instance to compare.</param>
+        /// <returns>
+        /// A signed number indicating the relative values of this instance and <paramref name="other"/>.
+        /// Returns less than zero if this instance is less than <paramref name="other"/>, zero if this
+        /// instance is equal to <paramref name="other"/>, and greater than zero if this instance is greater
+        /// than <paramref name="other"/>.
+        /// </returns>
+        public int CompareTo(ValueTuple<T1> other)
+        {
+            return Comparer<T1>.Default.Compare(Item1, other.Item1);
+        }
+
+        int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            var objTuple = (ValueTuple<T1>)other;
+
+            return comparer.Compare(Item1, objTuple.Item1);
+        }
+
+        /// <summary>
+        /// Returns the hash code for the current <see cref="ValueTuple{T1}"/> instance.
+        /// </summary>
+        /// <returns>A 32-bit signed integer hash code.</returns>
+        public override int GetHashCode()
+        {
+            return Item1?.GetHashCode() ?? 0;
+        }
+
+        int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+        {
+            return comparer.GetHashCode(Item1!);
+        }
+
+        int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
+        {
+            return comparer.GetHashCode(Item1!);
+        }
+
+        /// <summary>
+        /// Returns a string that represents the value of this <see cref="ValueTuple{T1}"/> instance.
+        /// </summary>
+        /// <returns>The string representation of this <see cref="ValueTuple{T1}"/> instance.</returns>
+        /// <remarks>
+        /// The string returned by this method takes the form <c>(Item1)</c>,
+        /// where <c>Item1</c> represents the value of <see cref="Item1"/>. If the field is <see langword="null"/>,
+        /// it is represented as <see cref="string.Empty"/>.
+        /// </remarks>
+        public override string ToString()
+        {
+            return "(" + Item1?.ToString() + ")";
+        }
+
+        string IValueTupleInternal.ToStringEnd()
+        {
+            return Item1?.ToString() + ")";
+        }
+
+        /// <summary>
+        /// The number of positions in this data structure.
+        /// </summary>
+        int ITuple.Length => 1;
+
+        /// <summary>
+        /// Get the element at position <param name="index"/>.
+        /// </summary>
+        object? ITuple.this[int index]
+        {
+            get
+            {
+                if (index != 0)
+                {
+                    throw new IndexOutOfRangeException();
+                }
+                return Item1;
+            }
+        }
+    }
+
+    /// <summary>
+    /// Represents a 2-tuple, or pair, as a value type.
+    /// </summary>
+    /// <typeparam name="T1">The type of the tuple's first component.</typeparam>
+    /// <typeparam name="T2">The type of the tuple's second component.</typeparam>
+    [Serializable]
+    [StructLayout(LayoutKind.Auto)]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public struct ValueTuple<T1, T2>
+        : IEquatable<ValueTuple<T1, T2>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2>>, IValueTupleInternal, ITuple
+    {
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2}"/> instance's first component.
+        /// </summary>
+        public T1 Item1;
+
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2}"/> instance's second component.
+        /// </summary>
+        public T2 Item2;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ValueTuple{T1, T2}"/> value type.
+        /// </summary>
+        /// <param name="item1">The value of the tuple's first component.</param>
+        /// <param name="item2">The value of the tuple's second component.</param>
+        public ValueTuple(T1 item1, T2 item2)
+        {
+            Item1 = item1;
+            Item2 = item2;
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2}"/> instance is equal to a specified object.
+        /// </summary>
+        /// <param name="obj">The object to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified object; otherwise, <see langword="false"/>.</returns>
+        ///
+        /// <remarks>
+        /// The <paramref name="obj"/> parameter is considered to be equal to the current instance under the following conditions:
+        /// <list type="bullet">
+        ///     <item><description>It is a <see cref="ValueTuple{T1, T2}"/> value type.</description></item>
+        ///     <item><description>Its components are of the same types as those of the current instance.</description></item>
+        ///     <item><description>Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.</description></item>
+        /// </list>
+        /// </remarks>
+        public override bool Equals(object? obj)
+        {
+            return obj is ValueTuple<T1, T2> && Equals((ValueTuple<T1, T2>)obj);
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2}"/> instance is equal to a specified <see cref="ValueTuple{T1, T2}"/>.
+        /// </summary>
+        /// <param name="other">The tuple to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified tuple; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="other"/> parameter is considered to be equal to the current instance if each of its fields
+        /// are equal to that of the current instance, using the default comparer for that field's type.
+        /// </remarks>
+        public bool Equals(ValueTuple<T1, T2> other)
+        {
+            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
+                && EqualityComparer<T2>.Default.Equals(Item2, other.Item2);
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2}"/> instance is equal to a specified object based on a specified comparison method.
+        /// </summary>
+        /// <param name="other">The object to compare with this instance.</param>
+        /// <param name="comparer">An object that defines the method to use to evaluate whether the two objects are equal.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified object; otherwise, <see langword="false"/>.</returns>
+        ///
+        /// <remarks>
+        /// This member is an explicit interface member implementation. It can be used only when the
+        ///  <see cref="ValueTuple{T1, T2}"/> instance is cast to an <see cref="IStructuralEquatable"/> interface.
+        ///
+        /// The <see cref="IEqualityComparer.Equals"/> implementation is called only if <c>other</c> is not <see langword="null"/>,
+        ///  and if it can be successfully cast (in C#) or converted (in Visual Basic) to a <see cref="ValueTuple{T1, T2}"/>
+        ///  whose components are of the same types as those of the current instance. The IStructuralEquatable.Equals(Object, IEqualityComparer) method
+        ///  first passes the <see cref="Item1"/> values of the <see cref="ValueTuple{T1, T2}"/> objects to be compared to the
+        ///  <see cref="IEqualityComparer.Equals"/> implementation. If this method call returns <see langword="true"/>, the method is
+        ///  called again and passed the <see cref="Item2"/> values of the two <see cref="ValueTuple{T1, T2}"/> instances.
+        /// </remarks>
+        bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+        {
+            if (other == null || !(other is ValueTuple<T1, T2>)) return false;
+
+            var objTuple = (ValueTuple<T1, T2>)other;
+
+            return comparer.Equals(Item1, objTuple.Item1)
+                && comparer.Equals(Item2, objTuple.Item2);
+        }
+
+        int IComparable.CompareTo(object? other)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            return CompareTo((ValueTuple<T1, T2>)other);
+        }
+
+        /// <summary>Compares this instance to a specified instance and returns an indication of their relative values.</summary>
+        /// <param name="other">An instance to compare.</param>
+        /// <returns>
+        /// A signed number indicating the relative values of this instance and <paramref name="other"/>.
+        /// Returns less than zero if this instance is less than <paramref name="other"/>, zero if this
+        /// instance is equal to <paramref name="other"/>, and greater than zero if this instance is greater
+        /// than <paramref name="other"/>.
+        /// </returns>
+        public int CompareTo(ValueTuple<T1, T2> other)
+        {
+            int c = Comparer<T1>.Default.Compare(Item1, other.Item1);
+            if (c != 0) return c;
+
+            return Comparer<T2>.Default.Compare(Item2, other.Item2);
+        }
+
+        int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            var objTuple = (ValueTuple<T1, T2>)other;
+
+            int c = comparer.Compare(Item1, objTuple.Item1);
+            if (c != 0) return c;
+
+            return comparer.Compare(Item2, objTuple.Item2);
+        }
+
+        /// <summary>
+        /// Returns the hash code for the current <see cref="ValueTuple{T1, T2}"/> instance.
+        /// </summary>
+        /// <returns>A 32-bit signed integer hash code.</returns>
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(Item1?.GetHashCode() ?? 0,
+                                    Item2?.GetHashCode() ?? 0);
+        }
+
+        int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        private int GetHashCodeCore(IEqualityComparer comparer)
+        {
+            return HashCode.Combine(comparer.GetHashCode(Item1!),
+                                    comparer.GetHashCode(Item2!));
+        }
+
+        int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        /// <summary>
+        /// Returns a string that represents the value of this <see cref="ValueTuple{T1, T2}"/> instance.
+        /// </summary>
+        /// <returns>The string representation of this <see cref="ValueTuple{T1, T2}"/> instance.</returns>
+        /// <remarks>
+        /// The string returned by this method takes the form <c>(Item1, Item2)</c>,
+        /// where <c>Item1</c> and <c>Item2</c> represent the values of the <see cref="Item1"/>
+        /// and <see cref="Item2"/> fields. If either field value is <see langword="null"/>,
+        /// it is represented as <see cref="string.Empty"/>.
+        /// </remarks>
+        public override string ToString()
+        {
+            return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ")";
+        }
+
+        string IValueTupleInternal.ToStringEnd()
+        {
+            return Item1?.ToString() + ", " + Item2?.ToString() + ")";
+        }
+
+        /// <summary>
+        /// The number of positions in this data structure.
+        /// </summary>
+        int ITuple.Length => 2;
+
+        /// <summary>
+        /// Get the element at position <param name="index"/>.
+        /// </summary>
+        object? ITuple.this[int index] =>
+            index switch
+            {
+                0 => Item1,
+                1 => Item2,
+                _ => throw new IndexOutOfRangeException(),
+            };
+    }
+
+    /// <summary>
+    /// Represents a 3-tuple, or triple, as a value type.
+    /// </summary>
+    /// <typeparam name="T1">The type of the tuple's first component.</typeparam>
+    /// <typeparam name="T2">The type of the tuple's second component.</typeparam>
+    /// <typeparam name="T3">The type of the tuple's third component.</typeparam>
+    [Serializable]
+    [StructLayout(LayoutKind.Auto)]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public struct ValueTuple<T1, T2, T3>
+        : IEquatable<ValueTuple<T1, T2, T3>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3>>, IValueTupleInternal, ITuple
+    {
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3}"/> instance's first component.
+        /// </summary>
+        public T1 Item1;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3}"/> instance's second component.
+        /// </summary>
+        public T2 Item2;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3}"/> instance's third component.
+        /// </summary>
+        public T3 Item3;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ValueTuple{T1, T2, T3}"/> value type.
+        /// </summary>
+        /// <param name="item1">The value of the tuple's first component.</param>
+        /// <param name="item2">The value of the tuple's second component.</param>
+        /// <param name="item3">The value of the tuple's third component.</param>
+        public ValueTuple(T1 item1, T2 item2, T3 item3)
+        {
+            Item1 = item1;
+            Item2 = item2;
+            Item3 = item3;
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3}"/> instance is equal to a specified object.
+        /// </summary>
+        /// <param name="obj">The object to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified object; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="obj"/> parameter is considered to be equal to the current instance under the following conditions:
+        /// <list type="bullet">
+        ///     <item><description>It is a <see cref="ValueTuple{T1, T2, T3}"/> value type.</description></item>
+        ///     <item><description>Its components are of the same types as those of the current instance.</description></item>
+        ///     <item><description>Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.</description></item>
+        /// </list>
+        /// </remarks>
+        public override bool Equals(object? obj)
+        {
+            return obj is ValueTuple<T1, T2, T3> && Equals((ValueTuple<T1, T2, T3>)obj);
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3}"/>
+        /// instance is equal to a specified <see cref="ValueTuple{T1, T2, T3}"/>.
+        /// </summary>
+        /// <param name="other">The tuple to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified tuple; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="other"/> parameter is considered to be equal to the current instance if each of its fields
+        /// are equal to that of the current instance, using the default comparer for that field's type.
+        /// </remarks>
+        public bool Equals(ValueTuple<T1, T2, T3> other)
+        {
+            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
+                && EqualityComparer<T2>.Default.Equals(Item2, other.Item2)
+                && EqualityComparer<T3>.Default.Equals(Item3, other.Item3);
+        }
+
+        bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+        {
+            if (other == null || !(other is ValueTuple<T1, T2, T3>)) return false;
+
+            var objTuple = (ValueTuple<T1, T2, T3>)other;
+
+            return comparer.Equals(Item1, objTuple.Item1)
+                && comparer.Equals(Item2, objTuple.Item2)
+                && comparer.Equals(Item3, objTuple.Item3);
+        }
+
+        int IComparable.CompareTo(object? other)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            return CompareTo((ValueTuple<T1, T2, T3>)other);
+        }
+
+        /// <summary>Compares this instance to a specified instance and returns an indication of their relative values.</summary>
+        /// <param name="other">An instance to compare.</param>
+        /// <returns>
+        /// A signed number indicating the relative values of this instance and <paramref name="other"/>.
+        /// Returns less than zero if this instance is less than <paramref name="other"/>, zero if this
+        /// instance is equal to <paramref name="other"/>, and greater than zero if this instance is greater
+        /// than <paramref name="other"/>.
+        /// </returns>
+        public int CompareTo(ValueTuple<T1, T2, T3> other)
+        {
+            int c = Comparer<T1>.Default.Compare(Item1, other.Item1);
+            if (c != 0) return c;
+
+            c = Comparer<T2>.Default.Compare(Item2, other.Item2);
+            if (c != 0) return c;
+
+            return Comparer<T3>.Default.Compare(Item3, other.Item3);
+        }
+
+        int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            var objTuple = (ValueTuple<T1, T2, T3>)other;
+
+            int c = comparer.Compare(Item1, objTuple.Item1);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item2, objTuple.Item2);
+            if (c != 0) return c;
+
+            return comparer.Compare(Item3, objTuple.Item3);
+        }
+
+        /// <summary>
+        /// Returns the hash code for the current <see cref="ValueTuple{T1, T2, T3}"/> instance.
+        /// </summary>
+        /// <returns>A 32-bit signed integer hash code.</returns>
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(Item1?.GetHashCode() ?? 0,
+                                    Item2?.GetHashCode() ?? 0,
+                                    Item3?.GetHashCode() ?? 0);
+        }
+
+        int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        private int GetHashCodeCore(IEqualityComparer comparer)
+        {
+            return HashCode.Combine(comparer.GetHashCode(Item1!),
+                                    comparer.GetHashCode(Item2!),
+                                    comparer.GetHashCode(Item3!));
+        }
+
+        int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        /// <summary>
+        /// Returns a string that represents the value of this <see cref="ValueTuple{T1, T2, T3}"/> instance.
+        /// </summary>
+        /// <returns>The string representation of this <see cref="ValueTuple{T1, T2, T3}"/> instance.</returns>
+        /// <remarks>
+        /// The string returned by this method takes the form <c>(Item1, Item2, Item3)</c>.
+        /// If any field value is <see langword="null"/>, it is represented as <see cref="string.Empty"/>.
+        /// </remarks>
+        public override string ToString()
+        {
+            return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ")";
+        }
+
+        string IValueTupleInternal.ToStringEnd()
+        {
+            return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ")";
+        }
+
+        /// <summary>
+        /// The number of positions in this data structure.
+        /// </summary>
+        int ITuple.Length => 3;
+
+        /// <summary>
+        /// Get the element at position <param name="index"/>.
+        /// </summary>
+        object? ITuple.this[int index] =>
+            index switch
+            {
+                0 => Item1,
+                1 => Item2,
+                2 => Item3,
+                _ => throw new IndexOutOfRangeException(),
+            };
+    }
+
+    /// <summary>
+    /// Represents a 4-tuple, or quadruple, as a value type.
+    /// </summary>
+    /// <typeparam name="T1">The type of the tuple's first component.</typeparam>
+    /// <typeparam name="T2">The type of the tuple's second component.</typeparam>
+    /// <typeparam name="T3">The type of the tuple's third component.</typeparam>
+    /// <typeparam name="T4">The type of the tuple's fourth component.</typeparam>
+    [Serializable]
+    [StructLayout(LayoutKind.Auto)]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public struct ValueTuple<T1, T2, T3, T4>
+        : IEquatable<ValueTuple<T1, T2, T3, T4>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3, T4>>, IValueTupleInternal, ITuple
+    {
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4}"/> instance's first component.
+        /// </summary>
+        public T1 Item1;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4}"/> instance's second component.
+        /// </summary>
+        public T2 Item2;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4}"/> instance's third component.
+        /// </summary>
+        public T3 Item3;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4}"/> instance's fourth component.
+        /// </summary>
+        public T4 Item4;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ValueTuple{T1, T2, T3, T4}"/> value type.
+        /// </summary>
+        /// <param name="item1">The value of the tuple's first component.</param>
+        /// <param name="item2">The value of the tuple's second component.</param>
+        /// <param name="item3">The value of the tuple's third component.</param>
+        /// <param name="item4">The value of the tuple's fourth component.</param>
+        public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4)
+        {
+            Item1 = item1;
+            Item2 = item2;
+            Item3 = item3;
+            Item4 = item4;
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3, T4}"/> instance is equal to a specified object.
+        /// </summary>
+        /// <param name="obj">The object to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified object; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="obj"/> parameter is considered to be equal to the current instance under the following conditions:
+        /// <list type="bullet">
+        ///     <item><description>It is a <see cref="ValueTuple{T1, T2, T3, T4}"/> value type.</description></item>
+        ///     <item><description>Its components are of the same types as those of the current instance.</description></item>
+        ///     <item><description>Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.</description></item>
+        /// </list>
+        /// </remarks>
+        public override bool Equals(object? obj)
+        {
+            return obj is ValueTuple<T1, T2, T3, T4> && Equals((ValueTuple<T1, T2, T3, T4>)obj);
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3, T4}"/>
+        /// instance is equal to a specified <see cref="ValueTuple{T1, T2, T3, T4}"/>.
+        /// </summary>
+        /// <param name="other">The tuple to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified tuple; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="other"/> parameter is considered to be equal to the current instance if each of its fields
+        /// are equal to that of the current instance, using the default comparer for that field's type.
+        /// </remarks>
+        public bool Equals(ValueTuple<T1, T2, T3, T4> other)
+        {
+            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
+                && EqualityComparer<T2>.Default.Equals(Item2, other.Item2)
+                && EqualityComparer<T3>.Default.Equals(Item3, other.Item3)
+                && EqualityComparer<T4>.Default.Equals(Item4, other.Item4);
+        }
+
+        bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+        {
+            if (other == null || !(other is ValueTuple<T1, T2, T3, T4>)) return false;
+
+            var objTuple = (ValueTuple<T1, T2, T3, T4>)other;
+
+            return comparer.Equals(Item1, objTuple.Item1)
+                && comparer.Equals(Item2, objTuple.Item2)
+                && comparer.Equals(Item3, objTuple.Item3)
+                && comparer.Equals(Item4, objTuple.Item4);
+        }
+
+        int IComparable.CompareTo(object? other)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3, T4>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            return CompareTo((ValueTuple<T1, T2, T3, T4>)other);
+        }
+
+        /// <summary>Compares this instance to a specified instance and returns an indication of their relative values.</summary>
+        /// <param name="other">An instance to compare.</param>
+        /// <returns>
+        /// A signed number indicating the relative values of this instance and <paramref name="other"/>.
+        /// Returns less than zero if this instance is less than <paramref name="other"/>, zero if this
+        /// instance is equal to <paramref name="other"/>, and greater than zero if this instance is greater
+        /// than <paramref name="other"/>.
+        /// </returns>
+        public int CompareTo(ValueTuple<T1, T2, T3, T4> other)
+        {
+            int c = Comparer<T1>.Default.Compare(Item1, other.Item1);
+            if (c != 0) return c;
+
+            c = Comparer<T2>.Default.Compare(Item2, other.Item2);
+            if (c != 0) return c;
+
+            c = Comparer<T3>.Default.Compare(Item3, other.Item3);
+            if (c != 0) return c;
+
+            return Comparer<T4>.Default.Compare(Item4, other.Item4);
+        }
+
+        int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3, T4>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            var objTuple = (ValueTuple<T1, T2, T3, T4>)other;
+
+            int c = comparer.Compare(Item1, objTuple.Item1);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item2, objTuple.Item2);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item3, objTuple.Item3);
+            if (c != 0) return c;
+
+            return comparer.Compare(Item4, objTuple.Item4);
+        }
+
+        /// <summary>
+        /// Returns the hash code for the current <see cref="ValueTuple{T1, T2, T3, T4}"/> instance.
+        /// </summary>
+        /// <returns>A 32-bit signed integer hash code.</returns>
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(Item1?.GetHashCode() ?? 0,
+                                    Item2?.GetHashCode() ?? 0,
+                                    Item3?.GetHashCode() ?? 0,
+                                    Item4?.GetHashCode() ?? 0);
+        }
+
+        int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        private int GetHashCodeCore(IEqualityComparer comparer)
+        {
+            return HashCode.Combine(comparer.GetHashCode(Item1!),
+                                    comparer.GetHashCode(Item2!),
+                                    comparer.GetHashCode(Item3!),
+                                    comparer.GetHashCode(Item4!));
+        }
+
+        int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        /// <summary>
+        /// Returns a string that represents the value of this <see cref="ValueTuple{T1, T2, T3, T4}"/> instance.
+        /// </summary>
+        /// <returns>The string representation of this <see cref="ValueTuple{T1, T2, T3, T4}"/> instance.</returns>
+        /// <remarks>
+        /// The string returned by this method takes the form <c>(Item1, Item2, Item3, Item4)</c>.
+        /// If any field value is <see langword="null"/>, it is represented as <see cref="string.Empty"/>.
+        /// </remarks>
+        public override string ToString()
+        {
+            return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ")";
+        }
+
+        string IValueTupleInternal.ToStringEnd()
+        {
+            return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ")";
+        }
+
+        /// <summary>
+        /// The number of positions in this data structure.
+        /// </summary>
+        int ITuple.Length => 4;
+
+        /// <summary>
+        /// Get the element at position <param name="index"/>.
+        /// </summary>
+        object? ITuple.this[int index] =>
+            index switch
+            {
+                0 => Item1,
+                1 => Item2,
+                2 => Item3,
+                3 => Item4,
+                _ => throw new IndexOutOfRangeException(),
+            };
+    }
+
+    /// <summary>
+    /// Represents a 5-tuple, or quintuple, as a value type.
+    /// </summary>
+    /// <typeparam name="T1">The type of the tuple's first component.</typeparam>
+    /// <typeparam name="T2">The type of the tuple's second component.</typeparam>
+    /// <typeparam name="T3">The type of the tuple's third component.</typeparam>
+    /// <typeparam name="T4">The type of the tuple's fourth component.</typeparam>
+    /// <typeparam name="T5">The type of the tuple's fifth component.</typeparam>
+    [Serializable]
+    [StructLayout(LayoutKind.Auto)]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public struct ValueTuple<T1, T2, T3, T4, T5>
+        : IEquatable<ValueTuple<T1, T2, T3, T4, T5>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3, T4, T5>>, IValueTupleInternal, ITuple
+    {
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> instance's first component.
+        /// </summary>
+        public T1 Item1;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> instance's second component.
+        /// </summary>
+        public T2 Item2;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> instance's third component.
+        /// </summary>
+        public T3 Item3;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> instance's fourth component.
+        /// </summary>
+        public T4 Item4;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> instance's fifth component.
+        /// </summary>
+        public T5 Item5;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> value type.
+        /// </summary>
+        /// <param name="item1">The value of the tuple's first component.</param>
+        /// <param name="item2">The value of the tuple's second component.</param>
+        /// <param name="item3">The value of the tuple's third component.</param>
+        /// <param name="item4">The value of the tuple's fourth component.</param>
+        /// <param name="item5">The value of the tuple's fifth component.</param>
+        public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
+        {
+            Item1 = item1;
+            Item2 = item2;
+            Item3 = item3;
+            Item4 = item4;
+            Item5 = item5;
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> instance is equal to a specified object.
+        /// </summary>
+        /// <param name="obj">The object to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified object; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="obj"/> parameter is considered to be equal to the current instance under the following conditions:
+        /// <list type="bullet">
+        ///     <item><description>It is a <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> value type.</description></item>
+        ///     <item><description>Its components are of the same types as those of the current instance.</description></item>
+        ///     <item><description>Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.</description></item>
+        /// </list>
+        /// </remarks>
+        public override bool Equals(object? obj)
+        {
+            return obj is ValueTuple<T1, T2, T3, T4, T5> && Equals((ValueTuple<T1, T2, T3, T4, T5>)obj);
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3, T4, T5}"/>
+        /// instance is equal to a specified <see cref="ValueTuple{T1, T2, T3, T4, T5}"/>.
+        /// </summary>
+        /// <param name="other">The tuple to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified tuple; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="other"/> parameter is considered to be equal to the current instance if each of its fields
+        /// are equal to that of the current instance, using the default comparer for that field's type.
+        /// </remarks>
+        public bool Equals(ValueTuple<T1, T2, T3, T4, T5> other)
+        {
+            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
+                && EqualityComparer<T2>.Default.Equals(Item2, other.Item2)
+                && EqualityComparer<T3>.Default.Equals(Item3, other.Item3)
+                && EqualityComparer<T4>.Default.Equals(Item4, other.Item4)
+                && EqualityComparer<T5>.Default.Equals(Item5, other.Item5);
+        }
+
+        bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+        {
+            if (other == null || !(other is ValueTuple<T1, T2, T3, T4, T5>)) return false;
+
+            var objTuple = (ValueTuple<T1, T2, T3, T4, T5>)other;
+
+            return comparer.Equals(Item1, objTuple.Item1)
+                && comparer.Equals(Item2, objTuple.Item2)
+                && comparer.Equals(Item3, objTuple.Item3)
+                && comparer.Equals(Item4, objTuple.Item4)
+                && comparer.Equals(Item5, objTuple.Item5);
+        }
+
+        int IComparable.CompareTo(object? other)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3, T4, T5>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            return CompareTo((ValueTuple<T1, T2, T3, T4, T5>)other);
+        }
+
+        /// <summary>Compares this instance to a specified instance and returns an indication of their relative values.</summary>
+        /// <param name="other">An instance to compare.</param>
+        /// <returns>
+        /// A signed number indicating the relative values of this instance and <paramref name="other"/>.
+        /// Returns less than zero if this instance is less than <paramref name="other"/>, zero if this
+        /// instance is equal to <paramref name="other"/>, and greater than zero if this instance is greater
+        /// than <paramref name="other"/>.
+        /// </returns>
+        public int CompareTo(ValueTuple<T1, T2, T3, T4, T5> other)
+        {
+            int c = Comparer<T1>.Default.Compare(Item1, other.Item1);
+            if (c != 0) return c;
+
+            c = Comparer<T2>.Default.Compare(Item2, other.Item2);
+            if (c != 0) return c;
+
+            c = Comparer<T3>.Default.Compare(Item3, other.Item3);
+            if (c != 0) return c;
+
+            c = Comparer<T4>.Default.Compare(Item4, other.Item4);
+            if (c != 0) return c;
+
+            return Comparer<T5>.Default.Compare(Item5, other.Item5);
+        }
+
+        int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3, T4, T5>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            var objTuple = (ValueTuple<T1, T2, T3, T4, T5>)other;
+
+            int c = comparer.Compare(Item1, objTuple.Item1);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item2, objTuple.Item2);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item3, objTuple.Item3);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item4, objTuple.Item4);
+            if (c != 0) return c;
+
+            return comparer.Compare(Item5, objTuple.Item5);
+        }
+
+        /// <summary>
+        /// Returns the hash code for the current <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> instance.
+        /// </summary>
+        /// <returns>A 32-bit signed integer hash code.</returns>
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(Item1?.GetHashCode() ?? 0,
+                                    Item2?.GetHashCode() ?? 0,
+                                    Item3?.GetHashCode() ?? 0,
+                                    Item4?.GetHashCode() ?? 0,
+                                    Item5?.GetHashCode() ?? 0);
+        }
+
+        int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        private int GetHashCodeCore(IEqualityComparer comparer)
+        {
+            return HashCode.Combine(comparer.GetHashCode(Item1!),
+                                    comparer.GetHashCode(Item2!),
+                                    comparer.GetHashCode(Item3!),
+                                    comparer.GetHashCode(Item4!),
+                                    comparer.GetHashCode(Item5!));
+        }
+
+        int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        /// <summary>
+        /// Returns a string that represents the value of this <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> instance.
+        /// </summary>
+        /// <returns>The string representation of this <see cref="ValueTuple{T1, T2, T3, T4, T5}"/> instance.</returns>
+        /// <remarks>
+        /// The string returned by this method takes the form <c>(Item1, Item2, Item3, Item4, Item5)</c>.
+        /// If any field value is <see langword="null"/>, it is represented as <see cref="string.Empty"/>.
+        /// </remarks>
+        public override string ToString()
+        {
+            return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ")";
+        }
+
+        string IValueTupleInternal.ToStringEnd()
+        {
+            return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ")";
+        }
+
+        /// <summary>
+        /// The number of positions in this data structure.
+        /// </summary>
+        int ITuple.Length => 5;
+
+        /// <summary>
+        /// Get the element at position <param name="index"/>.
+        /// </summary>
+        object? ITuple.this[int index] =>
+            index switch
+            {
+                0 => Item1,
+                1 => Item2,
+                2 => Item3,
+                3 => Item4,
+                4 => Item5,
+                _ => throw new IndexOutOfRangeException(),
+            };
+    }
+
+    /// <summary>
+    /// Represents a 6-tuple, or sixtuple, as a value type.
+    /// </summary>
+    /// <typeparam name="T1">The type of the tuple's first component.</typeparam>
+    /// <typeparam name="T2">The type of the tuple's second component.</typeparam>
+    /// <typeparam name="T3">The type of the tuple's third component.</typeparam>
+    /// <typeparam name="T4">The type of the tuple's fourth component.</typeparam>
+    /// <typeparam name="T5">The type of the tuple's fifth component.</typeparam>
+    /// <typeparam name="T6">The type of the tuple's sixth component.</typeparam>
+    [Serializable]
+    [StructLayout(LayoutKind.Auto)]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public struct ValueTuple<T1, T2, T3, T4, T5, T6>
+        : IEquatable<ValueTuple<T1, T2, T3, T4, T5, T6>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3, T4, T5, T6>>, IValueTupleInternal, ITuple
+    {
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> instance's first component.
+        /// </summary>
+        public T1 Item1;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> instance's second component.
+        /// </summary>
+        public T2 Item2;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> instance's third component.
+        /// </summary>
+        public T3 Item3;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> instance's fourth component.
+        /// </summary>
+        public T4 Item4;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> instance's fifth component.
+        /// </summary>
+        public T5 Item5;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> instance's sixth component.
+        /// </summary>
+        public T6 Item6;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> value type.
+        /// </summary>
+        /// <param name="item1">The value of the tuple's first component.</param>
+        /// <param name="item2">The value of the tuple's second component.</param>
+        /// <param name="item3">The value of the tuple's third component.</param>
+        /// <param name="item4">The value of the tuple's fourth component.</param>
+        /// <param name="item5">The value of the tuple's fifth component.</param>
+        /// <param name="item6">The value of the tuple's sixth component.</param>
+        public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
+        {
+            Item1 = item1;
+            Item2 = item2;
+            Item3 = item3;
+            Item4 = item4;
+            Item5 = item5;
+            Item6 = item6;
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> instance is equal to a specified object.
+        /// </summary>
+        /// <param name="obj">The object to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified object; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="obj"/> parameter is considered to be equal to the current instance under the following conditions:
+        /// <list type="bullet">
+        ///     <item><description>It is a <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> value type.</description></item>
+        ///     <item><description>Its components are of the same types as those of the current instance.</description></item>
+        ///     <item><description>Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.</description></item>
+        /// </list>
+        /// </remarks>
+        public override bool Equals(object? obj)
+        {
+            return obj is ValueTuple<T1, T2, T3, T4, T5, T6> && Equals((ValueTuple<T1, T2, T3, T4, T5, T6>)obj);
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/>
+        /// instance is equal to a specified <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/>.
+        /// </summary>
+        /// <param name="other">The tuple to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified tuple; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="other"/> parameter is considered to be equal to the current instance if each of its fields
+        /// are equal to that of the current instance, using the default comparer for that field's type.
+        /// </remarks>
+        public bool Equals(ValueTuple<T1, T2, T3, T4, T5, T6> other)
+        {
+            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
+                && EqualityComparer<T2>.Default.Equals(Item2, other.Item2)
+                && EqualityComparer<T3>.Default.Equals(Item3, other.Item3)
+                && EqualityComparer<T4>.Default.Equals(Item4, other.Item4)
+                && EqualityComparer<T5>.Default.Equals(Item5, other.Item5)
+                && EqualityComparer<T6>.Default.Equals(Item6, other.Item6);
+        }
+
+        bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+        {
+            if (other == null || !(other is ValueTuple<T1, T2, T3, T4, T5, T6>)) return false;
+
+            var objTuple = (ValueTuple<T1, T2, T3, T4, T5, T6>)other;
+
+            return comparer.Equals(Item1, objTuple.Item1)
+                && comparer.Equals(Item2, objTuple.Item2)
+                && comparer.Equals(Item3, objTuple.Item3)
+                && comparer.Equals(Item4, objTuple.Item4)
+                && comparer.Equals(Item5, objTuple.Item5)
+                && comparer.Equals(Item6, objTuple.Item6);
+        }
+
+        int IComparable.CompareTo(object? other)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3, T4, T5, T6>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            return CompareTo((ValueTuple<T1, T2, T3, T4, T5, T6>)other);
+        }
+
+        /// <summary>Compares this instance to a specified instance and returns an indication of their relative values.</summary>
+        /// <param name="other">An instance to compare.</param>
+        /// <returns>
+        /// A signed number indicating the relative values of this instance and <paramref name="other"/>.
+        /// Returns less than zero if this instance is less than <paramref name="other"/>, zero if this
+        /// instance is equal to <paramref name="other"/>, and greater than zero if this instance is greater
+        /// than <paramref name="other"/>.
+        /// </returns>
+        public int CompareTo(ValueTuple<T1, T2, T3, T4, T5, T6> other)
+        {
+            int c = Comparer<T1>.Default.Compare(Item1, other.Item1);
+            if (c != 0) return c;
+
+            c = Comparer<T2>.Default.Compare(Item2, other.Item2);
+            if (c != 0) return c;
+
+            c = Comparer<T3>.Default.Compare(Item3, other.Item3);
+            if (c != 0) return c;
+
+            c = Comparer<T4>.Default.Compare(Item4, other.Item4);
+            if (c != 0) return c;
+
+            c = Comparer<T5>.Default.Compare(Item5, other.Item5);
+            if (c != 0) return c;
+
+            return Comparer<T6>.Default.Compare(Item6, other.Item6);
+        }
+
+        int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3, T4, T5, T6>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            var objTuple = (ValueTuple<T1, T2, T3, T4, T5, T6>)other;
+
+            int c = comparer.Compare(Item1, objTuple.Item1);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item2, objTuple.Item2);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item3, objTuple.Item3);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item4, objTuple.Item4);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item5, objTuple.Item5);
+            if (c != 0) return c;
+
+            return comparer.Compare(Item6, objTuple.Item6);
+        }
+
+        /// <summary>
+        /// Returns the hash code for the current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> instance.
+        /// </summary>
+        /// <returns>A 32-bit signed integer hash code.</returns>
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(Item1?.GetHashCode() ?? 0,
+                                    Item2?.GetHashCode() ?? 0,
+                                    Item3?.GetHashCode() ?? 0,
+                                    Item4?.GetHashCode() ?? 0,
+                                    Item5?.GetHashCode() ?? 0,
+                                    Item6?.GetHashCode() ?? 0);
+        }
+
+        int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        private int GetHashCodeCore(IEqualityComparer comparer)
+        {
+            return HashCode.Combine(comparer.GetHashCode(Item1!),
+                                    comparer.GetHashCode(Item2!),
+                                    comparer.GetHashCode(Item3!),
+                                    comparer.GetHashCode(Item4!),
+                                    comparer.GetHashCode(Item5!),
+                                    comparer.GetHashCode(Item6!));
+        }
+
+        int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        /// <summary>
+        /// Returns a string that represents the value of this <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> instance.
+        /// </summary>
+        /// <returns>The string representation of this <see cref="ValueTuple{T1, T2, T3, T4, T5, T6}"/> instance.</returns>
+        /// <remarks>
+        /// The string returned by this method takes the form <c>(Item1, Item2, Item3, Item4, Item5, Item6)</c>.
+        /// If any field value is <see langword="null"/>, it is represented as <see cref="string.Empty"/>.
+        /// </remarks>
+        public override string ToString()
+        {
+            return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ")";
+        }
+
+        string IValueTupleInternal.ToStringEnd()
+        {
+            return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ")";
+        }
+
+        /// <summary>
+        /// The number of positions in this data structure.
+        /// </summary>
+        int ITuple.Length => 6;
+
+        /// <summary>
+        /// Get the element at position <param name="index"/>.
+        /// </summary>
+        object? ITuple.this[int index] =>
+            index switch
+            {
+                0 => Item1,
+                1 => Item2,
+                2 => Item3,
+                3 => Item4,
+                4 => Item5,
+                5 => Item6,
+                _ => throw new IndexOutOfRangeException(),
+            };
+    }
+
+    /// <summary>
+    /// Represents a 7-tuple, or sentuple, as a value type.
+    /// </summary>
+    /// <typeparam name="T1">The type of the tuple's first component.</typeparam>
+    /// <typeparam name="T2">The type of the tuple's second component.</typeparam>
+    /// <typeparam name="T3">The type of the tuple's third component.</typeparam>
+    /// <typeparam name="T4">The type of the tuple's fourth component.</typeparam>
+    /// <typeparam name="T5">The type of the tuple's fifth component.</typeparam>
+    /// <typeparam name="T6">The type of the tuple's sixth component.</typeparam>
+    /// <typeparam name="T7">The type of the tuple's seventh component.</typeparam>
+    [Serializable]
+    [StructLayout(LayoutKind.Auto)]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7>
+        : IEquatable<ValueTuple<T1, T2, T3, T4, T5, T6, T7>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3, T4, T5, T6, T7>>, IValueTupleInternal, ITuple
+    {
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance's first component.
+        /// </summary>
+        public T1 Item1;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance's second component.
+        /// </summary>
+        public T2 Item2;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance's third component.
+        /// </summary>
+        public T3 Item3;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance's fourth component.
+        /// </summary>
+        public T4 Item4;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance's fifth component.
+        /// </summary>
+        public T5 Item5;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance's sixth component.
+        /// </summary>
+        public T6 Item6;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance's seventh component.
+        /// </summary>
+        public T7 Item7;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> value type.
+        /// </summary>
+        /// <param name="item1">The value of the tuple's first component.</param>
+        /// <param name="item2">The value of the tuple's second component.</param>
+        /// <param name="item3">The value of the tuple's third component.</param>
+        /// <param name="item4">The value of the tuple's fourth component.</param>
+        /// <param name="item5">The value of the tuple's fifth component.</param>
+        /// <param name="item6">The value of the tuple's sixth component.</param>
+        /// <param name="item7">The value of the tuple's seventh component.</param>
+        public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
+        {
+            Item1 = item1;
+            Item2 = item2;
+            Item3 = item3;
+            Item4 = item4;
+            Item5 = item5;
+            Item6 = item6;
+            Item7 = item7;
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance is equal to a specified object.
+        /// </summary>
+        /// <param name="obj">The object to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified object; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="obj"/> parameter is considered to be equal to the current instance under the following conditions:
+        /// <list type="bullet">
+        ///     <item><description>It is a <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> value type.</description></item>
+        ///     <item><description>Its components are of the same types as those of the current instance.</description></item>
+        ///     <item><description>Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.</description></item>
+        /// </list>
+        /// </remarks>
+        public override bool Equals(object? obj)
+        {
+            return obj is ValueTuple<T1, T2, T3, T4, T5, T6, T7> && Equals((ValueTuple<T1, T2, T3, T4, T5, T6, T7>)obj);
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/>
+        /// instance is equal to a specified <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/>.
+        /// </summary>
+        /// <param name="other">The tuple to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified tuple; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="other"/> parameter is considered to be equal to the current instance if each of its fields
+        /// are equal to that of the current instance, using the default comparer for that field's type.
+        /// </remarks>
+        public bool Equals(ValueTuple<T1, T2, T3, T4, T5, T6, T7> other)
+        {
+            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
+                && EqualityComparer<T2>.Default.Equals(Item2, other.Item2)
+                && EqualityComparer<T3>.Default.Equals(Item3, other.Item3)
+                && EqualityComparer<T4>.Default.Equals(Item4, other.Item4)
+                && EqualityComparer<T5>.Default.Equals(Item5, other.Item5)
+                && EqualityComparer<T6>.Default.Equals(Item6, other.Item6)
+                && EqualityComparer<T7>.Default.Equals(Item7, other.Item7);
+        }
+
+        bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+        {
+            if (other == null || !(other is ValueTuple<T1, T2, T3, T4, T5, T6, T7>)) return false;
+
+            var objTuple = (ValueTuple<T1, T2, T3, T4, T5, T6, T7>)other;
+
+            return comparer.Equals(Item1, objTuple.Item1)
+                && comparer.Equals(Item2, objTuple.Item2)
+                && comparer.Equals(Item3, objTuple.Item3)
+                && comparer.Equals(Item4, objTuple.Item4)
+                && comparer.Equals(Item5, objTuple.Item5)
+                && comparer.Equals(Item6, objTuple.Item6)
+                && comparer.Equals(Item7, objTuple.Item7);
+        }
+
+        int IComparable.CompareTo(object? other)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3, T4, T5, T6, T7>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            return CompareTo((ValueTuple<T1, T2, T3, T4, T5, T6, T7>)other);
+        }
+
+        /// <summary>Compares this instance to a specified instance and returns an indication of their relative values.</summary>
+        /// <param name="other">An instance to compare.</param>
+        /// <returns>
+        /// A signed number indicating the relative values of this instance and <paramref name="other"/>.
+        /// Returns less than zero if this instance is less than <paramref name="other"/>, zero if this
+        /// instance is equal to <paramref name="other"/>, and greater than zero if this instance is greater
+        /// than <paramref name="other"/>.
+        /// </returns>
+        public int CompareTo(ValueTuple<T1, T2, T3, T4, T5, T6, T7> other)
+        {
+            int c = Comparer<T1>.Default.Compare(Item1, other.Item1);
+            if (c != 0) return c;
+
+            c = Comparer<T2>.Default.Compare(Item2, other.Item2);
+            if (c != 0) return c;
+
+            c = Comparer<T3>.Default.Compare(Item3, other.Item3);
+            if (c != 0) return c;
+
+            c = Comparer<T4>.Default.Compare(Item4, other.Item4);
+            if (c != 0) return c;
+
+            c = Comparer<T5>.Default.Compare(Item5, other.Item5);
+            if (c != 0) return c;
+
+            c = Comparer<T6>.Default.Compare(Item6, other.Item6);
+            if (c != 0) return c;
+
+            return Comparer<T7>.Default.Compare(Item7, other.Item7);
+        }
+
+        int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3, T4, T5, T6, T7>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            var objTuple = (ValueTuple<T1, T2, T3, T4, T5, T6, T7>)other;
+
+            int c = comparer.Compare(Item1, objTuple.Item1);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item2, objTuple.Item2);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item3, objTuple.Item3);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item4, objTuple.Item4);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item5, objTuple.Item5);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item6, objTuple.Item6);
+            if (c != 0) return c;
+
+            return comparer.Compare(Item7, objTuple.Item7);
+        }
+
+        /// <summary>
+        /// Returns the hash code for the current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance.
+        /// </summary>
+        /// <returns>A 32-bit signed integer hash code.</returns>
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(Item1?.GetHashCode() ?? 0,
+                                    Item2?.GetHashCode() ?? 0,
+                                    Item3?.GetHashCode() ?? 0,
+                                    Item4?.GetHashCode() ?? 0,
+                                    Item5?.GetHashCode() ?? 0,
+                                    Item6?.GetHashCode() ?? 0,
+                                    Item7?.GetHashCode() ?? 0);
+        }
+
+        int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        private int GetHashCodeCore(IEqualityComparer comparer)
+        {
+            return HashCode.Combine(comparer.GetHashCode(Item1!),
+                                    comparer.GetHashCode(Item2!),
+                                    comparer.GetHashCode(Item3!),
+                                    comparer.GetHashCode(Item4!),
+                                    comparer.GetHashCode(Item5!),
+                                    comparer.GetHashCode(Item6!),
+                                    comparer.GetHashCode(Item7!));
+        }
+
+        int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        /// <summary>
+        /// Returns a string that represents the value of this <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance.
+        /// </summary>
+        /// <returns>The string representation of this <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7}"/> instance.</returns>
+        /// <remarks>
+        /// The string returned by this method takes the form <c>(Item1, Item2, Item3, Item4, Item5, Item6, Item7)</c>.
+        /// If any field value is <see langword="null"/>, it is represented as <see cref="string.Empty"/>.
+        /// </remarks>
+        public override string ToString()
+        {
+            return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ")";
+        }
+
+        string IValueTupleInternal.ToStringEnd()
+        {
+            return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ")";
+        }
+
+        /// <summary>
+        /// The number of positions in this data structure.
+        /// </summary>
+        int ITuple.Length => 7;
+
+        /// <summary>
+        /// Get the element at position <param name="index"/>.
+        /// </summary>
+        object? ITuple.this[int index] =>
+            index switch
+            {
+                0 => Item1,
+                1 => Item2,
+                2 => Item3,
+                3 => Item4,
+                4 => Item5,
+                5 => Item6,
+                6 => Item7,
+                _ => throw new IndexOutOfRangeException(),
+            };
+    }
+
+    /// <summary>
+    /// Represents an 8-tuple, or octuple, as a value type.
+    /// </summary>
+    /// <typeparam name="T1">The type of the tuple's first component.</typeparam>
+    /// <typeparam name="T2">The type of the tuple's second component.</typeparam>
+    /// <typeparam name="T3">The type of the tuple's third component.</typeparam>
+    /// <typeparam name="T4">The type of the tuple's fourth component.</typeparam>
+    /// <typeparam name="T5">The type of the tuple's fifth component.</typeparam>
+    /// <typeparam name="T6">The type of the tuple's sixth component.</typeparam>
+    /// <typeparam name="T7">The type of the tuple's seventh component.</typeparam>
+    /// <typeparam name="TRest">The type of the tuple's eighth component.</typeparam>
+    [Serializable]
+    [StructLayout(LayoutKind.Auto)]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>
+    : IEquatable<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>>, IValueTupleInternal, ITuple
+    where TRest : struct
+    {
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance's first component.
+        /// </summary>
+        public T1 Item1;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance's second component.
+        /// </summary>
+        public T2 Item2;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance's third component.
+        /// </summary>
+        public T3 Item3;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance's fourth component.
+        /// </summary>
+        public T4 Item4;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance's fifth component.
+        /// </summary>
+        public T5 Item5;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance's sixth component.
+        /// </summary>
+        public T6 Item6;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance's seventh component.
+        /// </summary>
+        public T7 Item7;
+        /// <summary>
+        /// The current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance's eighth component.
+        /// </summary>
+        public TRest Rest;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> value type.
+        /// </summary>
+        /// <param name="item1">The value of the tuple's first component.</param>
+        /// <param name="item2">The value of the tuple's second component.</param>
+        /// <param name="item3">The value of the tuple's third component.</param>
+        /// <param name="item4">The value of the tuple's fourth component.</param>
+        /// <param name="item5">The value of the tuple's fifth component.</param>
+        /// <param name="item6">The value of the tuple's sixth component.</param>
+        /// <param name="item7">The value of the tuple's seventh component.</param>
+        /// <param name="rest">The value of the tuple's eight component.</param>
+        public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest)
+        {
+            if (!(rest is IValueTupleInternal))
+            {
+                throw new ArgumentException(SR.ArgumentException_ValueTupleLastArgumentNotAValueTuple);
+            }
+
+            Item1 = item1;
+            Item2 = item2;
+            Item3 = item3;
+            Item4 = item4;
+            Item5 = item5;
+            Item6 = item6;
+            Item7 = item7;
+            Rest = rest;
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance is equal to a specified object.
+        /// </summary>
+        /// <param name="obj">The object to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified object; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="obj"/> parameter is considered to be equal to the current instance under the following conditions:
+        /// <list type="bullet">
+        ///     <item><description>It is a <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> value type.</description></item>
+        ///     <item><description>Its components are of the same types as those of the current instance.</description></item>
+        ///     <item><description>Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.</description></item>
+        /// </list>
+        /// </remarks>
+        public override bool Equals(object? obj)
+        {
+            return obj is ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> && Equals((ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>)obj);
+        }
+
+        /// <summary>
+        /// Returns a value that indicates whether the current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/>
+        /// instance is equal to a specified <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/>.
+        /// </summary>
+        /// <param name="other">The tuple to compare with this instance.</param>
+        /// <returns><see langword="true"/> if the current instance is equal to the specified tuple; otherwise, <see langword="false"/>.</returns>
+        /// <remarks>
+        /// The <paramref name="other"/> parameter is considered to be equal to the current instance if each of its fields
+        /// are equal to that of the current instance, using the default comparer for that field's type.
+        /// </remarks>
+        public bool Equals(ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> other)
+        {
+            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
+                && EqualityComparer<T2>.Default.Equals(Item2, other.Item2)
+                && EqualityComparer<T3>.Default.Equals(Item3, other.Item3)
+                && EqualityComparer<T4>.Default.Equals(Item4, other.Item4)
+                && EqualityComparer<T5>.Default.Equals(Item5, other.Item5)
+                && EqualityComparer<T6>.Default.Equals(Item6, other.Item6)
+                && EqualityComparer<T7>.Default.Equals(Item7, other.Item7)
+                && EqualityComparer<TRest>.Default.Equals(Rest, other.Rest);
+        }
+
+        bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+        {
+            if (other == null || !(other is ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>)) return false;
+
+            var objTuple = (ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>)other;
+
+            return comparer.Equals(Item1, objTuple.Item1)
+                && comparer.Equals(Item2, objTuple.Item2)
+                && comparer.Equals(Item3, objTuple.Item3)
+                && comparer.Equals(Item4, objTuple.Item4)
+                && comparer.Equals(Item5, objTuple.Item5)
+                && comparer.Equals(Item6, objTuple.Item6)
+                && comparer.Equals(Item7, objTuple.Item7)
+                && comparer.Equals(Rest, objTuple.Rest);
+        }
+
+        int IComparable.CompareTo(object? other)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            return CompareTo((ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>)other);
+        }
+
+        /// <summary>Compares this instance to a specified instance and returns an indication of their relative values.</summary>
+        /// <param name="other">An instance to compare.</param>
+        /// <returns>
+        /// A signed number indicating the relative values of this instance and <paramref name="other"/>.
+        /// Returns less than zero if this instance is less than <paramref name="other"/>, zero if this
+        /// instance is equal to <paramref name="other"/>, and greater than zero if this instance is greater
+        /// than <paramref name="other"/>.
+        /// </returns>
+        public int CompareTo(ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> other)
+        {
+            int c = Comparer<T1>.Default.Compare(Item1, other.Item1);
+            if (c != 0) return c;
+
+            c = Comparer<T2>.Default.Compare(Item2, other.Item2);
+            if (c != 0) return c;
+
+            c = Comparer<T3>.Default.Compare(Item3, other.Item3);
+            if (c != 0) return c;
+
+            c = Comparer<T4>.Default.Compare(Item4, other.Item4);
+            if (c != 0) return c;
+
+            c = Comparer<T5>.Default.Compare(Item5, other.Item5);
+            if (c != 0) return c;
+
+            c = Comparer<T6>.Default.Compare(Item6, other.Item6);
+            if (c != 0) return c;
+
+            c = Comparer<T7>.Default.Compare(Item7, other.Item7);
+            if (c != 0) return c;
+
+            return Comparer<TRest>.Default.Compare(Rest, other.Rest);
+        }
+
+        int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+        {
+            if (other == null) return 1;
+
+            if (!(other is ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>))
+            {
+                throw new ArgumentException(SR.Format(SR.ArgumentException_ValueTupleIncorrectType, GetType()), nameof(other));
+            }
+
+            var objTuple = (ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>)other;
+
+            int c = comparer.Compare(Item1, objTuple.Item1);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item2, objTuple.Item2);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item3, objTuple.Item3);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item4, objTuple.Item4);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item5, objTuple.Item5);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item6, objTuple.Item6);
+            if (c != 0) return c;
+
+            c = comparer.Compare(Item7, objTuple.Item7);
+            if (c != 0) return c;
+
+            return comparer.Compare(Rest, objTuple.Rest);
+        }
+
+        /// <summary>
+        /// Returns the hash code for the current <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance.
+        /// </summary>
+        /// <returns>A 32-bit signed integer hash code.</returns>
+        public override int GetHashCode()
+        {
+            // We want to have a limited hash in this case. We'll use the first 7 elements of the tuple
+            if (!(Rest is IValueTupleInternal))
+            {
+                return HashCode.Combine(Item1?.GetHashCode() ?? 0,
+                                        Item2?.GetHashCode() ?? 0,
+                                        Item3?.GetHashCode() ?? 0,
+                                        Item4?.GetHashCode() ?? 0,
+                                        Item5?.GetHashCode() ?? 0,
+                                        Item6?.GetHashCode() ?? 0,
+                                        Item7?.GetHashCode() ?? 0);
+            }
+
+            int size = ((IValueTupleInternal)Rest).Length;
+            int restHashCode = Rest.GetHashCode();
+            if (size >= 8)
+            {
+                return restHashCode;
+            }
+
+            // In this case, the rest member has less than 8 elements so we need to combine some of our elements with the elements in rest
+            int k = 8 - size;
+            switch (k)
+            {
+                case 1:
+                    return HashCode.Combine(Item7?.GetHashCode() ?? 0,
+                                            restHashCode);
+                case 2:
+                    return HashCode.Combine(Item6?.GetHashCode() ?? 0,
+                                            Item7?.GetHashCode() ?? 0,
+                                            restHashCode);
+                case 3:
+                    return HashCode.Combine(Item5?.GetHashCode() ?? 0,
+                                            Item6?.GetHashCode() ?? 0,
+                                            Item7?.GetHashCode() ?? 0,
+                                            restHashCode);
+                case 4:
+                    return HashCode.Combine(Item4?.GetHashCode() ?? 0,
+                                            Item5?.GetHashCode() ?? 0,
+                                            Item6?.GetHashCode() ?? 0,
+                                            Item7?.GetHashCode() ?? 0,
+                                            restHashCode);
+                case 5:
+                    return HashCode.Combine(Item3?.GetHashCode() ?? 0,
+                                            Item4?.GetHashCode() ?? 0,
+                                            Item5?.GetHashCode() ?? 0,
+                                            Item6?.GetHashCode() ?? 0,
+                                            Item7?.GetHashCode() ?? 0,
+                                            restHashCode);
+                case 6:
+                    return HashCode.Combine(Item2?.GetHashCode() ?? 0,
+                                            Item3?.GetHashCode() ?? 0,
+                                            Item4?.GetHashCode() ?? 0,
+                                            Item5?.GetHashCode() ?? 0,
+                                            Item6?.GetHashCode() ?? 0,
+                                            Item7?.GetHashCode() ?? 0,
+                                            restHashCode);
+                case 7:
+                case 8:
+                    return HashCode.Combine(Item1?.GetHashCode() ?? 0,
+                                            Item2?.GetHashCode() ?? 0,
+                                            Item3?.GetHashCode() ?? 0,
+                                            Item4?.GetHashCode() ?? 0,
+                                            Item5?.GetHashCode() ?? 0,
+                                            Item6?.GetHashCode() ?? 0,
+                                            Item7?.GetHashCode() ?? 0,
+                                            restHashCode);
+            }
+
+            Debug.Fail("Missed all cases for computing ValueTuple hash code");
+            return -1;
+        }
+
+        int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        private int GetHashCodeCore(IEqualityComparer comparer)
+        {
+            // We want to have a limited hash in this case. We'll use the first 7 elements of the tuple
+            if (!(Rest is IValueTupleInternal rest))
+            {
+                return HashCode.Combine(comparer.GetHashCode(Item1!), comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!),
+                                        comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!),
+                                        comparer.GetHashCode(Item7!));
+            }
+
+            int size = rest.Length;
+            int restHashCode = rest.GetHashCode(comparer);
+            if (size >= 8)
+            {
+                return restHashCode;
+            }
+
+            // In this case, the rest member has less than 8 elements so we need to combine some our elements with the elements in rest
+            int k = 8 - size;
+            switch (k)
+            {
+                case 1:
+                    return HashCode.Combine(comparer.GetHashCode(Item7!),
+                                            restHashCode);
+                case 2:
+                    return HashCode.Combine(comparer.GetHashCode(Item6!),
+                                            comparer.GetHashCode(Item7!),
+                                            restHashCode);
+                case 3:
+                    return HashCode.Combine(comparer.GetHashCode(Item5!),
+                                            comparer.GetHashCode(Item6!),
+                                            comparer.GetHashCode(Item7!),
+                                            restHashCode);
+                case 4:
+                    return HashCode.Combine(comparer.GetHashCode(Item4!),
+                                            comparer.GetHashCode(Item5!),
+                                            comparer.GetHashCode(Item6!),
+                                            comparer.GetHashCode(Item7!),
+                                            restHashCode);
+                case 5:
+                    return HashCode.Combine(comparer.GetHashCode(Item3!),
+                                            comparer.GetHashCode(Item4!),
+                                            comparer.GetHashCode(Item5!),
+                                            comparer.GetHashCode(Item6!),
+                                            comparer.GetHashCode(Item7!),
+                                            restHashCode);
+                case 6:
+                    return HashCode.Combine(comparer.GetHashCode(Item2!),
+                                            comparer.GetHashCode(Item3!),
+                                            comparer.GetHashCode(Item4!),
+                                            comparer.GetHashCode(Item5!),
+                                            comparer.GetHashCode(Item6!),
+                                            comparer.GetHashCode(Item7!),
+                                            restHashCode);
+                case 7:
+                case 8:
+                    return HashCode.Combine(comparer.GetHashCode(Item1!),
+                                            comparer.GetHashCode(Item2!),
+                                            comparer.GetHashCode(Item3!),
+                                            comparer.GetHashCode(Item4!),
+                                            comparer.GetHashCode(Item5!),
+                                            comparer.GetHashCode(Item6!),
+                                            comparer.GetHashCode(Item7!),
+                                            restHashCode);
+            }
+
+            Debug.Fail("Missed all cases for computing ValueTuple hash code");
+            return -1;
+        }
+
+        int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
+        {
+            return GetHashCodeCore(comparer);
+        }
+
+        /// <summary>
+        /// Returns a string that represents the value of this <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance.
+        /// </summary>
+        /// <returns>The string representation of this <see cref="ValueTuple{T1, T2, T3, T4, T5, T6, T7, TRest}"/> instance.</returns>
+        /// <remarks>
+        /// The string returned by this method takes the form <c>(Item1, Item2, Item3, Item4, Item5, Item6, Item7, Rest)</c>.
+        /// If any field value is <see langword="null"/>, it is represented as <see cref="string.Empty"/>.
+        /// </remarks>
+        public override string ToString()
+        {
+            if (Rest is IValueTupleInternal)
+            {
+                return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + ((IValueTupleInternal)Rest).ToStringEnd();
+            }
+
+            return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + Rest.ToString() + ")";
+        }
+
+        string IValueTupleInternal.ToStringEnd()
+        {
+            if (Rest is IValueTupleInternal)
+            {
+                return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + ((IValueTupleInternal)Rest).ToStringEnd();
+            }
+
+            return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + Rest.ToString() + ")";
+        }
+
+        /// <summary>
+        /// The number of positions in this data structure.
+        /// </summary>
+        int ITuple.Length => Rest is IValueTupleInternal ? 7 + ((IValueTupleInternal)Rest).Length : 8;
+
+        /// <summary>
+        /// Get the element at position <param name="index"/>.
+        /// </summary>
+        object? ITuple.this[int index]
+        {
+            get
+            {
+                switch (index)
+                {
+                    case 0:
+                        return Item1;
+                    case 1:
+                        return Item2;
+                    case 2:
+                        return Item3;
+                    case 3:
+                        return Item4;
+                    case 4:
+                        return Item5;
+                    case 5:
+                        return Item6;
+                    case 6:
+                        return Item7;
+                }
+
+                if (Rest is IValueTupleInternal)
+                {
+                    return ((IValueTupleInternal)Rest)[index - 7];
+                }
+
+
+                if (index == 7)
+                {
+                    return Rest;
+                }
+
+                throw new IndexOutOfRangeException();
+            }
+        }
+    }
+}

+ 16 - 0
src/System.Runtime.Extensions/System.Runtime.Extensions.csproj

@@ -0,0 +1,16 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
+    <OutputPath>$(SolutionDir)out/bin/</OutputPath>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>$(SolutionDir)tools/Open.snk</AssemblyOriginatorKeyFile>
+    <AssemblyVersion>4.2.1.0</AssemblyVersion>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\System.Private.CorLib\System.Private.CorLib.csproj" />
+  </ItemGroup>
+
+</Project>

+ 5 - 0
src/System.Runtime.Extensions/TypeForwards.cs

@@ -0,0 +1,5 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: TypeForwardedTo(typeof(Math))]

+ 25 - 0
src/System.Runtime/TypeForwards.cs

@@ -33,3 +33,28 @@ using System.Text;
 [assembly: TypeForwardedTo(typeof(Action<>))]
 [assembly: TypeForwardedTo(typeof(Action<,>))]
 [assembly: TypeForwardedTo(typeof(Action<,,>))]
+[assembly: TypeForwardedTo(typeof(Action<,,,>))]
+[assembly: TypeForwardedTo(typeof(Action<,,,,>))]
+[assembly: TypeForwardedTo(typeof(Action<,,,,,>))]
+[assembly: TypeForwardedTo(typeof(Action<,,,,,,>))]
+[assembly: TypeForwardedTo(typeof(Action<,,,,,,,>))]
+[assembly: TypeForwardedTo(typeof(Func<>))]
+[assembly: TypeForwardedTo(typeof(Func<,>))]
+[assembly: TypeForwardedTo(typeof(Func<,,>))]
+[assembly: TypeForwardedTo(typeof(Func<,,,>))]
+[assembly: TypeForwardedTo(typeof(Func<,,,,>))]
+[assembly: TypeForwardedTo(typeof(Func<,,,,,>))]
+[assembly: TypeForwardedTo(typeof(Func<,,,,,,>))]
+[assembly: TypeForwardedTo(typeof(Func<,,,,,,,>))]
+[assembly: TypeForwardedTo(typeof(Func<,,,,,,,,>))]
+[assembly: TypeForwardedTo(typeof(ValueTuple))]
+[assembly: TypeForwardedTo(typeof(ValueTuple<>))]
+[assembly: TypeForwardedTo(typeof(ValueTuple<,>))]
+[assembly: TypeForwardedTo(typeof(ValueTuple<,,>))]
+[assembly: TypeForwardedTo(typeof(ValueTuple<,,,>))]
+[assembly: TypeForwardedTo(typeof(ValueTuple<,,,,>))]
+[assembly: TypeForwardedTo(typeof(ValueTuple<,,,,,>))]
+[assembly: TypeForwardedTo(typeof(ValueTuple<,,,,,,>))]
+[assembly: TypeForwardedTo(typeof(ValueTuple<,,,,,,,>))]
+[assembly: TypeForwardedTo(typeof(Span<>))]
+[assembly: TypeForwardedTo(typeof(ReadOnlySpan<>))]