Error: parameter `T` is never used [E0392], but I use it

pub struct ActionResult<T, C: Change<T>, E: Event> {
    change: C,
    event: E,
}

Constraints don't count as "using" a type parameter. You have to actually use it as part of one of the fields.

Simplest way is to just add a _marker: PhantomData<T> member, though that depends on what exactly Change<T> means relative to T. PhantomData<X> basically means "pretend I have an X here, but don't actually make one".

At this point you can also consider the question if the type parameter in Change should instead be an associated type. I'm not saying it has to be, but it's something that simplifies if it is.

How to understand when I need associated type or generic type parameter?

Associated type means: for each impl there's only one fitting type.

For example, Iterator::Item is an associated type, which means that every iterable type can be iterated in only one way, yielding a specific type of item.

In traits like Add you have both combined: Add<Other> with associated type Output. The meaning is: you can potentially have multiple impls, to be able to add values of different types to your type, but the output of the addition is determined by the two input types.

2 Likes

How to make this code works?

use std::borrow::BorrowMut;

pub trait Value {
    fn get(&self) -> i32;
    fn set(&mut self, value: i32);
}

pub struct UnmanagedValue {
    value: i32,
}

impl Value for UnmanagedValue {
    fn get(&self) -> i32 {
        self.value
    }
    
    fn set(&mut self, value: i32) {
        self.value = value;
    }
}

pub struct ManagedValue {
    value: i32,
}

impl Value for ManagedValue {
    fn get(&self) -> i32 {
        self.value
    }
    
    fn set(&mut self, value: i32) {
        if self.value == value {
            return;
        }
        self.value = value;
    }
}

pub struct SetValueAction {
    value: i32,
}

pub trait Action<T>: Sized {
    fn execute(self, target: &mut T);
}

impl<V: Value, T: BorrowMut<V>> Action<T> for SetValueAction {
    fn execute(self, target: &mut T) {
        target.borrow_mut().set(self.value);
    }
}

fn main() {
}

Error:

<anon>:47:6: 47:7 error: the type parameter `V` is not constrained by the impl trait, self type, or predicates [E0207]
<anon>:47 impl<V: Value, T: BorrowMut<V>> Action<T> for SetValueAction {

The issue with this code is: if T happens to implement BorrowMut<Foo> and BorrowMut<Bar> what does target.borrow_mut() return?

And Foo: Value and Bar: Value? It is impossible case. It Is forbidden.

I don't think there's a way to express that constraint. That's the difference between input and output/associated types. You can implement Borrow<X> for Z and Borrow<Y> for Z but you can only implement Deref for Z once with a single Target associated type.

@gkoz It is unavailable because of lack of feature in type system. This should be fixed.

Or please someone show me another way (correct way).

I opened issue [E0207] if type parameter used only in impl constraints · Issue #33374 · rust-lang/rust · GitHub because I think that it is lack or a bug.

You can move the BorrowMut bound to the Action trait.

pub trait Action<V, T: BorrowMut<V>>: Sized {
    fn execute(self, target: T);
}

impl<V: Value, T: BorrowMut<V>> Action<V, T> for SetValueAction {
    fn execute(self, mut target: T) {
        target.borrow_mut().set(self.value);
    }
}

Doing this, you do not need target to be a reference (you can still pass a mutable reference because &mut T implements BorrowMut<T>).

You are wrong. I can, but I don't want because of two reasons:

  • I may want to implement Action for SomeType: Value instead of composition. I may want. My library users may want. It is not bad.
  • Action shouldn't be binded to that. Action is something that may be applied to some target. That's it. Everything else is implementation details.

That's what an associated type is generally for. BorrowMut is a trait implemented in std, so you are not allowed to assume that it does not have random impls.