New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler panic on type inference for impl Generator yielding a reference #52304

Open
bergus opened this Issue Jul 12, 2018 · 11 comments

Comments

Projects
None yet
6 participants
@bergus
Copy link

bergus commented Jul 12, 2018

I'm getting

error: internal compiler error: librustc/infer/error_reporting/mod.rs:184: ReEmpty
thread 'main' panicked at 'Box', librustc_errors/lib.rs:554:9

when trying to compile

#![feature(generators, generator_trait)]
use std::ops::Generator;
fn example() -> impl Generator {
    || { yield &1 }
}

on rustc 1.29.0-nightly (e5f6498 2018-07-10) - Playground demo.

This seems to happen when I yield a reference type and don't specify the exact type in impl Generator<Yield=&Whatever>.

@Zoxc

This comment has been minimized.

Copy link
Contributor

Zoxc commented Aug 1, 2018

We don't generate an error message for the ReEmpty region here and panic instead. Here is the message that should be printed with a placeholder:

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
 --> test-region.rs:3:17
  |
3 | fn example() -> impl Generator {
  |                 ^^^^^^^^^^^^^^
  |
  = note: hidden type `[generator@test-region.rs:4:5: 4:20 for<'r> {i32, &'r i32, ()}]` captures BUG[ReEmpty]

Should ReEmpty be allowed for impl Trait? cc @rust-lang/compiler

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Aug 4, 2018

Why are we capturing ReEmpty here?

@Zoxc

This comment has been minimized.

Copy link
Contributor

Zoxc commented Aug 6, 2018

There isn't any ReEmpty in the type. There's some scary code which replaces regions with ReEmpty which is closure related. I'm not sure what is going on there, but perhaps generators should be treated the same? cc @nikomatsakis

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Aug 18, 2018

@Zoxc Oh, all of that code is for exporting impl Trait concrete types from inference results, which needs to "connect up" lifetimes inside the inferred concrete type with lifetime parameters.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Aug 19, 2018

I think the problem is that the yield_ty of the generator ends up being &'ReEmpty u32, because nothing is constraining it to be anything else. I wonder why this isn't occurring with closures.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Aug 19, 2018

This doesn't occur with closures because regionck forces the return type of the closure to outlive the closure's call scope, which prevents ReEmpty from being inferred.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Aug 19, 2018

I think that the correct way to fix it would be to require all "implicit" projections in impl Trait types to be well-formed. that goes in the wrong direction.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Aug 19, 2018

The requirement we want is that that "implicit" impl Generator for [generator type] makes sense.

That requires that the projections in that impl are alive as long as [generator type] is alive (we don't consider that as a "well-formed" requirement, but the "projection outlives" rules assume that). That does not hold if regions in the projections can be inferred to ReEmpty - we need to be checking that.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Aug 19, 2018

I think that in closures, CallSite (from the fix to #29793) is serving that rule with lexical lifetimes - not sure what is checking that with NLL.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Aug 19, 2018

This can, in fact, be used as a soundness hole (assuming you can call resume):

#![feature(generators, generator_trait)]
use std::fmt::Debug;

use std::ops::Generator;
fn gen_taker<G: Generator>(mut g: G)
    where G::Yield: Debug, G::Return: Debug
{
    let a = unsafe { g.resume() };
    drop(g);
    println!("{:?}", a);
}
fn main() {
    gen_taker(|| {
        let x = 1;
        yield &x
    });
}
@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Aug 19, 2018

Note: the version above is fixed by NLL. need to check whether fix is tight.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment