1- use std:: fmt;
1+ use std:: { fmt, iter } ;
22
33use crate :: ext:: * ;
44use crate :: goal_builder:: GoalBuilder ;
@@ -252,15 +252,27 @@ fn impl_header_wf_goal<I: Interner>(
252252
253253 let mut gb = GoalBuilder :: new ( db) ;
254254 // forall<P0...Pn> {...}
255- Some (
256- gb. forall ( & impl_fields, ( ) , |gb, _, ( trait_ref, where_clauses) , ( ) | {
255+ Some ( gb. forall (
256+ & impl_fields,
257+ impl_id,
258+ |gb, _, ( trait_ref, where_clauses) , impl_id| {
257259 let interner = gb. interner ( ) ;
258260
259- let trait_constraint_goal = compute_well_known_impl_constraint ( gb. db ( ) , & trait_ref, where_clauses) ;
260-
261261 // if (WC && input types are well formed) { ... }
262- let impl_wf = impl_wf_environment ( interner, & where_clauses, & trait_ref) ;
263- gb. implies ( impl_wf, |gb| {
262+ let impl_wf = ProgramClauses :: from (
263+ interner,
264+ impl_wf_environment ( interner, & where_clauses, & trait_ref) ,
265+ ) ;
266+
267+ let trait_constraint_goal = compute_well_known_impl_constraint (
268+ gb. db ( ) ,
269+ impl_id,
270+ & impl_wf,
271+ & trait_ref,
272+ where_clauses,
273+ ) ;
274+
275+ let well_formed_goal = gb. implies ( impl_wf. iter ( interner) , |gb| {
264276 // We retrieve all the input types of the where clauses appearing on the trait impl,
265277 // e.g. in:
266278 // ```
@@ -277,13 +289,16 @@ fn impl_header_wf_goal<I: Interner>(
277289 let goals = types
278290 . into_iter ( )
279291 . map ( |ty| ty. well_formed ( ) . cast ( interner) )
280- . chain ( Some ( ( * trait_ref) . clone ( ) . well_formed ( ) . cast ( interner) ) )
281- . chain ( trait_constraint_goal. into_iter ( ) ) ;
292+ . chain ( Some ( ( * trait_ref) . clone ( ) . well_formed ( ) . cast ( interner) ) ) ;
282293
283294 gb. all :: < _ , Goal < I > > ( goals)
284- } )
285- } ) ,
286- )
295+ } ) ;
296+
297+ gb. all :: < _ , Goal < I > > (
298+ iter:: once ( well_formed_goal) . chain ( trait_constraint_goal. into_iter ( ) ) ,
299+ )
300+ } ,
301+ ) )
287302}
288303
289304/// Creates the conditions that an impl (and its contents of an impl)
@@ -445,14 +460,22 @@ fn compute_assoc_ty_goal<I: Interner>(
445460 ) )
446461}
447462
448- fn compute_well_known_impl_constraint < I : Interner > ( db : & dyn RustIrDatabase < I > , trait_ref : & TraitRef < I > , where_clause : & [ Binders < WhereClause < I > > ] ) -> Option < Goal < I > > {
463+ fn compute_well_known_impl_constraint < I : Interner > (
464+ db : & dyn RustIrDatabase < I > ,
465+ impl_id : ImplId < I > ,
466+ impl_wf : & ProgramClauses < I > ,
467+ trait_ref : & TraitRef < I > ,
468+ where_clause : & [ Binders < WhereClause < I > > ] ,
469+ ) -> Option < Goal < I > > {
449470 let interner = db. interner ( ) ;
450471
451472 match db. trait_datum ( trait_ref. trait_id ) . well_known ? {
452473 // You can't add a manual implementation of Sized
453474 WellKnownTrait :: SizedTrait => Some ( GoalData :: CannotProve ( ( ) ) . intern ( interner) ) ,
454- WellKnownTrait :: CopyTrait => compute_copy_impl_constraint ( db, trait_ref, where_clause) ,
455- WellKnownTrait :: DropTrait => compute_drop_impl_constraint ( db, trait_ref, where_clause) ,
475+ WellKnownTrait :: CopyTrait => compute_copy_impl_constraint ( db, impl_wf, trait_ref) ,
476+ WellKnownTrait :: DropTrait => {
477+ compute_drop_impl_constraint ( db, impl_id, trait_ref, where_clause)
478+ }
456479 WellKnownTrait :: CloneTrait => None ,
457480 }
458481}
@@ -492,14 +515,12 @@ fn compute_struct_sized_constraint<I: Interner>(
492515/// 2) don't have a Drop impl
493516fn compute_copy_impl_constraint < I : Interner > (
494517 db : & dyn RustIrDatabase < I > ,
518+ impl_wf : & ProgramClauses < I > ,
495519 trait_ref : & TraitRef < I > ,
496- _where_clause : & [ Binders < WhereClause < I > > ] ,
497520) -> Option < Goal < I > > {
498521 let interner = db. interner ( ) ;
499522
500523 let ty = trait_ref. self_type_parameter ( interner) ;
501-
502- let copy_trait = db. well_known_trait_id ( WellKnownTrait :: CopyTrait ) ?;
503524 let ty_data = ty. data ( interner) ;
504525
505526 let ( struct_id, substitution) = match ty_data {
@@ -532,20 +553,98 @@ fn compute_copy_impl_constraint<I: Interner>(
532553 . into_iter ( )
533554 . map ( |f| {
534555 TraitRef {
535- trait_id : copy_trait ,
556+ trait_id : trait_ref . trait_id ,
536557 substitution : Substitution :: from1 ( interner, f) ,
537558 }
538559 . cast ( interner)
539560 } )
540561 . chain ( neg_drop_goal. into_iter ( ) ) ;
541562
542- Some ( Goal :: all ( interner, goals) )
563+ Some ( GoalData :: Implies ( impl_wf . clone ( ) , Goal :: all ( interner, goals) ) . intern ( interner ) )
543564}
544565
566+ /// Computes goal to prove constraints on a Drop implementation
567+ /// Drop implementation is considered well-formed if:
568+ /// a) it's implemented on an ADT
569+ /// b) The generic parameters of the impl's type must all be parameters
570+ /// of the Drop impl itself (i.e., no specialization like
571+ /// `impl Drop for S<Foo> {...}` is allowed).
572+ /// c) Any bounds on the genereic parameters of the impl must be
573+ /// deductible from the bounds imposed by the struct definition
574+ /// (i.e. the implementation must be exactly as generic as the ADT definition).
545575fn compute_drop_impl_constraint < I : Interner > (
546576 db : & dyn RustIrDatabase < I > ,
577+ impl_id : ImplId < I > ,
547578 trait_ref : & TraitRef < I > ,
548- where_clauses : & [ Binders < WhereClause < I > > ]
579+ where_clauses : & [ QuantifiedWhereClause < I > ] ,
549580) -> Option < Goal < I > > {
550- None
581+ let interner = db. interner ( ) ;
582+
583+ let ty = trait_ref. self_type_parameter ( interner) ;
584+ let ty_data = ty. data ( interner) ;
585+
586+ let ( struct_id, substitution) = match ty_data {
587+ TyData :: Apply ( ApplicationTy {
588+ name : TypeName :: Struct ( struct_id) ,
589+ substitution,
590+ } ) => ( * struct_id, substitution) ,
591+ _ => return Some ( GoalData :: CannotProve ( ( ) ) . intern ( interner) ) ,
592+ } ;
593+
594+ let mut gb = GoalBuilder :: new ( db) ;
595+
596+ let struct_datum = db. struct_datum ( struct_id) ;
597+ let struct_name = struct_datum. name ( interner) ;
598+
599+ let implied_by_struct_def_goal = gb. implies (
600+ struct_datum
601+ . binders
602+ . map_ref ( |b| & b. where_clauses )
603+ . substitute ( interner, substitution)
604+ . into_iter ( )
605+ . map ( move |qwc| {
606+ qwc. into_from_env_goal ( interner)
607+ . cast :: < ProgramClause < I > > ( interner)
608+ } ) ,
609+ |gb| {
610+ gb. all (
611+ where_clauses
612+ . iter ( )
613+ . map ( |wc| wc. clone ( ) . into_well_formed_goal ( interner) ) ,
614+ )
615+ } ,
616+ ) ;
617+
618+ let eq_goal = gb. forall (
619+ & struct_datum. binders ,
620+ ( struct_name, impl_id) ,
621+ |gb, substitution, _, ( struct_name, impl_id) | {
622+ let interner = gb. interner ( ) ;
623+
624+ let impl_datum = gb. db ( ) . impl_datum ( impl_id) ;
625+ let def_struct: Ty < I > = ApplicationTy {
626+ name : struct_name,
627+ substitution,
628+ }
629+ . cast ( interner)
630+ . intern ( interner) ;
631+
632+ gb. exists (
633+ & impl_datum
634+ . binders
635+ . map_ref ( |b| b. trait_ref . self_type_parameter ( interner) ) ,
636+ def_struct,
637+ |gb, _, impl_struct, def_struct| {
638+ let interner = gb. interner ( ) ;
639+ GoalData :: EqGoal ( EqGoal {
640+ a : ParameterData :: Ty ( def_struct) . intern ( interner) ,
641+ b : ParameterData :: Ty ( impl_struct. clone ( ) ) . intern ( interner) ,
642+ } )
643+ . intern ( interner)
644+ } ,
645+ )
646+ } ,
647+ ) ;
648+
649+ Some ( gb. all ( [ implied_by_struct_def_goal, eq_goal] . iter ( ) ) )
551650}
0 commit comments