Skip to content

Type inference fails even though all types are known #58517

@SeeSpring

Description

@SeeSpring
Contributor

The following code fails to compile, even though all types are known
https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=8de9e57e8de5cd8f2896f422d693f453

pub fn f(s: &str) {
    let mut it = s.split(|c: char| c == ',').fuse();
    let t = it.next().unwrap().parse::<usize>().unwrap();
}
   Compiling playground v0.0.1 (/playground)
error[E0282]: type annotations needed
 --> src/main.rs:3:13
  |
3 |     let t = it.next().unwrap().parse::<usize>().unwrap();
  |             ^^^^^^^^^^^^^^^^^^ cannot infer type for `T`
  |
  = note: type must be known at this point

error: aborting due to previous error

For more information about this error, try `rustc --explain E0282`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.

Activity

talchas

talchas commented on Feb 16, 2019

@talchas

Bisecting releases says it worked in 1.12.0, broke in 1.13.0

added
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
C-bugCategory: This is a bug.
regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.
on Feb 16, 2019
jonas-schievink

jonas-schievink commented on Feb 16, 2019

@jonas-schievink
Contributor

Technically a stable regression, so marking as such - even though nobody seems to have been hit by it. It does pretty clearly look like a bug though.

ExpHP

ExpHP commented on Feb 19, 2019

@ExpHP
Contributor

Ran cargo-bisect-rustc on the nightlies:

3c5a0fa...e9bc1ba

This is still a pretty broad range...

jonas-schievink

jonas-schievink commented on Feb 19, 2019

@jonas-schievink
Contributor

Only thing in that range that touches the typesystem seems to be #35883

Mark-Simulacrum

Mark-Simulacrum commented on Feb 19, 2019

@Mark-Simulacrum
Member

May also be related to #35656

jonas-schievink

jonas-schievink commented on Feb 19, 2019

@jonas-schievink
Contributor

Ah, I missed that one. That might be more likely, yeah (since specialization might now be involved, but before wasn't).

pnkfelix

pnkfelix commented on Feb 28, 2019

@pnkfelix
Member

triage, P-medium. (Not a soundness issue, and appears to have a straight-forward if annoying work-around of introducing a local with an explicit type.) Leaving nominated label for discussion at next T-compiler meeting.

pnkfelix

pnkfelix commented on Feb 28, 2019

@pnkfelix
Member

Discussed briefuly at T-compiler meeting. assigning to self in attempt to ensure this doesn't just get lost. (I don't want to leave it nominated for discussion again at next week's meeting.)

self-assigned this
on Feb 28, 2019
pnkfelix

pnkfelix commented on Sep 23, 2019

@pnkfelix
Member

I would like to double-check the running hypothesis that this was caused by the addition of FusedIterator in PR #35656 .

I briefly attempted to make a standalone test case that does not rely on core::str nor core::iter by transcribing the relevant traits and structure definitions, but the pieces here are pretty gnarly.

  • (Basically the choices for further minimization, as I see them, are either a bottom-up approach of trying to implement a minimal set of traits/structs from scratch that exhibit the same issue here, or a top-down approach of transcribing the relevant traits/structs from the core crate, and then ripping out as much as possible.)

Anyway, while investigating the behavior of the test itself, here are some potentially interesting observations:

  • Original bug report still reproduces: play
  • Removing the fuse() call yields a variant that compiles successfully: play
  • Replacing the closure argument passed to split with a char argument also yields a variant that compiles successfully: play
    • I would be curious to know why this is.
    • It might be due to some detail of how the two relevant impls in core::str::pattern are defined
    • Or it might have something to do with the level of distance between a concrete closure type vs the FnMut(char) -> bool in the impl declaration impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool
estebank

estebank commented on Dec 10, 2019

@estebank
Contributor

The output from #65951 might shed some light:

error[E0282]: type annotations needed
 --> file12.rs:3:23
  |
3 |     let t = it.next().unwrap().parse::<usize>().unwrap();
  |             --------- ^^^^^^ cannot infer type for `T`
  |             |
  |             this method call resolves to `std::option::Option<<Self as std::iter::Iterator>::Item>`
  |
  = note: type must be known at this point
added 3 commits that reference this issue on Dec 11, 2019
SeeSpring

SeeSpring commented on Mar 11, 2020

@SeeSpring
ContributorAuthor

Seems to be due to specialization
Minimized version below
Playground

#![no_implicit_prelude]
#![feature(specialization)]

extern crate core;
extern crate std;

use core::marker::Sized;
use core::ops::FnMut;
use core::option::Option;
use std::panic;
use std::unimplemented;

pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
    fn fuse(self) -> Fuse<Self>
    where
        Self: Sized,
    {
        unimplemented!()
    }
}

trait FusedIterator: Iterator {}
pub struct Fuse<I>(I);
impl<I> Iterator for Fuse<I>
where
    I: Iterator,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        unimplemented!()
    }
}

impl<I> Iterator for Fuse<I> where I: FusedIterator {}

impl<'a, I> FusedIterator for Fuse<I> where I: Iterator {}

pub fn f(s: &Mystr) {
    let mut it = s.split(|c: char| c == ',').fuse();
    let t = it.next();
    let u = t.unwrap();
    let v = u.parse::<usize>().unwrap();
}

pub struct Mystr;

impl Mystr {
    pub fn split<'a, P>(&'a self, pat: P) -> Split<'a, P>
    where
        P: Pattern<'a>,
    {
        Split(pat.into_searcher(self))
    }
}

pub trait Pattern<'a> {
    type Searcher: Searcher<'a>;

    fn into_searcher(self, haystack: &'a Mystr) -> Self::Searcher;
}

impl<'a, F> Pattern<'a> for F
where
    F: FnMut(char) -> bool,
{
    type Searcher = CharPredicateSearcher<'a, F>;

    fn into_searcher(self, haystack: &'a Mystr) -> Self::Searcher {
        unimplemented!()
    }
}

pub struct CharPredicateSearcher<'a, F>(F, core::marker::PhantomData<&'a ()>)
where
    F: FnMut(char) -> bool;

unsafe impl<'a, F> Searcher<'a> for CharPredicateSearcher<'a, F> where F: FnMut(char) -> bool {}

pub unsafe trait Searcher<'a> {}

pub struct Split<'a, P>(<P as Pattern<'a>>::Searcher)
where
    P: Pattern<'a>;

impl<'a, P> Iterator for Split<'a, P>
where
    P: Pattern<'a>,
{
    type Item = &'a str;
    fn next(&mut self) -> Option<Self::Item> {
        unimplemented!()
    }
}

impl<'a, P> FusedIterator for Split<'a, P> where P: Pattern<'a> {}

fn main() {}
Spoonbender

Spoonbender commented on Mar 23, 2022

@Spoonbender

Triage: original issue seems resolved, as the example provided in the original post now compiles. The latest example still won't compile.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-inferenceArea: Type inferenceC-bugCategory: This is a bug.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @pnkfelix@ExpHP@estebank@jonas-schievink@talchas

      Issue actions

        Type inference fails even though all types are known · Issue #58517 · rust-lang/rust