Florian
Florian

Reputation: 170

Problem with value arguments in const fn with basic numeric generics

I'm trying to translate some of my C++ code into Rust and came across the following problem. The code is simplified to a (hopefully) minimal not-working example. In the end it is supposed to work with all unsigned integer types, but for this example it just needs to implement the PartialOrd trait.

#![allow(incomplete_features)]  
#![feature(generic_const_exprs)]
#![feature(const_trait_impl)]   


const fn foo<T>(n: T, k: T) -> T                                       
where                                                                   
    T: Sized,                                                           
    T: Copy,
    T: ~const core::marker::Destruct,
    T: ~const std::cmp::PartialOrd,                            
{                                                                       
    if n < k {                                                          
        n
    } else {
        k
    }
}                                                                       

Fails to compile with the following error message:

error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
 13 |     if n < k {                                                          
    |        ^

If I replace the arguments n and k with references, it compiles. Turns out, the functions in the PartialOrd are also implemented using references. So from my understanding, the expression 2 < 4 will call the le function with references. For performance reasons, I doubt that's what's happening, though.

It's actually two questions that I'm asking:

  1. Can I solve the error without using references?
  2. Why is PartialOrd using references while Ord uses values (at least for min and max, but not for cmp)?

Upvotes: 1

Views: 121

Answers (1)

Marcus Dunn
Marcus Dunn

Reputation: 580

  1. Adding #![feature(const_refs_to_cell)] makes it compile.
  2. min and max take Self because they return one of the two arguments as Self. Other methods in Ord and PartialOrd else returns a bool or an Ordering so they can take by reference. if min and max they took by reference the signature would be fn max<'a>(&'a self, other: &'a Self) -> &'a Self which you "get for free" because there is a impl<A> Ord for &A where A: Ord.

Upvotes: 2

Related Questions