void UnpackNestedType(StringBuilder builder, IReturnType returnType) { if (returnType.IsArrayReturnType) { ArrayReturnType art = returnType.CastToArrayReturnType(); builder.Append('('); UnpackNestedType(builder, art.ArrayElementType); if (art.ArrayDimensions > 1) { builder.Append(','); builder.Append(art.ArrayDimensions); } builder.Append(')'); } else if (returnType.IsConstructedReturnType) { ConstructedReturnType crt = returnType.CastToConstructedReturnType(); UnpackNestedType(builder, crt.UnboundType); builder.Append("[of "); for (int i = 0; i < crt.TypeArguments.Count; ++i) { if (i > 0) { builder.Append(", "); } builder.Append(Convert(crt.TypeArguments[i])); } builder.Append(']'); } else { string fullName = returnType.FullyQualifiedName; if (fullName != null && typeConversionTable.ContainsKey(fullName)) { builder.Append(typeConversionTable[fullName].ToString()); } else { if (UseFullyQualifiedTypeNames) { builder.Append(fullName); } else { builder.Append(returnType.Name); } } } }
public override bool Equals(object o) { IReturnType rt = o as IReturnType; if (rt == null || !rt.IsArrayReturnType) { return(false); } ArrayReturnType art = rt.CastToArrayReturnType(); if (art.ArrayDimensions != dimensions) { return(false); } return(elementType.Equals(art.ArrayElementType)); }
public virtual ArrayReturnType CastToArrayReturnType() { IReturnType baseType = BaseType; ArrayReturnType temp; if (baseType != null && TryEnter()) { temp = baseType.CastToArrayReturnType(); } else { throw new InvalidCastException("Cannot cast " + ToString() + " to expected type."); } _busy = false; return(temp); }
/// <summary> /// Gets whether this type parameter occurs in the specified return type. /// </summary> public bool OccursIn(IReturnType rt) { ArrayReturnType art = rt.CastToArrayReturnType(); if (art != null) { return OccursIn(art.ArrayElementType); } ConstructedReturnType crt = rt.CastToConstructedReturnType(); if (crt != null) { return crt.TypeArguments.Any(ta => OccursIn(ta)); } GenericReturnType grt = rt.CastToGenericReturnType(); if (grt != null) { return this.TypeParameter.Equals(grt.TypeParameter); } return false; }
bool CheckReturnType(IReturnType t) { if (t.IsGenericReturnType) { return t.CastToGenericReturnType().TypeParameter.Method == null; } else if (t.IsArrayReturnType) { return CheckReturnType(t.CastToArrayReturnType().ArrayElementType); } else if (t.IsConstructedReturnType) { foreach (IReturnType para in t.CastToConstructedReturnType().TypeArguments) { if (para != null) { if (CheckReturnType(para)) return true; } } return false; } else { return false; } }
static bool AreTypesDifferent(IReturnType oldType, CodeTypeReference newType) { IClass oldClass = oldType.GetUnderlyingClass(); if (oldClass == null) { // ignore type changes to untyped VB fields return(false); } if (newType.BaseType == "System.Void") { // field types get replaced with System.Void if the type cannot be resolved // (e.g. generic fields in the Boo designer which aren't converted to CodeDom) // we'll ignore such type changes (fields should never have the type void) return(false); } ArrayReturnType oldArray = oldType.IsArrayReturnType ? oldType.CastToArrayReturnType() : null; if (oldArray == null ^ newType.ArrayRank < 1) { return(true); } if (oldArray == null) { if (oldClass.DotNetName != newType.BaseType) { return(true); } } else { if (oldArray.ArrayDimensions != newType.ArrayRank) { return(true); } if (AreTypesDifferent(oldArray.ArrayElementType, newType.ArrayElementType)) { return(true); } } return(false); }
/// <summary> /// Make exact inference from U for V. /// </summary> void MakeExactInference(IReturnType U, IReturnType V) { Log(" MakeExactInference from " + U + " for " + V); if (U == null || V == null) { return; } // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.Fixed == false) { Log(" Add bound '" + U.DotNetName + "' to " + tp); tp.Bounds.Add(U); return; } // Otherwise if U is an array type Ue[…] and V is an array type Ve[…] of the same rank // then an exact inference from Ue to Ve is made ArrayReturnType arrU = U.CastToArrayReturnType(); ArrayReturnType arrV = V.CastToArrayReturnType(); if (arrU != null && arrV != null && arrU.ArrayDimensions == arrV.ArrayDimensions) { MakeExactInference(arrU.ArrayElementType, arrV.ArrayElementType); return; } // Otherwise if V is a constructed type C<V1…Vk> and U is a constructed // type C<U1…Uk> then an exact inference is made from each Ui to the corresponding Vi. ConstructedReturnType CU = U.CastToConstructedReturnType(); ConstructedReturnType CV = V.CastToConstructedReturnType(); if (CU != null && CV != null && object.Equals(CU.UnboundType, CV.UnboundType) && CU.TypeArgumentCount == CV.TypeArgumentCount && CU.TypeArguments.Count == CU.TypeArgumentCount && CV.TypeArguments.Count == CV.TypeArgumentCount) { for (int i = 0; i < CU.TypeArgumentCount; i++) { MakeExactInference(CU.TypeArguments[i], CV.TypeArguments[i]); } return; } }
TypeResolveResult CreateTypeResolveResult(IReturnType resolvedType) { if (resolvedType == null) { return(null); } else { IReturnType rt = resolvedType; while (rt != null && rt.IsArrayReturnType) { rt = rt.CastToArrayReturnType().ArrayElementType; } IClass resolvedClass = rt != null?rt.GetUnderlyingClass() : null; return(new TypeResolveResult(resolver.CallingClass, resolver.CallingMember, resolvedType, resolvedClass)); } }
public static IReturnType TranslateType(IReturnType input, IList <IReturnType> typeParameters, bool convertForMethod) { if (input == null || typeParameters == null || typeParameters.Count == 0) { return(input); // nothing to do when there are no type parameters specified } if (input.IsGenericReturnType) { GenericReturnType rt = input.CastToGenericReturnType(); if (convertForMethod ? (rt.TypeParameter.Method != null) : (rt.TypeParameter.Method == null)) { if (rt.TypeParameter.Index < typeParameters.Count) { IReturnType newType = typeParameters[rt.TypeParameter.Index]; if (newType != null) { return(newType); } } } } else if (input.IsArrayReturnType) { ArrayReturnType arInput = input.CastToArrayReturnType(); IReturnType e = arInput.ArrayElementType; IReturnType t = TranslateType(e, typeParameters, convertForMethod); if (e != t && t != null) { return(new ArrayReturnType(arInput.ProjectContent, t, arInput.ArrayDimensions)); } } else if (input.IsConstructedReturnType) { ConstructedReturnType cinput = input.CastToConstructedReturnType(); List <IReturnType> para = new List <IReturnType>(cinput.TypeArguments.Count); foreach (IReturnType argument in cinput.TypeArguments) { para.Add(TranslateType(argument, typeParameters, convertForMethod)); } return(new ConstructedReturnType(cinput.UnboundType, para)); } return(input); }
/// <summary> /// Gets whether this type parameter occurs in the specified return type. /// </summary> public bool OccursIn(IReturnType rt) { ArrayReturnType art = rt.CastToArrayReturnType(); if (art != null) { return(OccursIn(art.ArrayElementType)); } ConstructedReturnType crt = rt.CastToConstructedReturnType(); if (crt != null) { return(crt.TypeArguments.Any(ta => OccursIn(ta))); } GenericReturnType grt = rt.CastToGenericReturnType(); if (grt != null) { return(this.TypeParameter.Equals(grt.TypeParameter)); } return(false); }
void AddExternalType(IReturnType rt, List <ClassNameTypeCountPair> externalTypes, int classCount) { if (rt.IsDefaultReturnType) { ClassNameTypeCountPair pair = new ClassNameTypeCountPair(rt); if (!classIndices.ContainsKey(pair)) { classIndices.Add(pair, externalTypes.Count + classCount); externalTypes.Add(pair); } } else if (rt.IsGenericReturnType) { // ignore } else if (rt.IsArrayReturnType) { AddExternalType(rt.CastToArrayReturnType().ArrayElementType, externalTypes, classCount); } else if (rt.IsConstructedReturnType) { AddExternalType(rt.CastToConstructedReturnType().UnboundType, externalTypes, classCount); foreach (IReturnType typeArgument in rt.CastToConstructedReturnType().TypeArguments) { AddExternalType(typeArgument, externalTypes, classCount); } } else if (rt.IsDecoratingReturnType <PointerReturnType>()) { AddExternalType(rt.CastToDecoratingReturnType <PointerReturnType>().BaseType, externalTypes, classCount); } else { LoggingService.Warn("Unknown return type: " + rt.ToString()); } }
static bool IsApplicable(IList <IParameter> parameters, IReturnType[] arguments, bool allowAdditionalArguments, out int score, out bool expanded) { // see ECMA-334, § 14.4.2.1 // TODO: recognize ref/out (needs info about passing mode for arguments, you have to introduce RefReturnType) expanded = false; score = 0; if (parameters.Count == 0) { return(arguments.Length == 0); } if (!allowAdditionalArguments && parameters.Count > arguments.Length + 1) { return(false); } int lastParameter = parameters.Count - 1; // check all arguments except the last bool ok = true; for (int i = 0; i < Math.Min(lastParameter, arguments.Length); i++) { if (IsApplicable(arguments[i], parameters[i].ReturnType)) { score++; } else { ok = false; } } if (!ok) { return(false); } if (parameters.Count == arguments.Length) { // try if method is applicable in normal form by checking last argument if (IsApplicable(arguments[lastParameter], parameters[lastParameter].ReturnType)) { return(true); } } // method is not applicable in normal form, try expanded form: // - last parameter must be params array if (!parameters[lastParameter].IsParams) { return(false); } expanded = true; score++; // - all additional parameters must be applicable to the unpacked array IReturnType rt = parameters[lastParameter].ReturnType; if (rt == null || !rt.IsArrayReturnType) { return(false); } for (int i = lastParameter; i < arguments.Length; i++) { if (IsApplicable(arguments[i], rt.CastToArrayReturnType().ArrayElementType)) { score++; } else { ok = false; } } return(ok); }
/// <summary> /// Infers type arguments specified by passing expectedArgument as parameter where passedArgument /// was expected. The resulting type arguments are written to outputArray. /// Returns false when expectedArgument and passedArgument are incompatible, otherwise true /// is returned (true is used both for successful inferring and other kind of errors). /// </summary> /// <remarks> /// The C# spec (§ 25.6.4) has a bug: it says that type inference works if the passedArgument is IEnumerable{T} /// and the expectedArgument is an array; passedArgument and expectedArgument must be swapped here. /// </remarks> public static bool InferTypeArgument(IReturnType expectedArgument, IReturnType passedArgument, IReturnType[] outputArray) { if (expectedArgument == null) { return(true); } if (passedArgument == null || passedArgument == NullReturnType.Instance) { return(true); } if (passedArgument.IsArrayReturnType) { IReturnType passedArrayElementType = passedArgument.CastToArrayReturnType().ArrayElementType; if (expectedArgument.IsArrayReturnType && expectedArgument.CastToArrayReturnType().ArrayDimensions == passedArgument.CastToArrayReturnType().ArrayDimensions) { return(InferTypeArgument(expectedArgument.CastToArrayReturnType().ArrayElementType, passedArrayElementType, outputArray)); } else if (expectedArgument.IsConstructedReturnType) { switch (expectedArgument.FullyQualifiedName) { case "System.Collections.Generic.IList": case "System.Collections.Generic.ICollection": case "System.Collections.Generic.IEnumerable": return(InferTypeArgument(expectedArgument.CastToConstructedReturnType().TypeArguments[0], passedArrayElementType, outputArray)); } } // If P is an array type, and A is not an array type of the same rank, // or an instantiation of IList<>, ICollection<>, or IEnumerable<>, then // type inference fails for the generic method. return(false); } if (expectedArgument.IsGenericReturnType) { GenericReturnType methodTP = expectedArgument.CastToGenericReturnType(); if (methodTP.TypeParameter.Method != null) { if (methodTP.TypeParameter.Index < outputArray.Length) { outputArray[methodTP.TypeParameter.Index] = passedArgument; } return(true); } } if (expectedArgument.IsConstructedReturnType) { // The spec for this case is quite complex. // For our purposes, we can simplify enourmously: if (!passedArgument.IsConstructedReturnType) { return(false); } IList <IReturnType> expectedTA = expectedArgument.CastToConstructedReturnType().TypeArguments; IList <IReturnType> passedTA = passedArgument.CastToConstructedReturnType().TypeArguments; int count = Math.Min(expectedTA.Count, passedTA.Count); for (int i = 0; i < count; i++) { InferTypeArgument(expectedTA[i], passedTA[i], outputArray); } } return(true); }
static int GetMoreSpecific(IReturnType r, IReturnType s) { if (r == null && s == null) return 0; if (r == null) return 2; if (s == null) return 1; if (r.IsGenericReturnType && !(s.IsGenericReturnType)) return 2; if (s.IsGenericReturnType && !(r.IsGenericReturnType)) return 1; if (r.IsArrayReturnType && s.IsArrayReturnType) return GetMoreSpecific(r.CastToArrayReturnType().ArrayElementType, s.CastToArrayReturnType().ArrayElementType); if (r.IsConstructedReturnType && s.IsConstructedReturnType) return GetMoreSpecific(r.CastToConstructedReturnType().TypeArguments, s.CastToConstructedReturnType().TypeArguments); return 0; }
/// <summary> /// Make exact inference from U for V. /// </summary> void MakeExactInference(IReturnType U, IReturnType V) { Log(" MakeExactInference from " + U + " for " + V); if (U == null || V == null) return; // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.Fixed == false) { Log(" Add bound '" + U.DotNetName + "' to " + tp); tp.Bounds.Add(U); return; } // Otherwise if U is an array type Ue[…] and V is an array type Ve[…] of the same rank // then an exact inference from Ue to Ve is made ArrayReturnType arrU = U.CastToArrayReturnType(); ArrayReturnType arrV = V.CastToArrayReturnType(); if (arrU != null && arrV != null && arrU.ArrayDimensions == arrV.ArrayDimensions) { MakeExactInference(arrU.ArrayElementType, arrV.ArrayElementType); return; } // Otherwise if V is a constructed type C<V1…Vk> and U is a constructed // type C<U1…Uk> then an exact inference is made from each Ui to the corresponding Vi. ConstructedReturnType CU = U.CastToConstructedReturnType(); ConstructedReturnType CV = V.CastToConstructedReturnType(); if (CU != null && CV != null && object.Equals(CU.UnboundType, CV.UnboundType) && CU.TypeArgumentCount == CV.TypeArgumentCount && CU.TypeArguments.Count == CU.TypeArgumentCount && CV.TypeArguments.Count == CV.TypeArgumentCount) { for (int i = 0; i < CU.TypeArgumentCount; i++) { MakeExactInference(CU.TypeArguments[i], CV.TypeArguments[i]); } return; } }
static IReturnType GetElementType(IReturnType potentialArrayType) { if (potentialArrayType == null) return null; ArrayReturnType result; while ((result = potentialArrayType.CastToArrayReturnType()) != null) { potentialArrayType = result.ArrayElementType; } return potentialArrayType; }
void AddExternalType(IReturnType rt, List<ClassNameTypeCountPair> externalTypes, int classCount) { if (rt.IsDefaultReturnType) { ClassNameTypeCountPair pair = new ClassNameTypeCountPair(rt); if (!classIndices.ContainsKey(pair)) { classIndices.Add(pair, externalTypes.Count + classCount); externalTypes.Add(pair); } } else if (rt.IsGenericReturnType) { // ignore } else if (rt.IsArrayReturnType) { AddExternalType(rt.CastToArrayReturnType().ArrayElementType, externalTypes, classCount); } else if (rt.IsConstructedReturnType) { AddExternalType(rt.CastToConstructedReturnType().UnboundType, externalTypes, classCount); foreach (IReturnType typeArgument in rt.CastToConstructedReturnType().TypeArguments) { AddExternalType(typeArgument, externalTypes, classCount); } } else if (rt.IsDecoratingReturnType<PointerReturnType>()) { AddExternalType(rt.CastToDecoratingReturnType<PointerReturnType>().BaseType, externalTypes, classCount); } else { LoggingService.Warn("Unknown return type: " + rt.ToString()); } }
public static IReturnType TranslateType(IReturnType input, IList<IReturnType> typeParameters, bool convertForMethod) { if (typeParameters == null || typeParameters.Count == 0) { return input; // nothing to do when there are no type parameters specified } if (input.IsGenericReturnType) { GenericReturnType rt = input.CastToGenericReturnType(); if (convertForMethod ? (rt.TypeParameter.Method != null) : (rt.TypeParameter.Method == null)) { if (rt.TypeParameter.Index < typeParameters.Count) { IReturnType newType = typeParameters[rt.TypeParameter.Index]; if (newType != null) { return newType; } } } } else if (input.IsArrayReturnType) { ArrayReturnType arInput = input.CastToArrayReturnType(); IReturnType e = arInput.ArrayElementType; IReturnType t = TranslateType(e, typeParameters, convertForMethod); if (e != t && t != null) return new ArrayReturnType(arInput.ProjectContent, t, arInput.ArrayDimensions); } else if (input.IsConstructedReturnType) { ConstructedReturnType cinput = input.CastToConstructedReturnType(); List<IReturnType> para = new List<IReturnType>(cinput.TypeArguments.Count); foreach (IReturnType argument in cinput.TypeArguments) { para.Add(TranslateType(argument, typeParameters, convertForMethod)); } return new ConstructedReturnType(cinput.UnboundType, para); } return input; }
/// <summary> /// Gets all types the specified type inherits from (all classes and interfaces). /// Unlike the class inheritance tree, this method takes care of type arguments and calculates the type /// arguments that are passed to base classes. /// </summary> public static IEnumerable <IReturnType> GetTypeInheritanceTree(IReturnType typeToListInheritanceTreeFor) { if (typeToListInheritanceTreeFor == null) { throw new ArgumentNullException("typeToListInheritanceTreeFor"); } lock (getTypeInheritanceTreeCache) { IEnumerable <IReturnType> result; if (getTypeInheritanceTreeCache.TryGetValue(typeToListInheritanceTreeFor, out result)) { return(result); } } IClass classToListInheritanceTreeFor = typeToListInheritanceTreeFor.GetUnderlyingClass(); if (classToListInheritanceTreeFor == null) { return new IReturnType[] { typeToListInheritanceTreeFor } } ; if (typeToListInheritanceTreeFor.IsArrayReturnType) { IReturnType elementType = typeToListInheritanceTreeFor.CastToArrayReturnType().ArrayElementType; List <IReturnType> resultList = new List <IReturnType>(); resultList.Add(typeToListInheritanceTreeFor); resultList.AddRange(GetTypeInheritanceTree( new ConstructedReturnType( classToListInheritanceTreeFor.ProjectContent.GetClass("System.Collections.Generic.IList", 1).DefaultReturnType, new IReturnType[] { elementType } ) )); resultList.Add(classToListInheritanceTreeFor.ProjectContent.GetClass("System.Collections.IList", 0).DefaultReturnType); resultList.Add(classToListInheritanceTreeFor.ProjectContent.GetClass("System.Collections.ICollection", 0).DefaultReturnType); // non-generic IEnumerable is already added by generic IEnumerable return(resultList); } HashSet <IReturnType> visitedSet = new HashSet <IReturnType>(); List <IReturnType> visitedList = new List <IReturnType>(); Queue <IReturnType> typesToVisit = new Queue <IReturnType>(); bool enqueuedLastBaseType = false; IReturnType currentType = typeToListInheritanceTreeFor; IClass currentClass = classToListInheritanceTreeFor; IReturnType nextType; do { if (currentClass != null) { if (visitedSet.Add(currentType)) { visitedList.Add(currentType); foreach (IReturnType type in currentClass.BaseTypes) { typesToVisit.Enqueue(TranslateIfRequired(currentType, type)); } } } if (typesToVisit.Count > 0) { nextType = typesToVisit.Dequeue(); } else { nextType = enqueuedLastBaseType ? null : DefaultClass.GetBaseTypeByClassType(classToListInheritanceTreeFor); enqueuedLastBaseType = true; } if (nextType != null) { currentType = nextType; currentClass = nextType.GetUnderlyingClass(); } } while (nextType != null); lock (getTypeInheritanceTreeCache) { if (getTypeInheritanceTreeCache.Count == 0) { DomCache.RegisterForClear(ClearGetTypeInheritanceTreeCache); } getTypeInheritanceTreeCache[typeToListInheritanceTreeFor] = visitedList; } return(visitedList); }
/// <summary> /// Tests if an implicit conversion exists from "from" to "to". /// Conversions from concrete types to generic types are only allowed when the generic type belongs to the /// method "allowGenericTargetsOnThisMethod". /// </summary> static bool ConversionExistsInternal(IReturnType from, IReturnType to, IMethod allowGenericTargetsOnThisMethod) { // ECMA-334, § 13.1 Implicit conversions // Identity conversion: if (from == to) { return(true); } if (from == null || to == null) { return(false); } if (from.Equals(to)) { return(true); } bool fromIsDefault = from.IsDefaultReturnType; bool toIsDefault = to.IsDefaultReturnType; if (fromIsDefault && toIsDefault) { // Implicit numeric conversions: int f = GetPrimitiveType(from); int t = GetPrimitiveType(to); if (f == SByte && (t == Short || t == Int || t == Long || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Byte && (t == Short || t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Short && (t == Int || t == Long || t == Float || t == Double || t == Decimal)) { return(true); } if (f == UShort && (t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Int && (t == Long || t == Float || t == Double || t == Decimal)) { return(true); } if (f == UInt && (t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if ((f == Long || f == ULong) && (t == Float || t == Double || t == Decimal)) { return(true); } if (f == Char && (t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Float && t == Double) { return(true); } } // Implicit reference conversions: if (toIsDefault && to.FullyQualifiedName == "System.Object") { return(true); // from any type to object } if (from == NullReturnType.Instance) { IClass toClass = to.GetUnderlyingClass(); if (toClass != null) { switch (toClass.ClassType) { case ClassType.Class: case ClassType.Delegate: case ClassType.Interface: return(true); case ClassType.Struct: return(toClass.FullyQualifiedName == "System.Nullable"); } } return(false); } if ((toIsDefault || to.IsConstructedReturnType || to.IsGenericReturnType) && (fromIsDefault || from.IsArrayReturnType || from.IsConstructedReturnType)) { foreach (IReturnType baseTypeOfFrom in GetTypeInheritanceTree(from)) { if (IsConstructedConversionToGenericReturnType(baseTypeOfFrom, to, allowGenericTargetsOnThisMethod)) { return(true); } } } if (from.IsArrayReturnType && to.IsArrayReturnType) { ArrayReturnType fromArt = from.CastToArrayReturnType(); ArrayReturnType toArt = to.CastToArrayReturnType(); // from array to other array type if (fromArt.ArrayDimensions == toArt.ArrayDimensions) { return(ConversionExistsInternal(fromArt.ArrayElementType, toArt.ArrayElementType, allowGenericTargetsOnThisMethod)); } } if (from.IsDecoratingReturnType <AnonymousMethodReturnType>() && (toIsDefault || to.IsConstructedReturnType)) { AnonymousMethodReturnType amrt = from.CastToDecoratingReturnType <AnonymousMethodReturnType>(); IMethod method = CSharp.TypeInference.GetDelegateOrExpressionTreeSignature(to, amrt.CanBeConvertedToExpressionTree); if (method != null) { if (amrt.HasParameterList) { if (amrt.MethodParameters.Count != method.Parameters.Count) { return(false); } for (int i = 0; i < amrt.MethodParameters.Count; i++) { if (amrt.MethodParameters[i].ReturnType != null) { if (!object.Equals(amrt.MethodParameters[i].ReturnType, method.Parameters[i].ReturnType)) { return(false); } } } } IReturnType rt = amrt.ResolveReturnType(method.Parameters.Select(p => p.ReturnType).ToArray()); return(ConversionExistsInternal(rt, method.ReturnType, allowGenericTargetsOnThisMethod)); } } return(false); }
/// <summary> /// Checks if an implicit conversion exists from <paramref name="from"/> to <paramref name="to"/>. /// </summary> public static bool ConversionExists(IReturnType from, IReturnType to) { // ECMA-334, § 13.1 Implicit conversions // Identity conversion: if (from == to) return true; if (from == null || to == null) return false; if (from.Equals(to)) { return true; } bool fromIsDefault = from.IsDefaultReturnType; bool toIsDefault = to.IsDefaultReturnType; if (fromIsDefault && toIsDefault) { // Implicit numeric conversions: int f = GetPrimitiveType(from); int t = GetPrimitiveType(to); if (f == SByte && (t == Short || t == Int || t == Long || t == Float || t == Double || t == Decimal)) return true; if (f == Byte && (t == Short || t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) return true; if (f == Short && (t == Int || t == Long || t == Float || t == Double || t == Decimal)) return true; if (f == UShort && (t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) return true; if (f == Int && (t == Long || t == Float || t == Double || t == Decimal)) return true; if (f == UInt && (t == Long || t == ULong || t == Float || t == Double || t == Decimal)) return true; if ((f == Long || f == ULong) && (t == Float || t == Double || t == Decimal)) return true; if (f == Char && (t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) return true; if (f == Float && t == Double) return true; } // Implicit reference conversions: if (toIsDefault && to.FullyQualifiedName == "System.Object") { return true; // from any type to object } if (toIsDefault && (fromIsDefault || from.IsArrayReturnType)) { IClass c1 = from.GetUnderlyingClass(); IClass c2 = to.GetUnderlyingClass(); if (c1 != null && c1.IsTypeInInheritanceTree(c2)) { return true; } } if (from.IsArrayReturnType && to.IsArrayReturnType) { ArrayReturnType fromArt = from.CastToArrayReturnType(); ArrayReturnType toArt = to.CastToArrayReturnType(); // from array to other array type if (fromArt.ArrayDimensions == toArt.ArrayDimensions) { return ConversionExists(fromArt.ArrayElementType, toArt.ArrayElementType); } } if (from.IsConstructedReturnType && to.IsConstructedReturnType) { if (from.FullyQualifiedName == to.FullyQualifiedName) { IList<IReturnType> fromTypeArguments = from.CastToConstructedReturnType().TypeArguments; IList<IReturnType> toTypeArguments = to.CastToConstructedReturnType().TypeArguments; if (fromTypeArguments.Count == toTypeArguments.Count) { for (int i = 0; i < fromTypeArguments.Count; i++) { if (fromTypeArguments[i] == toTypeArguments[i]) continue; if (object.Equals(fromTypeArguments[i], toTypeArguments[i])) continue; if (!(toTypeArguments[i].IsGenericReturnType)) return false; } return true; } } } return false; }
/// <summary> /// Infers type arguments specified by passing expectedArgument as parameter where passedArgument /// was expected. The resulting type arguments are written to outputArray. /// Returns false when expectedArgument and passedArgument are incompatible, otherwise true /// is returned (true is used both for successful inferring and other kind of errors). /// </summary> public static bool InferTypeArgument(IReturnType expectedArgument, IReturnType passedArgument, IReturnType[] outputArray) { if (expectedArgument == null) return true; if (passedArgument == null) return true; // TODO: NullTypeReference if (expectedArgument.IsArrayReturnType) { IReturnType expectedArrayElementType = expectedArgument.CastToArrayReturnType().ArrayElementType; if (passedArgument.IsArrayReturnType && expectedArgument.CastToArrayReturnType().ArrayDimensions == passedArgument.CastToArrayReturnType().ArrayDimensions) { return InferTypeArgument(expectedArrayElementType, passedArgument.CastToArrayReturnType().ArrayElementType, outputArray); } else if (passedArgument.IsConstructedReturnType) { switch (passedArgument.FullyQualifiedName) { case "System.Collections.Generic.IList": case "System.Collections.Generic.ICollection": case "System.Collections.Generic.IEnumerable": return InferTypeArgument(expectedArrayElementType, passedArgument.CastToConstructedReturnType().TypeArguments[0], outputArray); } } // If P is an array type, and A is not an array type of the same rank, // or an instantiation of IList<>, ICollection<>, or IEnumerable<>, then // type inference fails for the generic method. return false; } if (expectedArgument.IsGenericReturnType) { GenericReturnType methodTP = expectedArgument.CastToGenericReturnType(); if (methodTP.TypeParameter.Method != null) { if (methodTP.TypeParameter.Index < outputArray.Length) { outputArray[methodTP.TypeParameter.Index] = passedArgument; } return true; } } if (expectedArgument.IsConstructedReturnType) { // The spec for this case is quite complex. // For our purposes, we can simplify enourmously: if (!passedArgument.IsConstructedReturnType) return false; IList<IReturnType> expectedTA = expectedArgument.CastToConstructedReturnType().TypeArguments; IList<IReturnType> passedTA = passedArgument.CastToConstructedReturnType().TypeArguments; int count = Math.Min(expectedTA.Count, passedTA.Count); for (int i = 0; i < count; i++) { InferTypeArgument(expectedTA[i], passedTA[i], outputArray); } } return true; }
void UnpackNestedType(StringBuilder builder, IReturnType returnType) { if (returnType.IsArrayReturnType) { ArrayReturnType art = returnType.CastToArrayReturnType(); builder.Append('('); UnpackNestedType(builder, art.ArrayElementType); if (art.ArrayDimensions > 1) { builder.Append(','); builder.Append(art.ArrayDimensions); } builder.Append(')'); } else if (returnType.IsConstructedReturnType) { ConstructedReturnType crt = returnType.CastToConstructedReturnType(); UnpackNestedType(builder, crt.UnboundType); builder.Append("[of "); for (int i = 0; i < crt.TypeArguments.Count; ++i) { if (i > 0) builder.Append(", "); builder.Append(Convert(crt.TypeArguments[i])); } builder.Append(']'); } else { string fullName = returnType.FullyQualifiedName; if (fullName != null && typeConversionTable.ContainsKey(fullName)) { builder.Append(typeConversionTable[fullName].ToString()); } else { if (UseFullyQualifiedTypeNames) { builder.Append(fullName); } else { builder.Append(returnType.Name); } } } }
/// <summary> /// Checks if an implicit conversion exists from <paramref name="from"/> to <paramref name="to"/>. /// </summary> public static bool ConversionExists(IReturnType from, IReturnType to) { // ECMA-334, § 13.1 Implicit conversions // Identity conversion: if (from == to) { return(true); } if (from == null || to == null) { return(false); } if (from.Equals(to)) { return(true); } bool fromIsDefault = from.IsDefaultReturnType; bool toIsDefault = to.IsDefaultReturnType; if (fromIsDefault && toIsDefault) { // Implicit numeric conversions: int f = GetPrimitiveType(from); int t = GetPrimitiveType(to); if (f == SByte && (t == Short || t == Int || t == Long || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Byte && (t == Short || t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Short && (t == Int || t == Long || t == Float || t == Double || t == Decimal)) { return(true); } if (f == UShort && (t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Int && (t == Long || t == Float || t == Double || t == Decimal)) { return(true); } if (f == UInt && (t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if ((f == Long || f == ULong) && (t == Float || t == Double || t == Decimal)) { return(true); } if (f == Char && (t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Float && t == Double) { return(true); } } // Implicit reference conversions: if (toIsDefault && to.FullyQualifiedName == "System.Object") { return(true); // from any type to object } if (toIsDefault && (fromIsDefault || from.IsArrayReturnType)) { IClass c1 = from.GetUnderlyingClass(); IClass c2 = to.GetUnderlyingClass(); if (c1 != null && c1.IsTypeInInheritanceTree(c2)) { return(true); } } if (from.IsArrayReturnType && to.IsArrayReturnType) { ArrayReturnType fromArt = from.CastToArrayReturnType(); ArrayReturnType toArt = to.CastToArrayReturnType(); // from array to other array type if (fromArt.ArrayDimensions == toArt.ArrayDimensions) { return(ConversionExists(fromArt.ArrayElementType, toArt.ArrayElementType)); } } if (from.IsConstructedReturnType && to.IsConstructedReturnType) { if (from.FullyQualifiedName == to.FullyQualifiedName) { IList <IReturnType> fromTypeArguments = from.CastToConstructedReturnType().TypeArguments; IList <IReturnType> toTypeArguments = to.CastToConstructedReturnType().TypeArguments; if (fromTypeArguments.Count == toTypeArguments.Count) { for (int i = 0; i < fromTypeArguments.Count; i++) { if (fromTypeArguments[i] == toTypeArguments[i]) { continue; } if (object.Equals(fromTypeArguments[i], toTypeArguments[i])) { continue; } if (!(toTypeArguments[i].IsGenericReturnType)) { return(false); } } return(true); } } } return(false); }
/// <summary> /// Make lower bound inference from U for V. /// </summary> void MakeLowerBoundInference(IReturnType U, IReturnType V) { Log(" MakeLowerBoundInference from " + U + " for " + V); if (U == null || V == null) { return; } // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.Fixed == false) { Log(" Add bound '" + U.DotNetName + "' to " + tp); tp.Bounds.Add(U); return; } // Otherwise if U is an array type Ue[…] and V is either an array type Ve[…]of the // same rank, or if U is a onedimensional array type Ue[]and V is one of // IEnumerable<Ve>, ICollection<Ve> or IList<Ve> then ArrayReturnType arrU = U.CastToArrayReturnType(); ArrayReturnType arrV = V.CastToArrayReturnType(); ConstructedReturnType CV = V.CastToConstructedReturnType(); if (arrU != null && (arrV != null && arrU.ArrayDimensions == arrV.ArrayDimensions || (arrU.ArrayDimensions == 1 && IsIEnumerableCollectionOrList(CV)))) { IReturnType Ue = arrU.ArrayElementType; IReturnType Ve = arrV != null ? arrV.ArrayElementType : CV.TypeArguments[0]; // If Ue is known to be a reference type then a lowerbound inference from Ue to Ve is made if (IsReferenceType(Ue) ?? false) { MakeLowerBoundInference(Ue, Ve); } else { // Otherwise an exact inference from Ue to Ve is made MakeExactInference(Ue, Ve); } return; } // Otherwise if V is a constructed type C<V1…Vk> and there is a unique set of // types U1…Uk such that a standard implicit conversion exists from U to C<U1…Uk> // then an exact inference is made from each Ui for the corresponding Vi. if (CV != null) { foreach (IReturnType U2 in MemberLookupHelper.GetTypeInheritanceTree(U)) { ConstructedReturnType CU2 = U2.CastToConstructedReturnType(); if (CU2 != null && object.Equals(CU2.UnboundType, CV.UnboundType) && CU2.TypeArgumentCount == CV.TypeArgumentCount && CU2.TypeArguments.Count == CU2.TypeArgumentCount && // unfortunately these might not be the same... CV.TypeArguments.Count == CV.TypeArgumentCount) { for (int i = 0; i < CU2.TypeArgumentCount; i++) { MakeExactInference(CU2.TypeArguments[i], CV.TypeArguments[i]); } return; } } } }
public static TypeReference ConvertType(IReturnType returnType, ClassFinder context) { if (returnType == null) { return(TypeReference.Null); } if (returnType is NullReturnType) { return(TypeReference.Null); } ArrayReturnType arrayReturnType = returnType.CastToArrayReturnType(); if (arrayReturnType != null) { TypeReference typeRef = ConvertType(arrayReturnType.ArrayElementType, context); int[] rank = typeRef.RankSpecifier ?? new int[0]; Array.Resize(ref rank, rank.Length + 1); rank[rank.Length - 1] = arrayReturnType.ArrayDimensions - 1; typeRef.RankSpecifier = rank; return(typeRef); } PointerReturnType pointerReturnType = returnType.CastToDecoratingReturnType <PointerReturnType>(); if (pointerReturnType != null) { TypeReference typeRef = ConvertType(pointerReturnType.BaseType, context); typeRef.PointerNestingLevel++; return(typeRef); } IList <IReturnType> typeArguments = EmptyList <IReturnType> .Instance; if (returnType.IsConstructedReturnType) { typeArguments = returnType.CastToConstructedReturnType().TypeArguments; } IClass c = returnType.GetUnderlyingClass(); if (c != null) { return(CreateTypeReference(c, typeArguments, context)); } else { TypeReference typeRef; if (IsPrimitiveType(returnType)) { typeRef = new TypeReference(returnType.FullyQualifiedName, true); } else if (context != null && CanUseShortTypeName(returnType, context)) { typeRef = new TypeReference(returnType.Name); } else { string fullName = returnType.FullyQualifiedName; if (string.IsNullOrEmpty(fullName)) { fullName = returnType.Name; } typeRef = new TypeReference(fullName); } foreach (IReturnType typeArgument in typeArguments) { typeRef.GenericTypes.Add(ConvertType(typeArgument, context)); } return(typeRef); } }
void WriteType(IReturnType rt) { if (rt == null) { writer.Write(NullRTReferenceCode); return; } if (rt.IsDefaultReturnType) { string name = rt.FullyQualifiedName; if (name == "System.Void") { writer.Write(VoidRTCode); } else { writer.Write(classIndices[new ClassNameTypeCountPair(rt)]); } } else if (rt.IsGenericReturnType) { GenericReturnType grt = rt.CastToGenericReturnType(); if (grt.TypeParameter.Method != null) { writer.Write(MethodGenericRTCode); } else { writer.Write(TypeGenericRTCode); } writer.Write(grt.TypeParameter.Index); } else if (rt.IsArrayReturnType) { writer.Write(ArrayRTCode); writer.Write(rt.CastToArrayReturnType().ArrayDimensions); WriteType(rt.CastToArrayReturnType().ArrayElementType); } else if (rt.IsConstructedReturnType) { ConstructedReturnType crt = rt.CastToConstructedReturnType(); writer.Write(ConstructedRTCode); WriteType(crt.UnboundType); writer.Write((byte)crt.TypeArguments.Count); foreach (IReturnType typeArgument in crt.TypeArguments) { WriteType(typeArgument); } } else if (rt.IsDecoratingReturnType<PointerReturnType>()) { writer.Write(PointerRTCode); WriteType(rt.CastToDecoratingReturnType<PointerReturnType>().BaseType); } else { writer.Write(NullRTReferenceCode); LoggingService.Warn("Unknown return type: " + rt.ToString()); } }
void WriteType(IReturnType rt) { if (rt == null) { writer.Write(NullRTReferenceCode); return; } if (rt.IsDefaultReturnType) { string name = rt.FullyQualifiedName; if (name == "System.Void") { writer.Write(VoidRTCode); } else if (name == "dynamic") { writer.Write(DynamicRTCode); } else { writer.Write(classIndices[new ClassNameTypeCountPair(rt)]); } } else if (rt.IsGenericReturnType) { GenericReturnType grt = rt.CastToGenericReturnType(); if (grt.TypeParameter.Method != null) { writer.Write(MethodGenericRTCode); } else { writer.Write(TypeGenericRTCode); } writer.Write(grt.TypeParameter.Index); } else if (rt.IsArrayReturnType) { writer.Write(ArrayRTCode); writer.Write(rt.CastToArrayReturnType().ArrayDimensions); WriteType(rt.CastToArrayReturnType().ArrayElementType); } else if (rt.IsConstructedReturnType) { ConstructedReturnType crt = rt.CastToConstructedReturnType(); writer.Write(ConstructedRTCode); WriteType(crt.UnboundType); writer.Write((byte)crt.TypeArguments.Count); foreach (IReturnType typeArgument in crt.TypeArguments) { WriteType(typeArgument); } } else if (rt.IsDecoratingReturnType <PointerReturnType>()) { writer.Write(PointerRTCode); WriteType(rt.CastToDecoratingReturnType <PointerReturnType>().BaseType); } else { writer.Write(NullRTReferenceCode); LoggingService.Warn("Unknown return type: " + rt.ToString()); } }
void UnpackNestedType(StringBuilder builder, IReturnType returnType) { if (returnType.IsArrayReturnType) { builder.Append('('); int dimensions = returnType.CastToArrayReturnType().ArrayDimensions; for (int i = 1; i < dimensions; ++i) { builder.Append(','); } builder.Append(')'); UnpackNestedType(builder, returnType.CastToArrayReturnType().ArrayElementType); } else if (returnType.IsConstructedReturnType) { UnpackNestedType(builder, returnType.CastToConstructedReturnType().UnboundType); builder.Append("(Of "); IList<IReturnType> ta = returnType.CastToConstructedReturnType().TypeArguments; for (int i = 0; i < ta.Count; ++i) { if (i > 0) builder.Append(", "); builder.Append(Convert(ta[i])); } builder.Append(')'); } }
static bool AreTypesDifferent(IReturnType oldType, CodeTypeReference newType) { IClass oldClass = oldType.GetUnderlyingClass(); if (oldClass == null) { // ignore type changes to untyped VB fields return false; } if (newType.BaseType == "System.Void") { // field types get replaced with System.Void if the type cannot be resolved // (e.g. generic fields in the Boo designer which aren't converted to CodeDom) // we'll ignore such type changes (fields should never have the type void) return false; } ArrayReturnType oldArray = oldType.IsArrayReturnType ? oldType.CastToArrayReturnType() : null; if (oldArray == null ^ newType.ArrayRank < 1) { return true; } if (oldArray == null) { if (oldClass.DotNetName != newType.BaseType) { return true; } } else { if (oldArray.ArrayDimensions != newType.ArrayRank) { return true; } if (AreTypesDifferent(oldArray.ArrayElementType, newType.ArrayElementType)) { return true; } } return false; }
static void UnpackArrayType(StringBuilder builder, IReturnType returnType) { if (returnType.IsArrayReturnType) { builder.Append('['); int dimensions = returnType.CastToArrayReturnType().ArrayDimensions; for (int i = 1; i < dimensions; ++i) { builder.Append(','); } builder.Append(']'); UnpackArrayType(builder, returnType.CastToArrayReturnType().ArrayElementType); } }
/// <summary> /// Make lower bound inference from U for V. /// </summary> void MakeLowerBoundInference(IReturnType U, IReturnType V) { Log(" MakeLowerBoundInference from " + U + " for " + V); if (U == null || V == null) return; // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.Fixed == false) { Log(" Add bound '" + U.DotNetName + "' to " + tp); tp.Bounds.Add(U); return; } // Otherwise if U is an array type Ue[…] and V is either an array type Ve[…]of the // same rank, or if U is a onedimensional array type Ue[]and V is one of // IEnumerable<Ve>, ICollection<Ve> or IList<Ve> then ArrayReturnType arrU = U.CastToArrayReturnType(); ArrayReturnType arrV = V.CastToArrayReturnType(); ConstructedReturnType CV = V.CastToConstructedReturnType(); if (arrU != null && (arrV != null && arrU.ArrayDimensions == arrV.ArrayDimensions || (arrU.ArrayDimensions == 1 && IsIEnumerableCollectionOrList(CV)))) { IReturnType Ue = arrU.ArrayElementType; IReturnType Ve = arrV != null ? arrV.ArrayElementType : CV.TypeArguments[0]; // If Ue is known to be a reference type then a lowerbound inference from Ue to Ve is made if (IsReferenceType(Ue) ?? false) { MakeLowerBoundInference(Ue, Ve); } else { // Otherwise an exact inference from Ue to Ve is made MakeExactInference(Ue, Ve); } return; } // Otherwise if V is a constructed type C<V1…Vk> and there is a unique set of // types U1…Uk such that a standard implicit conversion exists from U to C<U1…Uk> // then an exact inference is made from each Ui for the corresponding Vi. if (CV != null) { foreach (IReturnType U2 in MemberLookupHelper.GetTypeInheritanceTree(U)) { ConstructedReturnType CU2 = U2.CastToConstructedReturnType(); if (CU2 != null && object.Equals(CU2.UnboundType, CV.UnboundType) && CU2.TypeArgumentCount == CV.TypeArgumentCount && CU2.TypeArguments.Count == CU2.TypeArgumentCount // unfortunately these might not be the same... && CV.TypeArguments.Count == CV.TypeArgumentCount) { for (int i = 0; i < CU2.TypeArgumentCount; i++) { MakeExactInference(CU2.TypeArguments[i], CV.TypeArguments[i]); } return; } } } }