@@ -3,6 +3,7 @@ use self::env_elaborator::elaborate_env_clauses;
33use self :: program_clauses:: ToProgramClauses ;
44use crate :: split:: Split ;
55use crate :: RustIrDatabase ;
6+ use chalk_engine:: context:: Floundered ;
67use chalk_ir:: cast:: Cast ;
78use chalk_ir:: could_match:: CouldMatch ;
89use chalk_ir:: interner:: Interner ;
@@ -12,6 +13,7 @@ use rustc_hash::FxHashSet;
1213pub mod builder;
1314mod builtin_traits;
1415mod env_elaborator;
16+ mod generalize;
1517pub mod program_clauses;
1618
1719/// 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>(
111113 db : & ' db dyn RustIrDatabase < I > ,
112114 environment : & Environment < I > ,
113115 goal : & DomainGoal < I > ,
114- ) -> Vec < ProgramClause < I > > {
116+ ) -> Result < Vec < ProgramClause < I > > , Floundered > {
115117 debug_heading ! (
116118 "program_clauses_for_goal(goal={:?}, environment={:?})" ,
117119 goal,
@@ -121,13 +123,13 @@ pub(crate) fn program_clauses_for_goal<'db, I: Interner>(
121123
122124 let mut vec = vec ! [ ] ;
123125 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) ? ;
125127 program_clauses_for_env ( db, environment, & mut vec) ;
126128 vec. retain ( |c| c. could_match ( interner, goal) ) ;
127129
128130 debug ! ( "vec = {:#?}" , vec) ;
129131
130- vec
132+ Ok ( vec)
131133}
132134
133135/// Returns a set of program clauses that could possibly match
@@ -139,17 +141,26 @@ fn program_clauses_that_could_match<I: Interner>(
139141 environment : & Environment < I > ,
140142 goal : & DomainGoal < I > ,
141143 clauses : & mut Vec < ProgramClause < I > > ,
142- ) {
144+ ) -> Result < ( ) , Floundered > {
143145 let interner = db. interner ( ) ;
144146 let builder = & mut ClauseBuilder :: new ( db, clauses) ;
145147
146148 match goal {
147149 DomainGoal :: Holds ( WhereClause :: Implemented ( trait_ref) ) => {
148150 let trait_id = trait_ref. trait_id ;
149151
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+
150161 // This is needed for the coherence related impls, as well
151162 // 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) ;
153164
154165 for impl_id in db. impls_for_trait (
155166 trait_ref. trait_id ,
@@ -168,8 +179,8 @@ fn program_clauses_that_could_match<I: Interner>(
168179 push_auto_trait_impls ( builder, trait_id, struct_id) ;
169180 }
170181 }
171- TyData :: InferenceVar ( _) => {
172- panic ! ( "auto-traits should flounder if nothing is known" )
182+ TyData :: InferenceVar ( _) | TyData :: BoundVar ( _ ) => {
183+ return Err ( Floundered ) ;
173184 }
174185 _ => { }
175186 }
@@ -222,19 +233,29 @@ fn program_clauses_that_could_match<I: Interner>(
222233 // and `bounded_ty` is the `exists<T> { .. }`
223234 // clauses shown above.
224235
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+ } ) ;
238259 }
239260
240261 if let Some ( well_known) = trait_datum. well_known {
@@ -257,9 +278,9 @@ fn program_clauses_that_could_match<I: Interner>(
257278 }
258279 DomainGoal :: WellFormed ( WellFormed :: Ty ( ty) )
259280 | DomainGoal :: IsUpstream ( ty)
260- | DomainGoal :: DownstreamType ( ty) => match_ty ( builder, environment, ty) ,
281+ | DomainGoal :: DownstreamType ( ty) => match_ty ( builder, environment, ty) ? ,
261282 DomainGoal :: IsFullyVisible ( ty) | DomainGoal :: IsLocal ( ty) => {
262- match_ty ( builder, environment, ty)
283+ match_ty ( builder, environment, ty) ?
263284 }
264285 DomainGoal :: FromEnv ( _) => ( ) , // Computed in the environment
265286 DomainGoal :: Normalize ( Normalize { alias, ty : _ } ) => {
@@ -277,6 +298,18 @@ fn program_clauses_that_could_match<I: Interner>(
277298 let associated_ty_datum = db. associated_ty_data ( alias. associated_ty_id ) ;
278299 let trait_id = associated_ty_datum. trait_id ;
279300 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+
280313 push_program_clauses_for_associated_type_values_in_impls_of (
281314 builder,
282315 trait_id,
@@ -288,6 +321,8 @@ fn program_clauses_that_could_match<I: Interner>(
288321 . to_program_clauses ( builder) ,
289322 DomainGoal :: Compatible ( ( ) ) => ( ) ,
290323 } ;
324+
325+ Ok ( ( ) )
291326}
292327
293328/// Generate program clauses from the associated-type values
@@ -348,9 +383,9 @@ fn match_ty<I: Interner>(
348383 builder : & mut ClauseBuilder < ' _ , I > ,
349384 environment : & Environment < I > ,
350385 ty : & Ty < I > ,
351- ) {
386+ ) -> Result < ( ) , Floundered > {
352387 let interner = builder. interner ( ) ;
353- match ty. data ( interner) {
388+ Ok ( match ty. data ( interner) {
354389 TyData :: Apply ( application_ty) => match_type_name ( builder, application_ty. name ) ,
355390 TyData :: Placeholder ( _) => {
356391 builder. push_clause ( WellFormed :: Ty ( ty. clone ( ) ) , Some ( FromEnv :: Ty ( ty. clone ( ) ) ) ) ;
@@ -365,12 +400,12 @@ fn match_ty<I: Interner>(
365400 . substitution
366401 . iter ( interner)
367402 . 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 > > ( ) ?;
369405 }
370- TyData :: BoundVar ( _) => { }
371- TyData :: InferenceVar ( _) => panic ! ( "should have floundered" ) ,
406+ TyData :: BoundVar ( _) | TyData :: InferenceVar ( _) => return Err ( Floundered ) ,
372407 TyData :: Dyn ( _) => { }
373- }
408+ } )
374409}
375410
376411fn match_type_name < I : Interner > ( builder : & mut ClauseBuilder < ' _ , I > , name : TypeName < I > ) {
@@ -396,6 +431,8 @@ fn program_clauses_for_env<'db, I: Interner>(
396431 environment : & Environment < I > ,
397432 clauses : & mut Vec < ProgramClause < I > > ,
398433) {
434+ clauses. extend ( environment. clauses . iter ( db. interner ( ) ) . cloned ( ) ) ;
435+
399436 let mut last_round = FxHashSet :: default ( ) ;
400437 elaborate_env_clauses (
401438 db,
0 commit comments