@@ -301,103 +301,108 @@ impl<'a> CompletionContext<'a> {
301301 . find_map ( ast:: Impl :: cast) ;
302302 }
303303
304+ fn expected_type_and_name ( & self ) -> ( Option < Type > , Option < NameOrNameRef > ) {
305+ let mut node = match self . token . parent ( ) {
306+ Some ( it) => it,
307+ None => return ( None , None ) ,
308+ } ;
309+ loop {
310+ break match_ast ! {
311+ match node {
312+ ast:: LetStmt ( it) => {
313+ cov_mark:: hit!( expected_type_let_with_leading_char) ;
314+ cov_mark:: hit!( expected_type_let_without_leading_char) ;
315+ let ty = it. pat( )
316+ . and_then( |pat| self . sema. type_of_pat( & pat) ) ;
317+ let name = if let Some ( ast:: Pat :: IdentPat ( ident) ) = it. pat( ) {
318+ ident. name( ) . map( NameOrNameRef :: Name )
319+ } else {
320+ None
321+ } ;
322+
323+ ( ty, name)
324+ } ,
325+ ast:: ArgList ( _it) => {
326+ cov_mark:: hit!( expected_type_fn_param_with_leading_char) ;
327+ cov_mark:: hit!( expected_type_fn_param_without_leading_char) ;
328+ ActiveParameter :: at_token(
329+ & self . sema,
330+ self . token. clone( ) ,
331+ ) . map( |ap| {
332+ let name = ap. ident( ) . map( NameOrNameRef :: Name ) ;
333+ ( Some ( ap. ty) , name)
334+ } )
335+ . unwrap_or( ( None , None ) )
336+ } ,
337+ ast:: RecordExprFieldList ( _it) => {
338+ cov_mark:: hit!( expected_type_struct_field_without_leading_char) ;
339+ self . token. prev_sibling_or_token( )
340+ . and_then( |se| se. into_node( ) )
341+ . and_then( |node| ast:: RecordExprField :: cast( node) )
342+ . and_then( |rf| self . sema. resolve_record_field( & rf) . zip( Some ( rf) ) )
343+ . map( |( f, rf) |(
344+ Some ( f. 0 . ty( self . db) ) ,
345+ rf. field_name( ) . map( NameOrNameRef :: NameRef ) ,
346+ ) )
347+ . unwrap_or( ( None , None ) )
348+ } ,
349+ ast:: RecordExprField ( it) => {
350+ cov_mark:: hit!( expected_type_struct_field_with_leading_char) ;
351+ self . sema
352+ . resolve_record_field( & it)
353+ . map( |f|(
354+ Some ( f. 0 . ty( self . db) ) ,
355+ it. field_name( ) . map( NameOrNameRef :: NameRef ) ,
356+ ) )
357+ . unwrap_or( ( None , None ) )
358+ } ,
359+ ast:: MatchExpr ( it) => {
360+ cov_mark:: hit!( expected_type_match_arm_without_leading_char) ;
361+ let ty = it. expr( )
362+ . and_then( |e| self . sema. type_of_expr( & e) ) ;
363+ ( ty, None )
364+ } ,
365+ ast:: IfExpr ( it) => {
366+ cov_mark:: hit!( expected_type_if_let_without_leading_char) ;
367+ let ty = it. condition( )
368+ . and_then( |cond| cond. expr( ) )
369+ . and_then( |e| self . sema. type_of_expr( & e) ) ;
370+ ( ty, None )
371+ } ,
372+ ast:: IdentPat ( it) => {
373+ cov_mark:: hit!( expected_type_if_let_with_leading_char) ;
374+ cov_mark:: hit!( expected_type_match_arm_with_leading_char) ;
375+ let ty = self . sema. type_of_pat( & ast:: Pat :: from( it) ) ;
376+ ( ty, None )
377+ } ,
378+ ast:: Fn ( it) => {
379+ cov_mark:: hit!( expected_type_fn_ret_with_leading_char) ;
380+ cov_mark:: hit!( expected_type_fn_ret_without_leading_char) ;
381+ let def = self . sema. to_def( & it) ;
382+ ( def. map( |def| def. ret_type( self . db) ) , None )
383+ } ,
384+ ast:: Stmt ( it) => ( None , None ) ,
385+ _ => {
386+ match node. parent( ) {
387+ Some ( n) => {
388+ node = n;
389+ continue ;
390+ } ,
391+ None => ( None , None ) ,
392+ }
393+ } ,
394+ }
395+ } ;
396+ }
397+ }
398+
304399 fn fill (
305400 & mut self ,
306401 original_file : & SyntaxNode ,
307402 file_with_fake_ident : SyntaxNode ,
308403 offset : TextSize ,
309404 ) {
310- let ( expected_type, expected_name) = {
311- let mut node = match self . token . parent ( ) {
312- Some ( it) => it,
313- None => return ,
314- } ;
315- loop {
316- break match_ast ! {
317- match node {
318- ast:: LetStmt ( it) => {
319- cov_mark:: hit!( expected_type_let_with_leading_char) ;
320- cov_mark:: hit!( expected_type_let_without_leading_char) ;
321- let ty = it. pat( )
322- . and_then( |pat| self . sema. type_of_pat( & pat) ) ;
323- let name = if let Some ( ast:: Pat :: IdentPat ( ident) ) = it. pat( ) {
324- ident. name( ) . map( NameOrNameRef :: Name )
325- } else {
326- None
327- } ;
328-
329- ( ty, name)
330- } ,
331- ast:: ArgList ( _it) => {
332- cov_mark:: hit!( expected_type_fn_param_with_leading_char) ;
333- cov_mark:: hit!( expected_type_fn_param_without_leading_char) ;
334- ActiveParameter :: at_token(
335- & self . sema,
336- self . token. clone( ) ,
337- ) . map( |ap| {
338- let name = ap. ident( ) . map( NameOrNameRef :: Name ) ;
339- ( Some ( ap. ty) , name)
340- } )
341- . unwrap_or( ( None , None ) )
342- } ,
343- ast:: RecordExprFieldList ( _it) => {
344- cov_mark:: hit!( expected_type_struct_field_without_leading_char) ;
345- self . token. prev_sibling_or_token( )
346- . and_then( |se| se. into_node( ) )
347- . and_then( |node| ast:: RecordExprField :: cast( node) )
348- . and_then( |rf| self . sema. resolve_record_field( & rf) . zip( Some ( rf) ) )
349- . map( |( f, rf) |(
350- Some ( f. 0 . ty( self . db) ) ,
351- rf. field_name( ) . map( NameOrNameRef :: NameRef ) ,
352- ) )
353- . unwrap_or( ( None , None ) )
354- } ,
355- ast:: RecordExprField ( it) => {
356- cov_mark:: hit!( expected_type_struct_field_with_leading_char) ;
357- self . sema
358- . resolve_record_field( & it)
359- . map( |f|(
360- Some ( f. 0 . ty( self . db) ) ,
361- it. field_name( ) . map( NameOrNameRef :: NameRef ) ,
362- ) )
363- . unwrap_or( ( None , None ) )
364- } ,
365- ast:: MatchExpr ( it) => {
366- cov_mark:: hit!( expected_type_match_arm_without_leading_char) ;
367- let ty = it. expr( )
368- . and_then( |e| self . sema. type_of_expr( & e) ) ;
369-
370- ( ty, None )
371- } ,
372- ast:: IdentPat ( it) => {
373- cov_mark:: hit!( expected_type_if_let_with_leading_char) ;
374- cov_mark:: hit!( expected_type_match_arm_with_leading_char) ;
375- let ty = self . sema. type_of_pat( & ast:: Pat :: from( it) ) ;
376-
377- ( ty, None )
378- } ,
379- ast:: Fn ( _it) => {
380- cov_mark:: hit!( expected_type_fn_ret_with_leading_char) ;
381- cov_mark:: hit!( expected_type_fn_ret_without_leading_char) ;
382- let ty = self . token. ancestors( )
383- . find_map( |ancestor| ast:: Expr :: cast( ancestor) )
384- . and_then( |expr| self . sema. type_of_expr( & expr) ) ;
385-
386- ( ty, None )
387- } ,
388- _ => {
389- match node. parent( ) {
390- Some ( n) => {
391- node = n;
392- continue ;
393- } ,
394- None => ( None , None ) ,
395- }
396- } ,
397- }
398- } ;
399- }
400- } ;
405+ let ( expected_type, expected_name) = self . expected_type_and_name ( ) ;
401406 self . expected_type = expected_type;
402407 self . expected_name = expected_name;
403408 self . attribute_under_caret = find_node_at_offset ( & file_with_fake_ident, offset) ;
@@ -802,6 +807,7 @@ fn foo() {
802807
803808 #[ test]
804809 fn expected_type_if_let_without_leading_char ( ) {
810+ cov_mark:: check!( expected_type_if_let_without_leading_char) ;
805811 check_expected_type_and_name (
806812 r#"
807813enum Foo { Bar, Baz, Quux }
@@ -811,8 +817,8 @@ fn foo() {
811817 if let $0 = f { }
812818}
813819"# ,
814- expect ! [ [ r#"ty: () , name: ?"# ] ] ,
815- ) // FIXME should be `ty: u32, name: ?`
820+ expect ! [ [ r#"ty: Foo , name: ?"# ] ] ,
821+ )
816822 }
817823
818824 #[ test]
@@ -840,8 +846,8 @@ fn foo() -> u32 {
840846 $0
841847}
842848"# ,
843- expect ! [ [ r#"ty: () , name: ?"# ] ] ,
844- ) // FIXME this should be `ty: u32, name: ?`
849+ expect ! [ [ r#"ty: u32 , name: ?"# ] ] ,
850+ )
845851 }
846852
847853 #[ test]
@@ -852,6 +858,18 @@ fn foo() -> u32 {
852858fn foo() -> u32 {
853859 c$0
854860}
861+ "# ,
862+ expect ! [ [ r#"ty: u32, name: ?"# ] ] ,
863+ )
864+ }
865+
866+ #[ test]
867+ fn expected_type_fn_ret_fn_ref_fully_typed ( ) {
868+ check_expected_type_and_name (
869+ r#"
870+ fn foo() -> u32 {
871+ foo$0
872+ }
855873"# ,
856874 expect ! [ [ r#"ty: u32, name: ?"# ] ] ,
857875 )
0 commit comments