1
1
use crate :: check:: { FnCtxt , Inherited } ;
2
2
use crate :: constrained_generic_params:: { identify_constrained_generic_params, Parameter } ;
3
3
4
+ use crate :: traits:: query:: type_op:: { self , TypeOp , TypeOpOutput } ;
4
5
use rustc_ast as ast;
5
6
use rustc_data_structures:: fx:: FxHashSet ;
6
7
use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
@@ -15,13 +16,14 @@ use rustc_infer::infer::TyCtxtInferExt;
15
16
use rustc_middle:: hir:: map as hir_map;
16
17
use rustc_middle:: ty:: subst:: { GenericArgKind , InternalSubsts , Subst } ;
17
18
use rustc_middle:: ty:: trait_def:: TraitSpecializationKind ;
18
- use rustc_middle:: ty:: { self , AdtKind , GenericParamDefKind , ToPredicate , Ty , TyCtxt , TypeFoldable , TypeVisitor , WithConstness } ;
19
- use rustc_session:: lint;
19
+ use rustc_middle:: ty:: {
20
+ self , AdtKind , GenericParamDefKind , ToPredicate , Ty , TyCtxt , TypeFoldable , TypeVisitor ,
21
+ WithConstness ,
22
+ } ;
20
23
use rustc_session:: parse:: feature_err;
21
24
use rustc_span:: symbol:: { sym, Ident , Symbol } ;
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 _} ;
25
+ use rustc_span:: Span ;
26
+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
25
27
use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCauseCode , WellFormedLoc } ;
26
28
27
29
use std:: convert:: TryInto ;
@@ -255,75 +257,119 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
255
257
}
256
258
}
257
259
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.
260
+ check_gat_where_clauses ( tcx, trait_item, encl_trait_def_id) ;
261
+ }
262
+
263
+ /// Require that the user writes as where clauses on GATs the implicit
264
+ /// outlives bounds involving trait parameters in trait functions and
265
+ /// lifetimes passed as GAT substs. See `self-outlives-lint` test.
266
+ fn check_gat_where_clauses (
267
+ tcx : TyCtxt < ' _ > ,
268
+ trait_item : & hir:: TraitItem < ' _ > ,
269
+ encl_trait_def_id : DefId ,
270
+ ) {
261
271
let item = tcx. associated_item ( trait_item. def_id ) ;
272
+ // If the current trait item isn't a type, it isn't a GAT
273
+ if !matches ! ( item. kind, ty:: AssocKind :: Type ) {
274
+ return ;
275
+ }
262
276
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) ,
277
+ // If the current associated type doesn't have any (own) params, it's not a GAT
278
+ if generics. params . len ( ) == 0 {
279
+ return ;
280
+ }
281
+ let associated_items: & ty:: AssocItems < ' _ > = tcx. associated_items ( encl_trait_def_id) ;
282
+ // For every function in this trait...
283
+ for item in
284
+ associated_items. in_definition_order ( ) . filter ( |item| matches ! ( item. kind, ty:: AssocKind :: Fn ) )
285
+ {
286
+ tcx. infer_ctxt ( ) . enter ( |infcx| {
287
+ let sig: ty:: Binder < ' _ , ty:: FnSig < ' _ > > = tcx. fn_sig ( item. def_id ) ;
288
+ let sig = infcx. replace_bound_vars_with_placeholders ( sig) ;
289
+ // Find out what regions are passed as GAT substs
290
+ let mut visitor = GATSubstCollector {
291
+ tcx,
292
+ gat : trait_item. def_id . to_def_id ( ) ,
293
+ regions : FxHashSet :: default ( ) ,
294
+ _types : FxHashSet :: default ( ) ,
295
+ } ;
296
+ sig. output ( ) . visit_with ( & mut visitor) ;
297
+ // If there are none, then it nothing to do
298
+ if visitor. regions . is_empty ( ) {
299
+ return ;
300
+ }
301
+ let mut clauses = FxHashSet :: default ( ) ;
302
+ // Otherwise, find the clauses required from implied bounds
303
+ for input in sig. inputs ( ) {
304
+ // For a given input type, find the implied bounds
305
+ let TypeOpOutput { output : bounds, .. } = match ty:: ParamEnv :: empty ( )
306
+ . and ( type_op:: implied_outlives_bounds:: ImpliedOutlivesBounds { ty : input } )
307
+ . fully_perform ( & infcx)
308
+ {
309
+ Ok ( o) => o,
310
+ Err ( _) => continue ,
311
+ } ;
312
+ debug ! ( ?bounds) ;
313
+ for bound in bounds {
314
+ match bound {
315
+ traits:: query:: OutlivesBound :: RegionSubParam ( r, p) => {
316
+ // If the implied bound is a `RegionSubParam` and
317
+ // the region is used a GAT subst...
318
+ for idx in visitor
319
+ . regions
320
+ . iter ( )
321
+ . filter ( |( proj_r, _) | proj_r == & r)
322
+ . map ( |r| r. 1 )
323
+ {
324
+ // Then create a clause that is required on the GAT
325
+ let param_r = tcx. mk_region ( ty:: RegionKind :: ReEarlyBound (
326
+ ty:: EarlyBoundRegion {
327
+ def_id : generics. params [ idx] . def_id ,
328
+ index : idx as u32 ,
329
+ name : generics. params [ idx] . name ,
330
+ } ,
331
+ ) ) ;
332
+ let clause = ty:: PredicateKind :: TypeOutlives (
333
+ ty:: OutlivesPredicate ( tcx. mk_ty ( ty:: Param ( p) ) , param_r) ,
309
334
) ;
310
- error. emit ( ) ;
335
+ let clause = tcx. mk_predicate ( ty:: Binder :: dummy ( clause) ) ;
336
+ clauses. insert ( clause) ;
311
337
}
312
338
}
339
+ _ => { }
313
340
}
314
- } )
315
- } ) ;
341
+ }
342
+ }
343
+ // If there are any missing clauses, emit an error
344
+ debug ! ( ?clauses) ;
345
+ if !clauses. is_empty ( ) {
346
+ let written_predicates: ty:: GenericPredicates < ' _ > =
347
+ tcx. predicates_of ( trait_item. def_id ) ;
348
+ for clause in clauses {
349
+ let found =
350
+ written_predicates. predicates . iter ( ) . find ( |p| p. 0 == clause) . is_some ( ) ;
351
+ debug ! ( ?clause, ?found) ;
352
+ let mut error = tcx. sess . struct_span_err (
353
+ trait_item. generics . span ,
354
+ & format ! ( "Missing bound: {}" , clause) ,
355
+ ) ;
356
+ error. emit ( ) ;
357
+ }
358
+ }
359
+ } )
316
360
}
317
361
}
318
362
319
- struct RegionsInGATs < ' tcx > {
363
+ struct GATSubstCollector < ' tcx > {
320
364
tcx : TyCtxt < ' tcx > ,
321
365
gat : DefId ,
322
366
// Which region appears and which parameter index its subsituted for
323
367
regions : FxHashSet < ( ty:: Region < ' tcx > , usize ) > ,
368
+ // Which params appears and which parameter index its subsituted for
369
+ _types : FxHashSet < ( Ty < ' tcx > , usize ) > ,
324
370
}
325
371
326
- impl < ' tcx > TypeVisitor < ' tcx > for RegionsInGATs < ' tcx > {
372
+ impl < ' tcx > TypeVisitor < ' tcx > for GATSubstCollector < ' tcx > {
327
373
type BreakTy = !;
328
374
329
375
fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
0 commit comments