Skip to content

Supertrait loops are (still) unsound #43784

Closed

Description

@arielb1

First reported in https://users.rust-lang.org/t/unexpected-behaviors-of-trait-bounds/12286/3

STR

pub trait Partial: Copy {
}

pub trait Complete: Partial {
}

impl<T> Partial for T where T: Complete {}
impl<T> Complete for T {}

fn copy<P: Partial>(p: P) -> (P, P) {
    (p, p)
}

fn main() {
    let (p, q) = copy("hello".to_string());
    drop(p);
    println!("{}", q);
}

cc @nikomatsakis - let's discuss this when you are back from vacation (unless @aturon can come up with a solution?)

Activity

  1. added
    I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Aug 10, 2017
  2. arielb1 commented on Aug 10, 2017

    @arielb1
    ContributorAuthor

    Associated types variant, which bypasses some fixes based only on supertraits:

    pub trait Partial<X: ?Sized>: Copy {
    }
    
    pub trait Complete {
        type Assoc: Partial<Self>;
    }
    
    impl<T> Partial<T> for T::Assoc where
        T: Complete
    {
    }
    
    // Project(
    impl<T> Complete for T {
        type Assoc = T;
    }
    
    fn main() {
        let (p, q) = copy::<String>("hello".to_string());
        drop(p);
        println!("{}", q);
    }
    
    fn copy<P: Complete>(p: P::Assoc) -> (P::Assoc, P::Assoc) {
        copy2(p)
    }
    
    fn copy2<P: Partial<P>>(p: P) -> (P, P) {
        (p, p)
    }
  3. scalexm commented on Aug 10, 2017

    @scalexm
    Contributor

    Chalk's strategy will solve this, but I guess that shouldn't be extremely difficult to fix even with the current strategy. The first impl is valid:

    impl<T> Partial for T where T: Complete {}

    since T: Complete indeed implies that T: Copy.

    The second however, is not:

    impl<T> Complete for T {}

    the impl declaration should be able to prove that T: Partial holds (ok because of the first impl), but also that T: Partial is well-formed, i.e. that T: Copy holds.

    Same thing in the second example, this impl declaration:

    impl<T> Complete for T {
        type Assoc = T;
    }

    should prove that Self::Assoc: Partial<Self> (ok) and that Self::Assoc: Partial<Self> is well-formed, i.e. Self::Assoc: Copy. The latter is not being proved currently.

  4. nikomatsakis commented on Aug 24, 2017

    @nikomatsakis
    Contributor

    triage: P-high -- has pending fix

  5. added a commit that references this issue on Aug 25, 2017
    426711d
  6. added a commit that references this issue on Feb 15, 2021
  7. added 2 commits that reference this issue on Feb 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-highHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions