private static TypeWithModifiers SubstituteAllTypeParameters(AbstractTypeMap substitution, TypeWithModifiers type) { if (substitution != null) { TypeWithModifiers previous; do { previous = type; type = type.SubstituteType(substitution); } while (type != previous); } return type; }
private static TypeWithModifiers SubstituteAllTypeParameters(AbstractTypeMap substitution, TypeWithModifiers type) { if (substitution != null) { TypeWithModifiers previous; do { previous = type; type = type.SubstituteType(substitution); } while (type != previous); } return(type); }
/// <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(TypeWithModifiers t1, TypeWithModifiers t2, ref MutableTypeMap substitution) { 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); } 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); } 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); } 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)) { 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); } 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; } 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 (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; } } }
private ArrayTypeSymbol SubstituteArrayType(ArrayTypeSymbol t) { var oldElement = new TypeWithModifiers(t.ElementType, t.CustomModifiers); TypeWithModifiers element = oldElement.SubstituteType(this); if (element == oldElement) { return t; } if (t.IsSZArray) { ImmutableArray<NamedTypeSymbol> interfaces = t.Interfaces; //.InterfacesNoUseSiteDiagnostics(); Debug.Assert(0 <= interfaces.Length && interfaces.Length <= 2); if (interfaces.Length == 1) { Debug.Assert(interfaces[0] is NamedTypeSymbol); // IList<T> interfaces = ImmutableArray.Create<NamedTypeSymbol>((NamedTypeSymbol)SubstituteType(interfaces[0]).AsTypeSymbolOnly()); } else if (interfaces.Length == 2) { Debug.Assert(interfaces[0] is NamedTypeSymbol); // IList<T> interfaces = ImmutableArray.Create<NamedTypeSymbol>((NamedTypeSymbol)SubstituteType(interfaces[0]).AsTypeSymbolOnly(), (NamedTypeSymbol)SubstituteType(interfaces[1]).AsTypeSymbolOnly()); } else if (interfaces.Length != 0) { throw ExceptionUtilities.Unreachable; } return ArrayTypeSymbol.CreateSZArray( element.Type, t.BaseType, //.BaseTypeNoUseSiteDiagnostics, interfaces, element.CustomModifiers); } return ArrayTypeSymbol.CreateMDArray( element.Type, t.Rank, t.Sizes, t.LowerBounds, t.BaseType, //.BaseTypeNoUseSiteDiagnostics, element.CustomModifiers); }
/// <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); } } }
private PointerTypeSymbol SubstitutePointerType(PointerTypeSymbol t) { var oldPointedAtType = new TypeWithModifiers(t.PointedAtType, t.CustomModifiers); TypeWithModifiers pointedAtType = oldPointedAtType.SubstituteType(this); if (pointedAtType == oldPointedAtType) { return t; } return new PointerTypeSymbol(pointedAtType.Type, pointedAtType.CustomModifiers); }
private TypeSymbol SubstituteNonNullableType(NonNullableReferenceTypeSymbol t) { var oldUnderlyingType = new TypeWithModifiers(t.UnderlyingType); TypeWithModifiers underlyingType = oldUnderlyingType.SubstituteType(this); if (underlyingType == oldUnderlyingType) { return t; } if (underlyingType.Type.IsValueType) return underlyingType.Type; return underlyingType.Type as NonNullableReferenceTypeSymbol ?? NonNullableReferenceTypeSymbol.CreateNonNullableReference(underlyingType.Type); }