Stream: wg-async-foundations

Topic: mismatched types diag #54326


davidtwco (May 07 2019 at 08:28, on Zulip):

@eddyb continuing our conversation from yesterday on Discord, after #60592, you mentioned needing to fix this case:

trait Foo {
    type Out;
}
struct FooFromFn<F>(F);
impl<F: Fn() -> R, R> Foo for FooFromFn<F> {
    type Out = R;
}
fn foo() -> impl Foo<Out = i32> {
  FooFromFn(|| true)
}

Would you be able to elaborate a little on where you think the problem is so that I can start working on a fix later today?

eddyb (May 07 2019 at 14:10, on Zulip):

so the problem is you have these facts:

there is no $1: Fn() -> i32 bound, only $0: Foo<Out = i32> and effectively FooFromFn<$1> coerces to $0 which isn't stored down anywhere today (but we probably could?)

eddyb (May 07 2019 at 14:12, on Zulip):

also, the $1: Fn() -> i32 bound would potentially be wrong to have as a known fact, unless we short-circuit the coercion and unify $0 with FooFromFn<$1>, so that we can elaborate the predicates and get $1: Fn() -> i32 "for free"

eddyb (May 07 2019 at 14:12, on Zulip):

let me rephrase, ugh

eddyb (May 07 2019 at 14:17, on Zulip):

@davidtwco however, that short-circuit is dangerous, because...

eddyb (May 07 2019 at 14:18, on Zulip):
FooFromFn({
    return (expr: SomeOtherType);
    || true
})
eddyb (May 07 2019 at 14:20, on Zulip):

that will cause $0 to be unified with SomeOtherType before FooFromFn<$1> is attempted to be coerced to SomeOtherType

eddyb (May 07 2019 at 14:21, on Zulip):

so we could only do this in the very special case of "there is only one truth source for this inference variable, and it's the type of this expression"

eddyb (May 07 2019 at 14:21, on Zulip):

in which case, it can be unified early with the "expected type skeleton" or w/e

eddyb (May 07 2019 at 14:22, on Zulip):

this is all very disturbing tbh, I'd get a hold of @nikomatsakis first

davidtwco (May 14 2019 at 07:15, on Zulip):

cc @nikomatsakis do you have any thoughts on the above?

davidtwco (May 28 2019 at 17:59, on Zulip):

(apologies for yet another ping, but in case this got missed in what I assume is a sea of notifications, @nikomatsakis)

nikomatsakis (May 28 2019 at 18:01, on Zulip):

@davidtwco =) you're not wrong

nikomatsakis (Jun 13 2019 at 17:53, on Zulip):

ok so to jump back to this for a few minutes

nikomatsakis (Jun 13 2019 at 17:54, on Zulip):

I'm trying to catch up with eddyb here

nikomatsakis (Jun 13 2019 at 17:55, on Zulip):

it's definitely true that we'd prefer not to solve this in the desugaring

nikomatsakis (Jun 13 2019 at 17:56, on Zulip):

how much do you get the context here, @davidtwco ?

davidtwco (Jun 13 2019 at 17:56, on Zulip):

Very little, unfortunately.

nikomatsakis (Jun 13 2019 at 17:58, on Zulip):

you know about the idea of an expected type?

davidtwco (Jun 13 2019 at 17:58, on Zulip):

A little bit.

nikomatsakis (Jun 13 2019 at 17:59, on Zulip):

ok so if you have let x: u32 = ...

nikomatsakis (Jun 13 2019 at 17:59, on Zulip):

then when we are typing the ... we know it's supposed to produce a u32

nikomatsakis (Jun 13 2019 at 17:59, on Zulip):

we sometimes go to some lengths here

davidtwco (Jun 13 2019 at 17:59, on Zulip):

And the same is true with function return types from signatures, for example?

davidtwco (Jun 13 2019 at 18:00, on Zulip):

(that it would be used as a expected type)

nikomatsakis (Jun 13 2019 at 18:00, on Zulip):

so...

nikomatsakis (Jun 13 2019 at 18:00, on Zulip):
#![feature(async_await, futures_api)]

async fn foo() -> i32 {
    if false {
        return Ok(6);
    }

    5
}
nikomatsakis (Jun 13 2019 at 18:00, on Zulip):

can we desugar this a bit?

nikomatsakis (Jun 13 2019 at 18:00, on Zulip):

how bad is the desugared version? :)

nikomatsakis (Jun 13 2019 at 18:00, on Zulip):

but yeah the problem here is that, somehow,

nikomatsakis (Jun 13 2019 at 18:00, on Zulip):

the return type of the future

nikomatsakis (Jun 13 2019 at 18:00, on Zulip):

is being left to be inferred

nikomatsakis (Jun 13 2019 at 18:00, on Zulip):

and only later (too late) unified with i32

nikomatsakis (Jun 13 2019 at 18:00, on Zulip):

this is why the diagnostics are confusing

