@@ -127,7 +127,7 @@ use syntax::ast;
127127use syntax:: attr;
128128use syntax:: feature_gate:: { GateIssue , emit_feature_err} ;
129129use syntax:: source_map:: { DUMMY_SP , original_sp} ;
130- use syntax:: symbol:: { kw, sym} ;
130+ use syntax:: symbol:: { kw, sym, Ident } ;
131131use syntax:: util:: parser:: ExprPrecedence ;
132132
133133use std:: cell:: { Cell , RefCell , Ref , RefMut } ;
@@ -1925,34 +1925,7 @@ fn check_impl_items_against_trait<'tcx>(
19251925 }
19261926
19271927 if !missing_items. is_empty ( ) {
1928- let mut err = struct_span_err ! ( tcx. sess, impl_span, E0046 ,
1929- "not all trait items implemented, missing: `{}`" ,
1930- missing_items. iter( )
1931- . map( |trait_item| trait_item. ident. to_string( ) )
1932- . collect:: <Vec <_>>( ) . join( "`, `" ) ) ;
1933- err. span_label ( impl_span, format ! ( "missing `{}` in implementation" ,
1934- missing_items. iter( )
1935- . map( |trait_item| trait_item. ident. to_string( ) )
1936- . 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 ( ) ;
1943- 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 ;
1948- if let Some ( span) = tcx. hir ( ) . span_if_local ( trait_item. def_id ) {
1949- err. span_label ( span, format ! ( "`{}` from trait" , trait_item. ident) ) ;
1950- err. tool_only_span_suggestion ( sugg_sp, & msg, code, appl) ;
1951- } else {
1952- err. span_suggestion_hidden ( sugg_sp, & msg, code, appl) ;
1953- }
1954- }
1955- err. emit ( ) ;
1928+ missing_items_err ( tcx, impl_span, & missing_items, full_impl_span) ;
19561929 }
19571930
19581931 if !invalidated_items. is_empty ( ) {
@@ -1965,11 +1938,100 @@ fn check_impl_items_against_trait<'tcx>(
19651938 invalidator. ident,
19661939 invalidated_items. iter( )
19671940 . map( |name| name. to_string( ) )
1968- . collect:: <Vec <_>>( ) . join( "`, `" ) )
1941+ . collect:: <Vec <_>>( ) . join( "`, `" )
1942+ )
1943+ }
1944+ }
1945+
1946+ fn missing_items_err (
1947+ tcx : TyCtxt < ' _ > ,
1948+ impl_span : Span ,
1949+ missing_items : & [ ty:: AssocItem ] ,
1950+ full_impl_span : Span ,
1951+ ) {
1952+ let missing_items_msg = missing_items. iter ( )
1953+ . map ( |trait_item| trait_item. ident . to_string ( ) )
1954+ . collect :: < Vec < _ > > ( ) . join ( "`, `" ) ;
1955+
1956+ let mut err = struct_span_err ! (
1957+ tcx. sess,
1958+ impl_span,
1959+ E0046 ,
1960+ "not all trait items implemented, missing: `{}`" ,
1961+ missing_items_msg
1962+ ) ;
1963+ err. span_label ( impl_span, format ! ( "missing `{}` in implementation" , missing_items_msg) ) ;
1964+
1965+ // `Span` before impl block closing brace.
1966+ let hi = full_impl_span. hi ( ) - BytePos ( 1 ) ;
1967+ // Point at the place right before the closing brace of the relevant `impl` to suggest
1968+ // adding the associated item at the end of its body.
1969+ let sugg_sp = full_impl_span. with_lo ( hi) . with_hi ( hi) ;
1970+ // Obtain the level of indentation ending in `sugg_sp`.
1971+ let indentation = tcx. sess . source_map ( ) . span_to_margin ( sugg_sp) . unwrap_or ( 0 ) ;
1972+ // Make the whitespace that will make the suggestion have the right indentation.
1973+ let padding: String = ( 0 ..indentation) . map ( |_| " " ) . collect ( ) ;
1974+
1975+ for trait_item in missing_items {
1976+ let snippet = suggestion_signature ( & trait_item, tcx) ;
1977+ let code = format ! ( "{}{}\n {}" , padding, snippet, padding) ;
1978+ let msg = format ! ( "implement the missing item: `{}`" , snippet) ;
1979+ let appl = Applicability :: HasPlaceholders ;
1980+ if let Some ( span) = tcx. hir ( ) . span_if_local ( trait_item. def_id ) {
1981+ err. span_label ( span, format ! ( "`{}` from trait" , trait_item. ident) ) ;
1982+ err. tool_only_span_suggestion ( sugg_sp, & msg, code, appl) ;
1983+ } else {
1984+ err. span_suggestion_hidden ( sugg_sp, & msg, code, appl) ;
1985+ }
19691986 }
1987+ err. emit ( ) ;
1988+ }
1989+
1990+ /// Return placeholder code for the given function.
1991+ fn fn_sig_suggestion ( sig : & ty:: FnSig < ' _ > , ident : Ident ) -> String {
1992+ let args = sig. inputs ( )
1993+ . iter ( )
1994+ . map ( |ty| Some ( match ty. kind {
1995+ ty:: Param ( param) if param. name == kw:: SelfUpper => "self" . to_string ( ) ,
1996+ ty:: Ref ( reg, ref_ty, mutability) => {
1997+ let reg = match & format ! ( "{}" , reg) [ ..] {
1998+ "'_" | "" => String :: new ( ) ,
1999+ reg => format ! ( "{} " , reg) ,
2000+ } ;
2001+ match ref_ty. kind {
2002+ ty:: Param ( param) if param. name == kw:: SelfUpper => {
2003+ format ! ( "&{}{}self" , reg, mutability. prefix_str( ) )
2004+ }
2005+ _ => format ! ( "_: {:?}" , ty) ,
2006+ }
2007+ }
2008+ _ => format ! ( "_: {:?}" , ty) ,
2009+ } ) )
2010+ . chain ( std:: iter:: once ( if sig. c_variadic {
2011+ Some ( "..." . to_string ( ) )
2012+ } else {
2013+ None
2014+ } ) )
2015+ . filter_map ( |arg| arg)
2016+ . collect :: < Vec < String > > ( )
2017+ . join ( ", " ) ;
2018+ let output = sig. output ( ) ;
2019+ let output = if !output. is_unit ( ) {
2020+ format ! ( " -> {:?}" , output)
2021+ } else {
2022+ String :: new ( )
2023+ } ;
2024+
2025+ let unsafety = sig. unsafety . prefix_str ( ) ;
2026+ // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
2027+ // not be present in the `fn` definition, not will we account for renamed
2028+ // lifetimes between the `impl` and the `trait`, but this should be good enough to
2029+ // fill in a significant portion of the missing code, and other subsequent
2030+ // suggestions can help the user fix the code.
2031+ format ! ( "{}fn {}({}){} {{ unimplemented!() }}" , unsafety, ident, args, output)
19702032}
19712033
1972- /// Given a `ty::AssocItem` and a `TyCtxt`, return placeholder code for that associated item.
2034+ /// Return placeholder code for the given associated item.
19732035/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
19742036/// structured suggestion.
19752037fn suggestion_signature ( assoc : & ty:: AssocItem , tcx : TyCtxt < ' _ > ) -> String {
@@ -1979,61 +2041,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
19792041 // late-bound regions, and we don't want method signatures to show up
19802042 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
19812043 // 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)
2044+ fn_sig_suggestion ( tcx. fn_sig ( assoc. def_id ) . skip_binder ( ) , assoc. ident )
20372045 }
20382046 ty:: AssocKind :: Type => format ! ( "type {} = Type;" , assoc. ident) ,
20392047 // FIXME(type_alias_impl_trait): we should print bounds here too.
0 commit comments