/// <summary>
        /// Resolves list of input arguments.
        /// Implicit parameters passed by compiler are ignored.
        /// </summary>
        /// <param name="routine">Routine.</param>
        /// <param name="ctx">Type context to transfer type masks into.</param>
        /// <returns>List of input PHP arguments.</returns>
        public static IList <PhpParam> GetExpectedArguments(this IPhpRoutineSymbol routine, TypeRefContext ctx)
        {
            Contract.ThrowIfNull(routine);
            Contract.ThrowIfNull(ctx);

            List <PhpParam> result = null;

            int index = 0;

            var ps = routine.Parameters;

            foreach (ParameterSymbol p in ps)
            {
                if (result == null && p.IsImplicitlyDeclared && !p.IsParams)
                {
                    continue;
                }

                //
                var phpparam = p.IsParams
                    ? new PhpParam(p, index++, TypeRefMask.AnyType.WithIsRef(((ArrayTypeSymbol)p.Type).ElementType.Is_PhpAlias()))
                    : new PhpParam(p, index++, TypeRefFactory.CreateMask(ctx, p.Type, notNull: p.HasNotNull));

                result ??= new List <PhpParam>(ps.Length);
                result.Add(phpparam);
            }

            //
            return(result ?? (IList <PhpParam>)Array.Empty <PhpParam>());
        }
예제 #2
0
        /// <summary>
        /// Resolves list of input arguments.
        /// Implicit parameters passed by compiler are ignored.
        /// </summary>
        /// <param name="routine">Routine.</param>
        /// <param name="ctx">TYpe context to transmer type masks into.</param>
        /// <returns>List of input PHP arguments.</returns>
        public static PhpParam[] GetExpectedArguments(this IPhpRoutineSymbol routine, TypeRefContext ctx)
        {
            Contract.ThrowIfNull(routine);

            var ps     = routine.Parameters;
            var table  = (routine as SourceRoutineSymbol)?.LocalsTable;
            var result = new List <PhpParam>(ps.Length);

            foreach (ParameterSymbol p in ps)
            {
                if (result.Count == 0 && p.IsImplicitlyDeclared)
                {
                    continue;
                }

                // default value (bound expression)
                ConstantValue cvalue;
                var           psrc        = p as SourceParameterSymbol;
                var           defaultexpr = psrc != null
                    ? psrc.Initializer
                    : ((cvalue = p.ExplicitDefaultConstantValue) != null ? new BoundLiteral(cvalue.Value) : null);

                //
                var phpparam = new PhpParam(
                    TypeRefFactory.CreateMask(ctx, p.Type),
                    p.RefKind != RefKind.None,
                    p.IsParams,
                    defaultexpr);

                result.Add(phpparam);
            }

            //
            return(result.ToArray());
        }
예제 #3
0
        /// <summary>
        /// Gets type mask corresponding to given qualified name within this context.
        /// </summary>
        public TypeRefMask GetTypeMask(QualifiedName qname, bool includesSubclasses = true)
        {
            if (qname.IsReservedClassName)
            {
                return(GetTypeMaskOfReservedClassName(qname.Name));
            }

            return(GetTypeMask(TypeRefFactory.CreateTypeRef(qname), includesSubclasses));
        }
예제 #4
0
        /// <summary>
        /// Gets expected return type mask of given symbol (field, function, method or property).
        /// </summary>
        /// <remarks>Returned type mask corresponds to types that can be returned by invoking given symbol.</remarks>
        public static TypeRefMask GetResultType(this IPhpValue symbol, TypeRefContext ctx)
        {
            Contract.ThrowIfNull(symbol);
            Contract.ThrowIfNull(ctx);

            TypeSymbol t;

            if (symbol is FieldSymbol)
            {
                t = ((FieldSymbol)symbol).Type;
            }
            else if (symbol is MethodSymbol)
            {
                var m = (MethodSymbol)symbol;
                var r = symbol as SourceRoutineSymbol;
                if (r != null && r.IsStatic && r.SyntaxReturnType == null)
                {
                    // In case of a static function, we can return expected return type mask exactly.
                    // Such function cannot be overriden and we know exactly what the return type will be even the CLR type covers more possibilities.
                    return(ctx.AddToContext(r.TypeRefContext, r.ResultTypeMask));
                }

                t = m.ReturnType;
            }
            else if (symbol is PropertySymbol)
            {
                t = ((PropertySymbol)symbol).Type;
            }
            else if (symbol is ParameterSymbol)
            {
                var ps = (ParameterSymbol)symbol;
                t = ps.Type;

                if (ps.IsParams)
                {
                    Debug.Assert(t.IsSZArray());
                    return(ctx.GetArrayTypeMask(TypeRefFactory.CreateMask(ctx, ((ArrayTypeSymbol)t).ElementType)));
                }
            }
            else
            {
                throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(symbol);
            }

            // create the type mask from the CLR type symbol
            var mask = TypeRefFactory.CreateMask(ctx, t);

            // [CastToFalse]
            if (symbol is IPhpRoutineSymbol && ((IPhpRoutineSymbol)symbol).CastToFalse)
            {
                mask |= ctx.GetBooleanTypeMask();    // the function may return FALSE
            }

            //
            return(mask);
        }
