The type parameter `I` is not constrained by the impl trait, self type, or predicates

I have this trait

pub trait VariableAnalysis<'a, I> where I : Iterator<Item = &'a char> { 
  // ...
}

I have done

struct Expression;

impl<'a,I> VariableAnalysis<'a, I> for Expression where Term : VariableAnalysis<'a, I> ,I : Iterator<Item = &'a char> {
// ..
}

That all works , also compiles. But then I try to use it in

impl<'a, I> std::ops::Div for Expression where Self : VariableAnalysis<'a, I> , I: Iterator<Item = &'a char> {
    type Output = Self;
    fn div(self,other : Expression) -> Self::Output  {
        // ..
    }
}

The trait bounds are correct but I get error

error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates
   --> arkley_algebra\src\arithmetics\div.rs:137:9
    |
137 | impl<'a,I> std::ops::Div for Expression where Self : VariableAnalysis<'a,I> , I : Iterator<Item = &'a char>  {
    |         ^ unconstrained type parameter

I don't understand is I not constrained by impl and self ?

impl<'a,I> VariableAnalysis<'a, I> for Expression ... says that VariableAnalysis is be implemented for any 'a and I that satisfy the bounds. In the Div implementation, there is no means by which a caller of div() can choose which of those iterator types should apply.

Usually when this comes up, it means you need the trait to have an associated type instead of a type parameter. However, that likely does not apply straightforwardly here given the lifetime 'a.

If you show us more of what the trait does (unredact those // ..), we might be able to give a better suggestion.

The trait is just

use std::collections::{BtreeMap,BtreeSet};
pub trait VariableAnalysis<'a, I> where I : Iterator<Item = &'a char>  {
    fn get_unique_variables(&self) -> BTreeSet<&char>;
    fn contains_any_variable(&self,variables : I) -> bool;
    fn contains_variable(&self, variable: &char) -> bool;
    fn contains_all(&self,variables : I) -> bool;    
}
// Where for eg 

pub type Variables = BTreeMap<char,f64>;

struct Term {
    pub(crate) coefficient: f64,
    pub(crate) variables: Variables,

}// cuz expression doesn't use any iter stuff only this base class rly uses it rn

impl<'a,I> VariableAnalysis<'a, I> for Term where I : Iterator<Item = &'a char> {
    fn get_unique_variables(&self) -> BTreeSet<&char> {
        self.variables.keys().collect()   
    }

    fn contains_any_variable(&self,mut variables : I) -> bool {
        variables.any(|key| self.variables.contains_key(key))
    }

    fn contains_all(&self,mut variables : I) -> bool {
       variables.all(|c| self.variables.contains_key(c))
    }

    fn contains_variable(&self, variable: &char) -> bool {
        self.variables.contains_key(variable)
    }
}

The goal for I is to be able to call the functions like contains_any_variable , with any iteratable thing (eg Vec , slice , btreeset etc)

Edit : A bit of a workaround is to put claus at the end of each function (not optimal but works)

pub trait VariableAnalysis {
    fn get_unique_variables(&self) -> BTreeSet<&char>;
    fn contains_any_variable<'a,I>(&self,variables : I) -> bool where I : Iterator<Item = &'a char>;
    fn contains_variable(&self, variable: &char) -> bool;
    fn contains_all<'a,I>(&self,variables : I) -> bool where I : Iterator<Item = &'a char>;    

}

This isn't a workaround — it's the correct choice, because whether and how VariableAnalysis is implemented doesn't depend on the iterator type. If it's implemented at all, it works with every iterator.

Also, you should stop using &char as the item type — there is no point in passing small types like that by reference. Pass char instead; it may be be more efficient, and it will certainly be more convenient to avoid the lifetime parameters. Convert iterators to fit this like so: .iter().copied().

1 Like

Also, you should stop using &char as the item type

The reason I chose this was i use the methods very often and I only need to compare the items with each other basically like &char == &'.' . So in that case I think using a reference is much better (but I may be wrong)

There are no benefits to comparing references instead of char == '.'.

1 Like

Oh then I will remove try to remove all those &char references that I have used (yup ive used alot of them :sweat_smile:)

There isn't a good reason to ever do that. It's unnecessary complexity for no benefit.