Skip to content

Commit bcfdfe4

Browse files
committed
use the closure def-id in returns, but closure-base def-id in locals
Using the `closure_base_def_id` indiscriminantely, as we were doing before, winds up "going wrong" if the closure type includes the `impl Trait` from the parent. The problem arises because the return value for closures is inferred and meant to treat the return type *opaquely*, so we don't want to be "desugaring" it into the underlying type.
1 parent c7df1f5 commit bcfdfe4

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

src/librustc_mir/borrow_check/nll/type_check/input_output.rs

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
7070
if let Err(terr) = self.eq_opaque_type_and_type(
7171
mir_output_ty,
7272
normalized_output_ty,
73+
self.mir_def_id,
7374
Locations::All(output_span),
7475
ConstraintCategory::BoringNoLocation,
7576
) {

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
883883
)
884884
}
885885

886+
/// Try to relate `sub <: sup`; if this fails, instantiate opaque
887+
/// variables in `sub` with their inferred definitions and try
888+
/// again. This is used for opaque types in places (e.g., `let x:
889+
/// impl Foo = ..`).
886890
fn sub_types_or_anon(
887891
&mut self,
888892
sub: Ty<'tcx>,
@@ -892,7 +896,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
892896
) -> Fallible<()> {
893897
if let Err(terr) = self.sub_types(sub, sup, locations, category) {
894898
if let TyKind::Opaque(..) = sup.sty {
895-
return self.eq_opaque_type_and_type(sub, sup, locations, category);
899+
// When you have `let x: impl Foo = ...` in a closure,
900+
// the resulting inferend values are stored with the
901+
// def-id of the base function.
902+
let parent_def_id = self.tcx().closure_base_def_id(self.mir_def_id);
903+
return self.eq_opaque_type_and_type(sub, sup, parent_def_id, locations, category);
896904
} else {
897905
return Err(terr);
898906
}
@@ -940,13 +948,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
940948
&mut self,
941949
revealed_ty: Ty<'tcx>,
942950
anon_ty: Ty<'tcx>,
951+
anon_owner_def_id: DefId,
943952
locations: Locations,
944953
category: ConstraintCategory,
945954
) -> Fallible<()> {
955+
debug!(
956+
"eq_opaque_type_and_type( \
957+
revealed_ty={:?}, \
958+
anon_ty={:?})",
959+
revealed_ty, anon_ty
960+
);
946961
let infcx = self.infcx;
947962
let tcx = infcx.tcx;
948963
let param_env = self.param_env;
949-
let parent_def_id = infcx.tcx.closure_base_def_id(self.mir_def_id);
964+
debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id);
950965
let opaque_type_map = self.fully_perform_op(
951966
locations,
952967
category,
@@ -957,7 +972,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
957972
let dummy_body_id = ObligationCause::dummy().body_id;
958973
let (output_ty, opaque_type_map) =
959974
obligations.add(infcx.instantiate_opaque_types(
960-
parent_def_id,
975+
anon_owner_def_id,
961976
dummy_body_id,
962977
param_env,
963978
&anon_ty,
@@ -978,8 +993,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
978993
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
979994
let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty);
980995
debug!(
981-
"eq_opaque_type_and_type: concrete_ty={:?} opaque_defn_ty={:?}",
982-
opaque_decl.concrete_ty, opaque_defn_ty
996+
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
997+
opaque_decl.concrete_ty,
998+
infcx.resolve_type_vars_if_possible(&opaque_decl.concrete_ty),
999+
opaque_defn_ty
9831000
);
9841001
obligations.add(infcx
9851002
.at(&ObligationCause::dummy(), param_env)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(nll)]
2+
3+
// Regression test for #54593: the MIR type checker was going wrong
4+
// when a closure returns the `impl Copy` from its parent fn. It was
5+
// (incorrectly) replacing the `impl Copy` in its return type with the
6+
// hidden type (`()`) but that type resulted from a recursive call to
7+
// `foo` and hence is treated opaquely within the closure body. This
8+
// resulted in a failed subtype relationship.
9+
//
10+
// run-pass
11+
12+
fn foo() -> impl Copy { || foo(); }
13+
fn bar() -> impl Copy { || bar(); }
14+
fn main() { }

0 commit comments

Comments
 (0)