/// <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)); }
/// <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)); }
public void FlowThroughReturn(TypeRefMask type) { _flowCtx.ReturnType |= type; }
/// <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)); }
public ArrayTypeRef(IEnumerable <object> keys, TypeRefMask elementType) { _keys = null;// new HashSet<object>(keys); _elementType = elementType; }
public LambdaTypeRef(TypeRefMask returnType, AST.Signature signature) { _returnType = returnType; _signature = signature; }
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); }
/// <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); } }
public void SetVar(string name, TypeRefMask type) { SetVar(_flowCtx.GetVarIndex(new VariableName(name)), type); }
/// <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); }
/// <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) { }