@@ -1800,12 +1800,12 @@ fn check_specialization_validity<'tcx>(
18001800
18011801fn check_impl_items_against_trait < ' tcx > (
18021802 tcx : TyCtxt < ' tcx > ,
1803- impl_span : Span ,
1803+ full_impl_span : Span ,
18041804 impl_id : DefId ,
18051805 impl_trait_ref : ty:: TraitRef < ' tcx > ,
18061806 impl_item_refs : & [ hir:: ImplItemRef ] ,
18071807) {
1808- let impl_span = tcx. sess . source_map ( ) . def_span ( impl_span ) ;
1808+ let impl_span = tcx. sess . source_map ( ) . def_span ( full_impl_span ) ;
18091809
18101810 // If the trait reference itself is erroneous (so the compilation is going
18111811 // to fail), skip checking the items here -- the `impl_item` table in `tcx`
@@ -1934,26 +1934,115 @@ fn check_impl_items_against_trait<'tcx>(
19341934 missing_items. iter( )
19351935 . map( |trait_item| trait_item. ident. to_string( ) )
19361936 . collect:: <Vec <_>>( ) . join( "`, `" ) ) ) ;
1937+
1938+ // `Span` before impl block closing brace.
1939+ let hi = full_impl_span. hi ( ) - BytePos ( 1 ) ;
1940+ let sugg_sp = full_impl_span. with_lo ( hi) . with_hi ( hi) ;
1941+ let indentation = tcx. sess . source_map ( ) . span_to_margin ( sugg_sp) . unwrap_or ( 0 ) ;
1942+ let padding: String = ( 0 ..indentation) . map ( |_| " " ) . collect ( ) ;
19371943 for trait_item in missing_items {
1944+ let snippet = suggestion_signature ( & trait_item, tcx) ;
1945+ let code = format ! ( "{}{}\n {}" , padding, snippet, padding) ;
1946+ let msg = format ! ( "implement the missing item: `{}`" , snippet) ;
1947+ let appl = Applicability :: HasPlaceholders ;
19381948 if let Some ( span) = tcx. hir ( ) . span_if_local ( trait_item. def_id ) {
19391949 err. span_label ( span, format ! ( "`{}` from trait" , trait_item. ident) ) ;
1950+ err. tool_only_span_suggestion ( sugg_sp, & msg, code, appl) ;
19401951 } else {
1941- err. note_trait_signature ( trait_item. ident . to_string ( ) ,
1942- trait_item. signature ( tcx) ) ;
1952+ err. span_suggestion_hidden ( sugg_sp, & msg, code, appl) ;
19431953 }
19441954 }
19451955 err. emit ( ) ;
19461956 }
19471957
19481958 if !invalidated_items. is_empty ( ) {
19491959 let invalidator = overridden_associated_type. unwrap ( ) ;
1950- span_err ! ( tcx. sess, invalidator. span, E0399 ,
1951- "the following trait items need to be reimplemented \
1952- as `{}` was overridden: `{}`",
1953- invalidator. ident,
1954- invalidated_items. iter( )
1955- . map( |name| name. to_string( ) )
1956- . collect:: <Vec <_>>( ) . join( "`, `" ) )
1960+ span_err ! (
1961+ tcx. sess,
1962+ invalidator. span,
1963+ E0399 ,
1964+ "the following trait items need to be reimplemented as `{}` was overridden: `{}`" ,
1965+ invalidator. ident,
1966+ invalidated_items. iter( )
1967+ . map( |name| name. to_string( ) )
1968+ . collect:: <Vec <_>>( ) . join( "`, `" ) )
1969+ }
1970+ }
1971+
1972+ /// Given a `ty::AssocItem` and a `TyCtxt`, return placeholder code for that associated item.
1973+ /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
1974+ /// structured suggestion.
1975+ fn suggestion_signature ( assoc : & ty:: AssocItem , tcx : TyCtxt < ' _ > ) -> String {
1976+ match assoc. kind {
1977+ ty:: AssocKind :: Method => {
1978+ // We skip the binder here because the binder would deanonymize all
1979+ // late-bound regions, and we don't want method signatures to show up
1980+ // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
1981+ // regions just fine, showing `fn(&MyType)`.
1982+ let sig = tcx. fn_sig ( assoc. def_id ) ;
1983+ let unsafety = match sig. unsafety ( ) {
1984+ hir:: Unsafety :: Unsafe => "unsafe " ,
1985+ _ => "" ,
1986+ } ;
1987+ let args = sig. inputs ( )
1988+ . skip_binder ( )
1989+ . iter ( )
1990+ . map ( |ty| Some ( match ty. kind {
1991+ ty:: Param ( param) if param. name == kw:: SelfUpper => {
1992+ "self" . to_string ( )
1993+ }
1994+ ty:: Ref ( reg, ref_ty, mutability) => {
1995+ let mutability = match mutability {
1996+ hir:: Mutability :: MutMutable => "mut " ,
1997+ _ => "" ,
1998+ } ;
1999+ let mut reg = format ! ( "{}" , reg) ;
2000+ if & reg[ ..] == "'_" {
2001+ reg = "" . to_string ( ) ;
2002+ }
2003+ if & reg[ ..] != "" {
2004+ reg = format ! ( "{} " , reg) ;
2005+ }
2006+ match ref_ty. kind {
2007+ ty:: Param ( param)
2008+ if param. name == kw:: SelfUpper => {
2009+ format ! ( "&{}{}self" , reg, mutability)
2010+ }
2011+ _ => format ! ( "_: {:?}" , ty) ,
2012+ }
2013+
2014+ }
2015+ _ => format ! ( "_: {:?}" , ty) ,
2016+ } ) )
2017+ . chain ( std:: iter:: once ( if sig. c_variadic ( ) {
2018+ Some ( "..." . to_string ( ) )
2019+ } else {
2020+ None
2021+ } ) )
2022+ . filter_map ( |arg| arg)
2023+ . collect :: < Vec < String > > ( )
2024+ . join ( ", " ) ;
2025+ let output = sig. output ( ) ;
2026+ let output = if !output. skip_binder ( ) . is_unit ( ) {
2027+ format ! ( " -> {:?}" , output. skip_binder( ) )
2028+ } else {
2029+ String :: new ( )
2030+ } ;
2031+ // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
2032+ // not be present in the `fn` definition, not will we account for renamed
2033+ // lifetimes between the `impl` and the `trait`, but this should be good enough to
2034+ // fill in a significant portion of the missing code, and other subsequent
2035+ // suggestions can help the user fix the code.
2036+ format ! ( "{}fn {}({}){} {{ unimplemented!() }}" , unsafety, assoc. ident, args, output)
2037+ }
2038+ ty:: AssocKind :: Type => format ! ( "type {} = Type;" , assoc. ident) ,
2039+ // FIXME(type_alias_impl_trait): we should print bounds here too.
2040+ ty:: AssocKind :: OpaqueTy => format ! ( "type {} = Type;" , assoc. ident) ,
2041+ ty:: AssocKind :: Const => {
2042+ let ty = tcx. type_of ( assoc. def_id ) ;
2043+ let val = expr:: ty_kind_suggestion ( ty) . unwrap_or ( "value" ) ;
2044+ format ! ( "const {}: {:?} = {};" , assoc. ident, ty, val)
2045+ }
19572046 }
19582047}
19592048
0 commit comments