Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cannot infer appropriate lifetime error message is confusing #42317

Closed
vext01 opened this issue May 30, 2017 · 4 comments
Closed

cannot infer appropriate lifetime error message is confusing #42317

vext01 opened this issue May 30, 2017 · 4 comments

Comments

@vext01
Copy link
Contributor

vext01 commented May 30, 2017

Hi,

There is a class of error message which: a) is common, b) I've always been very confused by.

Here's an example:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/librustc_mir/transform/metarust_block_marker.rs:98:32
   |
98 |             let new_blk = self.make_callsite_block(bb, bb_data);
   |                                ^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 91:49...
  --> src/librustc_mir/transform/metarust_block_marker.rs:91:50
   |
91 |       fn add_callsites(&self, mir: &mut Mir<'tcx>) {
   |  __________________________________________________^
92 | |         // store the news blocks (which call the marker) here. There is one extra block per old
93 | |         // block, and the extra block is stored at the old block's index.
94 | |         let mut extra_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>> = IndexVec::new();
...  |
108| |         }
109| |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/librustc_mir/transform/metarust_block_marker.rs:98:27
   |
98 |             let new_blk = self.make_callsite_block(bb, bb_data);
   |                           ^^^^
note: but, the lifetime must be valid for the lifetime 'tcx as defined on the body at 91:49...
  --> src/librustc_mir/transform/metarust_block_marker.rs:91:50
   |
91 |       fn add_callsites(&self, mir: &mut Mir<'tcx>) {
   |  __________________________________________________^
92 | |         // store the news blocks (which call the marker) here. There is one extra block per old
93 | |         // block, and the extra block is stored at the old block's index.
94 | |         let mut extra_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>> = IndexVec::new();
...  |
108| |         }
109| |     }
   | |_____^
note: ...so that expression is assignable (expected rustc::mir::BasicBlockData<'tcx>, found rustc::mir::BasicBlockData<'_>)
  --> src/librustc_mir/transform/metarust_block_marker.rs:100:35
   |
100|                 extra_blocks.push(new_bb_data);
   |                                   ^^^^^^^^^^^

error: aborting due to previous error

The first issue I have is the sheer amount of information I am bombarded with. I can't keep all these details in my head while I am digesting the message.

Second, the flow of the error message and the locality of the details therein are confusing. Let me demonstrate by showing my trail of thought as I read the error:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/librustc_mir/transform/metarust_block_marker.rs:98:32
   |
98 |             let new_blk = self.make_callsite_block(bb, bb_data);
   |                                ^^^^^^^^^^^^^^^^^^^
   |

OK, something is wrong with the call to make_callsite_block.

But what's an autoref?

note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 91:49...

What lifetime is "the lifetime"?

#1 could say the lifetime name in brackets to reduce cognitive load.

  --> src/librustc_mir/transform/metarust_block_marker.rs:91:50
   |
91 |       fn add_callsites(&self, mir: &mut Mir<'tcx>) {
   |  __________________________________________________^

So now we are talking about a different function now. Is that the callee, or the caller of the one referenced before? Consult source code. Now where was I again?

92 | |         // store the news blocks (which call the marker) here. There is one extra block per old
93 | |         // block, and the extra block is stored at the old block's index.
94 | |         let mut extra_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>> = IndexVec::new();
...  |
108| |         }
109| |     }
   | |_____^
note: ...so that reference does not outlive borrowed content

Which reference is "that reference"?

  --> src/librustc_mir/transform/metarust_block_marker.rs:98:27
   |
98 |             let new_blk = self.make_callsite_block(bb, bb_data);
   |                           ^^^^
note: but, the lifetime must be valid for the lifetime 'tcx as defined on the body at 91:49...
  --> src/librustc_mir/transform/metarust_block_marker.rs:91:50

Argh! Head explodes.

   |
91 |       fn add_callsites(&self, mir: &mut Mir<'tcx>) {
   |  __________________________________________________^
92 | |         // store the news blocks (which call the marker) here. There is one extra block per old
93 | |         // block, and the extra block is stored at the old block's index.
94 | |         let mut extra_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>> = IndexVec::new();
...  |
108| |         }
109| |     }
   | |_____^
note: ...so that expression is assignable (expected rustc::mir::BasicBlockData<'tcx>, found rustc::mir::BasicBlockData<'_>)
  --> src/librustc_mir/transform/metarust_block_marker.rs:100:35
   |
100|                 extra_blocks.push(new_bb_data);
   |                                   ^^^^^^^^^^^

Being brutally honest, usually by this point I've given up trying to understand the error message and have instead resorted to brute force, adding/changing different lifetime annotations until the program compiles.

I guess this relates to rust-lang/nomicon#2, where I was trying to improve the documentation so that beginners could better understand lifetimes. Despite having written that PR, I still don't feel confident I've understood.

There has to be a more intuitive way for the compiler to explain what is wrong. Any ideas?

(For context: I've been using Rust for probably 2 or 3 months, however, I am an experienced programmer in many other languages)

@eddyb
Copy link
Member

eddyb commented Jun 7, 2017

cc @nikomatsakis

@nikomatsakis
Copy link
Contributor

Yes. These messages are definitely bad. In truth, although this looks like one message, it covers a very wide range of scenarios. What I've been doing is trying to analyze and figure out how to handle those scenarios separately.

At the moment, @gaurikholkar is actually actively at work on the first such case, which has to do with returning data when one of the regions in question is a named lifetime and the other is anonymous. We plan to go from there and carve out many more cases to improve. Thanks for the "thought process", I'll add this issue to my etherpad where I am tracking and brainstorming. (I should also open an issue on the various ideas that @gaurikholkar and I have been kicking around.)

I think in the meantime I will close this issue, though, in favor of opening one a more general one.

@nikomatsakis
Copy link
Contributor

See also #42516

@vext01
Copy link
Contributor Author

vext01 commented Jun 8, 2017

Thanks Niko. I'm glad the Rust community sees worth in improving error messages :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants