11use core:: ops:: ControlFlow ;
22use std:: borrow:: Cow ;
3+ use std:: cmp:: Ordering ;
34use std:: iter;
45
56use hir:: def_id:: { DefId , DefIdMap , LocalDefId } ;
@@ -18,7 +19,7 @@ use rustc_middle::ty::{
1819 Upcast ,
1920} ;
2021use rustc_middle:: { bug, span_bug} ;
21- use rustc_span:: { DUMMY_SP , Span } ;
22+ use rustc_span:: { BytePos , DUMMY_SP , Span } ;
2223use rustc_trait_selection:: error_reporting:: InferCtxtErrorExt ;
2324use rustc_trait_selection:: infer:: InferCtxtExt ;
2425use rustc_trait_selection:: regions:: InferCtxtRegionExt ;
@@ -1795,6 +1796,105 @@ fn compare_number_of_method_arguments<'tcx>(
17951796 ) ,
17961797 ) ;
17971798
1799+ // Only emit verbose suggestions when the trait span isn’t local (e.g., cross-crate).
1800+ if !trait_m. def_id . is_local ( ) {
1801+ let trait_sig = tcx. fn_sig ( trait_m. def_id ) ;
1802+ let trait_arg_idents = tcx. fn_arg_idents ( trait_m. def_id ) ;
1803+ let sm = tcx. sess . source_map ( ) ;
1804+ // Find the span of the space between the parentheses in a method.
1805+ // fn foo(...) {}
1806+ // ^^^
1807+ let impl_inputs_span = if let ( Some ( first) , Some ( last) ) =
1808+ ( impl_m_sig. decl . inputs . first ( ) , impl_m_sig. decl . inputs . last ( ) )
1809+ {
1810+ // We have inputs; construct the span from those.
1811+ // fn foo( a: i32, b: u32 ) {}
1812+ // ^^^^^^^^^^^^^^^^
1813+ let arg_idents = tcx. fn_arg_idents ( impl_m. def_id ) ;
1814+ let first_lo = arg_idents
1815+ . get ( 0 )
1816+ . and_then ( |id| id. map ( |id| id. span . lo ( ) ) )
1817+ . unwrap_or ( first. span . lo ( ) ) ;
1818+ Some ( impl_m_sig. span . with_lo ( first_lo) . with_hi ( last. span . hi ( ) ) )
1819+ } else {
1820+ // We have no inputs; construct the span to the left of the last parenthesis
1821+ // fn foo( ) {}
1822+ // ^
1823+ // FIXME: Keep spans for function parentheses around to make this more robust.
1824+ sm. span_to_snippet ( impl_m_sig. span ) . ok ( ) . and_then ( |s| {
1825+ let right_paren = s. as_bytes ( ) . iter ( ) . rposition ( |& b| b == b')' ) ?;
1826+ let pos = impl_m_sig. span . lo ( ) + BytePos ( right_paren as u32 ) ;
1827+ Some ( impl_m_sig. span . with_lo ( pos) . with_hi ( pos) )
1828+ } )
1829+ } ;
1830+ let suggestion = match trait_number_args. cmp ( & impl_number_args) {
1831+ Ordering :: Greater => {
1832+ // Span is right before the end parenthesis:
1833+ // fn foo(a: i32 ) {}
1834+ // ^
1835+ let trait_inputs = trait_sig. skip_binder ( ) . inputs ( ) . skip_binder ( ) ;
1836+ let missing = trait_inputs
1837+ . iter ( )
1838+ . enumerate ( )
1839+ . skip ( impl_number_args)
1840+ . map ( |( idx, ty) | {
1841+ let name = trait_arg_idents
1842+ . get ( idx)
1843+ . and_then ( |ident| * ident)
1844+ . map ( |ident| ident. to_string ( ) )
1845+ . unwrap_or_else ( || "_" . to_string ( ) ) ;
1846+ format ! ( "{name}: {ty}" )
1847+ } )
1848+ . collect :: < Vec < _ > > ( ) ;
1849+
1850+ if missing. is_empty ( ) {
1851+ None
1852+ } else {
1853+ impl_inputs_span. map ( |s| {
1854+ let span = s. shrink_to_hi ( ) ;
1855+ let prefix = if impl_number_args == 0 { "" } else { ", " } ;
1856+ let replacement = format ! ( "{prefix}{}" , missing. join( ", " ) ) ;
1857+ (
1858+ span,
1859+ format ! (
1860+ "add the missing parameter{} from the trait" ,
1861+ pluralize!( trait_number_args - impl_number_args)
1862+ ) ,
1863+ replacement,
1864+ )
1865+ } )
1866+ }
1867+ }
1868+ Ordering :: Less => impl_inputs_span. and_then ( |full| {
1869+ // Span of the arguments that there are too many of:
1870+ // fn foo(a: i32, b: u32) {}
1871+ // ^^^^^^^^
1872+ let lo = if trait_number_args == 0 {
1873+ full. lo ( )
1874+ } else {
1875+ impl_m_sig
1876+ . decl
1877+ . inputs
1878+ . get ( trait_number_args - 1 )
1879+ . map ( |arg| arg. span . hi ( ) ) ?
1880+ } ;
1881+ let span = full. with_lo ( lo) ;
1882+ Some ( (
1883+ span,
1884+ format ! (
1885+ "remove the extra parameter{} to match the trait" ,
1886+ pluralize!( impl_number_args - trait_number_args)
1887+ ) ,
1888+ String :: new ( ) ,
1889+ ) )
1890+ } ) ,
1891+ Ordering :: Equal => unreachable ! ( ) ,
1892+ } ;
1893+ if let Some ( ( span, msg, replacement) ) = suggestion {
1894+ err. span_suggestion_verbose ( span, msg, replacement, Applicability :: MaybeIncorrect ) ;
1895+ }
1896+ }
1897+
17981898 return Err ( err. emit_unless_delay ( delay) ) ;
17991899 }
18001900
0 commit comments