bool TypeConstraint::checkTypeAliasNonObj(const TypedValue* tv) const { assert(tv->m_type != KindOfObject); // this checks when tv is not an object assert(!isSelf() && !isParent()); auto p = getTypeAliasOrClassWithAutoload(m_namedEntity, m_typeName); auto td = p.first; auto c = p.second; // Common case is that we actually find the alias: if (td) { if (td->nullable && tv->m_type == KindOfNull) return true; return td->any || equivDataTypes(td->kind, tv->m_type); } // Otherwise, this isn't a proper type alias, but it *might* be a // first-class enum. Check if the type is an enum and check the // constraint if it is. We only need to do this when the underlying // type is not an object, since only int and string can be enums. if (c && isEnum(c)) { auto dt = c->enumBaseTy(); // For an enum, if the underlying type is mixed, we still require // it is either an int or a string! if (dt) { return equivDataTypes(*dt, tv->m_type); } else { return IS_INT_TYPE(tv->m_type) || IS_STRING_TYPE(tv->m_type); } } return false; }
MaybeDataType TypeConstraint::underlyingDataTypeResolved() const { assert(!isSelf() && !isParent()); if (!hasConstraint()) return folly::none; auto t = underlyingDataType(); // If we aren't a class or type alias, nothing special to do. if (!isObjectOrTypeAlias()) return t; auto p = getTypeAliasOrClassWithAutoload(m_namedEntity, m_typeName); auto td = p.first; auto c = p.second; // See if this is a type alias. if (td) { if (td->kind != KindOfObject) { t = td->kind; } else { c = td->klass; } } // If the underlying type is a class, see if it is an enum and get that. if (c && isEnum(c)) { t = c->enumBaseTy(); } return t; }
bool TypeConstraint::checkTypeAliasNonObj(const TypedValue* tv) const { assert(tv->m_type != KindOfObject); assert(isObject()); auto p = getTypeAliasOrClassWithAutoload(m_namedEntity, m_typeName); auto td = p.first; auto c = p.second; // Common case is that we actually find the alias: if (td) { if (td->nullable && tv->m_type == KindOfNull) return true; auto result = annotCompat(tv->m_type, td->type, td->klass ? td->klass->name() : nullptr); switch (result) { case AnnotAction::Pass: return true; case AnnotAction::Fail: return false; case AnnotAction::CallableCheck: return is_callable(tvAsCVarRef(tv)); case AnnotAction::DictCheck: return tv->m_data.parr->isDict(); case AnnotAction::VecCheck: return tv->m_data.parr->isVecArray(); case AnnotAction::ObjectCheck: break; } assert(result == AnnotAction::ObjectCheck); assert(td->type == AnnotType::Object); // Fall through to the check below, since this could be a type // alias to an enum type c = td->klass; } // Otherwise, this isn't a proper type alias, but it *might* be a // first-class enum. Check if the type is an enum and check the // constraint if it is. We only need to do this when the underlying // type is not an object, since only int and string can be enums. if (c && isEnum(c)) { auto dt = c->enumBaseTy(); // For an enum, if the underlying type is mixed, we still require // it is either an int or a string! if (dt) { return equivDataTypes(*dt, tv->m_type); } else { return isIntType(tv->m_type) || isStringType(tv->m_type); } } return false; }
MaybeDataType TypeConstraint::underlyingDataTypeResolved() const { assert(!isSelf() && !isParent() && !isCallable()); assert(IMPLIES( !hasConstraint() || isTypeVar() || isTypeConstant(), isMixed())); if (!isPrecise()) return folly::none; auto t = underlyingDataType(); assert(t); // If we aren't a class or type alias, nothing special to do. if (!isObject()) return t; assert(t == KindOfObject); auto p = getTypeAliasOrClassWithAutoload(m_namedEntity, m_typeName); auto td = p.first; auto c = p.second; // See if this is a type alias. if (td) { if (td->type != Type::Object) { t = (getAnnotMetaType(td->type) != MetaType::Precise) ? folly::none : MaybeDataType(getAnnotDataType(td->type)); } else { c = td->klass; } } // If the underlying type is a class, see if it is an enum and get that. if (c && isEnum(c)) { t = c->enumBaseTy(); } return t; }