Skip to content

Commit 239f1e7

Browse files
committed
Fix regression from lazy opaque types
1 parent 775e480 commit 239f1e7

File tree

7 files changed

+126
-10
lines changed

7 files changed

+126
-10
lines changed

compiler/rustc_typeck/src/check/closure.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -259,22 +259,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
259259
/// The `cause_span` should be the span that caused us to
260260
/// have this expected signature, or `None` if we can't readily
261261
/// know that.
262+
#[instrument(level = "debug", skip(self, cause_span))]
262263
fn deduce_sig_from_projection(
263264
&self,
264265
cause_span: Option<Span>,
265266
projection: ty::PolyProjectionPredicate<'tcx>,
266267
) -> Option<ExpectedSig<'tcx>> {
267268
let tcx = self.tcx;
268269

269-
debug!("deduce_sig_from_projection({:?})", projection);
270-
271270
let trait_def_id = projection.trait_def_id(tcx);
272271

273272
let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
274273
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
275274
let is_gen = gen_trait == trait_def_id;
276275
if !is_fn && !is_gen {
277-
debug!("deduce_sig_from_projection: not fn or generator");
276+
debug!("not fn or generator");
278277
return None;
279278
}
280279

@@ -283,15 +282,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
283282
// associated item and not yield.
284283
let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1];
285284
if return_assoc_item != projection.projection_def_id() {
286-
debug!("deduce_sig_from_projection: not return assoc item of generator");
285+
debug!("not return assoc item of generator");
287286
return None;
288287
}
289288
}
290289

291290
let input_tys = if is_fn {
292291
let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
293292
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
294-
debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
293+
debug!(?arg_param_ty);
295294

296295
match arg_param_ty.kind() {
297296
ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::<Vec<_>>(),
@@ -306,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
306305
// Since this is a return parameter type it is safe to unwrap.
307306
let ret_param_ty = projection.skip_binder().term.ty().unwrap();
308307
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
309-
debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
308+
debug!(?ret_param_ty);
310309

311310
let sig = projection.rebind(self.tcx.mk_fn_sig(
312311
input_tys.iter(),
@@ -315,7 +314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
315314
hir::Unsafety::Normal,
316315
Abi::Rust,
317316
));
318-
debug!("deduce_sig_from_projection: sig={:?}", sig);
317+
debug!(?sig);
319318

320319
Some(ExpectedSig { cause_span, sig })
321320
}

compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
730730
) -> Vec<Ty<'tcx>> {
731731
let formal_ret = self.resolve_vars_with_obligations(formal_ret);
732732
let ret_ty = match expected_ret.only_has_type(self) {
733-
Some(ret) => ret,
733+
Some(ret) => {
734+
// HACK(oli-obk): This is a backwards compatibility hack. Without it, the inference
735+
// variable will get instantiated with the opaque type. The inference variable often
736+
// has various helpful obligations registered for it that help closures figure out their
737+
// signature. If we infer the inference var to the opaque type, the closure won't be able
738+
// to find those obligations anymore, and it can't necessarily find them from the opaque
739+
// type itself. We could be more powerful with inference if we *combined* the obligations
740+
// so that we got both the obligations from the opaque type and the ones from the inference
741+
// variable. That will accept more code than we do right now, so we need to carefully consider
742+
// the implications.
743+
// Note: this check is pessimistic, as the inference type could be matched with something other
744+
// than the opaque type, but then we need a new `TypeRelation` just for this specific case and
745+
// can't re-use `sup` below.
746+
if formal_ret.has_infer_types() {
747+
for ty in ret.walk() {
748+
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() {
749+
if let ty::Opaque(def_id, _) = *ty.kind() {
750+
if self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() {
751+
return Vec::new();
752+
}
753+
}
754+
}
755+
}
756+
}
757+
ret
758+
}
734759
None => return Vec::new(),
735760
};
736761
let expect_args = self
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// This doesn't work, because we don't flow information from opaque types
2+
// into function arguments via the function's generic parameters
3+
// FIXME(oli-obk): make `expected_inputs_for_expected_output` support this
4+
5+
fn reify_as() -> Thunk<impl FnOnce(Continuation) -> Continuation> {
6+
Thunk::new(|mut cont| { //~ ERROR type annotations needed
7+
cont.reify_as();
8+
cont
9+
})
10+
}
11+
12+
#[must_use]
13+
struct Thunk<F>(F);
14+
15+
impl<F> Thunk<F> {
16+
fn new(f: F) -> Self
17+
where
18+
F: ContFn,
19+
{
20+
Thunk(f)
21+
}
22+
}
23+
24+
trait ContFn {}
25+
26+
impl<F: FnOnce(Continuation) -> Continuation> ContFn for F {}
27+
28+
struct Continuation;
29+
30+
impl Continuation {
31+
fn reify_as(&mut self) {}
32+
}
33+
34+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/hidden-type-is-opaque-2.rs:6:17
3+
|
4+
LL | Thunk::new(|mut cont| {
5+
| ^^^^^^^^ consider giving this closure parameter a type
6+
|
7+
= note: type must be known at this point
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0282`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// check-pass
2+
3+
fn reify_as() -> Thunk<impl ContFn> {
4+
Thunk::new(|mut cont| {
5+
cont.reify_as();
6+
cont
7+
})
8+
}
9+
10+
#[must_use]
11+
struct Thunk<F>(F);
12+
13+
impl<F> Thunk<F> {
14+
fn new(f: F) -> Self
15+
where
16+
F: FnOnce(Continuation) -> Continuation,
17+
{
18+
Thunk(f)
19+
}
20+
}
21+
22+
trait ContFn {}
23+
24+
impl<F: FnOnce(Continuation) -> Continuation> ContFn for F {}
25+
26+
struct Continuation;
27+
28+
impl Continuation {
29+
fn reify_as(&mut self) {}
30+
}
31+
32+
fn main() {}

src/test/ui/impl-trait/issues/issue-70877.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ impl Iterator for Bar {
1313
type Item = FooItem;
1414

1515
fn next(&mut self) -> Option<Self::Item> {
16-
Some(Box::new(quux))
16+
Some(Box::new(quux)) //~ ERROR mismatched types
1717
}
1818
}
1919

src/test/ui/impl-trait/issues/issue-70877.stderr

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-70877.rs:16:9
3+
|
4+
LL | type FooRet = impl std::fmt::Debug;
5+
| -------------------- the expected opaque type
6+
...
7+
LL | fn next(&mut self) -> Option<Self::Item> {
8+
| ------------------ expected `Option<Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> FooRet + 'static)>>` because of return type
9+
LL | Some(Box::new(quux))
10+
| ^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found fn item
11+
|
12+
= note: expected enum `Option<Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> FooRet + 'static)>>`
13+
found enum `Option<Box<for<'r> fn(&'r (dyn ToString + 'r)) -> FooRet {quux}>>`
14+
115
error: opaque type's hidden type cannot be another opaque type from the same scope
216
--> $DIR/issue-70877.rs:31:12
317
|
@@ -15,5 +29,6 @@ note: opaque type being used as hidden type
1529
LL | type FooRet = impl std::fmt::Debug;
1630
| ^^^^^^^^^^^^^^^^^^^^
1731

18-
error: aborting due to previous error
32+
error: aborting due to 2 previous errors
1933

34+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)