11use crate :: check:: { FnCtxt , Inherited } ;
22use crate :: constrained_generic_params:: { identify_constrained_generic_params, Parameter } ;
33
4+ use crate :: traits:: query:: type_op:: { self , TypeOp , TypeOpOutput } ;
45use rustc_ast as ast;
56use rustc_data_structures:: fx:: FxHashSet ;
67use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
@@ -15,13 +16,14 @@ use rustc_infer::infer::TyCtxtInferExt;
1516use rustc_middle:: hir:: map as hir_map;
1617use rustc_middle:: ty:: subst:: { GenericArgKind , InternalSubsts , Subst } ;
1718use 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+ } ;
2023use rustc_session:: parse:: feature_err;
2124use 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 _;
2527use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCauseCode , WellFormedLoc } ;
2628
2729use std:: convert:: TryInto ;
@@ -255,75 +257,119 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
255257 }
256258 }
257259
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+ ) {
261271 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+ }
262276 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) ,
309334 ) ;
310- error. emit ( ) ;
335+ let clause = tcx. mk_predicate ( ty:: Binder :: dummy ( clause) ) ;
336+ clauses. insert ( clause) ;
311337 }
312338 }
339+ _ => { }
313340 }
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+ } )
316360 }
317361}
318362
319- struct RegionsInGATs < ' tcx > {
363+ struct GATSubstCollector < ' tcx > {
320364 tcx : TyCtxt < ' tcx > ,
321365 gat : DefId ,
322366 // Which region appears and which parameter index its subsituted for
323367 regions : FxHashSet < ( ty:: Region < ' tcx > , usize ) > ,
368+ // Which params appears and which parameter index its subsituted for
369+ _types : FxHashSet < ( Ty < ' tcx > , usize ) > ,
324370}
325371
326- impl < ' tcx > TypeVisitor < ' tcx > for RegionsInGATs < ' tcx > {
372+ impl < ' tcx > TypeVisitor < ' tcx > for GATSubstCollector < ' tcx > {
327373 type BreakTy = !;
328374
329375 fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
0 commit comments