예제 #5
0
        public virtual TypeRefMask GetResultType(TypeRefContext ctx)
        {
            var treturn = TypeRefFactory.CreateMask(ctx, this.ReturnType);

            if (this.CastToFalse)
            {
                treturn |= ctx.GetBooleanTypeMask();    // ISemanticFunction may return FALSE
            }

            return(treturn);
        }
예제 #6
0
 /// <summary>
 /// Enqueues initializers of a class fields and constants.
 /// </summary>
 void EnqueueFieldsInitializer(SourceTypeSymbol type)
 {
     type.GetMembers().OfType <SourceFieldSymbol>().Foreach(f =>
     {
         if (f.Initializer != null)
         {
             EnqueueExpression(
                 f.Initializer,
                 TypeRefFactory.CreateTypeRefContext(type), //the context will be lost, analysis resolves constant values only and types are temporary
                 NameUtils.GetNamingContext(type.Syntax));
         }
     });
 }
예제 #7
0
        internal override TypeSymbol GetFieldType(ConsList <FieldSymbol> fieldsBeingBound)
        {
            var vartag = _phpdoc?.GetElement <PHPDocBlock.VarTag>();

            if (vartag != null && vartag.TypeNamesArray.Length != 0)
            {
                var typectx = TypeRefFactory.CreateTypeRefContext(_type);
                var tmask   = PHPDoc.GetTypeMask(typectx, vartag.TypeNamesArray);
                var t       = DeclaringCompilation.GetTypeFromTypeRef(typectx, tmask);
                return(t);
            }

            // TODO: analysed PHP type

            return(DeclaringCompilation.CoreTypes.PhpValue);
        }
        internal override TypeSymbol GetFieldType(ConsList <FieldSymbol> fieldsBeingBound)
        {
            // TODO: HHVM TypeHint

            //
            if ((IsConst || IsReadOnly) && Initializer != null)
            {
                // resolved type symbol if possible
                if (Initializer.ResultType != null)
                {
                    return(Initializer.ResultType);
                }

                // resolved value type if possible
                var cvalue = Initializer.ConstantValue;
                if (cvalue.HasValue)
                {
                    var specialType = (cvalue.Value != null)
                        ? cvalue.ToConstantValueOrNull()?.SpecialType
                        : SpecialType.System_Object;    // NULL

                    if (specialType.HasValue && specialType != SpecialType.None)
                    {
                        return(DeclaringCompilation.GetSpecialType(specialType.Value));
                    }
                }

                //
                //return DeclaringCompilation.GetTypeFromTypeRef(typectx, Initializer.TypeRefMask);
            }

            // PHPDoc @var type
            if ((DeclaringCompilation.Options.PhpDocTypes & PhpDocTypes.FieldTypes) != 0)
            {
                var vartag = FindPhpDocVarTag();
                if (vartag != null && vartag.TypeNamesArray.Length != 0)
                {
                    var dummyctx = TypeRefFactory.CreateTypeRefContext(_containingType);
                    var tmask    = PHPDoc.GetTypeMask(dummyctx, vartag.TypeNamesArray, NameUtils.GetNamingContext(_containingType.Syntax));
                    return(DeclaringCompilation.GetTypeFromTypeRef(dummyctx, tmask));
                }
            }

            // default
            return(DeclaringCompilation.CoreTypes.PhpValue);
        }
        /// <summary>
        /// Resolves list of input arguments.
        /// Implicit parameters passed by compiler are ignored.
        /// </summary>
        /// <param name="routine">Routine.</param>
        /// <param name="ctx">Type context to transfer type masks into.</param>
        /// <returns>List of input PHP arguments.</returns>
        public static IList <PhpParam> GetExpectedArguments(this IPhpRoutineSymbol routine, TypeRefContext ctx)
        {
            Contract.ThrowIfNull(routine);
            Contract.ThrowIfNull(ctx);

            List <PhpParam> result = null;

            int index = 0;

            var ps = routine.Parameters;

            foreach (ParameterSymbol p in ps)
            {
                if (result == null && p.IsImplicitlyDeclared && !p.IsParams)
                {
                    continue;
                }

                //
                var phpparam = new PhpParam(
                    index++,
                    TypeRefFactory.CreateMask(ctx, p.Type, notNull: p.HasNotNullAttribute()),
                    p.RefKind != RefKind.None,
                    p.IsParams,
                    isPhpRw: p.GetPhpRwAttribute() != null,
                    defaultValue: p.Initializer);

                if (result == null)
                {
                    result = new List <PhpParam>(ps.Length);
                }

                result.Add(phpparam);
            }

            //
            return(result ?? (IList <PhpParam>)Array.Empty <PhpParam>());
        }
        /// <summary>
        /// Gets expected return type mask of given symbol (field, function, method or property).
        /// </summary>
        /// <remarks>Returned type mask corresponds to types that can be returned by invoking given symbol.</remarks>
        public static TypeRefMask GetResultType(this IPhpValue symbol, TypeRefContext ctx)
        {
            Contract.ThrowIfNull(symbol);
            Contract.ThrowIfNull(ctx);

            TypeSymbol t;

            if (symbol is FieldSymbol)
            {
                t = ((FieldSymbol)symbol).Type;
            }
            else if (symbol is MethodSymbol)
            {
                var m = (MethodSymbol)symbol;
                var r = symbol as SourceRoutineSymbol;

                // if the method is generator use ConstructClrReturnType analysis for return type
                // TODO: would not be necessary if GN_SGS got fixed (the routine could report the return type correctly itself)
                if (r != null && r.IsGeneratorMethod())
                {
                    t = m.ReturnType;
                }
                else if (r != null && r.IsStatic && r.SyntaxReturnType == null)
                {
                    // In case of a static function, we can return expected return type mask exactly.
                    // Such function cannot be overriden and we know exactly what the return type will be even the CLR type covers more possibilities.
                    return(ctx.AddToContext(r.TypeRefContext, r.ResultTypeMask));
                }
                else
                {
                    t = m.ReturnType;
                }
            }
            else if (symbol is PropertySymbol)
            {
                t = ((PropertySymbol)symbol).Type;
            }
            else if (symbol is ParameterSymbol)
            {
                var ps = (ParameterSymbol)symbol;
                t = ps.Type;

                if (ps.IsParams)
                {
                    Debug.Assert(t.IsSZArray());
                    return(ctx.GetArrayTypeMask(TypeRefFactory.CreateMask(ctx, ((ArrayTypeSymbol)t).ElementType)));
                }
            }
            else
            {
                throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(symbol);
            }

            // create the type mask from the CLR type symbol
            var mask = TypeRefFactory.CreateMask(ctx, t);

            // [CastToFalse]
            if (symbol is IPhpRoutineSymbol && ((IPhpRoutineSymbol)symbol).CastToFalse)
            {
                mask |= ctx.GetBooleanTypeMask();    // the function may return FALSE

                // remove NULL (NULL is changed to FALSE), note it also can't return -1
                mask = ctx.WithoutNull(mask);
            }

            //
            return(mask);
        }
