@@ -3,7 +3,7 @@ use crate::check::{FnCtxt, Inherited};
33use crate :: constrained_generic_params:: { identify_constrained_generic_params, Parameter } ;
44
55use rustc_ast as ast;
6- use rustc_data_structures:: fx:: FxHashSet ;
6+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
77use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
88use rustc_hir as hir;
99use rustc_hir:: def_id:: { DefId , LocalDefId } ;
@@ -258,145 +258,131 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
258258 . emit ( ) ;
259259 }
260260 }
261-
262- check_gat_where_clauses ( tcx, trait_item, encl_trait_def_id) ;
263261}
264262
265263/// Require that the user writes where clauses on GATs for the implicit
266264/// outlives bounds involving trait parameters in trait functions and
267265/// lifetimes passed as GAT substs. See `self-outlives-lint` test.
268- ///
269- /// This trait will be our running example. We are currently WF checking the `Item` item...
270- ///
271- /// ```rust
272- /// trait LendingIterator {
273- /// type Item<'me>; // <-- WF checking this trait item
274- ///
275- /// fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
276- /// }
277266/// ```
278- fn check_gat_where_clauses ( tcx : TyCtxt < ' _ > , gat_hir : & hir:: TraitItem < ' _ > , gat_def_id : DefId ) {
279- let gat_item = tcx. associated_item ( gat_def_id) ;
280- let gat_def_id = gat_hir. def_id ;
281- // If the current trait item isn't a type, it isn't a GAT
282- if !matches ! ( gat_item. kind, ty:: AssocKind :: Type ) {
283- return ;
284- }
285- let gat_generics: & ty:: Generics = tcx. generics_of ( gat_def_id) ;
286- // If the current associated type doesn't have any (own) params, it's not a GAT
287- // FIXME(jackh726): we can also warn in the more general case
288- if gat_generics. params . len ( ) == 0 {
289- return ;
290- }
291- let associated_items: & ty:: AssocItems < ' _ > = tcx. associated_items ( gat_def_id) ;
292- let mut clauses: Option < FxHashSet < ty:: Predicate < ' _ > > > = None ;
293- // For every function in this trait...
294- // In our example, this would be the `next` method
295- for item in
296- associated_items. in_definition_order ( ) . filter ( |item| matches ! ( item. kind, ty:: AssocKind :: Fn ) )
297- {
298- let item_hir_id = hir:: HirId :: make_owner ( item. def_id . expect_local ( ) ) ;
299- let param_env = tcx. param_env ( item. def_id . expect_local ( ) ) ;
267+ fn check_gat_where_clauses ( tcx : TyCtxt < ' _ > , associated_items : & [ hir:: TraitItemRef ] ) {
268+ let mut required_bounds_by_item = FxHashMap :: default ( ) ;
269+
270+ for gat_item in associated_items {
271+ let gat_def_id = gat_item. id . def_id ;
272+ let gat_item = tcx. associated_item ( gat_def_id) ;
273+ // If this item is not an assoc ty, or has no substs, then it's not a GAT
274+ if gat_item. kind != ty:: AssocKind :: Type {
275+ continue ;
276+ }
277+ let gat_generics = tcx. generics_of ( gat_def_id) ;
278+ if gat_generics. params . is_empty ( ) {
279+ continue ;
280+ }
300281
301- // Get the signature using placeholders. In our example, this would
302- // convert the late-bound 'a into a free region.
303- let sig = tcx. liberate_late_bound_regions ( item. def_id , tcx. fn_sig ( item. def_id ) ) ;
282+ let mut new_required_bounds: Option < FxHashSet < ty:: Predicate < ' _ > > > = None ;
283+ for item in associated_items {
284+ if !matches ! ( & item. kind, hir:: AssocItemKind :: Fn { .. } ) {
285+ // FIXME: next commit will add items...
286+ continue ;
287+ }
304288
305- // The types we can assume to be well-formed. In our example, this
306- // would be &'a mut Self, from the first argument.
307- let mut wf_tys = FxHashSet :: default ( ) ;
308- wf_tys. extend ( sig. inputs ( ) ) ;
289+ let item_def_id = item. id . def_id ;
290+ // Skip our own GAT, since it would blow away the required bounds
291+ if item_def_id == gat_def_id {
292+ continue ;
293+ }
309294
310- // The clauses we that we would require from this function
311- let function_clauses = gather_gat_bounds (
312- tcx,
313- param_env,
314- item_hir_id,
315- sig. output ( ) ,
316- & wf_tys,
317- gat_def_id,
318- gat_generics,
319- ) ;
295+ let item_hir_id = item. id . hir_id ( ) ;
296+ let param_env = tcx. param_env ( item_def_id) ;
320297
321- if let Some ( function_clauses) = function_clauses {
322- // Imagine we have:
323- // ```
324- // trait Foo {
325- // type Bar<'me>;
326- // fn gimme(&self) -> Self::Bar<'_>;
327- // fn gimme_default(&self) -> Self::Bar<'static>;
328- // }
329- // ```
330- // We only want to require clauses on `Bar` that we can prove from *all* functions (in this
331- // case, `'me` can be `static` from `gimme_default`)
332- match clauses. as_mut ( ) {
333- Some ( clauses) => {
334- clauses. drain_filter ( |p| !function_clauses. contains ( p) ) ;
335- }
336- None => {
337- clauses = Some ( function_clauses) ;
298+ // Get the signature using placeholders. In our example, this would
299+ // convert the late-bound 'a into a free region.
300+ let sig = tcx. liberate_late_bound_regions (
301+ item_def_id. to_def_id ( ) ,
302+ tcx. fn_sig ( item_def_id. to_def_id ( ) ) ,
303+ ) ;
304+
305+ // The types we can assume to be well-formed. In our example, this
306+ // would be &'a mut Self, from the first argument.
307+ let mut wf_tys = FxHashSet :: default ( ) ;
308+ wf_tys. extend ( sig. inputs ( ) ) ;
309+
310+ // The clauses we that we would require from this function
311+ let item_required_bounds = gather_gat_bounds (
312+ tcx,
313+ param_env,
314+ item_hir_id,
315+ sig. output ( ) ,
316+ & wf_tys,
317+ gat_def_id,
318+ gat_generics,
319+ ) ;
320+
321+ if let Some ( item_required_bounds) = item_required_bounds {
322+ // Take the intersection of the new_required_bounds and the item_required_bounds
323+ // for this item. This is why we use an Option<_>, since we need to distinguish
324+ // the empty set of bounds from the uninitialized set of bounds.
325+ if let Some ( new_required_bounds) = & mut new_required_bounds {
326+ new_required_bounds. retain ( |b| item_required_bounds. contains ( b) ) ;
327+ } else {
328+ new_required_bounds = Some ( item_required_bounds) ;
338329 }
339330 }
340331 }
332+
333+ if let Some ( required_bounds) = new_required_bounds {
334+ required_bounds_by_item. insert ( gat_def_id, required_bounds) ;
335+ }
341336 }
342337
343- // If there are any clauses that aren't provable, emit an error
344- let clauses = clauses. unwrap_or_default ( ) ;
345- debug ! ( ?clauses) ;
346- if !clauses. is_empty ( ) {
338+ for ( gat_def_id, required_bounds) in required_bounds_by_item {
339+ let gat_item_hir = tcx. hir ( ) . expect_trait_item ( gat_def_id) ;
340+ debug ! ( ?required_bounds) ;
347341 let param_env = tcx. param_env ( gat_def_id) ;
342+ let gat_hir = gat_item_hir. hir_id ( ) ;
348343
349- let mut clauses : Vec < _ > = clauses
344+ let mut unsatisfied_bounds : Vec < _ > = required_bounds
350345 . into_iter ( )
351346 . filter ( |clause| match clause. kind ( ) . skip_binder ( ) {
352347 ty:: PredicateKind :: RegionOutlives ( ty:: OutlivesPredicate ( a, b) ) => {
353- !region_known_to_outlive (
354- tcx,
355- gat_hir. hir_id ( ) ,
356- param_env,
357- & FxHashSet :: default ( ) ,
358- a,
359- b,
360- )
348+ !region_known_to_outlive ( tcx, gat_hir, param_env, & FxHashSet :: default ( ) , a, b)
361349 }
362350 ty:: PredicateKind :: TypeOutlives ( ty:: OutlivesPredicate ( a, b) ) => {
363- !ty_known_to_outlive (
364- tcx,
365- gat_hir. hir_id ( ) ,
366- param_env,
367- & FxHashSet :: default ( ) ,
368- a,
369- b,
370- )
351+ !ty_known_to_outlive ( tcx, gat_hir, param_env, & FxHashSet :: default ( ) , a, b)
371352 }
372353 _ => bug ! ( "Unexpected PredicateKind" ) ,
373354 } )
374- . map ( |clause| format ! ( "{}" , clause) )
355+ . map ( |clause| clause. to_string ( ) )
375356 . collect ( ) ;
376357
377358 // We sort so that order is predictable
378- clauses . sort ( ) ;
359+ unsatisfied_bounds . sort ( ) ;
379360
380- if !clauses . is_empty ( ) {
381- let plural = if clauses . len ( ) > 1 { "s" } else { "" } ;
361+ if !unsatisfied_bounds . is_empty ( ) {
362+ let plural = if unsatisfied_bounds . len ( ) > 1 { "s" } else { "" } ;
382363 let mut err = tcx. sess . struct_span_err (
383- gat_hir . span ,
384- & format ! ( "missing required bound{} on `{}`" , plural, gat_hir . ident) ,
364+ gat_item_hir . span ,
365+ & format ! ( "missing required bound{} on `{}`" , plural, gat_item_hir . ident) ,
385366 ) ;
386367
387368 let suggestion = format ! (
388369 "{} {}" ,
389- if !gat_hir. generics. where_clause. predicates. is_empty( ) { "," } else { " where" } ,
390- clauses. join( ", " ) ,
370+ if !gat_item_hir. generics. where_clause. predicates. is_empty( ) {
371+ ","
372+ } else {
373+ " where"
374+ } ,
375+ unsatisfied_bounds. join( ", " ) ,
391376 ) ;
392377 err. span_suggestion (
393- gat_hir . generics . where_clause . tail_span_for_suggestion ( ) ,
378+ gat_item_hir . generics . where_clause . tail_span_for_suggestion ( ) ,
394379 & format ! ( "add the required where clause{}" , plural) ,
395380 suggestion,
396381 Applicability :: MachineApplicable ,
397382 ) ;
398383
399- let bound = if clauses. len ( ) > 1 { "these bounds are" } else { "this bound is" } ;
384+ let bound =
385+ if unsatisfied_bounds. len ( ) > 1 { "these bounds are" } else { "this bound is" } ;
400386 err. note ( & format ! (
401387 "{} currently required to ensure that impls have maximum flexibility" ,
402388 bound
@@ -1025,6 +1011,11 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
10251011
10261012 FxHashSet :: default ( )
10271013 } ) ;
1014+
1015+ // Only check traits, don't check trait aliases
1016+ if let hir:: ItemKind :: Trait ( _, _, _, _, items) = item. kind {
1017+ check_gat_where_clauses ( tcx, items) ;
1018+ }
10281019}
10291020
10301021/// Checks all associated type defaults of trait `trait_def_id`.
0 commit comments