@@ -1694,8 +1694,15 @@ fn compare_number_of_method_arguments<'tcx>(
16941694) -> Result < ( ) , ErrorGuaranteed > {
16951695 let impl_m_fty = tcx. fn_sig ( impl_m. def_id ) ;
16961696 let trait_m_fty = tcx. fn_sig ( trait_m. def_id ) ;
1697- let trait_number_args = trait_m_fty. skip_binder ( ) . inputs ( ) . skip_binder ( ) . len ( ) ;
1698- let impl_number_args = impl_m_fty. skip_binder ( ) . inputs ( ) . skip_binder ( ) . len ( ) ;
1697+ let trait_inputs = trait_m_fty. skip_binder ( ) . inputs ( ) . skip_binder ( ) ;
1698+ let impl_inputs = impl_m_fty. skip_binder ( ) . inputs ( ) . skip_binder ( ) ;
1699+ let trait_number_args = trait_inputs. len ( ) ;
1700+ let impl_number_args = impl_inputs. len ( ) ;
1701+ let params_prefix_match = impl_inputs
1702+ . iter ( )
1703+ . zip ( trait_inputs)
1704+ . take ( impl_number_args. min ( trait_number_args) )
1705+ . all ( |( impl_ty, trait_ty) | impl_ty == trait_ty) ;
16991706
17001707 if trait_number_args != impl_number_args {
17011708 let trait_sig = trait_m. def_id . as_local ( ) . and_then ( |def_id| {
@@ -1765,28 +1772,6 @@ fn compare_number_of_method_arguments<'tcx>(
17651772 ) ;
17661773
17671774 let sm = tcx. sess . source_map ( ) ;
1768-
1769- fn find_param_bounds ( snippet : & str ) -> Option < ( usize , usize ) > {
1770- let start = snippet. find ( '(' ) ?;
1771- let mut depth = 1usize ;
1772- let bytes = snippet. as_bytes ( ) ;
1773- let mut i = start + 1 ;
1774- while i < bytes. len ( ) {
1775- match bytes[ i] {
1776- b'(' => depth += 1 ,
1777- b')' => {
1778- depth -= 1 ;
1779- if depth == 0 {
1780- return Some ( ( start + 1 , i) ) ;
1781- }
1782- }
1783- _ => { }
1784- }
1785- i += 1 ;
1786- }
1787- None
1788- }
1789-
17901775 let impl_inputs_span = ( !impl_m_sig. span . is_dummy ( ) )
17911776 . then ( || {
17921777 sm. span_to_snippet ( impl_m_sig. span ) . ok ( ) . and_then ( |snippet| {
@@ -1799,7 +1784,28 @@ fn compare_number_of_method_arguments<'tcx>(
17991784 } )
18001785 . flatten ( ) ;
18011786
1802- let suggestion = trait_sig
1787+ let missing_params = ( trait_number_args > impl_number_args && params_prefix_match)
1788+ . then ( || {
1789+ trait_sig
1790+ . as_ref ( )
1791+ . and_then ( |( _, trait_sig) | {
1792+ sm. span_to_snippet ( trait_sig. span ) . ok ( ) . and_then ( |snippet| {
1793+ find_param_bounds ( & snippet) . and_then ( |( lo_rel, hi_rel) | {
1794+ tail_params ( & snippet[ lo_rel..hi_rel] , impl_number_args)
1795+ } )
1796+ } )
1797+ } )
1798+ . or_else ( || {
1799+ let signature = trait_m. signature ( tcx) ;
1800+ find_param_bounds ( & signature) . and_then ( |( lo, hi) | {
1801+ tail_params ( & signature[ lo..hi] . trim ( ) , impl_number_args)
1802+ } )
1803+ } )
1804+ } )
1805+ . flatten ( ) ;
1806+
1807+ let full_suggestion = trait_sig
1808+ . as_ref ( )
18031809 . and_then ( |( _, trait_sig) | {
18041810 sm. span_to_snippet ( trait_sig. span ) . ok ( ) . and_then ( |snippet| {
18051811 find_param_bounds ( & snippet)
@@ -1811,7 +1817,15 @@ fn compare_number_of_method_arguments<'tcx>(
18111817 find_param_bounds ( & signature) . map ( |( lo, hi) | signature[ lo..hi] . trim ( ) . to_string ( ) )
18121818 } ) ;
18131819
1814- if let ( Some ( span) , Some ( suggestion) ) = ( impl_inputs_span, suggestion) {
1820+ if let ( Some ( span) , Some ( missing) ) = ( impl_inputs_span, missing_params) {
1821+ let sep = if impl_number_args == 0 { "" } else { ", " } ;
1822+ err. span_suggestion_verbose (
1823+ span. shrink_to_hi ( ) ,
1824+ "add the missing parameter from the trait" ,
1825+ format ! ( "{sep}{missing}" ) ,
1826+ Applicability :: MaybeIncorrect ,
1827+ ) ;
1828+ } else if let ( Some ( span) , Some ( suggestion) ) = ( impl_inputs_span, full_suggestion) {
18151829 err. span_suggestion_verbose (
18161830 span,
18171831 "modify the signature to match the trait definition" ,
@@ -1826,6 +1840,53 @@ fn compare_number_of_method_arguments<'tcx>(
18261840 Ok ( ( ) )
18271841}
18281842
1843+ fn find_param_bounds ( snippet : & str ) -> Option < ( usize , usize ) > {
1844+ let start = snippet. find ( '(' ) ?;
1845+ let mut depth = 1usize ;
1846+ let bytes = snippet. as_bytes ( ) ;
1847+ let mut i = start + 1 ;
1848+ while i < bytes. len ( ) {
1849+ match bytes[ i] {
1850+ b'(' => depth += 1 ,
1851+ b')' => {
1852+ depth -= 1 ;
1853+ if depth == 0 {
1854+ return Some ( ( start + 1 , i) ) ;
1855+ }
1856+ }
1857+ _ => { }
1858+ }
1859+ i += 1 ;
1860+ }
1861+ None
1862+ }
1863+
1864+ fn split_top_level_params ( params : & str ) -> Vec < String > {
1865+ let mut depth = 0usize ;
1866+ let mut start = 0 ;
1867+ let mut out = Vec :: new ( ) ;
1868+ for ( idx, ch) in params. char_indices ( ) {
1869+ match ch {
1870+ '(' | '<' | '[' | '{' => depth += 1 ,
1871+ ')' | '>' | ']' | '}' => depth = depth. saturating_sub ( 1 ) ,
1872+ ',' if depth == 0 => {
1873+ out. push ( params[ start..idx] . trim ( ) . to_string ( ) ) ;
1874+ start = idx + 1 ;
1875+ }
1876+ _ => { }
1877+ }
1878+ }
1879+ if start < params. len ( ) {
1880+ out. push ( params[ start..] . trim ( ) . to_string ( ) ) ;
1881+ }
1882+ out
1883+ }
1884+
1885+ fn tail_params ( params : & str , skip : usize ) -> Option < String > {
1886+ let parts = split_top_level_params ( params) ;
1887+ ( parts. len ( ) > skip) . then ( || parts. into_iter ( ) . skip ( skip) . collect :: < Vec < _ > > ( ) . join ( ", " ) )
1888+ }
1889+
18291890fn compare_synthetic_generics < ' tcx > (
18301891 tcx : TyCtxt < ' tcx > ,
18311892 impl_m : ty:: AssocItem ,
0 commit comments