Skip to content

Function parameter type resolution incorrect when multiple generics used #134387

@ambaxter

Description

@ambaxter

I tried this code:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9788298bae9b348de0833cd9b125c70e

use smallvec::SmallVec;
use std::iter::repeat_n;
use std::iter::RepeatN;
use std::ops::Index;

#[derive(Debug, Copy, Clone)]
pub enum EndMasks {
    L(u8),
    R(u8),
    BOTH(u8, u8),
}

#[derive(Debug, Copy, Clone)]
pub struct FindResults {
    index: usize,
    end_masks: EndMasks,
}

pub enum FindEnds<F>
where
    F: Fn(u8, u8) -> Option<(u8, u8)>,
{
    Either(u8, u8),
    Both(F),
}

pub trait LenTrait {
    fn len(&self) -> usize;
}

impl LenTrait for [u8] {
    fn len(&self) -> usize {
        self.len()
    }
}

impl LenTrait for Vec<u8> {
    fn len(&self) -> usize {
        self.len()
    }
}

#[derive(Debug, Clone, Copy)]
pub struct BMRepeatPattern {
    byte: u8,
    len: usize,
}

impl BMRepeatPattern {
    #[inline]
    pub fn new(byte: u8, len: usize) -> BMRepeatPattern {
        BMRepeatPattern { byte, len }
    }
}

impl LenTrait for BMRepeatPattern {
    #[inline]
    fn len(&self) -> usize {
        self.len
    }
}

impl Index<usize> for BMRepeatPattern {
    type Output = u8;
    #[inline]
    fn index(&self, idx: usize) -> &u8 {
        assert!(idx < self.len);
        &self.byte
    }
}

impl<'a> IntoIterator for &'a BMRepeatPattern {
    type Item = &'a u8;
    type IntoIter = RepeatN<&'a u8>;

    fn into_iter(self) -> Self::IntoIter {
        repeat_n(&self.byte, self.len)
    }
}

#[derive(Debug, Clone, Copy)]
pub struct BMRepeatBadCharShiftMap {
    pattern: BMRepeatPattern,
}

impl BMRepeatBadCharShiftMap {
    #[inline]
    pub fn new(pattern: BMRepeatPattern) -> Self {
        Self { pattern }
    }
}

impl Index<u8> for BMRepeatBadCharShiftMap {
    type Output = usize;

    fn index(&self, index: u8) -> &Self::Output {
        if self.pattern.byte == index {
            &0
        } else {
            &self.pattern.len
        }
    }
}

#[derive(Debug)]
pub struct BMRepeat {
    bad_char_shift_map: BMRepeatBadCharShiftMap,
    pattern: BMRepeatPattern,
}

impl BMRepeat {
    pub fn new(byte: u8, len: usize) -> BMRepeat {
        let pattern = BMRepeatPattern::new(byte, len);
        let bad_char_shift_map = BMRepeatBadCharShiftMap { pattern };
        BMRepeat {
            bad_char_shift_map,
            pattern,
        }
    }
}


impl BMRepeat {
    pub fn find_first_in<'a, T, F>(&'a self, text: &'a T, e: FindEnds<F>) -> Option<FindResults>
    where
        T: Index<usize, Output = u8> + LenTrait + ?Sized,
        &'a T: IntoIterator<Item = &'a u8>,
        <&'a T as IntoIterator>::IntoIter: Sized + DoubleEndedIterator + ExactSizeIterator,
        F: Fn(u8, u8) -> Option<(u8, u8)>,
    {
        find_spec(text, &self.pattern, &self.bad_char_shift_map, 1, e)
            .first()
            .copied()
    }
}

pub fn find_spec<'a, TT: 'a, TP: 'a, F>(
    text: &'a TT,
    pattern: &'a TP,
    bad_char_shift_map: &BMRepeatBadCharShiftMap,
    limit: usize,
    e: FindEnds<F>,
) -> SmallVec<[FindResults; 1]>
where
    TT: Index<usize, Output = u8> + LenTrait + ?Sized,
    &'a TT: IntoIterator<Item = &'a u8>,
    <&'a TT as IntoIterator>::IntoIter: Sized + DoubleEndedIterator + ExactSizeIterator,
    TP: Index<usize, Output = u8> + LenTrait + ?Sized,
    &'a TP: IntoIterator<Item = &'a u8>,
    <&'a TP as IntoIterator>::IntoIter: Sized + DoubleEndedIterator + ExactSizeIterator,
    F: Fn(u8, u8) -> Option<(u8, u8)>,
{
    unimplemented!()
}

fn main() {
    
}

I expected to see this happen:

Compiler correctly identifies the types used in the function

Instead, this happened:

error[E0308]: mismatched types
   --> src/main.rs:136:25
    |
129 |     pub fn find_first_in<'a, T, F>(&'a self, text: &'a T, e: FindEnds<F>) -> Option<FindResults>
    |                              - expected this type parameter
...
136 |         find_spec(text, &self.pattern, &self.bad_char_shift_map, 1, e)
    |         ---------       ^^^^^^^^^^^^^ expected `&T`, found `&BMRepeatPattern`
    |         |
    |         arguments to this function are incorrect
    |
    = note: expected reference `&T`
               found reference `&BMRepeatPattern`
note: function defined here
   --> src/main.rs:142:8
    |
142 | pub fn find_spec<'a, TT: 'a, TP: 'a, F>(
    |        ^^^^^^^^^
143 |     text: &'a TT,
144 |     pattern: &'a TP,
    |     ---------------

This error is fixed if I explicitly set the function types

    pub fn find_first_in<'a, T, F>(&'a self, text: &'a T, e: FindEnds<F>) -> Option<FindResults>
    where
        T: Index<usize, Output = u8> + LenTrait + ?Sized,
        &'a T: IntoIterator<Item = &'a u8>,
        <&'a T as IntoIterator>::IntoIter: Sized + DoubleEndedIterator + ExactSizeIterator,
        F: Fn(u8, u8) -> Option<(u8, u8)>,
    {
        find_spec::<T, BMRepeatPattern, F>(text, &self.pattern, &self.bad_char_shift_map, 1, e)
            .first()
            .copied()
    }

Meta

rustc --version --verbose:

rustc --version --verbose
rustc 1.83.0 (90b35a623 2024-11-26)
binary: rustc
commit-hash: 90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf
commit-date: 2024-11-26
host: aarch64-apple-darwin
release: 1.83.0
LLVM version: 19.1.1

This behavior also exists in Beta and Nightly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions