@@ -3,6 +3,7 @@ use self::env_elaborator::elaborate_env_clauses;
3
3
use self :: program_clauses:: ToProgramClauses ;
4
4
use crate :: split:: Split ;
5
5
use crate :: RustIrDatabase ;
6
+ use chalk_engine:: context:: Floundered ;
6
7
use chalk_ir:: cast:: Cast ;
7
8
use chalk_ir:: could_match:: CouldMatch ;
8
9
use chalk_ir:: interner:: Interner ;
@@ -12,6 +13,7 @@ use rustc_hash::FxHashSet;
12
13
pub mod builder;
13
14
mod builtin_traits;
14
15
mod env_elaborator;
16
+ mod generalize;
15
17
pub mod program_clauses;
16
18
17
19
/// For auto-traits, we generate a default rule for every struct,
@@ -111,7 +113,7 @@ pub(crate) fn program_clauses_for_goal<'db, I: Interner>(
111
113
db : & ' db dyn RustIrDatabase < I > ,
112
114
environment : & Environment < I > ,
113
115
goal : & DomainGoal < I > ,
114
- ) -> Vec < ProgramClause < I > > {
116
+ ) -> Result < Vec < ProgramClause < I > > , Floundered > {
115
117
debug_heading ! (
116
118
"program_clauses_for_goal(goal={:?}, environment={:?})" ,
117
119
goal,
@@ -121,13 +123,13 @@ pub(crate) fn program_clauses_for_goal<'db, I: Interner>(
121
123
122
124
let mut vec = vec ! [ ] ;
123
125
vec. extend ( db. custom_clauses ( ) ) ;
124
- program_clauses_that_could_match ( db, environment, goal, & mut vec) ;
126
+ program_clauses_that_could_match ( db, environment, goal, & mut vec) ? ;
125
127
program_clauses_for_env ( db, environment, & mut vec) ;
126
128
vec. retain ( |c| c. could_match ( interner, goal) ) ;
127
129
128
130
debug ! ( "vec = {:#?}" , vec) ;
129
131
130
- vec
132
+ Ok ( vec)
131
133
}
132
134
133
135
/// Returns a set of program clauses that could possibly match
@@ -139,17 +141,26 @@ fn program_clauses_that_could_match<I: Interner>(
139
141
environment : & Environment < I > ,
140
142
goal : & DomainGoal < I > ,
141
143
clauses : & mut Vec < ProgramClause < I > > ,
142
- ) {
144
+ ) -> Result < ( ) , Floundered > {
143
145
let interner = db. interner ( ) ;
144
146
let builder = & mut ClauseBuilder :: new ( db, clauses) ;
145
147
146
148
match goal {
147
149
DomainGoal :: Holds ( WhereClause :: Implemented ( trait_ref) ) => {
148
150
let trait_id = trait_ref. trait_id ;
149
151
152
+ let trait_datum = db. trait_datum ( trait_id) ;
153
+
154
+ if trait_datum. is_non_enumerable_trait ( ) || trait_datum. is_auto_trait ( ) {
155
+ let self_ty = trait_ref. self_type_parameter ( interner) ;
156
+ if self_ty. bound ( interner) . is_some ( ) || self_ty. inference_var ( interner) . is_some ( ) {
157
+ return Err ( Floundered ) ;
158
+ }
159
+ }
160
+
150
161
// This is needed for the coherence related impls, as well
151
162
// as for the `Implemented(Foo) :- FromEnv(Foo)` rule.
152
- db . trait_datum ( trait_id ) . to_program_clauses ( builder) ;
163
+ trait_datum. to_program_clauses ( builder) ;
153
164
154
165
for impl_id in db. impls_for_trait (
155
166
trait_ref. trait_id ,
@@ -168,8 +179,8 @@ fn program_clauses_that_could_match<I: Interner>(
168
179
push_auto_trait_impls ( builder, trait_id, struct_id) ;
169
180
}
170
181
}
171
- TyData :: InferenceVar ( _) => {
172
- panic ! ( "auto-traits should flounder if nothing is known" )
182
+ TyData :: InferenceVar ( _) | TyData :: BoundVar ( _ ) => {
183
+ return Err ( Floundered ) ;
173
184
}
174
185
_ => { }
175
186
}
@@ -222,19 +233,29 @@ fn program_clauses_that_could_match<I: Interner>(
222
233
// and `bounded_ty` is the `exists<T> { .. }`
223
234
// clauses shown above.
224
235
225
- for exists_qwc in dyn_ty. bounds . map_ref ( |r| r. iter ( interner) ) {
226
- // Replace the `T` from `exists<T> { .. }` with `self_ty`,
227
- // yielding clases like
228
- //
229
- // ```
230
- // forall<'a> { Implemented(dyn Fn(&u8): Fn<(&'a u8)>) }
231
- // ```
232
- let qwc = exists_qwc. substitute ( interner, & [ self_ty. clone ( ) . cast ( interner) ] ) ;
233
-
234
- builder. push_binders ( & qwc, |builder, wc| {
235
- builder. push_fact ( wc) ;
236
- } ) ;
237
- }
236
+ // Turn free BoundVars in the type into new existentials. E.g.
237
+ // we might get some `dyn Foo<?X>`, and we don't want to return
238
+ // a clause with a free variable. We can instead return a
239
+ // slightly more general clause by basically turning this into
240
+ // `exists<A> dyn Foo<A>`.
241
+ let generalized_dyn_ty = generalize:: Generalize :: apply ( db. interner ( ) , dyn_ty) ;
242
+
243
+ builder. push_binders ( & generalized_dyn_ty, |builder, dyn_ty| {
244
+ for exists_qwc in dyn_ty. bounds . map_ref ( |r| r. iter ( interner) ) {
245
+ // Replace the `T` from `exists<T> { .. }` with `self_ty`,
246
+ // yielding clases like
247
+ //
248
+ // ```
249
+ // forall<'a> { Implemented(dyn Fn(&u8): Fn<(&'a u8)>) }
250
+ // ```
251
+ let qwc =
252
+ exists_qwc. substitute ( interner, & [ self_ty. clone ( ) . cast ( interner) ] ) ;
253
+
254
+ builder. push_binders ( & qwc, |builder, wc| {
255
+ builder. push_fact ( wc) ;
256
+ } ) ;
257
+ }
258
+ } ) ;
238
259
}
239
260
240
261
if let Some ( well_known) = trait_datum. well_known {
@@ -257,9 +278,9 @@ fn program_clauses_that_could_match<I: Interner>(
257
278
}
258
279
DomainGoal :: WellFormed ( WellFormed :: Ty ( ty) )
259
280
| DomainGoal :: IsUpstream ( ty)
260
- | DomainGoal :: DownstreamType ( ty) => match_ty ( builder, environment, ty) ,
281
+ | DomainGoal :: DownstreamType ( ty) => match_ty ( builder, environment, ty) ? ,
261
282
DomainGoal :: IsFullyVisible ( ty) | DomainGoal :: IsLocal ( ty) => {
262
- match_ty ( builder, environment, ty)
283
+ match_ty ( builder, environment, ty) ?
263
284
}
264
285
DomainGoal :: FromEnv ( _) => ( ) , // Computed in the environment
265
286
DomainGoal :: Normalize ( Normalize { alias, ty : _ } ) => {
@@ -277,6 +298,18 @@ fn program_clauses_that_could_match<I: Interner>(
277
298
let associated_ty_datum = db. associated_ty_data ( alias. associated_ty_id ) ;
278
299
let trait_id = associated_ty_datum. trait_id ;
279
300
let trait_parameters = db. trait_parameters_from_projection ( alias) ;
301
+
302
+ let trait_datum = db. trait_datum ( trait_id) ;
303
+
304
+ // Flounder if the self-type is unknown and the trait is non-enumerable.
305
+ //
306
+ // e.g., Normalize(<?X as Iterator>::Item = u32)
307
+ if ( alias. self_type_parameter ( interner) . is_var ( interner) )
308
+ && trait_datum. is_non_enumerable_trait ( )
309
+ {
310
+ return Err ( Floundered ) ;
311
+ }
312
+
280
313
push_program_clauses_for_associated_type_values_in_impls_of (
281
314
builder,
282
315
trait_id,
@@ -288,6 +321,8 @@ fn program_clauses_that_could_match<I: Interner>(
288
321
. to_program_clauses ( builder) ,
289
322
DomainGoal :: Compatible ( ( ) ) => ( ) ,
290
323
} ;
324
+
325
+ Ok ( ( ) )
291
326
}
292
327
293
328
/// Generate program clauses from the associated-type values
@@ -348,9 +383,9 @@ fn match_ty<I: Interner>(
348
383
builder : & mut ClauseBuilder < ' _ , I > ,
349
384
environment : & Environment < I > ,
350
385
ty : & Ty < I > ,
351
- ) {
386
+ ) -> Result < ( ) , Floundered > {
352
387
let interner = builder. interner ( ) ;
353
- match ty. data ( interner) {
388
+ Ok ( match ty. data ( interner) {
354
389
TyData :: Apply ( application_ty) => match_type_name ( builder, application_ty. name ) ,
355
390
TyData :: Placeholder ( _) => {
356
391
builder. push_clause ( WellFormed :: Ty ( ty. clone ( ) ) , Some ( FromEnv :: Ty ( ty. clone ( ) ) ) ) ;
@@ -365,12 +400,12 @@ fn match_ty<I: Interner>(
365
400
. substitution
366
401
. iter ( interner)
367
402
. map ( |p| p. assert_ty_ref ( interner) )
368
- . for_each ( |ty| match_ty ( builder, environment, & ty) )
403
+ . map ( |ty| match_ty ( builder, environment, & ty) )
404
+ . collect :: < Result < _ , Floundered > > ( ) ?;
369
405
}
370
- TyData :: BoundVar ( _) => { }
371
- TyData :: InferenceVar ( _) => panic ! ( "should have floundered" ) ,
406
+ TyData :: BoundVar ( _) | TyData :: InferenceVar ( _) => return Err ( Floundered ) ,
372
407
TyData :: Dyn ( _) => { }
373
- }
408
+ } )
374
409
}
375
410
376
411
fn match_type_name < I : Interner > ( builder : & mut ClauseBuilder < ' _ , I > , name : TypeName < I > ) {
@@ -396,6 +431,8 @@ fn program_clauses_for_env<'db, I: Interner>(
396
431
environment : & Environment < I > ,
397
432
clauses : & mut Vec < ProgramClause < I > > ,
398
433
) {
434
+ clauses. extend ( environment. clauses . iter ( db. interner ( ) ) . cloned ( ) ) ;
435
+
399
436
let mut last_round = FxHashSet :: default ( ) ;
400
437
elaborate_env_clauses (
401
438
db,
0 commit comments