@@ -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 } ;
@@ -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`
@@ -1925,35 +1925,132 @@ 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- for trait_item in missing_items {
1938- if let Some ( span) = tcx. hir ( ) . span_if_local ( trait_item. def_id ) {
1939- err. span_label ( span, format ! ( "`{}` from trait" , trait_item. ident) ) ;
1940- } else {
1941- err. note_trait_signature ( trait_item. ident . to_string ( ) ,
1942- trait_item. signature ( tcx) ) ;
1943- }
1944- }
1945- err. emit ( ) ;
1928+ missing_items_err ( tcx, impl_span, & missing_items, full_impl_span) ;
19461929 }
19471930
19481931 if !invalidated_items. is_empty ( ) {
19491932 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( "`, `" ) )
1933+ span_err ! (
1934+ tcx. sess,
1935+ invalidator. span,
1936+ E0399 ,
1937+ "the following trait items need to be reimplemented as `{}` was overridden: `{}`" ,
1938+ invalidator. ident,
1939+ invalidated_items. iter( )
1940+ . map( |name| name. to_string( ) )
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+ }
1986+ }
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)
2032+ }
2033+
2034+ /// Return placeholder code for the given associated item.
2035+ /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
2036+ /// structured suggestion.
2037+ fn suggestion_signature ( assoc : & ty:: AssocItem , tcx : TyCtxt < ' _ > ) -> String {
2038+ match assoc. kind {
2039+ ty:: AssocKind :: Method => {
2040+ // We skip the binder here because the binder would deanonymize all
2041+ // late-bound regions, and we don't want method signatures to show up
2042+ // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
2043+ // regions just fine, showing `fn(&MyType)`.
2044+ fn_sig_suggestion ( tcx. fn_sig ( assoc. def_id ) . skip_binder ( ) , assoc. ident )
2045+ }
2046+ ty:: AssocKind :: Type => format ! ( "type {} = Type;" , assoc. ident) ,
2047+ // FIXME(type_alias_impl_trait): we should print bounds here too.
2048+ ty:: AssocKind :: OpaqueTy => format ! ( "type {} = Type;" , assoc. ident) ,
2049+ ty:: AssocKind :: Const => {
2050+ let ty = tcx. type_of ( assoc. def_id ) ;
2051+ let val = expr:: ty_kind_suggestion ( ty) . unwrap_or ( "value" ) ;
2052+ format ! ( "const {}: {:?} = {};" , assoc. ident, ty, val)
2053+ }
19572054 }
19582055}
19592056
0 commit comments