@@ -11,16 +11,17 @@ use rustc_hir::intravisit::Visitor;
11
11
use rustc_hir:: itemlikevisit:: ParItemLikeVisitor ;
12
12
use rustc_hir:: lang_items:: LangItem ;
13
13
use rustc_hir:: ItemKind ;
14
+ use rustc_infer:: infer:: TyCtxtInferExt ;
14
15
use rustc_middle:: hir:: map as hir_map;
15
- use rustc_middle:: ty:: subst:: { InternalSubsts , Subst } ;
16
+ use rustc_middle:: ty:: subst:: { GenericArgKind , InternalSubsts , Subst } ;
16
17
use 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;
20
20
use rustc_session:: parse:: feature_err;
21
21
use 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 _} ;
24
25
use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCauseCode , WellFormedLoc } ;
25
26
26
27
use std:: convert:: TryInto ;
@@ -253,6 +254,97 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
253
254
. emit ( ) ;
254
255
}
255
256
}
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
+ }
256
348
}
257
349
258
350
fn could_be_self ( trait_def_id : LocalDefId , ty : & hir:: Ty < ' _ > ) -> bool {
0 commit comments