@@ -15,7 +15,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
15
15
use rustc_middle::ty::subst::{InternalSubsts, Subst};
16
16
use rustc_middle::ty::util::ExplicitSelf;
17
17
use rustc_middle::ty::{
18
- self, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
18
+ self, AssocItem, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
19
19
};
20
20
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
21
21
use rustc_span::Span;
@@ -68,7 +68,10 @@ pub(crate) fn compare_impl_method<'tcx>(
68
68
return;
69
69
}
70
70
71
- tcx.ensure().compare_predicates_and_trait_impl_trait_tys(impl_m.def_id);
71
+ if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
72
+ {
73
+ return;
74
+ }
72
75
}
73
76
74
77
/// This function is best explained by example. Consider a trait:
@@ -137,15 +140,13 @@ pub(crate) fn compare_impl_method<'tcx>(
137
140
///
138
141
/// Finally we register each of these predicates as an obligation and check that
139
142
/// they hold.
140
- pub(super) fn compare_predicates_and_trait_impl_trait_tys <'tcx>(
143
+ fn compare_predicate_entailment <'tcx>(
141
144
tcx: TyCtxt<'tcx>,
142
- def_id: DefId,
143
- ) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
144
- let impl_m = tcx.opt_associated_item(def_id).unwrap();
145
- let impl_m_span = tcx.def_span(def_id);
146
- let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
147
- let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
148
-
145
+ impl_m: &AssocItem,
146
+ impl_m_span: Span,
147
+ trait_m: &AssocItem,
148
+ impl_trait_ref: ty::TraitRef<'tcx>,
149
+ ) -> Result<(), ErrorGuaranteed> {
149
150
let trait_to_impl_substs = impl_trait_ref.substs;
150
151
151
152
// This node-id should be used for the `body_id` field on each
@@ -164,7 +165,6 @@ pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
164
165
kind: impl_m.kind,
165
166
},
166
167
);
167
- let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
168
168
169
169
// Create mapping from impl to placeholder.
170
170
let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
@@ -270,12 +270,6 @@ pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
270
270
271
271
let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
272
272
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
273
- let mut collector =
274
- ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
275
- // FIXME(RPITIT): This should only be needed on the output type, but
276
- // RPITIT placeholders shouldn't show up anywhere except for there,
277
- // so I think this is fine.
278
- let trait_sig = trait_sig.fold_with(&mut collector);
279
273
280
274
// Next, add all inputs and output as well-formed tys. Importantly,
281
275
// we have to do this before normalization, since the normalized ty may
@@ -436,6 +430,121 @@ pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
436
430
&outlives_environment,
437
431
);
438
432
433
+ Ok(())
434
+ })
435
+ }
436
+
437
+ pub fn collect_trait_impl_trait_tys<'tcx>(
438
+ tcx: TyCtxt<'tcx>,
439
+ def_id: DefId,
440
+ ) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
441
+ let impl_m = tcx.opt_associated_item(def_id).unwrap();
442
+ let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
443
+ let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
444
+ let param_env = tcx.param_env(def_id);
445
+
446
+ let trait_to_impl_substs = impl_trait_ref.substs;
447
+
448
+ let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
449
+ let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
450
+ let cause = ObligationCause::new(
451
+ return_span,
452
+ impl_m_hir_id,
453
+ ObligationCauseCode::CompareImplItemObligation {
454
+ impl_item_def_id: impl_m.def_id.expect_local(),
455
+ trait_item_def_id: trait_m.def_id,
456
+ kind: impl_m.kind,
457
+ },
458
+ );
459
+
460
+ // Create mapping from impl to placeholder.
461
+ let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
462
+
463
+ // Create mapping from trait to placeholder.
464
+ let trait_to_placeholder_substs =
465
+ impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
466
+
467
+ tcx.infer_ctxt().enter(|ref infcx| {
468
+ let ocx = ObligationCtxt::new(infcx);
469
+
470
+ let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
471
+ let impl_return_ty = ocx.normalize(
472
+ norm_cause.clone(),
473
+ param_env,
474
+ infcx
475
+ .replace_bound_vars_with_fresh_vars(
476
+ return_span,
477
+ infer::HigherRankedType,
478
+ tcx.fn_sig(impl_m.def_id),
479
+ )
480
+ .output(),
481
+ );
482
+
483
+ let mut collector =
484
+ ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
485
+ let unnormalized_trait_return_ty = tcx
486
+ .liberate_late_bound_regions(
487
+ impl_m.def_id,
488
+ tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
489
+ )
490
+ .output()
491
+ .fold_with(&mut collector);
492
+ let trait_return_ty =
493
+ ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty);
494
+
495
+ let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]);
496
+
497
+ match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
498
+ Ok(infer::InferOk { value: (), obligations }) => {
499
+ ocx.register_obligations(obligations);
500
+ }
501
+ Err(terr) => {
502
+ let mut diag = struct_span_err!(
503
+ tcx.sess,
504
+ cause.span(),
505
+ E0053,
506
+ "method `{}` has an incompatible return type for trait",
507
+ trait_m.name
508
+ );
509
+ let hir = tcx.hir();
510
+ infcx.note_type_err(
511
+ &mut diag,
512
+ &cause,
513
+ hir.get_if_local(impl_m.def_id)
514
+ .and_then(|node| node.fn_decl())
515
+ .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
516
+ Some(infer::ValuePairs::Terms(ExpectedFound {
517
+ expected: trait_return_ty.into(),
518
+ found: impl_return_ty.into(),
519
+ })),
520
+ terr,
521
+ false,
522
+ false,
523
+ );
524
+ return Err(diag.emit());
525
+ }
526
+ }
527
+
528
+ // Check that all obligations are satisfied by the implementation's
529
+ // RPITs.
530
+ let errors = ocx.select_all_or_error();
531
+ if !errors.is_empty() {
532
+ let reported = infcx.report_fulfillment_errors(&errors, None, false);
533
+ return Err(reported);
534
+ }
535
+
536
+ // Finally, resolve all regions. This catches wily misuses of
537
+ // lifetime parameters.
538
+ let outlives_environment = OutlivesEnvironment::with_bounds(
539
+ param_env,
540
+ Some(infcx),
541
+ infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
542
+ );
543
+ infcx.check_region_obligations_and_report_errors(
544
+ impl_m.def_id.expect_local(),
545
+ &outlives_environment,
546
+ );
547
+
439
548
let mut collected_tys = FxHashMap::default();
440
549
for (def_id, (ty, substs)) in collector.types {
441
550
match infcx.fully_resolve(ty) {
@@ -1322,7 +1431,7 @@ pub(crate) fn compare_ty_impl<'tcx>(
1322
1431
})();
1323
1432
}
1324
1433
1325
- /// The equivalent of [compare_predicates_and_trait_impl_trait_tys ], but for associated types
1434
+ /// The equivalent of [compare_predicate_entailment ], but for associated types
1326
1435
/// instead of associated functions.
1327
1436
fn compare_type_predicate_entailment<'tcx>(
1328
1437
tcx: TyCtxt<'tcx>,
0 commit comments