@@ -37,10 +37,13 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
37
37
a trait or new type instead") ;
38
38
}
39
39
}
40
- }
41
40
42
- impl < ' cx , ' tcx , ' v > visit:: Visitor < ' v > for OrphanChecker < ' cx , ' tcx > {
43
- fn visit_item ( & mut self , item : & ast:: Item ) {
41
+ /// Checks exactly one impl for orphan rules and other such
42
+ /// restrictions. In this fn, it can happen that multiple errors
43
+ /// apply to a specific impl, so just return after reporting one
44
+ /// to prevent inundating the user with a bunch of similar error
45
+ /// reports.
46
+ fn check_item ( & self , item : & ast:: Item ) {
44
47
let def_id = ast_util:: local_def ( item. id ) ;
45
48
match item. node {
46
49
ast:: ItemImpl ( _, _, _, None , _, _) => {
@@ -63,13 +66,15 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
63
66
span_err ! ( self . tcx. sess, item. span, E0118 ,
64
67
"no base type found for inherent implementation; \
65
68
implement a trait or new type instead") ;
69
+ return ;
66
70
}
67
71
}
68
72
}
69
73
ast:: ItemImpl ( _, _, _, Some ( _) , _, _) => {
70
74
// "Trait" impl
71
75
debug ! ( "coherence2::orphan check: trait impl {}" , item. repr( self . tcx) ) ;
72
- let trait_def_id = ty:: impl_trait_ref ( self . tcx , def_id) . unwrap ( ) . def_id ;
76
+ let trait_ref = ty:: impl_trait_ref ( self . tcx , def_id) . unwrap ( ) ;
77
+ let trait_def_id = trait_ref. def_id ;
73
78
match traits:: orphan_check ( self . tcx , def_id) {
74
79
Ok ( ( ) ) => { }
75
80
Err ( traits:: OrphanCheckErr :: NoLocalInputType ) => {
@@ -80,6 +85,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
80
85
types defined in this crate; \
81
86
only traits defined in the current crate can be \
82
87
implemented for arbitrary types") ;
88
+ return ;
83
89
}
84
90
}
85
91
Err ( traits:: OrphanCheckErr :: UncoveredTy ( param_ty) ) => {
@@ -89,9 +95,100 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
89
95
some local type (e.g. `MyStruct<T>`); only traits defined in \
90
96
the current crate can be implemented for a type parameter",
91
97
param_ty. user_string( self . tcx) ) ;
98
+ return ;
92
99
}
93
100
}
94
101
}
102
+
103
+ // In addition to the above rules, we restrict impls of defaulted traits
104
+ // so that they can only be implemented on structs/enums. To see why this
105
+ // restriction exists, consider the following example (#22978). Imagine
106
+ // that crate A defines a defaulted trait `Foo` and a fn that operates
107
+ // on pairs of types:
108
+ //
109
+ // ```
110
+ // // Crate A
111
+ // trait Foo { }
112
+ // impl Foo for .. { }
113
+ // fn two_foos<A:Foo,B:Foo>(..) {
114
+ // one_foo::<(A,B)>(..)
115
+ // }
116
+ // fn one_foo<T:Foo>(..) { .. }
117
+ // ```
118
+ //
119
+ // This type-checks fine; in particular the fn
120
+ // `two_foos` is able to conclude that `(A,B):Foo`
121
+ // because `A:Foo` and `B:Foo`.
122
+ //
123
+ // Now imagine that crate B comes along and does the following:
124
+ //
125
+ // ```
126
+ // struct A { }
127
+ // struct B { }
128
+ // impl Foo for A { }
129
+ // impl Foo for B { }
130
+ // impl !Send for (A, B) { }
131
+ // ```
132
+ //
133
+ // This final impl is legal according to the orpan
134
+ // rules, but it invalidates the reasoning from
135
+ // `two_foos` above.
136
+ debug ! ( "trait_ref={} trait_def_id={} trait_has_default_impl={}" ,
137
+ trait_ref. repr( self . tcx) ,
138
+ trait_def_id. repr( self . tcx) ,
139
+ ty:: trait_has_default_impl( self . tcx, trait_def_id) ) ;
140
+ if
141
+ ty:: trait_has_default_impl ( self . tcx , trait_def_id) &&
142
+ trait_def_id. krate != ast:: LOCAL_CRATE
143
+ {
144
+ let self_ty = trait_ref. self_ty ( ) ;
145
+ let opt_self_def_id = match self_ty. sty {
146
+ ty:: ty_struct( self_def_id, _) | ty:: ty_enum( self_def_id, _) =>
147
+ Some ( self_def_id) ,
148
+ ty:: ty_uniq( ..) =>
149
+ self . tcx . lang_items . owned_box ( ) ,
150
+ _ =>
151
+ None
152
+ } ;
153
+
154
+ let msg = match opt_self_def_id {
155
+ // We only want to permit structs/enums, but not *all* structs/enums.
156
+ // They must be local to the current crate, so that people
157
+ // can't do `unsafe impl Send for Rc<SomethingLocal>` or
158
+ // `impl !Send for Box<SomethingLocalAndSend>`.
159
+ Some ( self_def_id) => {
160
+ if self_def_id. krate == ast:: LOCAL_CRATE {
161
+ None
162
+ } else {
163
+ Some ( format ! (
164
+ "cross-crate traits with a default impl, like `{}`, \
165
+ can only be implemented for a struct/enum type \
166
+ defined in the current crate",
167
+ ty:: item_path_str( self . tcx, trait_def_id) ) )
168
+ }
169
+ }
170
+ _ => {
171
+ Some ( format ! (
172
+ "cross-crate traits with a default impl, like `{}`, \
173
+ can only be implemented for a struct/enum type, \
174
+ not `{}`",
175
+ ty:: item_path_str( self . tcx, trait_def_id) ,
176
+ self_ty. user_string( self . tcx) ) )
177
+ }
178
+ } ;
179
+
180
+ if let Some ( msg) = msg {
181
+ span_err ! ( self . tcx. sess, item. span, E0321 , "{}" , msg) ;
182
+ return ;
183
+ }
184
+ }
185
+
186
+ // Disallow *all* explicit impls of `Sized` for now.
187
+ if Some ( trait_def_id) == self . tcx . lang_items . sized_trait ( ) {
188
+ span_err ! ( self . tcx. sess, item. span, E0322 ,
189
+ "explicit impls for the `Sized` trait are not permitted" ) ;
190
+ return ;
191
+ }
95
192
}
96
193
ast:: ItemDefaultImpl ( ..) => {
97
194
// "Trait" impl
@@ -100,14 +197,20 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
100
197
if trait_ref. def_id . krate != ast:: LOCAL_CRATE {
101
198
span_err ! ( self . tcx. sess, item. span, E0318 ,
102
199
"cannot create default implementations for traits outside the \
103
- crate they're defined in; define a new trait instead.") ;
200
+ crate they're defined in; define a new trait instead") ;
201
+ return ;
104
202
}
105
203
}
106
204
_ => {
107
205
// Not an impl
108
206
}
109
207
}
208
+ }
209
+ }
110
210
211
+ impl < ' cx , ' tcx , ' v > visit:: Visitor < ' v > for OrphanChecker < ' cx , ' tcx > {
212
+ fn visit_item ( & mut self , item : & ast:: Item ) {
213
+ self . check_item ( item) ;
111
214
visit:: walk_item ( self , item) ;
112
215
}
113
216
}
0 commit comments