0

I'm trying to figure out the rules for which version of a function Rust will use inside of a trait implementation. Specifically, there are functions implemented here that I want to forward to from my own trait.

When I define a trait T with a function sin; I want the implementation of T for Complex64 to refer to the implementation of sin in the num::complex crate, but attempting to do so results in infinite recursion.

This problem led me to try to figure out what it is that makes the call recursive, rather than referring to the existing function. My test cases are below (playground link); I've tried implementing a trait on an existing type, a new type, and a generic struct, but all those cases seem to forward correctly to the existing implementation.

What is special about Complex64 that it causes recursion? Is there any way around this?

extern crate num;
use num::complex::*;

use std::fmt::Debug;
use std::marker::PhantomData;

// Vanilla struct
struct S { }

// Generic struct
struct G<K> { _g: PhantomData<K> }

// Trait with a function we want to forward to existing implementations
trait T {
    fn sin(self) -> Self;
}

// Existing implementation for vanilla struct
impl S {
    fn sin(self) -> Self { println!("Outside Version"); S {} }
}

// Existing implementation for generic struct
impl<K: Debug> G<K> {
    fn sin(self) -> Self { println!("Outside (generic)"); G { _g: PhantomData } }
}

// Forwarding for vanilla struct
impl T for S {
    fn sin(self) -> Self { self.sin() }
}

// Forwarding for generic struct
impl T for G<f32> {
    fn sin(self) -> Self { self.sin() }
}

// Forwarding for primitive type
impl T for f32 {
    fn sin(self) -> Self { let x = self.sin(); println!("{}", x); x }
}

// Forwarding for externally defined type
// NOTE: for this impl only, we get a warning about unconditional recursion
impl T for Complex64 {
    fn sin(self) -> Self { let x = self.sin(); println!("{}", x); x }
}

// Function to ensure we're using the version of sin defined in T
fn do_sin<K: T>(k: K) {
    k.sin();
}

fn main() {
    let x = S {};
    let y = 1.2f32;
    let z: G<f32> = G { _g: PhantomData };
    let w = Complex64 { re: 1.0, im: 2.0 };
    do_sin(x); // forwarding works
    do_sin(y); // forwarding works
    do_sin(z); // forwarding works
    do_sin(w); // forwarding fails with infinite recursion
}
Isaac
  • 3,586
  • 1
  • 18
  • 20

0 Answers0