예제 #11
0
 protected override TypeRefContext CreateTypeRefContext() => TypeRefFactory.CreateTypeRefContext(_type);
예제 #12
0
        /// <summary>
        /// Resolves value of the function call in compile time if possible and updates the variable type if necessary
        /// </summary>
        public static void HandleSpecialFunctionCall(BoundGlobalFunctionCall call, ExpressionAnalysis analysis, ConditionBranch branch)
        {
            // Only direct function names
            if (!HasSimpleName(call, out string name))
            {
                return;
            }

            // Type checking functions
            if (branch != ConditionBranch.AnyResult && CanBeTypeCheckingFunction(call, name, out var arg))
            {
                if (HandleTypeCheckingFunctions(call, name, arg, analysis, branch))
                {
                    return;
                }
            }

            // Functions with all arguments resolved
            if (call.ArgumentsInSourceOrder.All(a => a.Value.ConstantValue.HasValue))
            {
                // Clear out the constant value result from the previous run of this method (if it was valid, it will be reassigned below)
                call.ConstantValue = default(Optional <object>);

                string str;

                var args = call.ArgumentsInSourceOrder;
                switch (name)
                {
                case "is_callable":         // bool is_callable( string $function_name )
                case "function_exists":     // bool function_exists ( string $function_name )
                    if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out str))
                    {
                        // TRUE <=> function is defined unconditionally in a reference library (PE assembly)
                        var tmp = analysis.Model.ResolveFunction(NameUtils.MakeQualifiedName(str, true));
                        if (tmp is PEMethodSymbol || (tmp is AmbiguousMethodSymbol && ((AmbiguousMethodSymbol)tmp).Ambiguities.All(f => f is PEMethodSymbol)))      // TODO: unconditional declaration ?
                        {
                            call.ConstantValue = ConstantValueExtensions.AsOptional(true);
                            return;
                        }
                    }
                    break;

                // bool class_exists ( string $class_name [, bool $autoload = true ] )
                case "class_exists":
                    if (args.Length >= 1)
                    {
                        // TRUE <=> class is defined unconditionally in a reference library (PE assembly)
                        var class_name = args[0].Value.ConstantValue.Value as string;
                        if (class_name != null)
                        {
                            var tmp = analysis.Model.ResolveType(NameUtils.MakeQualifiedName(class_name, true));
                            if (tmp is PENamedTypeSymbol)       // TODO: unconditional declaration ?
                            {
                                call.ConstantValue = ConstantValueExtensions.AsOptional(true);
                                return;
                            }
                        }
                    }
                    break;

                // bool method_exists ( string $class_name , string $method_name )
                case "method_exists":
                    if (args.Length == 2)
                    {
                        var class_name = args[0].Value.ConstantValue.Value as string;
                        if (class_name != null && args[1].Value.ConstantValue.TryConvertToString(out str))
                        {
                            var tmp = (NamedTypeSymbol)analysis.Model.ResolveType(NameUtils.MakeQualifiedName(class_name, true));
                            if (tmp is PENamedTypeSymbol)
                            {
                                if (tmp.LookupMethods(str).Any())
                                {
                                    call.ConstantValue = ConstantValueExtensions.AsOptional(true);
                                    return;
                                }
                            }
                        }
                    }
                    break;

                case "extension_loaded":        // bool extension_loaded(name)
                    if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out str))
                    {
                        if (analysis.Model.Extensions.Contains(str, StringComparer.OrdinalIgnoreCase))
                        {
                            call.ConstantValue = ConstantValueExtensions.AsOptional(true);
                            return;
                        }
                    }
                    break;

                case "defined":
                case "constant":
                    if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out str))
                    {
                        // TODO: const_name in form of "{CLASS}::{NAME}"
                        var tmp = analysis.Model.ResolveConstant(str);
                        if (tmp is PEFieldSymbol symbol)        // TODO: also user constants defined in the same scope
                        {
                            if (name == "defined")
                            {
                                call.ConstantValue = ConstantValueExtensions.AsOptional(true);
                            }
                            else     // name == "constant"
                            {
                                var cvalue = symbol.GetConstantValue(false);
                                call.ConstantValue = (cvalue != null) ? new Optional <object>(cvalue.Value) : null;
                                call.TypeRefMask   = TypeRefFactory.CreateMask(analysis.TypeCtx, symbol.Type);
                            }

                            return;
                        }
                    }
                    break;

                case "strlen":
                    if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out string value))
                    {
                        call.ConstantValue = new Optional <object>(value.Length);
                    }
                    return;
                }
            }
        }
