TypePtr ParameterExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { assert(type->is(Type::KindOfSome) || type->is(Type::KindOfAny)); TypePtr ret = getTypeSpec(ar, true); VariableTablePtr variables = getScope()->getVariables(); // Functions that can be called dynamically have to have // variant parameters, even if they have a type hint if ((Option::AllDynamic || getFunctionScope()->isDynamic()) || getFunctionScope()->isRedeclaring() || getFunctionScope()->isVirtual()) { if (!Option::HardTypeHints || !ret->isExactType()) { variables->forceVariant(ar, m_name, VariableTable::AnyVars); ret = Type::Variant; } } if (m_defaultValue && !m_ref) { TypePtr r = m_defaultValue->inferAndCheck(ar, Type::Some, false); if (!m_defaultValue->is(KindOfConstantExpression) || !static_pointer_cast<ConstantExpression>(m_defaultValue)->isNull()) { ret = Type::Coerce(ar, r, ret); } } // parameters are like variables, but we need to remember these are // parameters so when variable table is generated, they are not generated // as declared variables. return variables->addParamLike(m_name, ret, ar, shared_from_this(), getScope()->isFirstPass()); }
TypePtr ClosureExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { if (m_vars) { assert(m_values && m_values->getCount() == m_vars->getCount()); // containing function's variable table (not closure function's) VariableTablePtr variables = getScope()->getVariables(); // closure function's variable table VariableTablePtr cvariables = m_func->getFunctionScope()->getVariables(); // force all reference use vars into variant for this function scope for (int i = 0; i < m_vars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); const string &name = param->getName(); if (param->isRef()) { variables->forceVariant(ar, name, VariableTable::AnyVars); } } // infer the types of the values m_values->inferAndCheck(ar, Type::Some, false); // coerce the types inferred from m_values into m_vars for (int i = 0; i < m_vars->getCount(); i++) { ExpressionPtr value = (*m_values)[i]; ParameterExpressionPtr var = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); assert(!var->getExpectedType()); assert(!var->getImplementedType()); if (var->isRef()) { var->setActualType(Type::Variant); } else { TypePtr origVarType(var->getActualType() ? var->getActualType() : Type::Some); var->setActualType(Type::Coerce(ar, origVarType, value->getType())); } } { // this lock isn't technically needed for thread-safety, since // the dependencies are all set up. however, the lock assertions // will fail if we don't acquire it. GET_LOCK(m_func->getFunctionScope()); // bootstrap the closure function's variable table with // the types from m_vars for (int i = 0; i < m_vars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); const string &name = param->getName(); cvariables->addParamLike(name, param->getType(), ar, shared_from_this(), getScope()->isFirstPass()); } } } return s_ClosureType; }
void MethodStatement::inferFunctionTypes(AnalysisResultPtr ar) { IMPLEMENT_INFER_AND_CHECK_ASSERT(getFunctionScope()); FunctionScopeRawPtr funcScope = getFunctionScope(); bool pseudoMain = funcScope->inPseudoMain(); if (m_stmt && funcScope->isFirstPass()) { if (pseudoMain || funcScope->getReturnType() || m_stmt->hasRetExp()) { bool lastIsReturn = false; if (m_stmt->getCount()) { StatementPtr lastStmt = (*m_stmt)[m_stmt->getCount()-1]; if (lastStmt->is(Statement::KindOfReturnStatement)) { lastIsReturn = true; } } if (!lastIsReturn) { ExpressionPtr constant = makeScalarExpression(ar, funcScope->inPseudoMain() ? Variant(1) : Variant(Variant::NullInit())); ReturnStatementPtr returnStmt = ReturnStatementPtr( new ReturnStatement(getScope(), getLocation(), constant)); m_stmt->addElement(returnStmt); } } } if (m_params) { m_params->inferAndCheck(ar, Type::Any, false); } // must also include params and use vars if this is a generator. note: we are // OK reading the params from the AST nodes of the original generator // function, since we have the dependency links set up if (funcScope->isGenerator()) { // orig function params MethodStatementRawPtr m = getOrigGeneratorFunc(); assert(m); VariableTablePtr variables = funcScope->getVariables(); ExpressionListPtr params = m->getParams(); if (params) { for (int i = 0; i < params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); const string &name = param->getName(); assert(!param->isRef() || param->getType()->is(Type::KindOfVariant)); variables->addParamLike(name, param->getType(), ar, param, funcScope->isFirstPass()); } } // use vars ExpressionListPtr useVars = m->getFunctionScope()->getClosureVars(); if (useVars) { for (int i = 0; i < useVars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*useVars)[i]); const string &name = param->getName(); assert(!param->isRef() || param->getType()->is(Type::KindOfVariant)); variables->addParamLike(name, param->getType(), ar, param, funcScope->isFirstPass()); } } } if (m_stmt) { m_stmt->inferTypes(ar); } }