@@ -9,10 +9,15 @@ use crate::errors;
99use rustc_errors:: { codes:: * , struct_span_code_err} ;
1010use rustc_hir:: def_id:: { DefId , LocalDefId } ;
1111use rustc_hir:: LangItem ;
12+ use rustc_infer:: infer:: { RegionVariableOrigin , TyCtxtInferExt } ;
13+ use rustc_infer:: traits:: { Obligation , ObligationCause } ;
1214use 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 } ;
1417use rustc_session:: parse:: feature_err;
1518use rustc_span:: { sym, ErrorGuaranteed } ;
19+ use rustc_trait_selection:: traits:: ObligationCtxt ;
20+ use rustc_type_ir:: elaborate;
1621
1722mod builtin;
1823mod inherent_impls;
@@ -223,5 +228,106 @@ fn check_object_overlap<'tcx>(
223228 }
224229 }
225230 }
231+
232+ even_cooler_object_overlap ( tcx, impl_def_id, trait_ref. def_id ) ;
233+
226234 Ok ( ( ) )
227235}
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