@@ -127,7 +127,7 @@ use syntax::ast;
127
127
use syntax:: attr;
128
128
use syntax:: feature_gate:: { GateIssue , emit_feature_err} ;
129
129
use syntax:: source_map:: { DUMMY_SP , original_sp} ;
130
- use syntax:: symbol:: { kw, sym} ;
130
+ use syntax:: symbol:: { kw, sym, Ident } ;
131
131
use syntax:: util:: parser:: ExprPrecedence ;
132
132
133
133
use std:: cell:: { Cell , RefCell , Ref , RefMut } ;
@@ -1800,12 +1800,12 @@ fn check_specialization_validity<'tcx>(
1800
1800
1801
1801
fn check_impl_items_against_trait < ' tcx > (
1802
1802
tcx : TyCtxt < ' tcx > ,
1803
- impl_span : Span ,
1803
+ full_impl_span : Span ,
1804
1804
impl_id : DefId ,
1805
1805
impl_trait_ref : ty:: TraitRef < ' tcx > ,
1806
1806
impl_item_refs : & [ hir:: ImplItemRef ] ,
1807
1807
) {
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 ) ;
1809
1809
1810
1810
// If the trait reference itself is erroneous (so the compilation is going
1811
1811
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
@@ -1925,35 +1925,132 @@ fn check_impl_items_against_trait<'tcx>(
1925
1925
}
1926
1926
1927
1927
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) ;
1946
1929
}
1947
1930
1948
1931
if !invalidated_items. is_empty ( ) {
1949
1932
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
+ }
1957
2054
}
1958
2055
}
1959
2056
0 commit comments