Ejemplo n.º 1
0
        public static IGenericContext CreateCustomMap(IMethod methodDefinition, IMethod methodSpecialization, IMethod additionalMethodDefinition = null)
        {
            var context = new MetadataGenericContext();
            var customTypeSubstitution = new MutableTypeMap();

            var methodSpecAdapter = methodSpecialization as MetadataMethodAdapter;

            if (methodSpecAdapter != null)
            {
                var methodSymbolSpec = methodSpecAdapter.MethodDef;
                AppendMapping(customTypeSubstitution, methodSymbolSpec);
            }

            var methodDefAdapter = methodDefinition as MetadataMethodAdapter;

            if (methodDefAdapter != null)
            {
                var methodSymbolDef = methodDefAdapter.MethodDef;
                AppendMapping(customTypeSubstitution, methodSymbolDef, true);
            }

            if (additionalMethodDefinition != null)
            {
                var metadataMethodAdapter = additionalMethodDefinition as MetadataMethodAdapter;
                if (metadataMethodAdapter != null && methodSpecAdapter != null)
                {
                    var additionalMethodSymbolDef = metadataMethodAdapter.MethodDef;
                    AppendMethodDirectMapping(customTypeSubstitution, methodSpecAdapter.MethodDef, additionalMethodSymbolDef);
                }
            }

            context.CustomTypeSubstitution = customTypeSubstitution;
            return(context);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        public static bool CanUnify(TypeSymbol t1, TypeSymbol t2)
        {
            MutableTypeMap substitution = null;
            bool           result       = CanUnifyHelper(t1, t2, ref substitution);

            Debug.Assert(!result || (substitution == null && t1 == t2) ||
                         substitution.SubstituteType(t1) == substitution.SubstituteType(t2));
            return(result);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        public static bool CanUnify(TypeSymbol t1, TypeSymbol t2)
        {
            MutableTypeMap substitution = null;
            bool           result       = CanUnifyHelper(t1, t2, ref substitution);

#if DEBUG
            Debug.Assert(!result ||
                         SubstituteAllTypeParameters(substitution, t1) == SubstituteAllTypeParameters(substitution, t2));
#endif
            return(result);
        }
Ejemplo n.º 4
0
        private static void AddSubstitution(ref MutableTypeMap?substitution, TypeParameterSymbol tp1, TypeWithAnnotations t2)
        {
            if (substitution == null)
            {
                substitution = new MutableTypeMap();
            }

            // MutableTypeMap.Add will throw if the key has already been added.  However,
            // if t1 was already in the substitution, it would have been substituted at the
            // start of CanUnifyHelper and we wouldn't be here.
            substitution.Add(tp1, t2);
        }
Ejemplo n.º 5
0
 private static void AppendMethodDirectMapping(MutableTypeMap customTypeSubstitution, MethodSymbol methodSymbolSpec, MethodSymbol methodSymbolDef)
 {
     for (var i = 0; i < methodSymbolSpec.TypeParameters.Length; i++)
     {
         var typeParameterSymbol = methodSymbolDef.TypeParameters[i];
         var typeArgument        = methodSymbolSpec.TypeArguments[i];
         if (!ReferenceEquals(typeParameterSymbol, typeArgument))
         {
             customTypeSubstitution.Add(typeParameterSymbol, typeArgument);
         }
     }
 }
Ejemplo n.º 6
0
        private static void AddSubstitution(ref MutableTypeMap substitution, TypeParameterSymbol tp1, TypeWithModifiers t2)
        {
            if (substitution == null)
            {
                substitution = new MutableTypeMap();
            }

            // MutableTypeMap.Add will throw if the key has already been added.  However,
            // if t1 was already in the substitution, it would have been substituted at the
            // start of CanUnifyHelper and we wouldn't be here.

            // @MattWindsor91 (Concept-C# 2017)
            // use AddAndPropagate here to avoid denormalised typemaps.
            substitution.AddAndPropagate(tp1, t2);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Tries to produce a substitution of type parameters that will make
        /// two types identical.
        /// </summary>
        public static bool CanUnify(TypeSymbol t1, TypeSymbol t2, ref MutableTypeMap substitution, ImmutableHashSet <TypeParameterSymbol> untouchables)
        {
            if (t1 == t2)
            {
                return(true);
            }

            bool result = CanUnifyHelper((object)t1 == null ? default(TypeWithModifiers) : new TypeWithModifiers(t1),
                                         (object)t2 == null ? default(TypeWithModifiers) : new TypeWithModifiers(t2),
                                         ref substitution,
                                         untouchables);

#if DEBUG
            Debug.Assert(!result ||
                         SubstituteAllTypeParameters(substitution, new TypeWithModifiers(t1)).Equals(SubstituteAllTypeParameters(substitution, new TypeWithModifiers(t2)), TypeCompareKind.IgnoreTupleNames));
#endif
            return(result);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        public static bool CanUnify(TypeSymbol t1, TypeSymbol t2)
        {
            if (t1 == t2)
            {
                return(true);
            }

            MutableTypeMap substitution = null;
            bool           result       = CanUnifyHelper((object)t1 == null ? default(TypeWithModifiers) : new TypeWithModifiers(t1),
                                                         (object)t2 == null ? default(TypeWithModifiers) : new TypeWithModifiers(t2),
                                                         ref substitution);

#if DEBUG
            Debug.Assert(!result ||
                         SubstituteAllTypeParameters(substitution, new TypeWithModifiers(t1)) == SubstituteAllTypeParameters(substitution, new TypeWithModifiers(t2)));
#endif
            return(result);
        }
Ejemplo n.º 9
0
 private static void AppendMapping(MutableTypeMap customTypeSubstitution, NamedTypeSymbol namedTypeSymbol, bool invert = false)
 {
     for (var i = 0; i < namedTypeSymbol.TypeParameters.Length; i++)
     {
         var typeParameterSymbol = namedTypeSymbol.TypeParameters[i];
         var typeArgument        = namedTypeSymbol.TypeArguments[i];
         if (!ReferenceEquals(typeParameterSymbol, typeArgument))
         {
             if (invert)
             {
                 Debug.Assert(typeArgument is TypeParameterSymbol, "TypeParameterSymbol is required");
                 customTypeSubstitution.Add(typeArgument as TypeParameterSymbol, customTypeSubstitution.SubstituteType(typeParameterSymbol));
             }
             else
             {
                 customTypeSubstitution.Add(typeParameterSymbol, typeArgument);
             }
         }
     }
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        public static bool CanUnify(TypeSymbol t1, TypeSymbol t2)
        {
            if (TypeSymbol.Equals(t1, t2, TypeCompareKind.ConsiderEverything2))
            {
                return(true);
            }

            MutableTypeMap substitution = null;
            bool           result       = CanUnifyHelper(t1, t2, ref substitution);

#if DEBUG
            if (result && ((object)t1 != null && (object)t2 != null))
            {
                var substituted1 = SubstituteAllTypeParameters(substitution, TypeSymbolWithAnnotations.Create(t1));
                var substituted2 = SubstituteAllTypeParameters(substitution, TypeSymbolWithAnnotations.Create(t2));

                Debug.Assert(substituted1.TypeSymbol.Equals(substituted2.TypeSymbol, TypeCompareKind.IgnoreTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes));
                Debug.Assert(substituted1.CustomModifiers.SequenceEqual(substituted2.CustomModifiers));
            }
#endif
            return(result);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        /// <param name="t1">LHS</param>
        /// <param name="t2">RHS</param>
        /// <param name="substitution">
        /// Substitutions performed so far (or null for none).
        /// Keys are type parameters, values are types (possibly type parameters).
        /// Will be updated with new substitutions by the callee.
        /// Should be ignored when false is returned.
        /// </param>
        /// <returns>True if there exists a type map such that Map(LHS) == Map(RHS).</returns>
        /// <remarks>
        /// Derived from Dev10's BSYMMGR::UnifyTypes.
        /// Two types will not unify if they have different custom modifiers.
        /// </remarks>
        private static bool CanUnifyHelper(TypeSymbolWithAnnotations t1, TypeSymbolWithAnnotations t2, ref MutableTypeMap substitution)
        {
            if (t1.IsNull || t2.IsNull)
            {
                return(t1.IsSameAs(t2));
            }

            if (TypeSymbol.Equals(t1.TypeSymbol, t2.TypeSymbol, TypeCompareKind.ConsiderEverything2) && t1.CustomModifiers.SequenceEqual(t2.CustomModifiers))
            {
                return(true);
            }

            if (substitution != null)
            {
                t1 = t1.SubstituteType(substitution);
                t2 = t2.SubstituteType(substitution);
            }

            // If one of the types is a type parameter, then the substitution could make them equal.
            if (TypeSymbol.Equals(t1.TypeSymbol, t2.TypeSymbol, TypeCompareKind.ConsiderEverything2) && t1.CustomModifiers.SequenceEqual(t2.CustomModifiers))
            {
                return(true);
            }

            // We can avoid a lot of redundant checks if we ensure that we only have to check
            // for type parameters on the LHS
            if (!t1.TypeSymbol.IsTypeParameter() && t2.TypeSymbol.IsTypeParameter())
            {
                TypeSymbolWithAnnotations tmp = t1;
                t1 = t2;
                t2 = tmp;
            }

            // If t1 is not a type parameter, then neither is t2
            Debug.Assert(t1.TypeSymbol.IsTypeParameter() || !t2.TypeSymbol.IsTypeParameter());

            switch (t1.Kind)
            {
            case SymbolKind.ArrayType:
            {
                if (t2.TypeKind != t1.TypeKind || !t2.CustomModifiers.SequenceEqual(t1.CustomModifiers))
                {
                    return(false);
                }

                ArrayTypeSymbol at1 = (ArrayTypeSymbol)t1.TypeSymbol;
                ArrayTypeSymbol at2 = (ArrayTypeSymbol)t2.TypeSymbol;

                return(CanUnifyHelper(at1.ElementType, at2.ElementType, ref substitution));
            }

            case SymbolKind.PointerType:
            {
                if (t2.TypeKind != t1.TypeKind || !t2.CustomModifiers.SequenceEqual(t1.CustomModifiers))
                {
                    return(false);
                }

                PointerTypeSymbol pt1 = (PointerTypeSymbol)t1.TypeSymbol;
                PointerTypeSymbol pt2 = (PointerTypeSymbol)t2.TypeSymbol;

                return(CanUnifyHelper(pt1.PointedAtType, pt2.PointedAtType, ref substitution));
            }

            case SymbolKind.NamedType:
            case SymbolKind.ErrorType:
            {
                if (t2.TypeKind != t1.TypeKind || !t2.CustomModifiers.SequenceEqual(t1.CustomModifiers))
                {
                    return(false);
                }

                NamedTypeSymbol nt1 = (NamedTypeSymbol)t1.TypeSymbol;
                NamedTypeSymbol nt2 = (NamedTypeSymbol)t2.TypeSymbol;

                if (nt1.IsTupleType)
                {
                    if (!nt2.IsTupleType)
                    {
                        return(false);
                    }

                    return(CanUnifyHelper(nt1.TupleUnderlyingType, nt2.TupleUnderlyingType, ref substitution));
                }

                if (!nt1.IsGenericType)
                {
                    return(!nt2.IsGenericType && TypeSymbol.Equals(nt1, nt2, TypeCompareKind.ConsiderEverything2));
                }
                else if (!nt2.IsGenericType)
                {
                    return(false);
                }

                int arity = nt1.Arity;

                if (nt2.Arity != arity || !TypeSymbol.Equals(nt2.OriginalDefinition, nt1.OriginalDefinition, TypeCompareKind.ConsiderEverything2))
                {
                    return(false);
                }

                var nt1Arguments = nt1.TypeArgumentsNoUseSiteDiagnostics;
                var nt2Arguments = nt2.TypeArgumentsNoUseSiteDiagnostics;

                for (int i = 0; i < arity; i++)
                {
                    if (!CanUnifyHelper(nt1Arguments[i],
                                        nt2Arguments[i],
                                        ref substitution))
                    {
                        return(false);
                    }
                }

                // Note: Dev10 folds this into the loop since GetTypeArgsAll includes type args for containing types
                // TODO: Calling CanUnifyHelper for the containing type is an overkill, we simply need to go through type arguments for all containers.
                return((object)nt1.ContainingType == null || CanUnifyHelper(nt1.ContainingType, nt2.ContainingType, ref substitution));
            }

            case SymbolKind.TypeParameter:
            {
                // These substitutions are not allowed in C#
                if (t2.TypeKind == TypeKind.Pointer || t2.SpecialType == SpecialType.System_Void)
                {
                    return(false);
                }

                TypeParameterSymbol tp1 = (TypeParameterSymbol)t1.TypeSymbol;

                // Perform the "occurs check" - i.e. ensure that t2 doesn't contain t1 to avoid recursive types
                // Note: t2 can't be the same type param - we would have caught that with ReferenceEquals above
                if (Contains(t2.TypeSymbol, tp1))
                {
                    return(false);
                }

                if (t1.CustomModifiers.IsDefaultOrEmpty)
                {
                    AddSubstitution(ref substitution, tp1, t2);
                    return(true);
                }

                if (t1.CustomModifiers.SequenceEqual(t2.CustomModifiers))
                {
                    AddSubstitution(ref substitution, tp1, TypeSymbolWithAnnotations.Create(t2.TypeSymbol));
                    return(true);
                }

                if (t1.CustomModifiers.Length < t2.CustomModifiers.Length &&
                    t1.CustomModifiers.SequenceEqual(t2.CustomModifiers.Take(t1.CustomModifiers.Length)))
                {
                    AddSubstitution(ref substitution, tp1,
                                    TypeSymbolWithAnnotations.Create(t2.TypeSymbol,
                                                                     customModifiers: ImmutableArray.Create(t2.CustomModifiers, t1.CustomModifiers.Length, t2.CustomModifiers.Length - t1.CustomModifiers.Length)));
                    return(true);
                }

                if (t2.TypeSymbol.IsTypeParameter())
                {
                    var tp2 = (TypeParameterSymbol)t2.TypeSymbol;

                    if (t2.CustomModifiers.IsDefaultOrEmpty)
                    {
                        AddSubstitution(ref substitution, tp2, t1);
                        return(true);
                    }

                    if (t2.CustomModifiers.Length < t1.CustomModifiers.Length &&
                        t2.CustomModifiers.SequenceEqual(t1.CustomModifiers.Take(t2.CustomModifiers.Length)))
                    {
                        AddSubstitution(ref substitution, tp2,
                                        TypeSymbolWithAnnotations.Create(t1.TypeSymbol,
                                                                         customModifiers: ImmutableArray.Create(t1.CustomModifiers, t2.CustomModifiers.Length, t1.CustomModifiers.Length - t2.CustomModifiers.Length)));
                        return(true);
                    }
                }

                return(false);
            }

            default:
            {
                return(false);
            }
            }
        }
Ejemplo n.º 12
0
 private static bool CanUnifyHelper(TypeSymbol t1, TypeSymbol t2, ref MutableTypeMap substitution)
 {
     return(CanUnifyHelper(TypeSymbolWithAnnotations.Create(t1), TypeSymbolWithAnnotations.Create(t2), ref substitution));
 }
Ejemplo n.º 13
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        /// <param name="t1">LHS</param>
        /// <param name="t2">RHS</param>
        /// <param name="substitution">
        /// Substitutions performed so far (or null for none).
        /// Keys are type parameters, values are types (possibly type parameters).
        /// Will be updated with new subsitutions by the callee.
        /// Should be ignored when false is returned.
        /// </param>
        /// <returns>True if there exists a type map such that Map(LHS) == Map(RHS).</returns>
        /// <remarks>
        /// Derived from Dev10's BSYMMGR::UnifyTypes.
        /// Two types will not unify if they have different custom modifiers.
        /// </remarks>
        private static bool CanUnifyHelper(TypeSymbol t1, TypeSymbol t2, ref MutableTypeMap substitution)
        {
            if (ReferenceEquals(t1, t2))
            {
                return(true);
            }
            else if ((object)t1 == null || (object)t2 == null)
            {
                // Can't both be null or they would have been ReferenceEquals
                return(false);
            }

            if (substitution != null)
            {
                t1 = substitution.SubstituteType(t1);
                t2 = substitution.SubstituteType(t2);
            }

            // If one of the types is a type parameter, then the substitution could make them ReferenceEquals.
            if (ReferenceEquals(t1, t2))
            {
                return(true);
            }

            // We can avoid a lot of redundant checks if we ensure that we only have to check
            // for type parameters on the LHS
            if (!t1.IsTypeParameter() && t2.IsTypeParameter())
            {
                TypeSymbol tmp = t1;
                t1 = t2;
                t2 = tmp;
            }

            // If t1 is not a type parameter, then neither is t2
            Debug.Assert(t1.IsTypeParameter() || !t2.IsTypeParameter());

            switch (t1.Kind)
            {
            case SymbolKind.ArrayType:
            {
                if (t2.TypeKind != t1.TypeKind)
                {
                    return(false);
                }

                ArrayTypeSymbol at1 = (ArrayTypeSymbol)t1;
                ArrayTypeSymbol at2 = (ArrayTypeSymbol)t2;

                if (at1.Rank != at2.Rank || !at1.CustomModifiers.SequenceEqual(at2.CustomModifiers))
                {
                    return(false);
                }

                return(CanUnifyHelper(at1.ElementType, at2.ElementType, ref substitution));
            }

            case SymbolKind.PointerType:
            {
                if (t2.TypeKind != t1.TypeKind)
                {
                    return(false);
                }

                PointerTypeSymbol pt1 = (PointerTypeSymbol)t1;
                PointerTypeSymbol pt2 = (PointerTypeSymbol)t2;

                if (!pt1.CustomModifiers.SequenceEqual(pt2.CustomModifiers))
                {
                    return(false);
                }

                return(CanUnifyHelper(pt1.PointedAtType, pt2.PointedAtType, ref substitution));
            }

            case SymbolKind.NamedType:
            case SymbolKind.ErrorType:
            {
                if (t2.TypeKind != t1.TypeKind)
                {
                    return(false);
                }

                NamedTypeSymbol nt1 = (NamedTypeSymbol)t1;
                NamedTypeSymbol nt2 = (NamedTypeSymbol)t2;

                if (!nt1.IsGenericType)
                {
                    return(!nt2.IsGenericType && nt1 == nt2);
                }
                else if (!nt2.IsGenericType)
                {
                    return(false);
                }

                int arity = nt1.Arity;

                if (nt2.Arity != arity || nt2.OriginalDefinition != nt1.OriginalDefinition)
                {
                    return(false);
                }

                for (int i = 0; i < arity; i++)
                {
                    if (!CanUnifyHelper(nt1.TypeArgumentsNoUseSiteDiagnostics[i], nt2.TypeArgumentsNoUseSiteDiagnostics[i], ref substitution))
                    {
                        return(false);
                    }
                }

                // Note: Dev10 folds this into the loop since GetTypeArgsAll includes type args for containing types
                return((object)nt1.ContainingType == null || CanUnifyHelper(nt1.ContainingType, nt2.ContainingType, ref substitution));
            }

            case SymbolKind.TypeParameter:
            {
                // These substitutions are not allowed in C#
                if (t2.TypeKind == TypeKind.Pointer || t2.SpecialType == SpecialType.System_Void)
                {
                    return(false);
                }

                TypeParameterSymbol tp1 = (TypeParameterSymbol)t1;

                // Perform the "occurs check" - i.e. ensure that t2 doesn't contain t1 to avoid recursive types
                // Note: t2 can't be the same type param - we would have caught that with ReferenceEquals above
                if (Contains(t2, tp1))
                {
                    return(false);
                }

                if (substitution == null)
                {
                    substitution = new MutableTypeMap();
                }

                // MutableTypeMap.Add will throw if the key has already been added.  However,
                // if t1 was already in the substitution, it would have been substituted at the
                // start of this method and we wouldn't be here.
                substitution.Add(tp1, t2);

                return(true);
            }

            default:
            {
                return(t1 == t2);
            }
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        /// <param name="t1">LHS</param>
        /// <param name="t2">RHS</param>
        /// <param name="substitution">
        /// Substitutions performed so far (or null for none).
        /// Keys are type parameters, values are types (possibly type parameters).
        /// Will be updated with new substitutions by the callee.
        /// Should be ignored when false is returned.
        /// </param>
        /// <param name="untouchables">
        /// Set of type symbols that cannot be replaced by substitution.
        /// </param>
        /// <returns>True if there exists a type map such that Map(LHS) == Map(RHS).</returns>
        /// <remarks>
        /// Derived from Dev10's BSYMMGR::UnifyTypes.
        /// Two types will not unify if they have different custom modifiers.
        /// </remarks>
        private static bool CanUnifyHelper(TypeWithModifiers t1, TypeWithModifiers t2, ref MutableTypeMap substitution, ImmutableHashSet <TypeParameterSymbol> untouchables)
        {
            if (t1 == t2)
            {
                return(true);
            }
            else if ((object)t1.Type == null || (object)t2.Type == null)
            {
                // Can't both be null or they would have been equal
                return(false);
            }

            if (substitution != null)
            {
                t1 = t1.SubstituteType(substitution);
                t2 = t2.SubstituteType(substitution);
            }

            // If one of the types is a type parameter, then the substitution could make them equal.
            if (t1 == t2)
            {
                return(true);
            }

            // We can avoid a lot of redundant checks if we ensure that we only have to check
            // for type parameters on the LHS
            if (!t1.Type.IsTypeParameter() && t2.Type.IsTypeParameter())
            {
                TypeWithModifiers tmp = t1;
                t1 = t2;
                t2 = tmp;
            }

            // If t1 is not a type parameter, then neither is t2
            Debug.Assert(t1.Type.IsTypeParameter() || !t2.Type.IsTypeParameter());

            switch (t1.Type.Kind)
            {
            case SymbolKind.ArrayType:
            {
                if (t2.Type.TypeKind != t1.Type.TypeKind || !t2.CustomModifiers.SequenceEqual(t1.CustomModifiers))
                {
                    return(false);
                }

                ArrayTypeSymbol at1 = (ArrayTypeSymbol)t1.Type;
                ArrayTypeSymbol at2 = (ArrayTypeSymbol)t2.Type;

                if (!at1.HasSameShapeAs(at2))
                {
                    return(false);
                }

                return(CanUnifyHelper(new TypeWithModifiers(at1.ElementType, at1.CustomModifiers), new TypeWithModifiers(at2.ElementType, at2.CustomModifiers), ref substitution, untouchables));
            }

            case SymbolKind.PointerType:
            {
                if (t2.Type.TypeKind != t1.Type.TypeKind || !t2.CustomModifiers.SequenceEqual(t1.CustomModifiers))
                {
                    return(false);
                }

                PointerTypeSymbol pt1 = (PointerTypeSymbol)t1.Type;
                PointerTypeSymbol pt2 = (PointerTypeSymbol)t2.Type;

                return(CanUnifyHelper(new TypeWithModifiers(pt1.PointedAtType, pt1.CustomModifiers), new TypeWithModifiers(pt2.PointedAtType, pt2.CustomModifiers), ref substitution, untouchables));
            }

            case SymbolKind.NamedType:
            case SymbolKind.ErrorType:
            {
                if (t2.Type.TypeKind != t1.Type.TypeKind || !t2.CustomModifiers.SequenceEqual(t1.CustomModifiers))
                {
                    return(false);
                }

                NamedTypeSymbol nt1 = (NamedTypeSymbol)t1.Type;
                NamedTypeSymbol nt2 = (NamedTypeSymbol)t2.Type;

                if (nt1.IsTupleType)
                {
                    if (!nt2.IsTupleType)
                    {
                        return(false);
                    }

                    return(CanUnifyHelper(new TypeWithModifiers(nt1.TupleUnderlyingType), new TypeWithModifiers(nt2.TupleUnderlyingType), ref substitution, untouchables));
                }

                if (!nt1.IsGenericType)
                {
                    return(!nt2.IsGenericType && nt1 == nt2);
                }
                else if (!nt2.IsGenericType)
                {
                    return(false);
                }

                int arity = nt1.Arity;

                if (nt2.Arity != arity || nt2.OriginalDefinition != nt1.OriginalDefinition)
                {
                    return(false);
                }

                var nt1Arguments = nt1.TypeArgumentsNoUseSiteDiagnostics;
                var nt2Arguments = nt2.TypeArgumentsNoUseSiteDiagnostics;

                var nt1HasModifiers = nt1.HasTypeArgumentsCustomModifiers;
                var nt2HasModifiers = nt2.HasTypeArgumentsCustomModifiers;

                for (int i = 0; i < arity; i++)
                {
                    if (!CanUnifyHelper(new TypeWithModifiers(nt1Arguments[i], nt1HasModifiers ? nt1.GetTypeArgumentCustomModifiers(i) : default(ImmutableArray <CustomModifier>)),
                                        new TypeWithModifiers(nt2Arguments[i], nt2HasModifiers ? nt2.GetTypeArgumentCustomModifiers(i) : default(ImmutableArray <CustomModifier>)),
                                        ref substitution,
                                        untouchables))
                    {
                        return(false);
                    }
                }

                // Note: Dev10 folds this into the loop since GetTypeArgsAll includes type args for containing types
                // TODO: Calling CanUnifyHelper for the containing type is an overkill, we simply need to go through type arguments for all containers.
                return((object)nt1.ContainingType == null || CanUnifyHelper(new TypeWithModifiers(nt1.ContainingType), new TypeWithModifiers(nt2.ContainingType), ref substitution, untouchables));
            }

            case SymbolKind.TypeParameter:
            {
                // These substitutions are not allowed in C#
                if (t2.Type.TypeKind == TypeKind.Pointer || t2.Type.SpecialType == SpecialType.System_Void)
                {
                    return(false);
                }

                TypeParameterSymbol tp1 = (TypeParameterSymbol)t1.Type;

                // Perform the "occurs check" - i.e. ensure that t2 doesn't contain t1 to avoid recursive types
                // Note: t2 can't be the same type param - we would have caught that with ReferenceEquals above
                if (Contains(t2.Type, tp1))
                {
                    return(false);
                }

                // @MattWindsor91 (Concept-C# 2017)
                // Quickfix to make sure that, when there are two TPs
                // to be unified, and both are associated, we
                //var isAssocFlowingInwards =
                //    t2.Type.IsTypeParameter()
                //    && ((TypeParameterSymbol)t2.Type).IsAssociatedType
                //    && tp1.IsAssociatedType;

                if (!untouchables.Contains(tp1))        // && !isAssocFlowingInwards)
                {
                    if (t1.CustomModifiers.IsDefaultOrEmpty)
                    {
                        AddSubstitution(ref substitution, tp1, t2);
                        return(true);
                    }

                    if (t1.CustomModifiers.SequenceEqual(t2.CustomModifiers))
                    {
                        AddSubstitution(ref substitution, tp1, new TypeWithModifiers(t2.Type));
                        return(true);
                    }

                    if (t1.CustomModifiers.Length < t2.CustomModifiers.Length &&
                        t1.CustomModifiers.SequenceEqual(t2.CustomModifiers.Take(t1.CustomModifiers.Length)))
                    {
                        AddSubstitution(ref substitution, tp1,
                                        new TypeWithModifiers(t2.Type,
                                                              ImmutableArray.Create(t2.CustomModifiers, t1.CustomModifiers.Length, t2.CustomModifiers.Length - t1.CustomModifiers.Length)));
                        return(true);
                    }
                }

                if (t2.Type.IsTypeParameter())
                {
                    var tp2 = (TypeParameterSymbol)t2.Type;

                    if (!untouchables.Contains(tp2))
                    {
                        if (t2.CustomModifiers.IsDefaultOrEmpty)
                        {
                            AddSubstitution(ref substitution, tp2, t1);
                            return(true);
                        }

                        if (t2.CustomModifiers.Length < t1.CustomModifiers.Length &&
                            t2.CustomModifiers.SequenceEqual(t1.CustomModifiers.Take(t2.CustomModifiers.Length)))
                        {
                            AddSubstitution(ref substitution, tp2,
                                            new TypeWithModifiers(t1.Type,
                                                                  ImmutableArray.Create(t1.CustomModifiers, t2.CustomModifiers.Length, t1.CustomModifiers.Length - t2.CustomModifiers.Length)));
                            return(true);
                        }
                    }
                }

                return(false);
            }

            default:
            {
                return(t1 == t2);
            }
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        public static bool CanUnify(TypeSymbol t1, TypeSymbol t2)
        {
            MutableTypeMap substitution = null;

            return(CanUnify(t1, t2, ref substitution, ImmutableHashSet <TypeParameterSymbol> .Empty));
        }