Skip to content

Type inference requires type of LHS to be known for binary operators #8280

Closed
@mihneadb

Description

@mihneadb
Contributor

This is the code:

use std::hashmap;

fn main() {
    let mut map = hashmap::HashMap::new();

    let str = "Hello, world!";

    for &char in str.to_ascii().iter() {
        let count = map.find(&char);
        match count {
            Some(&x) => map.insert(char, x + 1),
            None => map.insert(char, 1)
        }
    }

    println!("{:?}", map);
}

Error message:

count_chars.rs:11:41: 11:42 error: the type of this value must be known in this context
count_chars.rs:11             Some(&x) => map.insert(char, x + 1),
                                                       ^
error: aborting due to previous error

Activity

huonw

huonw commented on Aug 4, 2013

@huonw
Member

Either

-            Some(&x) => map.insert(char, x + 1),
+            Some(&x) => map.insert(char, 1 + x),

or

-            Some(&x) => map.insert(char, x + 1),
-            None => map.insert(char, 1)
+            None => map.insert(char, 1),
+            Some(&x) => map.insert(char, x + 1),

makes the inference work:

  • in the first case, the 1 in 1 + x defaults to int and so the second argument (i.e. x) is inferred to also be int
  • in the second, the plain insert comes first and so that 1 there defaults to int and the inference succeeds.

(There are various ("correct") type errors and mutability issues that stop it compiling from after this.)

It seems like the original code should be legal, given the trivial adjustments (especially reordering the arms).

(cc @nikomatsakis)

huonw

huonw commented on Nov 10, 2013

@huonw
Member

Triage: I've updated the code for language changes; the inference is still suboptimal (i.e. it fails), the fixes in the comment above still address the inference issue, but also still hit the borrowing errors.

The following code works fine:

use std::hashmap;

fn main() {
    let mut map = hashmap::HashMap::new();

    let str = "Hello, world!";

    for &char in str.to_ascii().iter() {
        map.insert_or_update_with(char, 1, |_, v| *v += 1);
    }

    println!("{:?}", map);
}
nikomatsakis

nikomatsakis commented on Nov 11, 2013

@nikomatsakis
Contributor

Reading this example more closely, I actually don't think inference is expected to succeed here. You haven't told it the type of the values in the map, but you attempting to do x + 1. Due to the possibility of overloaded operators, we (at least currently) require that the type of x be known at that point. Reordering the arms makes type inference succeed because it forces the type of x to be int. Similarly, using insert_or_update_with also supplies the initial value (1), giving us the information we needed. I'm going to close.

nikomatsakis

nikomatsakis commented on Nov 11, 2013

@nikomatsakis
Contributor

That said -- we currently treat operator overloading as an operator, but it's possible that with the changes in #10337 we could avoid the requirement that we know the type of x. I'm going to tentatively re-open as a "sub-bug" of #10337.

nikomatsakis

nikomatsakis commented on Nov 11, 2013

@nikomatsakis
Contributor

Update title.

added a commit that references this issue on Dec 1, 2014
ad24fd6
Aatch

Aatch commented on Jan 20, 2015

@Aatch
Contributor

Multidispatch should have fixed this, correct?

nikomatsakis

nikomatsakis commented on Jan 20, 2015

@nikomatsakis
Contributor

@Aatch It did not. The distinction has to do with needing to decide between "builtin" operators like + on integers and trait-driven operations. Currently we do this at the moment of type-checking the + (or other operator). It'll take some rearchitecting but we could defer this decision.

arielb1

arielb1 commented on Jun 21, 2015

@arielb1
Contributor

This does compile (rather, type-check - of course it won't borrow-check) at 1.0 and above.

added
E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
on Jun 21, 2015
wthrowe

wthrowe commented on Jun 21, 2015

@wthrowe
Contributor

The following does not work, however:

fn main() {
    0u8.into() == 0u8;
}

It gives: "error: unable to infer enough type information about _; type annotations or generic parameter binding required" (on the into())

I'd been assuming that was this issue since it works if you switch the order of the operands, but if this one is solved perhaps it is a new one?

steveklabnik

steveklabnik commented on Jan 3, 2017

@steveklabnik
Member

Triage: @arielb1 said that this compiles, but it at least needs some massaging due to changes. I tried to do some of them, but it wasn't totally clear to me what should be done, exactly.

It's not clear to me if @wthrowe 's example is the same thing or different.

added
C-enhancementCategory: An issue proposing an enhancement or a PR with one.
and removed
E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
on Jul 19, 2017
bstrie

bstrie commented on Dec 2, 2017

@bstrie
Contributor

My own attempt to concoct a modern reproduction no longer exhibits this bug:

    let mut v = Vec::new();
    
    match v.get(0) {
        Some(&x) => v.push(x + 1),  // A-OK
        None => v.push(1),
    }

In fact, our inference is so good these days that even this works:

    let mut v = Vec::new();
    
    match v.get(0) {
        Some(&x) => v.push(x + x),
        None => v.push(1),
    }

Given that this bug was filed so long before 1.0 that the test case no longer works and that nobody seems to have come up with a reproduction of the original behavior, I'm closing this.

arielb1

arielb1 commented on Dec 3, 2017

@arielb1
Contributor

So autoref for operators will make this stop working for the normal reasons. I suppose that would be a regression. I hope it won't be too terribly annoying.

added a commit that references this issue on Jan 27, 2022

Auto merge of rust-lang#8280 - xFrednet:8276-map-clone-msrv, r=flip1995

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-inferenceArea: Type inferenceC-enhancementCategory: An issue proposing an enhancement or a PR with one.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @steveklabnik@nikomatsakis@Aatch@mihneadb@bstrie

      Issue actions

        Type inference requires type of LHS to be known for binary operators · Issue #8280 · rust-lang/rust