private static bool ReturnTypesMatch(MethodSymbol candidateMethod, TypeMap candidateMethodTypeMap, ref ParamInfo <TypeSymbol> targetReturnParam) { Debug.Assert(candidateMethodTypeMap != null); if (candidateMethod.ReturnsByRef != targetReturnParam.IsByRef) { return(false); } TypeSymbolWithAnnotations candidateMethodType = candidateMethod.ReturnType; TypeSymbol targetReturnType = targetReturnParam.Type; // CONSIDER: Do we want to add special handling for error types? Right now, we expect they'll just fail to match. var substituted = candidateMethodType.SubstituteType(candidateMethodTypeMap); if (!TypeSymbol.Equals(substituted.TypeSymbol, targetReturnType, TypeCompareKind.ConsiderEverything2)) { return(false); } if (!CustomModifiersMatch(substituted.CustomModifiers, targetReturnParam.CustomModifiers) || !CustomModifiersMatch(candidateMethodTypeMap.SubstituteCustomModifiers(candidateMethod.RefCustomModifiers), targetReturnParam.RefCustomModifiers)) { return(false); } return(true); }
private static TypeSymbolWithAnnotations SubstituteAllTypeParameters(AbstractTypeMap substitution, TypeSymbolWithAnnotations type) { if (substitution != null) { TypeSymbolWithAnnotations previous; do { previous = type; type = type.SubstituteType(substitution); } while (!type.IsSameAs(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(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); } } }
private static TypeSymbolWithAnnotations SubstituteType(TypeMap typeMap, TypeSymbolWithAnnotations typeSymbol) { return(typeMap == null ? typeSymbol : typeSymbol.SubstituteType(typeMap)); }
internal TypeSymbolWithAnnotations SubstituteType(TypeSymbolWithAnnotations previous) { return(previous.SubstituteType(this)); }