Skip to content

Instantly share code, notes, and snippets.

@sgrif

sgrif/bug.rs Secret

Created December 3, 2017 19:54
Show Gist options
  • Save sgrif/48bf08a27b3da35a44ac085cada0622c to your computer and use it in GitHub Desktop.
Save sgrif/48bf08a27b3da35a44ac085cada0622c to your computer and use it in GitHub Desktop.
pub trait DistinctDsl {
type Output;
fn distinct(self) -> Self::Output;
}
#[derive(Default)]
pub struct SelectStatement<D = NoDistinctClause, FU = NoForUpdateClause> {
distinct: D,
for_update: FU,
}
impl<FU> SelectStatement<NoDistinctClause, FU> {
pub fn for_update(self) -> SelectStatement<NoDistinctClause, ForUpdateClause> {
SelectStatement {
distinct: self.distinct,
for_update: ForUpdateClause,
}
}
}
pub struct DistinctClause;
#[derive(Default)]
pub struct NoDistinctClause;
pub struct ForUpdateClause;
#[derive(Default)]
pub struct NoForUpdateClause;
impl<D> DistinctDsl for SelectStatement<D> {
type Output = SelectStatement<DistinctClause>;
fn distinct(self) -> Self::Output {
SelectStatement {
distinct: DistinctClause,
for_update: self.for_update,
}
}
}
pub trait AsQuery {
type Query;
fn as_query(self) -> Self::Query;
}
impl<D, FU> AsQuery for SelectStatement<D, FU> {
type Query = Self;
fn as_query(self) -> Self::Query {
self
}
}
pub trait SelectStatementDefinitelyDoesntImplementMe: AsQuery {}
// This is the thing that causes problems. Since `DistinctDsl` is implemented only when the `FU`
// slot is a specific type, someone could theoretically write `impl<D>
// SelectStatementDefinitelyDoesntImplementMe for SelectStatement<D, MyLocalType>`, which *would*
// make this infinitely recursive. However, that case gets evaluated even when we are looking at
// the concrete type `SelectStatement<NoDistinctClause, ForUpdateClause>, which we can definitively
// say *does not* implement `SelectStatementDefinitelyDoesntImplementMe`
impl<T> DistinctDsl for T
where
T: SelectStatementDefinitelyDoesntImplementMe,
T::Query: DistinctDsl,
{
type Output = <T::Query as DistinctDsl>::Output;
fn distinct(self) -> Self::Output {
self.as_query().distinct()
}
}
pub fn stuff() {
// UFCS is important here. If we use the method syntax, it just resolves to the method not
// existing (this discrepancy is incredibly annoying, the overflow should either not be masked
// there, or we should consistently treat overflow as "this impl doesn't apply")
DistinctDsl::distinct(SelectStatement::default().for_update())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment