1
Fork 0

Refactoring

This commit is contained in:
Nick Cameron 2015-12-23 19:27:20 +13:00
parent 95dc7efad0
commit aaa02b3ff9
13 changed files with 238 additions and 226 deletions

View file

@ -368,7 +368,7 @@ pub fn raw_emit_lint(sess: &Session,
lvlsrc: LevelSource, lvlsrc: LevelSource,
span: Option<Span>, span: Option<Span>,
msg: &str) { msg: &str) {
raw_struct_lint(sess, lint, lvlsrc, span, msg).map(|mut e| e.emit()); raw_struct_lint(sess, lint, lvlsrc, span, msg).emit();
} }
pub fn raw_struct_lint<'a>(sess: &'a Session, pub fn raw_struct_lint<'a>(sess: &'a Session,
@ -376,10 +376,10 @@ pub fn raw_struct_lint<'a>(sess: &'a Session,
lvlsrc: LevelSource, lvlsrc: LevelSource,
span: Option<Span>, span: Option<Span>,
msg: &str) msg: &str)
-> Option<DiagnosticBuilder<'a>> { -> DiagnosticBuilder<'a> {
let (mut level, source) = lvlsrc; let (mut level, source) = lvlsrc;
if level == Allow { if level == Allow {
return None; return sess.diagnostic().struct_dummy();
} }
let name = lint.name_lower(); let name = lint.name_lower();
@ -416,7 +416,8 @@ pub fn raw_struct_lint<'a>(sess: &'a Session,
if let Some(span) = def { if let Some(span) = def {
err.span_note(span, "lint level defined here"); err.span_note(span, "lint level defined here");
} }
Some(err)
err
} }
pub trait LintContext: Sized { pub trait LintContext: Sized {
@ -456,9 +457,9 @@ pub trait LintContext: Sized {
lint: &'static Lint, lint: &'static Lint,
span: Option<Span>, span: Option<Span>,
msg: &str) msg: &str)
-> Option<DiagnosticBuilder> { -> DiagnosticBuilder {
let (level, src) = match self.level_src(lint) { let (level, src) = match self.level_src(lint) {
None => return None, None => return self.sess().diagnostic().struct_dummy(),
Some(pair) => pair, Some(pair) => pair,
}; };
@ -474,17 +475,14 @@ pub trait LintContext: Sized {
lint: &'static Lint, lint: &'static Lint,
span: Span, span: Span,
msg: &str) msg: &str)
-> Option<DiagnosticBuilder> { -> DiagnosticBuilder {
self.lookup(lint, Some(span), msg) self.lookup(lint, Some(span), msg)
} }
/// Emit a lint and note at the appropriate level, for a particular span. /// Emit a lint and note at the appropriate level, for a particular span.
fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str, fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
note_span: Span, note: &str) { note_span: Span, note: &str) {
let mut err = match self.lookup(lint, Some(span), msg) { let mut err = self.lookup(lint, Some(span), msg);
Some(e) => e,
None => return
};
if self.current_level(lint) != Level::Allow { if self.current_level(lint) != Level::Allow {
if note_span == span { if note_span == span {
err.fileline_note(note_span, note); err.fileline_note(note_span, note);
@ -498,10 +496,7 @@ pub trait LintContext: Sized {
/// Emit a lint and help at the appropriate level, for a particular span. /// Emit a lint and help at the appropriate level, for a particular span.
fn span_lint_help(&self, lint: &'static Lint, span: Span, fn span_lint_help(&self, lint: &'static Lint, span: Span,
msg: &str, help: &str) { msg: &str, help: &str) {
let mut err = match self.lookup(lint, Some(span), msg) { let mut err = self.lookup(lint, Some(span), msg);
Some(e) => e,
None => return
};
self.span_lint(lint, span, msg); self.span_lint(lint, span, msg);
if self.current_level(lint) != Level::Allow { if self.current_level(lint) != Level::Allow {
err.span_help(span, help); err.span_help(span, help);

View file

@ -237,7 +237,7 @@ pub trait ErrorReporting<'tcx> {
fn report_type_error(&self, fn report_type_error(&self,
trace: TypeTrace<'tcx>, trace: TypeTrace<'tcx>,
terr: &TypeError<'tcx>) terr: &TypeError<'tcx>)
-> Option<DiagnosticBuilder<'tcx>>; -> DiagnosticBuilder<'tcx>;
fn check_and_note_conflicting_crates(&self, fn check_and_note_conflicting_crates(&self,
err: &mut DiagnosticBuilder, err: &mut DiagnosticBuilder,
@ -478,11 +478,11 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
fn report_type_error(&self, fn report_type_error(&self,
trace: TypeTrace<'tcx>, trace: TypeTrace<'tcx>,
terr: &TypeError<'tcx>) terr: &TypeError<'tcx>)
-> Option<DiagnosticBuilder<'tcx>> { -> DiagnosticBuilder<'tcx> {
let expected_found_str = match self.values_str(&trace.values) { let expected_found_str = match self.values_str(&trace.values) {
Some(v) => v, Some(v) => v,
None => { None => {
return None; /* derived error */ return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */
} }
}; };
@ -507,7 +507,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
}, },
_ => () _ => ()
} }
Some(err) err
} }
/// Adds a note if the types come from similarly named crates /// Adds a note if the types come from similarly named crates
@ -560,11 +560,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
trace: TypeTrace<'tcx>, trace: TypeTrace<'tcx>,
terr: &TypeError<'tcx>) { terr: &TypeError<'tcx>) {
let span = trace.origin.span(); let span = trace.origin.span();
let err = self.report_type_error(trace, terr); let mut err = self.report_type_error(trace, terr);
err.map(|mut err| {
self.tcx.note_and_explain_type_err(&mut err, terr, span); self.tcx.note_and_explain_type_err(&mut err, terr, span);
err.emit(); err.emit();
});
} }
/// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived

View file

@ -1281,7 +1281,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
mk_msg: M, mk_msg: M,
actual_ty: String, actual_ty: String,
err: Option<&TypeError<'tcx>>) err: Option<&TypeError<'tcx>>)
-> Option<DiagnosticBuilder<'tcx>> -> DiagnosticBuilder<'tcx>
where M: FnOnce(Option<String>, String) -> String, where M: FnOnce(Option<String>, String) -> String,
{ {
self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err) self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err)
@ -1296,7 +1296,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
where M: FnOnce(Option<String>, String) -> String, where M: FnOnce(Option<String>, String) -> String,
{ {
self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err) self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err)
.map(|mut e| e.emit()); .emit();
} }
pub fn type_error_struct_str_with_expected<M>(&self, pub fn type_error_struct_str_with_expected<M>(&self,
@ -1305,7 +1305,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
expected_ty: Option<Ty<'tcx>>, expected_ty: Option<Ty<'tcx>>,
actual_ty: String, actual_ty: String,
err: Option<&TypeError<'tcx>>) err: Option<&TypeError<'tcx>>)
-> Option<DiagnosticBuilder<'tcx>> -> DiagnosticBuilder<'tcx>
where M: FnOnce(Option<String>, String) -> String, where M: FnOnce(Option<String>, String) -> String,
{ {
debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty); debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty);
@ -1324,9 +1324,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
if let Some(err) = err { if let Some(err) = err {
self.tcx.note_and_explain_type_err(&mut db, err, sp); self.tcx.note_and_explain_type_err(&mut db, err, sp);
} }
Some(db) db
} else { } else {
None self.tcx.sess.diagnostic().struct_dummy()
} }
} }
@ -1337,7 +1337,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err: Option<&TypeError<'tcx>>) err: Option<&TypeError<'tcx>>)
where M: FnOnce(String) -> String, where M: FnOnce(String) -> String,
{ {
self.type_error_struct(sp, mk_msg, actual_ty, err).map(|mut e| e.emit()); self.type_error_struct(sp, mk_msg, actual_ty, err).emit();
} }
pub fn type_error_struct<M>(&self, pub fn type_error_struct<M>(&self,
@ -1345,14 +1345,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
mk_msg: M, mk_msg: M,
actual_ty: Ty<'tcx>, actual_ty: Ty<'tcx>,
err: Option<&TypeError<'tcx>>) err: Option<&TypeError<'tcx>>)
-> Option<DiagnosticBuilder<'tcx>> -> DiagnosticBuilder<'tcx>
where M: FnOnce(String) -> String, where M: FnOnce(String) -> String,
{ {
let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
// Don't report an error if actual type is TyError. // Don't report an error if actual type is TyError.
if actual_ty.references_error() { if actual_ty.references_error() {
return None; return self.tcx.sess.diagnostic().struct_dummy();
} }
self.type_error_struct_str(sp, self.type_error_struct_str(sp,

View file

@ -60,7 +60,7 @@ struct ExpectErrorEmitter {
fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
match lvl { match lvl {
Level::Bug | Level::Fatal | Level::Error => {} Level::Bug | Level::Fatal | Level::Error => {}
Level::Warning | Level::Note | Level::Help => { _ => {
return; return;
} }
} }

View file

@ -754,18 +754,17 @@ impl LateLintPass for UnconditionalRecursion {
if !reached_exit_without_self_call && !self_call_spans.is_empty() { if !reached_exit_without_self_call && !self_call_spans.is_empty() {
let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp, let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp,
"function cannot return without recurring"); "function cannot return without recurring");
let mut db = db.as_mut();
// FIXME #19668: these could be span_lint_note's instead of this manual guard. // FIXME #19668: these could be span_lint_note's instead of this manual guard.
if cx.current_level(UNCONDITIONAL_RECURSION) != Level::Allow { if cx.current_level(UNCONDITIONAL_RECURSION) != Level::Allow {
// offer some help to the programmer. // offer some help to the programmer.
for call in &self_call_spans { for call in &self_call_spans {
db = db.map(|db| db.span_note(*call, "recursive call site")); db.span_note(*call, "recursive call site");
} }
db = db.map(|db| db.fileline_help(sp, "a `loop` may express intention \ db.fileline_help(sp, "a `loop` may express intention \
better if this is on purpose")); better if this is on purpose");
} }
db.map(|db| db.emit()); db.emit();
} }
// all done // all done

View file

@ -144,9 +144,9 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
if let Some(sp) = child[ns].span() { if let Some(sp) = child[ns].span() {
let note = format!("first definition of {} `{}` here", ns_str, name); let note = format!("first definition of {} `{}` here", ns_str, name);
err.as_mut().map(|mut e| e.span_note(sp, &note)); err.span_note(sp, &note);
} }
err.as_mut().map(|mut e| e.emit()); err.emit();
child child
} }
} }
@ -261,10 +261,9 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
mod_spans[0], mod_spans[0],
ResolutionError::SelfImportCanOnlyAppearOnceInTheList); ResolutionError::SelfImportCanOnlyAppearOnceInTheList);
for other_span in mod_spans.iter().skip(1) { for other_span in mod_spans.iter().skip(1) {
e.as_mut().map(|mut e| e.span_note(*other_span, e.span_note(*other_span, "another `self` import appears here");
"another `self` import appears here"));
} }
e.as_mut().map(|mut e| e.emit()); e.emit();
} }
for source_item in source_items { for source_item in source_items {

View file

@ -216,18 +216,18 @@ pub enum UnresolvedNameContext {
fn resolve_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, fn resolve_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
span: syntax::codemap::Span, span: syntax::codemap::Span,
resolution_error: ResolutionError<'b>) { resolution_error: ResolutionError<'b>) {
resolve_struct_error(resolver, span, resolution_error).map(|mut e| e.emit()); resolve_struct_error(resolver, span, resolution_error).emit();
} }
fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
span: syntax::codemap::Span, span: syntax::codemap::Span,
resolution_error: ResolutionError<'b>) resolution_error: ResolutionError<'b>)
-> Option<DiagnosticBuilder<'a>> { -> DiagnosticBuilder<'a> {
if !resolver.emit_errors { if !resolver.emit_errors {
return None; return resolver.session.diagnostic().struct_dummy();
} }
Some(match resolution_error { match resolution_error {
ResolutionError::TypeParametersFromOuterFunction => { ResolutionError::TypeParametersFromOuterFunction => {
struct_span_err!(resolver.session, struct_span_err!(resolver.session,
span, span,
@ -532,7 +532,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
E0435, E0435,
"attempt to use a non-constant value in a constant") "attempt to use a non-constant value in a constant")
} }
}) }
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -2202,10 +2202,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// If it's a typedef, give a note // If it's a typedef, give a note
if let DefTy(..) = path_res.base_def { if let DefTy(..) = path_res.base_def {
err.as_mut().map(|mut e| e.span_note(trait_path.span, err.span_note(trait_path.span,
"`type` aliases cannot be used for traits")); "`type` aliases cannot be used for traits");
} }
err.as_mut().map(|mut e| e.emit()); err.emit();
Err(()) Err(())
} }
} else { } else {
@ -3493,11 +3493,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
path_name); path_name);
if self.emit_errors { if self.emit_errors {
err.as_mut().map(|mut e| e.fileline_help(expr.span, &msg)); err.fileline_help(expr.span, &msg);
} else { } else {
err.as_mut().map(|mut e| e.span_help(expr.span, &msg)); err.span_help(expr.span, &msg);
} }
err.as_mut().map(|mut e| e.emit()); err.emit();
self.record_def(expr.id, err_path_resolution()); self.record_def(expr.id, err_path_resolution());
} else { } else {
// Write the result into the def map. // Write the result into the def map.
@ -3534,11 +3534,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
path_name); path_name);
if self.emit_errors { if self.emit_errors {
err.as_mut().map(|mut e| e.fileline_help(expr.span, &msg)); err.fileline_help(expr.span, &msg);
} else { } else {
err.as_mut().map(|mut e| e.span_help(expr.span, &msg)); err.span_help(expr.span, &msg);
} }
err.as_mut().map(|mut e| e.emit()); err.emit();
} }
_ => { _ => {
// Keep reporting some errors even if they're ignored above. // Keep reporting some errors even if they're ignored above.

View file

@ -2213,11 +2213,9 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &hir::EnumDef, sp: Span,
&format!("enum variant is more than three times larger ({} bytes) \ &format!("enum variant is more than three times larger ({} bytes) \
than the next largest (ignoring padding)", than the next largest (ignoring padding)",
largest)) largest))
.map(|mut e| { .span_note(enum_def.variants[largest_index].span,
e.span_note(enum_def.variants[largest_index].span,
"this variant is the largest") "this variant is the largest")
.emit(); .emit();
});
} }
} }