예제 #13
0
        /// <summary>
        /// Resolves value of the function call in compile time if possible and updates the variable type if necessary
        /// </summary>
        public static void HandleSpecialFunctionCall <T>(BoundGlobalFunctionCall call, ExpressionAnalysis <T> analysis, ConditionBranch branch)
        {
            // Only direct function names
            if (!HasSimpleName(call, out string name))
            {
                return;
            }

            // Type checking functions
            if (branch != ConditionBranch.AnyResult && CanBeTypeCheckingFunction(call, name, out var arg))
            {
                if (HandleTypeCheckingFunctions(call, name, arg, analysis, branch))
                {
                    return;
                }
            }

            var args = call.ArgumentsInSourceOrder;

            // Clear out the constant value result from the previous run of this method (if it was valid, it will be reassigned below)
            call.ConstantValue = default;

            string str;

            switch (name)           // TODO: case insensitive
            {
            case "is_callable":     // bool is_callable( string $function_name )
            case "function_exists": // bool function_exists ( string $function_name )
                if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out str))
                {
                    // TRUE <=> function is defined unconditionally in a reference library (PE assembly)
                    if (IsUnconditionalDeclaration(analysis.Model.ResolveFunction(NameUtils.MakeQualifiedName(str, true))))
                    {
                        call.ConstantValue = ConstantValueExtensions.AsOptional(true);
                    }
                }
                break;

            // bool class_exists ( string $class_name [, bool $autoload = true ] )
            case "class_exists":
            case "interface_exists":
                if (args.Length >= 1)
                {
                    // TRUE <=> class is defined unconditionally in a reference library (PE assembly)
                    var class_name = args[0].Value.ConstantValue.Value as string;
                    if (!string.IsNullOrEmpty(class_name))
                    {
                        var tmp = (TypeSymbol)analysis.Model.ResolveType(NameUtils.MakeQualifiedName(class_name, true));
                        if (tmp is PENamedTypeSymbol && !tmp.IsPhpUserType())       // TODO: + SourceTypeSymbol when reachable unconditional declaration
                        {
                            bool @interface = (name == "interface_exists");
                            if (tmp.TypeKind == (@interface ? TypeKind.Interface : TypeKind.Class))
                            {
                                call.ConstantValue = ConstantValueExtensions.AsOptional(true);
                            }
                        }
                    }
                }
                break;

            // bool method_exists ( string $class_name , string $method_name )
            case "method_exists":
                if (args.Length == 2)
                {
                    var class_name = args[0].Value.ConstantValue.Value as string;
                    if (class_name != null && args[1].Value.ConstantValue.TryConvertToString(out str))
                    {
                        var tmp = (NamedTypeSymbol)analysis.Model.ResolveType(NameUtils.MakeQualifiedName(class_name, true));
                        if (tmp is PENamedTypeSymbol && !tmp.IsPhpUserType())
                        {
                            if (tmp.LookupMethods(str).Count != 0)     // TODO: why not User Types // TODO: why not resolve FALSE as well below?
                            {
                                call.ConstantValue = ConstantValueExtensions.AsOptional(true);
                            }
                        }
                    }
                }
                break;

            case "defined":         // defined(CONST_NAME)
            case "constant":        // constant(CONST_NAME)
                if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out str))
                {
                    // TODO: const_name in form of "{CLASS}::{NAME}"
                    // TODO: also user constants defined in the same scope?

                    // quick evaluation of PE constants that can't be changed at run time

                    var tmp = analysis.Model.ResolveConstant(str);
                    if (tmp is PEFieldSymbol fld)
                    {
                        if (name == "defined")
                        {
                            call.ConstantValue = ConstantValueExtensions.AsOptional(true);
                        }
                        else     // name == "constant"
                        {
                            if (fld.Type.Is_Func_Context_TResult(out var tresult))
                            {
                                call.TypeRefMask = TypeRefFactory.CreateMask(analysis.TypeCtx, tresult);
                            }
                            else
                            {
                                var cvalue = fld.GetConstantValue(false);
                                call.ConstantValue = (cvalue != null) ? new Optional <object>(cvalue.Value) : null;
                                call.TypeRefMask   = TypeRefFactory.CreateMask(analysis.TypeCtx, fld.Type, notNull: fld.IsNotNull());
                            }
                        }
                    }
                    else if (tmp is PEPropertySymbol prop)
                    {
                        if (name == "defined")
                        {
                            call.ConstantValue = ConstantValueExtensions.AsOptional(true);
                        }
                        else     // name == "constant"
                        {
                            call.TypeRefMask = TypeRefFactory.CreateMask(analysis.TypeCtx, prop.Type, notNull: prop.IsNotNull());
                        }
                    }
                }
                break;

            case "strlen":
                if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out string value))
                {
                    call.ConstantValue = new Optional <object>(value.Length);
                }
                break;

            case "file_exists":
                if (args.Length == 1)
                {
                    if (TryResolveFile(analysis.Model, analysis.Routine, args[0].Value, out var script))
                    {
                        // there is compiled script at this path,
                        // the expression will be always true
                        call.ConstantValue = true.AsOptional();
                    }
                }
                break;
            }
        }
