Skip to content
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

Broken code after 2017-09-30 nightly #45142

Closed
pedrohjordao opened this issue Oct 9, 2017 · 24 comments
Closed

Broken code after 2017-09-30 nightly #45142

pedrohjordao opened this issue Oct 9, 2017 · 24 comments
Labels
C-bug Category: This is a bug. P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@pedrohjordao
Copy link

pedrohjordao commented Oct 9, 2017

The following code was working until the 2017-09-30 nightly:

Playground

Maybe it's catching something I'm not seeing. If that's the case maybe someone could explain it to me?

@pedrohjordao
Copy link
Author

pedrohjordao commented Oct 9, 2017

Notice that if I change the inner try_from call and call the function

fn a_function<'a, R: io::Read>(_: &'a mut EventReader<R>) {}

everything is fine. The way I understand both calls should work the same way.

@pedrohjordao
Copy link
Author

Changing a_function to

fn a_function<'a, R: io::Read>(value: &'a mut EventReader<R>) -> Result<Other, ()> {
    Other::try_from(value)
}

makes everything work. So I believe this is actually a bug.

@sfackler sfackler added regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Oct 9, 2017
@TimNN TimNN added the C-bug Category: This is a bug. label Oct 10, 2017
@nikomatsakis
Copy link
Contributor

Most likely caused by #43880

@nikomatsakis
Copy link
Contributor

I think what is happening is that we are no longer inserting the auto-coercion because of the inner details of how method calls are working after #43880 -- i.e., we used to effectively pass &mut *value in the compiler.

@pedrohjordao if you rewrite to <Other as TryFrom<&'a mut EventReader<R>>::try_from(value), that will work too, right?

@nikomatsakis
Copy link
Contributor

triage: P-high

Calling P-high -- we should decide if we plan to fix. cc @arielb1

@rust-highfive rust-highfive added the P-high High priority label Oct 19, 2017
@pedrohjordao
Copy link
Author

pedrohjordao commented Oct 20, 2017

@nikomatsakis huum, I think I get the reasoning behind what you're saying about the change, but I do hope you decide to fix it or make a really nice compiler error pointing to the correct call.

Anyway, it might be my sleepy brain making me confuse, but there might still be something wrong. What you said still doesn't work:

https://play.rust-lang.org/?gist=5d5fc92da3270bf04736f943e8f236a5&version=undefined

@arielb1 arielb1 self-assigned this Nov 2, 2017
@arielb1
Copy link
Contributor

arielb1 commented Nov 2, 2017

@pedrohjordao

That's because you need <Other as TryFrom<&mut EventReader<R>>>::try_from(value), without the 'a.

@arielb1
Copy link
Contributor

arielb1 commented Nov 2, 2017

I can't get this code as written to compile with any version of rustc.

@pedrohjordao
Copy link
Author

pedrohjordao commented Nov 2, 2017 via email

@arielb1
Copy link
Contributor

arielb1 commented Nov 2, 2017

@pedrohjordao

I tried again and it worked. I'm not sure what was the problem. It was me using nightlies around #43880, from August 30 with TryFrom copied over instead of nightlies from September 30.

@arielb1
Copy link
Contributor

arielb1 commented Nov 2, 2017

And looking again at the set of commits , I think #44174 (Add blanket TryFrom impl when From is implemented) is actually the PR to blame - it actually landed on Sep 30 (unlike #43880, which landed on Aug 30) and locally adding/removing the impl it added reproduces the problem.

@arielb1 arielb1 added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 2, 2017
@arielb1
Copy link
Contributor

arielb1 commented Nov 2, 2017

Minimal example (you can use the actual TryFrom instead of the one implemented here).

struct Test;

struct EventReader<R>(R);

impl<'a, R> TryFrom<&'a mut EventReader<R>> for Test {
    type Error = ();

    fn try_from(value: &'a mut EventReader<R>) -> Result<Self, Self::Error> {
        Other::try_from(value);
        Other::try_from(value);
        Ok(Test {})
    }
}

struct Other;

pub trait TryFrom<T>: Sized {
    /// The type returned in the event of a conversion error.
    type Error;

    /// Performs the conversion.
    fn try_from(value: T) -> Result<Self, Self::Error>;
}

impl<'a, R> TryFrom<&'a mut EventReader<R>> for Other {
    type Error = ();

    fn try_from(value: &'a mut EventReader<R>) -> Result<Self, Self::Error> {
        unimplemented!()
    }
}

pub enum Infallible {}

#[cfg(error)]
impl<T, U> TryFrom<U> for T where T: From<U> {
    type Error = Infallible;

    fn try_from(value: U) -> Result<Self, Self::Error> {
        Ok(T::from(value))
    }
}

#[cfg(not(error))]
impl<'a, T> TryFrom<&'a str> for T where T: std::str::FromStr
{
    type Error = <T as std::str::FromStr>::Err;

    fn try_from(s: &'a str) -> Result<T, Self::Error> {
        std::str::FromStr::from_str(s)
    }
}

fn main() {}

@arielb1
Copy link
Contributor

arielb1 commented Nov 2, 2017