View file

@ -232,20 +232,19 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
let mut err = fcx.type_error_struct(call_expr.span, |actual| { let mut err = fcx.type_error_struct(call_expr.span, |actual| {
format!("expected function, found `{}`", actual) format!("expected function, found `{}`", actual)
}, callee_ty, None); }, callee_ty, None);
let mut err = err.as_mut();
if let hir::ExprCall(ref expr, _) = call_expr.node { if let hir::ExprCall(ref expr, _) = call_expr.node {
let tcx = fcx.tcx(); let tcx = fcx.tcx();
if let Some(pr) = tcx.def_map.borrow().get(&expr.id) { if let Some(pr) = tcx.def_map.borrow().get(&expr.id) {
if pr.depth == 0 && pr.base_def != def::DefErr { if pr.depth == 0 && pr.base_def != def::DefErr {
if let Some(span) = tcx.map.span_if_local(pr.def_id()) { if let Some(span) = tcx.map.span_if_local(pr.def_id()) {
err = err.map(|e| e.span_note(span, "defined here")); err.span_note(span, "defined here");
} }
} }
} }
} }
err.map(|e| e.emit()); err.emit();
// This is the "default" function signature, used in case of error. // This is the "default" function signature, used in case of error.
// In that case, we check each argument against "error" in order to // In that case, we check each argument against "error" in order to

