<p dir="auto">Some days ago, I wrote some code involving char as HashMap key. At that time, char didn't implement the IterBytes trait, so I implemented it locally myself. After updating rust, my code failed to compile with a somewhat less than obvious error.</p>
<p dir="auto">Example:</p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="extern mod std;
use std::map::HashMap;
use to_bytes::{IterBytes, Cb};

impl char: IterBytes {
    pure fn iter_bytes(lsb0: bool, f: Cb) {
        (self as i32).iter_bytes(lsb0, f);
    }
}

fn main() {
    let h = HashMap();
    h.insert('a', ());
    io::println(h.contains_key('a').to_str());
}"><pre class="notranslate"><span class="pl-k">extern</span> <span class="pl-k">mod</span> std<span class="pl-kos">;</span>
<span class="pl-k">use</span> std<span class="pl-kos">::</span>map<span class="pl-kos">::</span><span class="pl-v">HashMap</span><span class="pl-kos">;</span>
<span class="pl-k">use</span> to_bytes<span class="pl-kos">::</span><span class="pl-kos">{</span><span class="pl-v">IterBytes</span><span class="pl-kos">,</span> <span class="pl-v">Cb</span><span class="pl-kos">}</span><span class="pl-kos">;</span>

<span class="pl-k">impl</span> <span class="pl-smi">char</span><span class="pl-kos">:</span> <span class="pl-smi">IterBytes</span> <span class="pl-kos">{</span>
    pure <span class="pl-k">fn</span> <span class="pl-en">iter_bytes</span><span class="pl-kos">(</span><span class="pl-s1">lsb0</span><span class="pl-kos">:</span> <span class="pl-smi">bool</span><span class="pl-kos">,</span> <span class="pl-s1">f</span><span class="pl-kos">:</span> <span class="pl-smi">Cb</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-kos">(</span><span class="pl-smi">self</span> <span class="pl-k">as</span> <span class="pl-smi">i32</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">iter_bytes</span><span class="pl-kos">(</span>lsb0<span class="pl-kos">,</span> f<span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span>

<span class="pl-k">fn</span> <span class="pl-en">main</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">let</span> h = <span class="pl-v">HashMap</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    h<span class="pl-kos">.</span><span class="pl-en">insert</span><span class="pl-kos">(</span><span class="pl-s">'a'</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    io<span class="pl-kos">::</span><span class="pl-en">println</span><span class="pl-kos">(</span>h<span class="pl-kos">.</span><span class="pl-en">contains_key</span><span class="pl-kos">(</span><span class="pl-s">'a'</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to_str</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Produces the following errors:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="minimal.rs:12:12: 12:19 error: multiple applicable methods in scope
minimal.rs:12     let h = HashMap();
                          ^~~~~~~
minimal.rs:12:12: 12:19 error: multiple applicable methods in scope
minimal.rs:12     let h = HashMap();
                          ^~~~~~~
minimal.rs:13:4: 13:12 error: multiple applicable methods in scope
minimal.rs:13     h.insert('a', ());
                  ^~~~~~~~
minimal.rs:13:4: 13:12 error: multiple applicable methods in scope
minimal.rs:13     h.insert('a', ());
                  ^~~~~~~~
minimal.rs:14:16: 14:30 error: multiple applicable methods in scope
minimal.rs:14     io::println(h.contains_key('a').to_str());
                              ^~~~~~~~~~~~~~
minimal.rs:14:16: 14:30 error: multiple applicable methods in scope
minimal.rs:14     io::println(h.contains_key('a').to_str());
                              ^~~~~~~~~~~~~~
error: aborting due to 6 previous errors"><pre class="notranslate"><code class="notranslate">minimal.rs:12:12: 12:19 error: multiple applicable methods in scope
minimal.rs:12     let h = HashMap();
                          ^~~~~~~
minimal.rs:12:12: 12:19 error: multiple applicable methods in scope
minimal.rs:12     let h = HashMap();
                          ^~~~~~~
minimal.rs:13:4: 13:12 error: multiple applicable methods in scope
minimal.rs:13     h.insert('a', ());
                  ^~~~~~~~
minimal.rs:13:4: 13:12 error: multiple applicable methods in scope
minimal.rs:13     h.insert('a', ());
                  ^~~~~~~~
minimal.rs:14:16: 14:30 error: multiple applicable methods in scope
minimal.rs:14     io::println(h.contains_key('a').to_str());
                              ^~~~~~~~~~~~~~
minimal.rs:14:16: 14:30 error: multiple applicable methods in scope
minimal.rs:14     io::println(h.contains_key('a').to_str());
                              ^~~~~~~~~~~~~~
error: aborting due to 6 previous errors
</code></pre></div>
<p dir="auto">Note that there is no way to know that the problem is the duplicate implementation of IterBytes.</p>
<p dir="auto">The following code compiles:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="struct Foo&lt;'a&gt;(&amp;'a uint);

impl&lt;'a&gt; Foo&lt;'a&gt; {
  fn bar&lt;'a&gt;(self, other:Foo&lt;'a&gt;) {}
}"><pre class="notranslate"><code class="notranslate">struct Foo&lt;'a&gt;(&amp;'a uint);

impl&lt;'a&gt; Foo&lt;'a&gt; {
  fn bar&lt;'a&gt;(self, other:Foo&lt;'a&gt;) {}
}
</code></pre></div>
<p dir="auto">However, in the event of a lifetime mismatch, this can lead to confusing error messages.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="use std::kinds::marker::ContravariantLifetime;
// Using a Contravariant lifetime because #[deriving] doesn't seem to work well
// with &amp;-ptrs. Example holds with a covariant one as well.

#[deriving(PartialEq)]
struct Foo&lt;'a&gt;(ContravariantLifetime&lt;'a&gt;, uint);