예제 #14
0
 public virtual TypeRefMask GetResultType(TypeRefContext ctx)
 {
     return(TypeRefFactory.CreateMask(ctx, this.ReturnType));
 }
예제 #15
0
 /// <summary>
 /// Field's <see cref="TypeRefContext"/> instance.
 /// </summary>
 internal TypeRefContext EnsureTypeRefContext() => _typeCtx ?? (_typeCtx = TypeRefFactory.CreateTypeRefContext(_containingType));
예제 #16
0
        /// <summary>
        /// Gets type mask corresponding to given TypeRef within this context.
        /// </summary>
        public TypeRefMask GetTypeMask(AST.TypeRef /*!*/ tref, bool includesSubclasses = true)
        {
            Contract.ThrowIfNull(tref);

            if (tref != null)
            {
                if (tref is AST.PrimitiveTypeRef)
                {
                    switch (((AST.PrimitiveTypeRef)tref).PrimitiveTypeName)
                    {
                    case AST.PrimitiveTypeRef.PrimitiveType.@int: return(GetLongTypeMask());

                    case AST.PrimitiveTypeRef.PrimitiveType.@float: return(GetDoubleTypeMask());

                    case AST.PrimitiveTypeRef.PrimitiveType.@string: return(GetStringTypeMask());

                    case AST.PrimitiveTypeRef.PrimitiveType.@bool: return(GetBooleanTypeMask());

                    case AST.PrimitiveTypeRef.PrimitiveType.array: return(GetArrayTypeMask());

                    case AST.PrimitiveTypeRef.PrimitiveType.callable: return(GetCallableTypeMask());

                    case AST.PrimitiveTypeRef.PrimitiveType.@void: return(0);

                    case AST.PrimitiveTypeRef.PrimitiveType.iterable: return(GetArrayTypeMask() | GetTypeMask(NameUtils.SpecialNames.Traversable, true));      // array | Traversable

                    case AST.PrimitiveTypeRef.PrimitiveType.@object: return(GetSystemObjectTypeMask());

                    default: throw new ArgumentException();
                    }
                }
                else if (tref is AST.INamedTypeRef named)
                {
                    return(GetTypeMask(named.ClassName, includesSubclasses));
                }
                else if (tref is AST.ReservedTypeRef reserved)
                {
                    return(GetTypeMaskOfReservedClassName(reserved.QualifiedName.Value.Name));
                }
                else if (tref is AST.AnonymousTypeRef)
                {
                    return(GetTypeMask(((AST.AnonymousTypeRef)tref).TypeDeclaration.GetAnonymousTypeQualifiedName(), false));
                }
                else if (tref is AST.MultipleTypeRef)
                {
                    TypeRefMask result = 0;
                    foreach (var x in ((AST.MultipleTypeRef)tref).MultipleTypes)
                    {
                        result |= GetTypeMask(x, includesSubclasses);
                    }
                    return(result);
                }
                else if (tref is AST.NullableTypeRef nullable)
                {
                    return(GetTypeMask(nullable.TargetType) | this.GetNullTypeMask());
                }
                else if (tref is AST.GenericTypeRef)
                {
                    return(GetTypeMask(TypeRefFactory.CreateTypeRef(tref), includesSubclasses));
                }
                else if (tref is AST.IndirectTypeRef)
                {
                    return(GetTypeMask((AST.IndirectTypeRef)tref, true));
                }
            }

            return(TypeRefMask.AnyType);
        }