mirror of https://github.com/astral-sh/ruff
Remove it from ClassType
This commit is contained in:
parent
7818186fcc
commit
e609da0c72
|
|
@ -1160,7 +1160,7 @@ impl<'db> Type<'db> {
|
||||||
pub(crate) fn to_class_type(self, db: &'db dyn Db) -> Option<ClassType<'db>> {
|
pub(crate) fn to_class_type(self, db: &'db dyn Db) -> Option<ClassType<'db>> {
|
||||||
match self {
|
match self {
|
||||||
Type::ClassLiteral(class_literal) => Some(class_literal.default_specialization(db)),
|
Type::ClassLiteral(class_literal) => Some(class_literal.default_specialization(db)),
|
||||||
Type::GenericAlias(alias) => Some(ClassType::Generic(alias)),
|
Type::GenericAlias(instance) => Some(ClassType::Generic(instance.alias(db))),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1284,8 +1284,8 @@ impl<'db> Type<'db> {
|
||||||
Self::BytesLiteral(BytesLiteralType::new(db, bytes))
|
Self::BytesLiteral(BytesLiteralType::new(db, bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn typed_dict(defining_class: impl Into<ClassType<'db>>) -> Self {
|
pub(crate) fn typed_dict(defining_class: ClassType<'db>) -> Self {
|
||||||
Self::TypedDict(TypedDictType::new(defining_class.into()))
|
Self::TypedDict(TypedDictType::new(defining_class))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -1570,7 +1570,9 @@ impl<'db> Type<'db> {
|
||||||
Some(class_literal.default_specialization(db).into_callable(db))
|
Some(class_literal.default_specialization(db).into_callable(db))
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::GenericAlias(alias) => Some(ClassType::Generic(alias).into_callable(db)),
|
Type::GenericAlias(instance) => {
|
||||||
|
Some(ClassType::Generic(instance.alias(db)).into_callable(db))
|
||||||
|
}
|
||||||
|
|
||||||
Type::NewTypeInstance(newtype) => {
|
Type::NewTypeInstance(newtype) => {
|
||||||
Type::instance(db, newtype.base_class_type(db)).try_upcast_to_callable(db)
|
Type::instance(db, newtype.base_class_type(db)).try_upcast_to_callable(db)
|
||||||
|
|
@ -2417,20 +2419,22 @@ impl<'db> Type<'db> {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| ConstraintSet::from(relation.is_assignability())),
|
.unwrap_or_else(|| ConstraintSet::from(relation.is_assignability())),
|
||||||
(Type::GenericAlias(alias), Type::SubclassOf(target_subclass_ty)) => target_subclass_ty
|
(Type::GenericAlias(instance), Type::SubclassOf(target_subclass_ty)) => {
|
||||||
.subclass_of()
|
target_subclass_ty
|
||||||
.into_class()
|
.subclass_of()
|
||||||
.map(|subclass_of_class| {
|
.into_class()
|
||||||
ClassType::Generic(alias).has_relation_to_impl(
|
.map(|subclass_of_class| {
|
||||||
db,
|
ClassType::Generic(instance.alias(db)).has_relation_to_impl(
|
||||||
subclass_of_class,
|
db,
|
||||||
inferable,
|
subclass_of_class,
|
||||||
relation,
|
inferable,
|
||||||
relation_visitor,
|
relation,
|
||||||
disjointness_visitor,
|
relation_visitor,
|
||||||
)
|
disjointness_visitor,
|
||||||
})
|
)
|
||||||
.unwrap_or_else(|| ConstraintSet::from(relation.is_assignability())),
|
})
|
||||||
|
.unwrap_or_else(|| ConstraintSet::from(relation.is_assignability()))
|
||||||
|
}
|
||||||
|
|
||||||
// This branch asks: given two types `type[T]` and `type[S]`, is `type[T]` a subtype of `type[S]`?
|
// This branch asks: given two types `type[T]` and `type[S]`, is `type[T]` a subtype of `type[S]`?
|
||||||
(Type::SubclassOf(self_subclass_ty), Type::SubclassOf(target_subclass_ty)) => {
|
(Type::SubclassOf(self_subclass_ty), Type::SubclassOf(target_subclass_ty)) => {
|
||||||
|
|
@ -2457,7 +2461,7 @@ impl<'db> Type<'db> {
|
||||||
disjointness_visitor,
|
disjointness_visitor,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Type::GenericAlias(alias), _) => ClassType::from(alias)
|
(Type::GenericAlias(instance), _) => ClassType::Generic(instance.alias(db))
|
||||||
.metaclass_instance_type(db)
|
.metaclass_instance_type(db)
|
||||||
.has_relation_to_impl(
|
.has_relation_to_impl(
|
||||||
db,
|
db,
|
||||||
|
|
@ -3181,7 +3185,7 @@ impl<'db> Type<'db> {
|
||||||
| (Type::GenericAlias(alias_b), Type::SubclassOf(subclass_of_ty)) => {
|
| (Type::GenericAlias(alias_b), Type::SubclassOf(subclass_of_ty)) => {
|
||||||
match subclass_of_ty.subclass_of() {
|
match subclass_of_ty.subclass_of() {
|
||||||
SubclassOfInner::Dynamic(_) => ConstraintSet::from(false),
|
SubclassOfInner::Dynamic(_) => ConstraintSet::from(false),
|
||||||
SubclassOfInner::Class(class_a) => ClassType::from(alias_b)
|
SubclassOfInner::Class(class_a) => ClassType::Generic(alias_b.alias(db))
|
||||||
.when_subclass_of(db, class_a, inferable)
|
.when_subclass_of(db, class_a, inferable)
|
||||||
.negate(db),
|
.negate(db),
|
||||||
}
|
}
|
||||||
|
|
@ -3296,9 +3300,9 @@ impl<'db> Type<'db> {
|
||||||
.metaclass_instance_type(db)
|
.metaclass_instance_type(db)
|
||||||
.when_subtype_of(db, instance, inferable)
|
.when_subtype_of(db, instance, inferable)
|
||||||
.negate(db),
|
.negate(db),
|
||||||
(Type::GenericAlias(alias), instance @ Type::NominalInstance(_))
|
(Type::GenericAlias(generic), instance @ Type::NominalInstance(_))
|
||||||
| (instance @ Type::NominalInstance(_), Type::GenericAlias(alias)) => {
|
| (instance @ Type::NominalInstance(_), Type::GenericAlias(generic)) => {
|
||||||
ClassType::from(alias)
|
ClassType::Generic(generic.alias(db))
|
||||||
.metaclass_instance_type(db)
|
.metaclass_instance_type(db)
|
||||||
.has_relation_to_impl(
|
.has_relation_to_impl(
|
||||||
db,
|
db,
|
||||||
|
|
@ -3831,7 +3835,8 @@ impl<'db> Type<'db> {
|
||||||
),
|
),
|
||||||
|
|
||||||
Type::GenericAlias(instance) => {
|
Type::GenericAlias(instance) => {
|
||||||
let attr = Some(ClassType::from(*instance).class_member(db, name, policy));
|
let attr =
|
||||||
|
Some(ClassType::Generic(instance.alias(db)).class_member(db, name, policy));
|
||||||
match instance
|
match instance
|
||||||
.alias(db)
|
.alias(db)
|
||||||
.specialization(db)
|
.specialization(db)
|
||||||
|
|
@ -5040,7 +5045,7 @@ impl<'db> Type<'db> {
|
||||||
.metaclass_instance_type(db)
|
.metaclass_instance_type(db)
|
||||||
.try_bool_impl(db, allow_short_circuit, visitor)?
|
.try_bool_impl(db, allow_short_circuit, visitor)?
|
||||||
}
|
}
|
||||||
Type::GenericAlias(alias) => ClassType::from(*alias)
|
Type::GenericAlias(generic) => ClassType::Generic(generic.alias(db))
|
||||||
.metaclass_instance_type(db)
|
.metaclass_instance_type(db)
|
||||||
.try_bool_impl(db, allow_short_circuit, visitor)?,
|
.try_bool_impl(db, allow_short_circuit, visitor)?,
|
||||||
|
|
||||||
|
|
@ -6642,7 +6647,9 @@ impl<'db> Type<'db> {
|
||||||
match self {
|
match self {
|
||||||
Type::Dynamic(_) | Type::Never => Some(self),
|
Type::Dynamic(_) | Type::Never => Some(self),
|
||||||
Type::ClassLiteral(class) => Some(Type::instance(db, class.default_specialization(db))),
|
Type::ClassLiteral(class) => Some(Type::instance(db, class.default_specialization(db))),
|
||||||
Type::GenericAlias(alias) => Some(Type::instance(db, ClassType::from(alias))),
|
Type::GenericAlias(instance) => {
|
||||||
|
Some(Type::instance(db, ClassType::Generic(instance.alias(db))))
|
||||||
|
}
|
||||||
Type::SubclassOf(subclass_of_ty) => Some(subclass_of_ty.to_instance(db)),
|
Type::SubclassOf(subclass_of_ty) => Some(subclass_of_ty.to_instance(db)),
|
||||||
Type::KnownInstance(KnownInstanceType::NewType(newtype)) => {
|
Type::KnownInstance(KnownInstanceType::NewType(newtype)) => {
|
||||||
Some(Type::NewTypeInstance(newtype))
|
Some(Type::NewTypeInstance(newtype))
|
||||||
|
|
@ -6725,9 +6732,11 @@ impl<'db> Type<'db> {
|
||||||
Ok(ty)
|
Ok(ty)
|
||||||
}
|
}
|
||||||
Type::GenericAlias(instance) if instance.alias(db).is_typed_dict(db) => {
|
Type::GenericAlias(instance) if instance.alias(db).is_typed_dict(db) => {
|
||||||
Ok(Type::typed_dict(*instance))
|
Ok(Type::typed_dict(ClassType::Generic(instance.alias(db))))
|
||||||
|
}
|
||||||
|
Type::GenericAlias(instance) => {
|
||||||
|
Ok(Type::instance(db, ClassType::Generic(instance.alias(db))))
|
||||||
}
|
}
|
||||||
Type::GenericAlias(instance) => Ok(Type::instance(db, ClassType::from(*instance))),
|
|
||||||
|
|
||||||
Type::SubclassOf(_)
|
Type::SubclassOf(_)
|
||||||
| Type::BooleanLiteral(_)
|
| Type::BooleanLiteral(_)
|
||||||
|
|
@ -7085,7 +7094,7 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::ClassLiteral(class) => class.metaclass(db),
|
Type::ClassLiteral(class) => class.metaclass(db),
|
||||||
Type::GenericAlias(alias) => ClassType::from(alias).metaclass(db),
|
Type::GenericAlias(instance) => ClassType::Generic(instance.alias(db)).metaclass(db),
|
||||||
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
|
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
|
||||||
SubclassOfInner::Dynamic(_) => self,
|
SubclassOfInner::Dynamic(_) => self,
|
||||||
SubclassOfInner::Class(class) => SubclassOfType::from(
|
SubclassOfInner::Class(class) => SubclassOfType::from(
|
||||||
|
|
@ -8271,7 +8280,7 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||||
}
|
}
|
||||||
KnownInstanceType::NewType(newtype) => {
|
KnownInstanceType::NewType(newtype) => {
|
||||||
if let ClassType::Generic(generic_alias) = newtype.base_class_type(db) {
|
if let ClassType::Generic(generic_alias) = newtype.base_class_type(db) {
|
||||||
visitor.visit_generic_alias_type(db, generic_alias.alias(db));
|
visitor.visit_generic_alias_type(db, generic_alias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -419,7 +419,7 @@ pub enum ClassType<'db> {
|
||||||
// should use `ClassLiteral::default_specialization` instead of assuming
|
// should use `ClassLiteral::default_specialization` instead of assuming
|
||||||
// `ClassType::NonGeneric`.
|
// `ClassType::NonGeneric`.
|
||||||
NonGeneric(ClassLiteral<'db>),
|
NonGeneric(ClassLiteral<'db>),
|
||||||
Generic(GenericAliasInstance<'db>),
|
Generic(GenericAlias<'db>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[salsa::tracked]
|
#[salsa::tracked]
|
||||||
|
|
@ -439,14 +439,16 @@ impl<'db> ClassType<'db> {
|
||||||
pub(super) fn into_generic_alias(self, db: &'db dyn Db) -> Option<GenericAlias<'db>> {
|
pub(super) fn into_generic_alias(self, db: &'db dyn Db) -> Option<GenericAlias<'db>> {
|
||||||
match self {
|
match self {
|
||||||
Self::NonGeneric(_) => None,
|
Self::NonGeneric(_) => None,
|
||||||
Self::Generic(instance) => Some(instance.alias(db)),
|
Self::Generic(alias) => Some(alias),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn into_type(self, db: &'db dyn Db) -> Type<'db> {
|
pub(super) fn into_type(self, db: &'db dyn Db) -> Type<'db> {
|
||||||
match self {
|
match self {
|
||||||
Self::NonGeneric(class) => class.into(),
|
Self::NonGeneric(class) => class.into(),
|
||||||
Self::Generic(generic) => Type::GenericAlias(generic),
|
Self::Generic(instance) => {
|
||||||
|
Type::GenericAlias(GenericAliasInstance::new(db, instance, None))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1280,17 +1282,11 @@ fn into_callable_cycle_initial<'db>(
|
||||||
CallableTypes::one(CallableType::bottom(db))
|
CallableTypes::one(CallableType::bottom(db))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> From<GenericAliasInstance<'db>> for ClassType<'db> {
|
|
||||||
fn from(generic: GenericAliasInstance<'db>) -> ClassType<'db> {
|
|
||||||
ClassType::Generic(generic)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'db> VarianceInferable<'db> for ClassType<'db> {
|
impl<'db> VarianceInferable<'db> for ClassType<'db> {
|
||||||
fn variance_of(self, db: &'db dyn Db, typevar: BoundTypeVarInstance<'db>) -> TypeVarVariance {
|
fn variance_of(self, db: &'db dyn Db, typevar: BoundTypeVarInstance<'db>) -> TypeVarVariance {
|
||||||
match self {
|
match self {
|
||||||
Self::NonGeneric(class) => class.variance_of(db, typevar),
|
Self::NonGeneric(class) => class.variance_of(db, typevar),
|
||||||
Self::Generic(generic) => generic.alias(db).variance_of(db, typevar),
|
Self::Generic(alias) => alias.variance_of(db, typevar),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1595,11 +1591,7 @@ impl<'db> ClassLiteral<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassType::Generic(GenericAliasInstance::new(
|
ClassType::Generic(GenericAlias::new(db, self, specialization))
|
||||||
db,
|
|
||||||
GenericAlias::new(db, self, specialization),
|
|
||||||
binding_context,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,9 @@ impl<'db> ClassBase<'db> {
|
||||||
match ty {
|
match ty {
|
||||||
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
|
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
|
||||||
Type::ClassLiteral(literal) => Some(Self::Class(literal.default_specialization(db))),
|
Type::ClassLiteral(literal) => Some(Self::Class(literal.default_specialization(db))),
|
||||||
Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic))),
|
Type::GenericAlias(instance) => {
|
||||||
|
Some(Self::Class(ClassType::Generic(instance.alias(db))))
|
||||||
|
}
|
||||||
Type::NominalInstance(instance)
|
Type::NominalInstance(instance)
|
||||||
if instance.has_known_class(db, KnownClass::GenericAlias) =>
|
if instance.has_known_class(db, KnownClass::GenericAlias) =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -599,7 +599,7 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
(ClassType::NonGeneric(class), _) => {
|
(ClassType::NonGeneric(class), _) => {
|
||||||
class.display_with(self.db, self.settings.clone()).fmt_detailed(f)
|
class.display_with(self.db, self.settings.clone()).fmt_detailed(f)
|
||||||
},
|
},
|
||||||
(ClassType::Generic(instance), _) => instance.alias(self.db).display_with(self.db, self.settings.clone()).fmt_detailed(f),
|
(ClassType::Generic(instance), _) => instance.display_with(self.db, self.settings.clone()).fmt_detailed(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::ProtocolInstance(protocol) => match protocol.inner {
|
Type::ProtocolInstance(protocol) => match protocol.inner {
|
||||||
|
|
@ -608,7 +608,6 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
.display_with(self.db, self.settings.clone())
|
.display_with(self.db, self.settings.clone())
|
||||||
.fmt_detailed(f),
|
.fmt_detailed(f),
|
||||||
ClassType::Generic(instance) => instance
|
ClassType::Generic(instance) => instance
|
||||||
.alias(self.db)
|
|
||||||
.display_with(self.db, self.settings.clone())
|
.display_with(self.db, self.settings.clone())
|
||||||
.fmt_detailed(f),
|
.fmt_detailed(f),
|
||||||
},
|
},
|
||||||
|
|
@ -674,7 +673,6 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
.write_str("type")?;
|
.write_str("type")?;
|
||||||
f.write_char('[')?;
|
f.write_char('[')?;
|
||||||
instance
|
instance
|
||||||
.alias(self.db)
|
|
||||||
.display_with(self.db, self.settings.clone())
|
.display_with(self.db, self.settings.clone())
|
||||||
.fmt_detailed(f)?;
|
.fmt_detailed(f)?;
|
||||||
f.write_char(']')
|
f.write_char(']')
|
||||||
|
|
|
||||||
|
|
@ -1578,7 +1578,7 @@ impl KnownFunction {
|
||||||
let mut good_argument = true;
|
let mut good_argument = true;
|
||||||
let classes = match param_type {
|
let classes = match param_type {
|
||||||
Type::ClassLiteral(class) => vec![ClassType::NonGeneric(*class)],
|
Type::ClassLiteral(class) => vec![ClassType::NonGeneric(*class)],
|
||||||
Type::GenericAlias(generic_alias) => vec![ClassType::Generic(*generic_alias)],
|
Type::GenericAlias(generic) => vec![ClassType::Generic(generic.alias(db))],
|
||||||
Type::Union(union) => {
|
Type::Union(union) => {
|
||||||
let elements = union.elements(db);
|
let elements = union.elements(db);
|
||||||
let mut classes = Vec::with_capacity(elements.len());
|
let mut classes = Vec::with_capacity(elements.len());
|
||||||
|
|
@ -1587,8 +1587,8 @@ impl KnownFunction {
|
||||||
Type::ClassLiteral(class) => {
|
Type::ClassLiteral(class) => {
|
||||||
classes.push(ClassType::NonGeneric(*class));
|
classes.push(ClassType::NonGeneric(*class));
|
||||||
}
|
}
|
||||||
Type::GenericAlias(generic_alias) => {
|
Type::GenericAlias(generic) => {
|
||||||
classes.push(ClassType::Generic(*generic_alias));
|
classes.push(ClassType::Generic(generic.alias(db)));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
good_argument = false;
|
good_argument = false;
|
||||||
|
|
|
||||||
|
|
@ -686,7 +686,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Type::ClassLiteral(class) => ClassType::NonGeneric(*class),
|
Type::ClassLiteral(class) => ClassType::NonGeneric(*class),
|
||||||
Type::GenericAlias(class) => ClassType::Generic(*class),
|
Type::GenericAlias(generic) => ClassType::Generic(generic.alias(self.db())),
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -8085,7 +8085,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
|
|
||||||
let class = match callable_type {
|
let class = match callable_type {
|
||||||
Type::ClassLiteral(class) => Some(ClassType::NonGeneric(class)),
|
Type::ClassLiteral(class) => Some(ClassType::NonGeneric(class)),
|
||||||
Type::GenericAlias(generic) => Some(ClassType::Generic(generic)),
|
Type::GenericAlias(generic) => Some(ClassType::Generic(generic.alias(self.db()))),
|
||||||
Type::SubclassOf(subclass) => subclass.subclass_of().into_class(),
|
Type::SubclassOf(subclass) => subclass.subclass_of().into_class(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1049,10 +1049,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::GenericAlias(alias) => self.infer_explicitly_specialized_type_alias(
|
Type::GenericAlias(instance) => self.infer_explicitly_specialized_type_alias(
|
||||||
subscript,
|
subscript,
|
||||||
value_ty,
|
value_ty,
|
||||||
alias.binding_context(self.db()),
|
instance.binding_context(self.db()),
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
Type::StringLiteral(_) => {
|
Type::StringLiteral(_) => {
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,7 @@ impl<'db> SubclassOfInner<'db> {
|
||||||
match ty {
|
match ty {
|
||||||
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
|
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
|
||||||
Type::ClassLiteral(literal) => Some(Self::Class(literal.default_specialization(db))),
|
Type::ClassLiteral(literal) => Some(Self::Class(literal.default_specialization(db))),
|
||||||
Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic))),
|
Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic.alias(db)))),
|
||||||
Type::SpecialForm(SpecialFormType::Any) => Some(Self::Dynamic(DynamicType::Any)),
|
Type::SpecialForm(SpecialFormType::Any) => Some(Self::Dynamic(DynamicType::Any)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue