@@ -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
}
@@ -87,6 +100,23 @@ impl<'a, 'p, I: Interner> Visitor<'a, I> for ParameterOccurenceCheck<'a, 'p, I>
87
100
}
88
101
}
89
102
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
+
90
120
fn interner ( & self ) -> & ' a I {
91
121
self . interner
92
122
}
@@ -110,36 +140,25 @@ fn principal_id<'a, I: Interner>(
110
140
) -> Option < TraitId < I > > {
111
141
let interner = db. interner ( ) ;
112
142
113
- let principal_id = bounds
143
+ return bounds
114
144
. skip_binders ( )
115
145
. 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 ( ) ;
125
149
}
126
150
127
151
fn auto_trait_ids < ' a , I : Interner > (
128
- db : & dyn RustIrDatabase < I > ,
152
+ db : & ' a dyn RustIrDatabase < I > ,
129
153
bounds : & ' a Binders < QuantifiedWhereClauses < I > > ,
130
154
) -> impl Iterator < Item = TraitId < I > > + ' a {
131
155
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
+
138
157
bounds
139
158
. skip_binders ( )
140
159
. iter ( interner)
141
- . skip ( to_skip)
142
160
. filter_map ( |clause| clause. trait_id ( ) )
161
+ . filter ( move |& id| db. trait_datum ( id) . is_auto_trait ( ) )
143
162
}
144
163
145
164
pub fn add_unsize_program_clauses < I : Interner > (
@@ -196,10 +215,11 @@ pub fn add_unsize_program_clauses<I: Interner>(
196
215
}
197
216
198
217
// COMMENT FROM RUSTC:
218
+ // ------------------
199
219
// Require that the traits involved in this upcast are **equal**;
200
220
// only the **lifetime bound** is changed.
201
221
//
202
- // FIXME: This condition is arguably too strong -- it would
222
+ // This condition is arguably too strong -- it would
203
223
// suffice for the source trait to be a *subtype* of the target
204
224
// trait. In particular, changing from something like
205
225
// `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>(
211
231
// with what our behavior should be there. -nikomatsakis
212
232
// ------------------
213
233
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.
216
237
//
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 {
219
241
bounds : bounds_a. map_ref ( |bounds| {
220
242
QuantifiedWhereClauses :: from (
221
243
interner,
@@ -238,16 +260,15 @@ pub fn add_unsize_program_clauses<I: Interner>(
238
260
239
261
// Check that new source is equal to target
240
262
let eq_goal = EqGoal {
241
- a : source_ty . cast ( interner) ,
263
+ a : new_source_ty . cast ( interner) ,
242
264
b : target_ty. clone ( ) . cast ( interner) ,
243
265
}
244
266
. cast ( interner) ;
245
267
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
+ } )
251
272
. cast ( interner) ;
252
273
253
274
builder. push_clause ( trait_ref. clone ( ) , [ eq_goal, lifetime_outlives_goal] . iter ( ) ) ;
@@ -294,6 +315,27 @@ pub fn add_unsize_program_clauses<I: Interner>(
294
315
) ;
295
316
}
296
317
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
+
297
339
// Struct<T> -> Struct<U>
298
340
// Unsizing of enums is not allowed
299
341
(
@@ -318,19 +360,18 @@ pub fn add_unsize_program_clauses<I: Interner>(
318
360
return ;
319
361
}
320
362
321
- let struct_tail_field = struct_datum
363
+ let adt_tail_field = struct_datum
322
364
. binders
323
365
. map_ref ( |bound| bound. fields . last ( ) . unwrap ( ) ) ;
324
366
325
367
// Collect unsize parameters that last field contains and
326
368
// ensure there at least one of them.
327
369
let unsize_parameter_candidates =
328
- outer_binder_parameters_used ( interner, & struct_tail_field ) ;
370
+ outer_binder_parameters_used ( interner, & adt_tail_field ) ;
329
371
330
372
if unsize_parameter_candidates. len ( ) == 0 {
331
373
return ;
332
374
}
333
-
334
375
// Ensure none of the other fields mention the parameters used
335
376
// in unsizing.
336
377
if uses_outer_binder_params (
@@ -345,15 +386,15 @@ pub fn add_unsize_program_clauses<I: Interner>(
345
386
346
387
let parameters_a = substitution_a. parameters ( interner) ;
347
388
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
349
390
// unsizing parameters is equal to the target.
350
391
let substitution = Substitution :: from (
351
392
interner,
352
393
parameters_a. iter ( ) . enumerate ( ) . map ( |( i, p) | {
353
394
if unsize_parameter_candidates. contains ( & i) {
354
- p
355
- } else {
356
395
& parameters_b[ i]
396
+ } else {
397
+ p
357
398
}
358
399
} ) ,
359
400
) ;
@@ -370,8 +411,8 @@ pub fn add_unsize_program_clauses<I: Interner>(
370
411
. cast ( interner) ;
371
412
372
413
// 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) ;
375
416
376
417
// Check that `TailField<T>: Unsize<TailField<U>>`
377
418
let last_field_unsizing_goal: Goal < I > = TraitRef {
0 commit comments