View file

@ -132,17 +132,15 @@ impl<'tcx> CastCheck<'tcx> {
actual, actual,
fcx.infcx().ty_to_string(self.cast_ty)) fcx.infcx().ty_to_string(self.cast_ty))
}, self.expr_ty, None) }, self.expr_ty, None)
.map(|mut err| { .fileline_help(self.span,
err.fileline_help(self.span,
&format!("cast through {} first", match e { &format!("cast through {} first", match e {
CastError::NeedViaPtr => "a raw pointer", CastError::NeedViaPtr => "a raw pointer",
CastError::NeedViaThinPtr => "a thin pointer", CastError::NeedViaThinPtr => "a thin pointer",
CastError::NeedViaInt => "an integer", CastError::NeedViaInt => "an integer",
CastError::NeedViaUsize => "a usize", CastError::NeedViaUsize => "a usize",
_ => unreachable!() _ => unreachable!()
})); }))
err.emit(); .emit();
});
} }
CastError::CastToBool => { CastError::CastToBool => {
struct_span_err!(fcx.tcx().sess, self.span, E0054, "cannot cast as `bool`") struct_span_err!(fcx.tcx().sess, self.span, E0054, "cannot cast as `bool`")
@ -174,10 +172,8 @@ impl<'tcx> CastCheck<'tcx> {
actual, actual,
fcx.infcx().ty_to_string(self.cast_ty)) fcx.infcx().ty_to_string(self.cast_ty))
}, self.expr_ty, None) }, self.expr_ty, None)
.map(|mut err| { .fileline_note(self.span, "vtable kinds may not match")
err.fileline_note(self.span, "vtable kinds may not match"); .emit();
err.emit();
});
} }
} }
} }

