Skip to content

Diesel's build is failing on beta and nightly #47139

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

Closed
sgrif opened this issue Jan 2, 2018 · 52 comments
Closed

Diesel's build is failing on beta and nightly #47139

sgrif opened this issue Jan 2, 2018 · 52 comments
Assignees
Labels
P-high High priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Milestone

Comments

@sgrif
Copy link
Contributor

sgrif commented Jan 2, 2018

There appears to be some regression in trait resolution between beta and nightly. Our builds are failing on nightly with this error: https://travis-ci.org/diesel-rs/diesel/jobs/324077372#L1081

I haven't yet looked into what the exact cause is, but the same code is compiling successfully on stable and beta.

@sgrif
Copy link
Contributor Author

sgrif commented Jan 3, 2018

This is now a regression from stable to beta

@sgrif sgrif changed the title Diesel's build is failing on nightly Diesel's build is failing on beta and nightly Jan 3, 2018
sgrif added a commit to diesel-rs/diesel that referenced this issue Jan 3, 2018
Our build is failing due to a regression in Rust.
rust-lang/rust#47139
@shssoichiro
Copy link
Contributor

I have some time now, I can go through and do a bisect to find the cause.

@sfackler sfackler added the regression-from-stable-to-beta Performance or correctness regression from stable to beta. label Jan 3, 2018
@sgrif
Copy link
Contributor Author

sgrif commented Jan 3, 2018

@shssoichiro Thank you! <3 I'm sorry I haven't provided a more specific reproduction case

@shssoichiro
Copy link
Contributor

shssoichiro commented Jan 4, 2018

It looks like the regression originated in 8c59418. My first guess at what's happening is that the blanket impl<T> SliceContains for T where T: PartialEq is causing an infinite recursion in trying to resolve diesel's Insertable trait, although I haven't created a minimized reproduction.

@nikomatsakis
Copy link
Contributor

Hmm. Any idea how those two traits are connected? That seems surprising.

@nikomatsakis nikomatsakis added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. P-high High priority labels Jan 4, 2018
@nikomatsakis nikomatsakis self-assigned this Jan 4, 2018
@nikomatsakis
Copy link
Contributor

I'd like to dig a bit more into this and understand better what's going on.

@sgrif
Copy link
Contributor Author

sgrif commented Jan 4, 2018

I'm not sure how SliceContains could affect Diesel, but I agree that it's the only thing in that commit that looks like it could possibly cause any problems here.

@sgrif
Copy link
Contributor Author

sgrif commented Jan 4, 2018

FWIW the impls it appears to be recursing through look like this:

impl<T, Tab> Insertable<Tab> for Option<T>
where
    T: Insertable<Tab>,
    T::Values: Default,
{
    // ...
}

impl<'a, T, Tab> Insertable<Tab> for &'a Option<T>
where
    Option<&'a T>: Insertable<Tab>,
{
    // ...
}

@sgrif
Copy link
Contributor Author

sgrif commented Jan 15, 2018

I'm no longer seeing this on nightly (our builds are still failing due to #47462). The bug was fixed somewhere in b98fd524e...6828cf901

@sgrif
Copy link
Contributor Author

sgrif commented Jan 15, 2018

I don't see anything in that diff that looks like it could have in any way affected this.

@Mark-Simulacrum Mark-Simulacrum modified the milestones: 1.24, 1.23 Jan 15, 2018
@Mark-Simulacrum Mark-Simulacrum added regression-from-stable-to-stable Performance or correctness regression from one stable version to another. regression-from-stable-to-beta Performance or correctness regression from stable to beta. and removed regression-from-stable-to-beta Performance or correctness regression from stable to beta. regression-from-stable-to-stable Performance or correctness regression from one stable version to another. labels Jan 15, 2018
@Mark-Simulacrum Mark-Simulacrum modified the milestones: 1.23, 1.24 Jan 15, 2018
@nikomatsakis
Copy link
Contributor

@sgrif huh, creepy.

@nikomatsakis
Copy link
Contributor

@sgrif but still failing on beta?

@nickbabcock
Copy link
Contributor

I've noticed that I no longer see the issue on 1.24.0-beta.7 (c7037ff 2018-01-21), so it looks like a recent beta version fixed it.

@sgrif
Copy link
Contributor Author

sgrif commented Jan 23, 2018

beta.7 is still failing on Travis for us. https://travis-ci.org/diesel-rs/diesel/jobs/331917195

@sgrif
Copy link
Contributor Author

sgrif commented Jan 23, 2018

As is the most recent nightly https://travis-ci.org/diesel-rs/diesel/jobs/331917198

@nickbabcock
Copy link
Contributor

Weird, I have both the beta.7 and nightly for diesel_cli 1.1.0 working fine. And a couple weeks ago this was broken.

