@@ -49,36 +49,36 @@ where
4949}
5050
5151#[ derive( PartialEq , Eq , Debug , Clone , Copy ) ]
52- pub enum SimplifyParams {
53- Yes ,
54- No ,
52+ pub enum TreatParams {
53+ /// Treat parametes as bound types in the given environment.
54+ ///
55+ /// For this to be correct the input has to be fully normalized
56+ /// in its param env as it may otherwise cause us to ignore
57+ /// potentially applying impls.
58+ AsBoundTypes ,
59+ AsPlaceholders ,
5560}
5661
5762/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
5863///
5964/// The idea is to get something simple that we can use to quickly decide if two types could unify,
6065/// for example during method lookup.
6166///
62- /// A special case here are parameters and projections. Projections can be normalized to
63- /// a different type, meaning that `<T as Trait>::Assoc` and `u8` can be unified, even though
64- /// their outermost layer is different while parameters like `T` of impls are later replaced
65- /// with an inference variable, which then also allows unification with other types.
67+ /// A special case here are parameters and projections, which are only injective
68+ /// if they are treated as bound types.
6669///
67- /// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections²,
68- /// the reasoning for this can be seen at the places doing this.
70+ /// For example when storing impls based on their simplified self type, we treat
71+ /// generic parameters as placeholders. We must not simplify them here,
72+ /// as they can unify with any other type.
6973///
74+ /// With projections we have to be even more careful, as even when treating them as bound types
75+ /// this is still only correct if they are fully normalized.
7076///
71- /// ¹ meaning that if two outermost layers are different, then the whole types are also different.
72- /// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during
73- /// candidate selection. We do not consider non blanket impls for `<_ as Trait>::Assoc` even
74- /// though `_` can be inferred to a concrete type later at which point a concrete impl
75- /// could actually apply. After experimenting for about an hour I wasn't able to cause any issues
76- /// this way so I am not going to change this until we actually find an issue as I am really
77- /// interesting in getting an actual test for this.
78- pub fn simplify_type (
79- tcx : TyCtxt < ' _ > ,
80- ty : Ty < ' _ > ,
81- can_simplify_params : SimplifyParams ,
77+ /// ¹ meaning that if the outermost layers are different, then the whole types are also different.
78+ pub fn simplify_type < ' tcx > (
79+ tcx : TyCtxt < ' tcx > ,
80+ ty : Ty < ' tcx > ,
81+ treat_params : TreatParams ,
8282) -> Option < SimplifiedType > {
8383 match * ty. kind ( ) {
8484 ty:: Bool => Some ( BoolSimplifiedType ) ,
@@ -91,7 +91,7 @@ pub fn simplify_type(
9191 ty:: Array ( ..) => Some ( ArraySimplifiedType ) ,
9292 ty:: Slice ( ..) => Some ( SliceSimplifiedType ) ,
9393 ty:: RawPtr ( ptr) => Some ( PtrSimplifiedType ( ptr. mutbl ) ) ,
94- ty:: Dynamic ( ref trait_info, ..) => match trait_info. principal_def_id ( ) {
94+ ty:: Dynamic ( trait_info, ..) => match trait_info. principal_def_id ( ) {
9595 Some ( principal_def_id) if !tcx. trait_is_auto ( principal_def_id) => {
9696 Some ( TraitSimplifiedType ( principal_def_id) )
9797 }
@@ -100,24 +100,21 @@ pub fn simplify_type(
100100 ty:: Ref ( _, _, mutbl) => Some ( RefSimplifiedType ( mutbl) ) ,
101101 ty:: FnDef ( def_id, _) | ty:: Closure ( def_id, _) => Some ( ClosureSimplifiedType ( def_id) ) ,
102102 ty:: Generator ( def_id, _, _) => Some ( GeneratorSimplifiedType ( def_id) ) ,
103- ty:: GeneratorWitness ( ref tys) => {
104- Some ( GeneratorWitnessSimplifiedType ( tys. skip_binder ( ) . len ( ) ) )
105- }
103+ ty:: GeneratorWitness ( tys) => Some ( GeneratorWitnessSimplifiedType ( tys. skip_binder ( ) . len ( ) ) ) ,
106104 ty:: Never => Some ( NeverSimplifiedType ) ,
107- ty:: Tuple ( ref tys) => Some ( TupleSimplifiedType ( tys. len ( ) ) ) ,
108- ty:: FnPtr ( ref f) => Some ( FunctionSimplifiedType ( f. skip_binder ( ) . inputs ( ) . len ( ) ) ) ,
109- ty:: Projection ( _) | ty:: Param ( _) => {
110- if can_simplify_params == SimplifyParams :: Yes {
111- // In normalized types, projections don't unify with
112- // anything. when lazy normalization happens, this
113- // will change. It would still be nice to have a way
114- // to deal with known-not-to-unify-with-anything
115- // projections (e.g., the likes of <__S as Encoder>::Error).
105+ ty:: Tuple ( tys) => Some ( TupleSimplifiedType ( tys. len ( ) ) ) ,
106+ ty:: FnPtr ( f) => Some ( FunctionSimplifiedType ( f. skip_binder ( ) . inputs ( ) . len ( ) ) ) ,
107+ ty:: Param ( _) | ty:: Projection ( _) => match treat_params {
108+ // When treated as bound types, projections don't unify with
109+ // anything as long as they are fully normalized.
110+ //
111+ // We will have to be careful with lazy normalization here.
112+ TreatParams :: AsBoundTypes => {
113+ debug ! ( "treating `{}` as a bound type" , ty ) ;
116114 Some ( ParameterSimplifiedType )
117- } else {
118- None
119115 }
120- }
116+ TreatParams :: AsPlaceholders => None ,
117+ } ,
121118 ty:: Opaque ( def_id, _) => Some ( OpaqueSimplifiedType ( def_id) ) ,
122119 ty:: Foreign ( def_id) => Some ( ForeignSimplifiedType ( def_id) ) ,
123120 ty:: Placeholder ( ..) | ty:: Bound ( ..) | ty:: Infer ( _) | ty:: Error ( _) => None ,
0 commit comments