private bool bindExplicitConversionFromArrayToIList() { // 13.2.2 // // The explicit reference conversions are: // // * 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. Debug.Assert(_typeSrc != null); Debug.Assert(_typeDest != null); if (!(_typeSrc is ArrayType arrSrc) || !arrSrc.IsSZArray || !(_typeDest is AggregateType aggDest) || !aggDest.IsInterfaceType || aggDest.TypeArgsAll.Count != 1) { return(false); } AggregateSymbol aggIList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !SymbolLoader.IsBaseAggregate(aggIList, aggDest.OwningAggregate)) && (aggIReadOnlyList == null || !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggDest.OwningAggregate))) { return(false); } CType typeArr = arrSrc.ElementType; CType typeLst = aggDest.TypeArgsAll[0]; if (!CConversions.FExpRefConv(typeArr, typeLst)) { return(false); } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_REFCHECK); } return(true); }
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.IsSZArray || !(_typeSrc is AggregateType aggSrc) || !aggSrc.IsInterfaceType || aggSrc.TypeArgsAll.Count != 1) { return(false); } AggregateSymbol aggIList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !SymbolLoader.IsBaseAggregate(aggIList, aggSrc.OwningAggregate)) && (aggIReadOnlyList == null || !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggSrc.OwningAggregate))) { return(false); } CType typeArr = arrayDest.ElementType; CType typeLst = aggSrc.TypeArgsAll[0]; Debug.Assert(!(typeArr is MethodGroupType)); if (typeArr != typeLst && !CConversions.FExpRefConv(typeArr, typeLst)) { return(false); } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_REFCHECK); } 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(CType typeSrc, CType typeDst) { Debug.Assert(typeSrc != null); Debug.Assert(typeDst != null); if (typeSrc.IsReferenceType && typeDst.IsReferenceType) { // is there an implicit reference conversion in either direction? // this handles the bulk of the cases ... if (SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst) || SymbolLoader.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 is TypeParameterType || typeSrc is TypeParameterType && 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 is AggregateType atSrc && typeDst is AggregateType atDst) { AggregateSymbol aggSrc = atSrc.OwningAggregate; AggregateSymbol aggDest = atDst.OwningAggregate; if ((aggSrc.IsClass() && !aggSrc.IsSealed() && aggDest.IsInterface()) || (aggSrc.IsInterface() && aggDest.IsClass() && !aggDest.IsSealed()) || (aggSrc.IsInterface() && aggDest.IsInterface())) { return(true); } } if (typeSrc is ArrayType arrSrc) { // * 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 (typeDst is ArrayType arrDst) { return(arrSrc.Rank == arrDst.Rank && arrSrc.IsSZArray == arrDst.IsSZArray && FExpRefConv(arrSrc.ElementType, arrDst.ElementType)); } // * 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 (!arrSrc.IsSZArray || !typeDst.IsInterfaceType) { return(false); } AggregateType aggDst = (AggregateType)typeDst; TypeArray typeArgsAll = aggDst.TypeArgsAll; if (typeArgsAll.Count != 1) { return(false); } AggregateSymbol aggIList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !SymbolLoader.IsBaseAggregate(aggIList, aggDst.OwningAggregate)) && (aggIReadOnlyList == null || !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggDst.OwningAggregate))) { return(false); } return(FExpRefConv(arrSrc.ElementType, typeArgsAll[0])); } if (typeDst is ArrayType arrayDest && typeSrc is AggregateType aggtypeSrc) { // * From System.Array and the interfaces it implements, to any array-type. if (SymbolLoader.HasIdentityOrImplicitReferenceConversion(SymbolLoader.GetPredefindType(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. if (!arrayDest.IsSZArray || !typeSrc.IsInterfaceType || aggtypeSrc.TypeArgsAll.Count != 1) { return(false); } AggregateSymbol aggIList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST); AggregateSymbol aggIReadOnlyList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST); if ((aggIList == null || !SymbolLoader.IsBaseAggregate(aggIList, aggtypeSrc.OwningAggregate)) && (aggIReadOnlyList == null || !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggtypeSrc.OwningAggregate))) { return(false); } CType typeArr = arrayDest.ElementType; CType typeLst = aggtypeSrc.TypeArgsAll[0]; Debug.Assert(!(typeArr is MethodGroupType)); return(typeArr == typeLst || FExpRefConv(typeArr, typeLst)); } if (HasGenericDelegateExplicitReferenceConversion(typeSrc, typeDst)) { return(true); } } else if (typeSrc.IsReferenceType) { // conversion of T . U, where T : class, U // .. these constraints implies where U : class return(SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst)); } else if (typeDst.IsReferenceType) { // conversion of T . U, where U : class, T // .. these constraints implies where T : class return(SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc)); } return(false); }
private static AggregateSymbol GetPredefAgg(PredefinedType pt) => SymbolLoader.GetPredefAgg(pt);