Skip to content

Mismatched assumptions for interaction between associated type and lifetime in trait #24622

Closed

Description

@huonw
pub trait Foo<'a> {
    type Bar: std::fmt::Debug;
    fn baz(&'a self) -> Self::Bar;
}

pub struct X {
    name : String,
}

impl<'a> Foo<'a> for X {
    type Bar = &'a String;
    fn baz(&'a self) -> &'a String {
        &self.name
    }
}

pub fn foo<T: for<'a> Foo<'a>>(x: T) {
    let y = x.baz();
    drop(x);
    // for T = X, this is a &String pointing to dropped memory
    println!("{:?}", y); 
}

pub fn main() {
    foo(X { name: "foo".to_string() });
}

This segfaults.

The impl is allowing &'a String because 'a is in scope, but the use in foo assumes that Bar is independent of 'a.

(Noticed in http://stackoverflow.com/q/29745134/1256624 .)

Activity

  1. huonw commented on Apr 20, 2015

    @huonw
    ContributorAuthor

    triage: P-high

    cc @nikomatsakis

  2. bluss commented on Apr 20, 2015

    @bluss
    Contributor

    petgraph uses this kind of trait to provide generic "neighbor vertex" iterators.

  3. arielb1 commented on Apr 21, 2015

    @arielb1
    Contributor

    I think a cleaner example is:

    pub trait Foo<'a> {
        type Bar;
    }
    
    impl<'a, T> Foo<'a> for T { type Bar = &'a T; }
    
    fn denormalise<'a, T>(t: &'a T) -> <T as Foo<'a>>::Bar {
        t
    }
    
    pub fn free_and_use<T: for<'a> Foo<'a>,
                        F: for<'a> FnOnce(<T as Foo<'a>>::Bar)>(x: T, f: F) {
        let y;
        'body: loop { // lifetime annotations added for clarity
            's: loop { y = denormalise(&x); break }
            drop(x);
            return f(y);
        }
    }
    
    pub fn main() {
        free_and_use("foo".to_string(), |s| println!("{}", s));
    }

    It is clear here that the declaration and implementation of Foo is not doing anything wrong, but free_and_use wrongly assumes that <T as Foo<'s>>::Bar : 'body, which does not make a lot of sense.

  4. nikomatsakis commented on Apr 24, 2015

    @nikomatsakis
    Contributor

    Yes, I see the problem. It lies in some of the logic around type parameter outlives rules -- we assume type parameters outlive the current fn, and we assume the same of projections, which is clearly wrong. I've been wanting to revisit these rules about projections and how long they live (#23442) though not for soundness reasons.

  5. nikomatsakis commented on Apr 24, 2015

    @nikomatsakis
    Contributor

    triage: P-high

  6. added
    P-highHigh priority
    and removed on Apr 24, 2015
  7. self-assigned this
    on Apr 24, 2015
  8. nikomatsakis commented on May 28, 2015

    @nikomatsakis
    Contributor

    Just FYI -- I've been working steadily on this. I'm going to try and writeup my thoughts "soon" (famous last words).

  9. added
    T-langRelevant to the language team
    on Jun 5, 2015
  10. 2 remaining items

  11. added 5 commits that reference this issue on Jul 6, 2015
    9c0413b
    970a3a3
  12. nikomatsakis commented on Nov 5, 2015

    @nikomatsakis
    Contributor

    This original example is now giving me an error on stable: http://is.gd/bidora

    The question is, did we add a test?

  13. nikomatsakis commented on Nov 5, 2015

    @nikomatsakis
    Contributor

    The test associated-types-outlives.rs claims to be a regression test for this issue. Closing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-associated-itemsArea: Associated items (types, constants & functions)A-lifetimesArea: Lifetimes / regionsA-trait-systemArea: Trait systemP-highHigh priorityT-langRelevant to the language team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions