Replies: 5 comments
-
yes, the analysis is unsound in the presence of trait bounds. We don't have concrete plans to work on it but we would definitely like to tackle it at some point. We just have other projects in mind and resources are limited. It will make a fantastic project if someone wants to get involved! I do have some ideas though. It all boils down to how you interpret The first one is that we can interpret Under this reading, This leaves space to be able to implement traits on other refinement types not just the trivial one. For example, you could do Another idea that is still very vague in my mind is to interpret trait impls using what I call a shape. A shape is what you get when you strip all refinements out of a type, i.e., a plain rust type. You could then interpret Footnotes
|
Beta Was this translation helpful? Give feedback.
-
Thank you for the detailed reply, interesting thoughts! This seems like a challenging problem indeed. (As a side note, I'm really fascinated by this project, thanks for working on it!) A thought for a 'hack' to fix soundness: Have you played around with the thought of restricting polymorphic refinements as soon as a trait bound is introduced? I.e., the current A second thought, this time about your first idea:
Both questions seem quite important to me, so what if instead of allowing whole different method Maybe an example to illustrate this idea: Without knowledge of Flux's inner workings, I would assume something like the following to happen: From Rust, Flux sees that An (admittedly) significant downside to this approach is that I don't know how a user could specify a precondition to fn swap<T: MyTrait, q: predicate>(&mut T{v: q(v)}, &mut T{v: q(v)}) requires precondition(q, T, MyTrait) {...} where With this signature, Flux could only infer some supertype of (Another downside to this, I suppose, is that standard library methods probably aren't valid Flux anymore?) |
Beta Was this translation helpful? Give feedback.
-
Something like this wouldn't be too hard to implement, at least to handle the example in the op. You have the right intuition, but the details are a bit different. When you have a function
This feels similar in spirit to the shape idea. You could also introduce bounds using shapes, e.g., saying Anyhow, agree that you need some form of constraining the refinements the trait is being implemented on. I also fancy the idea of using more parametric predicates. For example, one thing I know we will need is associated predicates. I have an example in mind where you want to refine the pub trait Index<Idx> {
type Output;
predicate p: (Self, Idx) -> bool;
fn index(&self, index: Idx{Self::p(index)}) -> &Self::Output;
}
impl<T> Index<usize> for RVec<T> {
type Output = T;
predicate p = |vec, index| 0 <= index && index < vec.len;
fn index(&self: RVec<T>[@vec], index: usize{0 <= index && index < vec.len}) -> &T { ... }
} This hides a lot of complexity and it touches on some recent progress we've been making around polymorphic sorts |
Beta Was this translation helpful? Give feedback.
-
Exciting stuff! I will definitely be following the progress :) Feel free to close this issue if you're already tracking this somewhere/have other plans |
Beta Was this translation helpful? Give feedback.
-
I'm converting this into a discussion because it has interesting context, but there's no specific issue. |
Beta Was this translation helpful? Give feedback.
-
Inspired by the Flux paper's usage of the std library
swap<T>(&mut T, &mut T)
function, I was curious why/how Flux was able to pass refinements through the function. I think I reached a conclusion in that one cannot do anything with aT
, just move it around, so whatever refinement inputswap
gets, it will be preserved through to the output.I came up with the following example that still has a
T
, but actually changes the T, meaning a generic refinement input can not in general be preserved to the output:In contrast to the paper's function,
T
is now aMyTrait
, with which I can "arbitrarily" modify the values, in particular, refinements from the input may not hold anymore, and indeed,test
is not type safe.What is Flux's story for this (or rephrased, are there plans to support this)? On my system, using commit d64a0a3, running
rustc-flux --crate-type=lib file.rs
results in no errors and0
exit code, however, the playground reports an invisible error: link.(Replacing the MyTrait stuff with just
T: Default
and*a = Default::default()
results in a compiler panic:crates/flux-refineck/src/type_env.rs:143:13: cannot move out of *_1
)Beta Was this translation helpful? Give feedback.
All reactions