public virtual bool CheckTypeAccess(CType type, Symbol symWhere) { Debug.Assert(type != null); // Array, Ptr, Nub, etc don't matter. type = type.GetNakedType(true); if (!type.IsAggregateType()) { Debug.Assert(type.IsVoidType() || type.IsErrorType() || type.IsTypeParameterType()); return(true); } for (AggregateType ats = type.AsAggregateType(); ats != null; ats = ats.outerType) { if (ACCESSERROR.ACCESSERROR_NOERROR != CheckAccessCore(ats.GetOwningAggregate(), ats.outerType, symWhere, null)) { return(false); } } TypeArray typeArgs = type.AsAggregateType().GetTypeArgsAll(); for (int i = 0; i < typeArgs.size; i++) { if (!CheckTypeAccess(typeArgs.Item(i), symWhere)) { return(false); } } return(true); }
private bool IsBaseInterface(CType pDerived, CType pBase) { Debug.Assert(pDerived != null); Debug.Assert(pBase != null); if (!pBase.isInterfaceType()) { return(false); } if (!pDerived.IsAggregateType()) { return(false); } AggregateType atsDer = pDerived.AsAggregateType(); while (atsDer != null) { TypeArray ifacesAll = atsDer.GetIfacesAll(); for (int i = 0; i < ifacesAll.Count; i++) { if (AreTypesEqualForConversion(ifacesAll[i], pBase)) { return(true); } } atsDer = atsDer.GetBaseClass(); } return(false); }
// It would be nice to make this a virtual method on typeSym. public AggregateType GetAggTypeSym(CType typeSym) { Debug.Assert(typeSym != null); Debug.Assert(typeSym.IsAggregateType() || typeSym.IsTypeParameterType() || typeSym.IsArrayType() || typeSym.IsNullableType()); switch (typeSym.GetTypeKind()) { case TypeKind.TK_AggregateType: return(typeSym.AsAggregateType()); case TypeKind.TK_ArrayType: return(GetReqPredefType(PredefinedType.PT_ARRAY)); case TypeKind.TK_TypeParameterType: return(typeSym.AsTypeParameterType().GetEffectiveBaseClass()); case TypeKind.TK_NullableType: return(typeSym.AsNullableType().GetAts(ErrorContext)); } Debug.Assert(false, "Bad typeSym!"); return(null); }
private bool HasAnyBaseInterfaceConversion(CType pDerived, CType pBase) { if (!pBase.isInterfaceType()) { return(false); } if (!pDerived.IsAggregateType()) { return(false); } AggregateType atsDer = pDerived.AsAggregateType(); while (atsDer != null) { TypeArray ifacesAll = atsDer.GetIfacesAll(); for (int i = 0; i < ifacesAll.Count; i++) { if (HasInterfaceConversion(ifacesAll[i].AsAggregateType(), pBase.AsAggregateType())) { return(true); } } atsDer = atsDer.GetBaseClass(); } return(false); }
private bool bindImplicitConversionFromArray() { // 13.1.4 // // The implicit reference conversions are: // // * From an array-type S with an element type SE to an array-type T with an element // type TE, provided all of the following are true: // * S and T differ only in element type. In other words, S and T have the same number of dimensions. // * An implicit reference conversion exists from SE to TE. // * From a one-dimensional array-type S[] to System.Collections.Generic.IList<S>, // System.Collections.Generic.IReadOnlyList<S> and their base interfaces // * From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> // and their base interfaces, provided there is an implicit reference conversion from S to T. // * From any array-type to System.Array. // * From any array-type to any interface implemented by System.Array. if (!GetSymbolLoader().HasBaseConversion(typeSrc, typeDest)) { return(false); } EXPRFLAG grfex = 0; // The above if checks for dest==Array, object or an interface the array implements, // including IList<T>, ICollection<T>, IEnumerable<T>, IReadOnlyList<T>, IReadOnlyCollection<T> // and the non-generic versions. // REVIEW : Determine when we need EXF_REFCHECK! if ((typeDest.IsArrayType() || (typeDest.isInterfaceType() && typeDest.AsAggregateType().GetTypeArgsAll().Size == 1 && ((typeDest.AsAggregateType().GetTypeArgsAll().Item(0) != typeSrc.AsArrayType().GetElementType()) || 0 != (flags & CONVERTTYPE.FORCECAST)))) && (0 != (flags & CONVERTTYPE.FORCECAST) || TypeManager.TypeContainsTyVars(typeSrc, null) || TypeManager.TypeContainsTyVars(typeDest, null))) { grfex = EXPRFLAG.EXF_REFCHECK; } if (needsExprDest) { binder.bindSimpleCast(exprSrc, exprTypeDest, out exprDest, grfex); } return(true); }
public AggregateSymbol GetNakedAgg(bool fStripNub) { CType type = GetNakedType(fStripNub); if (type != null && type.IsAggregateType()) { return(type.AsAggregateType().getAggregate()); } return(null); }
/*************************************************************************************************** * * There exists an explicit conversion ... * From a generic delegate type S to generic delegate type T, provided all of the follow are true: * o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is, * S is D<S1,... Sk> and T is D<T1,... Tk>. * o S is not compatible with or identical to T. * o If type parameter Xi is declared to be invariant then Si must be identical to Ti. * o If type parameter Xi is declared to be covariant ("out") then Si must be convertible * to Ti via an identify conversion, implicit reference conversion, or explicit reference conversion. * o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti, * or Si and Ti must both be reference types. ***************************************************************************************************/ public static bool HasGenericDelegateExplicitReferenceConversion(SymbolLoader loader, CType pSource, CType pTarget) { if (!pSource.isDelegateType() || !pTarget.isDelegateType() || pSource.getAggregate() != pTarget.getAggregate() || loader.HasIdentityOrImplicitReferenceConversion(pSource, pTarget)) { return(false); } TypeArray pTypeParams = pSource.getAggregate().GetTypeVarsAll(); TypeArray pSourceArgs = pSource.AsAggregateType().GetTypeArgsAll(); TypeArray pTargetArgs = pTarget.AsAggregateType().GetTypeArgsAll(); Debug.Assert(pTypeParams.size == pSourceArgs.size); Debug.Assert(pTypeParams.size == pTargetArgs.size); for (int iParam = 0; iParam < pTypeParams.size; ++iParam) { CType pSourceArg = pSourceArgs.Item(iParam); CType pTargetArg = pTargetArgs.Item(iParam); // If they're identical then this one is automatically good, so skip it. // If we have an error type, then we're in some fault tolerance. Let it through. if (pSourceArg == pTargetArg || pTargetArg.IsErrorType() || pSourceArg.IsErrorType()) { continue; } TypeParameterType pParam = pTypeParams.Item(iParam).AsTypeParameterType(); if (pParam.Invariant) { return(false); } if (pParam.Covariant) { if (!FExpRefConv(loader, pSourceArg, pTargetArg)) { return(false); } } else if (pParam.Contravariant) { if (!pSourceArg.IsRefType() || !pTargetArg.IsRefType()) { return(false); } } } return(true); }
private bool HasArrayConversionToInterface(ArrayType pSource, CType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); if (!pSource.IsSZArray) { return(false); } if (!pDest.isInterfaceType()) { return(false); } // * From a single-dimensional array type S[] to IList<T> or IReadOnlyList<T> and their base // interfaces, provided that there is an implicit identity or reference // conversion from S to T. // We only have six interfaces to check. IList<T>, IReadOnlyList<T> and their bases: // * The base interface of IList<T> is ICollection<T>. // * The base interface of ICollection<T> is IEnumerable<T>. // * The base interface of IEnumerable<T> is IEnumerable. // * The base interface of IReadOnlyList<T> is IReadOnlyCollection<T>. // * The base interface of IReadOnlyCollection<T> is IEnumerable<T>. if (pDest.isPredefType(PredefinedType.PT_IENUMERABLE)) { return(true); } AggregateType atsDest = pDest.AsAggregateType(); AggregateSymbol aggDest = pDest.getAggregate(); if (!aggDest.isPredefAgg(PredefinedType.PT_G_ILIST) && !aggDest.isPredefAgg(PredefinedType.PT_G_ICOLLECTION) && !aggDest.isPredefAgg(PredefinedType.PT_G_IENUMERABLE) && !aggDest.isPredefAgg(PredefinedType.PT_G_IREADONLYCOLLECTION) && !aggDest.isPredefAgg(PredefinedType.PT_G_IREADONLYLIST)) { return(false); } Debug.Assert(atsDest.GetTypeArgsAll().Count == 1); CType pSourceElement = pSource.GetElementType(); CType pDestTypeArgument = atsDest.GetTypeArgsAll()[0]; return(HasIdentityOrImplicitReferenceConversion(pSourceElement, pDestTypeArgument)); }
public static IEnumerable <CType> AllPossibleInterfaces(this CType type) { Debug.Assert(type != null); if (type.IsAggregateType()) { foreach (CType t in type.AsAggregateType().TypeAndBaseClassInterfaces()) { yield return(t); } } else if (type.IsTypeParameterType()) { foreach (CType t in type.AsTypeParameterType().GetEffectiveBaseClass().TypeAndBaseClassInterfaces()) { yield return(t); } foreach (CType t in type.AsTypeParameterType().GetInterfaceBounds().AllConstraintInterfaces()) { yield return(t); } } }
private bool IsBaseClass(CType pDerived, CType pBase) { Debug.Assert(pDerived != null); Debug.Assert(pBase != null); // A base class has got to be a class. The derived type might be a struct. if (!pBase.isClassType()) { return(false); } if (pDerived.IsNullableType()) { pDerived = pDerived.AsNullableType().GetAts(ErrorContext); if (pDerived == null) { return(false); } } if (!pDerived.IsAggregateType()) { return(false); } AggregateType atsDer = pDerived.AsAggregateType(); AggregateType atsBase = pBase.AsAggregateType(); AggregateType atsCur = atsDer.GetBaseClass(); while (atsCur != null) { if (atsCur == atsBase) { return(true); } atsCur = atsCur.GetBaseClass(); } return(false); }
private bool bindExplicitConversionFromIListToArray(ArrayType arrayDest) { // 13.2.2 // // The explicit reference conversions are: // // * From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces // to a one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from // S[] to System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T // are the same type or there is an implicit or explicit reference conversion from S to T. if (arrayDest.rank != 1 || !_typeSrc.isInterfaceType() || _typeSrc.AsAggregateType().GetTypeArgsAll().Count != 1) { return(false); } AggregateSymbol aggIList = GetSymbolLoader().GetOptPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = GetSymbolLoader().GetOptPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !GetSymbolLoader().IsBaseAggregate(aggIList, _typeSrc.AsAggregateType().getAggregate())) && (aggIReadOnlyList == null || !GetSymbolLoader().IsBaseAggregate(aggIReadOnlyList, _typeSrc.AsAggregateType().getAggregate()))) { return(false); } CType typeArr = arrayDest.GetElementType(); CType typeLst = _typeSrc.AsAggregateType().GetTypeArgsAll()[0]; Debug.Assert(!typeArr.IsNeverSameType()); if (typeArr != typeLst && !CConversions.FExpRefConv(GetSymbolLoader(), typeArr, typeLst)) { return(false); } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_REFCHECK); } return(true); }
//////////////////////////////////////////////////////////////////////////////// private bool UpperBoundConstructedInference(CType pSource, CType pDest) { if (!pSource.IsAggregateType()) { return false; } AggregateType pConstructedSource = pSource.AsAggregateType(); TypeArray pSourceArgs = pConstructedSource.GetTypeArgsAll(); if (pSourceArgs.size == 0) { return false; } // SPEC: Otherwise, if V is a constructed CType C<V1...Vk> and U is // SPEC: C<U1...Uk> then an exact inference, // SPEC: lower bound inference or upper bound inference // SPEC: is made from each Ui to the corresponding Vi. if (pDest.IsAggregateType() && pConstructedSource.GetOwningAggregate() == pDest.AsAggregateType().GetOwningAggregate()) { if (pDest.isInterfaceType() || pDest.isDelegateType()) { UpperBoundTypeArgumentInference(pConstructedSource, pDest.AsAggregateType()); } else { ExactTypeArgumentInference(pConstructedSource, pDest.AsAggregateType()); } return true; } // SPEC: Otherwise, if U is a class CType C<U1...Uk> and V is a class CType which // SPEC: inherits directly or indirectly from C<V1...Vk> then an exact ... if (UpperBoundClassInference(pConstructedSource, pDest)) { return true; } // SPEC: Otherwise, if U is an interface CType C<U1...Uk> and V is a class CType // SPEC: or struct CType and there is a unique set V1...Vk such that V directly // SPEC: or indirectly implements C<V1...Vk> then an exact ... // SPEC: ... and U is an interface CType ... if (UpperBoundInterfaceInference(pConstructedSource, pDest)) { return true; } return false; }
//////////////////////////////////////////////////////////////////////////////// private bool LowerBoundClassInference(CType pSource, AggregateType pDest) { if (!pDest.isClassType()) { return false; } // SPEC: Otherwise, if V is a class CType C<V1...Vk> and U is a class CType which // SPEC: inherits directly or indirectly from C<U1...Uk> // SPEC: then an exact inference is made from each Ui to the corresponding Vi. // SPEC: Otherwise, if V is a class CType C<V1...Vk> and U is a CType parameter // SPEC: with effective base class C<U1...Uk> // SPEC: then an exact inference is made from each Ui to the corresponding Vi. // SPEC: Otherwise, if V is a class CType C<V1...Vk> and U is a CType parameter // SPEC: with an effective base class which inherits directly or indirectly from // SPEC: C<U1...Uk> then an exact inference is made // SPEC: from each Ui to the corresponding Vi. AggregateType pSourceBase = null; if (pSource.isClassType()) { pSourceBase = pSource.AsAggregateType().GetBaseClass(); } else if (pSource.IsTypeParameterType()) { pSourceBase = pSource.AsTypeParameterType().GetEffectiveBaseClass(); } while (pSourceBase != null) { if (pSourceBase.GetOwningAggregate() == pDest.GetOwningAggregate()) { ExactTypeArgumentInference(pSourceBase, pDest); return true; } pSourceBase = pSourceBase.GetBaseClass(); } return false; }
/*************************************************************************************************** * Determine whether there is an explicit or implicit reference conversion (or identity conversion) * from typeSrc to typeDst. This is when: * * 13.2.3 Explicit reference conversions * * The explicit reference conversions are: * From object to any reference-type. * From any class-type S to any class-type T, provided S is a base class of T. * From any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T. * From any interface-type S to any class-type T, provided T is not sealed or provided T implements S. * From any interface-type S to any interface-type T, provided S is not derived from T. * From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true: * o S and T differ only in element type. (In other words, S and T have the same number of dimensions.) * o An explicit reference conversion exists from SE to TE. * From System.Array and the interfaces it implements, to any array-type. * From System.Delegate and the interfaces it implements, to any delegate-type. * From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces, provided there is an explicit reference conversion from S to T. * From a generic delegate type S to generic delegate type T, provided all of the follow are true: * o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is, * S is D<S1,... Sk> and T is D<T1,... Tk>. * o S is not compatible with or identical to T. * o If type parameter Xi is declared to be invariant then Si must be identical to Ti. * o If type parameter Xi is declared to be covariant ("out") then Si must be convertible * to Ti via an identify conversion, implicit reference conversion, or explicit reference conversion. * o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti, * or Si and Ti must both be reference types. * From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T are the same type or there is an implicit or explicit reference conversion from S to T. * * For a type-parameter T that is known to be a reference type (§25.7), the following explicit reference conversions exist: * From the effective base class C of T to T and from any base class of C to T. * From any interface-type to T. * From T to any interface-type I provided there isn’t already an implicit reference conversion from T to I. * From a type-parameter U to T provided that T depends on U (§25.7). [Note: Since T is known to be a reference type, within the scope of T, the run-time type of U will always be a reference type, even if U is not known to be a reference type at compile-time. end note] * * Both src and dst are reference types and there is a builtin explicit conversion from * src to dst. * Or src is a reference type and dst is a base type of src (in which case the conversion is * implicit as well). * Or dst is a reference type and src is a base type of dst. * * The latter two cases can happen with type variables even though the other type variable is not * a reference type. ***************************************************************************************************/ public static bool FExpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst) { Debug.Assert(typeSrc != null); Debug.Assert(typeDst != null); if (typeSrc.IsRefType() && typeDst.IsRefType()) { // is there an implicit reference conversion in either direction? // this handles the bulk of the cases ... if (loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst) || loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc)) { return(true); } // For a type-parameter T that is known to be a reference type (§25.7), the following explicit reference conversions exist: // • From any interface-type to T. // • From T to any interface-type I provided there isn’t already an implicit reference conversion from T to I. if (typeSrc.isInterfaceType() && typeDst.IsTypeParameterType()) { return(true); } if (typeSrc.IsTypeParameterType() && typeDst.isInterfaceType()) { return(true); } // * From any class-type S to any interface-type T, provided S is not sealed // * From any interface-type S to any class-type T, provided T is not sealed // * From any interface-type S to any interface-type T, provided S is not derived from T. if (typeSrc.IsAggregateType() && typeDst.IsAggregateType()) { AggregateSymbol aggSrc = typeSrc.AsAggregateType().getAggregate(); AggregateSymbol aggDest = typeDst.AsAggregateType().getAggregate(); if ((aggSrc.IsClass() && !aggSrc.IsSealed() && aggDest.IsInterface()) || (aggSrc.IsInterface() && aggDest.IsClass() && !aggDest.IsSealed()) || (aggSrc.IsInterface() && aggDest.IsInterface())) { return(true); } } // * From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true: // o S and T differ only in element type. (In other words, S and T have the same number of dimensions.) // o An explicit reference conversion exists from SE to TE. if (typeSrc.IsArrayType() && typeDst.IsArrayType()) { return(typeSrc.AsArrayType().rank == typeDst.AsArrayType().rank&& FExpRefConv(loader, typeSrc.AsArrayType().GetElementType(), typeDst.AsArrayType().GetElementType())); } // * From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> // and their base interfaces, provided there is an explicit reference conversion from S to T. if (typeSrc.IsArrayType()) { if (typeSrc.AsArrayType().rank != 1 || !typeDst.isInterfaceType() || typeDst.AsAggregateType().GetTypeArgsAll().Size != 1) { return(false); } AggregateSymbol aggIList = loader.GetOptPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = loader.GetOptPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !loader.IsBaseAggregate(aggIList, typeDst.AsAggregateType().getAggregate())) && (aggIReadOnlyList == null || !loader.IsBaseAggregate(aggIReadOnlyList, typeDst.AsAggregateType().getAggregate()))) { return(false); } return(FExpRefConv(loader, typeSrc.AsArrayType().GetElementType(), typeDst.AsAggregateType().GetTypeArgsAll().Item(0))); } if (typeDst.IsArrayType() && typeSrc.IsAggregateType()) { // * From System.Array and the interfaces it implements, to any array-type. if (loader.HasIdentityOrImplicitReferenceConversion(loader.GetReqPredefType(PredefinedType.PT_ARRAY), typeSrc)) { return(true); } // * From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a // one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to // System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T // are the same type or there is an implicit or explicit reference conversion from S to T. ArrayType arrayDest = typeDst.AsArrayType(); AggregateType aggtypeSrc = typeSrc.AsAggregateType(); if (arrayDest.rank != 1 || !typeSrc.isInterfaceType() || aggtypeSrc.GetTypeArgsAll().Size != 1) { return(false); } AggregateSymbol aggIList = loader.GetOptPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = loader.GetOptPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !loader.IsBaseAggregate(aggIList, aggtypeSrc.getAggregate())) && (aggIReadOnlyList == null || !loader.IsBaseAggregate(aggIReadOnlyList, aggtypeSrc.getAggregate()))) { return(false); } CType typeArr = arrayDest.GetElementType(); CType typeLst = aggtypeSrc.GetTypeArgsAll().Item(0); Debug.Assert(!typeArr.IsNeverSameType()); return(typeArr == typeLst || FExpRefConv(loader, typeArr, typeLst)); } if (HasGenericDelegateExplicitReferenceConversion(loader, typeSrc, typeDst)) { return(true); } } else if (typeSrc.IsRefType()) { // conversion of T . U, where T : class, U // .. these constraints implies where U : class return(loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst)); } else if (typeDst.IsRefType()) { // conversion of T . U, where U : class, T // .. these constraints implies where T : class return(loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc)); } return(false); }
public BetterType CompareTypes(TypeArray ta1, TypeArray ta2) { if (ta1 == ta2) { return(BetterType.Same); } if (ta1.Size != ta2.Size) { // The one with more parameters is more specific. return(ta1.Size > ta2.Size ? BetterType.Left : BetterType.Right); } BetterType nTot = BetterType.Neither; for (int i = 0; i < ta1.Size; i++) { CType type1 = ta1.Item(i); CType type2 = ta2.Item(i); BetterType nParam = BetterType.Neither; LAgain: if (type1.GetTypeKind() != type2.GetTypeKind()) { if (type1.IsTypeParameterType()) { nParam = BetterType.Right; } else if (type2.IsTypeParameterType()) { nParam = BetterType.Left; } } else { switch (type1.GetTypeKind()) { default: Debug.Assert(false, "Bad kind in CompareTypes"); break; case TypeKind.TK_TypeParameterType: case TypeKind.TK_ErrorType: break; case TypeKind.TK_PointerType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_ArrayType: case TypeKind.TK_NullableType: type1 = type1.GetBaseOrParameterOrElementType(); type2 = type2.GetBaseOrParameterOrElementType(); goto LAgain; case TypeKind.TK_AggregateType: nParam = CompareTypes(type1.AsAggregateType().GetTypeArgsAll(), type2.AsAggregateType().GetTypeArgsAll()); break; } } if (nParam == BetterType.Right || nParam == BetterType.Left) { if (nTot == BetterType.Same || nTot == BetterType.Neither) { nTot = nParam; } else if (nParam != nTot) { return(BetterType.Neither); } } } return(nTot); }
public static bool TypeContainsType(CType type, CType typeFind) { LRecurse: // Label used for "tail" recursion. if (type == typeFind || type.Equals(typeFind)) return true; switch (type.GetTypeKind()) { default: Debug.Assert(false, "Bad Symbol kind in TypeContainsType"); return false; case TypeKind.TK_NullType: case TypeKind.TK_VoidType: case TypeKind.TK_OpenTypePlaceholderType: // There should only be a single instance of these. Debug.Assert(typeFind.GetTypeKind() != type.GetTypeKind()); return false; case TypeKind.TK_ArrayType: case TypeKind.TK_NullableType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_PointerType: type = type.GetBaseOrParameterOrElementType(); goto LRecurse; case TypeKind.TK_AggregateType: { // BLOCK AggregateType ats = type.AsAggregateType(); for (int i = 0; i < ats.GetTypeArgsAll().Size; i++) { if (TypeContainsType(ats.GetTypeArgsAll().Item(i), typeFind)) return true; } } return false; case TypeKind.TK_ErrorType: if (type.AsErrorType().HasParent()) { ErrorType err = type.AsErrorType(); Debug.Assert(err.nameText != null && err.typeArgs != null); for (int i = 0; i < err.typeArgs.Size; i++) { if (TypeContainsType(err.typeArgs.Item(i), typeFind)) return true; } if (err.HasTypeParent()) { type = err.GetTypeParent(); goto LRecurse; } } return false; case TypeKind.TK_TypeParameterType: return false; } }
private CType SubstTypeCore(CType type, SubstContext pctx) { CType typeSrc; CType typeDst; switch (type.GetTypeKind()) { default: Debug.Assert(false); return type; case TypeKind.TK_NullType: case TypeKind.TK_VoidType: case TypeKind.TK_OpenTypePlaceholderType: case TypeKind.TK_MethodGroupType: case TypeKind.TK_BoundLambdaType: case TypeKind.TK_UnboundLambdaType: case TypeKind.TK_NaturalIntegerType: case TypeKind.TK_ArgumentListType: return type; case TypeKind.TK_ParameterModifierType: typeDst = SubstTypeCore(typeSrc = type.AsParameterModifierType().GetParameterType(), pctx); return (typeDst == typeSrc) ? type : GetParameterModifier(typeDst, type.AsParameterModifierType().isOut); case TypeKind.TK_ArrayType: typeDst = SubstTypeCore(typeSrc = type.AsArrayType().GetElementType(), pctx); return (typeDst == typeSrc) ? type : GetArray(typeDst, type.AsArrayType().rank); case TypeKind.TK_PointerType: typeDst = SubstTypeCore(typeSrc = type.AsPointerType().GetReferentType(), pctx); return (typeDst == typeSrc) ? type : GetPointer(typeDst); case TypeKind.TK_NullableType: typeDst = SubstTypeCore(typeSrc = type.AsNullableType().GetUnderlyingType(), pctx); return (typeDst == typeSrc) ? type : GetNullable(typeDst); case TypeKind.TK_AggregateType: if (type.AsAggregateType().GetTypeArgsAll().size > 0) { AggregateType ats = type.AsAggregateType(); TypeArray typeArgs = SubstTypeArray(ats.GetTypeArgsAll(), pctx); if (ats.GetTypeArgsAll() != typeArgs) return GetAggregate(ats.getAggregate(), typeArgs); } return type; case TypeKind.TK_ErrorType: if (type.AsErrorType().HasParent()) { ErrorType err = type.AsErrorType(); Debug.Assert(err.nameText != null && err.typeArgs != null); CType pParentType = null; if (err.HasTypeParent()) { pParentType = SubstTypeCore(err.GetTypeParent(), pctx); } TypeArray typeArgs = SubstTypeArray(err.typeArgs, pctx); if (typeArgs != err.typeArgs || (err.HasTypeParent() && pParentType != err.GetTypeParent())) { return GetErrorType(pParentType, err.GetNSParent(), err.nameText, typeArgs); } } return type; case TypeKind.TK_TypeParameterType: { TypeParameterSymbol tvs = type.AsTypeParameterType().GetTypeParameterSymbol(); int index = tvs.GetIndexInTotalParameters(); if (tvs.IsMethodTypeParameter()) { if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null) return type; Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters()); if (index < pctx.ctypeMeth) { Debug.Assert(pctx.prgtypeMeth != null); return pctx.prgtypeMeth[index]; } else { return ((pctx.grfst & SubstTypeFlags.NormMeth) != 0 ? GetStdMethTypeVar(index) : type); } } if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null) return type; return index < pctx.ctypeCls ? pctx.prgtypeCls[index] : ((pctx.grfst & SubstTypeFlags.NormClass) != 0 ? GetStdClsTypeVar(index) : type); } } }
private AggregateType GetUserDefinedBinopArgumentType(CType type) { for (; ;) { switch (type.GetTypeKind()) { case TypeKind.TK_NullableType: type = type.StripNubs(); break; case TypeKind.TK_TypeParameterType: type = type.AsTypeParameterType().GetEffectiveBaseClass(); break; case TypeKind.TK_AggregateType: if ((type.isClassType() || type.isStructType()) && !type.AsAggregateType().getAggregate().IsSkipUDOps()) { return type.AsAggregateType(); } return null; default: return null; } } }
private AggregateType GetEnumBinOpType(ExpressionKind ek, CType argType1, CType argType2, out AggregateType ppEnumType) { Debug.Assert(argType1.isEnumType() || argType2.isEnumType()); AggregateType type1 = argType1.AsAggregateType(); AggregateType type2 = argType2.AsAggregateType(); AggregateType typeEnum = type1.isEnumType() ? type1 : type2; Debug.Assert(type1 == typeEnum || type1 == typeEnum.underlyingEnumType()); Debug.Assert(type2 == typeEnum || type2 == typeEnum.underlyingEnumType()); AggregateType typeDst = typeEnum; switch (ek) { case ExpressionKind.EK_BITAND: case ExpressionKind.EK_BITOR: case ExpressionKind.EK_BITXOR: Debug.Assert(type1 == type2); break; case ExpressionKind.EK_ADD: Debug.Assert(type1 != type2); break; case ExpressionKind.EK_SUB: if (type1 == type2) typeDst = typeEnum.underlyingEnumType(); break; default: Debug.Assert(ek.isRelational()); typeDst = GetReqPDT(PredefinedType.PT_BOOL); break; } ppEnumType = typeEnum; return typeDst; }
/* * BindExplicitConversion * * This is a complex routine with complex parameter. Generally, this should * be called through one of the helper methods that insulates you * from the complexity of the interface. This routine handles all the logic * associated with explicit conversions. * * Note that this function calls BindImplicitConversion first, so the main * logic is only concerned with conversions that can be made explicitly, but * not implicitly. */ public bool Bind() { // To test for a standard conversion, call canConvert(exprSrc, typeDest, STANDARDANDCONVERTTYPE.NOUDC) and // canConvert(typeDest, typeSrc, STANDARDANDCONVERTTYPE.NOUDC). Debug.Assert((_flags & CONVERTTYPE.STANDARD) == 0); // 13.2 Explicit conversions // // The following conversions are classified as explicit conversions: // // * All implicit conversions // * Explicit numeric conversions // * Explicit enumeration conversions // * Explicit reference conversions // * Explicit interface conversions // * Unboxing conversions // * Explicit type parameter conversions // * User-defined explicit conversions // * Explicit nullable conversions // * Lifted user-defined explicit conversions // // Explicit conversions can occur in cast expressions (14.6.6). // // The explicit conversions that are not implicit conversions are conversions that cannot be // proven always to succeed, conversions that are known possibly to lose information, and // conversions across domains of types sufficiently different to merit explicit notation. // The set of explicit conversions includes all implicit conversions. // Don't try user-defined conversions now because we'll try them again later. if (_binder.BindImplicitConversion(_exprSrc, _typeSrc, _exprTypeDest, _pDestinationTypeForLambdaErrorReporting, _needsExprDest, out _exprDest, _flags | CONVERTTYPE.ISEXPLICIT)) { return(true); } if (_typeSrc == null || _typeDest == null || _typeSrc.IsErrorType() || _typeDest.IsErrorType() || _typeDest.IsNeverSameType()) { return(false); } if (_typeDest.IsNullableType()) { // This is handled completely by BindImplicitConversion. return(false); } if (_typeSrc.IsNullableType()) { return(bindExplicitConversionFromNub()); } if (bindExplicitConversionFromArrayToIList()) { return(true); } // if we were casting an integral constant to another constant type, // then, if the constant were in range, then the above call would have succeeded. // But it failed, and so we know that the constant is not in range switch (_typeDest.GetTypeKind()) { default: VSFAIL("Bad type kind"); return(false); case TypeKind.TK_VoidType: return(false); // Can't convert to a method group or anon method. case TypeKind.TK_NullType: return(false); // Can never convert TO the null type. case TypeKind.TK_TypeParameterType: if (bindExplicitConversionToTypeVar()) { return(true); } break; case TypeKind.TK_ArrayType: if (bindExplicitConversionToArray(_typeDest.AsArrayType())) { return(true); } break; case TypeKind.TK_PointerType: if (bindExplicitConversionToPointer()) { return(true); } break; case TypeKind.TK_AggregateType: { AggCastResult result = bindExplicitConversionToAggregate(_typeDest.AsAggregateType()); if (result == AggCastResult.Success) { return(true); } if (result == AggCastResult.Abort) { return(false); } break; } } // No built-in conversion was found. Maybe a user-defined conversion? if (0 == (_flags & CONVERTTYPE.NOUDC)) { return(_binder.bindUserDefinedConversion(_exprSrc, _typeSrc, _typeDest, _needsExprDest, out _exprDest, false)); } return(false); }
//////////////////////////////////////////////////////////////////////////////// // For a base call we need to remap from the virtual to the specific override // to invoke. This is also used to map a virtual on pObject (like ToString) to // the specific override when the pObject is a simple type (int, bool, char, // etc). In these cases it is safe to assume that any override won't later be // removed.... We start searching from "typeObj" up the superclass hierarchy // until we find a method with an exact signature match. public static void RemapToOverride(SymbolLoader symbolLoader, SymWithType pswt, CType typeObj) { // For a property/indexer we remap the accessors, not the property/indexer. // Since every event has both accessors we remap the event instead of the accessors. Debug.Assert(pswt && (pswt.Sym.IsMethodSymbol() || pswt.Sym.IsEventSymbol() || pswt.Sym.IsMethodOrPropertySymbol())); Debug.Assert(typeObj != null); // Don't remap static or interface methods. if (typeObj.IsNullableType()) { typeObj = typeObj.AsNullableType().GetAts(symbolLoader.GetErrorContext()); if (typeObj == null) { VSFAIL("Why did GetAts return null?"); return; } } // Don't remap non-virtual members if (!typeObj.IsAggregateType() || typeObj.isInterfaceType() || !pswt.Sym.IsVirtual()) { return; } symbmask_t mask = pswt.Sym.mask(); AggregateType atsObj = typeObj.AsAggregateType(); // Search for an override version of the method. while (atsObj != null && atsObj.getAggregate() != pswt.Sym.parent) { for (Symbol symT = symbolLoader.LookupAggMember(pswt.Sym.name, atsObj.getAggregate(), mask); symT != null; symT = symbolLoader.LookupNextSym(symT, atsObj.getAggregate(), mask)) { if (symT.IsOverride() && (symT.SymBaseVirtual() == pswt.Sym || symT.SymBaseVirtual() == pswt.Sym.SymBaseVirtual())) { pswt.Set(symT, atsObj); return; } } atsObj = atsObj.GetBaseClass(); } }
//////////////////////////////////////////////////////////////////////////////// private bool UpperBoundInterfaceInference(AggregateType pSource, CType pDest) { if (!pSource.isInterfaceType()) { return false; } // SPEC: Otherwise, if U is an interface CType C<U1...Uk> and V is a class CType // SPEC: or struct CType and there is a unique set V1...Vk such that V directly // SPEC: or indirectly implements C<V1...Vk> then an exact ... // SPEC: ... and U is an interface CType ... if (!pDest.isStructType() && !pDest.isClassType() && !pDest.isInterfaceType()) { return false; } var interfaces = pDest.AllPossibleInterfaces(); AggregateType pInterface = null; foreach (AggregateType pCurrent in interfaces) { if (pCurrent.GetOwningAggregate() == pSource.GetOwningAggregate()) { if (pInterface == null) { pInterface = pCurrent; } else if (pInterface != pCurrent) { // Not unique. Bail out. return false; } } } if (pInterface == null) { return false; } UpperBoundTypeArgumentInference(pInterface, pDest.AsAggregateType()); return true; }
//////////////////////////////////////////////////////////////////////////////// // // Output types // private bool DoesOutputTypeContain(EXPR pSource, CType pDest, TypeParameterType pParam) { // SPEC: If E is a method group or an anonymous function and T is a delegate // SPEC: CType or expression tree CType then the return CType of T is an output CType // SPEC: of E with CType T. pDest = pDest.GetDelegateTypeOfPossibleExpression(); if (!pDest.isDelegateType()) { return false; } if (!pSource.isUNBOUNDLAMBDA() && !pSource.isMEMGRP()) { return false; } CType pDelegateReturn = pDest.AsAggregateType().GetDelegateReturnType(GetSymbolLoader()); if (pDelegateReturn == null) { return false; } return TypeManager.TypeContainsType(pDelegateReturn, pParam); }
private bool HasImplicitReferenceConversion(CType pSource, CType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); // The implicit reference conversions are: // * From any reference type to Object. if (pSource.IsRefType() && pDest.isPredefType(PredefinedType.PT_OBJECT)) { return(true); } // * From any class type S to any class type T provided S is derived from T. if (pSource.isClassType() && pDest.isClassType() && IsBaseClass(pSource, pDest)) { return(true); } // ORIGINAL RULES: // // * From any class type S to any interface type T provided S implements T. // if (pSource.isClassType() && pDest.isInterfaceType() && IsBaseInterface(pSource, pDest)) // { // return true; // } // // * from any interface type S to any interface type T, provided S is derived from T. // if (pSource.isInterfaceType() && pDest.isInterfaceType() && IsBaseInterface(pSource, pDest)) // { // return true; // } // VARIANCE EXTENSIONS: // * From any class type S to any interface type T provided S implements an interface // convertible to T. // * From any interface type S to any interface type T provided S implements an interface // convertible to T. // * From any interface type S to any interface type T provided S is not T and S is // an interface convertible to T. if (pSource.isClassType() && pDest.isInterfaceType() && HasAnyBaseInterfaceConversion(pSource, pDest)) { return(true); } if (pSource.isInterfaceType() && pDest.isInterfaceType() && HasAnyBaseInterfaceConversion(pSource, pDest)) { return(true); } if (pSource.isInterfaceType() && pDest.isInterfaceType() && pSource != pDest && HasInterfaceConversion(pSource.AsAggregateType(), pDest.AsAggregateType())) { return(true); } // * From an array type S with an element type SE to an array type T with element type TE // provided that all of the following are true: // * S and T differ only in element type. In other words, S and T have the same number of dimensions. // * Both SE and TE are reference types. // * An implicit reference conversion exists from SE to TE. if (pSource.IsArrayType() && pDest.IsArrayType() && HasCovariantArrayConversion(pSource.AsArrayType(), pDest.AsArrayType())) { return(true); } // * From any array type to System.Array or any interface implemented by System.Array. if (pSource.IsArrayType() && (pDest.isPredefType(PredefinedType.PT_ARRAY) || IsBaseInterface(GetReqPredefType(PredefinedType.PT_ARRAY, false), pDest))) { return(true); } // * From a single-dimensional array type S[] to IList<T> and its base // interfaces, provided that there is an implicit identity or reference // conversion from S to T. if (pSource.IsArrayType() && HasArrayConversionToInterface(pSource.AsArrayType(), pDest)) { return(true); } // * From any delegate type to System.Delegate // // SPEC OMISSION: // // The spec should actually say // // * From any delegate type to System.Delegate // * From any delegate type to System.MulticastDelegate // * From any delegate type to any interface implemented by System.MulticastDelegate if (pSource.isDelegateType() && (pDest.isPredefType(PredefinedType.PT_MULTIDEL) || pDest.isPredefType(PredefinedType.PT_DELEGATE) || IsBaseInterface(GetReqPredefType(PredefinedType.PT_MULTIDEL, false), pDest))) { return(true); } // VARIANCE EXTENSION: // * From any delegate type S to a delegate type T provided S is not T and // S is a delegate convertible to T if (pSource.isDelegateType() && pDest.isDelegateType() && HasDelegateConversion(pSource.AsAggregateType(), pDest.AsAggregateType())) { return(true); } // * From the null literal to any reference type // NOTE: We extend the specification here. The C# 3.0 spec does not describe // a "null type". Rather, it says that the null literal is typeless, and is // convertible to any reference or nullable type. However, the C# 2.0 and 3.0 // implementations have a "null type" which some expressions other than the // null literal may have. (For example, (null??null), which is also an // extension to the specification.) if (pSource.IsNullType() && pDest.IsRefType()) { return(true); } if (pSource.IsNullType() && pDest.IsNullableType()) { return(true); } // * Implicit conversions involving type parameters that are known to be reference types. if (pSource.IsTypeParameterType() && HasImplicitReferenceTypeParameterConversion(pSource.AsTypeParameterType(), pDest)) { return(true); } return(false); }
// Check the constraints of any type arguments in the given Type. public static bool CheckConstraints(CSemanticChecker checker, ErrorHandling errHandling, CType type, CheckConstraintsFlags flags) { type = type.GetNakedType(false); if (type.IsNullableType()) { CType typeT = type.AsNullableType().GetAts(checker.GetErrorContext()); if (typeT != null) { type = typeT; } else { type = type.GetNakedType(true); } } if (!type.IsAggregateType()) { return(true); } AggregateType ats = type.AsAggregateType(); if (ats.GetTypeArgsAll().Count == 0) { // Common case: there are no type vars, so there are no constraints. ats.fConstraintsChecked = true; ats.fConstraintError = false; return(true); } if (ats.fConstraintsChecked) { // Already checked. if (!ats.fConstraintError || (flags & CheckConstraintsFlags.NoDupErrors) != 0) { // No errors or no need to report errors again. return(!ats.fConstraintError); } } TypeArray typeVars = ats.getAggregate().GetTypeVars(); TypeArray typeArgsThis = ats.GetTypeArgsThis(); TypeArray typeArgsAll = ats.GetTypeArgsAll(); Debug.Assert(typeVars.Count == typeArgsThis.Count); if (!ats.fConstraintsChecked) { ats.fConstraintsChecked = true; ats.fConstraintError = false; } // Check the outer type first. If CheckConstraintsFlags.Outer is not specified and the // outer type has already been checked then don't bother checking it. if (ats.outerType != null && ((flags & CheckConstraintsFlags.Outer) != 0 || !ats.outerType.fConstraintsChecked)) { CheckConstraints(checker, errHandling, ats.outerType, flags); ats.fConstraintError |= ats.outerType.fConstraintError; } if (typeVars.Count > 0) { ats.fConstraintError |= !CheckConstraintsCore(checker, errHandling, ats.getAggregate(), typeVars, typeArgsThis, typeArgsAll, null, (flags & CheckConstraintsFlags.NoErrors)); } // Now check type args themselves. for (int i = 0; i < typeArgsThis.Count; i++) { CType arg = typeArgsThis[i].GetNakedType(true); if (arg.IsAggregateType() && !arg.AsAggregateType().fConstraintsChecked) { CheckConstraints(checker, errHandling, arg.AsAggregateType(), flags | CheckConstraintsFlags.Outer); if (arg.AsAggregateType().fConstraintError) { ats.fConstraintError = true; } } } return(!ats.fConstraintError); }
private static Type CalculateAssociatedSystemType(CType src) { Type result = null; switch (src.GetTypeKind()) { case TypeKind.TK_ArrayType: ArrayType a = src.AsArrayType(); Type elementType = a.GetElementType().AssociatedSystemType; if (a.rank == 1) { result = elementType.MakeArrayType(); } else { result = elementType.MakeArrayType(a.rank); } break; case TypeKind.TK_NullableType: NullableType n = src.AsNullableType(); Type underlyingType = n.GetUnderlyingType().AssociatedSystemType; result = typeof(Nullable <>).MakeGenericType(underlyingType); break; case TypeKind.TK_PointerType: PointerType p = src.AsPointerType(); Type referentType = p.GetReferentType().AssociatedSystemType; result = referentType.MakePointerType(); break; case TypeKind.TK_ParameterModifierType: ParameterModifierType r = src.AsParameterModifierType(); Type parameterType = r.GetParameterType().AssociatedSystemType; result = parameterType.MakeByRefType(); break; case TypeKind.TK_AggregateType: result = CalculateAssociatedSystemTypeForAggregate(src.AsAggregateType()); break; case TypeKind.TK_TypeParameterType: TypeParameterType t = src.AsTypeParameterType(); Type parentType = null; if (t.IsMethodTypeParameter()) { MethodInfo meth = t.GetOwningSymbol().AsMethodSymbol().AssociatedMemberInfo as MethodInfo; result = meth.GetGenericArguments()[t.GetIndexInOwnParameters()]; } else { parentType = t.GetOwningSymbol().AsAggregateSymbol().AssociatedSystemType; result = parentType.GetTypeInfo().GenericTypeParameters[t.GetIndexInOwnParameters()]; } break; case TypeKind.TK_ArgumentListType: case TypeKind.TK_BoundLambdaType: case TypeKind.TK_ErrorType: case TypeKind.TK_MethodGroupType: case TypeKind.TK_NaturalIntegerType: case TypeKind.TK_NullType: case TypeKind.TK_OpenTypePlaceholderType: case TypeKind.TK_UnboundLambdaType: case TypeKind.TK_VoidType: default: break; } Debug.Assert(result != null || src.GetTypeKind() == TypeKind.TK_AggregateType); return(result); }
public bool SubstEqualTypesCore(CType typeDst, CType typeSrc, SubstContext pctx) { LRecurse: // Label used for "tail" recursion. if (typeDst == typeSrc || typeDst.Equals(typeSrc)) { return true; } switch (typeSrc.GetTypeKind()) { default: Debug.Assert(false, "Bad Symbol kind in SubstEqualTypesCore"); return false; case TypeKind.TK_NullType: case TypeKind.TK_VoidType: case TypeKind.TK_OpenTypePlaceholderType: // There should only be a single instance of these. Debug.Assert(typeDst.GetTypeKind() != typeSrc.GetTypeKind()); return false; case TypeKind.TK_ArrayType: if (typeDst.GetTypeKind() != TypeKind.TK_ArrayType || typeDst.AsArrayType().rank != typeSrc.AsArrayType().rank) return false; goto LCheckBases; case TypeKind.TK_ParameterModifierType: if (typeDst.GetTypeKind() != TypeKind.TK_ParameterModifierType || ((pctx.grfst & SubstTypeFlags.NoRefOutDifference) == 0 && typeDst.AsParameterModifierType().isOut != typeSrc.AsParameterModifierType().isOut)) return false; goto LCheckBases; case TypeKind.TK_PointerType: case TypeKind.TK_NullableType: if (typeDst.GetTypeKind() != typeSrc.GetTypeKind()) return false; LCheckBases: typeSrc = typeSrc.GetBaseOrParameterOrElementType(); typeDst = typeDst.GetBaseOrParameterOrElementType(); goto LRecurse; case TypeKind.TK_AggregateType: if (typeDst.GetTypeKind() != TypeKind.TK_AggregateType) return false; { // BLOCK AggregateType atsSrc = typeSrc.AsAggregateType(); AggregateType atsDst = typeDst.AsAggregateType(); if (atsSrc.getAggregate() != atsDst.getAggregate()) return false; Debug.Assert(atsSrc.GetTypeArgsAll().Size == atsDst.GetTypeArgsAll().Size); // All the args must unify. for (int i = 0; i < atsSrc.GetTypeArgsAll().Size; i++) { if (!SubstEqualTypesCore(atsDst.GetTypeArgsAll().Item(i), atsSrc.GetTypeArgsAll().Item(i), pctx)) return false; } } return true; case TypeKind.TK_ErrorType: if (!typeDst.IsErrorType() || !typeSrc.AsErrorType().HasParent() || !typeDst.AsErrorType().HasParent()) return false; { ErrorType errSrc = typeSrc.AsErrorType(); ErrorType errDst = typeDst.AsErrorType(); Debug.Assert(errSrc.nameText != null && errSrc.typeArgs != null); Debug.Assert(errDst.nameText != null && errDst.typeArgs != null); if (errSrc.nameText != errDst.nameText || errSrc.typeArgs.Size != errDst.typeArgs.Size) return false; if (errSrc.HasTypeParent() != errDst.HasTypeParent()) { return false; } if (errSrc.HasTypeParent()) { if (errSrc.GetTypeParent() != errDst.GetTypeParent()) { return false; } if (!SubstEqualTypesCore(errDst.GetTypeParent(), errSrc.GetTypeParent(), pctx)) { return false; } } else { if (errSrc.GetNSParent() != errDst.GetNSParent()) { return false; } } // All the args must unify. for (int i = 0; i < errSrc.typeArgs.Size; i++) { if (!SubstEqualTypesCore(errDst.typeArgs.Item(i), errSrc.typeArgs.Item(i), pctx)) return false; } } return true; case TypeKind.TK_TypeParameterType: { // BLOCK TypeParameterSymbol tvs = typeSrc.AsTypeParameterType().GetTypeParameterSymbol(); int index = tvs.GetIndexInTotalParameters(); if (tvs.IsMethodTypeParameter()) { if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null) { // typeDst == typeSrc was handled above. Debug.Assert(typeDst != typeSrc); return false; } Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters()); Debug.Assert(pctx.prgtypeMeth == null || tvs.GetIndexInTotalParameters() < pctx.ctypeMeth); if (index < pctx.ctypeMeth && pctx.prgtypeMeth != null) { return typeDst == pctx.prgtypeMeth[index]; } if ((pctx.grfst & SubstTypeFlags.NormMeth) != 0) { return typeDst == GetStdMethTypeVar(index); } } else { if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null) { // typeDst == typeSrc was handled above. Debug.Assert(typeDst != typeSrc); return false; } Debug.Assert(pctx.prgtypeCls == null || tvs.GetIndexInTotalParameters() < pctx.ctypeCls); if (index < pctx.ctypeCls) return typeDst == pctx.prgtypeCls[index]; if ((pctx.grfst & SubstTypeFlags.NormClass) != 0) return typeDst == GetStdClsTypeVar(index); } } return false; } }
private bool HasAnyBaseInterfaceConversion(CType pDerived, CType pBase) { if (!pBase.isInterfaceType()) { return false; } if (!pDerived.IsAggregateType()) { return false; } AggregateType atsDer = pDerived.AsAggregateType(); while (atsDer != null) { TypeArray ifacesAll = atsDer.GetIfacesAll(); for (int i = 0; i < ifacesAll.size; i++) { if (HasInterfaceConversion(ifacesAll.Item(i).AsAggregateType(), pBase.AsAggregateType())) { return true; } } atsDer = atsDer.GetBaseClass(); } return false; }
public static bool TypeContainsTyVars(CType type, TypeArray typeVars) { LRecurse: // Label used for "tail" recursion. switch (type.GetTypeKind()) { default: Debug.Assert(false, "Bad Symbol kind in TypeContainsTyVars"); return false; case TypeKind.TK_UnboundLambdaType: case TypeKind.TK_BoundLambdaType: case TypeKind.TK_NullType: case TypeKind.TK_VoidType: case TypeKind.TK_OpenTypePlaceholderType: case TypeKind.TK_MethodGroupType: return false; case TypeKind.TK_ArrayType: case TypeKind.TK_NullableType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_PointerType: type = type.GetBaseOrParameterOrElementType(); goto LRecurse; case TypeKind.TK_AggregateType: { // BLOCK AggregateType ats = type.AsAggregateType(); for (int i = 0; i < ats.GetTypeArgsAll().Size; i++) { if (TypeContainsTyVars(ats.GetTypeArgsAll().Item(i), typeVars)) { return true; } } } return false; case TypeKind.TK_ErrorType: if (type.AsErrorType().HasParent()) { ErrorType err = type.AsErrorType(); Debug.Assert(err.nameText != null && err.typeArgs != null); for (int i = 0; i < err.typeArgs.Size; i++) { if (TypeContainsTyVars(err.typeArgs.Item(i), typeVars)) { return true; } } if (err.HasTypeParent()) { type = err.GetTypeParent(); goto LRecurse; } } return false; case TypeKind.TK_TypeParameterType: if (typeVars != null && typeVars.Size > 0) { int ivar = type.AsTypeParameterType().GetIndexInTotalParameters(); return ivar < typeVars.Size && type == typeVars.Item(ivar); } return true; } }
//////////////////////////////////////////////////////////////////////////////// private bool MethodGroupReturnTypeInference(EXPR pSource, CType pType) { // SPEC: Otherwise, if E is a method group and T is a delegate CType or // SPEC: expression tree CType with parameter types T1...Tk and return // SPEC: CType Tb and overload resolution of E with the types T1...Tk // SPEC: yields a single method with return CType U then a lower-bound // SPEC: inference is made from U to Tb. if (!pSource.isMEMGRP()) { return false; } pType = pType.GetDelegateTypeOfPossibleExpression(); if (!pType.isDelegateType()) { return false; } AggregateType pDelegateType = pType.AsAggregateType(); CType pDelegateReturnType = pDelegateType.GetDelegateReturnType(GetSymbolLoader()); if (pDelegateReturnType == null) { return false; } if (pDelegateReturnType.IsVoidType()) { return false; } // At this point we are in the second phase; we know that all the input types are fixed. TypeArray pDelegateParameters = GetFixedDelegateParameters(pDelegateType); if (pDelegateParameters == null) { return false; } ArgInfos argInfo = new ArgInfos() { carg = pDelegateParameters.size, types = pDelegateParameters, fHasExprs = false, prgexpr = null }; var argsBinder = new ExpressionBinder.GroupToArgsBinder(_binder, 0/* flags */, pSource.asMEMGRP(), argInfo, null, false, pDelegateType); bool success = argsBinder.Bind(false); if (!success) { return false; } MethPropWithInst mwi = argsBinder.GetResultsOfBind().GetBestResult(); CType pMethodReturnType = GetTypeManager().SubstType(mwi.Meth().RetType, mwi.GetType(), mwi.TypeArgs); if (pMethodReturnType.IsVoidType()) { return false; } LowerBoundInference(pMethodReturnType, pDelegateReturnType); return true; }
private static Type CalculateAssociatedSystemType(CType src) { Type result = null; switch (src.GetTypeKind()) { case TypeKind.TK_ArrayType: ArrayType a = src.AsArrayType(); Type elementType = a.GetElementType().AssociatedSystemType; if (a.rank == 1) { result = elementType.MakeArrayType(); } else { result = elementType.MakeArrayType(a.rank); } break; case TypeKind.TK_NullableType: NullableType n = src.AsNullableType(); Type underlyingType = n.GetUnderlyingType().AssociatedSystemType; result = typeof(Nullable<>).MakeGenericType(underlyingType); break; case TypeKind.TK_PointerType: PointerType p = src.AsPointerType(); Type referentType = p.GetReferentType().AssociatedSystemType; result = referentType.MakePointerType(); break; case TypeKind.TK_ParameterModifierType: ParameterModifierType r = src.AsParameterModifierType(); Type parameterType = r.GetParameterType().AssociatedSystemType; result = parameterType.MakeByRefType(); break; case TypeKind.TK_AggregateType: result = CalculateAssociatedSystemTypeForAggregate(src.AsAggregateType()); break; case TypeKind.TK_TypeParameterType: TypeParameterType t = src.AsTypeParameterType(); if (t.IsMethodTypeParameter()) { MethodInfo meth = t.GetOwningSymbol().AsMethodSymbol().AssociatedMemberInfo as MethodInfo; result = meth.GetGenericArguments()[t.GetIndexInOwnParameters()]; } else { Type parentType = t.GetOwningSymbol().AsAggregateSymbol().AssociatedSystemType; result = parentType.GetTypeInfo().GenericTypeParameters[t.GetIndexInOwnParameters()]; } break; case TypeKind.TK_ArgumentListType: case TypeKind.TK_BoundLambdaType: case TypeKind.TK_ErrorType: case TypeKind.TK_MethodGroupType: case TypeKind.TK_NaturalIntegerType: case TypeKind.TK_NullType: case TypeKind.TK_OpenTypePlaceholderType: case TypeKind.TK_UnboundLambdaType: case TypeKind.TK_VoidType: default: break; } Debug.Assert(result != null || src.GetTypeKind() == TypeKind.TK_AggregateType); return result; }
//////////////////////////////////////////////////////////////////////////////// private bool LowerBoundArrayInference(CType pSource, CType pDest) { // SPEC: Otherwise, if U is an array CType Ue[...] and V is either an array // SPEC: CType Ve[...] of the same rank, or if U is a one-dimensional array // SPEC: CType Ue[] and V is one of IEnumerable<Ve>, ICollection<Ve>, // SPEC: IList<Ve>, IReadOnlyCollection<Ve> or IReadOnlyList<Ve> then // SPEC: if Ue is known to be a reference CType then a lower-bound inference // SPEC: from Ue to Ve is made. // SPEC: otherwise an exact inference from Ue to Ve is made. // Consider the following: // // abstract class B<T> { public abstract M<U>(U u) : where U : T; } // class D : B<int[]> { // static void M<X>(X[] x) { } // public override M<U>(U u) { M(u); } // should infer M<int> // } if (pSource.IsTypeParameterType()) { pSource = pSource.AsTypeParameterType().GetEffectiveBaseClass(); } if (!pSource.IsArrayType()) { return false; } ArrayType pArraySource = pSource.AsArrayType(); CType pElementSource = pArraySource.GetElementType(); CType pElementDest = null; if (pDest.IsArrayType()) { ArrayType pArrayDest = pDest.AsArrayType(); if (pArrayDest.rank != pArraySource.rank) { return false; } pElementDest = pArrayDest.GetElementType(); } else if (pDest.isPredefType(PredefinedType.PT_G_IENUMERABLE) || pDest.isPredefType(PredefinedType.PT_G_ICOLLECTION) || pDest.isPredefType(PredefinedType.PT_G_ILIST) || pDest.isPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION) || pDest.isPredefType(PredefinedType.PT_G_IREADONLYLIST)) { if (pArraySource.rank != 1) { return false; } AggregateType pAggregateDest = pDest.AsAggregateType(); pElementDest = pAggregateDest.GetTypeArgsThis().Item(0); } else { return false; } if (pElementSource.IsRefType()) { LowerBoundInference(pElementSource, pElementDest); } else { ExactInference(pElementSource, pElementDest); } return true; }
private static bool CheckSingleConstraint(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags) { bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors); if (arg.IsOpenTypePlaceholderType()) { return true; } if (arg.IsErrorType()) { // Error should have been reported previously. return false; } if (checker.CheckBogus(arg)) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_BogusType, arg); } return false; } if (arg.IsPointerType() || arg.isSpecialByRefType()) { if (fReportErrors) { errHandling.Error(ErrorCode.ERR_BadTypeArgument, arg); } return false; } if (arg.isStaticClass()) { if (fReportErrors) { checker.ReportStaticClassError(null, arg, ErrorCode.ERR_GenericArgIsStaticClass); } return false; } bool fError = false; if (var.HasRefConstraint() && !arg.IsRefType()) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } fError = true; } TypeArray bnds = checker.GetSymbolLoader().GetTypeManager().SubstTypeArray(var.GetBounds(), typeArgsCls, typeArgsMeth); int itypeMin = 0; if (var.HasValConstraint()) { // If we have a type variable that is constrained to a value type, then we // want to check if its a nullable type, so that we can report the // constraint error below. In order to do this however, we need to check // that either the type arg is not a value type, or it is a nullable type. // // To check whether or not its a nullable type, we need to get the resolved // bound from the type argument and check against that. bool bIsValueType = arg.IsValType(); bool bIsNullable = arg.IsNullableType(); if (bIsValueType && arg.IsTypeParameterType()) { TypeArray pArgBnds = arg.AsTypeParameterType().GetBounds(); if (pArgBnds.size > 0) { bIsNullable = pArgBnds.Item(0).IsNullableType(); } } if (!bIsValueType || bIsNullable) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } fError = true; } // Since FValCon() is set it is redundant to check System.ValueType as well. if (bnds.size != 0 && bnds.Item(0).isPredefType(PredefinedType.PT_VALUE)) { itypeMin = 1; } } for (int j = itypeMin; j < bnds.size; j++) { CType typeBnd = bnds.Item(j); if (!SatisfiesBound(checker, arg, typeBnd)) { if (fReportErrors) { // The bound isn't satisfied because of a constaint type. Explain to the user why not. // There are 4 main cases, based on the type of the supplied type argument: // - reference type, or type parameter known to be a reference type // - nullable type, from which there is a boxing conversion to the constraint type(see below for details) // - type varaiable // - value type // These cases are broken out because: a) The sets of conversions which can be used // for constraint satisfaction is different based on the type argument supplied, // and b) Nullable is one funky type, and user's can use all the help they can get // when using it. ErrorCode error; if (arg.IsRefType()) { // A reference type can only satisfy bounds to types // to which they have an implicit reference conversion error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType; } else if (arg.IsNullableType() && checker.GetSymbolLoader().HasBaseConversion(arg.AsNullableType().GetUnderlyingType(), typeBnd)) // This is inlining FBoxingConv { // nullable types do not satisfy bounds to every type that they are boxable to // They only satisfy bounds of object and ValueType if (typeBnd.isPredefType(PredefinedType.PT_ENUM) || arg.AsNullableType().GetUnderlyingType() == typeBnd) { // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum // even though the conversion from Nullable to these types is a boxing conversion // This is a rare case, because these bounds can never be directly stated ... // These bounds can only occur when one type paramter is constrained to a second type parameter // and the second type parameter is instantiated with Enum or the underlying type of the first type // parameter error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum; } else { // Nullable types don't satisfy the bounds of any interface type // even when there is a boxing conversion from the Nullable type to // the interface type. This will be a relatively common scenario // so we cal it out separately from the previous case. Debug.Assert(typeBnd.isInterfaceType()); error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface; } } else if (arg.IsTypeParameterType()) { // Type variables can satisfy bounds through boxing and type variable conversions Debug.Assert(!arg.IsRefType()); error = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar; } else { // Value types can only satisfy bounds through boxing conversions. // Note that the exceptional case of Nullable types and boxing is handled above. error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType; } errHandling.Error(error, new ErrArgRef(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArgRef(arg, ErrArgFlags.Unique)); } fError = true; } } // Check the newable constraint. if (!var.HasNewConstraint() || arg.IsValType()) { return !fError; } if (arg.isClassType()) { AggregateSymbol agg = arg.AsAggregateType().getAggregate(); // Due to late binding nature of IDE created symbols, the AggregateSymbol might not // have all the information necessary yet, if it is not fully bound. // by calling LookupAggMember, it will ensure that we will update all the // information necessary at least for the given method. checker.GetSymbolLoader().LookupAggMember(checker.GetNameManager().GetPredefName(PredefinedName.PN_CTOR), agg, symbmask_t.MASK_ALL); if (agg.HasPubNoArgCtor() && !agg.IsAbstract()) { return !fError; } } else if (arg.IsTypeParameterType() && arg.AsTypeParameterType().HasNewConstraint()) { return !fError; } if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_NewConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } return false; }
// Check the constraints of any type arguments in the given Type. public static bool CheckConstraints(CSemanticChecker checker, ErrorHandling errHandling, CType type, CheckConstraintsFlags flags) { type = type.GetNakedType(false); if (type.IsNullableType()) { CType typeT = type.AsNullableType().GetAts(checker.GetErrorContext()); if (typeT != null) type = typeT; else type = type.GetNakedType(true); } if (!type.IsAggregateType()) return true; AggregateType ats = type.AsAggregateType(); if (ats.GetTypeArgsAll().size == 0) { // Common case: there are no type vars, so there are no constraints. ats.fConstraintsChecked = true; ats.fConstraintError = false; return true; } if (ats.fConstraintsChecked) { // Already checked. if (!ats.fConstraintError || (flags & CheckConstraintsFlags.NoDupErrors) != 0) { // No errors or no need to report errors again. return !ats.fConstraintError; } } TypeArray typeVars = ats.getAggregate().GetTypeVars(); TypeArray typeArgsThis = ats.GetTypeArgsThis(); TypeArray typeArgsAll = ats.GetTypeArgsAll(); Debug.Assert(typeVars.size == typeArgsThis.size); if (!ats.fConstraintsChecked) { ats.fConstraintsChecked = true; ats.fConstraintError = false; } // Check the outer type first. If CheckConstraintsFlags.Outer is not specified and the // outer type has already been checked then don't bother checking it. if (ats.outerType != null && ((flags & CheckConstraintsFlags.Outer) != 0 || !ats.outerType.fConstraintsChecked)) { CheckConstraints(checker, errHandling, ats.outerType, flags); ats.fConstraintError |= ats.outerType.fConstraintError; } if (typeVars.size > 0) ats.fConstraintError |= !CheckConstraintsCore(checker, errHandling, ats.getAggregate(), typeVars, typeArgsThis, typeArgsAll, null, (flags & CheckConstraintsFlags.NoErrors)); // Now check type args themselves. for (int i = 0; i < typeArgsThis.size; i++) { CType arg = typeArgsThis.Item(i).GetNakedType(true); if (arg.IsAggregateType() && !arg.AsAggregateType().fConstraintsChecked) { CheckConstraints(checker, errHandling, arg.AsAggregateType(), flags | CheckConstraintsFlags.Outer); if (arg.AsAggregateType().fConstraintError) ats.fConstraintError = true; } } return !ats.fConstraintError; }
/* * BindImplicitConversion * * This is a complex routine with complex parameters. Generally, this should * be called through one of the helper methods that insulates you * from the complexity of the interface. This routine handles all the logic * associated with implicit conversions. * * exprSrc - the expression being converted. Can be null if only type conversion * info is being supplied. * typeSrc - type of the source * typeDest - type of the destination * exprDest - returns an expression of the src converted to the dest. If null, we * only care about whether the conversion can be attempted, not the * expression tree. * flags - flags possibly customizing the conversions allowed. E.g., can suppress * user-defined conversions. * * returns true if the conversion can be made, false if not. */ public bool Bind() { // 13.1 Implicit conversions // // The following conversions are classified as implicit conversions: // // * Identity conversions // * Implicit numeric conversions // * Implicit enumeration conversions // * Implicit reference conversions // * Boxing conversions // * Implicit type parameter conversions // * Implicit constant expression conversions // * User-defined implicit conversions // * Implicit conversions from an anonymous method expression to a compatible delegate type // * Implicit conversion from a method group to a compatible delegate type // * Conversions from the null type (11.2.7) to any nullable type // * Implicit nullable conversions // * Lifted user-defined implicit conversions // // Implicit conversions can occur in a variety of situations, including function member invocations // (14.4.3), cast expressions (14.6.6), and assignments (14.14). // Can't convert to or from the error type. if (typeSrc == null || typeDest == null || typeDest.IsNeverSameType()) { return(false); } Debug.Assert(typeSrc != null && typeDest != null); // types must be supplied. Debug.Assert(exprSrc == null || typeSrc == exprSrc.type); // type of source should be correct if source supplied Debug.Assert(!needsExprDest || exprSrc != null); // need source expr to create dest expr switch (typeDest.GetTypeKind()) { case TypeKind.TK_ErrorType: Debug.Assert(typeDest.AsErrorType().HasTypeParent() || typeDest.AsErrorType().HasNSParent()); if (typeSrc != typeDest) { return(false); } if (needsExprDest) { exprDest = exprSrc; } return(true); case TypeKind.TK_NullType: // Can only convert to the null type if src is null. if (!typeSrc.IsNullType()) { return(false); } if (needsExprDest) { exprDest = exprSrc; } return(true); case TypeKind.TK_MethodGroupType: VSFAIL("Something is wrong with Type.IsNeverSameType()"); return(false); case TypeKind.TK_NaturalIntegerType: case TypeKind.TK_ArgumentListType: return(typeSrc == typeDest); case TypeKind.TK_VoidType: return(false); default: break; } if (typeSrc.IsErrorType()) { Debug.Assert(!typeDest.IsErrorType()); return(false); } // 13.1.1 Identity conversion // // An identity conversion converts from any type to the same type. This conversion exists only // such that an entity that already has a required type can be said to be convertible to that type. if (typeSrc == typeDest && ((flags & CONVERTTYPE.ISEXPLICIT) == 0 || (!typeSrc.isPredefType(PredefinedType.PT_FLOAT) && !typeSrc.isPredefType(PredefinedType.PT_DOUBLE)))) { if (needsExprDest) { exprDest = exprSrc; } return(true); } if (typeDest.IsNullableType()) { return(BindNubConversion(typeDest.AsNullableType())); } if (typeSrc.IsNullableType()) { return(bindImplicitConversionFromNullable(typeSrc.AsNullableType())); } if ((flags & CONVERTTYPE.ISEXPLICIT) != 0) { flags |= CONVERTTYPE.NOUDC; } // Get the fundamental types of destination. FUNDTYPE ftDest = typeDest.fundType(); Debug.Assert(ftDest != FUNDTYPE.FT_NONE || typeDest.IsParameterModifierType()); switch (typeSrc.GetTypeKind()) { default: VSFAIL("Bad type symbol kind"); break; case TypeKind.TK_MethodGroupType: if (exprSrc.isMEMGRP()) { EXPRCALL outExpr; bool retVal = binder.BindGrpConversion(exprSrc.asMEMGRP(), typeDest, needsExprDest, out outExpr, false); exprDest = outExpr; return(retVal); } return(false); case TypeKind.TK_VoidType: case TypeKind.TK_ErrorType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_ArgumentListType: return(false); case TypeKind.TK_NullType: if (bindImplicitConversionFromNull()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_ArrayType: if (bindImplicitConversionFromArray()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_PointerType: if (bindImplicitConversionFromPointer()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_TypeParameterType: if (bindImplicitConversionFromTypeVar(typeSrc.AsTypeParameterType())) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_AggregateType: // TypeReference and ArgIterator can't be boxed (or converted to anything else) if (typeSrc.isSpecialByRefType()) { return(false); } if (bindImplicitConversionFromAgg(typeSrc.AsAggregateType())) { return(true); } // If not, try user defined implicit conversions. break; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // RUNTIME BINDER ONLY CHANGE // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // Every incoming dynamic operand should be implicitly convertible // to any type that it is an instance of. if (exprSrc != null && exprSrc.RuntimeObject != null && typeDest.AssociatedSystemType.IsInstanceOfType(exprSrc.RuntimeObject) && binder.GetSemanticChecker().CheckTypeAccess(typeDest, binder.Context.ContextForMemberLookup())) { if (needsExprDest) { binder.bindSimpleCast(exprSrc, exprTypeDest, out exprDest, exprSrc.flags & EXPRFLAG.EXF_CANTBENULL); } return(true); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // END RUNTIME BINDER ONLY CHANGE // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // 13.1.8 User-defined implicit conversions // // A user-defined implicit conversion consists of an optional standard implicit conversion, // followed by execution of a user-defined implicit conversion operator, followed by another // optional standard implicit conversion. The exact rules for evaluating user-defined // conversions are described in 13.4.3. if (0 == (flags & CONVERTTYPE.NOUDC)) { return(binder.bindUserDefinedConversion(exprSrc, typeSrc, typeDest, needsExprDest, out exprDest, true)); } // No conversion was found. return(false); }
private bool DoesTypeArgumentsContainErrorSym(CType var) { if (!var.IsAggregateType()) { return false; } TypeArray typeVars = var.AsAggregateType().GetTypeArgsAll(); for (int i = 0; i < typeVars.size; i++) { CType type = typeVars.Item(i); if (type.IsErrorType()) { return true; } else if (type.IsAggregateType()) { // If we have an agg type sym, check if its type args have errors. if (DoesTypeArgumentsContainErrorSym(type)) { return true; } } } return false; }
//////////////////////////////////////////////////////////////////////////////// private bool ExactConstructedInference(CType pSource, CType pDest) { // SPEC: Otherwise, if V is a constructed CType C<V1...Vk> and U is a constructed // SPEC: CType C<U1...Uk> then an exact inference // SPEC: is made from each Ui to the corresponding Vi. if (!pSource.IsAggregateType() || !pDest.IsAggregateType()) { return false; } AggregateType pConstructedSource = pSource.AsAggregateType(); AggregateType pConstructedDest = pDest.AsAggregateType(); if (pConstructedSource.GetOwningAggregate() != pConstructedDest.GetOwningAggregate()) { return false; } ExactTypeArgumentInference(pConstructedSource, pConstructedDest); return true; }
///////////////////////////////////////////////////////////////////////////////// public static MethodOrPropertySymbol FindMostDerivedMethod( SymbolLoader symbolLoader, MethodOrPropertySymbol pMethProp, CType pType) { MethodSymbol method; bool bIsIndexer = false; if (pMethProp.IsMethodSymbol()) { method = pMethProp.AsMethodSymbol(); } else { PropertySymbol prop = pMethProp.AsPropertySymbol(); method = prop.methGet != null ? prop.methGet : prop.methSet; if (method == null) { return null; } bIsIndexer = prop.isIndexer(); } if (!method.isVirtual) { return method; } if (pType == null) { // This must be a static call. return method; } // Now get the slot method. if (method.swtSlot != null && method.swtSlot.Meth() != null) { method = method.swtSlot.Meth(); } if (!pType.IsAggregateType()) { // Not something that can have overrides anyway. return method; } for (AggregateSymbol pAggregate = pType.AsAggregateType().GetOwningAggregate(); pAggregate != null && pAggregate.GetBaseAgg() != null; pAggregate = pAggregate.GetBaseAgg()) { for (MethodOrPropertySymbol meth = symbolLoader.LookupAggMember(method.name, pAggregate, symbmask_t.MASK_MethodSymbol | symbmask_t.MASK_PropertySymbol).AsMethodOrPropertySymbol(); meth != null; meth = symbolLoader.LookupNextSym(meth, pAggregate, symbmask_t.MASK_MethodSymbol | symbmask_t.MASK_PropertySymbol).AsMethodOrPropertySymbol()) { if (!meth.isOverride) { continue; } if (meth.swtSlot.Sym != null && meth.swtSlot.Sym == method) { if (bIsIndexer) { Debug.Assert(meth.IsMethodSymbol()); return meth.AsMethodSymbol().getProperty(); } else { return meth; } } } } // If we get here, it means we can have two cases: one is that we have // a delegate. This is because the delegate invoke method is virtual and is // an override, but we wont have the slots set up correctly, and will // not find the base type in the inheritance hierarchy. The second is that // we're calling off of the base itself. Debug.Assert(method.parent.IsAggregateSymbol()); return method; }
//////////////////////////////////////////////////////////////////////////////// /* bool LowerBoundNullableInference(CType pSource, CType pDest) { // SPEC ISSUE: As noted above, the spec does not clearly call out how // SPEC ISSUE: to do CType inference to a nullable target. I propose the // SPEC ISSUE: following: // SPEC ISSUE: // SPEC ISSUE: Otherwise, if V is nullable CType V1? and U is a // SPEC ISSUE: non-nullable struct CType then an exact inference is made from U to V1. if (!pDest.IsNullableType() || !pSource.isStructType() || pSource.IsNullableType()) { return false; } ExactInference(pSource, pDest.AsNullableType().GetUnderlyingType()); return true; } * */ //////////////////////////////////////////////////////////////////////////////// private bool LowerBoundConstructedInference(CType pSource, CType pDest) { if (!pDest.IsAggregateType()) { return false; } AggregateType pConstructedDest = pDest.AsAggregateType(); TypeArray pDestArgs = pConstructedDest.GetTypeArgsAll(); if (pDestArgs.size == 0) { return false; } // SPEC: Otherwise, if V is a constructed class or struct CType C<V1...Vk> // SPEC: and U is C<U1...Uk> then an exact inference // SPEC: is made from each Ui to the corresponding Vi. // SPEC: Otherwise, if V is a constructed interface or delegate CType C<V1...Vk> // SPEC: and U is C<U1...Uk> then an exact inference, // SPEC: lower bound inference or upper bound inference // SPEC: is made from each Ui to the corresponding Vi. if (pSource.IsAggregateType() && pSource.AsAggregateType().GetOwningAggregate() == pConstructedDest.GetOwningAggregate()) { if (pSource.isInterfaceType() || pSource.isDelegateType()) { LowerBoundTypeArgumentInference(pSource.AsAggregateType(), pConstructedDest); } else { ExactTypeArgumentInference(pSource.AsAggregateType(), pConstructedDest); } return true; } // SPEC: Otherwise, if V is a class CType C<V1...Vk> and U is a class CType which // SPEC: inherits directly or indirectly from C<U1...Uk> then an exact ... // SPEC: ... and U is a CType parameter with effective base class ... // SPEC: ... and U is a CType parameter with an effective base class which inherits ... if (LowerBoundClassInference(pSource, pConstructedDest)) { return true; } // SPEC: Otherwise, if V is an interface CType C<V1...Vk> and U is a class CType // SPEC: or struct CType and there is a unique set U1...Uk such that U directly // SPEC: or indirectly implements C<U1...Uk> then an exact ... // SPEC: ... and U is an interface CType ... // SPEC: ... and U is a CType parameter ... if (LowerBoundInterfaceInference(pSource, pConstructedDest)) { return true; } return false; }
/*************************************************************************************************** There exists an explicit conversion ... * From a generic delegate type S to generic delegate type T, provided all of the follow are true: o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is, S is D<S1,... Sk> and T is D<T1,... Tk>. o S is not compatible with or identical to T. o If type parameter Xi is declared to be invariant then Si must be identical to Ti. o If type parameter Xi is declared to be covariant ("out") then Si must be convertible to Ti via an identify conversion, implicit reference conversion, or explicit reference conversion. o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti, or Si and Ti must both be reference types. ***************************************************************************************************/ public static bool HasGenericDelegateExplicitReferenceConversion(SymbolLoader loader, CType pSource, CType pTarget) { if (!pSource.isDelegateType() || !pTarget.isDelegateType() || pSource.getAggregate() != pTarget.getAggregate() || loader.HasIdentityOrImplicitReferenceConversion(pSource, pTarget)) { return false; } TypeArray pTypeParams = pSource.getAggregate().GetTypeVarsAll(); TypeArray pSourceArgs = pSource.AsAggregateType().GetTypeArgsAll(); TypeArray pTargetArgs = pTarget.AsAggregateType().GetTypeArgsAll(); Debug.Assert(pTypeParams.size == pSourceArgs.size); Debug.Assert(pTypeParams.size == pTargetArgs.size); for (int iParam = 0; iParam < pTypeParams.size; ++iParam) { CType pSourceArg = pSourceArgs.Item(iParam); CType pTargetArg = pTargetArgs.Item(iParam); // If they're identical then this one is automatically good, so skip it. // If we have an error type, then we're in some fault tolerance. Let it through. if (pSourceArg == pTargetArg || pTargetArg.IsErrorType() || pSourceArg.IsErrorType()) { continue; } TypeParameterType pParam = pTypeParams.Item(iParam).AsTypeParameterType(); if (pParam.Invariant) { return false; } if (pParam.Covariant) { if (!FExpRefConv(loader, pSourceArg, pTargetArg)) { return false; } } else if (pParam.Contravariant) { if (!pSourceArg.IsRefType() || !pTargetArg.IsRefType()) { return false; } } } return true; }
//////////////////////////////////////////////////////////////////////////////// private bool UpperBoundArrayInference(CType pSource, CType pDest) { // SPEC: Otherwise, if V is an array CType Ve[...] and U is an array // SPEC: CType Ue[...] of the same rank, or if V is a one-dimensional array // SPEC: CType Ve[] and U is one of IEnumerable<Ue>, ICollection<Ue>, // SPEC: IList<Ue>, IReadOnlyCollection<Ue> or IReadOnlyList<Ue> then // SPEC: if Ue is known to be a reference CType then an upper-bound inference // SPEC: from Ue to Ve is made. // SPEC: otherwise an exact inference from Ue to Ve is made. if (!pDest.IsArrayType()) { return false; } ArrayType pArrayDest = pDest.AsArrayType(); CType pElementDest = pArrayDest.GetElementType(); CType pElementSource = null; if (pSource.IsArrayType()) { ArrayType pArraySource = pSource.AsArrayType(); if (pArrayDest.rank != pArraySource.rank) { return false; } pElementSource = pArraySource.GetElementType(); } else if (pSource.isPredefType(PredefinedType.PT_G_IENUMERABLE) || pSource.isPredefType(PredefinedType.PT_G_ICOLLECTION) || pSource.isPredefType(PredefinedType.PT_G_ILIST) || pSource.isPredefType(PredefinedType.PT_G_IREADONLYLIST) || pSource.isPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION)) { if (pArrayDest.rank != 1) { return false; } AggregateType pAggregateSource = pSource.AsAggregateType(); pElementSource = pAggregateSource.GetTypeArgsThis().Item(0); } else { return false; } if (pElementSource.IsRefType()) { UpperBoundInference(pElementSource, pElementDest); } else { ExactInference(pElementSource, pElementDest); } return true; }
/*************************************************************************************************** Determine whether there is an explicit or implicit reference conversion (or identity conversion) from typeSrc to typeDst. This is when: 13.2.3 Explicit reference conversions The explicit reference conversions are: * From object to any reference-type. * From any class-type S to any class-type T, provided S is a base class of T. * From any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T. * From any interface-type S to any class-type T, provided T is not sealed or provided T implements S. * From any interface-type S to any interface-type T, provided S is not derived from T. * From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true: o S and T differ only in element type. (In other words, S and T have the same number of dimensions.) o An explicit reference conversion exists from SE to TE. * From System.Array and the interfaces it implements, to any array-type. * From System.Delegate and the interfaces it implements, to any delegate-type. * From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces, provided there is an explicit reference conversion from S to T. * From a generic delegate type S to generic delegate type T, provided all of the follow are true: o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is, S is D<S1,... Sk> and T is D<T1,... Tk>. o S is not compatible with or identical to T. o If type parameter Xi is declared to be invariant then Si must be identical to Ti. o If type parameter Xi is declared to be covariant ("out") then Si must be convertible to Ti via an identify conversion, implicit reference conversion, or explicit reference conversion. o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti, or Si and Ti must both be reference types. * From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T are the same type or there is an implicit or explicit reference conversion from S to T. For a type-parameter T that is known to be a reference type (§25.7), the following explicit reference conversions exist: * From the effective base class C of T to T and from any base class of C to T. * From any interface-type to T. * From T to any interface-type I provided there isn’t already an implicit reference conversion from T to I. * From a type-parameter U to T provided that T depends on U (§25.7). [Note: Since T is known to be a reference type, within the scope of T, the run-time type of U will always be a reference type, even if U is not known to be a reference type at compile-time. end note] * Both src and dst are reference types and there is a builtin explicit conversion from src to dst. * Or src is a reference type and dst is a base type of src (in which case the conversion is implicit as well). * Or dst is a reference type and src is a base type of dst. The latter two cases can happen with type variables even though the other type variable is not a reference type. ***************************************************************************************************/ public static bool FExpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst) { Debug.Assert(typeSrc != null); Debug.Assert(typeDst != null); if (typeSrc.IsRefType() && typeDst.IsRefType()) { // is there an implicit reference conversion in either direction? // this handles the bulk of the cases ... if (loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst) || loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc)) { return true; } // For a type-parameter T that is known to be a reference type (§25.7), the following explicit reference conversions exist: // • From any interface-type to T. // • From T to any interface-type I provided there isn’t already an implicit reference conversion from T to I. if (typeSrc.isInterfaceType() && typeDst.IsTypeParameterType()) { return true; } if (typeSrc.IsTypeParameterType() && typeDst.isInterfaceType()) { return true; } // * From any class-type S to any interface-type T, provided S is not sealed // * From any interface-type S to any class-type T, provided T is not sealed // * From any interface-type S to any interface-type T, provided S is not derived from T. if (typeSrc.IsAggregateType() && typeDst.IsAggregateType()) { AggregateSymbol aggSrc = typeSrc.AsAggregateType().getAggregate(); AggregateSymbol aggDest = typeDst.AsAggregateType().getAggregate(); if ((aggSrc.IsClass() && !aggSrc.IsSealed() && aggDest.IsInterface()) || (aggSrc.IsInterface() && aggDest.IsClass() && !aggDest.IsSealed()) || (aggSrc.IsInterface() && aggDest.IsInterface())) { return true; } } // * From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true: // o S and T differ only in element type. (In other words, S and T have the same number of dimensions.) // o An explicit reference conversion exists from SE to TE. if (typeSrc.IsArrayType() && typeDst.IsArrayType()) { return typeSrc.AsArrayType().rank == typeDst.AsArrayType().rank && FExpRefConv(loader, typeSrc.AsArrayType().GetElementType(), typeDst.AsArrayType().GetElementType()); } // * From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> // and their base interfaces, provided there is an explicit reference conversion from S to T. if (typeSrc.IsArrayType()) { if (typeSrc.AsArrayType().rank != 1 || !typeDst.isInterfaceType() || typeDst.AsAggregateType().GetTypeArgsAll().Size != 1) { return false; } AggregateSymbol aggIList = loader.GetOptPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = loader.GetOptPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !loader.IsBaseAggregate(aggIList, typeDst.AsAggregateType().getAggregate())) && (aggIReadOnlyList == null || !loader.IsBaseAggregate(aggIReadOnlyList, typeDst.AsAggregateType().getAggregate()))) { return false; } return FExpRefConv(loader, typeSrc.AsArrayType().GetElementType(), typeDst.AsAggregateType().GetTypeArgsAll().Item(0)); } if (typeDst.IsArrayType() && typeSrc.IsAggregateType()) { // * From System.Array and the interfaces it implements, to any array-type. if (loader.HasIdentityOrImplicitReferenceConversion(loader.GetReqPredefType(PredefinedType.PT_ARRAY), typeSrc)) { return true; } // * From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a // one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to // System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T // are the same type or there is an implicit or explicit reference conversion from S to T. ArrayType arrayDest = typeDst.AsArrayType(); AggregateType aggtypeSrc = typeSrc.AsAggregateType(); if (arrayDest.rank != 1 || !typeSrc.isInterfaceType() || aggtypeSrc.GetTypeArgsAll().Size != 1) { return false; } AggregateSymbol aggIList = loader.GetOptPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = loader.GetOptPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !loader.IsBaseAggregate(aggIList, aggtypeSrc.getAggregate())) && (aggIReadOnlyList == null || !loader.IsBaseAggregate(aggIReadOnlyList, aggtypeSrc.getAggregate()))) { return false; } CType typeArr = arrayDest.GetElementType(); CType typeLst = aggtypeSrc.GetTypeArgsAll().Item(0); Debug.Assert(!typeArr.IsNeverSameType()); return typeArr == typeLst || FExpRefConv(loader, typeArr, typeLst); } if (HasGenericDelegateExplicitReferenceConversion(loader, typeSrc, typeDst)) { return true; } } else if (typeSrc.IsRefType()) { // conversion of T . U, where T : class, U // .. these constraints implies where U : class return loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst); } else if (typeDst.IsRefType()) { // conversion of T . U, where U : class, T // .. these constraints implies where T : class return loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc); } return false; }
//////////////////////////////////////////////////////////////////////////////// private bool UpperBoundClassInference(AggregateType pSource, CType pDest) { if (!pSource.isClassType() || !pDest.isClassType()) { return false; } // SPEC: Otherwise, if U is a class CType C<U1...Uk> and V is a class CType which // SPEC: inherits directly or indirectly from C<V1...Vk> then an exact // SPEC: inference is made from each Ui to the corresponding Vi. AggregateType pDestBase = pDest.AsAggregateType().GetBaseClass(); while (pDestBase != null) { if (pDestBase.GetOwningAggregate() == pSource.GetOwningAggregate()) { ExactTypeArgumentInference(pSource, pDestBase); return true; } pDestBase = pDestBase.GetBaseClass(); } return false; }
public CType SubstType(CType typeSrc, CType typeCls, TypeArray typeArgsMeth) { return SubstType(typeSrc, typeCls.IsAggregateType() ? typeCls.AsAggregateType().GetTypeArgsAll() : null, typeArgsMeth); }
//////////////////////////////////////////////////////////////////////////////// // // Input types // private bool DoesInputTypeContain(EXPR pSource, CType pDest, TypeParameterType pParam) { // SPEC: If E is a method group or an anonymous function and T is a delegate // SPEC: CType or expression tree CType then all the parameter types of T are // SPEC: input types of E with CType T. pDest = pDest.GetDelegateTypeOfPossibleExpression(); if (!pDest.isDelegateType()) { return false; // No input types. } if (!pSource.isUNBOUNDLAMBDA() && !pSource.isMEMGRP()) { return false; // No input types. } TypeArray pDelegateParameters = pDest.AsAggregateType().GetDelegateParameters(GetSymbolLoader()); if (pDelegateParameters == null) { return false; } return TypeManager.ParametersContainTyVar(pDelegateParameters, pParam); }
public bool SubstEqualTypes(CType typeDst, CType typeSrc, CType typeCls, TypeArray typeArgsMeth) { return SubstEqualTypes(typeDst, typeSrc, typeCls.IsAggregateType() ? typeCls.AsAggregateType().GetTypeArgsAll() : null, typeArgsMeth, SubstTypeFlags.NormNone); }
public virtual bool CheckTypeAccess(CType type, Symbol symWhere) { Debug.Assert(type != null); // Array, Ptr, Nub, etc don't matter. type = type.GetNakedType(true); if (!type.IsAggregateType()) { Debug.Assert(type.IsVoidType() || type.IsErrorType() || type.IsTypeParameterType()); return true; } for (AggregateType ats = type.AsAggregateType(); ats != null; ats = ats.outerType) { if (ACCESSERROR.ACCESSERROR_NOERROR != CheckAccessCore(ats.GetOwningAggregate(), ats.outerType, symWhere, null)) { return false; } } TypeArray typeArgs = type.AsAggregateType().GetTypeArgsAll(); for (int i = 0; i < typeArgs.size; i++) { if (!CheckTypeAccess(typeArgs.Item(i), symWhere)) return false; } return true; }
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // RUNTIME BINDER ONLY CHANGE // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! internal bool GetBestAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, CType typeSrc, out CType typeDst) { // This method implements the "best accessible type" algorithm for determining the type // of untyped arguments in the runtime binder. It is also used in method type inference // to fix type arguments to types that are accessible. // The new type is returned in an out parameter. The result will be true (and the out param // non-null) only when the algorithm could find a suitable accessible type. Debug.Assert(semanticChecker != null); Debug.Assert(bindingContext != null); Debug.Assert(typeSrc != null); typeDst = null; if (semanticChecker.CheckTypeAccess(typeSrc, bindingContext.ContextForMemberLookup())) { // If we already have an accessible type, then use it. This is the terminal point of the recursion. typeDst = typeSrc; return true; } // These guys have no accessibility concerns. Debug.Assert(!typeSrc.IsVoidType() && !typeSrc.IsErrorType() && !typeSrc.IsTypeParameterType()); if (typeSrc.IsParameterModifierType() || typeSrc.IsPointerType()) { // We cannot vary these. return false; } CType intermediateType; if ((typeSrc.isInterfaceType() || typeSrc.isDelegateType()) && TryVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, typeSrc.AsAggregateType(), out intermediateType)) { // If we have an interface or delegate type, then it can potentially be varied by its type arguments // to produce an accessible type, and if that's the case, then return that. // Example: IEnumerable<PrivateConcreteFoo> --> IEnumerable<PublicAbstractFoo> typeDst = intermediateType; Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup())); return true; } if (typeSrc.IsArrayType() && TryArrayVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, typeSrc.AsArrayType(), out intermediateType)) { // Similarly to the interface and delegate case, arrays are covariant in their element type and // so we can potentially produce an array type that is accessible. // Example: PrivateConcreteFoo[] --> PublicAbstractFoo[] typeDst = intermediateType; Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup())); return true; } if (typeSrc.IsNullableType()) { // We have an inaccessible nullable type, which means that the best we can do is System.ValueType. typeDst = this.GetOptPredefAgg(PredefinedType.PT_VALUE).getThisType(); Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup())); return true; } if (typeSrc.IsArrayType()) { // We have an inaccessible array type for which we could not earlier find a better array type // with a covariant conversion, so the best we can do is System.Array. typeDst = this.GetReqPredefAgg(PredefinedType.PT_ARRAY).getThisType(); Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup())); return true; } Debug.Assert(typeSrc.IsAggregateType()); if (typeSrc.IsAggregateType()) { // We have an AggregateType, so recurse on its base class. AggregateType aggType = typeSrc.AsAggregateType(); AggregateType baseType = aggType.GetBaseClass(); if (baseType == null) { // This happens with interfaces, for instance. But in that case, the // conversion to object does exist, is an implicit reference conversion, // and so we will use it. baseType = this.GetReqPredefAgg(PredefinedType.PT_OBJECT).getThisType(); } return GetBestAccessibleType(semanticChecker, bindingContext, baseType, out typeDst); } return false; }
/*************************************************************************************************** * Lookup must be called before anything else can be called. * * typeSrc - Must be an AggregateType or TypeParameterType. * obj - the expression through which the member is being accessed. This is used for accessibility * of protected members and for constructing a MEMGRP from the results of the lookup. * It is legal for obj to be an EK_CLASS, in which case it may be used for accessibility, but * will not be used for MEMGRP construction. * symWhere - the symbol from with the name is being accessed (for checking accessibility). * name - the name to look for. * arity - the number of type args specified. Only members that support this arity are found. * Note that when arity is zero, all methods are considered since we do type argument * inferencing. * * flags - See MemLookFlags. * TypeVarsAllowed only applies to the most derived type (not base types). ***************************************************************************************************/ public bool Lookup(CSemanticChecker checker, CType typeSrc, EXPR obj, ParentSymbol symWhere, Name name, int arity, MemLookFlags flags) { Debug.Assert((flags & ~MemLookFlags.All) == 0); Debug.Assert(obj == null || obj.type != null); Debug.Assert(typeSrc.IsAggregateType() || typeSrc.IsTypeParameterType()); Debug.Assert(checker != null); _prgtype = _rgtypeStart; // Save the inputs for error handling, etc. _pSemanticChecker = checker; _pSymbolLoader = checker.GetSymbolLoader(); _typeSrc = typeSrc; _obj = (obj != null && !obj.isCLASS()) ? obj : null; _symWhere = symWhere; _name = name; _arity = arity; _flags = flags; if ((_flags & MemLookFlags.BaseCall) != 0) { _typeQual = null; } else if ((_flags & MemLookFlags.Ctor) != 0) { _typeQual = _typeSrc; } else if (obj != null) { _typeQual = (CType)obj.type; } else { _typeQual = null; } // Determine what to search. AggregateType typeCls1 = null; AggregateType typeIface = null; TypeArray ifaces = BSYMMGR.EmptyTypeArray(); AggregateType typeCls2 = null; if (typeSrc.IsTypeParameterType()) { Debug.Assert((_flags & (MemLookFlags.Ctor | MemLookFlags.NewObj | MemLookFlags.Operator | MemLookFlags.BaseCall | MemLookFlags.TypeVarsAllowed)) == 0); _flags &= ~MemLookFlags.TypeVarsAllowed; ifaces = typeSrc.AsTypeParameterType().GetInterfaceBounds(); typeCls1 = typeSrc.AsTypeParameterType().GetEffectiveBaseClass(); if (ifaces.size > 0 && typeCls1.isPredefType(PredefinedType.PT_OBJECT)) { typeCls1 = null; } } else if (!typeSrc.isInterfaceType()) { typeCls1 = typeSrc.AsAggregateType(); if (typeCls1.IsWindowsRuntimeType()) { ifaces = typeCls1.GetWinRTCollectionIfacesAll(GetSymbolLoader()); } } else { Debug.Assert(typeSrc.isInterfaceType()); Debug.Assert((_flags & (MemLookFlags.Ctor | MemLookFlags.NewObj | MemLookFlags.Operator | MemLookFlags.BaseCall)) == 0); typeIface = typeSrc.AsAggregateType(); ifaces = typeIface.GetIfacesAll(); } if (typeIface != null || ifaces.size > 0) { typeCls2 = GetSymbolLoader().GetReqPredefType(PredefinedType.PT_OBJECT); } // Search the class first (except possibly object). if (typeCls1 == null || LookupInClass(typeCls1, ref typeCls2)) { // Search the interfaces. if ((typeIface != null || ifaces.size > 0) && LookupInInterfaces(typeIface, ifaces) && typeCls2 != null) { // Search object last. Debug.Assert(typeCls2 != null && typeCls2.isPredefType(PredefinedType.PT_OBJECT)); AggregateType result = null; LookupInClass(typeCls2, ref result); } } // if we are requested with extension methods _results = new CMemberLookupResults(GetAllTypes(), _name); return(!FError()); }
private static bool CheckSingleConstraint(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags) { bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors); if (arg.IsOpenTypePlaceholderType()) { return(true); } if (arg.IsErrorType()) { // Error should have been reported previously. return(false); } if (checker.CheckBogus(arg)) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_BogusType, arg); } return(false); } if (arg.IsPointerType() || arg.isSpecialByRefType()) { if (fReportErrors) { errHandling.Error(ErrorCode.ERR_BadTypeArgument, arg); } return(false); } if (arg.isStaticClass()) { if (fReportErrors) { checker.ReportStaticClassError(null, arg, ErrorCode.ERR_GenericArgIsStaticClass); } return(false); } bool fError = false; if (var.HasRefConstraint() && !arg.IsRefType()) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } fError = true; } TypeArray bnds = checker.GetSymbolLoader().GetTypeManager().SubstTypeArray(var.GetBounds(), typeArgsCls, typeArgsMeth); int itypeMin = 0; if (var.HasValConstraint()) { // If we have a type variable that is constrained to a value type, then we // want to check if its a nullable type, so that we can report the // constraint error below. In order to do this however, we need to check // that either the type arg is not a value type, or it is a nullable type. // // To check whether or not its a nullable type, we need to get the resolved // bound from the type argument and check against that. bool bIsValueType = arg.IsValType(); bool bIsNullable = arg.IsNullableType(); if (bIsValueType && arg.IsTypeParameterType()) { TypeArray pArgBnds = arg.AsTypeParameterType().GetBounds(); if (pArgBnds.Count > 0) { bIsNullable = pArgBnds[0].IsNullableType(); } } if (!bIsValueType || bIsNullable) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } fError = true; } // Since FValCon() is set it is redundant to check System.ValueType as well. if (bnds.Count != 0 && bnds[0].isPredefType(PredefinedType.PT_VALUE)) { itypeMin = 1; } } for (int j = itypeMin; j < bnds.Count; j++) { CType typeBnd = bnds[j]; if (!SatisfiesBound(checker, arg, typeBnd)) { if (fReportErrors) { // The bound isn't satisfied because of a constraint type. Explain to the user why not. // There are 4 main cases, based on the type of the supplied type argument: // - reference type, or type parameter known to be a reference type // - nullable type, from which there is a boxing conversion to the constraint type(see below for details) // - type variable // - value type // These cases are broken out because: a) The sets of conversions which can be used // for constraint satisfaction is different based on the type argument supplied, // and b) Nullable is one funky type, and user's can use all the help they can get // when using it. ErrorCode error; if (arg.IsRefType()) { // A reference type can only satisfy bounds to types // to which they have an implicit reference conversion error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType; } else if (arg.IsNullableType() && checker.GetSymbolLoader().HasBaseConversion(arg.AsNullableType().GetUnderlyingType(), typeBnd)) // This is inlining FBoxingConv { // nullable types do not satisfy bounds to every type that they are boxable to // They only satisfy bounds of object and ValueType if (typeBnd.isPredefType(PredefinedType.PT_ENUM) || arg.AsNullableType().GetUnderlyingType() == typeBnd) { // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum // even though the conversion from Nullable to these types is a boxing conversion // This is a rare case, because these bounds can never be directly stated ... // These bounds can only occur when one type paramter is constrained to a second type parameter // and the second type parameter is instantiated with Enum or the underlying type of the first type // parameter error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum; } else { // Nullable types don't satisfy the bounds of any interface type // even when there is a boxing conversion from the Nullable type to // the interface type. This will be a relatively common scenario // so we cal it out separately from the previous case. Debug.Assert(typeBnd.isInterfaceType()); error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface; } } else if (arg.IsTypeParameterType()) { // Type variables can satisfy bounds through boxing and type variable conversions Debug.Assert(!arg.IsRefType()); error = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar; } else { // Value types can only satisfy bounds through boxing conversions. // Note that the exceptional case of Nullable types and boxing is handled above. error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType; } errHandling.Error(error, new ErrArgRef(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArgRef(arg, ErrArgFlags.Unique)); } fError = true; } } // Check the newable constraint. if (!var.HasNewConstraint() || arg.IsValType()) { return(!fError); } if (arg.isClassType()) { AggregateSymbol agg = arg.AsAggregateType().getAggregate(); // Due to late binding nature of IDE created symbols, the AggregateSymbol might not // have all the information necessary yet, if it is not fully bound. // by calling LookupAggMember, it will ensure that we will update all the // information necessary at least for the given method. checker.GetSymbolLoader().LookupAggMember(checker.GetNameManager().GetPredefName(PredefinedName.PN_CTOR), agg, symbmask_t.MASK_ALL); if (agg.HasPubNoArgCtor() && !agg.IsAbstract()) { return(!fError); } } else if (arg.IsTypeParameterType() && arg.AsTypeParameterType().HasNewConstraint()) { return(!fError); } if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_NewConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } return(false); }