nikomatsakis (Jun 13 2019 at 18:01, on Zulip):

we have some similar logic, e.g., for clsoures if you do:

nikomatsakis (Jun 13 2019 at 18:01, on Zulip):
foo(|| Ok(i32))
nikomatsakis (Jun 13 2019 at 18:01, on Zulip):

you could imagine us saying "the closure returns a type ?T"

nikomatsakis (Jun 13 2019 at 18:01, on Zulip):

and checking the body

nikomatsakis (Jun 13 2019 at 18:01, on Zulip):

and then comparing the ?T against the type in the signature of foo

nikomatsakis (Jun 13 2019 at 18:01, on Zulip):

and you would get a similar error

nikomatsakis (Jun 13 2019 at 18:01, on Zulip):

but what we actually do is to look at the signature of foo and try to see if we can figure out what the closure is supposed to return

nikomatsakis (Jun 13 2019 at 18:02, on Zulip):

so we can "bias" the error that way

nikomatsakis (Jun 13 2019 at 18:02, on Zulip):

(this also helps with coercions)

nikomatsakis (Jun 13 2019 at 18:02, on Zulip):

this is a bit subtle for closures because, if you look at foo, it often looks like

nikomatsakis (Jun 13 2019 at 18:02, on Zulip):
fn foo<T: Fn() -> i32>(t: T) { }
nikomatsakis (Jun 13 2019 at 18:02, on Zulip):

so when we type-check foo(|| Ok(22))

nikomatsakis (Jun 13 2019 at 18:02, on Zulip):

what happens is that we replace T (here, the closure type) with a fresh variable, let's call it ?C

nikomatsakis (Jun 13 2019 at 18:03, on Zulip):

and then we have this "trait obligation" ?C: Fn() -> i32

nikomatsakis (Jun 13 2019 at 18:03, on Zulip):

which can't be proven yet because we don't know what ?C is

nikomatsakis (Jun 13 2019 at 18:03, on Zulip):

to infer the closure return type, therefore, the code that @eddyb pointed us out goes and looks through the list of pending things we have to prove in the future

nikomatsakis (Jun 13 2019 at 18:03, on Zulip):

and looks for something like that

nikomatsakis (Jun 13 2019 at 18:03, on Zulip):

to extract the return type

nikomatsakis (Jun 13 2019 at 18:03, on Zulip):

the scenario here is going to be similar-ish

nikomatsakis (Jun 13 2019 at 18:04, on Zulip):

the async { .. .} at the heart of the desugaring, afer all, is generating a future type ?F

nikomatsakis (Jun 13 2019 at 18:04, on Zulip):

which must implement ?F: Future<Output = i32>

nikomatsakis (Jun 13 2019 at 18:04, on Zulip):

so to figure out the expected type we have to match that expectation

nikomatsakis (Jun 13 2019 at 18:04, on Zulip):

from @eddyb's comments above, it sounds like that might be a bit tricky though

nikomatsakis (Jun 13 2019 at 18:04, on Zulip):

but I think we gotta run to meta mtg :)

davidtwco (Jun 13 2019 at 18:04, on Zulip):

Ah yeah, it's just us today, I think.

davidtwco (Jun 13 2019 at 18:05, on Zulip):

(out of Santiago, you and I at least)

nikomatsakis (Jun 13 2019 at 18:05, on Zulip):

oh right

nikomatsakis (Jun 13 2019 at 18:05, on Zulip):

well let's just do a quick scan at least ;)

nikomatsakis (Jun 13 2019 at 18:15, on Zulip):

ok @davidtwco so... I wanted to get a more accurate desugaring here

nikomatsakis (Jun 13 2019 at 18:15, on Zulip):

because the details matter

nikomatsakis (Jun 13 2019 at 18:17, on Zulip):

is there an easy way to do that?

nikomatsakis (Jun 13 2019 at 18:17, on Zulip):

I guess that

#![feature(async_await, futures_api)]

use std::future::Future;

fn foo() -> impl Future<Output = i32> {
    async {
        if false {
            return Ok(6);
        }

        5
    }
}

fn main() { }
nikomatsakis (Jun 13 2019 at 18:17, on Zulip):

produces the same error, so that's something

davidtwco (Jun 13 2019 at 18:17, on Zulip):

I can dump the HIR locally if that would help.

nikomatsakis (Jun 13 2019 at 18:18, on Zulip):

I'm trying to remember all the flags for this sort of thing

nikomatsakis (Jun 13 2019 at 18:18, on Zulip):

I guess -Zunpretty=hir-tree

nikomatsakis (Jun 13 2019 at 18:19, on Zulip):

or just -Zunpretty=hir

nikomatsakis (Jun 13 2019 at 18:19, on Zulip):
fn foo()
 ->
      {
          ::std::future::from_generator(

                                        ||
                                            {
                                                match { let _t = false; _t } {
                                                    true => { return Ok(6); }
                                                    _ => { }
                                                }
                                                5
                                            })
      }

