1
+ //! This module is very similar to `compare_impl_item`.
2
+ //! Most logic is taken from there,
3
+ //! since in a very similar way we're comparing some declaration of a signature to an implementation.
4
+ //! The major difference is that we don't bother with self types, since for EIIs we're comparing freestanding item.
5
+
1
6
use std:: borrow:: Cow ;
2
7
use std:: iter;
3
8
@@ -8,14 +13,15 @@ use rustc_hir::{self as hir, FnSig, HirId, ItemKind};
8
13
use rustc_infer:: infer:: { self , InferCtxt , TyCtxtInferExt } ;
9
14
use rustc_infer:: traits:: { ObligationCause , ObligationCauseCode } ;
10
15
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
11
- use rustc_middle:: ty:: { self , TyCtxt , TypingMode } ;
16
+ use rustc_middle:: ty:: { self , TyCtxt , TypeVisitableExt , TypingMode } ;
12
17
use rustc_span:: { ErrorGuaranteed , Ident , Span , Symbol } ;
13
18
use rustc_trait_selection:: error_reporting:: InferCtxtErrorExt ;
14
19
use rustc_trait_selection:: regions:: InferCtxtRegionExt ;
15
- use rustc_trait_selection:: traits:: ObligationCtxt ;
20
+ use rustc_trait_selection:: traits:: { self , ObligationCtxt } ;
16
21
use tracing:: { debug, instrument} ;
17
22
18
23
use super :: potentially_plural_count;
24
+ use crate :: check:: compare_impl_item:: { CheckRegionBoundsOnItemOutput , check_region_bounds_on_item} ;
19
25
use crate :: errors:: { EiiWithGenerics , LifetimesOrBoundsMismatchOnEii } ;
20
26
21
27
/// checks whether the signature of some `external_impl`, matches
@@ -58,15 +64,15 @@ pub(crate) fn compare_eii_function_types<'tcx>(
58
64
let declaration_sig = infcx. enter_forall_and_leak_universe ( declaration_sig) ;
59
65
let declaration_sig = ocx. normalize ( & norm_cause, param_env, declaration_sig) ;
60
66
61
- let external_impl_sig = infcx. instantiate_binder_with_fresh_vars (
67
+ let unnormalized_external_impl_sig = infcx. instantiate_binder_with_fresh_vars (
62
68
external_impl_span,
63
69
infer:: BoundRegionConversionTime :: HigherRankedType ,
64
70
tcx. fn_sig ( external_impl) . instantiate (
65
71
tcx,
66
72
infcx. fresh_args_for_item ( external_impl_span, external_impl. to_def_id ( ) ) ,
67
73
) ,
68
74
) ;
69
- let external_impl_sig = ocx. normalize ( & norm_cause, param_env, external_impl_sig ) ;
75
+ let external_impl_sig = ocx. normalize ( & norm_cause, param_env, unnormalized_external_impl_sig ) ;
70
76
debug ! ( ?external_impl_sig) ;
71
77
72
78
// FIXME: We'd want to keep more accurate spans than "the method signature" when
@@ -93,6 +99,17 @@ pub(crate) fn compare_eii_function_types<'tcx>(
93
99
return Err ( emitted) ;
94
100
}
95
101
102
+ if !( declaration_sig, external_impl_sig) . references_error ( ) {
103
+ for ty in unnormalized_external_impl_sig. inputs_and_output {
104
+ ocx. register_obligation ( traits:: Obligation :: new (
105
+ infcx. tcx ,
106
+ cause. clone ( ) ,
107
+ param_env,
108
+ ty:: ClauseKind :: WellFormed ( ty. into ( ) ) ,
109
+ ) ) ;
110
+ }
111
+ }
112
+
96
113
// Check that all obligations are satisfied by the implementation's
97
114
// version.
98
115
let errors = ocx. select_all_or_error ( ) ;
@@ -116,6 +133,8 @@ pub(crate) fn compare_eii_function_types<'tcx>(
116
133
/// Checks a bunch of different properties of the impl/trait methods for
117
134
/// compatibility, such as asyncness, number of argument, self receiver kind,
118
135
/// and number of early- and late-bound generics.
136
+ ///
137
+ /// Corresponds to `check_method_is_structurally_compatible` for impl method compatibility checks.
119
138
fn check_is_structurally_compatible < ' tcx > (
120
139
tcx : TyCtxt < ' tcx > ,
121
140
external_impl : LocalDefId ,
@@ -125,7 +144,7 @@ fn check_is_structurally_compatible<'tcx>(
125
144
) -> Result < ( ) , ErrorGuaranteed > {
126
145
check_no_generics ( tcx, external_impl, declaration, eii_name, eii_attr_span) ?;
127
146
compare_number_of_method_arguments ( tcx, external_impl, declaration, eii_name, eii_attr_span) ?;
128
- check_region_bounds_on_impl_item ( tcx, external_impl, declaration, eii_attr_span) ?;
147
+ check_region_bounds_on_eii ( tcx, external_impl, declaration, eii_attr_span) ?;
129
148
Ok ( ( ) )
130
149
}
131
150
@@ -148,6 +167,44 @@ fn check_no_generics<'tcx>(
148
167
Ok ( ( ) )
149
168
}
150
169
170
+ fn check_region_bounds_on_eii < ' tcx > (
171
+ tcx : TyCtxt < ' tcx > ,
172
+ external_impl : LocalDefId ,
173
+ declaration : DefId ,
174
+ eii_attr_span : Span ,
175
+ ) -> Result < ( ) , ErrorGuaranteed > {
176
+ let external_impl_generics = tcx. generics_of ( external_impl. to_def_id ( ) ) ;
177
+ let external_impl_params = external_impl_generics. own_counts ( ) . lifetimes ;
178
+
179
+ let declaration_generics = tcx. generics_of ( declaration) ;
180
+ let declaration_params = declaration_generics. own_counts ( ) . lifetimes ;
181
+
182
+ let Some ( CheckRegionBoundsOnItemOutput { span, generics_span, bounds_span, where_span } ) =
183
+ check_region_bounds_on_item (
184
+ tcx,
185
+ external_impl,
186
+ declaration,
187
+ external_impl_generics,
188
+ external_impl_params,
189
+ declaration_generics,
190
+ declaration_params,
191
+ )
192
+ else {
193
+ return Ok ( ( ) ) ;
194
+ } ;
195
+
196
+ let mut diag = tcx. dcx ( ) . create_err ( LifetimesOrBoundsMismatchOnEii {
197
+ span,
198
+ ident : tcx. item_name ( external_impl. to_def_id ( ) ) ,
199
+ generics_span,
200
+ bounds_span,
201
+ where_span,
202
+ } ) ;
203
+
204
+ diag. span_label ( eii_attr_span, format ! ( "required because of this attribute" ) ) ;
205
+ return Err ( diag. emit ( ) ) ;
206
+ }
207
+
151
208
fn compare_number_of_method_arguments < ' tcx > (
152
209
tcx : TyCtxt < ' tcx > ,
153
210
external_impl : LocalDefId ,
@@ -159,152 +216,71 @@ fn compare_number_of_method_arguments<'tcx>(
159
216
let declaration_fty = tcx. fn_sig ( declaration) ;
160
217
let declaration_number_args = declaration_fty. skip_binder ( ) . inputs ( ) . skip_binder ( ) . len ( ) ;
161
218
let external_impl_number_args = external_impl_fty. skip_binder ( ) . inputs ( ) . skip_binder ( ) . len ( ) ;
219
+
220
+ // if the number of args are equal, we're trivially done
221
+ if declaration_number_args == external_impl_number_args {
222
+ return Ok ( ( ) ) ;
223
+ }
224
+
162
225
let external_impl_name = tcx. item_name ( external_impl. to_def_id ( ) ) ;
163
226
164
- if declaration_number_args != external_impl_number_args {
165
- let declaration_span = declaration
166
- . as_local ( )
167
- . and_then ( |def_id| {
168
- let declaration_sig = get_declaration_sig ( tcx, def_id) . expect ( "foreign item sig" ) ;
169
- let pos = declaration_number_args. saturating_sub ( 1 ) ;
170
- declaration_sig. decl . inputs . get ( pos) . map ( |arg| {
171
- if pos == 0 {
172
- arg. span
173
- } else {
174
- arg. span . with_lo ( declaration_sig. decl . inputs [ 0 ] . span . lo ( ) )
175
- }
176
- } )
177
- } )
178
- . or_else ( || tcx. hir_span_if_local ( declaration) )
179
- . unwrap_or_else ( || tcx. def_span ( declaration) ) ;
180
-
181
- let ( _, external_impl_sig, _, _) = & tcx. hir_expect_item ( external_impl) . expect_fn ( ) ;
182
- let pos = external_impl_number_args. saturating_sub ( 1 ) ;
183
- let impl_span = external_impl_sig
184
- . decl
185
- . inputs
186
- . get ( pos)
187
- . map ( |arg| {
227
+ let declaration_span = declaration
228
+ . as_local ( )
229
+ . and_then ( |def_id| {
230
+ let declaration_sig = get_declaration_sig ( tcx, def_id) . expect ( "foreign item sig" ) ;
231
+ let pos = declaration_number_args. saturating_sub ( 1 ) ;
232
+ declaration_sig. decl . inputs . get ( pos) . map ( |arg| {
188
233
if pos == 0 {
189
234
arg. span
190
235
} else {
191
- arg. span . with_lo ( external_impl_sig . decl . inputs [ 0 ] . span . lo ( ) )
236
+ arg. span . with_lo ( declaration_sig . decl . inputs [ 0 ] . span . lo ( ) )
192
237
}
193
238
} )
194
- . unwrap_or_else ( || tcx. def_span ( external_impl) ) ;
195
-
196
- let mut err = struct_span_code_err ! (
197
- tcx. dcx( ) ,
198
- impl_span,
199
- E0805 ,
200
- "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}" ,
201
- potentially_plural_count( external_impl_number_args, "parameter" ) ,
202
- declaration_number_args
203
- ) ;
204
-
205
- // if let Some(declaration_span) = declaration_span {
206
- err. span_label (
207
- declaration_span,
208
- format ! ( "requires {}" , potentially_plural_count( declaration_number_args, "parameter" ) ) ,
209
- ) ;
210
- // }
211
-
212
- err. span_label (
213
- impl_span,
214
- format ! (
215
- "expected {}, found {}" ,
216
- potentially_plural_count( declaration_number_args, "parameter" ) ,
217
- external_impl_number_args
218
- ) ,
219
- ) ;
220
-
221
- err. span_label ( eii_attr_span, format ! ( "required because of this attribute" ) ) ;
222
-
223
- return Err ( err. emit ( ) ) ;
224
- }
225
-
226
- Ok ( ( ) )
227
- }
239
+ } )
240
+ . or_else ( || tcx. hir_span_if_local ( declaration) )
241
+ . unwrap_or_else ( || tcx. def_span ( declaration) ) ;
242
+
243
+ let ( _, external_impl_sig, _, _) = & tcx. hir_expect_item ( external_impl) . expect_fn ( ) ;
244
+ let pos = external_impl_number_args. saturating_sub ( 1 ) ;
245
+ let impl_span = external_impl_sig
246
+ . decl
247
+ . inputs
248
+ . get ( pos)
249
+ . map ( |arg| {
250
+ if pos == 0 {
251
+ arg. span
252
+ } else {
253
+ arg. span . with_lo ( external_impl_sig. decl . inputs [ 0 ] . span . lo ( ) )
254
+ }
255
+ } )
256
+ . unwrap_or_else ( || tcx. def_span ( external_impl) ) ;
228
257
229
- fn check_region_bounds_on_impl_item < ' tcx > (
230
- tcx : TyCtxt < ' tcx > ,
231
- external_impl : LocalDefId ,
232
- declaration : DefId ,
233
- eii_attr_span : Span ,
234
- ) -> Result < ( ) , ErrorGuaranteed > {
235
- let external_impl_generics = tcx . generics_of ( external_impl . to_def_id ( ) ) ;
236
- let external_impl_params = external_impl_generics . own_counts ( ) . lifetimes ;
258
+ let mut err = struct_span_code_err ! (
259
+ tcx. dcx ( ) ,
260
+ impl_span ,
261
+ E0805 ,
262
+ "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}" ,
263
+ potentially_plural_count ( external_impl_number_args , "parameter" ) ,
264
+ declaration_number_args
265
+ ) ;
237
266
238
- let declaration_generics = tcx. generics_of ( declaration) ;
239
- let declaration_params = declaration_generics. own_counts ( ) . lifetimes ;
267
+ err. span_label (
268
+ declaration_span,
269
+ format ! ( "requires {}" , potentially_plural_count( declaration_number_args, "parameter" ) ) ,
270
+ ) ;
240
271
241
- debug ! ( ?declaration_generics, ?external_impl_generics) ;
242
-
243
- // Must have same number of early-bound lifetime parameters.
244
- // Unfortunately, if the user screws up the bounds, then this
245
- // will change classification between early and late. E.g.,
246
- // if in trait we have `<'a,'b:'a>`, and in impl we just have
247
- // `<'a,'b>`, then we have 2 early-bound lifetime parameters
248
- // in trait but 0 in the impl. But if we report "expected 2
249
- // but found 0" it's confusing, because it looks like there
250
- // are zero. Since I don't quite know how to phrase things at
251
- // the moment, give a kind of vague error message.
252
- if declaration_params != external_impl_params {
253
- let span = tcx
254
- . hir_get_generics ( external_impl)
255
- . expect ( "expected impl item to have generics or else we can't compare them" )
256
- . span ;
257
-
258
- let mut generics_span = None ;
259
- let mut bounds_span = vec ! [ ] ;
260
- let mut where_span = None ;
261
-
262
- if let Some ( declaration_node) = tcx. hir_get_if_local ( declaration)
263
- && let Some ( declaration_generics) = declaration_node. generics ( )
264
- {
265
- generics_span = Some ( declaration_generics. span ) ;
266
- // FIXME: we could potentially look at the impl's bounds to not point at bounds that
267
- // *are* present in the impl.
268
- for p in declaration_generics. predicates {
269
- if let hir:: WherePredicateKind :: BoundPredicate ( pred) = p. kind {
270
- for b in pred. bounds {
271
- if let hir:: GenericBound :: Outlives ( lt) = b {
272
- bounds_span. push ( lt. ident . span ) ;
273
- }
274
- }
275
- }
276
- }
277
- if let Some ( implementation_generics) = tcx. hir_get_generics ( external_impl) {
278
- let mut impl_bounds = 0 ;
279
- for p in implementation_generics. predicates {
280
- if let hir:: WherePredicateKind :: BoundPredicate ( pred) = p. kind {
281
- for b in pred. bounds {
282
- if let hir:: GenericBound :: Outlives ( _) = b {
283
- impl_bounds += 1 ;
284
- }
285
- }
286
- }
287
- }
288
- if impl_bounds == bounds_span. len ( ) {
289
- bounds_span = vec ! [ ] ;
290
- } else if implementation_generics. has_where_clause_predicates {
291
- where_span = Some ( implementation_generics. where_clause_span ) ;
292
- }
293
- }
294
- }
295
- let mut diag = tcx. dcx ( ) . create_err ( LifetimesOrBoundsMismatchOnEii {
296
- span,
297
- ident : tcx. item_name ( external_impl. to_def_id ( ) ) ,
298
- generics_span,
299
- bounds_span,
300
- where_span,
301
- } ) ;
272
+ err. span_label (
273
+ impl_span,
274
+ format ! (
275
+ "expected {}, found {}" ,
276
+ potentially_plural_count( declaration_number_args, "parameter" ) ,
277
+ external_impl_number_args
278
+ ) ,
279
+ ) ;
302
280
303
- diag. span_label ( eii_attr_span, format ! ( "required because of this attribute" ) ) ;
304
- return Err ( diag. emit ( ) ) ;
305
- }
281
+ err. span_label ( eii_attr_span, format ! ( "required because of this attribute" ) ) ;
306
282
307
- Ok ( ( ) )
283
+ Err ( err . emit ( ) )
308
284
}
309
285
310
286
fn report_eii_mismatch < ' tcx > (
0 commit comments