impl&lt;'a&gt; Foo&lt;'a&gt; {
 fn bar&lt;'a&gt;(self, other: Foo&lt;'a&gt;) -&gt; bool {
   self == other
 }
}"><pre class="notranslate"><code class="notranslate">use std::kinds::marker::ContravariantLifetime;
// Using a Contravariant lifetime because #[deriving] doesn't seem to work well
// with &amp;-ptrs. Example holds with a covariant one as well.

#[deriving(PartialEq)]
struct Foo&lt;'a&gt;(ContravariantLifetime&lt;'a&gt;, uint);

impl&lt;'a&gt; Foo&lt;'a&gt; {
 fn bar&lt;'a&gt;(self, other: Foo&lt;'a&gt;) -&gt; bool {
   self == other
 }
}
</code></pre></div>
<p dir="auto">This gives a tautological recommendation along with a confusing error:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="test.rs:8:2: 11:3 help: consider using an explicit lifetime parameter as shown: fn bar&lt;'a&gt;(self, other: Foo&lt;'a&gt;) -&gt; bool
test.rs:8  fn bar&lt;'a&gt;(self, other: Foo&lt;'a&gt;) -&gt; bool {
test.rs:9    //baz(self, other)
test.rs:10    self == other
test.rs:11  }
test.rs:10:12: 10:17 error: mismatched types: expected `Foo&lt;'a&gt;`, found `Foo&lt;'a&gt;` (lifetime mismatch)
test.rs:10    self == other"><pre class="notranslate"><code class="notranslate">test.rs:8:2: 11:3 help: consider using an explicit lifetime parameter as shown: fn bar&lt;'a&gt;(self, other: Foo&lt;'a&gt;) -&gt; bool
test.rs:8  fn bar&lt;'a&gt;(self, other: Foo&lt;'a&gt;) -&gt; bool {
test.rs:9    //baz(self, other)
test.rs:10    self == other
test.rs:11  }
test.rs:10:12: 10:17 error: mismatched types: expected `Foo&lt;'a&gt;`, found `Foo&lt;'a&gt;` (lifetime mismatch)
test.rs:10    self == other
</code></pre></div>
<p dir="auto">It's not really the error's fault for being so confusing, after all, we have shadowed the <code class="notranslate">'a</code> from the impl with a <code class="notranslate">'a</code> from the  definition of <code class="notranslate">baz()</code>. This should probably be disallowed or at least linted.</p>
<p dir="auto">The recommendation is flawed in two  ways</p>
<ul dir="auto">
<li>Firstly, it recommended <code class="notranslate">'a</code>, a lifetime which is already being used there (twice, actually). That's adding to the confusion. It clearly means to recommend a <em>new</em> lifetime (<code class="notranslate">'b</code>?)</li>
<li>It's wrong, even if you change the signature of <code class="notranslate">bar()</code> to use <code class="notranslate">'b</code>, it's still wrong, but then it gives the correct recommendation to use <code class="notranslate">fn bar(self, other: Foo&lt;'a&gt;) -&gt; bool</code> on recompiling.</li>
</ul>
<p dir="auto">This probably needs better error reporting (don't recommend lifetimes which are already being used in that context)</p>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/glennw/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/glennw">@glennw</a> came across this in Servo, getting tautological errors like <a href="https://pastebin.mozilla.org/7215857" rel="nofollow">this</a> and <a href="https://pastebin.mozilla.org/7216170" rel="nofollow">this</a>. The former is due to lifetime shadowing (and can be fixed by disallowing shadowing). I'm not yet sure what prompted the latter one, one of the lifetimes is elided but the other one is named <code class="notranslate">'a</code> in the surrounding impl and should have turned up in the error message instead of being underscored.</p>