use tsz_solver::{QueryDatabase, SubtypeFailureReason, TypeDatabase, TypeId};
pub(crate) use super::common::object_shape_for_type;
pub(crate) use tsz_solver::type_queries::{AssignabilityEvalKind, ExcessPropertiesKind};
pub(crate) fn classify_for_assignability_eval(
db: &dyn TypeDatabase,
type_id: TypeId,
) -> AssignabilityEvalKind {
tsz_solver::type_queries::classify_for_assignability_eval(db, type_id)
}
pub(crate) fn is_relation_cacheable(db: &dyn TypeDatabase, source: TypeId, target: TypeId) -> bool {
!tsz_solver::type_queries::contains_infer_types_db(db, source)
&& !tsz_solver::type_queries::contains_infer_types_db(db, target)
}
pub(crate) fn is_callable_type(db: &dyn TypeDatabase, type_id: TypeId) -> bool {
tsz_solver::type_queries::is_callable_type(db, type_id)
}
pub(crate) fn classify_for_excess_properties(
db: &dyn TypeDatabase,
type_id: TypeId,
) -> ExcessPropertiesKind {
tsz_solver::type_queries::classify_for_excess_properties(db, type_id)
}
pub(crate) fn get_function_return_type(db: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeId> {
tsz_solver::type_queries::get_return_type(db, type_id)
}
pub(crate) fn rewrite_function_error_slots_to_any(
db: &dyn TypeDatabase,
type_id: TypeId,
) -> TypeId {
tsz_solver::type_queries::rewrite_function_error_slots_to_any(db, type_id)
}
pub(crate) fn replace_function_return_type(
db: &dyn TypeDatabase,
type_id: TypeId,
new_return: TypeId,
) -> TypeId {
tsz_solver::type_queries::replace_function_return_type(db, type_id, new_return)
}
pub(crate) fn are_types_overlapping_with_env(
db: &dyn TypeDatabase,
env: &tsz_solver::TypeEnvironment,
left: TypeId,
right: TypeId,
strict_null_checks: bool,
) -> bool {
let mut flags: u16 = 0;
if strict_null_checks {
flags |= tsz_solver::RelationCacheKey::FLAG_STRICT_NULL_CHECKS;
}
let policy = tsz_solver::RelationPolicy::from_flags(flags);
tsz_solver::query_relation_with_resolver(
db,
env,
left,
right,
tsz_solver::RelationKind::Overlap,
policy,
tsz_solver::RelationContext::default(),
)
.is_related()
}
pub(crate) fn is_assignable_with_overrides<R: tsz_solver::TypeResolver>(
inputs: &AssignabilityQueryInputs<'_, R>,
overrides: &dyn tsz_solver::AssignabilityOverrideProvider,
) -> bool {
let AssignabilityQueryInputs {
db,
resolver,
source,
target,
flags,
inheritance_graph,
sound_mode,
} = *inputs;
let policy = tsz_solver::RelationPolicy::from_flags(flags)
.with_strict_subtype_checking(sound_mode)
.with_strict_any_propagation(sound_mode);
let context = tsz_solver::RelationContext {
query_db: Some(db),
inheritance_graph: Some(inheritance_graph),
class_check: None,
};
tsz_solver::query_relation_with_overrides(tsz_solver::RelationQueryInputs {
interner: db.as_type_database(),
resolver,
source,
target,
kind: tsz_solver::RelationKind::Assignable,
policy,
context,
overrides,
})
.is_related()
}
#[derive(Clone, Copy)]
pub(crate) struct AssignabilityQueryInputs<'a, R: tsz_solver::TypeResolver> {
pub db: &'a dyn QueryDatabase,
pub resolver: &'a R,
pub source: TypeId,
pub target: TypeId,
pub flags: u16,
pub inheritance_graph: &'a tsz_solver::InheritanceGraph,
pub sound_mode: bool,
}
pub(crate) fn is_assignable_with_resolver<R: tsz_solver::TypeResolver>(
db: &dyn QueryDatabase,
resolver: &R,
source: TypeId,
target: TypeId,
flags: u16,
inheritance_graph: &tsz_solver::InheritanceGraph,
sound_mode: bool,
) -> bool {
let policy = tsz_solver::RelationPolicy::from_flags(flags)
.with_strict_subtype_checking(sound_mode)
.with_strict_any_propagation(sound_mode);
let context = tsz_solver::RelationContext {
query_db: Some(db),
inheritance_graph: Some(inheritance_graph),
class_check: None,
};
tsz_solver::query_relation_with_resolver(
db,
resolver,
source,
target,
tsz_solver::RelationKind::Assignable,
policy,
context,
)
.is_related()
}
pub(crate) fn is_assignable_bivariant_with_resolver<R: tsz_solver::TypeResolver>(
db: &dyn QueryDatabase,
resolver: &R,
source: TypeId,
target: TypeId,
flags: u16,
inheritance_graph: &tsz_solver::InheritanceGraph,
sound_mode: bool,
) -> bool {
let policy = tsz_solver::RelationPolicy::from_flags(flags)
.with_strict_subtype_checking(sound_mode)
.with_strict_any_propagation(sound_mode);
let context = tsz_solver::RelationContext {
query_db: Some(db),
inheritance_graph: Some(inheritance_graph),
class_check: None,
};
tsz_solver::query_relation_with_resolver(
db,
resolver,
source,
target,
tsz_solver::RelationKind::AssignableBivariantCallbacks,
policy,
context,
)
.is_related()
}
pub(crate) fn is_subtype_with_resolver<R: tsz_solver::TypeResolver>(
db: &dyn QueryDatabase,
resolver: &R,
source: TypeId,
target: TypeId,
flags: u16,
inheritance_graph: &tsz_solver::InheritanceGraph,
class_check: Option<&dyn Fn(tsz_solver::SymbolRef) -> bool>,
) -> tsz_solver::RelationResult {
let policy = tsz_solver::RelationPolicy::from_flags(flags);
let context = tsz_solver::RelationContext {
query_db: Some(db),
inheritance_graph: Some(inheritance_graph),
class_check,
};
tsz_solver::query_relation_with_resolver(
db,
resolver,
source,
target,
tsz_solver::RelationKind::Subtype,
policy,
context,
)
}
pub(crate) fn is_redeclaration_identical_with_resolver<R: tsz_solver::TypeResolver>(
db: &dyn QueryDatabase,
resolver: &R,
source: TypeId,
target: TypeId,
flags: u16,
inheritance_graph: &tsz_solver::InheritanceGraph,
sound_mode: bool,
) -> bool {
let policy = tsz_solver::RelationPolicy::from_flags(flags)
.with_strict_subtype_checking(sound_mode)
.with_strict_any_propagation(sound_mode);
let context = tsz_solver::RelationContext {
query_db: Some(db),
inheritance_graph: Some(inheritance_graph),
class_check: None,
};
tsz_solver::query_relation_with_resolver(
db,
resolver,
source,
target,
tsz_solver::RelationKind::RedeclarationIdentical,
policy,
context,
)
.is_related()
}
pub(crate) struct AssignabilityFailureAnalysis {
pub weak_union_violation: bool,
pub failure_reason: Option<SubtypeFailureReason>,
}
pub(crate) struct AssignabilityGateResult {
pub related: bool,
pub analysis: Option<AssignabilityFailureAnalysis>,
}
pub(crate) fn check_assignable_gate_with_overrides<R: tsz_solver::TypeResolver>(
inputs: &AssignabilityQueryInputs<'_, R>,
overrides: &dyn tsz_solver::AssignabilityOverrideProvider,
ctx: Option<&crate::context::CheckerContext<'_>>,
collect_failure_analysis: bool,
) -> AssignabilityGateResult {
let related = is_assignable_with_overrides(inputs, overrides);
if !collect_failure_analysis || related {
return AssignabilityGateResult {
related,
analysis: None,
};
}
let analysis = ctx.map(|ctx| {
analyze_assignability_failure_with_context(
inputs.db.as_type_database(),
ctx,
inputs.resolver,
inputs.source,
inputs.target,
)
});
AssignabilityGateResult { related, analysis }
}
pub(crate) fn analyze_assignability_failure_with_context<R: tsz_solver::TypeResolver>(
db: &dyn TypeDatabase,
ctx: &crate::context::CheckerContext<'_>,
resolver: &R,
source: TypeId,
target: TypeId,
) -> AssignabilityFailureAnalysis {
let analysis = tsz_solver::analyze_assignability_failure_with_resolver(
db,
resolver,
source,
target,
|checker| ctx.configure_compat_checker(checker),
);
AssignabilityFailureAnalysis {
weak_union_violation: analysis.weak_union_violation,
failure_reason: analysis.failure_reason,
}
}