Problem statement:
Right now rust treats all owned types like String as having 'static lifetime, meaning rust in terms of borrow checking sees &'static str and String as same. This creates issues when we try to make a structure that is polymorphic over some type parameter S that could be a string slice reference or owned String.
Diagnostics:
1. `check` does not live long enough
borrowed value does not live long enough [E0597]
2. argument requires that `check` is borrowed for `'s` [E0597]
3. the parameter type `S` may not live long enough
...so that the type `S` will meet its required lifetime bounds [E0309]
Proposed solution is owned lifetime that is allowed only for non-reference types, therefore any reference outlives 'owned, because we know that structure with 'owned type does not hold any references to initial data, making a copy.
True, but Cow is runtime solution. Each time you want to touch field in structure that is Cow you have to check whatever it is borrowed or owned. In my case I want to have functions that are generated once for specific case: one for some reference type like string slice and then another one for owned String. This way we don`t have branching or some vtable dispatch on each value access.
you are constructing an &'a Foo<'a> which is a common mistake, that causes self to be "borrowed forever".
if you change it to just self: &Self it compiles: Rust Playground
In this particular case yes, however consider this example with general clone_with_string_type function that accepts another generic parameter for new string type Rust Playground, in this case we have to specify lifetimes because new string type (NS) can potentially also be a reference. So we can have multiple conversions: &'static str -> String, &'buffer str -> String, &'static str -> &'buffer str, etc.
I'm not sure why you're trying to write this contrived example, but you can fix it again by:
not having clone_with_string_type take a &'s1 Check<'s1, S>; there is no need to link the lifetime of the self reference to the lifetime that can be used to create an instance of S, simply because you are not creating a new instance of S. Use a separate lifetime untied to 's1 instead.
removing the 's lifetime parameter from Check: its usage along with the PhantomData signals to the borrow checker that Check holds some unknown reference with lifetime 's possibly unrelated to S, and this prevents any way to extend such lifetime when you know that S: AsStr<'longer_lifetime>.
therefore any reference outlives 'owned
This doesn't make sense to me. Something that is owned can live forever, and if any reference can outlive it then you get that any reference can live forever, which is obviously false.
It would allow "fixing" your code above only because it would make the type system unsound. I don't see how any sound implementation of this 'owned lifetime concept would fix your code.
What I`m trying to do is to parametrize certain structures, so that I could create one static instance of structure and one runtime instance of structure and have some code that can accept either one.
Also I need ability to go from static structure to runtime structure, have ability to clone it into runtime one, that I can pass around freely. Your fix indeed works however I encountered another problem when I tried to fit it with Sequence parameterized type Rust Playground.
I replaced phf::OrderedSet with &'static [T] because playground does not support dependencies, but idea stays the same.
In runtime I use VecSequence, but certain structures are initialized as static using PhfOrderedSetSequence, and at certain point I need to clone it into VecSequence.
You are using the lifetime 's3 both for the lifetime of the strings that can be used to create a NS and as the lifetime somehow connected to V (I'm not sure why you need that lifetime parameter on Sequence though). The latter forces the lifetime to be attached to the type, leading to the same issue as before. However there's no reason for these lifetimes to be the same, just use a different lifetime: Rust Playground
My idea with this lifetime was that it could only be used in bounds for generic type parameters, you cant make a reference with this lifetime, therefore all owned structures would be of lifetime 'owned. Because right now &'buffer str -> &'static str and &'buffer str -> String are identical to the borrow checker, but it is incorrect, because in first case it is invalid since generic 'buffer does not outlive 'static, while in second case 'buffer could be any lifetime since String makes a copy and does not hold any references to previous structures.
&'buffer str -> &'static str was just an example of incorrect semantics if we assume no copy, just coercion or some sort of reference. In general case we would have &'buffer str -> &'buffer2 str where 'buffer2 outlives 'buffer. If I have generic function over some String type that implements AsStr(see code snippet above), then I forced to add bounds 'buffer2: 'buffer, because potentialy output type could be a reference and in first case that I specified it makes sense. However there if I try to pass <'static, String> parameters to such function I will get borrow checker error, because again borrow checker cannot distinguish between &'static str and owned String type. 'buffer value could go out of scope immediately after a function is invoked and everything will be fine because String copied the data, it does not hold any references. The reason I have to explicitly specify lifetime is because I have generic Sequence and Dictionary traits that expect them to specify the lifetime of elements in them.
I feel like you might want to explore higher-ranked trait bounds, or, as others have said, use multiple lifetime parameters. Your initial example is more-or-less asking for a &'static &'static str or a &'static String when you use Check<'static, &'static str> or Check<'static, String>. Using the same one lifetime parameter for everything is really limiting.
Either you assume you can make a copy, and hence &'buffer str -> &'static str is also possible, or you don't assume you can make a copy, and hence &'buffer str -> String is a type error because the two types are different.
The thing is in general case if we have just S String type and NS String type that implements some trait AsStr, borrow checker has to assume that NS can still possibly borrow from S. My AsStr trait wants to borrow if it goes from &str to &str just with different lifetime and make a copy if it goes from &str -> String. Because we have trait abstraction, String also needs to have some lifetime to pass into AsStr trait, right now it is static but I think it should be this new owned lifetime. Owned lifetime represents absence of lifetime in a way. When we go from &'buffer str -> String, String does not hold any references, therefore we can say that it has a reference that is shorter than any lifetime. But now String can only have 'static lifetime which means it borrows something that lives till the end of the program which is not correct.
This sounds like you want, for any 'a and 'b such that 'a: 'b, to be able to convert from &'a str to &'b str, and to be able to convert from &'a str to String.
You don’t need to fill in a unique minimum 'b for the String case. You could just say that any'b works. This is more-or-less how I abstract over “there’s a particular minimum” and “there’s no minimum” in my own crates.
This is why I brought up higher-ranked trait bounds (in this case for<'b>).