@@ -195,7 +195,7 @@ impl Parse for HasFnsItem {
195195 Ok ( HasFnsItem :: Trait ( t) )
196196 } else if lookahead. peek ( Token ! [ impl ] ) {
197197 let mut imp = input. parse ( ) ?;
198- flatten_associated_items_in_impl_fns ( & mut imp) ;
198+ flatten_associated_items_in_impl_fns ( & mut imp) ? ;
199199 Ok ( HasFnsItem :: Impl ( imp) )
200200 } else {
201201 Err ( lookahead. error ( ) )
@@ -306,46 +306,95 @@ fn unpack_result(typ: &Type) -> Option<(Type, Type)> {
306306 }
307307}
308308
309- fn flatten_associated_items_in_impl_fns ( imp : & mut ItemImpl ) {
309+ fn flatten_associated_items_in_impl_fns ( imp : & mut ItemImpl ) -> Result < ( ) , Error > {
310310 // TODO: Flatten associated consts used in functions.
311311 // Flatten associated types used in functions.
312- let associated_types = imp
312+ let associated_types: HashMap < Ident , Type > = imp
313313 . items
314314 . iter ( )
315315 . filter_map ( |item| match item {
316316 ImplItem :: Type ( i) => Some ( ( i. ident . clone ( ) , i. ty . clone ( ) ) ) ,
317317 _ => None ,
318318 } )
319- . collect :: < HashMap < _ , _ > > ( ) ;
320- let fn_input_types = imp
321- . items
322- . iter_mut ( )
323- . filter_map ( |item| match item {
324- ImplItem :: Fn ( f) => Some ( f. sig . inputs . iter_mut ( ) . filter_map ( |input| match input {
325- FnArg :: Typed ( t) => Some ( & mut t. ty ) ,
326- _ => None ,
327- } ) ) ,
328- _ => None ,
329- } )
330- . flatten ( ) ;
331- for t in fn_input_types {
332- if let Type :: Path ( TypePath { qself : None , path } ) = t. as_mut ( ) {
333- let segments = & path. segments ;
334- if segments. len ( ) == 2
335- && segments. first ( ) == Some ( & PathSegment :: from ( format_ident ! ( "Self" ) ) )
336- {
337- if let Some ( PathSegment {
338- arguments : PathArguments :: None ,
339- ident,
340- } ) = segments. get ( 1 )
341- {
342- if let Some ( resolved_ty) = associated_types. get ( ident) {
343- * t. as_mut ( ) = resolved_ty. clone ( ) ;
319+ . collect ( ) ;
320+
321+ // Resolve Self::* in function input types and return types.
322+ for item in imp. items . iter_mut ( ) {
323+ if let ImplItem :: Fn ( f) = item {
324+ for input in f. sig . inputs . iter_mut ( ) {
325+ if let FnArg :: Typed ( t) = input {
326+ if let Some ( resolved) = resolve_self_type ( & t. ty , & associated_types) {
327+ * t. ty = resolved;
328+ }
329+ }
330+ }
331+ if let ReturnType :: Type ( _, ty) = & mut f. sig . output {
332+ if let Some ( resolved) = resolve_self_type ( ty, & associated_types) {
333+ * * ty = resolved;
334+ }
335+ }
336+ }
337+ }
338+
339+ // Check for any remaining unresolved Self::* types in fn signatures.
340+ for item in imp. items . iter ( ) {
341+ if let ImplItem :: Fn ( f) = item {
342+ for input in f. sig . inputs . iter ( ) {
343+ if let FnArg :: Typed ( t) = input {
344+ if let Some ( ident) = self_type_ident ( & t. ty ) {
345+ return Err ( Error :: new (
346+ t. ty . span ( ) ,
347+ format ! (
348+ "unresolved associated type `Self::{ident}` in function \
349+ parameter; use a concrete type instead"
350+ ) ,
351+ ) ) ;
344352 }
345353 }
346354 }
355+ if let ReturnType :: Type ( _, ty) = & f. sig . output {
356+ if let Some ( ident) = self_type_ident ( ty) {
357+ return Err ( Error :: new (
358+ ty. span ( ) ,
359+ format ! (
360+ "unresolved associated type `Self::{ident}` in return type; \
361+ use a concrete type instead"
362+ ) ,
363+ ) ) ;
364+ }
365+ }
366+ }
367+ }
368+
369+ Ok ( ( ) )
370+ }
371+
372+ /// If the type is `Self::Ident` and `Ident` exists in `associated_types`,
373+ /// return the resolved type. Otherwise return `None`.
374+ fn resolve_self_type ( ty : & Type , associated_types : & HashMap < Ident , Type > ) -> Option < Type > {
375+ match self_type_ident ( ty) {
376+ Some ( ident) => associated_types. get ( ident) . cloned ( ) ,
377+ None => None ,
378+ }
379+ }
380+
381+ /// If the type is `Self::Ident`, return the `Ident`. Otherwise return `None`.
382+ fn self_type_ident ( ty : & Type ) -> Option < & Ident > {
383+ if let Type :: Path ( TypePath { qself : None , path } ) = ty {
384+ let segments = & path. segments ;
385+ if segments. len ( ) == 2
386+ && segments. first ( ) == Some ( & PathSegment :: from ( format_ident ! ( "Self" ) ) )
387+ {
388+ if let Some ( PathSegment {
389+ arguments : PathArguments :: None ,
390+ ident,
391+ } ) = segments. get ( 1 )
392+ {
393+ return Some ( ident) ;
394+ }
347395 }
348396 }
397+ None
349398}
350399
351400pub fn ty_to_safe_ident_str ( ty : & Type ) -> String {
0 commit comments