void ClosureExpression::initializeFromUseList(ExpressionListPtr vars) { m_vars = ExpressionListPtr( new ExpressionList(vars->getScope(), vars->getRange())); // Because PHP is insane you can have a use variable with the same // name as a param name. // In that case, params win (which is different than zend but much easier) auto seenBefore = collectParamNames(); for (int i = vars->getCount() - 1; i >= 0; i--) { auto param = dynamic_pointer_cast<ParameterExpression>((*vars)[i]); assert(param); if (param->getName() == "this") { // "this" is automatically included. // Once we get rid of all the callsites, make this an error continue; } if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) { seenBefore.insert(param->getName().c_str()); m_vars->insertElement(param); } } initializeValuesFromVars(); }
void ClosureExpression::setCaptureList( AnalysisResultConstRawPtr ar, const std::set<std::string>& captureNames) { assert(m_captureState == CaptureState::Unknown); m_captureState = CaptureState::Known; bool usedThis = false; SCOPE_EXIT { /* * TODO: closures in a non-class scope should be neither static * nor non-static, but right now we don't really have this idea. * * This would allow not having to check for a $this or late bound * class in the closure object or on the ActRec when returning * from those closures. * * (We could also mark closures that don't use late static binding * with this flag to avoid checks on closures in member functions * when they use neither $this nor static::) */ if (!usedThis && !m_func->getModifiers()->isStatic()) { m_func->getModifiers()->add(T_STATIC); } }; if (captureNames.empty()) return; m_vars = ExpressionListPtr( new ExpressionList(getScope(), getRange())); for (auto const& name : captureNames) { if (name == "this") { usedThis = true; continue; } auto expr = std::make_shared<ParameterExpression>( BlockScopePtr(getScope()), getRange(), TypeAnnotationPtr(), true /* hhType */, name, ParamMode::In, 0 /* token modifier thing */, ExpressionPtr(), ExpressionPtr() ); m_vars->insertElement(expr); } initializeValuesFromVars(); analyzeVarsForClosure(ar); analyzeVarsForClosureExpression(ar); }