public override IType VisitParameterizedType(ParameterizedType type) { IType newType = base.VisitParameterizedType(type); if (newType != type && ConstraintsValid) { // something was changed, so we need to validate the constraints ParameterizedType newParameterizedType = newType as ParameterizedType; if (newParameterizedType != null) { // C# 4.0 spec: §4.4.4 Satisfying constraints var typeParameters = newParameterizedType.GetDefinition().TypeParameters; var substitution = newParameterizedType.GetSubstitution(); for (int i = 0; i < typeParameters.Count; i++) { if (!ValidateConstraints(typeParameters[i], newParameterizedType.GetTypeArgument(i), substitution, conversions)) { ConstraintsValid = false; break; } } } } return(newType); }
public override IType VisitParameterizedType(ParameterizedType type) { IType newType = base.VisitParameterizedType(type); if (newType != type && ConstraintsValid) { // something was changed, so we need to validate the constraints ParameterizedType newParameterizedType = newType as ParameterizedType; if (newParameterizedType != null) { // C# 4.0 spec: §4.4.4 Satisfying constraints var typeParameters = newParameterizedType.GetDefinition().TypeParameters; for (int i = 0; i < typeParameters.Count; i++) { ITypeParameter tp = typeParameters[i]; IType typeArg = newParameterizedType.GetTypeArgument(i); switch (typeArg.Kind) // void, null, and pointers cannot be used as type arguments { case TypeKind.Void: case TypeKind.Null: case TypeKind.Pointer: ConstraintsValid = false; break; } if (tp.HasReferenceTypeConstraint) { if (typeArg.IsReferenceType != true) { ConstraintsValid = false; } } if (tp.HasValueTypeConstraint) { if (!NullableType.IsNonNullableValueType(typeArg)) { ConstraintsValid = false; } } if (tp.HasDefaultConstructorConstraint) { ITypeDefinition def = typeArg.GetDefinition(); if (def != null && def.IsAbstract) { ConstraintsValid = false; } ConstraintsValid &= typeArg.GetConstructors( m => m.Parameters.Count == 0 && m.Accessibility == Accessibility.Public, GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions ).Any(); } foreach (IType constraintType in tp.DirectBaseTypes) { IType c = constraintType.AcceptVisitor(newParameterizedType.GetSubstitution()); ConstraintsValid &= conversions.IsConstraintConvertible(typeArg, c); } } } } return(newType); }
static IEnumerable<IType> GetNestedTypesImpl(IType outerType, IList<IType> nestedTypeArguments, Predicate<ITypeDefinition> filter, GetMemberOptions options) { ITypeDefinition outerTypeDef = outerType.GetDefinition(); if (outerTypeDef == null) yield break; int outerTypeParameterCount = outerTypeDef.TypeParameterCount; ParameterizedType pt = outerType as ParameterizedType; foreach (ITypeDefinition nestedType in outerTypeDef.NestedTypes) { int totalTypeParameterCount = nestedType.TypeParameterCount; if (nestedTypeArguments != null) { if (totalTypeParameterCount - outerTypeParameterCount != nestedTypeArguments.Count) continue; } if (!(filter == null || filter(nestedType))) continue; if (totalTypeParameterCount == 0 || (options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { yield return nestedType; } else { // We need to parameterize the nested type IType[] newTypeArguments = new IType[totalTypeParameterCount]; for (int i = 0; i < outerTypeParameterCount; i++) { newTypeArguments[i] = pt != null ? pt.GetTypeArgument(i) : outerTypeDef.TypeParameters[i]; } for (int i = outerTypeParameterCount; i < totalTypeParameterCount; i++) { if (nestedTypeArguments != null) newTypeArguments[i] = nestedTypeArguments[i - outerTypeParameterCount]; else newTypeArguments[i] = SpecialType.UnboundTypeArgument; } yield return new ParameterizedType(nestedType, newTypeArguments); } } }
/// <summary> /// Unpacks the generic Task[T]. Returns null if the input is not Task[T]. /// </summary> static IType UnpackTask(IType type) { ParameterizedType pt = type as ParameterizedType; if (pt != null && pt.TypeParameterCount == 1 && pt.Name == "Task" && pt.Namespace == "System.Threading.Tasks") { return(pt.GetTypeArgument(0)); } return(null); }
static IMethod GetDelegateOrExpressionTreeSignature(IType t) { ParameterizedType pt = t as ParameterizedType; if (pt != null && pt.TypeParameterCount == 1 && pt.Name == "Expression" && pt.Namespace == "System.Linq.Expressions") { t = pt.GetTypeArgument(0); } return(t.GetDelegateInvokeMethod()); }
/// <summary> /// Make exact inference from U to V. /// C# 4.0 spec: §7.5.2.8 Exact inferences /// </summary> void MakeExactInference(IType U, IType V) { Log.WriteLine("MakeExactInference from " + U + " to " + V); if (U.Nullability == V.Nullability) { U = U.WithoutNullability(); V = V.WithoutNullability(); } // 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.IsFixed == false) { Log.WriteLine(" Add exact bound '" + U + "' to " + tp); tp.AddExactBound(U); return; } // Handle by reference types: ByReferenceType brU = U as ByReferenceType; ByReferenceType brV = V as ByReferenceType; if (brU != null && brV != null) { MakeExactInference(brU.ElementType, brV.ElementType); return; } // Handle array types: ArrayType arrU = U as ArrayType; ArrayType arrV = V as ArrayType; if (arrU != null && arrV != null && arrU.Dimensions == arrV.Dimensions) { MakeExactInference(arrU.ElementType, arrV.ElementType); return; } // Handle parameterized type: ParameterizedType pU = U.TupleUnderlyingTypeOrSelf() as ParameterizedType; ParameterizedType pV = V.TupleUnderlyingTypeOrSelf() as ParameterizedType; if (pU != null && pV != null && object.Equals(pU.GenericType, pV.GenericType) && pU.TypeParameterCount == pV.TypeParameterCount) { Log.Indent(); for (int i = 0; i < pU.TypeParameterCount; i++) { MakeExactInference(pU.GetTypeArgument(i), pV.GetTypeArgument(i)); } Log.Unindent(); } }
bool ImplicitReferenceConversion(IType fromType, IType toType, int subtypeCheckNestingDepth) { // C# 4.0 spec: §6.1.6 // reference conversions are possible only if both types are known to be reference types if (!(fromType.IsReferenceType == true && toType.IsReferenceType == true)) { return(false); } ArrayType fromArray = fromType as ArrayType; if (fromArray != null) { ArrayType toArray = toType as ArrayType; if (toArray != null) { // array covariance (the broken kind) return(fromArray.Dimensions == toArray.Dimensions && ImplicitReferenceConversion(fromArray.ElementType, toArray.ElementType, subtypeCheckNestingDepth)); } // conversion from single-dimensional array S[] to IList<T>: ParameterizedType toPT = toType as ParameterizedType; if (fromArray.Dimensions == 1 && toPT != null && toPT.TypeParameterCount == 1 && toPT.Namespace == "System.Collections.Generic" && (toPT.Name == "IList" || toPT.Name == "ICollection" || toPT.Name == "IEnumerable" || toPT.Name == "IReadOnlyList")) { // array covariance plays a part here as well (string[] is IList<object>) return(IdentityConversion(fromArray.ElementType, toPT.GetTypeArgument(0)) || ImplicitReferenceConversion(fromArray.ElementType, toPT.GetTypeArgument(0), subtypeCheckNestingDepth)); } // conversion from any array to System.Array and the interfaces it implements: IType systemArray = compilation.FindType(KnownTypeCode.Array); return(systemArray.Kind != TypeKind.Unknown && (systemArray.Equals(toType) || ImplicitReferenceConversion(systemArray, toType, subtypeCheckNestingDepth))); } // now comes the hard part: traverse the inheritance chain and figure out generics+variance return(IsSubtypeOf(fromType, toType, subtypeCheckNestingDepth)); }
static IType UnpackExpressionTreeType(IType type) { ParameterizedType pt = type as ParameterizedType; if (pt != null && pt.TypeParameterCount == 1 && pt.Name == "Expression" && pt.Namespace == "System.Linq.Expressions") { return(pt.GetTypeArgument(0)); } else { return(type); } }
bool IdentityOrVarianceConversion(IType s, IType t, int subtypeCheckNestingDepth) { ITypeDefinition def = s.GetDefinition(); if (def != null && def.Equals(t.GetDefinition())) { ParameterizedType ps = s as ParameterizedType; ParameterizedType pt = t as ParameterizedType; if (ps != null && pt != null) { // C# 4.0 spec: §13.1.3.2 Variance Conversion for (int i = 0; i < def.TypeParameters.Count; i++) { IType si = ps.GetTypeArgument(i); IType ti = pt.GetTypeArgument(i); if (IdentityConversion(si, ti)) { continue; } ITypeParameter xi = def.TypeParameters[i]; switch (xi.Variance) { case VarianceModifier.Covariant: if (!ImplicitReferenceConversion(si, ti, subtypeCheckNestingDepth)) { return(false); } break; case VarianceModifier.Contravariant: if (!ImplicitReferenceConversion(ti, si, subtypeCheckNestingDepth)) { return(false); } break; default: return(false); } } } else if (ps != null || pt != null) { return(false); // only of of them is parameterized, or counts don't match? -> not valid conversion } return(true); } return(false); }
/// <summary> /// Finds IList<T> or IEnumerable<T> base type. /// </summary> /// <param name="fullNamePrefix">Type code to search for (IList<T> or IEnumerable<T>)</param></param> /// <param name="implementation">Found implementation.</param> /// <param name="itemType">The only generic argument of <paramref name="implementation"/></param> /// <returns>True if found, false otherwise.</returns> private static bool ResolveKnownBaseType(this IType type, KnownTypeCode knownTypeCode, out ParameterizedType implementation, out IType itemType) { if (type == null) { throw new ArgumentNullException("type"); } implementation = null; itemType = null; ParameterizedType impl = type.GetAllBaseTypes().OfType <ParameterizedType>(). Where(t => t.IsKnownType(knownTypeCode) && t.TypeParameterCount == 1) .FirstOrDefault(); if (impl != null) { implementation = impl; itemType = impl.GetTypeArgument(0); return(true); } return(false); }
/// <summary> /// Make upper bound inference from U to V. /// C# 4.0 spec: §7.5.2.10 Upper-bound inferences /// </summary> void MakeUpperBoundInference(IType U, IType V) { Log.WriteLine(" MakeUpperBoundInference from " + U + " to " + V); // 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.IsFixed == false) { Log.WriteLine(" Add upper bound '" + U + "' to " + tp); tp.UpperBounds.Add(U); return; } // Handle array types: ArrayType arrU = U as ArrayType; ArrayType arrV = V as ArrayType; ParameterizedType pU = U as ParameterizedType; if (arrV != null && arrU != null && arrU.Dimensions == arrV.Dimensions) { MakeUpperBoundInference(arrU.ElementType, arrV.ElementType); return; } else if (arrV != null && IsGenericInterfaceImplementedByArray(pU) && arrV.Dimensions == 1) { MakeUpperBoundInference(pU.GetTypeArgument(0), arrV.ElementType); return; } // Handle parameterized types: if (pU != null) { ParameterizedType uniqueBaseType = null; foreach (IType baseV in V.GetAllBaseTypes()) { ParameterizedType pV = baseV as ParameterizedType; if (pV != null && object.Equals(pU.GetDefinition(), pV.GetDefinition()) && pU.TypeParameterCount == pV.TypeParameterCount) { if (uniqueBaseType == null) { uniqueBaseType = pV; } else { return; // cannot make an inference because it's not unique } } } Log.Indent(); if (uniqueBaseType != null) { for (int i = 0; i < uniqueBaseType.TypeParameterCount; i++) { IType Ui = pU.GetTypeArgument(i); IType Vi = uniqueBaseType.GetTypeArgument(i); if (Ui.IsReferenceType == true) { // look for variance ITypeParameter Xi = pU.GetDefinition().TypeParameters[i]; switch (Xi.Variance) { case VarianceModifier.Covariant: MakeUpperBoundInference(Ui, Vi); break; case VarianceModifier.Contravariant: MakeLowerBoundInference(Ui, Vi); break; default: // invariant MakeExactInference(Ui, Vi); break; } } else { // not known to be a reference type MakeExactInference(Ui, Vi); } } } Log.Unindent(); } }
static IEnumerable <IType> GetNestedTypesImpl(IType outerType, IList <IType> nestedTypeArguments, ITypeResolveContext context, Predicate <ITypeDefinition> filter, GetMemberOptions options) { ITypeDefinition outerTypeDef = outerType.GetDefinition(); if (outerTypeDef == null) { yield break; } int outerTypeParameterCount = outerTypeDef.TypeParameterCount; ParameterizedType pt = outerType as ParameterizedType; foreach (ITypeDefinition nestedType in outerTypeDef.NestedTypes) { int totalTypeParameterCount = nestedType.TypeParameterCount; if (nestedTypeArguments != null) { if (totalTypeParameterCount - outerTypeParameterCount != nestedTypeArguments.Count) { continue; } } if (!(filter == null || filter(nestedType))) { continue; } if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { yield return(nestedType); } else if (totalTypeParameterCount == 0 || (pt == null && totalTypeParameterCount == outerTypeParameterCount)) { // The nested type has no new type parameters, and there are no type arguments // to copy from the outer type // -> we can directly return the nested type definition yield return(nestedType); } else { // We need to parameterize the nested type IType[] newTypeArguments = new IType[totalTypeParameterCount]; for (int i = 0; i < outerTypeParameterCount; i++) { newTypeArguments[i] = pt != null?pt.GetTypeArgument(i) : outerTypeDef.TypeParameters[i]; } for (int i = outerTypeParameterCount; i < totalTypeParameterCount; i++) { if (nestedTypeArguments != null) { newTypeArguments[i] = nestedTypeArguments[i - outerTypeParameterCount]; } else { newTypeArguments[i] = SharedTypes.UnboundTypeArgument; } } yield return(new ParameterizedType(nestedType, newTypeArguments)); } } }