Exemple #1
0
 /// <summary>
 /// Gets value indicating the given type represents a long and nothing else.
 /// </summary>
 protected bool IsLongOnly(TypeRefMask tmask)
 {
     return(tmask.IsSingleType && this.TypeCtx.IsLong(tmask));
 }
Exemple #2
0
 /// <summary>
 /// Gets value indicating the given type represents only array types.
 /// </summary>
 protected bool IsArrayOnly(TypeRefMask tmask)
 {
     return(!tmask.IsVoid && !tmask.IsAnyType && TypeCtx.GetTypes(tmask).All(x => x.IsArray));
 }
Exemple #3
0
 public void FlowThroughReturn(TypeRefMask type)
 {
     _flowCtx.ReturnType |= type;
 }
Exemple #4
0
 /// <summary>
 /// Gets value indicating the given type represents a double and nothing else.
 /// </summary>
 protected bool IsDoubleOnly(TypeRefMask tmask)
 {
     return(tmask.IsSingleType && this.TypeCtx.IsDouble(tmask));
 }
Exemple #5
0
 public ArrayTypeRef(IEnumerable <object> keys, TypeRefMask elementType)
 {
     _keys        = null;// new HashSet<object>(keys);
     _elementType = elementType;
 }
Exemple #6
0
 public LambdaTypeRef(TypeRefMask returnType, AST.Signature signature)
 {
     _returnType = returnType;
     _signature  = signature;
 }
Exemple #7
0
        private static bool HandleTypeChecking(
            TypeRefMask currentType,
            TypeRefMask targetType,
            ConditionBranch branch,
            FlowState flowState,
            VariableHandle handle,
            bool skipTrueIfAnyType)
        {
            // Information whether this path can ever be taken
            bool isFeasible = true;

            if (branch == ConditionBranch.ToTrue)
            {
                // In the true branch the IsAnyType case can be optionally skipped
                if (skipTrueIfAnyType && currentType.IsAnyType)
                {
                    return(isFeasible);
                }

                // Intersect the possible types with those checked by the function, always keeping the IsRef flag.
                // IncludesSubclasses is kept only if it is specified in targetType.
                TypeRefMask resultType = (currentType & (targetType | TypeRefMask.IsRefMask));

                if (resultType.IsVoid)
                {
                    // Clearing the type out in this branch means the variable will never be of that type.
                    // In order to prevent errors in analysis and code generation, set the type to the one specified.
                    resultType = targetType | (currentType & TypeRefMask.IsRefMask);

                    isFeasible = false;
                }

                flowState.SetLocalType(handle, resultType);
            }
            else
            {
                Debug.Assert(branch == ConditionBranch.ToFalse);

                // In the false branch we cannot handle the IsAnyType case
                if (currentType.IsAnyType)
                {
                    return(isFeasible);
                }

                // Remove the types and flags excluded by the fact that the function returned false
                TypeRefMask resultType = currentType & (~targetType);

                if (resultType.IsVoid)
                {
                    // Clearing the type out in this branch means the variable will always be of that type
                    // In order to prevent errors in analysis and code generation, do not alter the type in this case.

                    isFeasible = false;
                }
                else
                {
                    flowState.SetLocalType(handle, resultType);
                }
            }

            return(isFeasible);
        }
