@@ -7,8 +7,9 @@ use chalk_ir::{
7
7
cast:: Cast ,
8
8
interner:: HasInterner ,
9
9
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 ,
12
13
} ;
13
14
14
15
struct UnsizeParameterCollector < ' a , I : Interner > {
@@ -24,14 +25,12 @@ impl<'a, I: Interner> Visitor<'a, I> for UnsizeParameterCollector<'a, I> {
24
25
self
25
26
}
26
27
27
- // FIXME(areredify) when const generics land, collect const variables too
28
-
29
28
fn visit_ty ( & mut self , ty : & Ty < I > , outer_binder : DebruijnIndex ) -> Self :: Result {
30
29
let interner = self . interner ;
31
30
32
31
match ty. data ( interner) {
33
32
TyData :: BoundVar ( bound_var) => {
34
- // check if bound var referse to the outermost binder
33
+ // check if bound var refers to the outermost binder
35
34
if bound_var. debruijn . shifted_in ( ) == outer_binder {
36
35
self . parameters . insert ( bound_var. index ) ;
37
36
}
@@ -40,6 +39,20 @@ impl<'a, I: Interner> Visitor<'a, I> for UnsizeParameterCollector<'a, I> {
40
39
}
41
40
}
42
41
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
+
43
56
fn interner ( & self ) -> & ' a I {
44
57
self . interner
45
58
}
@@ -110,36 +123,25 @@ fn principal_id<'a, I: Interner>(
110
123
) -> Option < TraitId < I > > {
111
124
let interner = db. interner ( ) ;
112
125
113
- let principal_id = bounds
126
+ return bounds
114
127
. skip_binders ( )
115
128
. 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 ( ) ;
125
132
}
126
133
127
134
fn auto_trait_ids < ' a , I : Interner > (
128
- db : & dyn RustIrDatabase < I > ,
135
+ db : & ' a dyn RustIrDatabase < I > ,
129
136
bounds : & ' a Binders < QuantifiedWhereClauses < I > > ,
130
137
) -> impl Iterator < Item = TraitId < I > > + ' a {
131
138
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
+
138
140
bounds
139
141
. skip_binders ( )
140
142
. iter ( interner)
141
- . skip ( to_skip)
142
143
. filter_map ( |clause| clause. trait_id ( ) )
144
+ . filter ( move |& id| db. trait_datum ( id) . is_auto_trait ( ) )
143
145
}
144
146
145
147
pub fn add_unsize_program_clauses < I : Interner > (
@@ -196,10 +198,11 @@ pub fn add_unsize_program_clauses<I: Interner>(
196
198
}
197
199
198
200
// COMMENT FROM RUSTC:
201
+ // ------------------
199
202
// Require that the traits involved in this upcast are **equal**;
200
203
// only the **lifetime bound** is changed.
201
204
//
202
- // FIXME: This condition is arguably too strong -- it would
205
+ // This condition is arguably too strong -- it would
203
206
// suffice for the source trait to be a *subtype* of the target
204
207
// trait. In particular, changing from something like
205
208
// `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>(
211
214
// with what our behavior should be there. -nikomatsakis
212
215
// ------------------
213
216
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.
216
220
//
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 {
219
224
bounds : bounds_a. map_ref ( |bounds| {
220
225
QuantifiedWhereClauses :: from (
221
226
interner,
@@ -238,16 +243,15 @@ pub fn add_unsize_program_clauses<I: Interner>(
238
243
239
244
// Check that new source is equal to target
240
245
let eq_goal = EqGoal {
241
- a : source_ty . cast ( interner) ,
246
+ a : new_source_ty . cast ( interner) ,
242
247
b : target_ty. clone ( ) . cast ( interner) ,
243
248
}
244
249
. cast ( interner) ;
245
250
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
+ } )
251
255
. cast ( interner) ;
252
256
253
257
builder. push_clause ( trait_ref. clone ( ) , [ eq_goal, lifetime_outlives_goal] . iter ( ) ) ;
@@ -294,6 +298,27 @@ pub fn add_unsize_program_clauses<I: Interner>(
294
298
) ;
295
299
}
296
300
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
+
297
322
// Struct<T> -> Struct<U>
298
323
// Unsizing of enums is not allowed
299
324
(
@@ -318,19 +343,18 @@ pub fn add_unsize_program_clauses<I: Interner>(
318
343
return ;
319
344
}
320
345
321
- let struct_tail_field = struct_datum
346
+ let adt_tail_field = struct_datum
322
347
. binders
323
348
. map_ref ( |bound| bound. fields . last ( ) . unwrap ( ) ) ;
324
349
325
350
// Collect unsize parameters that last field contains and
326
351
// ensure there at least one of them.
327
352
let unsize_parameter_candidates =
328
- outer_binder_parameters_used ( interner, & struct_tail_field ) ;
353
+ outer_binder_parameters_used ( interner, & adt_tail_field ) ;
329
354
330
355
if unsize_parameter_candidates. len ( ) == 0 {
331
356
return ;
332
357
}
333
-
334
358
// Ensure none of the other fields mention the parameters used
335
359
// in unsizing.
336
360
if uses_outer_binder_params (
@@ -345,15 +369,15 @@ pub fn add_unsize_program_clauses<I: Interner>(
345
369
346
370
let parameters_a = substitution_a. parameters ( interner) ;
347
371
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
349
373
// unsizing parameters is equal to the target.
350
374
let substitution = Substitution :: from (
351
375
interner,
352
376
parameters_a. iter ( ) . enumerate ( ) . map ( |( i, p) | {
353
377
if unsize_parameter_candidates. contains ( & i) {
354
- p
355
- } else {
356
378
& parameters_b[ i]
379
+ } else {
380
+ p
357
381
}
358
382
} ) ,
359
383
) ;
@@ -370,8 +394,8 @@ pub fn add_unsize_program_clauses<I: Interner>(
370
394
. cast ( interner) ;
371
395
372
396
// 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) ;
375
399
376
400
// Check that `TailField<T>: Unsize<TailField<U>>`
377
401
let last_field_unsizing_goal: Goal < I > = TraitRef {
0 commit comments