1
- use std:: fmt;
1
+ use std:: { fmt, iter } ;
2
2
3
3
use crate :: ext:: * ;
4
4
use crate :: goal_builder:: GoalBuilder ;
@@ -252,15 +252,27 @@ fn impl_header_wf_goal<I: Interner>(
252
252
253
253
let mut gb = GoalBuilder :: new ( db) ;
254
254
// 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| {
257
259
let interner = gb. interner ( ) ;
258
260
259
- let trait_constraint_goal = compute_well_known_impl_constraint ( gb. db ( ) , & trait_ref, where_clauses) ;
260
-
261
261
// 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| {
264
276
// We retrieve all the input types of the where clauses appearing on the trait impl,
265
277
// e.g. in:
266
278
// ```
@@ -277,13 +289,16 @@ fn impl_header_wf_goal<I: Interner>(
277
289
let goals = types
278
290
. into_iter ( )
279
291
. 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) ) ) ;
282
293
283
294
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
+ ) )
287
302
}
288
303
289
304
/// Creates the conditions that an impl (and its contents of an impl)
@@ -445,14 +460,22 @@ fn compute_assoc_ty_goal<I: Interner>(
445
460
) )
446
461
}
447
462
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 > > {
449
470
let interner = db. interner ( ) ;
450
471
451
472
match db. trait_datum ( trait_ref. trait_id ) . well_known ? {
452
473
// You can't add a manual implementation of Sized
453
474
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
+ }
456
479
WellKnownTrait :: CloneTrait => None ,
457
480
}
458
481
}
@@ -492,14 +515,12 @@ fn compute_struct_sized_constraint<I: Interner>(
492
515
/// 2) don't have a Drop impl
493
516
fn compute_copy_impl_constraint < I : Interner > (
494
517
db : & dyn RustIrDatabase < I > ,
518
+ impl_wf : & ProgramClauses < I > ,
495
519
trait_ref : & TraitRef < I > ,
496
- _where_clause : & [ Binders < WhereClause < I > > ] ,
497
520
) -> Option < Goal < I > > {
498
521
let interner = db. interner ( ) ;
499
522
500
523
let ty = trait_ref. self_type_parameter ( interner) ;
501
-
502
- let copy_trait = db. well_known_trait_id ( WellKnownTrait :: CopyTrait ) ?;
503
524
let ty_data = ty. data ( interner) ;
504
525
505
526
let ( struct_id, substitution) = match ty_data {
@@ -532,20 +553,98 @@ fn compute_copy_impl_constraint<I: Interner>(
532
553
. into_iter ( )
533
554
. map ( |f| {
534
555
TraitRef {
535
- trait_id : copy_trait ,
556
+ trait_id : trait_ref . trait_id ,
536
557
substitution : Substitution :: from1 ( interner, f) ,
537
558
}
538
559
. cast ( interner)
539
560
} )
540
561
. chain ( neg_drop_goal. into_iter ( ) ) ;
541
562
542
- Some ( Goal :: all ( interner, goals) )
563
+ Some ( GoalData :: Implies ( impl_wf . clone ( ) , Goal :: all ( interner, goals) ) . intern ( interner ) )
543
564
}
544
565
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).
545
575
fn compute_drop_impl_constraint < I : Interner > (
546
576
db : & dyn RustIrDatabase < I > ,
577
+ impl_id : ImplId < I > ,
547
578
trait_ref : & TraitRef < I > ,
548
- where_clauses : & [ Binders < WhereClause < I > > ]
579
+ where_clauses : & [ QuantifiedWhereClause < I > ] ,
549
580
) -> 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 ( ) ) )
551
650
}
0 commit comments