|
8 | 8 |
|
9 | 9 | use hir::def_id::DefId; |
10 | 10 | use hir::LangItem; |
| 11 | +use rustc_data_structures::fx::FxIndexSet; |
11 | 12 | use rustc_hir as hir; |
12 | 13 | use rustc_infer::traits::ObligationCause; |
13 | 14 | use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; |
@@ -807,52 +808,61 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { |
807 | 808 | // |
808 | 809 | // We always perform upcasting coercions when we can because of reason |
809 | 810 | // #2 (region bounds). |
810 | | - let auto_traits_compatible = b_data |
811 | | - .auto_traits() |
812 | | - // All of a's auto traits need to be in b's auto traits. |
813 | | - .all(|b| a_data.auto_traits().any(|a| a == b)); |
814 | | - if auto_traits_compatible { |
815 | | - let principal_def_id_a = a_data.principal_def_id(); |
816 | | - let principal_def_id_b = b_data.principal_def_id(); |
817 | | - if principal_def_id_a == principal_def_id_b { |
818 | | - // no cyclic |
| 811 | + let principal_def_id_a = a_data.principal_def_id(); |
| 812 | + let principal_def_id_b = b_data.principal_def_id(); |
| 813 | + if principal_def_id_a == principal_def_id_b { |
| 814 | + // We may upcast to auto traits that are either explicitly listed in |
| 815 | + // the object type's bounds, or implied by the principal trait ref's |
| 816 | + // supertraits. |
| 817 | + let a_auto_traits: FxIndexSet<DefId> = a_data |
| 818 | + .auto_traits() |
| 819 | + .chain(principal_def_id_a.into_iter().flat_map(|principal_def_id| { |
| 820 | + util::supertrait_def_ids(self.tcx(), principal_def_id) |
| 821 | + .filter(|def_id| self.tcx().trait_is_auto(*def_id)) |
| 822 | + })) |
| 823 | + .collect(); |
| 824 | + let auto_traits_compatible = b_data |
| 825 | + .auto_traits() |
| 826 | + // All of a's auto traits need to be in b's auto traits. |
| 827 | + .all(|b| a_auto_traits.contains(&b)); |
| 828 | + if auto_traits_compatible { |
819 | 829 | candidates.vec.push(BuiltinUnsizeCandidate); |
820 | | - } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() { |
821 | | - // not casual unsizing, now check whether this is trait upcasting coercion. |
822 | | - let principal_a = a_data.principal().unwrap(); |
823 | | - let target_trait_did = principal_def_id_b.unwrap(); |
824 | | - let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); |
825 | | - if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( |
826 | | - source, |
827 | | - obligation.param_env, |
828 | | - &obligation.cause, |
829 | | - ) { |
830 | | - if deref_trait_ref.def_id() == target_trait_did { |
831 | | - return; |
832 | | - } |
| 830 | + } |
| 831 | + } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() { |
| 832 | + // not casual unsizing, now check whether this is trait upcasting coercion. |
| 833 | + let principal_a = a_data.principal().unwrap(); |
| 834 | + let target_trait_did = principal_def_id_b.unwrap(); |
| 835 | + let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); |
| 836 | + if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( |
| 837 | + source, |
| 838 | + obligation.param_env, |
| 839 | + &obligation.cause, |
| 840 | + ) { |
| 841 | + if deref_trait_ref.def_id() == target_trait_did { |
| 842 | + return; |
833 | 843 | } |
| 844 | + } |
834 | 845 |
|
835 | | - for (idx, upcast_trait_ref) in |
836 | | - util::supertraits(self.tcx(), source_trait_ref).enumerate() |
837 | | - { |
838 | | - self.infcx.probe(|_| { |
839 | | - if upcast_trait_ref.def_id() == target_trait_did |
840 | | - && let Ok(nested) = self.match_upcast_principal( |
841 | | - obligation, |
842 | | - upcast_trait_ref, |
843 | | - a_data, |
844 | | - b_data, |
845 | | - a_region, |
846 | | - b_region, |
847 | | - ) |
848 | | - { |
849 | | - if nested.is_none() { |
850 | | - candidates.ambiguous = true; |
851 | | - } |
852 | | - candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); |
| 846 | + for (idx, upcast_trait_ref) in |
| 847 | + util::supertraits(self.tcx(), source_trait_ref).enumerate() |
| 848 | + { |
| 849 | + self.infcx.probe(|_| { |
| 850 | + if upcast_trait_ref.def_id() == target_trait_did |
| 851 | + && let Ok(nested) = self.match_upcast_principal( |
| 852 | + obligation, |
| 853 | + upcast_trait_ref, |
| 854 | + a_data, |
| 855 | + b_data, |
| 856 | + a_region, |
| 857 | + b_region, |
| 858 | + ) |
| 859 | + { |
| 860 | + if nested.is_none() { |
| 861 | + candidates.ambiguous = true; |
853 | 862 | } |
854 | | - }) |
855 | | - } |
| 863 | + candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); |
| 864 | + } |
| 865 | + }) |
856 | 866 | } |
857 | 867 | } |
858 | 868 | } |
|
0 commit comments