/// <summary> /// Creates new type context, flow context and flow state for the routine. /// </summary> public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine, FlowContext flowCtx = null) { Contract.ThrowIfNull(routine); // get or create typeCtx var typeCtx = routine.TypeRefContext; if (flowCtx == null) { // create FlowContext flowCtx = new FlowContext(typeCtx, routine); } // create FlowState var state = new FlowState(flowCtx); // handle input parameters type foreach (var p in routine.SourceParameters) { var local = state.GetLocalHandle(new VariableName(p.Name)); var ptype = p.GetResultType(typeCtx); state.SetLocalType(local, ptype); } // $this if (routine.GetPhpThisVariablePlace() != null) { InitThisVar(flowCtx, state); } // return(state); }
/// <summary> /// Creates new type context, flow context and flow state for the routine. /// </summary> public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine, FlowContext flowCtx = null) { Contract.ThrowIfNull(routine); // get or create typeCtx var typeCtx = routine.TypeRefContext; if (flowCtx == null) { // create FlowContext flowCtx = new FlowContext(typeCtx, routine); } // create FlowState var state = new FlowState(flowCtx); // handle input parameters type foreach (var p in routine.SourceParameters) { var local = state.GetLocalHandle(new VariableName(p.Name)); var ptype = p.GetResultType(typeCtx); if (p.IsNotNull) { // remove 'null' type from the mask, // it cannot be null ptype = typeCtx.WithoutNull(ptype); } else if (p.Type.IsReferenceType) // a reference type that can be null { ptype |= typeCtx.GetNullTypeMask(); } state.SetLocalType(local, ptype); if (p.Syntax.PassedByRef && !p.Syntax.IsVariadic) { state.MarkLocalByRef(local); } } // $this if (routine.GetPhpThisVariablePlace() != null) { InitThisVar(flowCtx, state); } // return(state); }
/// <summary> /// Initializes <c>$this</c> variable, its type and initialized state. /// </summary> private static void InitThisVar(FlowContext /*!*/ ctx, FlowState /*!*/ initialState) { var thisVarType = ctx.TypeRefContext.GetThisTypeMask(); if (thisVarType.IsUninitialized) { thisVarType = TypeRefMask.AnyType; } // var thisHandle = ctx.GetVarIndex(VariableName.ThisVariableName); initialState.SetLocalType(thisHandle, thisVarType); // set $this type initialState.VisitLocal(thisHandle); // mark as visited (used) to not report as unused }
/// <summary> /// Creates new type context, flow context and flow state for the routine. /// </summary> public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine, FlowContext flowCtx = null) { Contract.ThrowIfNull(routine); // get or create typeCtx var typeCtx = routine.TypeRefContext; // create or reuse FlowContext flowCtx ??= new FlowContext(typeCtx, routine); // pre-allocate locals map // https://github.com/peachpiecompiler/peachpie/issues/1002 foreach (var variable in routine.LocalsTable.Variables) { if (variable is Semantics.LocalVariableReference local && local.VariableKind == VariableKind.LocalVariable) { flowCtx.GetVarIndex(variable.BoundName.NameValue); } } // create FlowState var state = new FlowState(flowCtx); // populate input parameters type foreach (var p in routine.SourceParameters) { var local = state.GetLocalHandle(new VariableName(p.Name)); var ptype = p.GetResultType(typeCtx); state.SetLocalType(local, ptype); } // $this if (routine.GetPhpThisVariablePlace() != null) { InitThisVar(flowCtx, state); } // return(state); }
/// <summary> /// Creates new type context, flow context and flow state for the routine. /// </summary> public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine) { Contract.ThrowIfNull(routine); // create typeCtx var typeCtx = routine.TypeRefContext; // create FlowContext var flowCtx = new FlowContext(typeCtx, routine); // create FlowState var state = new FlowState(flowCtx); // handle input parameters type var parameters = routine.SourceParameters; foreach (var p in parameters) { var local = state.GetLocalHandle(new VariableName(p.Name)); state.SetLocalType(local, p.GetResultType(typeCtx)); if (p.Syntax.PassedByRef && !p.Syntax.IsVariadic) { state.MarkLocalByRef(local); } } // $this if (routine.GetPhpThisVariablePlace() != null) { InitThisVar(flowCtx, state); } // return(state); }
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); }