@@ -7,8 +7,9 @@ use chalk_ir::{
77 cast:: Cast ,
88 interner:: HasInterner ,
99 visit:: { visitors:: FindAny , SuperVisit , Visit , VisitResult , Visitor } ,
10- ApplicationTy , Binders , DebruijnIndex , DomainGoal , DynTy , EqGoal , Goal , QuantifiedWhereClauses ,
11- Substitution , TraitId , Ty , TyData , TypeName , WhereClause ,
10+ ApplicationTy , Binders , Const , ConstValue , DebruijnIndex , DomainGoal , DynTy , EqGoal , Goal ,
11+ LifetimeOutlives , QuantifiedWhereClauses , Substitution , TraitId , Ty , TyData , TypeName ,
12+ WhereClause ,
1213} ;
1314
1415struct UnsizeParameterCollector < ' a , I : Interner > {
@@ -24,14 +25,12 @@ impl<'a, I: Interner> Visitor<'a, I> for UnsizeParameterCollector<'a, I> {
2425 self
2526 }
2627
27- // FIXME(areredify) when const generics land, collect const variables too
28-
2928 fn visit_ty ( & mut self , ty : & Ty < I > , outer_binder : DebruijnIndex ) -> Self :: Result {
3029 let interner = self . interner ;
3130
3231 match ty. data ( interner) {
3332 TyData :: BoundVar ( bound_var) => {
34- // check if bound var referse to the outermost binder
33+ // check if bound var refers to the outermost binder
3534 if bound_var. debruijn . shifted_in ( ) == outer_binder {
3635 self . parameters . insert ( bound_var. index ) ;
3736 }
@@ -40,6 +39,20 @@ impl<'a, I: Interner> Visitor<'a, I> for UnsizeParameterCollector<'a, I> {
4039 }
4140 }
4241
42+ fn visit_const ( & mut self , constant : & Const < I > , outer_binder : DebruijnIndex ) -> Self :: Result {
43+ let interner = self . interner ;
44+
45+ match constant. data ( interner) . value {
46+ ConstValue :: BoundVar ( bound_var) => {
47+ // check if bound var refers to the outermost binder
48+ if bound_var. debruijn . shifted_in ( ) == outer_binder {
49+ self . parameters . insert ( bound_var. index ) ;
50+ }
51+ }
52+ _ => ( ) ,
53+ }
54+ }
55+
4356 fn interner ( & self ) -> & ' a I {
4457 self . interner
4558 }
@@ -87,6 +100,23 @@ impl<'a, 'p, I: Interner> Visitor<'a, I> for ParameterOccurenceCheck<'a, 'p, I>
87100 }
88101 }
89102
103+ fn visit_const ( & mut self , constant : & Const < I > , outer_binder : DebruijnIndex ) -> Self :: Result {
104+ let interner = self . interner ;
105+
106+ match constant. data ( interner) . value {
107+ ConstValue :: BoundVar ( bound_var) => {
108+ if bound_var. debruijn . shifted_in ( ) == outer_binder
109+ && self . parameters . contains ( & bound_var. index )
110+ {
111+ FindAny :: FOUND
112+ } else {
113+ FindAny :: new ( )
114+ }
115+ }
116+ _ => FindAny :: new ( ) ,
117+ }
118+ }
119+
90120 fn interner ( & self ) -> & ' a I {
91121 self . interner
92122 }
@@ -110,36 +140,25 @@ fn principal_id<'a, I: Interner>(
110140) -> Option < TraitId < I > > {
111141 let interner = db. interner ( ) ;
112142
113- let principal_id = bounds
143+ return bounds
114144 . skip_binders ( )
115145 . iter ( interner)
116- . next ( )
117- . expect ( "Expected trait object to have at least one trait bound" )
118- . trait_id ( ) ?;
119-
120- if db. trait_datum ( principal_id) . is_auto_trait ( ) {
121- None
122- } else {
123- Some ( principal_id)
124- }
146+ . filter_map ( |b| b. trait_id ( ) )
147+ . filter ( |& id| !db. trait_datum ( id) . is_auto_trait ( ) )
148+ . next ( ) ;
125149}
126150
127151fn auto_trait_ids < ' a , I : Interner > (
128- db : & dyn RustIrDatabase < I > ,
152+ db : & ' a dyn RustIrDatabase < I > ,
129153 bounds : & ' a Binders < QuantifiedWhereClauses < I > > ,
130154) -> impl Iterator < Item = TraitId < I > > + ' a {
131155 let interner = db. interner ( ) ;
132- // all trait ref where clauses after the principal are auto traits
133- let to_skip = if principal_id ( db, bounds) . is_some ( ) {
134- 1
135- } else {
136- 0
137- } ;
156+
138157 bounds
139158 . skip_binders ( )
140159 . iter ( interner)
141- . skip ( to_skip)
142160 . filter_map ( |clause| clause. trait_id ( ) )
161+ . filter ( move |& id| db. trait_datum ( id) . is_auto_trait ( ) )
143162}
144163
145164pub fn add_unsize_program_clauses < I : Interner > (
@@ -196,10 +215,11 @@ pub fn add_unsize_program_clauses<I: Interner>(
196215 }
197216
198217 // COMMENT FROM RUSTC:
218+ // ------------------
199219 // Require that the traits involved in this upcast are **equal**;
200220 // only the **lifetime bound** is changed.
201221 //
202- // FIXME: This condition is arguably too strong -- it would
222+ // This condition is arguably too strong -- it would
203223 // suffice for the source trait to be a *subtype* of the target
204224 // trait. In particular, changing from something like
205225 // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be
@@ -211,11 +231,13 @@ pub fn add_unsize_program_clauses<I: Interner>(
211231 // with what our behavior should be there. -nikomatsakis
212232 // ------------------
213233
214- // Filter out auto traits of source that are not present in target
215- // and change source lifetime to target lifetime
234+ // Construct a new trait object type by taking the source ty,
235+ // filtering out auto traits of source that are not present in target
236+ // and changing source lifetime to target lifetime.
216237 //
217- // This new type should be equal to target type.
218- let source_ty = TyData :: Dyn ( DynTy {
238+ // In order for the coercion to be valid, this new type
239+ // should be equal to target type.
240+ let new_source_ty = TyData :: Dyn ( DynTy {
219241 bounds : bounds_a. map_ref ( |bounds| {
220242 QuantifiedWhereClauses :: from (
221243 interner,
@@ -238,16 +260,16 @@ pub fn add_unsize_program_clauses<I: Interner>(
238260
239261 // Check that new source is equal to target
240262 let eq_goal = EqGoal {
241- a : source_ty . cast ( interner) ,
263+ a : new_source_ty . cast ( interner) ,
242264 b : target_ty. clone ( ) . cast ( interner) ,
243265 }
244266 . cast ( interner) ;
245267
246- // FIXME(areredify) change this to outlives once #419 lands
247- let lifetime_outlives_goal = EqGoal {
248- a : lifetime_a. clone ( ) . cast ( interner ) ,
249- b : lifetime_b. clone ( ) . cast ( interner ) ,
250- }
268+ // Check that source lifetime outlives target lifetime
269+ let lifetime_outlives_goal: Goal < I > = WhereClause :: LifetimeOutlives ( LifetimeOutlives {
270+ a : lifetime_a. clone ( ) ,
271+ b : lifetime_b. clone ( ) ,
272+ } )
251273 . cast ( interner) ;
252274
253275 builder. push_clause ( trait_ref. clone ( ) , [ eq_goal, lifetime_outlives_goal] . iter ( ) ) ;
@@ -294,6 +316,27 @@ pub fn add_unsize_program_clauses<I: Interner>(
294316 ) ;
295317 }
296318
319+ (
320+ TyData :: Apply ( ApplicationTy {
321+ name : TypeName :: Array ,
322+ substitution : array_subst,
323+ } ) ,
324+ TyData :: Apply ( ApplicationTy {
325+ name : TypeName :: Slice ,
326+ substitution : slice_subst,
327+ } ) ,
328+ ) => {
329+ let array_ty = array_subst. at ( interner, 0 ) ;
330+ let slice_ty = slice_subst. at ( interner, 0 ) ;
331+
332+ let eq_goal = EqGoal {
333+ a : array_ty. clone ( ) ,
334+ b : slice_ty. clone ( ) ,
335+ } ;
336+
337+ builder. push_clause ( trait_ref. clone ( ) , iter:: once ( eq_goal) ) ;
338+ }
339+
297340 // Struct<T> -> Struct<U>
298341 // Unsizing of enums is not allowed
299342 (
@@ -318,21 +361,22 @@ pub fn add_unsize_program_clauses<I: Interner>(
318361 return ;
319362 }
320363
321- let struct_tail_field = struct_datum
364+ let adt_tail_field = struct_datum
322365 . binders
323366 . map_ref ( |bound| bound. fields . last ( ) . unwrap ( ) ) ;
324367
325368 // Collect unsize parameters that last field contains and
326369 // ensure there at least one of them.
327370 let unsize_parameter_candidates =
328- outer_binder_parameters_used ( interner, & struct_tail_field ) ;
371+ outer_binder_parameters_used ( interner, & adt_tail_field ) ;
329372
330373 if unsize_parameter_candidates. len ( ) == 0 {
331374 return ;
332375 }
333-
334376 // Ensure none of the other fields mention the parameters used
335377 // in unsizing.
378+ // We specifically want variables specified by the outermost binder
379+ // i.e. the struct generic arguments binder.
336380 if uses_outer_binder_params (
337381 interner,
338382 & struct_datum
@@ -345,15 +389,22 @@ pub fn add_unsize_program_clauses<I: Interner>(
345389
346390 let parameters_a = substitution_a. parameters ( interner) ;
347391 let parameters_b = substitution_b. parameters ( interner) ;
348- // Check that the source struct with the target's
392+ // Check that the source adt with the target's
349393 // unsizing parameters is equal to the target.
394+ // We construct a new substitution where if a parameter is used in the
395+ // coercion (i.e. it's a non-lifetime struct parameter used by it's last field),
396+ // then we take that parameter from target substitution, otherwise we take
397+ // it from the source substitution.
398+ //
399+ // In order for the coercion to be valid, target struct and
400+ // struct with this newly constructed substitution applied to it should be equal.
350401 let substitution = Substitution :: from (
351402 interner,
352403 parameters_a. iter ( ) . enumerate ( ) . map ( |( i, p) | {
353404 if unsize_parameter_candidates. contains ( & i) {
354- p
355- } else {
356405 & parameters_b[ i]
406+ } else {
407+ p
357408 }
358409 } ) ,
359410 ) ;
@@ -370,8 +421,8 @@ pub fn add_unsize_program_clauses<I: Interner>(
370421 . cast ( interner) ;
371422
372423 // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
373- let source_tail_field = struct_tail_field . substitute ( interner, substitution_a) ;
374- let target_tail_field = struct_tail_field . substitute ( interner, substitution_b) ;
424+ let source_tail_field = adt_tail_field . substitute ( interner, substitution_a) ;
425+ let target_tail_field = adt_tail_field . substitute ( interner, substitution_b) ;
375426
376427 // Check that `TailField<T>: Unsize<TailField<U>>`
377428 let last_field_unsizing_goal: Goal < I > = TraitRef {
@@ -442,7 +493,6 @@ pub fn add_unsize_program_clauses<I: Interner>(
442493 ) ;
443494 }
444495
445- // FIXME(areredify) extend with array -> slice unsizing
446496 _ => ( ) ,
447497 }
448498}
0 commit comments