fn main() { }
davidtwco (Jun 13 2019 at 18:19, on Zulip):

This is the hir-tree.

nikomatsakis (Jun 13 2019 at 18:20, on Zulip):

what's up with _t = false business?

nikomatsakis (Jun 13 2019 at 18:20, on Zulip):

oh

nikomatsakis (Jun 13 2019 at 18:20, on Zulip):

that's the desugaring for if I guess

nikomatsakis (Jun 13 2019 at 18:20, on Zulip):

dear god

nikomatsakis (Jun 13 2019 at 18:20, on Zulip):

:)

nikomatsakis (Jun 13 2019 at 18:20, on Zulip):

beautiful

nikomatsakis (Jun 13 2019 at 18:20, on Zulip):

and terrible

nikomatsakis (Jun 13 2019 at 18:20, on Zulip):

all at once

nikomatsakis (Jun 13 2019 at 18:21, on Zulip):

ok so from_generator is

pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
    GenFuture(x)
}
nikomatsakis (Jun 13 2019 at 18:21, on Zulip):

so this is pretty complex

nikomatsakis (Jun 13 2019 at 18:22, on Zulip):

the link between the actual return value and the expectation is rather...removed

nikomatsakis (Jun 13 2019 at 18:22, on Zulip):

i.e., the function is returning an opaque type

nikomatsakis (Jun 13 2019 at 18:22, on Zulip):

let's call it ?0

nikomatsakis (Jun 13 2019 at 18:22, on Zulip):

which has to meet the requirement ?0: Future<Output = i32>

nikomatsakis (Jun 13 2019 at 18:23, on Zulip):

and then there is a call to from_generator which returns an opaque type impl Future<Output = T::Return>

nikomatsakis (Jun 13 2019 at 18:23, on Zulip):

so the expected type for the generator is ?1 (instantiated value of T)

nikomatsakis (Jun 13 2019 at 18:23, on Zulip):

and we have the obligations that

nikomatsakis (Jun 13 2019 at 18:24, on Zulip):
?1: Generator<Yield = ()>
<?0 as Future>::Output = <?1 as Generator>::Return

or..something like that...

nikomatsakis (Jun 13 2019 at 18:24, on Zulip):

I should probably just dump state of compiler to see I guess

centril (Jun 13 2019 at 18:25, on Zulip):

that's the desugaring for if I guess

