11use rustc_data_structures:: svh:: Svh ;
22use rustc_hir as hir;
3+ use rustc_hir:: def:: DefKind ;
34use rustc_hir:: def_id:: { CrateNum , DefId , LocalDefId , LOCAL_CRATE } ;
5+ use rustc_infer:: traits:: util;
46use rustc_middle:: hir:: map as hir_map;
5- use rustc_middle:: ty:: subst:: Subst ;
7+ use rustc_middle:: ty:: subst:: { InternalSubsts , Subst } ;
68use rustc_middle:: ty:: { self , ToPredicate , Ty , TyCtxt , WithConstness } ;
79use rustc_session:: CrateDisambiguator ;
810use rustc_span:: symbol:: Symbol ;
@@ -365,6 +367,106 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
365367 fn_like. asyncness ( )
366368}
367369
370+ /// For associated types we allow bounds written on the associated type
371+ /// (`type X: Trait`) to be used as candidates. We also allow the same bounds
372+ /// when desugared as bounds on the trait `where Self::X: Trait`.
373+ ///
374+ /// Note that this filtering is done with the trait's identity substs to
375+ /// simplify checking that these bounds are met in impls. This means that
376+ /// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
377+ /// `hr-associated-type-bound-1.rs`.
378+ fn associated_type_projection_predicates (
379+ tcx : TyCtxt < ' _ > ,
380+ def_id : DefId ,
381+ ) -> & ' _ ty:: List < ty:: Predicate < ' _ > > {
382+ let trait_id = tcx. associated_item ( def_id) . container . id ( ) ;
383+ let trait_substs = InternalSubsts :: identity_for_item ( tcx, trait_id) ;
384+
385+ let generic_trait_bounds = tcx. predicates_of ( trait_id) ;
386+ let trait_bounds = generic_trait_bounds. instantiate_identity ( tcx) ;
387+ let trait_predicates = util:: elaborate_predicates ( tcx, trait_bounds. predicates . into_iter ( ) ) ;
388+
389+ let predicates = trait_predicates. filter_map ( |obligation| {
390+ let pred = obligation. predicate ;
391+ match pred. kind ( ) {
392+ ty:: PredicateKind :: Trait ( tr, _) => {
393+ if let ty:: Projection ( p) = tr. skip_binder ( ) . self_ty ( ) . kind {
394+ if p. item_def_id == def_id && p. substs . starts_with ( trait_substs) {
395+ return Some ( pred) ;
396+ }
397+ }
398+ }
399+ ty:: PredicateKind :: Projection ( proj) => {
400+ if let ty:: Projection ( p) = proj. skip_binder ( ) . projection_ty . self_ty ( ) . kind {
401+ if p. item_def_id == def_id && p. substs . starts_with ( trait_substs) {
402+ return Some ( pred) ;
403+ }
404+ }
405+ }
406+ _ => { }
407+ }
408+ None
409+ } ) ;
410+
411+ let result = tcx. mk_predicates ( predicates) ;
412+ debug ! ( "associated_type_projection_predicates({}) = {:?}" , tcx. def_path_str( def_id) , result) ;
413+ result
414+ }
415+
416+ /// Opaque types don't have the same issues as associated types: the only
417+ /// predicates on an opaque type (excluding those it inherits from its parent
418+ /// item) should be of the form we're expecting.
419+ fn opaque_type_projection_predicates (
420+ tcx : TyCtxt < ' _ > ,
421+ def_id : DefId ,
422+ ) -> & ' _ ty:: List < ty:: Predicate < ' _ > > {
423+ let substs = InternalSubsts :: identity_for_item ( tcx, def_id) ;
424+
425+ let generics_bounds = tcx. predicates_of ( def_id) ;
426+ let bounds = generics_bounds. instantiate_identity ( tcx) ;
427+ let predicates = util:: elaborate_predicates ( tcx, bounds. predicates . into_iter ( ) ) ;
428+
429+ let filtered_predicates = predicates. filter_map ( |obligation| {
430+ let pred = obligation. predicate ;
431+ match pred. kind ( ) {
432+ ty:: PredicateKind :: Trait ( tr, _) => {
433+ if let ty:: Opaque ( opaque_def_id, opaque_substs) = tr. skip_binder ( ) . self_ty ( ) . kind {
434+ if opaque_def_id == def_id && opaque_substs == substs {
435+ return Some ( pred) ;
436+ }
437+ }
438+ }
439+ ty:: PredicateKind :: Projection ( proj) => {
440+ if let ty:: Opaque ( opaque_def_id, opaque_substs) =
441+ proj. skip_binder ( ) . projection_ty . self_ty ( ) . kind
442+ {
443+ if opaque_def_id == def_id && opaque_substs == substs {
444+ return Some ( pred) ;
445+ }
446+ }
447+ }
448+ _ => { }
449+ }
450+ tcx. sess . delay_span_bug (
451+ obligation. cause . span ( tcx) ,
452+ & format ! ( "unexpected predicate {:?} on opaque type" , pred) ,
453+ ) ;
454+ None
455+ } ) ;
456+
457+ let result = tcx. mk_predicates ( filtered_predicates) ;
458+ debug ! ( "opaque_type_projection_predicates({}) = {:?}" , tcx. def_path_str( def_id) , result) ;
459+ result
460+ }
461+
462+ fn projection_predicates ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> & ' _ ty:: List < ty:: Predicate < ' _ > > {
463+ match tcx. def_kind ( def_id) {
464+ DefKind :: AssocTy => associated_type_projection_predicates ( tcx, def_id) ,
465+ DefKind :: OpaqueTy => opaque_type_projection_predicates ( tcx, def_id) ,
466+ k => bug ! ( "projection_predicates called on {}" , k. descr( def_id) ) ,
467+ }
468+ }
469+
368470pub fn provide ( providers : & mut ty:: query:: Providers < ' _ > ) {
369471 * providers = ty:: query:: Providers {
370472 asyncness,
@@ -381,6 +483,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
381483 instance_def_size_estimate,
382484 issue33140_self_ty,
383485 impl_defaultness,
486+ projection_predicates,
384487 ..* providers
385488 } ;
386489}
0 commit comments