@@ -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
@@ -422,6 +416,121 @@ pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
422
416
&outlives_environment,
423
417
);
424
418
419
+ Ok(())
420
+ })
421
+ }
422
+
423
+ pub fn collect_trait_impl_trait_tys<'tcx>(
424
+ tcx: TyCtxt<'tcx>,
425
+ def_id: DefId,
426
+ ) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
427
+ let impl_m = tcx.opt_associated_item(def_id).unwrap();
428
+ let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
429
+ let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
430
+ let param_env = tcx.param_env(def_id);
431
+
432
+ let trait_to_impl_substs = impl_trait_ref.substs;
433
+
434
+ let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
435
+ let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
436
+ let cause = ObligationCause::new(
437
+ return_span,
438
+ impl_m_hir_id,
439
+ ObligationCauseCode::CompareImplItemObligation {
440
+ impl_item_def_id: impl_m.def_id.expect_local(),
441
+ trait_item_def_id: trait_m.def_id,
442
+ kind: impl_m.kind,
443
+ },
444
+ );
445
+
446
+ // Create mapping from impl to placeholder.
447
+ let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
448
+
449
+ // Create mapping from trait to placeholder.
450
+ let trait_to_placeholder_substs =
451
+ impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
452
+
453
+ tcx.infer_ctxt().enter(|ref infcx| {
454
+ let ocx = ObligationCtxt::new(infcx);
455
+
456
+ let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
457
+ let impl_return_ty = ocx.normalize(
458
+ norm_cause.clone(),
459
+ param_env,
460
+ infcx
461
+ .replace_bound_vars_with_fresh_vars(
462
+ return_span,
463
+ infer::HigherRankedType,
464
+ tcx.fn_sig(impl_m.def_id),
465
+ )
466
+ .output(),
467
+ );
468
+
469
+ let mut collector =
470
+ ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
471
+ let unnormalized_trait_return_ty = tcx
472
+ .liberate_late_bound_regions(
473
+ impl_m.def_id,
474
+ tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
475
+ )
476
+ .output()
477
+ .fold_with(&mut collector);
478
+ let trait_return_ty =
479
+ ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty);
480
+
481
+ let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]);
482
+
483
+ match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
484
+ Ok(infer::InferOk { value: (), obligations }) => {
485
+ ocx.register_obligations(obligations);
486
+ }
487
+ Err(terr) => {
488
+ let mut diag = struct_span_err!(
489
+ tcx.sess,
490
+ cause.span(),
491
+ E0053,
492
+ "method `{}` has an incompatible return type for trait",
493
+ trait_m.name
494
+ );
495
+ let hir = tcx.hir();
496
+ infcx.note_type_err(
497
+ &mut diag,
498
+ &cause,
499
+ hir.get_if_local(impl_m.def_id)
500
+ .and_then(|node| node.fn_decl())
501
+ .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
502
+ Some(infer::ValuePairs::Terms(ExpectedFound {
503
+ expected: trait_return_ty.into(),
504
+ found: impl_return_ty.into(),
505
+ })),
506
+ terr,
507
+ false,
508
+ false,
509
+ );
510
+ return Err(diag.emit());
511
+ }
512
+ }
513
+
514
+ // Check that all obligations are satisfied by the implementation's
515
+ // RPITs.
516
+ let errors = ocx.select_all_or_error();
517
+ if !errors.is_empty() {
518
+ let reported = infcx.report_fulfillment_errors(&errors, None, false);
519
+ return Err(reported);
520
+ }
521
+
522
+ // Finally, resolve all regions. This catches wily misuses of
523
+ // lifetime parameters.
524
+ let outlives_environment = OutlivesEnvironment::with_bounds(
525
+ param_env,
526
+ Some(infcx),
527
+ infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
528
+ );
529
+ infcx.check_region_obligations_and_report_errors(
530
+ impl_m.def_id.expect_local(),
531
+ &outlives_environment,
532
+ );
533
+
425
534
let mut collected_tys = FxHashMap::default();
426
535
for (def_id, (ty, substs)) in collector.types {
427
536
match infcx.fully_resolve(ty) {
@@ -1307,7 +1416,7 @@ pub(crate) fn compare_ty_impl<'tcx>(
1307
1416
})();
1308
1417
}
1309
1418
1310
- /// The equivalent of [compare_predicates_and_trait_impl_trait_tys ], but for associated types
1419
+ /// The equivalent of [compare_predicate_entailment ], but for associated types
1311
1420
/// instead of associated functions.
1312
1421
fn compare_type_predicate_entailment<'tcx>(
1313
1422
tcx: TyCtxt<'tcx>,
0 commit comments