@@ -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`
@@ -1934,26 +1934,115 @@ fn check_impl_items_against_trait<'tcx>(
1934
1934
missing_items. iter( )
1935
1935
. map( |trait_item| trait_item. ident. to_string( ) )
1936
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 ( ) ;
1937
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 ;
1938
1948
if let Some ( span) = tcx. hir ( ) . span_if_local ( trait_item. def_id ) {
1939
1949
err. span_label ( span, format ! ( "`{}` from trait" , trait_item. ident) ) ;
1950
+ err. tool_only_span_suggestion ( sugg_sp, & msg, code, appl) ;
1940
1951
} 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) ;
1943
1953
}
1944
1954
}
1945
1955
err. emit ( ) ;
1946
1956
}
1947
1957
1948
1958
if !invalidated_items. is_empty ( ) {
1949
1959
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
+ }
1957
2046
}
1958
2047
}
1959
2048
0 commit comments