Repository: diesel-rs/diesel (language: rust)

Issue:
Investigate new nightly warning about a soundness hole in the type system
<!--
If you want to report a bug, we added some points below which help us track down the problem faster.
-->

## Setup

### Versions

- **Rust:** 1.80 (nightly)
- **Diesel:** master


## Problem Description

We get the following new warning for builds of `diesel-cli` on rust nightly:

```
warning[E0210]: type parameter `Col` must be covered by another type when it appears before the first local type (`database::multi_connection_impl::backend::MultiBackend`)
   --> diesel_cli/src/database.rs:109:10
    |
109 | #[derive(diesel::MultiConnection)]
    |          ^^^^^^^^^^^^^^^^^^^^^^^ type parameter `Col` must be covered by another type when it appears before the first local type (`database::multi_connection_impl::backend::MultiBackend`)
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
    = note: `#[warn(uncovered_param_in_projection)]` on by default
    = note: this warning originates in the derive macro `diesel::MultiConnection` (in Nightly builds, run with -Z macro-backtrace for more info)
```

### What is the expected output?

Builds without warning

Related: https://github.com/rust-lang/rust/issues/124559
<!--
Please include as much of your codebase as needed to reproduce the error.  If the relevant files are large, please consider linking to a public repository or a [Gist](https://gist.github.com/). This includes normally the following parts:

* The exact code where your hit the problem
* Relevant parts your schema, so any `table!` macro calls required for
* Any other type definitions involved in the code, which produces your problem
-->

## Checklist

- [x] I have already looked over the [issue tracker](https://github.com/diesel-rs/diesel/issues) and the [discussion forum](https://github.com/diesel-rs/diesel/discussions) for similar possible closed issues.
<!--
If you are unsure if your issue is a duplicate of an existing issue please link the issue in question here
--> 
- [ ] This issue can be reproduced on Rust's stable channel. (Your issue will be
  closed if this is not the case)
- [x] This issue can be reproduced without requiring a third party crate

<!--
Thank you for your submission!  You're helping make Diesel more robust 🎉

We'll try to respond as quickly as possible.
-->



Discussion / hints:

Fix patch:
diff --git a/diesel/src/insertable.rs b/diesel/src/insertable.rs
index e2010457f6ce..39e6d576475a 100644
--- a/diesel/src/insertable.rs
+++ b/diesel/src/insertable.rs
@@ -115,7 +115,7 @@ where
     }
 }
 
-pub trait InsertValues<T: Table, DB: Backend>: QueryFragment<DB> {
+pub trait InsertValues<DB: Backend, T: Table>: QueryFragment<DB> {
     fn column_names(&self, out: AstPass<'_, '_, DB>) -> QueryResult<()>;
 }
 
@@ -154,7 +154,7 @@ impl<T> Default for DefaultableColumnInsertValue<T> {
     }
 }
 
-impl<Col, Expr, DB> InsertValues<Col::Table, DB>
+impl<Col, Expr, DB> InsertValues<DB, Col::Table>
     for DefaultableColumnInsertValue<ColumnInsertValue<Col, Expr>>
 where
     DB: Backend + SqlDialect<InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword>,
@@ -168,7 +168,7 @@ where
     }
 }
 
-impl<Col, Expr, DB> InsertValues<Col::Table, DB> for ColumnInsertValue<Col, Expr>
+impl<Col, Expr, DB> InsertValues<DB, Col::Table> for ColumnInsertValue<Col, Expr>
 where
     DB: Backend,
     Col: Column,
@@ -218,7 +218,7 @@ where
 }
 
 #[cfg(feature = "sqlite")]
-impl<Col, Expr> InsertValues<Col::Table, crate::sqlite::Sqlite>
+impl<Col, Expr> InsertValues<crate::sqlite::Sqlite, Col::Table>
     for DefaultableColumnInsertValue<ColumnInsertValue<Col, Expr>>
 where
     Col: Column,
diff --git a/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs b/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs
index ba477d9b50f7..6d75058d10a3 100644
--- a/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs
+++ b/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs
@@ -235,7 +235,7 @@ where
     T: Table + Copy + QueryId + 'static,
     T::FromClause: QueryFragment<Sqlite>,
     Op: Copy + QueryId + QueryFragment<Sqlite>,
-    V: InsertValues<T, Sqlite> + CanInsertInSingleQuery<Sqlite> + QueryId,
+    V: InsertValues<Sqlite, T> + CanInsertInSingleQuery<Sqlite> + QueryId,
 {
     fn execute((Yes, query): Self, conn: &mut C) -> QueryResult<usize> {
         conn.transaction(|conn| {
diff --git a/diesel/src/query_builder/insert_statement/mod.rs b/diesel/src/query_builder/insert_statement/mod.rs
index fd992de0c27b..a8e0ca566377 100644
--- a/diesel/src/query_builder/insert_statement/mod.rs
+++ b/diesel/src/query_builder/insert_statement/mod.rs
@@ -455,7 +455,7 @@ impl<T, Tab, DB> QueryFragment<DB> for ValuesClause<T, Tab>
 where
     DB: Backend,
     Tab: Table,
-    T: InsertValues<Tab, DB>,
+    T: InsertValues<DB, Tab>,
     DefaultValues: QueryFragment<DB>,
 {
     fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
diff --git a/diesel/src/type_impls/tuples.rs b/diesel/src/type_impls/tuples.rs
index e47cc6273949..a59d273ed7bd 100644
--- a/diesel/src/type_impls/tuples.rs
+++ b/diesel/src/type_impls/tuples.rs
@@ -156,11 +156,11 @@ macro_rules! tuple_impls {
             }
 
             #[allow(unused_assignments)]
-            impl<$($T,)+ Tab, __DB> InsertValues<Tab, __DB> for ($($T,)+)
+            impl<$($T,)+ Tab, __DB> InsertValues<__DB, Tab> for ($($T,)+)
             where
                 Tab: Table,
                 __DB: Backend,
-                $($T: InsertValues<Tab, __DB>,)+
+                $($T: InsertValues<__DB, Tab>,)+
             {
                 fn column_names(&self, mut out: AstPass<'_, '_, __DB>) -> QueryResult<()> {
                     let mut needs_comma = false;
diff --git a/diesel_derives/src/multiconnection.rs b/diesel_derives/src/multiconnection.rs
index 40293fc085d0..fde7838aad8b 100644
--- a/diesel_derives/src/multiconnection.rs
+++ b/diesel_derives/src/multiconnection.rs
@@ -1195,7 +1195,7 @@ fn generate_querybuilder(connection_types: &[ConnectionVariant]) -> TokenStream
         let ty = c.ty;
         quote::quote! {
             super::backend::MultiBackend::#ident(_) => {
-                <Self as diesel::insertable::InsertValues<Col::Table, <#ty as diesel::connection::Connection>::Backend>>::column_names(
+                <Self as diesel::insertable::InsertValues<<#ty as diesel::connection::Connection>::Backend, Col::Table>>::column_names(
                     &self,
                     out.cast_database(
                         super::bind_collector::MultiBindCollector::#lower_ident,
@@ -1214,7 +1214,7 @@ fn generate_querybuilder(connection_types: &[ConnectionVariant]) -> TokenStream
     let insert_values_backend_bounds = connection_types.iter().map(|c| {
         let ty = c.ty;
         quote::quote! {
-            diesel::insertable::DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<Col, Expr>>: diesel::insertable::InsertValues<Col::Table, <#ty as diesel::connection::Connection>::Backend>
+            diesel::insertable::DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<Col, Expr>>: diesel::insertable::InsertValues<<#ty as diesel::connection::Connection>::Backend, Col::Table>
         }
     });
 
@@ -1405,7 +1405,7 @@ fn generate_querybuilder(connection_types: &[ConnectionVariant]) -> TokenStream
             }
         }
 
-        impl<Col, Expr> diesel::insertable::InsertValues<Col::Table, super::multi_connection_impl::backend::MultiBackend>
+        impl<Col, Expr> diesel::insertable::InsertValues<super::multi_connection_impl::backend::MultiBackend, Col::Table>
             for diesel::insertable::DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<Col, Expr>>
         where
             Col: diesel::prelude::Column,


Test patch:
diff --git a/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr b/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr
index 54d0fa5ca62d..4d125ea25ee4 100644
--- a/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr
+++ b/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr
@@ -14,7 +14,7 @@ note: required for `columns::hair_color` to implement `AppearsOnTable<NoFromClau
    = note: associated types for the current `impl` cannot be restricted in `where` clauses
    = note: 1 redundant requirement hidden
    = note: required for `&columns::hair_color` to implement `AppearsOnTable<NoFromClause>`
-   = note: required for `ColumnInsertValue<columns::name, &columns::hair_color>` to implement `InsertValues<users::table, _>`
+   = note: required for `ColumnInsertValue<columns::name, &columns::hair_color>` to implement `InsertValues<_, users::table>`
    = note: required for `diesel::query_builder::insert_statement::ValuesClause<ColumnInsertValue<columns::name, &columns::hair_color>, users::table>` to implement `QueryFragment<_>`
    = note: 1 redundant requirement hidden
    = note: required for `InsertStatement<table, ValuesClause<ColumnInsertValue<name, &hair_color>, table>>` to implement `QueryFragment<_>`