Skip to content

Commit bec079d

Browse files
split compare_predicate_entailment and collect_trait_impl_trait_tys out
1 parent 395e56f commit bec079d

File tree

7 files changed

+137
-33
lines changed

7 files changed

+137
-33
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1772,7 +1772,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17721772

17731773
// In some (most?) cases cause.body_id points to actual body, but in some cases
17741774
// it's an actual definition. According to the comments (e.g. in
1775-
// librustc_typeck/check/compare_method.rs:compare_predicates_and_trait_impl_trait_tys) the latter
1775+
// librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter
17761776
// is relied upon by some other code. This might (or might not) need cleanup.
17771777
let body_owner_def_id =
17781778
self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {

compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ rustc_queries! {
161161
separate_provide_extern
162162
}
163163

164-
query compare_predicates_and_trait_impl_trait_tys(key: DefId)
164+
query collect_trait_impl_trait_tys(key: DefId)
165165
-> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
166166
{
167167
desc { "better description please" }

compiler/rustc_middle/src/ty/util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ impl<'tcx> TyCtxt<'tcx> {
655655
self,
656656
def_id: DefId,
657657
) -> ty::EarlyBinder<Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>> {
658-
ty::EarlyBinder(self.compare_predicates_and_trait_impl_trait_tys(def_id))
658+
ty::EarlyBinder(self.collect_trait_impl_trait_tys(def_id))
659659
}
660660

661661
pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {

compiler/rustc_typeck/src/check/compare_method.rs

+127-18
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
1515
use rustc_middle::ty::subst::{InternalSubsts, Subst};
1616
use rustc_middle::ty::util::ExplicitSelf;
1717
use rustc_middle::ty::{
18-
self, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
18+
self, AssocItem, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
1919
};
2020
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
2121
use rustc_span::Span;
@@ -68,7 +68,10 @@ pub(crate) fn compare_impl_method<'tcx>(
6868
return;
6969
}
7070

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+
}
7275
}
7376

7477
/// This function is best explained by example. Consider a trait:
@@ -137,15 +140,13 @@ pub(crate) fn compare_impl_method<'tcx>(
137140
///
138141
/// Finally we register each of these predicates as an obligation and check that
139142
/// they hold.
140-
pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
143+
fn compare_predicate_entailment<'tcx>(
141144
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> {
149150
let trait_to_impl_substs = impl_trait_ref.substs;
150151

151152
// 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>(
164165
kind: impl_m.kind,
165166
},
166167
);
167-
let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
168168

169169
// Create mapping from impl to placeholder.
170170
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>(
270270

271271
let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
272272
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);
279273

280274
// Next, add all inputs and output as well-formed tys. Importantly,
281275
// 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>(
422416
&outlives_environment,
423417
);
424418

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+
425534
let mut collected_tys = FxHashMap::default();
426535
for (def_id, (ty, substs)) in collector.types {
427536
match infcx.fully_resolve(ty) {
@@ -1307,7 +1416,7 @@ pub(crate) fn compare_ty_impl<'tcx>(
13071416
})();
13081417
}
13091418

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
13111420
/// instead of associated functions.
13121421
fn compare_type_predicate_entailment<'tcx>(
13131422
tcx: TyCtxt<'tcx>,

compiler/rustc_typeck/src/check/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ use crate::require_c_abi_if_c_variadic;
132132
use crate::util::common::indenter;
133133

134134
use self::coercion::DynamicCoerceMany;
135-
use self::compare_method::compare_predicates_and_trait_impl_trait_tys;
135+
use self::compare_method::collect_trait_impl_trait_tys;
136136
use self::region::region_scope_tree;
137137
pub use self::Expectation::*;
138138

@@ -250,7 +250,7 @@ pub fn provide(providers: &mut Providers) {
250250
used_trait_imports,
251251
check_mod_item_types,
252252
region_scope_tree,
253-
compare_predicates_and_trait_impl_trait_tys,
253+
collect_trait_impl_trait_tys,
254254
..*providers
255255
};
256256
}

src/test/ui/impl-trait/in-trait/deep-match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ trait Foo {
99

1010
impl Foo for () {
1111
fn bar() -> i32 { 0 }
12-
//~^ ERROR method `bar` has an incompatible type for trait
12+
//~^ ERROR method `bar` has an incompatible return type for trait
1313
}
1414

1515
fn main() {}

src/test/ui/impl-trait/in-trait/deep-match.stderr

+4-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
1-
error[E0053]: method `bar` has an incompatible type for trait
1+
error[E0053]: method `bar` has an incompatible return type for trait
22
--> $DIR/deep-match.rs:11:17
33
|
44
LL | fn bar() -> i32 { 0 }
55
| ^^^
66
| |
77
| expected struct `Wrapper`, found `i32`
8-
| help: change the output type to match the trait: `Wrapper<_>`
8+
| return type in trait
99
|
10-
note: type in trait
11-
--> $DIR/deep-match.rs:7:17
12-
|
13-
LL | fn bar() -> Wrapper<impl Sized>;
14-
| ^^^^^^^^^^^^^^^^^^^
15-
= note: expected fn pointer `fn() -> Wrapper<_>`
16-
found fn pointer `fn() -> i32`
10+
= note: expected struct `Wrapper<_>`
11+
found type `i32`
1712

1813
error: aborting due to previous error
1914

0 commit comments

Comments
 (0)