Closed sweirich closed 5 years ago
This is also important when there are associated types:
trait FIndex {
type Output : ?Sized;
fn findex(&self, i:usize) -> &Self::Output;
}
impl FIndex for [u8] {
type Output = u8;
fn findex(&self, i:usize) -> &u8 {
&self[i]
}
}
When I match up the implementation of the trait, I need to know what the type Output
is for that implementation. The information that "type Output<[u8]> = u8" doesn't appear in mir-json.
I think the JSON now contains all the information that's necessary to resolve trait-method calls. There's a new impls
array at top level that contains information on each trait impl in the crate. (It currently doesn't include inherent impls, because inherent method calls are already resolved, but I don't think it would be hard to add them if necessary.)
An impls
entry looks like this (from your first example above):
{
"name": "::{{impl}}[0]",
// Indicates the trait this impl implements. `substs` gives the type
// arguments for the trait, which may refer to the type parameters of the
// impl.
"trait_ref": {
"substs": [
{ "kind": "Adt", "name": "::S[0]", "substs": [] }
],
"trait": "::T[0]"
}
// Generics (and predicates) for the impl block, for `impl<T: Clone> ...`.
"generics": {
"params": []
},
"predicates": {
"predicates": []
},
// The impl-item definitions.
"items": [
{
"kind": "Method",
// The def path of the impl-item. For `Method`s, this should match
// the name of the corresponding entry in `fns`.
"name": "::{{impl}}[0]::g[0]",
// The def path of the trait-item that this impl-item implements.
// If there is no impl-item that `implements` a particular
// trait-item, that means the impl uses the default from the trait.
"implements": "::T[0]::g[0]",
// Generics for the method itself. For `Method`s, these should
// match the generics of the `fn`. This consists of the generics
// inherited from the impl (if any), followed by any generics
// declared on the impl-item itself.
"generics": {
"params": []
},
"predicates": {
"predicates": []
},
// The `signature` field is specific to `Method`s.
"signature": {
"inputs": [],
"output": { "kind": "Uint", "uintkind": { "kind": "u32" } }
}
}
],
},
Now for an example like this:
trait T {
fn g<B>();
fn h<B>() {}
}
impl<A> T for Vec<A> {
fn g<B>() {}
// Use default for `h`
}
fn f() {
// In crux-mir, this is `::T::g::<Vec<u8>, bool>()`
<Vec<u8> as T>::g::<bool>();
<Vec<u8> as T>::h::<bool>();
}
Resolution of the call to T::g
can be done as follows:
::T::g
, which is ::T
. Split the type arguments at the call site into the trait args and method args. In this case, the trait has 1 type parameter (Self
), so the first type argument (Vec<u8>
) is for the trait, and the remaining argument (bool
) is for the method.trait_ref.trait
is ::T
and whose trait_ref.substs
unify with the trait arguments. In this case, that's ::{{impl}}[0]
, and unification assigns u8
to the impl's type parameter A
.items
array whose implements
field references the trait method being called (::T::g
). This item is called ::{{impl}}[0]::g
.::{{impl}}[0]::g
, with type arguments <u8, bool>
. The u8
comes from the impl type arguments found by unification, and the bool
is from the method type arguments.And for T::h
:
items
that implements
::T::h
, because the impl is using the default from the trait declaration.::T::h
, with type arguments <Vec<u8>, bool>
, which are exactly the original trait and method type arguments from the call site.I haven't looked closely at associated type projections, but hopefully resolving those should work similarly.
Thanks!
I've noticed that "implements" is not always included with every item.
For example, given this trait declaration
pub trait Def: Sized {
fn def() -> Self;
}
the following impl conforms to your description above
impl Def for u8 {
#[inline]
#[doc = "Returns default value of `0`"]
fn def() -> u8 { 0 }
}
but if I use a macro to generate the impl, then I don't get the "implements" component of the item
macro_rules! default_impl {
($t:ty, $v:expr, $doc:tt) => {
impl Def for $t {
#[inline]
#[doc = $doc]
fn def() -> $t { $v }
}
}
}
default_impl! { (), (), "Returns the default value of `()`" }
I believe this is fixed - mir-json
now produces implements
fields for both impl items in your example.
This is a bit obscure so not high priority. Trait methods can be called using a static type. However, mir-json does not include the right name in the output.
For example, this module (from mir-json's test/conc_eval/traits/static_two.rs) defines a trait with two different implementations.
In the output, the two implementations are called {{impl}}[0] and {{impl}}[1] respectively, but there is no associations between these names and the types. However, the type argument in the body of f is the only way to tell which function should be called.