View file

@ -69,7 +69,6 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
rcvr_ty, rcvr_ty,
None); None);
if let Some(ref mut err) = err {
// If the item has the name of a field, give a help note // If the item has the name of a field, give a help note
if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) {
if let Some(field) = def.struct_variant().find_field_named(item_name) { if let Some(field) = def.struct_variant().find_field_named(item_name) {
@ -144,7 +143,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span, span,
"found defined static methods, maybe a `self` is missing?"); "found defined static methods, maybe a `self` is missing?");
report_candidates(fcx, err, span, item_name, static_sources); report_candidates(fcx, &mut err, span, item_name, static_sources);
} }
if !unsatisfied_predicates.is_empty() { if !unsatisfied_predicates.is_empty() {
@ -162,11 +161,10 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
bound_list)); bound_list));
} }
suggest_traits_to_import(fcx, err, span, rcvr_ty, item_name, suggest_traits_to_import(fcx, &mut err, span, rcvr_ty, item_name,
rcvr_expr, out_of_scope_traits); rcvr_expr, out_of_scope_traits);
err.emit(); err.emit();
} }
}
MethodError::Ambiguity(sources) => { MethodError::Ambiguity(sources) => {
let mut err = struct_span_err!(fcx.sess(), span, E0034, let mut err = struct_span_err!(fcx.sess(), span, E0034,

View file

@ -1051,16 +1051,16 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
if t_cast.is_trait() { if t_cast.is_trait() {
match fcx.tcx().sess.codemap().span_to_snippet(t_span) { match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
Ok(s) => { Ok(s) => {
err.as_mut().unwrap().span_suggestion(t_span, err.span_suggestion(t_span,
"try casting to a reference instead:", "try casting to a reference instead:",
format!("&{}{}", mtstr, s)); format!("&{}{}", mtstr, s));
}, },
Err(_) => Err(_) =>
span_help!(err.as_mut().unwrap(), t_span, span_help!(err, t_span,
"did you mean `&{}{}`?", mtstr, tstr), "did you mean `&{}{}`?", mtstr, tstr),
} }
} else { } else {
span_help!(err.as_mut().unwrap(), span, span_help!(err, span,
"consider using an implicit coercion to `&{}{}` instead", "consider using an implicit coercion to `&{}{}` instead",
mtstr, tstr); mtstr, tstr);
} }
@ -1068,20 +1068,20 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
ty::TyBox(..) => { ty::TyBox(..) => {
match fcx.tcx().sess.codemap().span_to_snippet(t_span) { match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
Ok(s) => { Ok(s) => {
err.as_mut().unwrap().span_suggestion(t_span, err.span_suggestion(t_span,
"try casting to a `Box` instead:", "try casting to a `Box` instead:",
format!("Box<{}>", s)); format!("Box<{}>", s));
}, },
Err(_) => Err(_) =>
span_help!(err.as_mut().unwrap(), t_span, "did you mean `Box<{}>`?", tstr), span_help!(err, t_span, "did you mean `Box<{}>`?", tstr),
} }
} }
_ => { _ => {
span_help!(err.as_mut().unwrap(), e_span, span_help!(err, e_span,
"consider using a box or reference as appropriate"); "consider using a box or reference as appropriate");
} }
} }
err.map(|mut e| e.emit()); err.emit();
fcx.write_error(id); fcx.write_error(id);
} }
@ -1630,7 +1630,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mk_msg: M, mk_msg: M,
actual_ty: Ty<'tcx>, actual_ty: Ty<'tcx>,
err: Option<&TypeError<'tcx>>) err: Option<&TypeError<'tcx>>)
-> Option<DiagnosticBuilder<'tcx>> -> DiagnosticBuilder<'tcx>
where M: FnOnce(String) -> String, where M: FnOnce(String) -> String,
{ {
self.infcx().type_error_struct(sp, mk_msg, actual_ty, err) self.infcx().type_error_struct(sp, mk_msg, actual_ty, err)
@ -2966,13 +2966,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
`{}`", field.node, actual) `{}`", field.node, actual)
}, },
expr_t, None) expr_t, None)
.unwrap()
.fileline_help(field.span, .fileline_help(field.span,
"maybe a `()` to call it is missing? \ "maybe a `()` to call it is missing? \
If not, try an anonymous function") If not, try an anonymous function")
.emit(); .emit();
} else { } else {
fcx.type_error_struct( let mut err = fcx.type_error_struct(
expr.span, expr.span,
|actual| { |actual| {
format!("attempted access of field `{}` on \ format!("attempted access of field `{}` on \
@ -2981,13 +2980,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
field.node, field.node,
actual) actual)
}, },
expr_t, None) expr_t, None);
.map(|mut e| {
if let ty::TyStruct(def, _) = expr_t.sty { if let ty::TyStruct(def, _) = expr_t.sty {
suggest_field_names(&mut e, def.struct_variant(), field, vec![]); suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
} }
e.emit(); err.emit();
});
} }
fcx.write_error(expr.id); fcx.write_error(expr.id);
@ -3089,7 +3086,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
variant: ty::VariantDef<'tcx>, variant: ty::VariantDef<'tcx>,
field: &hir::Field, field: &hir::Field,
skip_fields: &[hir::Field]) { skip_fields: &[hir::Field]) {
fcx.type_error_struct( let mut err = fcx.type_error_struct(
field.name.span, field.name.span,
|actual| if let ty::TyEnum(..) = ty.sty { |actual| if let ty::TyEnum(..) = ty.sty {
format!("struct variant `{}::{}` has no field named `{}`", format!("struct variant `{}::{}` has no field named `{}`",
@ -3099,13 +3096,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
actual, field.name.node) actual, field.name.node)
}, },
ty, ty,
None) None);
.map(|mut e| {
// prevent all specified fields from being suggested // prevent all specified fields from being suggested
let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str()); let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str());
suggest_field_names(&mut e, variant, &field.name, skip_fields.collect()); suggest_field_names(&mut err, variant, &field.name, skip_fields.collect());
e.emit(); err.emit();
});
} }
fn check_expr_struct_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn check_expr_struct_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,

