Skip to content

Commit ec62699

Browse files
committed
Fix bug when opaque type was nested in another type.
Previously, types like (Foo, u8) would not be handled correctly (where Foo is an 'existential type')
1 parent 8ba9b10 commit ec62699

File tree

2 files changed

+67
-28
lines changed

2 files changed

+67
-28
lines changed

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

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,51 +1253,58 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
12531253
&anon_ty,
12541254
locations.span(body),
12551255
));
1256-
1257-
let revealed_ty_is_opaque = revealed_ty.is_impl_trait();
1258-
12591256
debug!(
12601257
"eq_opaque_type_and_type: \
12611258
instantiated output_ty={:?} \
12621259
opaque_type_map={:#?} \
1263-
revealed_ty={:?} \
1264-
revealed_ty_is_opaque={}",
1265-
output_ty, opaque_type_map, revealed_ty, revealed_ty_is_opaque
1260+
revealed_ty={:?}",
1261+
output_ty, opaque_type_map, revealed_ty
12661262
);
12671263
obligations.add(infcx
12681264
.at(&ObligationCause::dummy(), param_env)
12691265
.eq(output_ty, revealed_ty)?);
12701266

1271-
// This is 'true' when we're using an existential
1272-
// type without 'revelaing' it. For example, code like this:
1273-
//
1274-
// existential type Foo: Debug;
1275-
// fn foo1() -> Foo { ... }
1276-
// fn foo2() -> Foo { foo1() }
1277-
//
1278-
// In 'foo2', we're not revealing the type of 'Foo' - we're
1279-
// just treating it as the opaque type. All of the constraints
1280-
// in our 'opaque_type_map' apply to the concrete type,
1281-
// not to the opaque type itself. Therefore, it's enough
1282-
// to simply equate the output and opque 'revealed_type',
1283-
// as we do above
1284-
if revealed_ty_is_opaque {
1285-
return Ok(InferOk { value: None, obligations: obligations.into_vec() });
1286-
}
1287-
12881267
for (&opaque_def_id, opaque_decl) in &opaque_type_map {
12891268
let opaque_defn_ty = tcx.type_of(opaque_def_id);
12901269
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
12911270
let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty);
1271+
let concrete_is_opaque = infcx
1272+
.resolve_vars_if_possible(&opaque_decl.concrete_ty).is_impl_trait();
1273+
12921274
debug!(
1293-
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
1275+
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?} \
1276+
concrete_is_opaque={}",
12941277
opaque_decl.concrete_ty,
12951278
infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty),
1296-
opaque_defn_ty
1279+
opaque_defn_ty,
1280+
concrete_is_opaque
12971281
);
1298-
obligations.add(infcx
1299-
.at(&ObligationCause::dummy(), param_env)
1300-
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?);
1282+
1283+
// concrete_is_opaque is 'true' when we're using an existential
1284+
// type without 'revelaing' it. For example, code like this:
1285+
//
1286+
// existential type Foo: Debug;
1287+
// fn foo1() -> Foo { ... }
1288+
// fn foo2() -> Foo { foo1() }
1289+
//
1290+
// In 'foo2', we're not revealing the type of 'Foo' - we're
1291+
// just treating it as the opaque type.
1292+
//
1293+
// When this occurs, we do *not* want to try to equate
1294+
// the concrete type with the underlying defining type
1295+
// of the existential type - this will always fail, since
1296+
// the defining type of an existential type is always
1297+
// some other type (e.g. not itself)
1298+
// Essentially, none of the normal obligations apply here -
1299+
// we're just passing around some unknown opaque type,
1300+
// without actually looking at the underlying type it
1301+
// gets 'revealed' into
1302+
1303+
if !concrete_is_opaque {
1304+
obligations.add(infcx
1305+
.at(&ObligationCause::dummy(), param_env)
1306+
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?);
1307+
}
13011308
}
13021309

13031310
debug!("eq_opaque_type_and_type: equated");
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![feature(existential_type)]
2+
3+
#![allow(dead_code)]
4+
5+
pub trait MyTrait {}
6+
7+
impl MyTrait for bool {}
8+
9+
struct Blah {
10+
my_foo: Foo,
11+
my_u8: u8
12+
}
13+
14+
impl Blah {
15+
fn new() -> Blah {
16+
Blah {
17+
my_foo: make_foo(),
18+
my_u8: 12
19+
}
20+
}
21+
fn into_inner(self) -> (Foo, u8) {
22+
(self.my_foo, self.my_u8)
23+
}
24+
}
25+
26+
fn make_foo() -> Foo {
27+
true
28+
}
29+
30+
existential type Foo: MyTrait;
31+
32+
fn main() {}

0 commit comments

Comments
 (0)