Exemple #8
0
        /// <summary>
        /// Processes functions such as is_int, is_bool etc. Returns whether the function was one of these.
        /// </summary>
        private static bool HandleTypeCheckingFunctions <T>(
            BoundGlobalFunctionCall call,
            string name,
            BoundVariableRef arg,
            ExpressionAnalysis <T> analysis,
            ConditionBranch branch)
        {
            var typeCtx   = analysis.TypeCtx;
            var flowState = analysis.State;

            switch (name)
            {
            case "is_int":
            case "is_integer":
            case "is_long":
                HandleTypeCheckingExpression(arg, typeCtx.GetLongTypeMask(), branch, flowState, checkExpr: call);
                return(true);

            case "is_bool":
                HandleTypeCheckingExpression(arg, typeCtx.GetBooleanTypeMask(), branch, flowState, checkExpr: call);
                return(true);

            case "is_float":
            case "is_double":
            case "is_real":
                HandleTypeCheckingExpression(arg, typeCtx.GetDoubleTypeMask(), branch, flowState, checkExpr: call);
                return(true);

            case "is_string":
                var stringMask = typeCtx.GetStringTypeMask() | typeCtx.GetWritableStringTypeMask();
                HandleTypeCheckingExpression(arg, stringMask, branch, flowState, checkExpr: call);
                return(true);

            case "is_resource":
                HandleTypeCheckingExpression(arg, typeCtx.GetResourceTypeMask(), branch, flowState, checkExpr: call);
                return(true);

            case "is_null":
                HandleTypeCheckingExpression(arg, typeCtx.GetNullTypeMask(), branch, flowState, checkExpr: call);
                return(true);

            case "is_array":
                HandleTypeCheckingExpression(
                    arg,
                    currentType => typeCtx.GetArraysFromMask(currentType),
                    branch,
                    flowState,
                    skipPositiveIfAnyType: true,
                    checkExpr: call);
                return(true);

            case "is_object":
                // Keep IncludesSubclasses flag in the true branch and clear it in the false branch
                HandleTypeCheckingExpression(
                    arg,
                    currentType => typeCtx.GetObjectsFromMask(currentType).WithSubclasses,
                    branch,
                    flowState,
                    skipPositiveIfAnyType: true,
                    checkExpr: call);
                return(true);

            // TODO
            //case "is_scalar":
            //    return;

            case "is_numeric":
                HandleTypeCheckingExpression(
                    arg,
                    currentType =>
                {
                    // Specify numeric types if they are present
                    var targetType = typeCtx.IsLong(currentType) ? typeCtx.GetLongTypeMask() : 0;
                    targetType    |= typeCtx.IsDouble(currentType) ? typeCtx.GetDoubleTypeMask() : 0;

                    if (branch == ConditionBranch.ToTrue)
                    {
                        // Also string types can make is_numeric return true, but not anything else
                        targetType |= typeCtx.IsReadonlyString(currentType) ? typeCtx.GetStringTypeMask() : 0;
                        targetType |= typeCtx.IsWritableString(currentType) ? typeCtx.GetWritableStringTypeMask() : 0;

                        return(targetType);
                    }
                    else
                    {
                        // For number, is_numeric always returns true -> remove numeric types from false branch
                        return(targetType);
                    }
                },
                    branch,
                    flowState,
                    skipPositiveIfAnyType: true,
                    checkExpr: call);
                return(true);

            case "is_callable":
                HandleTypeCheckingExpression(
                    arg,
                    currentType =>
                {
                    // Closure is specified in both branches
                    TypeRefMask targetType = 0;
                    AddTypeIfInContext(typeCtx, type => type.IsLambda, false, ref targetType);

                    if (branch == ConditionBranch.ToTrue)
                    {
                        // Also string types, arrays and objects can make is_callable return true, but not anything else
                        targetType |= typeCtx.IsReadonlyString(currentType) ? typeCtx.GetStringTypeMask() : 0;
                        targetType |= typeCtx.IsWritableString(currentType) ? typeCtx.GetWritableStringTypeMask() : 0;
                        targetType |= typeCtx.GetArraysFromMask(currentType);
                        targetType |= typeCtx.GetObjectsFromMask(currentType);

                        return(targetType);
                    }
                    else
                    {
                        // For closure, is_callable always returns true -> remove the closure type from false branch,
                        // don't remove IncludeSubclasses flag
                        return(targetType);
                    }
                },
                    branch,
                    flowState,
                    skipPositiveIfAnyType: true,
                    checkExpr: call);
                return(true);

            // TODO
            //case "is_iterable":
            //    return;

            default:
                return(false);
            }
        }
Exemple #9
0
 public void SetVar(string name, TypeRefMask type)
 {
     SetVar(_flowCtx.GetVarIndex(new VariableName(name)), type);
 }
Exemple #10
0
 /// <summary>
 /// Initializes <see cref="CallInfo"/>.
 /// </summary>
 /// <param name="ctx">Type context of the caller.</param>
 /// <param name="paramsType">Type of parameters used for the call. Length of the array corresponds to the parameters count.</param>
 /// <param name="lateStaticBindType">Type of the <c>self</c> in the caller context.</param>
 public CallInfo(TypeRefContext ctx, TypeRefMask[] paramsType, TypeRefMask lateStaticBindType)
 {
     _typeCtx            = ctx;
     _paramsType         = paramsType;
     _lateStaticBindType = (lateStaticBindType.IsSingleType ? lateStaticBindType : 0);
 }
Exemple #11
0
 /// <summary>
 /// Initializes <see cref="CallInfo"/>.
 /// </summary>
 /// <param name="ctx">Type context of the caller.</param>
 /// <param name="paramsCount">Amount of parameters used for the call.</param>
 /// <param name="lateStaticBindType">Type of the <c>self</c> in the caller context.</param>
 public CallInfo(TypeRefContext ctx, int paramsCount, TypeRefMask lateStaticBindType)
     : this(ctx, GetParamsTypeArr(paramsCount, TypeRefMask.AnyType), lateStaticBindType)
 {
 }