@nikomatsakis
Copy link
Contributor

This failure seems like it might be a plausible model:

https://play.rust-lang.org/?gist=30e5797dec3f425a6d82f1f6a12dc0d0&version=stable

@nikomatsakis
Copy link
Contributor

The play snippet above fails with this:

error[E0275]: overflow evaluating the requirement `_#127t: std::marker::Sized`
  --> /home/nmatsakis/tmp/issue-47139.rs:42:12
   |
42 |     foo::< <Option<&_> as Insertable<()>>::Values >();
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
   = note: required because of the requirements on the impl of `Insertable<()>` for `&'_#31r std::option::Option<_#127t>`
   = note: required because of the requirements on the impl of `Insertable<()>` for `std::option::Option<&'_#31r std::option::Option<_#127t>>`
   = note: required because of the requirements on the impl of `Insertable<()>` for `&'_#30r std::option::Option<std::option::Option<_#127t>>`
   = note: required because of the requirements on the impl of `Insertable<()>` for `std::option::Option<&'_#30r std::option::Option<std::option::Option<_#127t>>>`
   = note: required because of the requirements on the impl of `Insertable<()>` for `&'_#29r std::option::Option<std::option::Option<std::option::Option<_#127t>>>`
   = note: required because of the requirements on the impl of `Insertable<()>` for `std::option::Option<&'_#29r std::option::Option<std::option::Option<std::option::Option<_#127t>>>>`
   = note: required because of the requirements on the impl of `Insertable<()>` for `&'_#28r std::option::Option<std::option::Option<std::option::Option<std::option::Option<_#127t>>>>`

where diesel fails with:

error[E0275]: overflow evaluating the requirement `<&'_#32r _#127t as insertable::Insertable<_#130t>>::Values`
  |
  = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
  = note: required because of the requirements on the impl of `insertable::Insertable<_#128t>` for `std::option::Option<&'_#32r _#127t>`
  = note: required because of the requirements on the impl of `insertable::Insertable<_#126t>` for `&'_#31r std::option::Option<_#127t>`
  = note: required because of the requirements on the impl of `insertable::Insertable<_#124t>` for `std::option::Option<&'_#31r std::option::Option<_#127t>>`
  = note: required because of the requirements on the impl of `insertable::Insertable<_#122t>` for `&'_#30r std::option::Option<std::option::Option<_#127t>>`
  = note: required because of the requirements on the impl of `insertable::Insertable<_#120t>` for `std::option::Option<&'_#30r std::option::Option<std::option::Option<_#127t>>>`
  = note: required because of the requirements on the impl of `insertable::Insertable<_#118t>` for `&'_#29r std::option::Option<std::option::Option<std::option::Option<_#127t>>>`
  = note: required because of the requirements on the impl of `insertable::Insertable<_#116t>` for `std::option::Option<&'_#29r std::option::Option<std::option::Option<std::option::Option<_#127t>>>>`
  = note: required because of the requirements on the impl of `insertable::Insertable<_#114t>` for `&'_#28r std::option::Option<std::option::Option<std::option::Option<std::option::Option<_#127t>>>>`

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Jan 23, 2018

We can simplify by removing the <Tab> type parameter.

What I don't know is why this failure occurs only sometimes in Diesel (vs predictably for that snippet above). It may be that I'm reproducing a different problem.

UPDATE: Looking at the logging more, I'm pretty sure it's the same basic pattern.

@nikomatsakis
Copy link
Contributor

@arielb1

try to evaluate <(&$0, &$1, &$2) as Insertable<$3>>

Interesting. I feel like I'm observing a different cycle, though one with a similar shape (I mean locally). I hadn't observed those impls yet.

@nikomatsakis
Copy link
Contributor

So it seems to me that extending the "select-project-recursion" nexus is going to be somewhat intrusive. I haven't pushed too hard on it, but it doesn't sound like the kind of thing I would want to backport. I am going to investigate a bit why this error is not happening on nightly -- I find that confusing.

@sgrif
Copy link
Contributor Author

sgrif commented Jan 24, 2018

I am going to investigate a bit why this error is not happening on nightly

This error is definitely happening on nightly. https://travis-ci.org/diesel-rs/diesel/jobs/332968985

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Jan 24, 2018

Digging in some more, the overflow is arising (in Diesel) as a result of a coherence check comparing these two impls:

impl<Conn, DB, T> ExecuteDsl<Conn, DB> for T
where
    Conn: Connection<Backend = DB>,
    DB: Backend,
    T: QueryFragment<DB> + QueryId,
{
}

#[cfg(feature = "sqlite")]
impl<'a, T, U, Op> ExecuteDsl<SqliteConnection> for InsertStatement<T, &'a [U], Op>
where
    &'a U: Insertable<T>,
    InsertStatement<T, <&'a U as Insertable<T>>::Values, Op>: QueryFragment<Sqlite>,
    T: Copy,
    Op: Copy,
{
}

