-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Modify compile-fail/E0389 error message WIP #48914
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
Changes from 7 commits
7d590b5
308e30e
f60788b
3f0ce08
bfc9b76
7a266a6
0c7fc04
fdb2f7f
55bd914
50299c6
7745b52
311a8be
6c649fb
1b06fe1
c119206
12d1415
1fb25fb
e6938ee
6686d10
e18a83b
e5a96a4
cbde62c
2ad20e8
c792d1e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,7 @@ use rustc::hir::map::definitions::DefPathData; | |
use rustc::infer::InferCtxt; | ||
use rustc::ty::{self, ParamEnv, TyCtxt}; | ||
use rustc::ty::maps::Providers; | ||
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Place}; | ||
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Local, Location, Place}; | ||
use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue}; | ||
use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind}; | ||
use rustc::mir::ClosureRegionRequirements; | ||
|
@@ -43,6 +43,7 @@ use dataflow::indexes::BorrowIndex; | |
use dataflow::move_paths::{IllegalMoveOriginKind, MoveError}; | ||
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex}; | ||
use util::borrowck_errors::{BorrowckErrors, Origin}; | ||
use util::collect_writes::FindAssignments; | ||
|
||
use std::iter; | ||
|
||
|
@@ -1421,6 +1422,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | |
} | ||
} | ||
|
||
fn get_main_error_message(&self, place:&Place<'tcx>) -> String{ | ||
match self.describe_place(place) { | ||
Some(name) => format!("immutable item `{}`", name), | ||
None => "immutable item".to_owned(), | ||
} | ||
} | ||
|
||
/// Currently MoveData does not store entries for all places in | ||
/// the input MIR. For example it will currently filter out | ||
/// places that are Copy; thus we do not track places of shared | ||
|
@@ -1551,12 +1559,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | |
self.is_mutable(place, is_local_mutation_allowed) | ||
{ | ||
error_reported = true; | ||
|
||
let item_msg = match self.describe_place(place) { | ||
Some(name) => format!("immutable item `{}`", name), | ||
None => "immutable item".to_owned(), | ||
}; | ||
|
||
let item_msg = self.get_main_error_message(place); | ||
let mut err = self.tcx | ||
.cannot_borrow_path_as_mutable(span, &item_msg, Origin::Mir); | ||
err.span_label(span, "cannot borrow as mutable"); | ||
|
@@ -1573,21 +1576,61 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | |
if let Err(place_err) = self.is_mutable(place, is_local_mutation_allowed) { | ||
error_reported = true; | ||
|
||
let item_msg = match self.describe_place(place) { | ||
Some(name) => format!("immutable item `{}`", name), | ||
None => "immutable item".to_owned(), | ||
let err_info = match *place_err { | ||
Place::Projection(ref proj) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can match on multiple levels to avoid deeply nested structures: enum Foo {
A { f: Bar },
B(Bar),
}
enum Bar {
X,
Y,
}
let x = Foo::B(Bar::X);
match x {
Foo::A { f: Bar::Y } => 1,
_ => 0,
} |
||
match proj.elem { | ||
ProjectionElem::Deref => { | ||
match proj.base { | ||
Place::Local(local) => { | ||
let locations = self.mir.find_assignments(local); | ||
if locations.len() > 0 { | ||
let item_msg = if error_reported { | ||
if let Some(name) = | ||
self.describe_place(place_err) { | ||
let var = str::replace(&name, "*", ""); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I'm not crazy about the string munging =) Maybe we should just do |
||
format!("`&`-reference `{}`", var) | ||
} else { | ||
self.get_main_error_message(place) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would pull this into a helper function and I would change these fn specialized_description(..) -> Option<String> then if it is |
||
} | ||
} else { | ||
self.get_main_error_message(place) | ||
}; | ||
Some((self.mir.source_info(locations[0]).span, | ||
"consider changing this to be a \ | ||
mutable reference: `&mut`", item_msg, | ||
"cannot assign through `&`-reference")) | ||
} else { | ||
None | ||
} | ||
} | ||
_ => None, | ||
} | ||
} | ||
_ => None, | ||
} | ||
} | ||
_ => None, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given how many branches there are here, it might make sense to make |
||
}; | ||
|
||
let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir); | ||
err.span_label(span, "cannot mutate"); | ||
|
||
if place != place_err { | ||
if let Some(name) = self.describe_place(place_err) { | ||
err.note(&format!("Value not mutable causing this error: `{}`", name)); | ||
if let Some((err_help_span, err_help_stmt, item_msg, sec_span)) = err_info { | ||
let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir, true); | ||
err.span_suggestion(err_help_span, err_help_stmt, format!("")); | ||
if place != place_err { | ||
err.span_label(span, sec_span); | ||
} | ||
err.emit() | ||
}else{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. spaces around |
||
let item_msg_ = self.get_main_error_message(place); | ||
let mut err = self.tcx.cannot_assign(span, &item_msg_, Origin::Mir, false); | ||
err.span_label(span, "cannot mutate"); | ||
if place != place_err { | ||
if let Some(name) = self.describe_place(place_err) { | ||
err.note(&format!("Value not mutable causing this error: `{}`", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lowercase sentences: |
||
name)); | ||
} | ||
} | ||
err.emit(); | ||
} | ||
|
||
err.emit(); | ||
} | ||
} | ||
Reservation(WriteKind::Move) | ||
|
@@ -2230,3 +2273,4 @@ impl ContextKind { | |
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! | |
#![feature(collection_placement)] | ||
#![feature(nonzero)] | ||
#![feature(underscore_lifetimes)] | ||
#![feature(crate_visibility_modifier)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, due to the usage here |
||
|
||
extern crate arena; | ||
#[macro_use] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
use rustc::mir::{Local, Location}; | ||
use rustc::mir::Mir; | ||
use rustc::mir::visit::PlaceContext; | ||
use rustc::mir::visit::Visitor; | ||
|
||
// The Visitor walks the MIR to return the assignment statements corresponding | ||
// to a Local. | ||
pub struct FindLocalAssignmentVisitor { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not need to be public, it is an impl detail. Just make it private. |
||
needle: Local, | ||
locations: Vec<Location>, | ||
} | ||
|
||
impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { | ||
fn visit_local(&mut self, | ||
local: &Local, | ||
place_context: PlaceContext<'tcx>, | ||
location: Location) { | ||
if self.needle != *local { | ||
return; | ||
} | ||
|
||
match place_context { | ||
PlaceContext::Store | PlaceContext::Call => { | ||
self.locations.push(location); | ||
} | ||
PlaceContext::AsmOutput | | ||
PlaceContext::Drop | | ||
PlaceContext::Inspect | | ||
PlaceContext::Borrow { .. } | | ||
PlaceContext::Projection(..) | | ||
PlaceContext::Copy | | ||
PlaceContext::Move | | ||
PlaceContext::StorageLive | | ||
PlaceContext::StorageDead | | ||
PlaceContext::Validate => { | ||
// TO-DO | ||
// self.super_local(local) | ||
} | ||
} | ||
} | ||
// TO-DO | ||
// fn super_local() | ||
} | ||
|
||
crate trait FindAssignments { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would move this to the top of the file -- this is what readers care about. Also, I would add a comment to the method: Finds all statements that assign directly to |
||
fn find_assignments(&self, local: Local) -> Vec<Location>; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: formatting |
||
|
||
impl<'tcx> FindAssignments for Mir<'tcx>{ | ||
fn find_assignments(&self, local: Local) -> Vec<Location>{ | ||
let mut visitor = FindLocalAssignmentVisitor{ needle: local, locations: vec![]}; | ||
visitor.visit_mir(self); | ||
visitor.locations | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,7 +27,7 @@ fn indirect_write_to_imm_box() { | |
let y: Box<_> = box &mut x; | ||
let p = &y; | ||
***p = 2; //[ast]~ ERROR cannot assign to data in a `&` reference | ||
//[mir]~^ ERROR cannot assign to immutable item `***p` | ||
//[mir]~^ ERROR cannot assign through `&`-reference `p` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not convinced about this change... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. certainly better than it was ("imutable item"), but not I think perfect yet -- and not necessarily better than AST variant, I don't think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The AST based error is this:
which I think has too much jargon, but some promising elements. This also intersects your style guide @estebank. Personally, my preference is that the "main" message is kind of generic and formal, like it is here, telling you nothing of the program itself, but that those details are revealed in the "underlines" and in a "conversational" tone. Maybe something like this?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this the common message for all such cases or just for the above case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
is how the message looks like now @nikomatsakis |
||
drop(p); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,5 +70,5 @@ fn main() { | |
}; | ||
s[2] = 20; | ||
//[ast]~^ ERROR cannot assign to immutable indexed content | ||
//[mir]~^^ ERROR cannot assign to immutable item | ||
//[mir]~^^ ERROR cannot assign through immutable item | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure about the look of this test though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one seems ok-ish to me, but we might be able to improve upon it. I'll think about it. |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given how deeply nested this is, it might make sense to move it to its own method, or at least adding a comment on top describing what the code is supposed to be doing.