@@ -199,7 +199,7 @@ where
199
199
// each variant are sized. For `structs`, we relax this requirement to
200
200
// all but the last field.
201
201
let sized_constraint_goal =
202
- WfWellKnownGoals :: struct_sized_constraint (
202
+ WfWellKnownConstraints :: struct_sized_constraint (
203
203
gb. db ( ) ,
204
204
fields,
205
205
is_enum,
@@ -251,6 +251,10 @@ where
251
251
) ,
252
252
) ;
253
253
254
+ if let Some ( well_known) = self . db . trait_datum ( trait_id) . well_known {
255
+ self . verify_well_known_impl ( impl_id, well_known) ?
256
+ }
257
+
254
258
debug ! ( "WF trait goal: {:?}" , impl_goal) ;
255
259
256
260
let mut fresh_solver = ( self . solver_builder ) ( ) ;
@@ -317,6 +321,38 @@ where
317
321
Err ( WfError :: IllFormedOpaqueTypeDecl ( opaque_ty_id) )
318
322
}
319
323
}
324
+
325
+ /// Verify builtin rules for well-known traits
326
+ pub fn verify_well_known_impl (
327
+ & self ,
328
+ impl_id : ImplId < I > ,
329
+ well_known : WellKnownTrait ,
330
+ ) -> Result < ( ) , WfError < I > > {
331
+ let mut solver = ( self . solver_builder ) ( ) ;
332
+ let impl_datum = self . db . impl_datum ( impl_id) ;
333
+
334
+ let is_legal = match well_known {
335
+ WellKnownTrait :: Copy => {
336
+ WfWellKnownConstraints :: copy_impl_constraint ( & mut * solver, self . db , & impl_datum)
337
+ }
338
+ WellKnownTrait :: Drop => {
339
+ WfWellKnownConstraints :: drop_impl_constraint ( & mut * solver, self . db , & impl_datum)
340
+ }
341
+ WellKnownTrait :: Clone | WellKnownTrait :: Unpin => true ,
342
+ // You can't add a manual implementation for the following traits:
343
+ WellKnownTrait :: Fn
344
+ | WellKnownTrait :: FnOnce
345
+ | WellKnownTrait :: FnMut
346
+ | WellKnownTrait :: Unsize
347
+ | WellKnownTrait :: Sized => false ,
348
+ } ;
349
+
350
+ if is_legal {
351
+ Ok ( ( ) )
352
+ } else {
353
+ Err ( WfError :: IllFormedTraitImpl ( impl_datum. trait_id ( ) ) )
354
+ }
355
+ }
320
356
}
321
357
322
358
fn impl_header_wf_goal < I : Interner > (
@@ -338,8 +374,6 @@ fn impl_header_wf_goal<I: Interner>(
338
374
let well_formed_goal = gb. forall ( & impl_fields, ( ) , |gb, _, ( trait_ref, where_clauses) , ( ) | {
339
375
let interner = gb. interner ( ) ;
340
376
341
- let trait_constraint_goal = WfWellKnownGoals :: inside_impl ( gb. db ( ) , & trait_ref) ;
342
-
343
377
// if (WC && input types are well formed) { ... }
344
378
gb. implies (
345
379
impl_wf_environment ( interner, & where_clauses, & trait_ref) ,
@@ -360,20 +394,14 @@ fn impl_header_wf_goal<I: Interner>(
360
394
let goals = types
361
395
. into_iter ( )
362
396
. map ( |ty| ty. well_formed ( ) . cast ( interner) )
363
- . chain ( Some ( ( * trait_ref) . clone ( ) . well_formed ( ) . cast ( interner) ) )
364
- . chain ( trait_constraint_goal. into_iter ( ) ) ;
397
+ . chain ( Some ( ( * trait_ref) . clone ( ) . well_formed ( ) . cast ( interner) ) ) ;
365
398
366
399
gb. all :: < _ , Goal < I > > ( goals)
367
400
} ,
368
401
)
369
402
} ) ;
370
403
371
- Some (
372
- gb. all (
373
- iter:: once ( well_formed_goal)
374
- . chain ( WfWellKnownGoals :: outside_impl ( db, & impl_datum) . into_iter ( ) ) ,
375
- ) ,
376
- )
404
+ Some ( well_formed_goal)
377
405
}
378
406
379
407
/// Creates the conditions that an impl (and its contents of an impl)
@@ -537,49 +565,9 @@ fn compute_assoc_ty_goal<I: Interner>(
537
565
538
566
/// Defines methods to compute well-formedness goals for well-known
539
567
/// traits (e.g. a goal for all fields of struct in a Copy impl to be Copy)
540
- struct WfWellKnownGoals { }
541
-
542
- impl WfWellKnownGoals {
543
- /// A convenience method to compute the goal assuming `trait_ref`
544
- /// well-formedness requirements are in the environment.
545
- pub fn inside_impl < I : Interner > (
546
- db : & dyn RustIrDatabase < I > ,
547
- trait_ref : & TraitRef < I > ,
548
- ) -> Option < Goal < I > > {
549
- match db. trait_datum ( trait_ref. trait_id ) . well_known ? {
550
- WellKnownTrait :: Copy => Self :: copy_impl_constraint ( db, trait_ref) ,
551
- WellKnownTrait :: Drop
552
- | WellKnownTrait :: Clone
553
- | WellKnownTrait :: Sized
554
- | WellKnownTrait :: FnOnce
555
- | WellKnownTrait :: FnMut
556
- | WellKnownTrait :: Fn
557
- | WellKnownTrait :: Unsize
558
- | WellKnownTrait :: Unpin => None ,
559
- }
560
- }
561
-
562
- /// Computes well-formedness goals without any assumptions about the environment.
563
- /// Note that `outside_impl` does not call `inside_impl`, one needs to call both
564
- /// in order to get the full set of goals to be proven.
565
- pub fn outside_impl < I : Interner > (
566
- db : & dyn RustIrDatabase < I > ,
567
- impl_datum : & ImplDatum < I > ,
568
- ) -> Option < Goal < I > > {
569
- let interner = db. interner ( ) ;
570
-
571
- match db. trait_datum ( impl_datum. trait_id ( ) ) . well_known ? {
572
- WellKnownTrait :: Drop => Self :: drop_impl_constraint ( db, impl_datum) ,
573
- WellKnownTrait :: Copy | WellKnownTrait :: Clone | WellKnownTrait :: Unpin => None ,
574
- // You can't add a manual implementation for following traits:
575
- WellKnownTrait :: Sized
576
- | WellKnownTrait :: FnOnce
577
- | WellKnownTrait :: FnMut
578
- | WellKnownTrait :: Fn
579
- | WellKnownTrait :: Unsize => Some ( GoalData :: CannotProve . intern ( interner) ) ,
580
- }
581
- }
568
+ struct WfWellKnownConstraints { }
582
569
570
+ impl WfWellKnownConstraints {
583
571
/// Computes a goal to prove Sized constraints on a struct definition.
584
572
/// Struct is considered well-formed (in terms of Sized) when it either
585
573
/// has no fields or all of it's fields except the last are proven to be Sized.
@@ -610,71 +598,108 @@ impl WfWellKnownGoals {
610
598
) )
611
599
}
612
600
613
- /// Computes a goal to prove constraints on a Copy implementation.
601
+ /// Verify constraints on a Copy implementation.
614
602
/// Copy impl is considered well-formed for
615
603
/// a) certain builtin types (scalar values, shared ref, etc..)
616
604
/// b) adts which
617
605
/// 1) have all Copy fields
618
606
/// 2) don't have a Drop impl
619
607
fn copy_impl_constraint < I : Interner > (
608
+ solver : & mut dyn Solver < I > ,
620
609
db : & dyn RustIrDatabase < I > ,
621
- trait_ref : & TraitRef < I > ,
622
- ) -> Option < Goal < I > > {
610
+ impl_datum : & ImplDatum < I > ,
611
+ ) -> bool {
623
612
let interner = db. interner ( ) ;
624
613
625
- let ty = trait_ref. self_type_parameter ( interner) ;
626
- let ty_data = ty. data ( interner) ;
614
+ let mut gb = GoalBuilder :: new ( db) ;
615
+
616
+ let impl_fields = impl_datum
617
+ . binders
618
+ . map_ref ( |v| ( & v. trait_ref , & v. where_clauses ) ) ;
627
619
628
620
// Implementations for scalars, pointer types and never type are provided by libcore.
629
621
// User implementations on types other than ADTs are forbidden.
630
- let ( adt_id, substitution) = match ty_data {
631
- TyData :: Apply ( ApplicationTy { name, substitution } ) => match name {
622
+ match impl_datum
623
+ . binders
624
+ . skip_binders ( )
625
+ . trait_ref
626
+ . self_type_parameter ( interner)
627
+ . data ( interner)
628
+ {
629
+ TyData :: Apply ( ApplicationTy { name, .. } ) => match name {
632
630
TypeName :: Scalar ( _)
633
631
| TypeName :: Raw ( _)
634
632
| TypeName :: Ref ( Mutability :: Not )
635
- | TypeName :: Never => return None ,
636
- TypeName :: Adt ( adt_id ) => ( * adt_id , substitution ) ,
637
- _ => return Some ( GoalData :: CannotProve . intern ( interner ) ) ,
633
+ | TypeName :: Never => return true ,
634
+ TypeName :: Adt ( _ ) => ( ) ,
635
+ _ => return false ,
638
636
} ,
639
637
640
- _ => return Some ( GoalData :: CannotProve . intern ( interner ) ) ,
638
+ _ => return false ,
641
639
} ;
642
640
643
- // not { Implemented(ImplSelfTy: Drop) }
644
- let neg_drop_goal = db
645
- . well_known_trait_id ( WellKnownTrait :: Drop )
646
- . map ( |drop_trait_id| {
647
- TraitRef {
648
- trait_id : drop_trait_id,
649
- substitution : Substitution :: from1 ( interner, ty. clone ( ) ) ,
650
- }
651
- . cast :: < Goal < I > > ( interner)
652
- . negate ( interner)
653
- } ) ;
641
+ // Well fomedness goal for ADTs
642
+ let well_formed_goal =
643
+ gb. forall ( & impl_fields, ( ) , |gb, _, ( trait_ref, where_clauses) , ( ) | {
644
+ let interner = gb. interner ( ) ;
654
645
655
- let adt_datum = db. adt_datum ( adt_id) ;
646
+ let ty = trait_ref. self_type_parameter ( interner) ;
647
+ let ty_data = ty. data ( interner) ;
656
648
657
- let goals = adt_datum
658
- . binders
659
- . map_ref ( |b| & b. variants )
660
- . substitute ( interner, substitution)
661
- . into_iter ( )
662
- . flat_map ( |v| {
663
- v. fields . into_iter ( ) . map ( |f| {
664
- // Implemented(FieldTy: Copy)
665
- TraitRef {
666
- trait_id : trait_ref. trait_id ,
667
- substitution : Substitution :: from1 ( interner, f) ,
668
- }
669
- . cast ( interner)
670
- } )
671
- } )
672
- . chain ( neg_drop_goal. into_iter ( ) ) ;
649
+ let ( adt_id, substitution) = match ty_data {
650
+ TyData :: Apply ( ApplicationTy { name, substitution } ) => match name {
651
+ TypeName :: Adt ( adt_id) => ( * adt_id, substitution) ,
652
+ _ => unreachable ! ( ) ,
653
+ } ,
654
+
655
+ _ => unreachable ! ( ) ,
656
+ } ;
657
+
658
+ // if (WC) { ... }
659
+ gb. implies (
660
+ impl_wf_environment ( interner, & where_clauses, & trait_ref) ,
661
+ |gb| -> Goal < I > {
662
+ let db = gb. db ( ) ;
663
+
664
+ // not { Implemented(ImplSelfTy: Drop) }
665
+ let neg_drop_goal =
666
+ db. well_known_trait_id ( WellKnownTrait :: Drop )
667
+ . map ( |drop_trait_id| {
668
+ TraitRef {
669
+ trait_id : drop_trait_id,
670
+ substitution : Substitution :: from1 ( interner, ty. clone ( ) ) ,
671
+ }
672
+ . cast :: < Goal < I > > ( interner)
673
+ . negate ( interner)
674
+ } ) ;
675
+
676
+ let adt_datum = db. adt_datum ( adt_id) ;
677
+
678
+ let goals = adt_datum
679
+ . binders
680
+ . map_ref ( |b| & b. variants )
681
+ . substitute ( interner, substitution)
682
+ . into_iter ( )
683
+ . flat_map ( |v| {
684
+ v. fields . into_iter ( ) . map ( |f| {
685
+ // Implemented(FieldTy: Copy)
686
+ TraitRef {
687
+ trait_id : trait_ref. trait_id ,
688
+ substitution : Substitution :: from1 ( interner, f) ,
689
+ }
690
+ . cast ( interner)
691
+ } )
692
+ } )
693
+ . chain ( neg_drop_goal. into_iter ( ) ) ;
694
+ gb. all ( goals)
695
+ } ,
696
+ )
697
+ } ) ;
673
698
674
- Some ( Goal :: all ( interner , goals ) )
699
+ solver . has_unique_solution ( db , & well_formed_goal . into_closed_goal ( interner ) )
675
700
}
676
701
677
- /// Computes goal to prove constraints on a Drop implementation
702
+ /// Verifies constraints on a Drop implementation
678
703
/// Drop implementation is considered well-formed if:
679
704
/// a) it's implemented on an ADT
680
705
/// b) The generic parameters of the impl's type must all be parameters
@@ -709,15 +734,16 @@ impl WfWellKnownGoals {
709
734
/// }
710
735
/// ```
711
736
fn drop_impl_constraint < I : Interner > (
737
+ solver : & mut dyn Solver < I > ,
712
738
db : & dyn RustIrDatabase < I > ,
713
739
impl_datum : & ImplDatum < I > ,
714
- ) -> Option < Goal < I > > {
740
+ ) -> bool {
715
741
let interner = db. interner ( ) ;
716
742
717
743
let adt_id = match impl_datum. self_type_adt_id ( interner) {
718
744
Some ( id) => id,
719
745
// Drop can only be implemented on a nominal type
720
- None => return Some ( GoalData :: CannotProve . intern ( interner ) ) ,
746
+ None => return false ,
721
747
} ;
722
748
723
749
let mut gb = GoalBuilder :: new ( db) ;
@@ -783,6 +809,8 @@ impl WfWellKnownGoals {
783
809
} ,
784
810
) ;
785
811
786
- Some ( gb. all ( [ implied_by_adt_def_goal, eq_goal] . iter ( ) ) )
812
+ let well_formed_goal = gb. all ( [ implied_by_adt_def_goal, eq_goal] . iter ( ) ) ;
813
+
814
+ solver. has_unique_solution ( db, & well_formed_goal. into_closed_goal ( interner) )
787
815
}
788
816
}
0 commit comments