@nikomatsakis
Copy link
Contributor

@sgrif Huh. At least in the commit I am looking at, it does not reproduce for some reason.

@sgrif
Copy link
Contributor Author

sgrif commented Jan 24, 2018

@nikomatsakis Yeah, it went away for a bit, then some code in Diesel changed and it came back

@sgrif
Copy link
Contributor Author

sgrif commented Jan 24, 2018

To save time, the way that the first impl applies is through:

impl<T, U, Op, Ret, DB> QueryFragment<DB> for InsertStatement<T, U, Op, Ret>
where
    DB: Backend,
    T: Table,
    T::FromClause: QueryFragment<DB>,
    U: QueryFragment<DB> + CanInsertInSingleQuery<DB>,
    Op: QueryFragment<DB>,
    Ret: QueryFragment<DB>,

The important bit is the CanInsertInSingleQuery, which is what makes it disjoint. The relevant impl that makes it disjoint is:

impl<'a, T, Tab, DB> CanInsertInSingleQuery<DB> for &'a [T]
where
    DB: Backend + SupportsDefaultKeyword,

where we know Sqlite: !SupportsDefaultKeyword. If you look at ExecuteDsl you'll notice some weird shit with the second type parameter (which is fully redundant with the first). It's basically a giant workaround to deal with the fact that associated types aren't taken into account WRT disjointness

@sgrif
Copy link
Contributor Author

sgrif commented Jan 24, 2018

Also just to rule this out, the weird shit we do with the second type parameter to ExecuteDsl has nothing to do with it. The issue still occurs with this patch applied to Diesel master (a patch I want to one day actually be able to commit...)

diff --git a/diesel/src/query_dsl/load_dsl.rs b/diesel/src/query_dsl/load_dsl.rs
index e3a1ea8..3b502b1 100644
--- a/diesel/src/query_dsl/load_dsl.rs
+++ b/diesel/src/query_dsl/load_dsl.rs
@@ -1,4 +1,3 @@
-use backend::Backend;
 use connection::Connection;
 use deserialize::Queryable;
 use query_builder::{AsQuery, QueryFragment, QueryId};
@@ -38,17 +37,15 @@ where
 /// to call `execute` from generic code.
 ///
 /// [`RunQueryDsl`]: ../trait.RunQueryDsl.html
-pub trait ExecuteDsl<Conn: Connection<Backend = DB>, DB: Backend = <Conn as Connection>::Backend>
-    : Sized {
+pub trait ExecuteDsl<Conn>: Sized {
     /// Execute this command
     fn execute(query: Self, conn: &Conn) -> QueryResult<usize>;
 }
 
-impl<Conn, DB, T> ExecuteDsl<Conn, DB> for T
+impl<Conn, T> ExecuteDsl<Conn> for T
 where
-    Conn: Connection<Backend = DB>,
-    DB: Backend,
-    T: QueryFragment<DB> + QueryId,
+    Conn: Connection,
+    T: QueryFragment<Conn::Backend> + QueryId,
 {
     fn execute(query: Self, conn: &Conn) -> QueryResult<usize> {
         conn.execute_returning_count(&query)

@sgrif
Copy link
Contributor Author

sgrif commented Jan 24, 2018

And the commit that cause the issue to re-appear is diesel-rs/diesel@8da028e

@nikomatsakis
Copy link
Contributor

OK, I found out how to make it build again in a fairly surgical way. The problem arises in this part of the coherence check, which is really just an effort to make an improved error message:

if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
!self.evaluate_candidate(stack, &c).may_apply()
}) {

The order of the vector returned by assemble_candidates seems to vary here, which is why the problem comes and goes. The danger is that some of the candidates in that vector cause overflows and some cause errors. Since this is a call to all(), if we happen to encounter one that returns false before the overflow, we're all set.

One simple fix that is obviously safe for beta backport is just not to do this call at all.

nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Jan 25, 2018
The scheme was causing overflows during coherence
checking (e.g. rust-lang#47139).
nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Jan 26, 2018
@sgrif
Copy link
Contributor Author

sgrif commented Jan 31, 2018

Fixed by #47738

@sgrif sgrif closed this as completed Jan 31, 2018
nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Feb 1, 2018
bors added a commit that referenced this issue Feb 1, 2018
remove intercrate ambiguity hints

The scheme was causing overflows during coherence checking (e.g. #47139). This is sort of a temporary fix; the proper fix I think involves reworking trait selection in deeper ways.

cc @sgrif -- this *should* fix diesel

cc @qnighy -- I'd like to discuss you with alternative techniques for achieving the same end. =) Actually, it might be good to put some energy into refactoring traits first.

r? @eddyb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P-high High priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. 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

7 participants