View file

@ -107,7 +107,6 @@ pub struct DiagnosticBuilder<'a> {
code: Option<String>, code: Option<String>,
span: Option<Span>, span: Option<Span>,
children: Vec<SubDiagnostic>, children: Vec<SubDiagnostic>,
cancelled: bool,
} }
// For example a note attached to an error. // For example a note attached to an error.
@ -121,12 +120,12 @@ struct SubDiagnostic {
impl<'a> DiagnosticBuilder<'a> { impl<'a> DiagnosticBuilder<'a> {
// Emit the diagnostic. // Emit the diagnostic.
pub fn emit(&mut self) { pub fn emit(&mut self) {
if self.cancelled { if self.cancelled() {
return; return;
} }
self.cancel();
self.emitter.borrow_mut().emit_struct(&self); self.emitter.borrow_mut().emit_struct(&self);
self.cancel();
// if self.is_fatal() { // if self.is_fatal() {
// panic!(FatalError); // panic!(FatalError);
@ -135,8 +134,15 @@ impl<'a> DiagnosticBuilder<'a> {
// Cancel the diagnostic (a structured diagnostic must either be emitted or // Cancel the diagnostic (a structured diagnostic must either be emitted or
// cancelled or it will panic when dropped). // cancelled or it will panic when dropped).
// BEWARE: if this DiagnosticBuilder is an error, then creating it will
// bump the error count on the Handler and cancelling it won't undo that.
// If you want to decrement the error count you should use `Handler::cancel`.
pub fn cancel(&mut self) { pub fn cancel(&mut self) {
self.cancelled = true; self.level = Level::Cancelled;
}
pub fn cancelled(&self) -> bool {
self.level == Level::Cancelled
} }
pub fn is_fatal(&self) -> bool { pub fn is_fatal(&self) -> bool {
@ -204,21 +210,28 @@ impl<'a> DiagnosticBuilder<'a> {
self self
} }
pub fn span(&mut self, sp: Span) -> &mut Self {
self.span = Some(sp);
self
}
pub fn code(&mut self, s: String) -> &mut Self {
self.code = Some(s);
self
}
// Convenience function for internal use, clients should use one of the // Convenience function for internal use, clients should use one of the
// struct_* methods on Handler. // struct_* methods on Handler.
fn new(emitter: &'a RefCell<Box<Emitter>>, fn new(emitter: &'a RefCell<Box<Emitter>>,
level: Level, level: Level,
message: &str, message: &str) -> DiagnosticBuilder<'a> {
code: Option<String>,
span: Option<Span>) -> DiagnosticBuilder<'a> {
DiagnosticBuilder { DiagnosticBuilder {
emitter: emitter, emitter: emitter,
level: level, level: level,
message: message.to_owned(), message: message.to_owned(),
code: code, code: None,
span: span, span: None,
children: vec![], children: vec![],
cancelled: false,
} }
} }
@ -249,7 +262,7 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
// we emit a bug. // we emit a bug.
impl<'a> Drop for DiagnosticBuilder<'a> { impl<'a> Drop for DiagnosticBuilder<'a> {
fn drop(&mut self) { fn drop(&mut self) {
if !self.cancelled { if !self.cancelled() {
self.emitter.borrow_mut().emit(None, "Error constructed but not emitted", None, Bug); self.emitter.borrow_mut().emit(None, "Error constructed but not emitted", None, Bug);
panic!(); panic!();
} }
@ -290,11 +303,16 @@ impl Handler {
} }
} }
pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
DiagnosticBuilder::new(&self.emit, Level::Cancelled, "")
}
pub fn struct_span_warn<'a>(&'a self, pub fn struct_span_warn<'a>(&'a self,
sp: Span, sp: Span,
msg: &str) msg: &str)
-> DiagnosticBuilder<'a> { -> DiagnosticBuilder<'a> {
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg, None, Some(sp)); let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
result.span(sp);
if !self.can_emit_warnings { if !self.can_emit_warnings {
result.cancel(); result.cancel();
} }
@ -305,18 +323,16 @@ impl Handler {
msg: &str, msg: &str,
code: &str) code: &str)
-> DiagnosticBuilder<'a> { -> DiagnosticBuilder<'a> {
let mut result = DiagnosticBuilder::new(&self.emit, let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
Level::Warning, result.span(sp);
msg, result.code(code.to_owned());
Some(code.to_owned()),
Some(sp));
if !self.can_emit_warnings { if !self.can_emit_warnings {
result.cancel(); result.cancel();
} }
result result
} }
pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg, None, None); let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
if !self.can_emit_warnings { if !self.can_emit_warnings {
result.cancel(); result.cancel();
} }
@ -327,28 +343,33 @@ impl Handler {
msg: &str) msg: &str)
-> DiagnosticBuilder<'a> { -> DiagnosticBuilder<'a> {
self.bump_err_count(); self.bump_err_count();
DiagnosticBuilder::new(&self.emit, Level::Error, msg, None, Some(sp)) let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
result.span(sp);
result
} }
pub fn struct_span_err_with_code<'a>(&'a self, pub fn struct_span_err_with_code<'a>(&'a self,
sp: Span, sp: Span,
msg: &str, msg: &str,
code: &str) code: &str)
-> DiagnosticBuilder<'a> { -> DiagnosticBuilder<'a> {
// FIXME (and below) this is potentially inaccurate, since the DiagnosticBuilder
// might be cancelled.
self.bump_err_count(); self.bump_err_count();
DiagnosticBuilder::new(&self.emit, Level::Error, msg, Some(code.to_owned()), Some(sp)) let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
result.span(sp);
result.code(code.to_owned());
result
} }
pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
self.bump_err_count(); self.bump_err_count();
DiagnosticBuilder::new(&self.emit, Level::Error, msg, None, None) DiagnosticBuilder::new(&self.emit, Level::Error, msg)
} }
pub fn struct_span_fatal<'a>(&'a self, pub fn struct_span_fatal<'a>(&'a self,
sp: Span, sp: Span,
msg: &str) msg: &str)
-> DiagnosticBuilder<'a> { -> DiagnosticBuilder<'a> {
self.bump_err_count(); self.bump_err_count();
DiagnosticBuilder::new(&self.emit, Level::Fatal, msg, None, Some(sp)) let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
result.span(sp);
result
} }
pub fn struct_span_fatal_with_code<'a>(&'a self, pub fn struct_span_fatal_with_code<'a>(&'a self,
sp: Span, sp: Span,
@ -356,11 +377,22 @@ impl Handler {
code: &str) code: &str)
-> DiagnosticBuilder<'a> { -> DiagnosticBuilder<'a> {
self.bump_err_count(); self.bump_err_count();
DiagnosticBuilder::new(&self.emit, Level::Fatal, msg, Some(code.to_owned()), Some(sp)) let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
result.span(sp);
result.code(code.to_owned());
result
} }
pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
self.bump_err_count(); self.bump_err_count();
DiagnosticBuilder::new(&self.emit, Level::Fatal, msg, None, None) DiagnosticBuilder::new(&self.emit, Level::Fatal, msg)
}
pub fn cancel(&mut self, err: &mut DiagnosticBuilder) {
if err.level == Level::Error || err.level == Level::Fatal {
assert!(self.has_errors());
self.err_count.set(self.err_count.get() + 1);
}
err.cancel();
} }
pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError { pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError {
@ -514,6 +546,7 @@ pub enum Level {
Warning, Warning,
Note, Note,
Help, Help,
Cancelled,
} }
impl fmt::Display for Level { impl fmt::Display for Level {
@ -526,6 +559,7 @@ impl fmt::Display for Level {
Warning => "warning".fmt(f), Warning => "warning".fmt(f),
Note => "note".fmt(f), Note => "note".fmt(f),
Help => "help".fmt(f), Help => "help".fmt(f),
Cancelled => unreachable!(),
} }
} }
} }
@ -537,6 +571,7 @@ impl Level {
Warning => term::color::BRIGHT_YELLOW, Warning => term::color::BRIGHT_YELLOW,
Note => term::color::BRIGHT_GREEN, Note => term::color::BRIGHT_GREEN,
Help => term::color::BRIGHT_CYAN, Help => term::color::BRIGHT_CYAN,
Cancelled => unreachable!(),
} }
} }
} }