@@ -2,12 +2,12 @@ use anyhow::bail;
22
33use fn_error_context:: context;
44use formality_core:: Downcasted ;
5- use formality_prove:: Env ;
5+ use formality_prove:: { Env , Safety } ;
66use formality_rust:: {
77 grammar:: {
88 AssociatedTy , AssociatedTyBoundData , AssociatedTyValue , AssociatedTyValueBoundData , Fn ,
9- FnBoundData , ImplItem , NegTraitImpl , NegTraitImplBoundData , TraitBoundData , TraitImpl ,
10- TraitImplBoundData , TraitItem ,
9+ FnBoundData , ImplItem , NegTraitImpl , NegTraitImplBoundData , Trait , TraitBoundData ,
10+ TraitImpl , TraitImplBoundData , TraitItem ,
1111 } ,
1212 prove:: ToWcs ,
1313} ;
@@ -17,10 +17,8 @@ use formality_types::{
1717} ;
1818
1919impl super :: Check < ' _ > {
20- #[ context( "check_trait_impl({v:?})" ) ]
21- pub ( super ) fn check_trait_impl ( & self , v : & TraitImpl ) -> Fallible < ( ) > {
22- let TraitImpl { binder } = v;
23-
20+ #[ context( "check_trait_impl({trait_impl:?})" ) ]
21+ pub ( super ) fn check_trait_impl ( & self , trait_impl : & TraitImpl ) -> Fallible < ( ) > {
2422 let mut env = Env :: default ( ) ;
2523
2624 let TraitImplBoundData {
@@ -29,7 +27,7 @@ impl super::Check<'_> {
2927 trait_parameters,
3028 where_clauses,
3129 impl_items,
32- } = env. instantiate_universally ( binder) ;
30+ } = env. instantiate_universally ( & trait_impl . binder ) ;
3331
3432 let trait_ref = trait_id. with ( self_ty, trait_parameters) ;
3533
@@ -45,32 +43,54 @@ impl super::Check<'_> {
4543 trait_items,
4644 } = trait_decl. binder . instantiate_with ( & trait_ref. parameters ) ?;
4745
46+ self . check_safety_matches ( & trait_decl, & trait_impl) ?;
47+
4848 for impl_item in & impl_items {
4949 self . check_trait_impl_item ( & env, & where_clauses, & trait_items, impl_item) ?;
5050 }
5151
5252 Ok ( ( ) )
5353 }
5454
55- pub ( super ) fn check_neg_trait_impl ( & self , i : & NegTraitImpl ) -> Fallible < ( ) > {
55+ #[ context( "check_neg_trait_impl({trait_impl:?})" ) ]
56+ pub ( super ) fn check_neg_trait_impl ( & self , trait_impl : & NegTraitImpl ) -> Fallible < ( ) > {
5657 let mut env = Env :: default ( ) ;
5758
5859 let NegTraitImplBoundData {
5960 trait_id,
6061 self_ty,
6162 trait_parameters,
6263 where_clauses,
63- } = env. instantiate_universally ( & i . binder ) ;
64+ } = env. instantiate_universally ( & trait_impl . binder ) ;
6465
6566 let trait_ref = trait_id. with ( self_ty, trait_parameters) ;
6667
68+ // Negative impls are always safe (rustc E0198) regardless of the trait's safety.
69+ if trait_impl. safety == Safety :: Unsafe {
70+ bail ! ( "negative impls cannot be unsafe" ) ;
71+ }
72+
6773 self . prove_where_clauses_well_formed ( & env, & where_clauses, & where_clauses) ?;
6874
6975 self . prove_goal ( & env, & where_clauses, trait_ref. not_implemented ( ) ) ?;
7076
7177 Ok ( ( ) )
7278 }
7379
80+ /// Validate that the declared safety of an impl matches the one from the trait declaration.
81+ fn check_safety_matches ( & self , trait_decl : & Trait , trait_impl : & TraitImpl ) -> Fallible < ( ) > {
82+ if trait_decl. safety != trait_impl. safety {
83+ match trait_decl. safety {
84+ Safety :: Safe => bail ! ( "implementing the trait `{:?}` is not unsafe" , trait_decl. id) ,
85+ Safety :: Unsafe => bail ! (
86+ "the trait `{:?}` requires an `unsafe impl` declaration" ,
87+ trait_decl. id
88+ ) ,
89+ }
90+ }
91+ Ok ( ( ) )
92+ }
93+
7494 fn check_trait_impl_item (
7595 & self ,
7696 env : & Env ,
0 commit comments