@@ -11,16 +11,17 @@ use rustc_hir::intravisit::Visitor;
1111use rustc_hir:: itemlikevisit:: ParItemLikeVisitor ;
1212use rustc_hir:: lang_items:: LangItem ;
1313use rustc_hir:: ItemKind ;
14+ use rustc_infer:: infer:: TyCtxtInferExt ;
1415use rustc_middle:: hir:: map as hir_map;
15- use rustc_middle:: ty:: subst:: { InternalSubsts , Subst } ;
16+ use rustc_middle:: ty:: subst:: { GenericArgKind , InternalSubsts , Subst } ;
1617use rustc_middle:: ty:: trait_def:: TraitSpecializationKind ;
17- use rustc_middle:: ty:: {
18- self , AdtKind , GenericParamDefKind , ToPredicate , Ty , TyCtxt , TypeFoldable , WithConstness ,
19- } ;
18+ use rustc_middle:: ty:: { self , AdtKind , GenericParamDefKind , ToPredicate , Ty , TyCtxt , TypeFoldable , TypeVisitor , WithConstness } ;
19+ use rustc_session:: lint;
2020use rustc_session:: parse:: feature_err;
2121use rustc_span:: symbol:: { sym, Ident , Symbol } ;
22- use rustc_span:: Span ;
23- use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
22+ use rustc_span:: { DUMMY_SP , Span } ;
23+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: { InferCtxtExt as _} ;
24+ use rustc_trait_selection:: traits:: query:: outlives_bounds:: { InferCtxtExt as _} ;
2425use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCauseCode , WellFormedLoc } ;
2526
2627use std:: convert:: TryInto ;
@@ -253,6 +254,97 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
253254 . emit ( ) ;
254255 }
255256 }
257+
258+ // Require that the user writes as where clauses on GATs the implicit
259+ // outlives bounds involving trait parameters in trait functions and
260+ // lifetimes passed as GAT substs. See `self-outlives-lint` test.
261+ let item = tcx. associated_item ( trait_item. def_id ) ;
262+ let generics: & ty:: Generics = tcx. generics_of ( trait_item. def_id ) ;
263+ if matches ! ( item. kind, ty:: AssocKind :: Type ) && generics. params . len ( ) > 0 {
264+ let associated_items: & ty:: AssocItems < ' _ > = tcx. associated_items ( encl_trait_def_id) ;
265+ associated_items
266+ . in_definition_order ( )
267+ . filter ( |item| matches ! ( item. kind, ty:: AssocKind :: Fn ) )
268+ . for_each ( |item| {
269+ tcx. infer_ctxt ( ) . enter ( |infcx| {
270+ let sig: ty:: Binder < ' _ , ty:: FnSig < ' _ > > = tcx. fn_sig ( item. def_id ) ;
271+ let sig = infcx. replace_bound_vars_with_placeholders ( sig) ;
272+ let output = sig. output ( ) ;
273+ let mut visitor = RegionsInGATs {
274+ tcx,
275+ gat : trait_item. def_id . to_def_id ( ) ,
276+ regions : FxHashSet :: default ( ) ,
277+ } ;
278+ output. visit_with ( & mut visitor) ;
279+ for input in sig. inputs ( ) {
280+ let bounds = infcx. implied_outlives_bounds ( ty:: ParamEnv :: empty ( ) , hir_id, input, DUMMY_SP ) ;
281+ debug ! ( ?bounds) ;
282+ let mut clauses = FxHashSet :: default ( ) ;
283+ for bound in bounds {
284+ match bound {
285+ traits:: query:: OutlivesBound :: RegionSubParam ( r, p) => {
286+ for idx in visitor. regions . iter ( ) . filter ( |( proj_r, _) | proj_r == & r) . map ( |r| r. 1 ) {
287+ let param_r = tcx. mk_region ( ty:: RegionKind :: ReEarlyBound ( ty:: EarlyBoundRegion {
288+ def_id : generics. params [ idx] . def_id ,
289+ index : idx as u32 ,
290+ name : generics. params [ idx] . name ,
291+ } ) ) ;
292+ let clause = ty:: PredicateKind :: TypeOutlives ( ty:: OutlivesPredicate ( tcx. mk_ty ( ty:: Param ( p) ) , param_r) ) ;
293+ let clause = tcx. mk_predicate ( ty:: Binder :: dummy ( clause) ) ;
294+ clauses. insert ( clause) ;
295+ }
296+ }
297+ _ => { }
298+ }
299+ }
300+ debug ! ( ?clauses) ;
301+ if !clauses. is_empty ( ) {
302+ let written_predicates: ty:: GenericPredicates < ' _ > = tcx. predicates_of ( trait_item. def_id ) ;
303+ for clause in clauses {
304+ let found = written_predicates. predicates . iter ( ) . find ( |p| p. 0 == clause) . is_some ( ) ;
305+ debug ! ( ?clause, ?found) ;
306+ let mut error = tcx. sess . struct_span_err (
307+ trait_item. generics . span ,
308+ & format ! ( "Missing bound: {}" , clause) ,
309+ ) ;
310+ error. emit ( ) ;
311+ }
312+ }
313+ }
314+ } )
315+ } ) ;
316+ }
317+ }
318+
319+ struct RegionsInGATs < ' tcx > {
320+ tcx : TyCtxt < ' tcx > ,
321+ gat : DefId ,
322+ // Which region appears and which parameter index its subsituted for
323+ regions : FxHashSet < ( ty:: Region < ' tcx > , usize ) > ,
324+ }
325+
326+ impl < ' tcx > TypeVisitor < ' tcx > for RegionsInGATs < ' tcx > {
327+ type BreakTy = !;
328+
329+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
330+ match t. kind ( ) {
331+ ty:: Projection ( p) if p. item_def_id == self . gat => {
332+ let ( _, substs) = p. trait_ref_and_own_substs ( self . tcx ) ;
333+ self . regions . extend ( substs. iter ( ) . enumerate ( ) . filter_map ( |( idx, subst) | {
334+ match subst. unpack ( ) {
335+ GenericArgKind :: Lifetime ( lt) => Some ( ( lt, idx) ) ,
336+ _ => None ,
337+ }
338+ } ) ) ;
339+ }
340+ _ => { }
341+ }
342+ t. super_visit_with ( self )
343+ }
344+
345+ fn tcx_for_anon_const_substs ( & self ) -> Option < TyCtxt < ' tcx > > {
346+ Some ( self . tcx )
347+ }
256348}
257349
258350fn could_be_self ( trait_def_id : LocalDefId , ty : & hir:: Ty < ' _ > ) -> bool {
0 commit comments