void TypeConstraint::verifyFail(const Func* func, int paramNum, const TypedValue* tv) const { Transl::VMRegAnchor _; std::ostringstream fname; fname << func->fullName()->data() << "()"; const StringData* tn = typeName(); if (isSelf()) { selfToTypeName(func, &tn); } else if (isParent()) { parentToTypeName(func, &tn); } auto const givenType = describe_actual_type(tv); if (isExtended()) { // Extended type hints raise warnings instead of recoverable // errors for now, to ease migration (we used to not check these // at all at runtime). assert(nullable() && "only nullable extended type hints are currently supported"); raise_warning( "Argument %d to %s must be of type ?%s, %s given", paramNum + 1, fname.str().c_str(), tn->data(), givenType); } else { raise_recoverable_error( "Argument %d passed to %s must be an instance of %s, %s given", paramNum + 1, fname.str().c_str(), tn->data(), givenType); } }
void TypeConstraint::verifyFail(const Func* func, int paramNum, TypedValue* tv) const { JIT::VMRegAnchor _; const StringData* tn = typeName(); if (isSelf()) { selfToTypeName(func, &tn); } else if (isParent()) { parentToTypeName(func, &tn); } auto const givenType = describe_actual_type(tv); auto c = tvToCell(tv); if (isArray() && !isSoft() && !func->mustBeRef(paramNum) && c->m_type == KindOfObject && c->m_data.pobj->isCollection()) { // To ease migration, the 'array' type constraint will implicitly cast // collections to arrays, provided the type constraint is not soft and // the parameter is not by reference. We raise a notice to let the user // know that there was a type mismatch and that an implicit conversion // was performed. raise_notice( folly::format( "Argument {} to {}() must be of type {}, {} given; argument {} was " "implicitly cast to array", paramNum + 1, func->fullName()->data(), fullName(), givenType, paramNum + 1 ).str() ); tvCastToArrayInPlace(tv); return; } if (isExtended() && isSoft()) { // Soft extended type hints raise warnings instead of recoverable // errors, to ease migration. raise_debugging( "Argument %d to %s() must be of type %s, %s given", paramNum + 1, func->fullName()->data(), fullName().c_str(), givenType); } else if (isExtended() && isNullable()) { raise_typehint_error( folly::format( "Argument {} to {}() must be of type {}, {} given", paramNum + 1, func->fullName()->data(), fullName(), givenType ).str() ); } else { raise_typehint_error( folly::format( "Argument {} passed to {}() must be an instance of {}, {} given", paramNum + 1, func->fullName()->data(), tn->data(), givenType ).str() ); } }
std::string TypeConstraint::displayName(const Func* func /*= nullptr*/) const { const StringData* tn = typeName(); std::string name; if (isSoft()) { name += '@'; } if (isNullable() && isExtended()) { name += '?'; } if (func && isSelf()) { selfToTypeName(func, &tn); name += tn->data(); } else if (func && isParent()) { parentToTypeName(func, &tn); name += tn->data(); } else { const char* str = tn->data(); auto len = tn->size(); if (len > 3 && tolower(str[0]) == 'h' && tolower(str[1]) == 'h' && str[2] == '\\') { bool strip = false; const char* stripped = str + 3; switch (len - 3) { case 3: strip = (!strcasecmp(stripped, "int") || !strcasecmp(stripped, "num")); break; case 4: strip = !strcasecmp(stripped, "bool"); break; case 5: strip = !strcasecmp(stripped, "float"); break; case 6: strip = !strcasecmp(stripped, "string"); break; case 8: strip = (!strcasecmp(stripped, "resource") || !strcasecmp(stripped, "noreturn") || !strcasecmp(stripped, "arraykey")); break; default: break; } if (strip) { str = stripped; } } name += str; } return name; }
void TypeConstraint::verifyFail(const Func* func, int paramNum, const TypedValue* tv) const { Transl::VMRegAnchor _; std::ostringstream fname; fname << func->fullName()->data() << "()"; const StringData* tn = typeName(); if (isSelf()) { selfToTypeName(func, &tn); } else if (isParent()) { parentToTypeName(func, &tn); } auto const givenType = describe_actual_type(tv); if (isExtended()) { if (isSoft()) { // Soft type hints raise warnings instead of recoverable // errors by design, to ease migration. raise_warning( "Argument %d passed to %s must be of type %s, %s given", paramNum + 1, fname.str().c_str(), fullName().c_str(), givenType); } else if (isNullable()) { // This error message is slightly different from the normal case // (fullName() vs tn) raise_recoverable_error( "Argument %d passed to %s must be of type %s, %s given", paramNum + 1, fname.str().c_str(), fullName().c_str(), givenType); } else { assert(false && "Only nullable and soft extended type hints are currently implemented"); } } else { raise_recoverable_error( "Argument %d passed to %s must be an instance of %s, %s given", paramNum + 1, fname.str().c_str(), tn->data(), givenType); } }