(It is lying a little bit; there's no actual let binding there but ExprKind::DropTemps(false); but the block is the semantic equivalent)

nikomatsakis (Jun 13 2019 at 18:26, on Zulip):

so I'm going to run with

> RUSTC_LOG=rustc_typeck::check::closure  rustc +rust-2-stage2 ~/tmp/issue-54326.rs --edition 2018
nikomatsakis (Jun 13 2019 at 18:26, on Zulip):

and we get

DEBUG 2019-06-13T18:26:19Z: rustc_typeck::check::closure: check_expr_closure(expr=expr(HirId { owner: DefIndex(13), local_id: 23 }: ||),expected=ExpectHasType(_#1t))
DEBUG 2019-06-13T18:26:19Z: rustc_typeck::check::closure: deduce_expectations_from_expected_type(expected_ty=_#1t)
DEBUG 2019-06-13T18:26:19Z: rustc_typeck::check::closure: deduce_expectations_from_obligations: obligation.predicate=Binder(TraitPredicate(<_#1t as std::marker::Sized>))
DEBUG 2019-06-13T18:26:19Z: rustc_typeck::check::closure: deduce_expectations_from_obligations: obligation.predicate=Binder(TraitPredicate(<_#1t as std::ops::Generator>))
DEBUG 2019-06-13T18:26:19Z: rustc_typeck::check::closure: deduce_expectations_from_obligations: obligation.predicate=Binder(ProjectionPredicate(ProjectionTy { substs: [_#1t], item_def_id: DefId(2:1651 ~ cor\
e[53a4]::ops[0]::generator[0]::Generator[0]::Yield[0]) }, ()))
DEBUG 2019-06-13T18:26:19Z: rustc_typeck::check::closure: deduce_sig_from_projection(Binder(ProjectionPredicate(ProjectionTy { substs: [_#1t], item_def_id: DefId(2:1651 ~ core[53a4]::ops[0]::generator[0]::G\
enerator[0]::Yield[0]) }, ())))
DEBUG 2019-06-13T18:26:19Z: rustc_typeck::check::closure: deduce_sig_from_projection: not return assoc item of generator
nikomatsakis (Jun 13 2019 at 18:27, on Zulip):

interestingly

nikomatsakis (Jun 13 2019 at 18:27, on Zulip):

we don't know the return type information yet

nikomatsakis (Jun 13 2019 at 18:27, on Zulip):

which I think @eddyb was alluding to above :)

nikomatsakis (Jun 13 2019 at 18:28, on Zulip):

we have three pending things:

?1: Sized
?1: Generator
<?1 as Generator>::Yield = ()
nikomatsakis (Jun 13 2019 at 18:28, on Zulip):

the last one is a bit uglier in Rust's debug output :)

(ProjectionPredicate(ProjectionTy { substs: [_#1t], item_def_id: DefId(2:1651 ~ core[53a4]::ops[0]::generator[0]::Generator[0]::Yield[0]) }, ())
nikomatsakis (Jun 13 2019 at 18:28, on Zulip):

a "projection predicate" is refers to proving the value of an associated type is equal to something else

nikomatsakis (Jun 13 2019 at 18:29, on Zulip):

the core::ops::generator::Generator::Yield identifies the associated type (and its trait)

nikomatsakis (Jun 13 2019 at 18:29, on Zulip):

and the substitutions are the type parameters from the trait (and, once we have GATs, the associated type)

nikomatsakis (Jun 13 2019 at 18:29, on Zulip):

in this case, [1]

nikomatsakis (Jun 13 2019 at 18:29, on Zulip):

so the point is that, with the setup we have now, we just don't know anything about this i32

nikomatsakis (Jun 13 2019 at 18:29, on Zulip):

that presumably comes later

nikomatsakis (Jun 13 2019 at 18:30, on Zulip):

but I gotta run now and do some other triage

nikomatsakis (Jun 13 2019 at 18:30, on Zulip):

lang team pre mtg:)

davidtwco (Jun 13 2019 at 18:31, on Zulip):

Thanks!

centril (Jun 13 2019 at 18:31, on Zulip):

@nikomatsakis waiting for you there :slight_smile:

nikomatsakis (Jun 13 2019 at 18:35, on Zulip):

so the point is that, with the setup we have now, we just don't know anything about this i32

@davidtwco just realized this is prob wrong -- I think the debug output is just filtering out some of the obligations

davidtwco (Jun 13 2019 at 19:12, on Zulip):

The extra logging in this snippet has all of the obligations (those with deduce_expectations_from_obligations lines too are the ones that are not filtered):

DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check::closure: deduce_expectations_from_expected_type(expected_ty=_#1t)
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: obligations_for_self_ty: self_ty=_#1t ty_var_root=_#1t pending_obligations=[/* omitted by davidtwco as they're listed below */]
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid(trait_ref=Binder(<_#0t as std::marker::Sized>), self_ty=_#0t, expected_vid=_#1t)
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid - found_vid=_#0t
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid(trait_ref=Binder(<_#0t as std::future::Future>), self_ty=_#0t, expected_vid=_#1t)
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid - found_vid=_#0t
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid(trait_ref=Binder(<_#0t as std::future::Future>), self_ty=_#0t, expected_vid=_#1t)
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid - found_vid=_#0t
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid(trait_ref=Binder(<_#1t as std::marker::Sized>), self_ty=_#1t, expected_vid=_#1t)
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid - found_vid=_#1t
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check::closure: deduce_expectations_from_obligations: obligation.predicate=Binder(TraitPredicate(<_#1t as std::marker::Sized>))
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid(trait_ref=Binder(<_#1t as std::ops::Generator>), self_ty=_#1t, expected_vid=_#1t)
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid - found_vid=_#1t
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check::closure: deduce_expectations_from_obligations: obligation.predicate=Binder(TraitPredicate(<_#1t as std::ops::Generator>))
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid(trait_ref=Binder(<_#1t as std::ops::Generator>), self_ty=_#1t, expected_vid=_#1t)
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check: self_type_matches_expected_vid - found_vid=_#1t
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check::closure: deduce_expectations_from_obligations: obligation.predicate=Binder(ProjectionPredicate(ProjectionTy { substs: [_#1t], item_def_id: DefId(2:1651 ~ core[54d4]::ops
[0]::generator[0]::Generator[0]::Yield[0]) }, ()))
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check::closure: deduce_sig_from_projection(Binder(ProjectionPredicate(ProjectionTy { substs: [_#1t], item_def_id: DefId(2:1651 ~ core[54d4]::ops[0]::generator[0]::Generator[0]:
:Yield[0]) }, ())))
DEBUG 2019-06-13T19:10:33Z: rustc_typeck::check::closure: deduce_sig_from_projection: not return assoc item of generator
nikomatsakis (Jun 19 2019 at 14:48, on Zulip):

So there was talk of setting up a meeting here -- I could perhaps meet tomorrow at 8am or 9am UTC-07:00 (Pacific time)

nikomatsakis (Jun 19 2019 at 14:48, on Zulip):

I'm here now, too, but I don't know if @Taylor Cramer or @davidtwco are..

Taylor Cramer (Jun 19 2019 at 15:02, on Zulip):

Oh, I'm here now

davidtwco (Jun 19 2019 at 15:02, on Zulip):

I am

Taylor Cramer (Jun 19 2019 at 15:02, on Zulip):

@nikomatsakis still around?

Taylor Cramer (Jun 19 2019 at 15:03, on Zulip):

8 or 9 PST tomorrow would also work for me

davidtwco (Jun 19 2019 at 15:04, on Zulip):

Likewise if it's just in Zulip and not Zoom.

nikomatsakis (Jun 19 2019 at 15:08, on Zulip):

I'm here

nikomatsakis (Jun 19 2019 at 15:08, on Zulip):

but it would have to be zulip, yeah

nikomatsakis (Jun 19 2019 at 15:09, on Zulip):

I guess the first question is how hard we want to work on this :

nikomatsakis (Jun 19 2019 at 15:10, on Zulip):

that said

nikomatsakis (Jun 19 2019 at 15:10, on Zulip):

hmm

nikomatsakis (Jun 19 2019 at 15:10, on Zulip):

there is a connection to some other diagnostic failures iirc

nikomatsakis (Jun 19 2019 at 15:10, on Zulip):

or just general inference failures I mean

nikomatsakis (Jun 19 2019 at 15:11, on Zulip):

notably there is some issue about fn foo<T: Foo>(t: T) where you have impl Foo for Fn(u32). The problem is that, today, we can't infer the expected type when you do foo(|x| ...), so we don't know the type of x.

nikomatsakis (Jun 19 2019 at 15:12, on Zulip):

this feels similar -- the problem there being that we have a pending obligation for T: Foo, but we don't (yet) know that this can only be solved by T: Fn(u32)

nikomatsakis (Jun 19 2019 at 15:12, on Zulip):

it seems like in both cases we're kind of talking about "simplifying" the expectations

nikomatsakis (Jun 19 2019 at 15:12, on Zulip):

(sigh, this will make the chalk style solving strategy more complex too)

nikomatsakis (Jun 19 2019 at 15:12, on Zulip):

but I think the first thing would be to establish whether, indeed, we know enough to even theoretically figure things out

Taylor Cramer (Jun 19 2019 at 15:13, on Zulip):

I'd personally be happy with something more narrow that could specifically propagate the required output type for async blocks, since iirc we have similar existing logic for closures

Taylor Cramer (Jun 19 2019 at 15:13, on Zulip):

But if you think we can solve this in a more principled way, I'm happy to spend time on it

nikomatsakis (Jun 19 2019 at 15:13, on Zulip):

I would be ok with something narrow, but we hvae to figure out what it should be

nikomatsakis (Jun 19 2019 at 15:14, on Zulip):

the link for the return type etc is pretty separated

nikomatsakis (Jun 19 2019 at 15:14, on Zulip):

I'm re-reading the backscroll to try and page this back in a bit

davidtwco (Jun 19 2019 at 15:14, on Zulip):

I'm also happy to work on this, all I managed to accomplish when first looking at the issue was generalizing the closure special-casing to generators.

nikomatsakis (Jun 19 2019 at 15:15, on Zulip):

I mean the easiest thing would be to add some sort of special node in the HIR I guess

nikomatsakis (Jun 19 2019 at 15:15, on Zulip):
fn foo()
 ->
      {
          ::std::future::from_generator(

                                        ||
                                            {
                                                match { let _t = false; _t } {
                                                    true => { return Ok(6); }
                                                    _ => { }
                                                }
                                                5
                                            })
      }

fn main() { }
nikomatsakis (Jun 19 2019 at 15:15, on Zulip):

that's the desugaring we posted before

nikomatsakis (Jun 19 2019 at 15:16, on Zulip):

the expected return type of the from_generator call is pretty separated from the requirements on the arguments

nikomatsakis (Jun 19 2019 at 15:16, on Zulip):

(this is the "link" I'm referring to)

davidtwco (Jun 19 2019 at 15:16, on Zulip):

Unfortunately, the bug that makes HIR lowering output for async fns means we can't see the return type from it.

nikomatsakis (Jun 19 2019 at 15:16, on Zulip):

yeah but that's ok

nikomatsakis (Jun 19 2019 at 15:16, on Zulip):

you know it's there ;)

nikomatsakis (Jun 19 2019 at 15:16, on Zulip):

some sort of -> impl Future, I presume

nikomatsakis (Jun 19 2019 at 15:17, on Zulip):

anyway I could imagine that we desugar to something like

nikomatsakis (Jun 19 2019 at 15:17, on Zulip):

from_generator(|| -> XX { .. }), except we couldn't write the XX -- i.e., we don't really have the syntax for what you'd want there

nikomatsakis (Jun 19 2019 at 15:18, on Zulip):

or maybe we could do from_generator::<...XXX...> if we setup it up right, to let us specify the return type

Taylor Cramer (Jun 19 2019 at 15:18, on Zulip):

Yeah, that was my initial attempt which failed because we don't have a way to copy types in hir

nikomatsakis (Jun 19 2019 at 15:18, on Zulip):

as @Taylor Cramer mentioned somewhere, it'd be require duplicating info in the HIR if we did it naively

nikomatsakis (Jun 19 2019 at 15:18, on Zulip):

yeah, you could imagine having some special hir node that means "return type of the enclosing function" or something but...

Taylor Cramer (Jun 19 2019 at 15:18, on Zulip):

Mhm, because you need the output type to appear in two places

nikomatsakis (Jun 19 2019 at 15:19, on Zulip):

... at that point it's not necessarily easier than the more principled way

Taylor Cramer (Jun 19 2019 at 15:19, on Zulip):

Indeed

Taylor Cramer (Jun 19 2019 at 15:19, on Zulip):

Especially given that it's not actually the return type, but the output type of the return type

nikomatsakis (Jun 19 2019 at 15:19, on Zulip):

right

nikomatsakis (Jun 19 2019 at 15:20, on Zulip):

I have to say that I'm not entirely convinced that HIR-level desugaring is correct for async fn

nikomatsakis (Jun 19 2019 at 15:20, on Zulip):

not that I thikn we should rewrite that

nikomatsakis (Jun 19 2019 at 15:20, on Zulip):

(In general, I feel like some of the things we do at HIR level might be better done at HIR -> MIR, though it'd require more duplication in the type-checker)

nikomatsakis (Jun 19 2019 at 15:20, on Zulip):

anyway that's off topic

nikomatsakis (Jun 19 2019 at 15:21, on Zulip):

@davidtwco do you have a "concise" listing of the pending obligations?

nikomatsakis (Jun 19 2019 at 15:21, on Zulip):

I couldn't quite extract it from the log you posted

nikomatsakis (Jun 19 2019 at 15:21, on Zulip):

I guess I can try to get one

davidtwco (Jun 19 2019 at 15:23, on Zulip):
pending_obligations=[
Obligation(predicate=Binder(TraitPredicate(<_#0t as std::marker::Sized>)), cause=ObligationCause { span: src/test/ui/async-await/issue-54326.rs:4:19: 4:22, body_id: HirId { owner: DefIndex(12), local_id: 25 }, code: SizedReturnType }, param_env=ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, depth=0),
Obligation(predicate=Binder(TraitPredicate(<_#0t as std::future::Future>)), cause=ObligationCause { span: src/test/ui/async-await/issue-54326.rs:4:19: 4:22, body_id: HirId { owner: DefIndex(12), local_id: 25 }, code: SizedReturnType }, param_env=ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, depth=0),
Obligation(predicate=Binder(ProjectionPredicate(ProjectionTy { substs: [_#0t], item_def_id: DefId(2:7110 ~ core[54d4]::future[0]::future[0]::Future[0]::Output[0]) }, i32)), cause=ObligationCause { span: src/test/ui/async-await/issue-54326.rs:4:19: 4:22, body_id: HirId { owner: DefIndex(12), local_id: 25 }, code: SizedReturnType }, param_env=ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, depth=0),
Obligation(predicate=Binder(TraitPredicate(<_#1t as std::marker::Sized>)), cause=ObligationCause { span: src/test/ui/async-await/issue-54326.rs:4:23: 10:2, body_id: HirId { owner: DefIndex(12), local_id: 25 }, code: ItemObligation(DefId(1:5180 ~ std[d43b]::future[0]::from_generator[0])) }, param_env=ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, depth=0),
Obligation(predicate=Binder(TraitPredicate(<_#1t as std::ops::Generator>)), cause=ObligationCause { span: src/test/ui/async-await/issue-54326.rs:4:23: 10:2, body_id: HirId { owner: DefIndex(12), local_id: 25 }, code: ItemObligation(DefId(1:5180 ~ std[d43b]::future[0]::from_generator[0])) }, param_env=ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, depth=0),
Obligation(predicate=Binder(ProjectionPredicate(ProjectionTy { substs: [_#1t], item_def_id: DefId(2:1651 ~ core[54d4]::ops[0]::generator[0]::Generator[0]::Yield[0]) }, ())), cause=ObligationCause { span: src/test/ui/async-await/issue-54326.rs:4:23: 10:2, body_id: HirId { owner: DefIndex(12), local_id: 25 }, code: ItemObligation(DefId(1:5180 ~ std[d43b]::future[0]::from_generator[0])) }, param_env=ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, depth=0),
Obligation(predicate=WellFormed(_#1t), cause=ObligationCause { span: src/test/ui/async-await/issue-54326.rs:4:23: 10:2, body_id: HirId { owner: DefIndex(12), local_id: 25 }, code: MiscObligation }, param_env=ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, depth=0)
]
nikomatsakis (Jun 19 2019 at 15:24, on Zulip):

ok let me see if I can make sense of that :)

davidtwco (Jun 19 2019 at 15:25, on Zulip):

Only those with a _#1t are considered because self_type_matches_expected_vid filters out the others.

nikomatsakis (Jun 19 2019 at 15:25, on Zulip):

looks like

nikomatsakis (Jun 19 2019 at 15:25, on Zulip):
?0: Sized
?0: Future
<?0 as Future>::Output = i32
?1: Sized
?1: Generator
<?1 as Generator>::Yield = ()
?1: WF
nikomatsakis (Jun 19 2019 at 15:25, on Zulip):

here ?0 is the (hidden) return type

nikomatsakis (Jun 19 2019 at 15:26, on Zulip):

and ?1 is the type of the argument

nikomatsakis (Jun 19 2019 at 15:26, on Zulip):

crucially, the link between ?0 and ?1 is absent -- which isn't too surprising to me

nikomatsakis (Jun 19 2019 at 15:26, on Zulip):

well, maybe a little

davidtwco (Jun 19 2019 at 15:26, on Zulip):

(here's the raw log that is a snippet from: https://gist.githubusercontent.com/davidtwco/2fa0aa796dc313bc7c90579b729b83ed/raw/4ca70a22274c61475e486354f583ec70bb5db257/gistfile1.txt)

nikomatsakis (Jun 19 2019 at 15:26, on Zulip):
pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
nikomatsakis (Jun 19 2019 at 15:27, on Zulip):

so clearly the input type is T

nikomatsakis (Jun 19 2019 at 15:27, on Zulip):

I guess that the return type (from our perspective) is an "opaque type", so an impl Future<Output = T::Return>

nikomatsakis (Jun 19 2019 at 15:28, on Zulip):

and that return type has to be unified with ?0

nikomatsakis (Jun 19 2019 at 15:28, on Zulip):

and then we have to try to solve <?0 as Future>::Output = i32

nikomatsakis (Jun 19 2019 at 15:28, on Zulip):

which will create a new obligation that <?1 as Generator>::Return = i32 eventually

nikomatsakis (Jun 19 2019 at 15:29, on Zulip):

so yeah it's pretty indirect to figure this out :) several steps down the line

nikomatsakis (Jun 19 2019 at 15:29, on Zulip):

and I'm understanding @eddyb's comments better, because in particular the processing of the return type probably happens at the wrong time right now.

nikomatsakis (Jun 19 2019 at 15:29, on Zulip):

(does this all make sense so far?)

nikomatsakis (Jun 19 2019 at 15:30, on Zulip):

we do have some logic that does some creative stuff where we unify the return type (here, impl Future) with the expected type (here, ?0) to try and figure out what it might mean for the arguments

davidtwco (Jun 19 2019 at 15:30, on Zulip):

I'm not super familiar with unification (or how the solving of an obligation happens, but I can leave that as a black box for now).

nikomatsakis (Jun 19 2019 at 15:31, on Zulip):

this is the

    /// Unifies the output type with the expected type early, for more coercions
    /// and forward type information on the input expressions.
    fn expected_inputs_for_expected_output(&self,
                                           call_span: Span,
                                           expected_ret: Expectation<'tcx>,
                                           formal_ret: Ty<'tcx>,
                                           formal_args: &[Ty<'tcx>])
                                           -> Vec<Ty<'tcx>> {

function

eddyb (Jun 19 2019 at 15:31, on Zulip):

the important thing is that this is speculative and preserves the shape but disconnects the resulting type variables from the original

nikomatsakis (Jun 19 2019 at 15:31, on Zulip):

I'm not super familiar with unification

ok. For our purposes, you can imagine that a ?T variable is like a little mutable cell in one of two states:

nikomatsakis (Jun 19 2019 at 15:32, on Zulip):

once it gets bound, any reference to ?T is kind of "redirected" to U

eddyb (Jun 19 2019 at 15:32, on Zulip):

because we can't enforce the expected type, we can only be guided by it

eddyb (Jun 19 2019 at 15:32, on Zulip):

(until we know the actual type and can try coercing it)

nikomatsakis (Jun 19 2019 at 15:32, on Zulip):

hmm, we are already processing obligations in that code

nikomatsakis (Jun 19 2019 at 15:33, on Zulip):

oh, but only a subset

nikomatsakis (Jun 19 2019 at 15:33, on Zulip):

we should add some debug logging in there, @davidtwco, that might help point a bit

davidtwco (Jun 19 2019 at 15:33, on Zulip):

Sorry, where?

nikomatsakis (Jun 19 2019 at 15:33, on Zulip):

the expected_inputs_for_expected_output function

nikomatsakis (Jun 19 2019 at 15:33, on Zulip):

I'm adding some in my local branch

nikomatsakis (Jun 19 2019 at 15:34, on Zulip):

in the meantime, that'd be a good function for us to talk through to help understand better what's going on

nikomatsakis (Jun 19 2019 at 15:34, on Zulip):

though maybe it'll have to be tomorrow -- should we shoot for 8am UTC-07:00 tomorrow again? I should probably get up and go wherever it is I am supposed to be

Taylor Cramer (Jun 20 2019 at 15:01, on Zulip):

@nikomatsakis @davidtwco around?

davidtwco (Jun 20 2019 at 15:20, on Zulip):

I’m around now sorry.

davidtwco (Jun 20 2019 at 15:21, on Zulip):

Had a small fire at work.

davidtwco (Jun 20 2019 at 15:21, on Zulip):

(digital fire, not real)

nikomatsakis (Jun 25 2019 at 17:01, on Zulip):

@davidtwco so I did some more digging into this, sorry for not writing back later -- my impression was that we may just need a somewhat smal PR here.

davidtwco (Jun 25 2019 at 17:02, on Zulip):

That's good.

davidtwco (Jun 25 2019 at 17:02, on Zulip):

I was actually just looking for an issue to work on.

nikomatsakis (Jun 25 2019 at 17:02, on Zulip):

though one that makes me ever so mildly nervous (it has implications around the chalk strategy, I think)

nikomatsakis (Jun 25 2019 at 17:27, on Zulip):

@davidtwco to briefly update you on whatI had planned to do

nikomatsakis (Jun 25 2019 at 17:37, on Zulip):

in the expected_inputs_for_expected_output function...

nikomatsakis (Jun 25 2019 at 17:37, on Zulip):

...we create a temporary fulfillment context and try to fulfill various trait obligations...

nikomatsakis (Jun 25 2019 at 17:37, on Zulip):

...but we are only fulfilling obligations that resulted from the subtyping rules

nikomatsakis (Jun 25 2019 at 17:37, on Zulip):

and not obliations that we already know to be required

nikomatsakis (Jun 25 2019 at 17:38, on Zulip):

I was going to -- at least experimentally, to start -- add a line like

nikomatsakis (Jun 25 2019 at 17:38, on Zulip):
for obligation in self.fulfill_cx.borrow().pending_obligations() {
    fulfill.register_predicate_obligation(self, obligation);
}
nikomatsakis (Jun 25 2019 at 17:39, on Zulip):

and see what happens :)

nikomatsakis (Jun 25 2019 at 17:39, on Zulip):

care to give it a try?

davidtwco (Jun 25 2019 at 17:44, on Zulip):

Can do.

davidtwco (Jun 25 2019 at 19:16, on Zulip):

@nikomatsakis Fails to compile proc_macro with that change:

error[E0631]: type mismatch in closure arguments
   --> src/libproc_macro/bridge/client.rs:298:29
    |
298 |               panic::set_hook(Box::new(move |info| {
    |                               ^        ----------- found signature of `fn(&std::panic::PanicInfo<'_>) -> _`
    |  _____________________________|
    | |
299 | |                 let hide = BridgeState::with(|state| match state {
300 | |                     BridgeState::NotConnected => false,
301 | |                     BridgeState::Connected(_) | BridgeState::InUse => true,
...   |
305 | |                 }
306 | |             }));
    | |______________^ expected signature of `for<'r, 's> fn(&'r std::panic::PanicInfo<'s>) -> _`
    |
    = note: required for the cast to the object type `dyn for<'r, 's> std::ops::Fn(&'r std::panic::PanicInfo<'s>) + std::marker::Send + std::marker::Sync`

error[E0271]: type mismatch resolving `for<'r, 's> <[closure@src/libproc_macro/bridge/client.rs:298:38: 306:14 prev:_] as std::ops::FnOnce<(&'r std::panic::PanicInfo<'s>,)>>::Output == ()`
   --> src/libproc_macro/bridge/client.rs:298:29
    |
298 |               panic::set_hook(Box::new(move |info| {
    |  _____________________________^
299 | |                 let hide = BridgeState::with(|state| match state {
300 | |                     BridgeState::NotConnected => false,
301 | |                     BridgeState::Connected(_) | BridgeState::InUse => true,
...   |
305 | |                 }
306 | |             }));
    | |______________^ expected bound lifetime parameter, found concrete lifetime
    |
    = note: required for the cast to the object type `dyn for<'r, 's> std::ops::Fn(&'r std::panic::PanicInfo<'s>) + std::marker::Send + std::marker::Sync`

error: aborting due to 2 previous errors
nikomatsakis (Jun 25 2019 at 19:50, on Zulip):

d'oh :)

nikomatsakis (Jun 25 2019 at 19:51, on Zulip):

@davidtwco what is branch name?

davidtwco (Jun 25 2019 at 19:51, on Zulip):

I’ve not pushed it.

davidtwco (Jun 25 2019 at 19:51, on Zulip):

Unless you don’t mean Git branch?

davidtwco (Jun 25 2019 at 19:52, on Zulip):

It was just pasting those three lines below the three you linked previously.

nikomatsakis (Jun 25 2019 at 19:53, on Zulip):

I did mean git branch but yeah I could make the change independently

nikomatsakis (Jul 08 2019 at 20:26, on Zulip):

@davidtwco circling back to this, I guess i'll create a branch locally

davidtwco (Jul 08 2019 at 20:36, on Zulip):

Cool, I’ve not looked at this since we last spoke.

Last update: Nov 18 2019 at 00:40UTC