bool ReturnStatement::analyze(semantic::SemanticAnalysis& sa, shptr<semantic::symbol::SymbolTable> symbolTable) const { auto ret_type = semantic::symbol::Symbol::makeSymbol("return", symbolTable->getCurrentScope())->getCurrentDefinition()->getType(); auto expr_type = std::make_shared<ast::Type>(ast::Type::Primitive_type::VOID); if (expression) { if (*ret_type == *expr_type) sa.reportError("Method returns void, but return statement has expression.", this->expression); else { expr_type = expression->get_type(sa, symbolTable); if (expr_type) { if (!(*ret_type == *expr_type || (ret_type->isRefType() && expr_type->getPrimitiveType() == ast::Type::Primitive_type::NULL_TYPE))) sa.reportError("Mismatched types in return: $type{" + ret_type->getName() + "} and {" + expr_type->getName() + "}", this->expression); } } } else if (*ret_type != *expr_type) sa.reportError("Method returns $type{" + ret_type->getName() + "} but return statement has no expression", this->getPosition()); return true; }
ALWAYS_INLINE bool DataWalker::visitTypedValue(TypedValue rval, DataFeature& features, PointerSet& visited, PointerMap* seenArrs) const { if (isRefType(rval.m_type)) { if (rval.m_data.pref->isReferenced()) { if (markVisited(rval.m_data.pref, features, visited)) { // Don't recurse forever; we already went down this path, and // stop the walk if we've already got everything we need. return canStopWalk(features); } // Right now consider it circular even if the referenced variant // only showed up in one spot. This could be revisted later. features.isCircular = true; if (canStopWalk(features)) return true; } rval = *rval.m_data.pref->cell(); } if (rval.m_type == KindOfObject) { features.hasObjectOrResource = true; traverseData(rval.m_data.pobj, features, visited); } else if (isArrayLikeType(rval.m_type)) { traverseData(rval.m_data.parr, features, visited, seenArrs); } else if (rval.m_type == KindOfResource) { features.hasObjectOrResource = true; } return canStopWalk(features); }
bool tvIsPlausible(TypedValue tv) { if (isRefType(tv.m_type)) { assertx(tv.m_data.pref); assertx(uintptr_t(tv.m_data.pref) % sizeof(void*) == 0); assertx(tv.m_data.pref->kindIsValid()); assertx(tv.m_data.pref->checkCountZ()); tv = *tv.m_data.pref->cell(); } return cellIsPlausible(tv); }
bool cellIsPlausible(const Cell cell) { assertx(!isRefType(cell.m_type)); auto assertPtr = [](const void* ptr) { assertx(ptr && (uintptr_t(ptr) % sizeof(ptr) == 0)); }; [&] { switch (cell.m_type) { case KindOfUninit: case KindOfNull: return; case KindOfBoolean: assertx(cell.m_data.num == 0 || cell.m_data.num == 1); return; case KindOfInt64: case KindOfDouble: return; case KindOfPersistentString: assertPtr(cell.m_data.pstr); assertx(cell.m_data.pstr->kindIsValid()); assertx(!cell.m_data.pstr->isRefCounted()); return; case KindOfString: assertPtr(cell.m_data.pstr); assertx(cell.m_data.pstr->kindIsValid()); assertx(cell.m_data.pstr->checkCountZ()); return; case KindOfPersistentVec: assertPtr(cell.m_data.parr); assertx(!cell.m_data.parr->isRefCounted()); assertx(cell.m_data.parr->isVecArray()); assertx(cell.m_data.parr->isNotDVArray()); return; case KindOfVec: assertPtr(cell.m_data.parr); assertx(cell.m_data.parr->checkCountZ()); assertx(cell.m_data.parr->isVecArray()); assertx(cell.m_data.parr->isNotDVArray()); return; case KindOfPersistentDict: assertPtr(cell.m_data.parr); assertx(!cell.m_data.parr->isRefCounted()); assertx(cell.m_data.parr->isDict()); assertx(cell.m_data.parr->isNotDVArray()); return; case KindOfDict: assertPtr(cell.m_data.parr); assertx(cell.m_data.parr->checkCountZ()); assertx(cell.m_data.parr->isDict()); assertx(cell.m_data.parr->isNotDVArray()); return; case KindOfPersistentKeyset: assertPtr(cell.m_data.parr); assertx(!cell.m_data.parr->isRefCounted()); assertx(cell.m_data.parr->isKeyset()); assertx(cell.m_data.parr->isNotDVArray()); return; case KindOfKeyset: assertPtr(cell.m_data.parr); assertx(cell.m_data.parr->checkCountZ()); assertx(cell.m_data.parr->isKeyset()); assertx(cell.m_data.parr->isNotDVArray()); return; case KindOfPersistentShape: if (RuntimeOption::EvalHackArrDVArrs) { assertPtr(cell.m_data.parr); assertx(!cell.m_data.parr->isRefCounted()); assertx(cell.m_data.parr->isShape()); assertx(cell.m_data.parr->isNotDVArray()); return; } assertPtr(cell.m_data.parr); assertx(cell.m_data.parr->kindIsValid()); assertx(!cell.m_data.parr->isRefCounted()); assertx(cell.m_data.parr->isShape()); assertx(cell.m_data.parr->dvArraySanityCheck()); return; case KindOfShape: assertPtr(cell.m_data.parr); assertx(cell.m_data.parr->checkCountZ()); assertx(cell.m_data.parr->isShape()); if (RuntimeOption::EvalHackArrDVArrs) { assertx(cell.m_data.parr->isNotDVArray()); return; } assertx(cell.m_data.parr->kindIsValid()); assertx(cell.m_data.parr->dvArraySanityCheck()); return; case KindOfPersistentArray: assertPtr(cell.m_data.parr); assertx(cell.m_data.parr->kindIsValid()); assertx(!cell.m_data.parr->isRefCounted()); assertx(cell.m_data.parr->isPHPArray()); assertx(cell.m_data.parr->dvArraySanityCheck()); return; case KindOfArray: assertPtr(cell.m_data.parr); assertx(cell.m_data.parr->kindIsValid()); assertx(cell.m_data.parr->checkCountZ()); assertx(cell.m_data.parr->isPHPArray()); assertx(cell.m_data.parr->dvArraySanityCheck()); return; case KindOfObject: assertPtr(cell.m_data.pobj); assertx(cell.m_data.pobj->kindIsValid()); assertx(cell.m_data.pobj->checkCountZ()); return; case KindOfRecord: assertPtr(cell.m_data.prec); assertx(cell.m_data.prec->kindIsValid()); assertx(cell.m_data.prec->checkCount()); return; case KindOfResource: assertPtr(cell.m_data.pres); assertx(cell.m_data.pres->kindIsValid()); assertx(cell.m_data.pres->checkCountZ()); return; case KindOfFunc: assertPtr(cell.m_data.pfunc); assertx(cell.m_data.pfunc->validate()); return; case KindOfClass: assertPtr(cell.m_data.pclass); assertx(cell.m_data.pclass->validate()); return; case KindOfClsMeth: assertx(cell.m_data.pclsmeth->validate()); return; case KindOfRef: assertx(!"KindOfRef found in a Cell"); break; } not_reached(); }(); return true; }
bool refIsPlausible(const Ref ref) { assertx(isRefType(ref.m_type)); return tvIsPlausible(ref); }