-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[ty] Recursive protocols #17929
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ty] Recursive protocols #17929
Changes from all commits
994e99d
0c90ea4
c1e3249
8baf93e
7109066
c95d755
e735ed2
88e5b58
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -587,6 +587,79 @@ impl<'db> Type<'db> { | |
matches!(self, Type::Dynamic(DynamicType::Todo(_))) | ||
} | ||
|
||
/// Replace references to the class `class` with a self-reference marker. This is currently | ||
/// used for recursive protocols, but could probably be extended to self-referential type- | ||
/// aliases and similar. | ||
#[must_use] | ||
pub fn replace_self_reference(&self, db: &'db dyn Db, class: ClassLiteral<'db>) -> Type<'db> { | ||
carljm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
match self { | ||
Self::ProtocolInstance(protocol) => { | ||
Self::ProtocolInstance(protocol.replace_self_reference(db, class)) | ||
} | ||
|
||
Self::Union(union) => UnionType::from_elements( | ||
db, | ||
union | ||
.elements(db) | ||
.iter() | ||
.map(|ty| ty.replace_self_reference(db, class)), | ||
), | ||
|
||
Self::Intersection(intersection) => IntersectionBuilder::new(db) | ||
.positive_elements( | ||
intersection | ||
.positive(db) | ||
.iter() | ||
.map(|ty| ty.replace_self_reference(db, class)), | ||
) | ||
.negative_elements( | ||
intersection | ||
.negative(db) | ||
.iter() | ||
.map(|ty| ty.replace_self_reference(db, class)), | ||
) | ||
.build(), | ||
|
||
Self::Tuple(tuple) => TupleType::from_elements( | ||
db, | ||
tuple | ||
.elements(db) | ||
.iter() | ||
.map(|ty| ty.replace_self_reference(db, class)), | ||
), | ||
|
||
Self::Callable(callable) => Self::Callable(callable.replace_self_reference(db, class)), | ||
|
||
Self::GenericAlias(_) | Self::TypeVar(_) => { | ||
// TODO: replace self-references in generic aliases and typevars | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was just about to ask if we could re-use this technique for generics 😄 👍 for it being a TODO There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The doc-comment of this function is probably more relevant? This is just the place where we would also have to look for references to the protocol class. Instead of |
||
*self | ||
} | ||
|
||
Self::Dynamic(_) | ||
| Self::AlwaysFalsy | ||
| Self::AlwaysTruthy | ||
| Self::Never | ||
| Self::BooleanLiteral(_) | ||
| Self::BytesLiteral(_) | ||
| Self::StringLiteral(_) | ||
| Self::IntLiteral(_) | ||
| Self::LiteralString | ||
| Self::FunctionLiteral(_) | ||
| Self::ModuleLiteral(_) | ||
| Self::ClassLiteral(_) | ||
| Self::NominalInstance(_) | ||
| Self::KnownInstance(_) | ||
| Self::PropertyInstance(_) | ||
sharkdp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Self::BoundMethod(_) | ||
| Self::WrapperDescriptor(_) | ||
| Self::MethodWrapper(_) | ||
| Self::DataclassDecorator(_) | ||
| Self::DataclassTransformer(_) | ||
| Self::SubclassOf(_) | ||
| Self::BoundSuper(_) => *self, | ||
} | ||
} | ||
|
||
pub fn contains_todo(&self, db: &'db dyn Db) -> bool { | ||
match self { | ||
Self::Dynamic(DynamicType::Todo(_) | DynamicType::SubscriptedProtocol) => true, | ||
|
@@ -7272,6 +7345,17 @@ impl<'db> CallableType<'db> { | |
} | ||
} | ||
} | ||
|
||
/// See [`Type::replace_self_reference`]. | ||
fn replace_self_reference(self, db: &'db dyn Db, class: ClassLiteral<'db>) -> Self { | ||
CallableType::from_overloads( | ||
db, | ||
self.signatures(db) | ||
.iter() | ||
.cloned() | ||
.map(|signature| signature.replace_self_reference(db, class)), | ||
) | ||
} | ||
} | ||
|
||
/// Represents a specific instance of `types.MethodWrapperType` | ||
|
Uh oh!
There was an error while loading. Please reload this page.