@@ -2,12 +2,12 @@ use anyhow::bail;
2
2
3
3
use fn_error_context:: context;
4
4
use formality_core:: Downcasted ;
5
- use formality_prove:: Env ;
5
+ use formality_prove:: { Env , Safety } ;
6
6
use formality_rust:: {
7
7
grammar:: {
8
8
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 ,
11
11
} ,
12
12
prove:: ToWcs ,
13
13
} ;
@@ -17,10 +17,8 @@ use formality_types::{
17
17
} ;
18
18
19
19
impl 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 < ( ) > {
24
22
let mut env = Env :: default ( ) ;
25
23
26
24
let TraitImplBoundData {
@@ -29,7 +27,7 @@ impl super::Check<'_> {
29
27
trait_parameters,
30
28
where_clauses,
31
29
impl_items,
32
- } = env. instantiate_universally ( binder) ;
30
+ } = env. instantiate_universally ( & trait_impl . binder ) ;
33
31
34
32
let trait_ref = trait_id. with ( self_ty, trait_parameters) ;
35
33
@@ -45,32 +43,54 @@ impl super::Check<'_> {
45
43
trait_items,
46
44
} = trait_decl. binder . instantiate_with ( & trait_ref. parameters ) ?;
47
45
46
+ self . check_safety_matches ( & trait_decl, & trait_impl) ?;
47
+
48
48
for impl_item in & impl_items {
49
49
self . check_trait_impl_item ( & env, & where_clauses, & trait_items, impl_item) ?;
50
50
}
51
51
52
52
Ok ( ( ) )
53
53
}
54
54
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 < ( ) > {
56
57
let mut env = Env :: default ( ) ;
57
58
58
59
let NegTraitImplBoundData {
59
60
trait_id,
60
61
self_ty,
61
62
trait_parameters,
62
63
where_clauses,
63
- } = env. instantiate_universally ( & i . binder ) ;
64
+ } = env. instantiate_universally ( & trait_impl . binder ) ;
64
65
65
66
let trait_ref = trait_id. with ( self_ty, trait_parameters) ;
66
67
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
+
67
73
self . prove_where_clauses_well_formed ( & env, & where_clauses, & where_clauses) ?;
68
74
69
75
self . prove_goal ( & env, & where_clauses, trait_ref. not_implemented ( ) ) ?;
70
76
71
77
Ok ( ( ) )
72
78
}
73
79
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
+
74
94
fn check_trait_impl_item (
75
95
& self ,
76
96
env : & Env ,
0 commit comments