1111use crate :: rustc:: hir;
1212use crate :: rustc:: hir:: def:: Def ;
1313use crate :: rustc:: lint:: { in_external_macro, LateContext , LateLintPass , Lint , LintArray , LintContext , LintPass } ;
14- use crate :: rustc:: ty:: { self , Ty } ;
14+ use crate :: rustc:: ty:: { self , Ty , TyKind , Predicate } ;
1515use crate :: rustc:: { declare_tool_lint, lint_array} ;
1616use crate :: rustc_errors:: Applicability ;
1717use crate :: syntax:: ast;
@@ -878,6 +878,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
878878 let name = implitem. ident . name ;
879879 let parent = cx. tcx . hir . get_parent ( implitem. id ) ;
880880 let item = cx. tcx . hir . expect_item ( parent) ;
881+ let def_id = cx. tcx . hir . local_def_id ( item. id ) ;
882+ let ty = cx. tcx . type_of ( def_id) ;
881883 if_chain ! {
882884 if let hir:: ImplItemKind :: Method ( ref sig, id) = implitem. node;
883885 if let Some ( first_arg_ty) = sig. decl. inputs. get( 0 ) ;
@@ -899,8 +901,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
899901 }
900902
901903 // check conventions w.r.t. conversion method names and predicates
902- let def_id = cx. tcx. hir. local_def_id( item. id) ;
903- let ty = cx. tcx. type_of( def_id) ;
904904 let is_copy = is_copy( cx, ty) ;
905905 for & ( ref conv, self_kinds) in & CONVENTIONS {
906906 if conv. check( & name. as_str( ) ) {
@@ -928,16 +928,37 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
928928 break ;
929929 }
930930 }
931+ }
932+ }
933+
934+ if let hir:: ImplItemKind :: Method ( _, _) = implitem. node {
935+ let ret_ty = return_ty ( cx, implitem. id ) ;
936+
937+ // if return type is impl trait
938+ if let TyKind :: Opaque ( def_id, _) = ret_ty. sty {
939+
940+ // then one of the associated types must be Self
941+ for predicate in cx. tcx . predicates_of ( def_id) . predicates . iter ( ) {
942+ match predicate {
943+ ( Predicate :: Projection ( poly_projection_predicate) , _) => {
944+ let binder = poly_projection_predicate. ty ( ) ;
945+ let associated_type = binder. skip_binder ( ) ;
946+ let associated_type_is_self_type = same_tys ( cx, ty, associated_type) ;
931947
932- let ret_ty = return_ty( cx, implitem. id) ;
933- if name == "new" &&
934- !ret_ty. walk( ) . any( |t| same_tys( cx, t, ty) ) {
935- span_lint( cx,
936- NEW_RET_NO_SELF ,
937- implitem. span,
938- "methods called `new` usually return `Self`" ) ;
948+ // if the associated type is self, early return and do not trigger lint
949+ if associated_type_is_self_type { return ; }
950+ } ,
951+ ( _, _) => { } ,
952+ }
939953 }
940954 }
955+
956+ if name == "new" && !same_tys ( cx, ret_ty, ty) {
957+ span_lint ( cx,
958+ NEW_RET_NO_SELF ,
959+ implitem. span ,
960+ "methods called `new` usually return `Self`" ) ;
961+ }
941962 }
942963 }
943964}
0 commit comments