@@ -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 }
@@ -110,36 +123,25 @@ fn principal_id<'a, I: Interner>(
110123) -> Option < TraitId < I > > {
111124 let interner = db. interner ( ) ;
112125
113- let principal_id = bounds
126+ return bounds
114127 . skip_binders ( )
115128 . 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- }
129+ . filter_map ( |b| b. trait_id ( ) )
130+ . filter ( |& id| !db. trait_datum ( id) . is_auto_trait ( ) )
131+ . next ( ) ;
125132}
126133
127134fn auto_trait_ids < ' a , I : Interner > (
128- db : & dyn RustIrDatabase < I > ,
135+ db : & ' a dyn RustIrDatabase < I > ,
129136 bounds : & ' a Binders < QuantifiedWhereClauses < I > > ,
130137) -> impl Iterator < Item = TraitId < I > > + ' a {
131138 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- } ;
139+
138140 bounds
139141 . skip_binders ( )
140142 . iter ( interner)
141- . skip ( to_skip)
142143 . filter_map ( |clause| clause. trait_id ( ) )
144+ . filter ( move |& id| db. trait_datum ( id) . is_auto_trait ( ) )
143145}
144146
145147pub fn add_unsize_program_clauses < I : Interner > (
@@ -196,10 +198,11 @@ pub fn add_unsize_program_clauses<I: Interner>(
196198 }
197199
198200 // COMMENT FROM RUSTC:
201+ // ------------------
199202 // Require that the traits involved in this upcast are **equal**;
200203 // only the **lifetime bound** is changed.
201204 //
202- // FIXME: This condition is arguably too strong -- it would
205+ // This condition is arguably too strong -- it would
203206 // suffice for the source trait to be a *subtype* of the target
204207 // trait. In particular, changing from something like
205208 // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be
@@ -211,11 +214,13 @@ pub fn add_unsize_program_clauses<I: Interner>(
211214 // with what our behavior should be there. -nikomatsakis
212215 // ------------------
213216
214- // Filter out auto traits of source that are not present in target
215- // and change source lifetime to target lifetime
217+ // Construct a new trait object type by taking the source ty,
218+ // filtering out auto traits of source that are not present in target
219+ // and changing source lifetime to target lifetime.
216220 //
217- // This new type should be equal to target type.
218- let source_ty = TyData :: Dyn ( DynTy {
221+ // In order for the coercion to be valid, this new type
222+ // should be equal to target type.
223+ let new_source_ty = TyData :: Dyn ( DynTy {
219224 bounds : bounds_a. map_ref ( |bounds| {
220225 QuantifiedWhereClauses :: from (
221226 interner,
@@ -238,16 +243,15 @@ pub fn add_unsize_program_clauses<I: Interner>(
238243
239244 // Check that new source is equal to target
240245 let eq_goal = EqGoal {
241- a : source_ty . cast ( interner) ,
246+ a : new_source_ty . cast ( interner) ,
242247 b : target_ty. clone ( ) . cast ( interner) ,
243248 }
244249 . cast ( interner) ;
245250
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- }
251+ let lifetime_outlives_goal: Goal < I > = WhereClause :: LifetimeOutlives ( LifetimeOutlives {
252+ a : lifetime_a. clone ( ) ,
253+ b : lifetime_b. clone ( ) ,
254+ } )
251255 . cast ( interner) ;
252256
253257 builder. push_clause ( trait_ref. clone ( ) , [ eq_goal, lifetime_outlives_goal] . iter ( ) ) ;
@@ -294,6 +298,27 @@ pub fn add_unsize_program_clauses<I: Interner>(
294298 ) ;
295299 }
296300
301+ (
302+ TyData :: Apply ( ApplicationTy {
303+ name : TypeName :: Array ,
304+ substitution : array_subst,
305+ } ) ,
306+ TyData :: Apply ( ApplicationTy {
307+ name : TypeName :: Slice ,
308+ substitution : slice_subst,
309+ } ) ,
310+ ) => {
311+ let array_ty = array_subst. at ( interner, 0 ) ;
312+ let slice_ty = slice_subst. at ( interner, 0 ) ;
313+
314+ let eq_goal = EqGoal {
315+ a : array_ty. clone ( ) ,
316+ b : slice_ty. clone ( ) ,
317+ } ;
318+
319+ builder. push_clause ( trait_ref. clone ( ) , iter:: once ( eq_goal) ) ;
320+ }
321+
297322 // Struct<T> -> Struct<U>
298323 // Unsizing of enums is not allowed
299324 (
@@ -318,19 +343,18 @@ pub fn add_unsize_program_clauses<I: Interner>(
318343 return ;
319344 }
320345
321- let struct_tail_field = struct_datum
346+ let adt_tail_field = struct_datum
322347 . binders
323348 . map_ref ( |bound| bound. fields . last ( ) . unwrap ( ) ) ;
324349
325350 // Collect unsize parameters that last field contains and
326351 // ensure there at least one of them.
327352 let unsize_parameter_candidates =
328- outer_binder_parameters_used ( interner, & struct_tail_field ) ;
353+ outer_binder_parameters_used ( interner, & adt_tail_field ) ;
329354
330355 if unsize_parameter_candidates. len ( ) == 0 {
331356 return ;
332357 }
333-
334358 // Ensure none of the other fields mention the parameters used
335359 // in unsizing.
336360 if uses_outer_binder_params (
@@ -345,15 +369,15 @@ pub fn add_unsize_program_clauses<I: Interner>(
345369
346370 let parameters_a = substitution_a. parameters ( interner) ;
347371 let parameters_b = substitution_b. parameters ( interner) ;
348- // Check that the source struct with the target's
372+ // Check that the source adt with the target's
349373 // unsizing parameters is equal to the target.
350374 let substitution = Substitution :: from (
351375 interner,
352376 parameters_a. iter ( ) . enumerate ( ) . map ( |( i, p) | {
353377 if unsize_parameter_candidates. contains ( & i) {
354- p
355- } else {
356378 & parameters_b[ i]
379+ } else {
380+ p
357381 }
358382 } ) ,
359383 ) ;
@@ -370,8 +394,8 @@ pub fn add_unsize_program_clauses<I: Interner>(
370394 . cast ( interner) ;
371395
372396 // 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) ;
397+ let source_tail_field = adt_tail_field . substitute ( interner, substitution_a) ;
398+ let target_tail_field = adt_tail_field . substitute ( interner, substitution_b) ;
375399
376400 // Check that `TailField<T>: Unsize<TailField<U>>`
377401 let last_field_unsizing_goal: Goal < I > = TraitRef {
0 commit comments