This looks like a change in an unstable library interface, let's see T-libs opinion on this.

@arielb1
Copy link
Contributor

arielb1 commented Nov 2, 2017

cc @rust-lang/libs

@arielb1
Copy link
Contributor

arielb1 commented Nov 2, 2017

@pedrohjordao

Possible fixes are

  1. <Other as TryFrom<&mut _>>::try_from(value)
  2. Other::try_from(&mut *value)

@pedrohjordao
Copy link
Author

pedrohjordao commented Nov 2, 2017 via email

@arielb1
Copy link
Contributor

arielb1 commented Nov 2, 2017

@pedrohjordao

This is not a regression in the compiler but rather a new impl that was added to TryFrom, therefore there's no simple compiler fix we can write to make this work.

I don't think we'll revert the impl we added to fix this use-case - it's an unstable trait and therefore changes are to be expected, and even if it was stable we very rarely revert new impls because of inference difficulties such as this.

However, I think that NLL (technically, MIR borrowck) will allow us to unify borrows and moves of mutable references and therefore to avoid this problem, so it is not final in that sense. But don't count on that.

@pedrohjordao
Copy link
Author

pedrohjordao commented Nov 2, 2017 via email

@pnkfelix
Copy link
Member

Since @arielb1 brought up MIR-borrowck, let's quickly CC #43234

@arielb1 arielb1 assigned aturon and unassigned arielb1 Dec 25, 2017
@Mark-Simulacrum Mark-Simulacrum added this to the 1.25 milestone Jan 15, 2018
@dtolnay dtolnay added the regression-from-stable-to-stable Performance or correctness regression from one stable version to another. label Jan 21, 2018
@dtolnay dtolnay removed the regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. label Jan 21, 2018
@Mark-Simulacrum Mark-Simulacrum removed this from the 1.25 milestone Mar 14, 2018
@ljedrz
Copy link
Contributor

ljedrz commented Aug 2, 2018

The minimal example compiles fine on current stable.

@estebank estebank added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Oct 11, 2018
@pnkfelix
Copy link
Member

pnkfelix commented Nov 12, 2018

The aforementioned "minimal example" used cfg blocks to include both working and non-working variants.

Here's a modified version that makes the non-working one the default, rather than vice versa: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=170ae503a6bd8d2cda4081b65fba6e3c

AFAICT, the non-working one still errors.

I haven't read the thread carefully yet, but I think the intention of the "minimal example" as written is that the non-working one should in fact work...

@pnkfelix pnkfelix removed the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Nov 12, 2018
@aturon aturon removed their assignment Apr 10, 2019
@pnkfelix
Copy link
Member

pnkfelix commented Jun 25, 2019

Looking at this (after a long time of it lying fallow), I'm not sure if the "minimal example" that @arielb1 provided above is actually illustrating the bug described here, because (I think) the error from ariel's example happens in every Rust version going back to version 1.0.6

  • (Or maybe that is ariel's whole point: Maybe the minimal example being provided there is just showing how this combination of traits and method calls is going to cause an error. That is, maybe it is not a minimal example showing where a regression in behavior was injected; which would mean my interpretation of how it was meant to be used in my previous comment was wrong.)

I'm going to try to go back to the original example filed on this bug to double-check what the story is.

@pnkfelix
Copy link
Member

Okay, when I look at the original example from the bug, I get the following diagnostic:

error[E0382]: use of moved value: `value`
  --> src/main.rs:22:37
   |
22 |                     Other::try_from(value);
   |                                     ^^^^^ value moved here in previous iteration of loop
   |
   = note: move occurs because `value` has type `&'a mut xml::EventReader<R>`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `*value`
  --> src/main.rs:27:20
   |
22 |                     Other::try_from(value);
   |                                     ----- value moved here
...
27 |             next = value.next();
   |                    ^^^^^ value used here after move
   |
   = note: move occurs because `value` has type `&'a mut xml::EventReader<R>`, which does not implement the `Copy` trait

error: aborting due to 2 previous errors

As @nikomatsakis and @arielb1 have previously stated, we are not likely to attempt to start re-inserting the auto-reborrows in this case like we used to before #43880.

However, I find it interesting that niko and ariel were initially suggesting this work-around: <Other as TryFrom<&mut EventReader<R>>>::try_from(value), (which if I understand correctly is a way to force the type-inference engine to know that a &mut is being passed there before it works out method-resolution). The reason I find it interesting is that I find that work-around to be a rather wordy way to ask the compiler to inject the auto-reborrow.

But it seems much more concise to just inject the reborrow ourselves into the source, which was ariel's second suggestion above: Option::try_from(&mut *value)

Furthermore, it seems entirely doable for us to extend the diagnostic above to include a suggestion to try doing just that, as a way to avoid moving a &mut-value into a context that is itself expecting an &mut value.

I'm going to file a new bug (with a reduced example) requesting that change to the diangostic. After that's been filed, I'll close this as not-a-bug.

@pnkfelix
Copy link
Member

Filed issue #62112 for extending the diagnostic.

Closing this as not-a-bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests