@@ -9,10 +9,15 @@ use crate::errors;
9
9
use rustc_errors:: { codes:: * , struct_span_code_err} ;
10
10
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
11
11
use rustc_hir:: LangItem ;
12
+ use rustc_infer:: infer:: { RegionVariableOrigin , TyCtxtInferExt } ;
13
+ use rustc_infer:: traits:: { Obligation , ObligationCause } ;
12
14
use rustc_middle:: query:: Providers ;
13
- use rustc_middle:: ty:: { self , TyCtxt , TypeVisitableExt } ;
15
+ use rustc_middle:: ty:: ExistentialPredicateStableCmpExt ;
16
+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitableExt } ;
14
17
use rustc_session:: parse:: feature_err;
15
18
use rustc_span:: { sym, ErrorGuaranteed } ;
19
+ use rustc_trait_selection:: traits:: ObligationCtxt ;
20
+ use rustc_type_ir:: elaborate;
16
21
17
22
mod builtin;
18
23
mod inherent_impls;
@@ -223,5 +228,106 @@ fn check_object_overlap<'tcx>(
223
228
}
224
229
}
225
230
}
231
+
232
+ even_cooler_object_overlap ( tcx, impl_def_id, trait_ref. def_id ) ;
233
+
226
234
Ok ( ( ) )
227
235
}
236
+
237
+ fn even_cooler_object_overlap < ' tcx > (
238
+ tcx : TyCtxt < ' tcx > ,
239
+ impl_def_id : LocalDefId ,
240
+ trait_def_id : DefId ,
241
+ ) {
242
+ if !tcx. is_object_safe ( trait_def_id) {
243
+ return ;
244
+ }
245
+
246
+ let infcx = & tcx. infer_ctxt ( ) . with_next_trait_solver ( true ) . intercrate ( true ) . build ( ) ;
247
+
248
+ let def_span = tcx. def_span ( impl_def_id) ;
249
+ let impl_args = infcx. fresh_args_for_item ( def_span, impl_def_id. to_def_id ( ) ) ;
250
+ let trait_ref =
251
+ tcx. impl_trait_ref ( impl_def_id) . expect ( "impl of trait" ) . instantiate ( tcx, impl_args) ;
252
+
253
+ let principal = ty:: Binder :: dummy ( ty:: ExistentialPredicate :: Trait (
254
+ ty:: ExistentialTraitRef :: erase_self_ty ( tcx, trait_ref) ,
255
+ ) ) ;
256
+ let mut assoc_tys = elaborate:: supertraits ( tcx, ty:: Binder :: dummy ( trait_ref) )
257
+ . flat_map ( |trait_ref| {
258
+ tcx. associated_items ( trait_ref. def_id ( ) )
259
+ . in_definition_order ( )
260
+ . filter ( |assoc_item| assoc_item. kind == ty:: AssocKind :: Type )
261
+ . filter ( |assoc_item| !tcx. generics_require_sized_self ( assoc_item. def_id ) )
262
+ . map ( move |assoc_item| {
263
+ trait_ref. map_bound ( |trait_ref| {
264
+ ty:: ExistentialPredicate :: Projection (
265
+ ty:: ExistentialProjection :: erase_self_ty (
266
+ tcx,
267
+ ty:: ProjectionPredicate {
268
+ projection_term : ty:: AliasTerm :: new (
269
+ tcx,
270
+ assoc_item. def_id ,
271
+ trait_ref. args ,
272
+ ) ,
273
+ term : infcx. next_ty_var ( def_span) . into ( ) ,
274
+ } ,
275
+ ) ,
276
+ )
277
+ } )
278
+ } )
279
+ } )
280
+ . collect :: < Vec < _ > > ( ) ;
281
+ assoc_tys. sort_by ( |a, b| a. skip_binder ( ) . stable_cmp ( tcx, & b. skip_binder ( ) ) ) ;
282
+
283
+ let dyn_ty = Ty :: new_dynamic (
284
+ tcx,
285
+ tcx. mk_poly_existential_predicates_from_iter ( [ principal] . into_iter ( ) . chain ( assoc_tys) ) ,
286
+ infcx. next_region_var ( RegionVariableOrigin :: MiscVariable ( def_span) ) ,
287
+ ty:: Dyn ,
288
+ ) ;
289
+
290
+ let ocx = ObligationCtxt :: new_with_diagnostics ( & infcx) ;
291
+ let cause = ObligationCause :: misc ( def_span, impl_def_id) ;
292
+ let Ok ( ( ) ) = ocx. eq ( & cause, ty:: ParamEnv :: empty ( ) , trait_ref. self_ty ( ) , dyn_ty) else {
293
+ return ;
294
+ } ;
295
+
296
+ ocx. register_obligations (
297
+ tcx. predicates_of ( impl_def_id)
298
+ . instantiate ( tcx, impl_args)
299
+ . into_iter ( )
300
+ . map ( |( clause, _) | Obligation :: new ( tcx, cause. clone ( ) , ty:: ParamEnv :: empty ( ) , clause) ) ,
301
+ ) ;
302
+
303
+ let errors_and_ambiguities = ocx. select_all_or_error ( ) ;
304
+ // We only care about the obligations that are *definitely* true errors.
305
+ // Ambiguities do not prove the disjointness of two impls.
306
+ let ( true_errors, _ambiguities) : ( Vec < _ > , Vec < _ > ) =
307
+ errors_and_ambiguities. into_iter ( ) . partition ( |error| error. is_true_error ( ) ) ;
308
+
309
+ if true_errors. is_empty ( ) {
310
+ let associated_type_spans: Vec < _ > = tcx
311
+ . associated_items ( impl_def_id)
312
+ . in_definition_order ( )
313
+ . filter ( |assoc_item| assoc_item. kind == ty:: AssocKind :: Type )
314
+ . map ( |assoc_item| tcx. def_span ( assoc_item. def_id ) )
315
+ . collect ( ) ;
316
+ if !associated_type_spans. is_empty ( ) {
317
+ tcx. dcx ( )
318
+ . struct_span_err (
319
+ def_span,
320
+ format ! (
321
+ "this impl overlaps with built-in trait impl for `{}`" ,
322
+ infcx. resolve_vars_if_possible( dyn_ty)
323
+ ) ,
324
+ )
325
+ . with_span_note (
326
+ associated_type_spans,
327
+ "this impl may be unsound because it could provide different values \
328
+ for these associated types",
329
+ )
330
+ . emit ( ) ;
331
+ }
332
+ }
333
+ }
0 commit comments