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; }
ExprPtr with(const Assign* v) const { // hack to assign [char] into <std.string> if (hasConstraint(this->constraint, v->type())) { if (*v->left()->type()->monoType() == *stdstrty && *v->right()->type()->monoType() == *chararrty) { static MonoTypePtr assignty = functy(list(stdstrty, chararrty), unitty); return fncall(var("stdstringAssign", assignty, v->left()->la()), list(switchOf(v->left(), *this), switchOf(v->right(), *this)), v->la()); } } return wrapWithTy(v->type(), new Assign(switchOf(v->left(), *this), switchOf(v->right(), *this), v->la())); }
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; }
bool ofxPhysics2d::has(ofxConstraint*c){ return hasConstraint(c); }
bool TypeConstraint::check(const TypedValue* tv, const Func* func) const { assert(hasConstraint()); // This is part of the interpreter runtime; perf matters. if (tv->m_type == KindOfRef) { tv = tv->m_data.pref->tv(); } if (nullable() && IS_NULL_TYPE(tv->m_type)) return true; if (tv->m_type == KindOfObject) { if (!isObjectOrTypedef()) return false; // Perfect match seems common enough to be worth skipping the hash // table lookup. if (m_typeName->isame(tv->m_data.pobj->getVMClass()->name())) { if (shouldProfile()) Class::profileInstanceOf(m_typeName); return true; } const Class *c = nullptr; const bool selfOrParentOrCallable = isSelf() || isParent() || isCallable(); if (selfOrParentOrCallable) { if (isSelf()) { selfToClass(func, &c); } else if (isParent()) { parentToClass(func, &c); } else { assert(isCallable()); return f_is_callable(tvAsCVarRef(tv)); } } else { // We can't save the Class* since it moves around from request // to request. assert(m_namedEntity); c = Unit::lookupClass(m_namedEntity); } if (shouldProfile() && c) { Class::profileInstanceOf(c->preClass()->name()); } if (c && tv->m_data.pobj->instanceof(c)) { return true; } return !selfOrParentOrCallable && checkTypedefObj(tv); } if (isObjectOrTypedef()) { switch (tv->m_type) { case KindOfArray: if (interface_supports_array(m_typeName)) { return true; } break; case KindOfString: case KindOfStaticString: if (interface_supports_string(m_typeName)) { return true; } break; case KindOfInt64: if (interface_supports_int(m_typeName)) { return true; } break; case KindOfDouble: if (interface_supports_double(m_typeName)) { return true; } break; default: break; } if (isCallable()) { return f_is_callable(tvAsCVarRef(tv)); } return isPrecise() && checkTypedefNonObj(tv); } return equivDataTypes(m_type.m_dt, tv->m_type); }
bool TypeConstraint::check(TypedValue* tv, const Func* func) const { assert(hasConstraint() && !isTypeVar() && !isMixed() && !isTypeConstant()); // This is part of the interpreter runtime; perf matters. if (tv->m_type == KindOfRef) { tv = tv->m_data.pref->tv(); } if (isNullable() && tv->m_type == KindOfNull) { return true; } if (tv->m_type == KindOfObject) { // Perfect match seems common enough to be worth skipping the hash // table lookup. const Class *c = nullptr; if (isObject()) { if (m_typeName->isame(tv->m_data.pobj->getVMClass()->name())) { if (isProfileRequest()) InstanceBits::profile(m_typeName); return true; } // We can't save the Class* since it moves around from request // to request. assert(m_namedEntity); c = Unit::lookupClass(m_namedEntity); } else { switch (metaType()) { case MetaType::Self: selfToClass(func, &c); break; case MetaType::Parent: parentToClass(func, &c); break; case MetaType::Callable: return is_callable(tvAsCVarRef(tv)); case MetaType::Precise: case MetaType::Number: case MetaType::ArrayKey: case MetaType::Dict: case MetaType::Vec: return false; case MetaType::Mixed: // We assert'd at the top of this function that the // metatype cannot be Mixed not_reached(); } } if (isProfileRequest() && c) { InstanceBits::profile(c->preClass()->name()); } if (c && tv->m_data.pobj->instanceof(c)) { return true; } return isObject() && checkTypeAliasObj(tv->m_data.pobj->getVMClass()); } auto const result = annotCompat(tv->m_type, m_type, m_typeName); 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: assert(isObject()); return checkTypeAliasNonObj(tv); } not_reached(); }
bool TypeConstraint::check(TypedValue* tv, const Func* func) const { assert(hasConstraint()); // This is part of the interpreter runtime; perf matters. if (tv->m_type == KindOfRef) { tv = tv->m_data.pref->tv(); } if (isNullable() && tv->m_type == KindOfNull) return true; if (isNumber()) { return IS_INT_TYPE(tv->m_type) || IS_DOUBLE_TYPE(tv->m_type); } if (isArrayKey()) { return IS_INT_TYPE(tv->m_type) || IS_STRING_TYPE(tv->m_type); } if (tv->m_type == KindOfObject) { if (!isObjectOrTypeAlias()) return false; // Perfect match seems common enough to be worth skipping the hash // table lookup. if (m_typeName->isame(tv->m_data.pobj->getVMClass()->name())) { if (isProfileRequest()) InstanceBits::profile(m_typeName); return true; } const Class *c = nullptr; const bool selfOrParentOrCallable = isSelf() || isParent() || isCallable(); if (selfOrParentOrCallable) { if (isSelf()) { selfToClass(func, &c); } else if (isParent()) { parentToClass(func, &c); } else { assert(isCallable()); return HHVM_FN(is_callable)(tvAsCVarRef(tv)); } } else { // We can't save the Class* since it moves around from request // to request. assert(m_namedEntity); c = Unit::lookupClass(m_namedEntity); } if (isProfileRequest() && c) { InstanceBits::profile(c->preClass()->name()); } if (c && tv->m_data.pobj->instanceof(c)) { return true; } return !selfOrParentOrCallable && checkTypeAliasObj(tv); } if (isObjectOrTypeAlias()) { do { switch (tv->m_type) { case KindOfInt64: if (interface_supports_int(m_typeName)) { return true; } continue; case KindOfDouble: if (interface_supports_double(m_typeName)) { return true; } continue; case KindOfStaticString: case KindOfString: if (interface_supports_string(m_typeName)) { return true; } continue; case KindOfArray: if (interface_supports_array(m_typeName)) { return true; } continue; case KindOfUninit: case KindOfNull: case KindOfBoolean: case KindOfObject: case KindOfResource: continue; case KindOfRef: case KindOfClass: break; } not_reached(); } while (0); if (isCallable()) { return HHVM_FN(is_callable)(tvAsCVarRef(tv)); } return isPrecise() && checkTypeAliasNonObj(tv); } return m_type.dt && equivDataTypes(*m_type.dt, tv->m_type); }
bool hasConstraint(const ConstraintPtr& c, const QualTypePtr& qt) { return hasConstraint(c, qt->constraints()); }