@@ -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,15 @@ 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+ let lifetime_outlives_goal: Goal < I > = WhereClause :: LifetimeOutlives ( LifetimeOutlives {
269+ a : lifetime_a. clone ( ) ,
270+ b : lifetime_b. clone ( ) ,
271+ } )
251272 . cast ( interner) ;
252273
253274 builder. push_clause ( trait_ref. clone ( ) , [ eq_goal, lifetime_outlives_goal] . iter ( ) ) ;
@@ -294,6 +315,27 @@ pub fn add_unsize_program_clauses<I: Interner>(
294315 ) ;
295316 }
296317
318+ (
319+ TyData :: Apply ( ApplicationTy {
320+ name : TypeName :: Array ,
321+ substitution : array_subst,
322+ } ) ,
323+ TyData :: Apply ( ApplicationTy {
324+ name : TypeName :: Slice ,
325+ substitution : slice_subst,
326+ } ) ,
327+ ) => {
328+ let array_ty = array_subst. at ( interner, 0 ) ;
329+ let slice_ty = slice_subst. at ( interner, 0 ) ;
330+
331+ let eq_goal = EqGoal {
332+ a : array_ty. clone ( ) ,
333+ b : slice_ty. clone ( ) ,
334+ } ;
335+
336+ builder. push_clause ( trait_ref. clone ( ) , iter:: once ( eq_goal) ) ;
337+ }
338+
297339 // Struct<T> -> Struct<U>
298340 // Unsizing of enums is not allowed
299341 (
@@ -318,19 +360,18 @@ pub fn add_unsize_program_clauses<I: Interner>(
318360 return ;
319361 }
320362
321- let struct_tail_field = struct_datum
363+ let adt_tail_field = struct_datum
322364 . binders
323365 . map_ref ( |bound| bound. fields . last ( ) . unwrap ( ) ) ;
324366
325367 // Collect unsize parameters that last field contains and
326368 // ensure there at least one of them.
327369 let unsize_parameter_candidates =
328- outer_binder_parameters_used ( interner, & struct_tail_field ) ;
370+ outer_binder_parameters_used ( interner, & adt_tail_field ) ;
329371
330372 if unsize_parameter_candidates. len ( ) == 0 {
331373 return ;
332374 }
333-
334375 // Ensure none of the other fields mention the parameters used
335376 // in unsizing.
336377 if uses_outer_binder_params (
@@ -345,15 +386,15 @@ pub fn add_unsize_program_clauses<I: Interner>(
345386
346387 let parameters_a = substitution_a. parameters ( interner) ;
347388 let parameters_b = substitution_b. parameters ( interner) ;
348- // Check that the source struct with the target's
389+ // Check that the source adt with the target's
349390 // unsizing parameters is equal to the target.
350391 let substitution = Substitution :: from (
351392 interner,
352393 parameters_a. iter ( ) . enumerate ( ) . map ( |( i, p) | {
353394 if unsize_parameter_candidates. contains ( & i) {
354- p
355- } else {
356395 & parameters_b[ i]
396+ } else {
397+ p
357398 }
358399 } ) ,
359400 ) ;
@@ -370,8 +411,8 @@ pub fn add_unsize_program_clauses<I: Interner>(
370411 . cast ( interner) ;
371412
372413 // 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) ;
414+ let source_tail_field = adt_tail_field . substitute ( interner, substitution_a) ;
415+ let target_tail_field = adt_tail_field . substitute ( interner, substitution_b) ;
375416
376417 // Check that `TailField<T>: Unsize<TailField<U>>`
377418 let last_field_unsizing_goal: Goal < I > = TraitRef {
0 commit comments