///// <summary> ///// Gets value determining whether <paramref name="totype"/> type can be assigned from <paramref name="fromtype"/>. ///// </summary> ///// <param name="totype">Type mask which we check whether is assignable from <paramref name="fromtype"/>.</param> ///// <param name="fromtype">Type mask we check whether is equal or is a subclass of <paramref name="totype"/>.</param> ///// <param name="ctx">Type context for resolving class names from type mask.</param> ///// <param name="model">Helper object which caches class inheritance.</param> ///// <remarks> ///// Gets <c>true</c>, if <paramref name="totype"/> is equal to or is a base type of <paramref name="fromtype"/>. ///// Gets <c>False</c> for <c>void</c> type masks. ///// </remarks> //public static bool IsAssignableFrom(this TypeRefMask totype, TypeRefMask fromtype, TypeRefContext/*!*/ctx, ISemanticModel/*!*/model) //{ // Debug.Assert(ctx != null); // Debug.Assert(model != null); // if ((totype & fromtype & ~(ulong)TypeRefMask.FlagsMask) != 0) // return true; // types are equal (or at least one of them is Any Type) // // object <-> unspecified object instance // if ((ctx.IsObject(totype) && ctx.IsObject(fromtype)) && // (ctx.IsAnObject(totype) || ctx.IsAnObject(fromtype))) // return true; // if (IsImplicitConversion(fromtype, totype, ctx, model)) // return true; // // cut off object types (primitive types do not have subclasses) // var selfObjs = ctx.GetObjectTypes(totype); // if (selfObjs.Count == 0) // return false; // self mask does not represent a class // var typeObjs = ctx.GetObjectTypes(fromtype); // if (typeObjs.Count == 0) // return false; // type mask does not represent a class // // build inheritance graph and check whether any type from self is a base of anything in type // if (selfObjs.Count == 1 && typeObjs.Count == 1) // return model.IsAssignableFrom(selfObjs[0].QualifiedName, typeObjs[0].QualifiedName); // // // return model.IsAssignableFrom(selfObjs.Select(t => t.QualifiedName), typeObjs.Select(t => t.QualifiedName)); //} ///// <summary> ///// Determines whether there is an implicit conversion from one type to another. ///// </summary> //private static bool IsImplicitConversion(TypeRefMask fromtype, TypeRefMask totype, TypeRefContext/*!*/ctx, ISemanticModel/*!*/model) //{ // // TODO: optimize bit operations // // // if (ctx.IsArray(totype) && ctx.IsArray(fromtype)) // { // // both types are arrays, type may be more specific (int[]) and self just ([]) // // TODO: check whether their element types are assignable, // // avoid infinite recursion! // return true; // } // // any callable -> "callable" // if (ctx.IsLambda(totype) && IsCallable(fromtype, ctx, model)) // return true; // //// allowed conversions // // int <-> bool // //if (ctx.IsInteger(totype) && ctx.IsBoolean(fromtype)) // int -> bool // // return true; // // int <-> double // if (ctx.IsNumber(fromtype) && ctx.IsNumber(totype)) // TODO: maybe settings for strict number type check // return true; // if (ctx.IsString(totype) && IsConversionToString(fromtype, ctx, model)) // return true; // // // if (ctx.IsNull(fromtype) && ctx.IsNullable(totype)) // return true; // NULL can be assigned to any nullable // // // return false; //} ///// <summary> ///// Determines whether given type can be converted to string without warning. ///// </summary> //internal static bool IsConversionToString(TypeRefMask fromtype, TypeRefContext/*!*/ctx, ISemanticModel/*!*/model) //{ // // primitive -> string // if (ctx.IsPrimitiveType(fromtype)) // return true; // // object with __toString() -> string // if (ctx.IsObject(fromtype) && ctx.GetObjectTypes(fromtype).Any(tref => model.GetClass(tref.QualifiedName).HasMethod(NameUtils.SpecialNames.__toString, model))) // return true; // // // return false; //} /// <summary> /// Checks whether given type may be callable. /// </summary> internal static bool IsCallable(TypeRefContext /*!*/ ctx, TypeRefMask type) { if (type.IsAnyType || type.IsRef || ctx.IsLambda(type) || ctx.IsAString(type) || ctx.IsArray(type) || ctx.IsObject(type)) { return(true); } //// type has "__invoke" method //if (type.IsSingleType) // just optimization //{ // var tref = ctx.GetObjectTypes(type).FirstOrDefault(); // if (tref != null) // { // var node = model.GetClass(tref.QualifiedName); // // type has __invoke method or is assignable from Closure // if (node.HasMethod(NameUtils.SpecialNames.__invoke, model) || model.IsAssignableFrom(NameUtils.SpecialNames.Closure, node)) // return true; // } //} return(false); }