@@ -4790,35 +4790,48 @@ impl<'db> Type<'db> {
4790
4790
}
4791
4791
}
4792
4792
4793
+ /// Similar to [`Self::try_enter`], but for async context managers.
4794
+ fn aenter ( self , db : & ' db dyn Db ) -> Type < ' db > {
4795
+ // TODO: Add proper error handling and rename this method to `try_aenter`.
4796
+ self . try_call_dunder ( db, "__aenter__" , CallArguments :: none ( ) )
4797
+ . map_or ( Type :: unknown ( ) , |result| {
4798
+ result. return_type ( db) . resolve_await ( db)
4799
+ } )
4800
+ }
4801
+
4802
+ /// Resolve the type of an `await …` expression where `self` is the type of the awaitable.
4793
4803
fn resolve_await ( self , db : & ' db dyn Db ) -> Type < ' db > {
4804
+ // TODO: Add proper error handling and rename this method to `try_await`.
4794
4805
self . try_call_dunder ( db, "__await__" , CallArguments :: none ( ) )
4795
4806
. map_or ( Type :: unknown ( ) , |result| {
4796
- let generator_ty = result. return_type ( db) ;
4797
-
4798
- if let Type :: ProtocolInstance ( instance) = generator_ty {
4799
- if let Protocol :: FromClass ( class) = instance. inner {
4800
- if class. is_known ( db, KnownClass :: Generator ) {
4801
- if let Some ( specialization) =
4802
- class. class_literal_specialized ( db, None ) . 1
4803
- {
4804
- if let [ _, _, return_ty] = specialization. types ( db) {
4805
- return * return_ty;
4806
- }
4807
- }
4807
+ result
4808
+ . return_type ( db)
4809
+ . generator_return_type ( db)
4810
+ . unwrap_or_else ( Type :: unknown)
4811
+ } )
4812
+ }
4813
+
4814
+ /// Get the return type of a `yield from …` expression where `self` is the type of the generator.
4815
+ ///
4816
+ /// This corresponds to the `ReturnT` parameter of the generic `typing.Generator[YieldT, SendT, ReturnT]`
4817
+ /// protocol.
4818
+ fn generator_return_type ( self , db : & ' db dyn Db ) -> Option < Type < ' db > > {
4819
+ // TODO: Ideally, we would first try to upcast `self` to an instance of `Generator` and *then*
4820
+ // match on the protocol instance to get the `ReturnType` type parameter.
4821
+
4822
+ if let Type :: ProtocolInstance ( instance) = self {
4823
+ if let Protocol :: FromClass ( class) = instance. inner {
4824
+ if class. is_known ( db, KnownClass :: Generator ) {
4825
+ if let Some ( specialization) = class. class_literal_specialized ( db, None ) . 1 {
4826
+ if let [ _, _, return_ty] = specialization. types ( db) {
4827
+ return Some ( * return_ty) ;
4808
4828
}
4809
4829
}
4810
4830
}
4831
+ }
4832
+ }
4811
4833
4812
- Type :: unknown ( )
4813
- } )
4814
- }
4815
-
4816
- fn aenter ( self , db : & ' db dyn Db ) -> Type < ' db > {
4817
- // TODO: Rename this method to `try_aenter` and add error handling
4818
- self . try_call_dunder ( db, "__aenter__" , CallArguments :: none ( ) )
4819
- . map_or ( Type :: unknown ( ) , |result| {
4820
- result. return_type ( db) . resolve_await ( db)
4821
- } )
4834
+ None
4822
4835
}
4823
4836
4824
4837
/// Given a class literal or non-dynamic SubclassOf type, try calling it (creating an instance)
0 commit comments