mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-16 17:03:35 +00:00
Auto merge of #30542 - nrc:errs-base, r=nagisa
As discussed [here](https://internals.rust-lang.org/t/more-structured-errors/3005) r? @nikomatsakis or anyone else on the @rust-lang/compiler team
This commit is contained in:
commit
176ee349a7
@ -40,6 +40,7 @@ use std::mem;
|
||||
use syntax::ast_util::{self, IdVisitingOperation};
|
||||
use syntax::attr::{self, AttrMetaMethods};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::errors::{self, DiagnosticBuilder};
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::ast;
|
||||
use syntax::attr::ThinAttributesExt;
|
||||
@ -47,7 +48,6 @@ use rustc_front::hir;
|
||||
use rustc_front::util;
|
||||
use rustc_front::intravisit as hir_visit;
|
||||
use syntax::visit as ast_visit;
|
||||
use syntax::errors;
|
||||
|
||||
/// Information about the registered lints.
|
||||
///
|
||||
@ -363,10 +363,24 @@ pub fn gather_attrs(attrs: &[ast::Attribute])
|
||||
/// in trans that run after the main lint pass is finished. Most
|
||||
/// lints elsewhere in the compiler should call
|
||||
/// `Session::add_lint()` instead.
|
||||
pub fn raw_emit_lint(sess: &Session, lint: &'static Lint,
|
||||
lvlsrc: LevelSource, span: Option<Span>, msg: &str) {
|
||||
pub fn raw_emit_lint(sess: &Session,
|
||||
lint: &'static Lint,
|
||||
lvlsrc: LevelSource,
|
||||
span: Option<Span>,
|
||||
msg: &str) {
|
||||
raw_struct_lint(sess, lint, lvlsrc, span, msg).emit();
|
||||
}
|
||||
|
||||
pub fn raw_struct_lint<'a>(sess: &'a Session,
|
||||
lint: &'static Lint,
|
||||
lvlsrc: LevelSource,
|
||||
span: Option<Span>,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
let (mut level, source) = lvlsrc;
|
||||
if level == Allow { return }
|
||||
if level == Allow {
|
||||
return sess.diagnostic().struct_dummy();
|
||||
}
|
||||
|
||||
let name = lint.name_lower();
|
||||
let mut def = None;
|
||||
@ -391,17 +405,19 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint,
|
||||
// For purposes of printing, we can treat forbid as deny.
|
||||
if level == Forbid { level = Deny; }
|
||||
|
||||
match (level, span) {
|
||||
(Warn, Some(sp)) => sess.span_warn(sp, &msg[..]),
|
||||
(Warn, None) => sess.warn(&msg[..]),
|
||||
(Deny, Some(sp)) => sess.span_err(sp, &msg[..]),
|
||||
(Deny, None) => sess.err(&msg[..]),
|
||||
let mut err = match (level, span) {
|
||||
(Warn, Some(sp)) => sess.struct_span_warn(sp, &msg[..]),
|
||||
(Warn, None) => sess.struct_warn(&msg[..]),
|
||||
(Deny, Some(sp)) => sess.struct_span_err(sp, &msg[..]),
|
||||
(Deny, None) => sess.struct_err(&msg[..]),
|
||||
_ => sess.bug("impossible level in raw_emit_lint"),
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(span) = def {
|
||||
sess.span_note(span, "lint level defined here");
|
||||
err.span_note(span, "lint level defined here");
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub trait LintContext: Sized {
|
||||
@ -418,44 +434,74 @@ pub trait LintContext: Sized {
|
||||
self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
|
||||
}
|
||||
|
||||
fn lookup_and_emit(&self, lint: &'static Lint, span: Option<Span>, msg: &str) {
|
||||
let (level, src) = match self.lints().levels.get(&LintId::of(lint)) {
|
||||
None => return,
|
||||
Some(&(Warn, src)) => {
|
||||
fn level_src(&self, lint: &'static Lint) -> Option<LevelSource> {
|
||||
self.lints().levels.get(&LintId::of(lint)).map(|ls| match ls {
|
||||
&(Warn, src) => {
|
||||
let lint_id = LintId::of(builtin::WARNINGS);
|
||||
(self.lints().get_level_source(lint_id).0, src)
|
||||
}
|
||||
Some(&pair) => pair,
|
||||
_ => *ls
|
||||
})
|
||||
}
|
||||
|
||||
fn lookup_and_emit(&self, lint: &'static Lint, span: Option<Span>, msg: &str) {
|
||||
let (level, src) = match self.level_src(lint) {
|
||||
None => return,
|
||||
Some(pair) => pair,
|
||||
};
|
||||
|
||||
raw_emit_lint(&self.sess(), lint, (level, src), span, msg);
|
||||
}
|
||||
|
||||
fn lookup(&self,
|
||||
lint: &'static Lint,
|
||||
span: Option<Span>,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder {
|
||||
let (level, src) = match self.level_src(lint) {
|
||||
None => return self.sess().diagnostic().struct_dummy(),
|
||||
Some(pair) => pair,
|
||||
};
|
||||
|
||||
raw_struct_lint(&self.sess(), lint, (level, src), span, msg)
|
||||
}
|
||||
|
||||
/// Emit a lint at the appropriate level, for a particular span.
|
||||
fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
|
||||
self.lookup_and_emit(lint, Some(span), msg);
|
||||
}
|
||||
|
||||
fn struct_span_lint(&self,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder {
|
||||
self.lookup(lint, Some(span), msg)
|
||||
}
|
||||
|
||||
/// 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,
|
||||
note_span: Span, note: &str) {
|
||||
self.span_lint(lint, span, msg);
|
||||
let mut err = self.lookup(lint, Some(span), msg);
|
||||
if self.current_level(lint) != Level::Allow {
|
||||
if note_span == span {
|
||||
self.sess().fileline_note(note_span, note)
|
||||
err.fileline_note(note_span, note);
|
||||
} else {
|
||||
self.sess().span_note(note_span, note)
|
||||
err.span_note(note_span, note);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
/// Emit a lint and help at the appropriate level, for a particular span.
|
||||
fn span_lint_help(&self, lint: &'static Lint, span: Span,
|
||||
msg: &str, help: &str) {
|
||||
let mut err = self.lookup(lint, Some(span), msg);
|
||||
self.span_lint(lint, span, msg);
|
||||
if self.current_level(lint) != Level::Allow {
|
||||
self.sess().span_help(span, help)
|
||||
err.span_help(span, help);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
/// Emit a lint at the appropriate level, with no associated span.
|
||||
|
@ -41,7 +41,7 @@ use rustc_front::hir;
|
||||
|
||||
pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
|
||||
raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
|
||||
GatherNodeLevels};
|
||||
raw_struct_lint, GatherNodeLevels};
|
||||
|
||||
/// Specification of a single lint.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -224,14 +224,15 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
|
||||
// this doesn't come from a macro that has #[allow_internal_unstable]
|
||||
!self.tcx.sess.codemap().span_allows_unstable(expr.span)
|
||||
{
|
||||
self.tcx.sess.span_err(
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
expr.span,
|
||||
"const fns are an unstable feature");
|
||||
fileline_help!(
|
||||
self.tcx.sess,
|
||||
&mut err,
|
||||
expr.span,
|
||||
"in Nightly builds, add `#![feature(const_fn)]` to the crate \
|
||||
attributes to enable");
|
||||
err.emit();
|
||||
}
|
||||
|
||||
let qualif = self.fn_like(fn_like.kind(),
|
||||
@ -714,27 +715,27 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
||||
if !is_const {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
if v.mode != Mode::Var {
|
||||
fn span_limited_call_error(tcx: &ty::ctxt, span: Span, s: &str) {
|
||||
span_err!(tcx.sess, span, E0015, "{}", s);
|
||||
}
|
||||
|
||||
// FIXME(#24111) Remove this check when const fn stabilizes
|
||||
if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features {
|
||||
span_limited_call_error(&v.tcx, e.span,
|
||||
&format!("function calls in {}s are limited to \
|
||||
struct and enum constructors",
|
||||
v.msg()));
|
||||
v.tcx.sess.span_note(e.span,
|
||||
"a limited form of compile-time function \
|
||||
evaluation is available on a nightly \
|
||||
compiler via `const fn`");
|
||||
let (msg, note) =
|
||||
if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features {
|
||||
(format!("function calls in {}s are limited to \
|
||||
struct and enum constructors",
|
||||
v.msg()),
|
||||
Some("a limited form of compile-time function \
|
||||
evaluation is available on a nightly \
|
||||
compiler via `const fn`"))
|
||||
} else {
|
||||
span_limited_call_error(&v.tcx, e.span,
|
||||
&format!("function calls in {}s are limited \
|
||||
to constant functions, \
|
||||
struct and enum constructors",
|
||||
v.msg()));
|
||||
(format!("function calls in {}s are limited \
|
||||
to constant functions, \
|
||||
struct and enum constructors",
|
||||
v.msg()),
|
||||
None)
|
||||
};
|
||||
let mut err = struct_span_err!(v.tcx.sess, e.span, E0015, "{}", msg);
|
||||
if let Some(note) = note {
|
||||
err.span_note(e.span, note);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,12 +215,13 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
|
||||
if inlined_arms.is_empty() {
|
||||
if !pat_ty.is_empty(cx.tcx) {
|
||||
// We know the type is inhabited, so this must be wrong
|
||||
span_err!(cx.tcx.sess, ex.span, E0002,
|
||||
"non-exhaustive patterns: type {} is non-empty",
|
||||
pat_ty);
|
||||
span_help!(cx.tcx.sess, ex.span,
|
||||
let mut err = struct_span_err!(cx.tcx.sess, ex.span, E0002,
|
||||
"non-exhaustive patterns: type {} is non-empty",
|
||||
pat_ty);
|
||||
span_help!(&mut err, ex.span,
|
||||
"Please ensure that all possible cases are being handled; \
|
||||
possibly adding wildcards or more match arms.");
|
||||
err.emit();
|
||||
}
|
||||
// If the type *is* empty, it's vacuously exhaustive
|
||||
return;
|
||||
@ -251,14 +252,15 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
|
||||
&& variant.kind() == VariantKind::Unit
|
||||
) {
|
||||
let ty_path = cx.tcx.item_path_str(edef.did);
|
||||
span_warn!(cx.tcx.sess, p.span, E0170,
|
||||
let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
|
||||
"pattern binding `{}` is named the same as one \
|
||||
of the variants of the type `{}`",
|
||||
ident.node, ty_path);
|
||||
fileline_help!(cx.tcx.sess, p.span,
|
||||
fileline_help!(err, p.span,
|
||||
"if you meant to match on a variant, \
|
||||
consider making the path in the pattern qualified: `{}::{}`",
|
||||
ty_path, ident.node);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -282,13 +284,13 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
|
||||
Ok(_) => {}
|
||||
|
||||
Err(err) => {
|
||||
span_err!(cx.tcx.sess, err.span, E0471,
|
||||
"constant evaluation error: {}",
|
||||
err.description());
|
||||
let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471,
|
||||
"constant evaluation error: {}",
|
||||
err.description());
|
||||
if !p.span.contains(err.span) {
|
||||
cx.tcx.sess.span_note(p.span,
|
||||
"in pattern here")
|
||||
diag.span_note(p.span, "in pattern here");
|
||||
}
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1076,9 +1078,10 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
|
||||
} else if has_guard {
|
||||
span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard");
|
||||
} else if by_ref_span.is_some() {
|
||||
span_err!(cx.tcx.sess, p.span, E0009,
|
||||
"cannot bind by-move and by-ref in the same pattern");
|
||||
span_note!(cx.tcx.sess, by_ref_span.unwrap(), "by-ref binding occurs here");
|
||||
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0009,
|
||||
"cannot bind by-move and by-ref in the same pattern");
|
||||
span_note!(&mut err, by_ref_span.unwrap(), "by-ref binding occurs here");
|
||||
err.emit();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -243,10 +243,11 @@ fn add_library(sess: &session::Session,
|
||||
// This error is probably a little obscure, but I imagine that it
|
||||
// can be refined over time.
|
||||
if link2 != link || link == RequireStatic {
|
||||
sess.err(&format!("cannot satisfy dependencies so `{}` only \
|
||||
shows up once", sess.cstore.crate_name(cnum)));
|
||||
sess.help("having upstream crates all available in one format \
|
||||
will likely make this go away");
|
||||
sess.struct_err(&format!("cannot satisfy dependencies so `{}` only \
|
||||
shows up once", sess.cstore.crate_name(cnum)))
|
||||
.help("having upstream crates all available in one format \
|
||||
will likely make this go away")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
None => { m.insert(cnum, link); }
|
||||
|
@ -146,17 +146,20 @@ fn configure_main(this: &mut EntryContext) {
|
||||
this.session.entry_type.set(Some(config::EntryMain));
|
||||
} else {
|
||||
// No main function
|
||||
this.session.err("main function not found");
|
||||
let mut err = this.session.struct_err("main function not found");
|
||||
if !this.non_main_fns.is_empty() {
|
||||
// There were some functions named 'main' though. Try to give the user a hint.
|
||||
this.session.note("the main function must be defined at the crate level \
|
||||
but you have one or more functions named 'main' that are not \
|
||||
defined at the crate level. Either move the definition or \
|
||||
attach the `#[main]` attribute to override this behavior.");
|
||||
err.note("the main function must be defined at the crate level \
|
||||
but you have one or more functions named 'main' that are not \
|
||||
defined at the crate level. Either move the definition or \
|
||||
attach the `#[main]` attribute to override this behavior.");
|
||||
for &(_, span) in &this.non_main_fns {
|
||||
this.session.span_note(span, "here is a function named 'main'");
|
||||
err.span_note(span, "here is a function named 'main'");
|
||||
}
|
||||
err.emit();
|
||||
this.session.abort_if_errors();
|
||||
} else {
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,12 +90,14 @@ use std::cell::{Cell, RefCell};
|
||||
use std::char::from_u32;
|
||||
use std::fmt;
|
||||
use syntax::ast;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::codemap::{self, Pos, Span};
|
||||
use syntax::parse::token;
|
||||
use syntax::ptr::P;
|
||||
|
||||
impl<'tcx> ty::ctxt<'tcx> {
|
||||
pub fn note_and_explain_region(&self,
|
||||
err: &mut DiagnosticBuilder,
|
||||
prefix: &str,
|
||||
region: ty::Region,
|
||||
suffix: &str) {
|
||||
@ -126,7 +128,10 @@ impl<'tcx> ty::ctxt<'tcx> {
|
||||
};
|
||||
let span = match scope.span(&self.region_maps, &self.map) {
|
||||
Some(s) => s,
|
||||
None => return self.sess.note(&unknown_scope())
|
||||
None => {
|
||||
err.note(&unknown_scope());
|
||||
return;
|
||||
}
|
||||
};
|
||||
let tag = match self.map.find(scope.node_id(&self.region_maps)) {
|
||||
Some(ast_map::NodeBlock(_)) => "block",
|
||||
@ -142,7 +147,8 @@ impl<'tcx> ty::ctxt<'tcx> {
|
||||
Some(ast_map::NodeStmt(_)) => "statement",
|
||||
Some(ast_map::NodeItem(it)) => item_scope_tag(&*it),
|
||||
Some(_) | None => {
|
||||
return self.sess.span_note(span, &unknown_scope());
|
||||
err.span_note(span, &unknown_scope());
|
||||
return;
|
||||
}
|
||||
};
|
||||
let scope_decorated_tag = match self.region_maps.code_extent_data(scope) {
|
||||
@ -214,9 +220,9 @@ impl<'tcx> ty::ctxt<'tcx> {
|
||||
};
|
||||
let message = format!("{}{}{}", prefix, description, suffix);
|
||||
if let Some(span) = span {
|
||||
self.sess.span_note(span, &message);
|
||||
err.span_note(span, &message);
|
||||
} else {
|
||||
self.sess.note(&message);
|
||||
err.note(&message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -228,9 +234,15 @@ pub trait ErrorReporting<'tcx> {
|
||||
fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
|
||||
-> Vec<RegionResolutionError<'tcx>>;
|
||||
|
||||
fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>);
|
||||
fn report_type_error(&self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
terr: &TypeError<'tcx>)
|
||||
-> DiagnosticBuilder<'tcx>;
|
||||
|
||||
fn check_and_note_conflicting_crates(&self, terr: &TypeError<'tcx>, sp: Span);
|
||||
fn check_and_note_conflicting_crates(&self,
|
||||
err: &mut DiagnosticBuilder,
|
||||
terr: &TypeError<'tcx>,
|
||||
sp: Span);
|
||||
|
||||
fn report_and_explain_type_error(&self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
@ -265,17 +277,20 @@ pub trait ErrorReporting<'tcx> {
|
||||
trace_origin: &[(TypeTrace<'tcx>, TypeError<'tcx>)],
|
||||
same_regions: &[SameRegions]);
|
||||
|
||||
fn give_suggestion(&self, same_regions: &[SameRegions]);
|
||||
fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]);
|
||||
}
|
||||
|
||||
trait ErrorReportingHelpers<'tcx> {
|
||||
fn report_inference_failure(&self,
|
||||
var_origin: RegionVariableOrigin);
|
||||
var_origin: RegionVariableOrigin)
|
||||
-> DiagnosticBuilder<'tcx>;
|
||||
|
||||
fn note_region_origin(&self,
|
||||
err: &mut DiagnosticBuilder,
|
||||
origin: &SubregionOrigin<'tcx>);
|
||||
|
||||
fn give_expl_lifetime_param(&self,
|
||||
err: &mut DiagnosticBuilder,
|
||||
decl: &hir::FnDecl,
|
||||
unsafety: hir::Unsafety,
|
||||
constness: hir::Constness,
|
||||
@ -460,35 +475,47 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) {
|
||||
fn report_type_error(&self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
terr: &TypeError<'tcx>)
|
||||
-> DiagnosticBuilder<'tcx> {
|
||||
let expected_found_str = match self.values_str(&trace.values) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
return; /* derived error */
|
||||
return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */
|
||||
}
|
||||
};
|
||||
|
||||
span_err!(self.tcx.sess, trace.origin.span(), E0308,
|
||||
"{}: {} ({})",
|
||||
trace.origin,
|
||||
expected_found_str,
|
||||
terr);
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
trace.origin.span(),
|
||||
E0308,
|
||||
"{}: {} ({})",
|
||||
trace.origin,
|
||||
expected_found_str,
|
||||
terr);
|
||||
|
||||
self.check_and_note_conflicting_crates(terr, trace.origin.span());
|
||||
self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span());
|
||||
|
||||
match trace.origin {
|
||||
TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
|
||||
hir::MatchSource::IfLetDesugar{..} =>
|
||||
self.tcx.sess.span_note(arm_span, "`if let` arm with an incompatible type"),
|
||||
_ => self.tcx.sess.span_note(arm_span, "match arm with an incompatible type"),
|
||||
hir::MatchSource::IfLetDesugar{..} => {
|
||||
err.span_note(arm_span, "`if let` arm with an incompatible type");
|
||||
}
|
||||
_ => {
|
||||
err.span_note(arm_span, "match arm with an incompatible type");
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
err
|
||||
}
|
||||
|
||||
/// Adds a note if the types come from similarly named crates
|
||||
fn check_and_note_conflicting_crates(&self, terr: &TypeError<'tcx>, sp: Span) {
|
||||
let report_path_match = |did1: DefId, did2: DefId| {
|
||||
fn check_and_note_conflicting_crates(&self,
|
||||
err: &mut DiagnosticBuilder,
|
||||
terr: &TypeError<'tcx>,
|
||||
sp: Span) {
|
||||
let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| {
|
||||
// Only external crates, if either is from a local
|
||||
// module we could have false positives
|
||||
if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
|
||||
@ -502,9 +529,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
// for imported and non-imported crates
|
||||
if exp_path == found_path {
|
||||
let crate_name = self.tcx.sess.cstore.crate_name(did1.krate);
|
||||
self.tcx.sess.span_note(sp, &format!("Perhaps two different versions \
|
||||
of crate `{}` are being used?",
|
||||
crate_name));
|
||||
err.span_note(sp, &format!("Perhaps two different versions \
|
||||
of crate `{}` are being used?",
|
||||
crate_name));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -517,13 +544,13 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
(&ty::TyStruct(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) |
|
||||
(&ty::TyEnum(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) |
|
||||
(&ty::TyStruct(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) => {
|
||||
report_path_match(exp_adt.did, found_adt.did);
|
||||
report_path_match(err, exp_adt.did, found_adt.did);
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
},
|
||||
TypeError::Traits(ref exp_found) => {
|
||||
report_path_match(exp_found.expected, exp_found.found);
|
||||
report_path_match(err, exp_found.expected, exp_found.found);
|
||||
},
|
||||
_ => () // FIXME(#22750) handle traits and stuff
|
||||
}
|
||||
@ -533,8 +560,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
trace: TypeTrace<'tcx>,
|
||||
terr: &TypeError<'tcx>) {
|
||||
let span = trace.origin.span();
|
||||
self.report_type_error(trace, terr);
|
||||
self.tcx.note_and_explain_type_err(terr, span);
|
||||
let mut err = self.report_type_error(trace, terr);
|
||||
self.tcx.note_and_explain_type_err(&mut err, terr, span);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
/// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived
|
||||
@ -584,51 +612,56 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
format!("the associated type `{}`", p),
|
||||
};
|
||||
|
||||
match sub {
|
||||
let mut err = match sub {
|
||||
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
|
||||
// Does the required lifetime have a nice name we can print?
|
||||
span_err!(
|
||||
self.tcx.sess, origin.span(), E0309,
|
||||
"{} may not live long enough", labeled_user_string);
|
||||
self.tcx.sess.fileline_help(
|
||||
origin.span(),
|
||||
&format!(
|
||||
"consider adding an explicit lifetime bound `{}: {}`...",
|
||||
bound_kind,
|
||||
sub));
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
origin.span(),
|
||||
E0309,
|
||||
"{} may not live long enough",
|
||||
labeled_user_string);
|
||||
err.fileline_help(origin.span(),
|
||||
&format!("consider adding an explicit lifetime bound `{}: {}`...",
|
||||
bound_kind,
|
||||
sub));
|
||||
err
|
||||
}
|
||||
|
||||
ty::ReStatic => {
|
||||
// Does the required lifetime have a nice name we can print?
|
||||
span_err!(
|
||||
self.tcx.sess, origin.span(), E0310,
|
||||
"{} may not live long enough", labeled_user_string);
|
||||
self.tcx.sess.fileline_help(
|
||||
origin.span(),
|
||||
&format!(
|
||||
"consider adding an explicit lifetime bound `{}: 'static`...",
|
||||
bound_kind));
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
origin.span(),
|
||||
E0310,
|
||||
"{} may not live long enough",
|
||||
labeled_user_string);
|
||||
err.fileline_help(origin.span(),
|
||||
&format!("consider adding an explicit lifetime \
|
||||
bound `{}: 'static`...",
|
||||
bound_kind));
|
||||
err
|
||||
}
|
||||
|
||||
_ => {
|
||||
// If not, be less specific.
|
||||
span_err!(
|
||||
self.tcx.sess, origin.span(), E0311,
|
||||
"{} may not live long enough",
|
||||
labeled_user_string);
|
||||
self.tcx.sess.fileline_help(
|
||||
origin.span(),
|
||||
&format!(
|
||||
"consider adding an explicit lifetime bound for `{}`",
|
||||
bound_kind));
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
origin.span(),
|
||||
E0311,
|
||||
"{} may not live long enough",
|
||||
labeled_user_string);
|
||||
err.fileline_help(origin.span(),
|
||||
&format!("consider adding an explicit lifetime bound for `{}`",
|
||||
bound_kind));
|
||||
self.tcx.note_and_explain_region(
|
||||
&mut err,
|
||||
&format!("{} must be valid for ", labeled_user_string),
|
||||
sub,
|
||||
"...");
|
||||
err
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.note_region_origin(&origin);
|
||||
self.note_region_origin(&mut err, &origin);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn report_concrete_failure(&self,
|
||||
@ -641,239 +674,262 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
self.report_and_explain_type_error(trace, &terr);
|
||||
}
|
||||
infer::Reborrow(span) => {
|
||||
span_err!(self.tcx.sess, span, E0312,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0312,
|
||||
"lifetime of reference outlines \
|
||||
lifetime of borrowed content...");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"...the reference is valid for ",
|
||||
sub,
|
||||
"...");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"...but the borrowed content is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
||||
span_err!(self.tcx.sess, span, E0313,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0313,
|
||||
"lifetime of borrowed pointer outlives \
|
||||
lifetime of captured variable `{}`...",
|
||||
self.tcx.local_var_name_str(upvar_id.var_id));
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"...the borrowed pointer is valid for ",
|
||||
sub,
|
||||
"...");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
&format!("...but `{}` is only valid for ",
|
||||
self.tcx.local_var_name_str(upvar_id.var_id)),
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::InfStackClosure(span) => {
|
||||
span_err!(self.tcx.sess, span, E0314,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0314,
|
||||
"closure outlives stack frame");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"...the closure must be valid for ",
|
||||
sub,
|
||||
"...");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"...but the closure's stack frame is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::InvokeClosure(span) => {
|
||||
span_err!(self.tcx.sess, span, E0315,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0315,
|
||||
"cannot invoke closure outside of its lifetime");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the closure is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::DerefPointer(span) => {
|
||||
span_err!(self.tcx.sess, span, E0473,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0473,
|
||||
"dereference of reference outside its lifetime");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the reference is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::FreeVariable(span, id) => {
|
||||
span_err!(self.tcx.sess, span, E0474,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0474,
|
||||
"captured variable `{}` does not outlive the enclosing closure",
|
||||
self.tcx.local_var_name_str(id));
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"captured variable is valid for ",
|
||||
sup,
|
||||
"");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"closure is valid for ",
|
||||
sub,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::IndexSlice(span) => {
|
||||
span_err!(self.tcx.sess, span, E0475,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0475,
|
||||
"index of slice outside its lifetime");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the slice is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::RelateObjectBound(span) => {
|
||||
span_err!(self.tcx.sess, span, E0476,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0476,
|
||||
"lifetime of the source pointer does not outlive \
|
||||
lifetime bound of the object type");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"object type is valid for ",
|
||||
sub,
|
||||
"");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"source pointer is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::RelateParamBound(span, ty) => {
|
||||
span_err!(self.tcx.sess, span, E0477,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0477,
|
||||
"the type `{}` does not fulfill the required lifetime",
|
||||
self.ty_to_string(ty));
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"type must outlive ",
|
||||
sub,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
span_err!(self.tcx.sess, span, E0478,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0478,
|
||||
"lifetime bound not satisfied");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"lifetime parameter instantiated with ",
|
||||
sup,
|
||||
"");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"but lifetime parameter must outlive ",
|
||||
sub,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::RelateDefaultParamBound(span, ty) => {
|
||||
span_err!(self.tcx.sess, span, E0479,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0479,
|
||||
"the type `{}` (provided as the value of \
|
||||
a type parameter) is not valid at this point",
|
||||
self.ty_to_string(ty));
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"type must outlive ",
|
||||
sub,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::CallRcvr(span) => {
|
||||
span_err!(self.tcx.sess, span, E0480,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0480,
|
||||
"lifetime of method receiver does not outlive \
|
||||
the method call");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the receiver is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::CallArg(span) => {
|
||||
span_err!(self.tcx.sess, span, E0481,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0481,
|
||||
"lifetime of function argument does not outlive \
|
||||
the function call");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the function argument is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::CallReturn(span) => {
|
||||
span_err!(self.tcx.sess, span, E0482,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0482,
|
||||
"lifetime of return value does not outlive \
|
||||
the function call");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the return value is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::Operand(span) => {
|
||||
span_err!(self.tcx.sess, span, E0483,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0483,
|
||||
"lifetime of operand does not outlive \
|
||||
the operation");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the operand is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::AddrOf(span) => {
|
||||
span_err!(self.tcx.sess, span, E0484,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0484,
|
||||
"reference is not valid at the time of borrow");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the borrow is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::AutoBorrow(span) => {
|
||||
span_err!(self.tcx.sess, span, E0485,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0485,
|
||||
"automatically reference is not valid \
|
||||
at the time of borrow");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the automatic borrow is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::ExprTypeIsNotInScope(t, span) => {
|
||||
span_err!(self.tcx.sess, span, E0486,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0486,
|
||||
"type of expression contains references \
|
||||
that are not valid during the expression: `{}`",
|
||||
self.ty_to_string(t));
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"type is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::SafeDestructor(span) => {
|
||||
span_err!(self.tcx.sess, span, E0487,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0487,
|
||||
"unsafe use of destructor: destructor might be called \
|
||||
while references are dead");
|
||||
// FIXME (22171): terms "super/subregion" are suboptimal
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"superregion: ",
|
||||
sup,
|
||||
"");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"subregion: ",
|
||||
sub,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::BindingTypeIsNotValidAtDecl(span) => {
|
||||
span_err!(self.tcx.sess, span, E0488,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0488,
|
||||
"lifetime of variable does not enclose its declaration");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the variable is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::ParameterInScope(_, span) => {
|
||||
span_err!(self.tcx.sess, span, E0489,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0489,
|
||||
"type/lifetime parameter not in scope here");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the parameter is only valid for ",
|
||||
sub,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
infer::DataBorrowed(ty, span) => {
|
||||
span_err!(self.tcx.sess, span, E0490,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0490,
|
||||
"a value of type `{}` is borrowed for too long",
|
||||
self.ty_to_string(ty));
|
||||
self.tcx.note_and_explain_region("the type is valid for ", sub, "");
|
||||
self.tcx.note_and_explain_region("but the borrow lasts for ", sup, "");
|
||||
self.tcx.note_and_explain_region(&mut err, "the type is valid for ", sub, "");
|
||||
self.tcx.note_and_explain_region(&mut err, "but the borrow lasts for ", sup, "");
|
||||
err.emit();
|
||||
}
|
||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||
span_err!(self.tcx.sess, span, E0491,
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0491,
|
||||
"in type `{}`, reference has a longer lifetime \
|
||||
than the data it references",
|
||||
self.ty_to_string(ty));
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"the pointer is valid for ",
|
||||
sub,
|
||||
"");
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"but the referenced data is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -884,37 +940,42 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
sub_region: Region,
|
||||
sup_origin: SubregionOrigin<'tcx>,
|
||||
sup_region: Region) {
|
||||
self.report_inference_failure(var_origin);
|
||||
let mut err = self.report_inference_failure(var_origin);
|
||||
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"first, the lifetime cannot outlive ",
|
||||
sup_region,
|
||||
"...");
|
||||
|
||||
self.note_region_origin(&sup_origin);
|
||||
self.note_region_origin(&mut err, &sup_origin);
|
||||
|
||||
self.tcx.note_and_explain_region(
|
||||
self.tcx.note_and_explain_region(&mut err,
|
||||
"but, the lifetime must be valid for ",
|
||||
sub_region,
|
||||
"...");
|
||||
|
||||
self.note_region_origin(&sub_origin);
|
||||
self.note_region_origin(&mut err, &sub_origin);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn report_processed_errors(&self,
|
||||
var_origins: &[RegionVariableOrigin],
|
||||
trace_origins: &[(TypeTrace<'tcx>, TypeError<'tcx>)],
|
||||
same_regions: &[SameRegions]) {
|
||||
for vo in var_origins {
|
||||
self.report_inference_failure(vo.clone());
|
||||
for (i, vo) in var_origins.iter().enumerate() {
|
||||
let mut err = self.report_inference_failure(vo.clone());
|
||||
if i == var_origins.len() - 1 {
|
||||
self.give_suggestion(&mut err, same_regions);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
self.give_suggestion(same_regions);
|
||||
|
||||
for &(ref trace, ref terr) in trace_origins {
|
||||
self.report_and_explain_type_error(trace.clone(), terr);
|
||||
}
|
||||
}
|
||||
|
||||
fn give_suggestion(&self, same_regions: &[SameRegions]) {
|
||||
fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]) {
|
||||
let scope_id = same_regions[0].scope_id;
|
||||
let parent = self.tcx.map.get_parent(scope_id);
|
||||
let parent_node = self.tcx.map.find(parent);
|
||||
@ -968,7 +1029,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self,
|
||||
generics, same_regions, &life_giver);
|
||||
let (fn_decl, expl_self, generics) = rebuilder.rebuild();
|
||||
self.give_expl_lifetime_param(&fn_decl, unsafety, constness, name,
|
||||
self.give_expl_lifetime_param(err, &fn_decl, unsafety, constness, name,
|
||||
expl_self.as_ref(), &generics, span);
|
||||
}
|
||||
}
|
||||
@ -1520,6 +1581,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
|
||||
|
||||
impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
fn give_expl_lifetime_param(&self,
|
||||
err: &mut DiagnosticBuilder,
|
||||
decl: &hir::FnDecl,
|
||||
unsafety: hir::Unsafety,
|
||||
constness: hir::Constness,
|
||||
@ -1531,11 +1593,12 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
opt_explicit_self, generics);
|
||||
let msg = format!("consider using an explicit lifetime \
|
||||
parameter as shown: {}", suggested_fn);
|
||||
self.tcx.sess.span_help(span, &msg[..]);
|
||||
err.span_help(span, &msg[..]);
|
||||
}
|
||||
|
||||
fn report_inference_failure(&self,
|
||||
var_origin: RegionVariableOrigin) {
|
||||
var_origin: RegionVariableOrigin)
|
||||
-> DiagnosticBuilder<'tcx> {
|
||||
let br_string = |br: ty::BoundRegion| {
|
||||
let mut s = br.to_string();
|
||||
if !s.is_empty() {
|
||||
@ -1574,13 +1637,13 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
span_err!(self.tcx.sess, var_origin.span(), E0495,
|
||||
struct_span_err!(self.tcx.sess, var_origin.span(), E0495,
|
||||
"cannot infer an appropriate lifetime{} \
|
||||
due to conflicting requirements",
|
||||
var_description);
|
||||
var_description)
|
||||
}
|
||||
|
||||
fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) {
|
||||
fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) {
|
||||
match *origin {
|
||||
infer::Subtype(ref trace) => {
|
||||
let desc = match trace.origin {
|
||||
@ -1622,7 +1685,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
|
||||
match self.values_str(&trace.values) {
|
||||
Some(values_str) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
trace.origin.span(),
|
||||
&format!("...so that {} ({})",
|
||||
desc, values_str));
|
||||
@ -1632,130 +1695,130 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
// all, since it is derived, but that would
|
||||
// require more refactoring than I feel like
|
||||
// doing right now. - nmatsakis
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
trace.origin.span(),
|
||||
&format!("...so that {}", desc));
|
||||
}
|
||||
}
|
||||
}
|
||||
infer::Reborrow(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that reference does not outlive \
|
||||
borrowed content");
|
||||
}
|
||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
&format!(
|
||||
"...so that closure can access `{}`",
|
||||
self.tcx.local_var_name_str(upvar_id.var_id)
|
||||
.to_string()))
|
||||
.to_string()));
|
||||
}
|
||||
infer::InfStackClosure(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that closure does not outlive its stack frame");
|
||||
}
|
||||
infer::InvokeClosure(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that closure is not invoked outside its lifetime");
|
||||
}
|
||||
infer::DerefPointer(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that pointer is not dereferenced \
|
||||
outside its lifetime");
|
||||
}
|
||||
infer::FreeVariable(span, id) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
&format!("...so that captured variable `{}` \
|
||||
does not outlive the enclosing closure",
|
||||
self.tcx.local_var_name_str(id)));
|
||||
}
|
||||
infer::IndexSlice(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that slice is not indexed outside the lifetime");
|
||||
}
|
||||
infer::RelateObjectBound(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that it can be closed over into an object");
|
||||
}
|
||||
infer::CallRcvr(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that method receiver is valid for the method call");
|
||||
}
|
||||
infer::CallArg(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that argument is valid for the call");
|
||||
}
|
||||
infer::CallReturn(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that return value is valid for the call");
|
||||
}
|
||||
infer::Operand(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that operand is valid for operation");
|
||||
}
|
||||
infer::AddrOf(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that reference is valid \
|
||||
at the time of borrow");
|
||||
}
|
||||
infer::AutoBorrow(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that auto-reference is valid \
|
||||
at the time of borrow");
|
||||
}
|
||||
infer::ExprTypeIsNotInScope(t, span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
&format!("...so type `{}` of expression is valid during the \
|
||||
expression",
|
||||
self.ty_to_string(t)));
|
||||
}
|
||||
infer::BindingTypeIsNotValidAtDecl(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that variable is valid at time of its declaration");
|
||||
}
|
||||
infer::ParameterInScope(_, span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that a type/lifetime parameter is in scope here");
|
||||
}
|
||||
infer::DataBorrowed(ty, span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
&format!("...so that the type `{}` is not borrowed for too long",
|
||||
self.ty_to_string(ty)));
|
||||
}
|
||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
&format!("...so that the reference type `{}` \
|
||||
does not outlive the data it points at",
|
||||
self.ty_to_string(ty)));
|
||||
}
|
||||
infer::RelateParamBound(span, t) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
&format!("...so that the type `{}` \
|
||||
will meet its required lifetime bounds",
|
||||
self.ty_to_string(t)));
|
||||
}
|
||||
infer::RelateDefaultParamBound(span, t) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
&format!("...so that type parameter \
|
||||
instantiated with `{}`, \
|
||||
@ -1763,16 +1826,16 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
self.ty_to_string(t)));
|
||||
}
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that the declared lifetime parameter bounds \
|
||||
are satisfied");
|
||||
}
|
||||
infer::SafeDestructor(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
"...so that references are valid when the destructor \
|
||||
runs")
|
||||
runs");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ use std::fmt;
|
||||
use syntax::ast;
|
||||
use syntax::codemap;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
|
||||
|
||||
use self::combine::CombineFields;
|
||||
@ -1269,19 +1270,43 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
actual_ty: String,
|
||||
err: Option<&TypeError<'tcx>>) where
|
||||
M: FnOnce(Option<String>, String) -> String,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
where M: FnOnce(Option<String>, String) -> String,
|
||||
{
|
||||
self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err)
|
||||
}
|
||||
|
||||
pub fn type_error_struct_str<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
actual_ty: String,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
where M: FnOnce(Option<String>, String) -> String,
|
||||
{
|
||||
self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err)
|
||||
}
|
||||
|
||||
pub fn type_error_message_str_with_expected<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
expected_ty: Option<Ty<'tcx>>,
|
||||
actual_ty: String,
|
||||
err: Option<&TypeError<'tcx>>) where
|
||||
M: FnOnce(Option<String>, String) -> String,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
where M: FnOnce(Option<String>, String) -> String,
|
||||
{
|
||||
self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err)
|
||||
.emit();
|
||||
}
|
||||
|
||||
pub fn type_error_struct_str_with_expected<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
expected_ty: Option<Ty<'tcx>>,
|
||||
actual_ty: String,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
where M: FnOnce(Option<String>, String) -> String,
|
||||
{
|
||||
debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty);
|
||||
|
||||
@ -1292,13 +1317,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
format!(" ({})", t_err)
|
||||
});
|
||||
|
||||
self.tcx.sess.span_err(sp, &format!("{}{}",
|
||||
let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}",
|
||||
mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty),
|
||||
error_str));
|
||||
|
||||
if let Some(err) = err {
|
||||
self.tcx.note_and_explain_type_err(err, sp)
|
||||
self.tcx.note_and_explain_type_err(&mut db, err, sp);
|
||||
}
|
||||
db
|
||||
} else {
|
||||
self.tcx.sess.diagnostic().struct_dummy()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1306,19 +1334,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
actual_ty: Ty<'tcx>,
|
||||
err: Option<&TypeError<'tcx>>) where
|
||||
M: FnOnce(String) -> String,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
where M: FnOnce(String) -> String,
|
||||
{
|
||||
self.type_error_struct(sp, mk_msg, actual_ty, err).emit();
|
||||
}
|
||||
|
||||
pub fn type_error_struct<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
actual_ty: Ty<'tcx>,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
where M: FnOnce(String) -> String,
|
||||
{
|
||||
let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
|
||||
|
||||
// Don't report an error if actual type is TyError.
|
||||
if actual_ty.references_error() {
|
||||
return;
|
||||
return self.tcx.sess.diagnostic().struct_dummy();
|
||||
}
|
||||
|
||||
self.type_error_message_str(sp,
|
||||
self.type_error_struct_str(sp,
|
||||
move |_e, a| { mk_msg(a) },
|
||||
self.ty_to_string(actual_ty), err);
|
||||
self.ty_to_string(actual_ty), err)
|
||||
}
|
||||
|
||||
pub fn report_mismatched_types(&self,
|
||||
|
@ -1500,7 +1500,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
},
|
||||
_ => false
|
||||
};
|
||||
span_err!(self.ir.tcx.sess, sp, E0269, "not all control paths return a value");
|
||||
let mut err = struct_span_err!(self.ir.tcx.sess,
|
||||
sp,
|
||||
E0269,
|
||||
"not all control paths return a value");
|
||||
if ends_with_stmt {
|
||||
let last_stmt = body.stmts.first().unwrap();
|
||||
let original_span = original_sp(self.ir.tcx.sess.codemap(),
|
||||
@ -1510,9 +1513,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
hi: original_span.hi,
|
||||
expn_id: original_span.expn_id
|
||||
};
|
||||
self.ir.tcx.sess.span_help(
|
||||
span_semicolon, "consider removing this semicolon:");
|
||||
err.span_help(span_semicolon, "consider removing this semicolon:");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
ty::FnDiverging
|
||||
|
@ -345,25 +345,25 @@ impl ShadowKind {
|
||||
}
|
||||
}
|
||||
|
||||
fn signal_shadowing_problem(
|
||||
sess: &Session, name: ast::Name, orig: Original, shadower: Shadower) {
|
||||
if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
|
||||
fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, shadower: Shadower) {
|
||||
let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
|
||||
// lifetime/lifetime shadowing is an error
|
||||
span_err!(sess, shadower.span, E0496,
|
||||
"{} name `{}` shadows a \
|
||||
{} name that is already in scope",
|
||||
shadower.kind.desc(), name, orig.kind.desc());
|
||||
struct_span_err!(sess, shadower.span, E0496,
|
||||
"{} name `{}` shadows a \
|
||||
{} name that is already in scope",
|
||||
shadower.kind.desc(), name, orig.kind.desc())
|
||||
} else {
|
||||
// shadowing involving a label is only a warning, due to issues with
|
||||
// labels and lifetimes not being macro-hygienic.
|
||||
sess.span_warn(shadower.span,
|
||||
&format!("{} name `{}` shadows a \
|
||||
{} name that is already in scope",
|
||||
shadower.kind.desc(), name, orig.kind.desc()));
|
||||
}
|
||||
sess.span_note(orig.span,
|
||||
&format!("shadowed {} `{}` declared here",
|
||||
orig.kind.desc(), name));
|
||||
sess.struct_span_warn(shadower.span,
|
||||
&format!("{} name `{}` shadows a \
|
||||
{} name that is already in scope",
|
||||
shadower.kind.desc(), name, orig.kind.desc()))
|
||||
};
|
||||
err.span_note(orig.span,
|
||||
&format!("shadowed {} `{}` declared here",
|
||||
orig.kind.desc(), name));
|
||||
err.emit();
|
||||
}
|
||||
|
||||
// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
|
||||
|
@ -394,17 +394,19 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
||||
// This is an 'unmarked' API, which should not exist
|
||||
// in the standard library.
|
||||
if self.tcx.sess.features.borrow().unmarked_api {
|
||||
self.tcx.sess.span_warn(span, "use of unmarked library feature");
|
||||
self.tcx.sess.span_note(span, "this is either a bug in the library you are \
|
||||
self.tcx.sess.struct_span_warn(span, "use of unmarked library feature")
|
||||
.span_note(span, "this is either a bug in the library you are \
|
||||
using or a bug in the compiler - please \
|
||||
report it in both places");
|
||||
report it in both places")
|
||||
.emit()
|
||||
} else {
|
||||
self.tcx.sess.span_err(span, "use of unmarked library feature");
|
||||
self.tcx.sess.span_note(span, "this is either a bug in the library you are \
|
||||
self.tcx.sess.struct_span_err(span, "use of unmarked library feature")
|
||||
.span_note(span, "this is either a bug in the library you are \
|
||||
using or a bug in the compiler - please \
|
||||
report it in both places");
|
||||
self.tcx.sess.span_note(span, "use #![feature(unmarked_api)] in the \
|
||||
crate attributes to override this");
|
||||
report it in both places")
|
||||
.span_note(span, "use #![feature(unmarked_api)] in the \
|
||||
crate attributes to override this")
|
||||
.emit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,9 @@ use middle::ty::fold::TypeFoldable;
|
||||
use util::nodemap::{FnvHashMap, FnvHashSet};
|
||||
|
||||
use std::fmt;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::attr::{AttributeMethods, AttrMetaMethods};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct TraitErrorKey<'tcx> {
|
||||
@ -94,12 +95,12 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
// then $X will be unified with TyError, but the error still needs to be
|
||||
// reported.
|
||||
if !infcx.tcx.sess.has_errors() || !predicate.references_error() {
|
||||
span_err!(
|
||||
infcx.tcx.sess, obligation.cause.span, E0271,
|
||||
let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
|
||||
"type mismatch resolving `{}`: {}",
|
||||
predicate,
|
||||
error.err);
|
||||
note_obligation_cause(infcx, obligation);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,14 +187,15 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
{
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
|
||||
"overflow evaluating the requirement `{}`",
|
||||
predicate);
|
||||
let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
|
||||
"overflow evaluating the requirement `{}`",
|
||||
predicate);
|
||||
|
||||
suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
|
||||
suggest_new_overflow_limit(infcx.tcx, &mut err, obligation.cause.span);
|
||||
|
||||
note_obligation_cause(infcx, obligation);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
|
||||
err.emit();
|
||||
infcx.tcx.sess.abort_if_errors();
|
||||
unreachable!();
|
||||
}
|
||||
@ -218,7 +220,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
|
||||
if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() {
|
||||
let trait_ref = trait_predicate.to_poly_trait_ref();
|
||||
span_err!(
|
||||
let mut err = struct_span_err!(
|
||||
infcx.tcx.sess, obligation.cause.span, E0277,
|
||||
"the trait `{}` is not implemented for the type `{}`",
|
||||
trait_ref, trait_ref.self_ty());
|
||||
@ -228,9 +230,10 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
let custom_note = report_on_unimplemented(infcx, &trait_ref.0,
|
||||
obligation.cause.span);
|
||||
if let Some(s) = custom_note {
|
||||
infcx.tcx.sess.fileline_note(obligation.cause.span, &s);
|
||||
err.fileline_note(obligation.cause.span, &s);
|
||||
}
|
||||
note_obligation_cause(infcx, obligation);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,44 +241,48 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
let predicate = infcx.resolve_type_vars_if_possible(predicate);
|
||||
let err = infcx.equality_predicate(obligation.cause.span,
|
||||
&predicate).err().unwrap();
|
||||
span_err!(
|
||||
let mut err = struct_span_err!(
|
||||
infcx.tcx.sess, obligation.cause.span, E0278,
|
||||
"the requirement `{}` is not satisfied (`{}`)",
|
||||
predicate,
|
||||
err);
|
||||
note_obligation_cause(infcx, obligation);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref predicate) => {
|
||||
let predicate = infcx.resolve_type_vars_if_possible(predicate);
|
||||
let err = infcx.region_outlives_predicate(obligation.cause.span,
|
||||
&predicate).err().unwrap();
|
||||
span_err!(
|
||||
let mut err = struct_span_err!(
|
||||
infcx.tcx.sess, obligation.cause.span, E0279,
|
||||
"the requirement `{}` is not satisfied (`{}`)",
|
||||
predicate,
|
||||
err);
|
||||
note_obligation_cause(infcx, obligation);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
span_err!(
|
||||
let mut err = struct_span_err!(
|
||||
infcx.tcx.sess, obligation.cause.span, E0280,
|
||||
"the requirement `{}` is not satisfied",
|
||||
predicate);
|
||||
note_obligation_cause(infcx, obligation);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
ty::Predicate::ObjectSafe(trait_def_id) => {
|
||||
let violations = object_safety_violations(
|
||||
infcx.tcx, trait_def_id);
|
||||
report_object_safety_error(infcx.tcx,
|
||||
obligation.cause.span,
|
||||
trait_def_id,
|
||||
violations);
|
||||
note_obligation_cause(infcx, obligation);
|
||||
let mut err = report_object_safety_error(infcx.tcx,
|
||||
obligation.cause.span,
|
||||
trait_def_id,
|
||||
violations);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
ty::Predicate::WellFormed(ty) => {
|
||||
@ -296,7 +303,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref);
|
||||
let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref);
|
||||
if !actual_trait_ref.self_ty().references_error() {
|
||||
span_err!(
|
||||
let mut err = struct_span_err!(
|
||||
infcx.tcx.sess, obligation.cause.span, E0281,
|
||||
"type mismatch: the type `{}` implements the trait `{}`, \
|
||||
but the trait `{}` is required ({})",
|
||||
@ -304,14 +311,17 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
expected_trait_ref,
|
||||
actual_trait_ref,
|
||||
e);
|
||||
note_obligation_cause(infcx, obligation);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
TraitNotObjectSafe(did) => {
|
||||
let violations = object_safety_violations(infcx.tcx, did);
|
||||
report_object_safety_error(infcx.tcx, obligation.cause.span, did, violations);
|
||||
note_obligation_cause(infcx, obligation);
|
||||
let mut err = report_object_safety_error(infcx.tcx, obligation.cause.span, did,
|
||||
violations);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -320,8 +330,9 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
violations: Vec<ObjectSafetyViolation>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
{
|
||||
span_err!(
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess, span, E0038,
|
||||
"the trait `{}` cannot be made into an object",
|
||||
tcx.item_path_str(trait_def_id));
|
||||
@ -333,13 +344,13 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
}
|
||||
match violation {
|
||||
ObjectSafetyViolation::SizedSelf => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
span,
|
||||
"the trait cannot require that `Self : Sized`");
|
||||
}
|
||||
|
||||
ObjectSafetyViolation::SupertraitSelf => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
span,
|
||||
"the trait cannot use `Self` as a type parameter \
|
||||
in the supertrait listing");
|
||||
@ -347,7 +358,7 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
|
||||
ObjectSafetyViolation::Method(method,
|
||||
MethodViolationCode::StaticMethod) => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
span,
|
||||
&format!("method `{}` has no receiver",
|
||||
method.name));
|
||||
@ -355,7 +366,7 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
|
||||
ObjectSafetyViolation::Method(method,
|
||||
MethodViolationCode::ReferencesSelf) => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
span,
|
||||
&format!("method `{}` references the `Self` type \
|
||||
in its arguments or return type",
|
||||
@ -364,13 +375,14 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
|
||||
ObjectSafetyViolation::Method(method,
|
||||
MethodViolationCode::Generic) => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
span,
|
||||
&format!("method `{}` has generic type parameters",
|
||||
method.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
err
|
||||
}
|
||||
|
||||
pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
@ -424,10 +436,12 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
{
|
||||
need_type_info(infcx, obligation.cause.span, self_ty);
|
||||
} else {
|
||||
span_err!(infcx.tcx.sess, obligation.cause.span, E0283,
|
||||
"type annotations required: cannot resolve `{}`",
|
||||
predicate);
|
||||
note_obligation_cause(infcx, obligation);
|
||||
let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0283,
|
||||
"type annotations required: \
|
||||
cannot resolve `{}`",
|
||||
predicate);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -443,10 +457,11 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
|
||||
_ => {
|
||||
if !infcx.tcx.sess.has_errors() {
|
||||
span_err!(infcx.tcx.sess, obligation.cause.span, E0284,
|
||||
"type annotations required: cannot resolve `{}`",
|
||||
predicate);
|
||||
note_obligation_cause(infcx, obligation);
|
||||
let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0284,
|
||||
"type annotations required: cannot resolve `{}`",
|
||||
predicate);
|
||||
note_obligation_cause(infcx, &mut err, obligation);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -463,16 +478,19 @@ fn need_type_info<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
err: &mut DiagnosticBuilder,
|
||||
obligation: &Obligation<'tcx, T>)
|
||||
where T: fmt::Display
|
||||
{
|
||||
note_obligation_cause_code(infcx,
|
||||
err,
|
||||
&obligation.predicate,
|
||||
obligation.cause.span,
|
||||
&obligation.cause.code);
|
||||
}
|
||||
|
||||
fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
err: &mut DiagnosticBuilder,
|
||||
predicate: &T,
|
||||
cause_span: Span,
|
||||
cause_code: &ObligationCauseCode<'tcx>)
|
||||
@ -482,59 +500,59 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
match *cause_code {
|
||||
ObligationCauseCode::MiscObligation => { }
|
||||
ObligationCauseCode::SliceOrArrayElem => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
"slice and array elements must have `Sized` type");
|
||||
}
|
||||
ObligationCauseCode::ProjectionWf(data) => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
&format!("required so that the projection `{}` is well-formed",
|
||||
data));
|
||||
}
|
||||
ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
&format!("required so that reference `{}` does not outlive its referent",
|
||||
ref_ty));
|
||||
}
|
||||
ObligationCauseCode::ItemObligation(item_def_id) => {
|
||||
let item_name = tcx.item_path_str(item_def_id);
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
&format!("required by `{}`", item_name));
|
||||
}
|
||||
ObligationCauseCode::ObjectCastObligation(object_ty) => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
&format!(
|
||||
"required for the cast to the object type `{}`",
|
||||
infcx.ty_to_string(object_ty)));
|
||||
}
|
||||
ObligationCauseCode::RepeatVec => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
"the `Copy` trait is required because the \
|
||||
repeated element will be copied");
|
||||
}
|
||||
ObligationCauseCode::VariableType(_) => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
"all local variables must have a statically known size");
|
||||
}
|
||||
ObligationCauseCode::ReturnType => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
"the return type of a function must have a \
|
||||
statically known size");
|
||||
}
|
||||
ObligationCauseCode::AssignmentLhsSized => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
"the left-hand-side of an assignment must have a statically known size");
|
||||
}
|
||||
ObligationCauseCode::StructInitializerSized => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
"structs must have a statically known size to be initialized");
|
||||
}
|
||||
@ -542,7 +560,7 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap();
|
||||
let trait_name = tcx.item_path_str(def_id);
|
||||
let name = tcx.local_var_name_str(var_id);
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
&format!("the closure that captures `{}` requires that all captured variables \
|
||||
implement the trait `{}`",
|
||||
@ -550,37 +568,45 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
trait_name));
|
||||
}
|
||||
ObligationCauseCode::FieldSized => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
"only the last field of a struct or enum variant \
|
||||
may have a dynamically sized type");
|
||||
}
|
||||
ObligationCauseCode::SharedStatic => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
"shared static variables must have a type that implements `Sync`");
|
||||
}
|
||||
ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
|
||||
let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
&format!("required because it appears within the type `{}`",
|
||||
parent_trait_ref.0.self_ty()));
|
||||
let parent_predicate = parent_trait_ref.to_predicate();
|
||||
note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
|
||||
note_obligation_cause_code(infcx,
|
||||
err,
|
||||
&parent_predicate,
|
||||
cause_span,
|
||||
&*data.parent_code);
|
||||
}
|
||||
ObligationCauseCode::ImplDerivedObligation(ref data) => {
|
||||
let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
&format!("required because of the requirements on the impl of `{}` for `{}`",
|
||||
parent_trait_ref,
|
||||
parent_trait_ref.0.self_ty()));
|
||||
let parent_predicate = parent_trait_ref.to_predicate();
|
||||
note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
|
||||
note_obligation_cause_code(infcx,
|
||||
err,
|
||||
&parent_predicate,
|
||||
cause_span,
|
||||
&*data.parent_code);
|
||||
}
|
||||
ObligationCauseCode::CompareImplMethodObligation => {
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
cause_span,
|
||||
&format!("the requirement `{}` appears on the impl method \
|
||||
but not on the corresponding trait method",
|
||||
@ -589,10 +615,10 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_new_overflow_limit(tcx: &ty::ctxt, span: Span) {
|
||||
fn suggest_new_overflow_limit(tcx: &ty::ctxt, err:&mut DiagnosticBuilder, span: Span) {
|
||||
let current_limit = tcx.sess.recursion_limit.get();
|
||||
let suggested_limit = current_limit * 2;
|
||||
tcx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
span,
|
||||
&format!(
|
||||
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
|
||||
|
@ -17,6 +17,7 @@ use std::fmt;
|
||||
use syntax::abi;
|
||||
use syntax::ast::{self, Name};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
|
||||
use rustc_front::hir;
|
||||
|
||||
@ -252,27 +253,30 @@ impl<'tcx> ty::TyS<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> ty::ctxt<'tcx> {
|
||||
pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) {
|
||||
pub fn note_and_explain_type_err(&self,
|
||||
db: &mut DiagnosticBuilder,
|
||||
err: &TypeError<'tcx>,
|
||||
sp: Span) {
|
||||
use self::TypeError::*;
|
||||
|
||||
match err.clone() {
|
||||
RegionsDoesNotOutlive(subregion, superregion) => {
|
||||
self.note_and_explain_region("", subregion, "...");
|
||||
self.note_and_explain_region("...does not necessarily outlive ",
|
||||
self.note_and_explain_region(db, "", subregion, "...");
|
||||
self.note_and_explain_region(db, "...does not necessarily outlive ",
|
||||
superregion, "");
|
||||
}
|
||||
RegionsNotSame(region1, region2) => {
|
||||
self.note_and_explain_region("", region1, "...");
|
||||
self.note_and_explain_region("...is not the same lifetime as ",
|
||||
self.note_and_explain_region(db, "", region1, "...");
|
||||
self.note_and_explain_region(db, "...is not the same lifetime as ",
|
||||
region2, "");
|
||||
}
|
||||
RegionsNoOverlap(region1, region2) => {
|
||||
self.note_and_explain_region("", region1, "...");
|
||||
self.note_and_explain_region("...does not overlap ",
|
||||
self.note_and_explain_region(db, "", region1, "...");
|
||||
self.note_and_explain_region(db, "...does not overlap ",
|
||||
region2, "");
|
||||
}
|
||||
RegionsInsufficientlyPolymorphic(_, conc_region) => {
|
||||
self.note_and_explain_region("concrete lifetime that was found is ",
|
||||
self.note_and_explain_region(db, "concrete lifetime that was found is ",
|
||||
conc_region, "");
|
||||
}
|
||||
RegionsOverlyPolymorphic(_, ty::ReVar(_)) => {
|
||||
@ -280,42 +284,40 @@ impl<'tcx> ty::ctxt<'tcx> {
|
||||
// inference variables, it's not very illuminating.
|
||||
}
|
||||
RegionsOverlyPolymorphic(_, conc_region) => {
|
||||
self.note_and_explain_region("expected concrete lifetime is ",
|
||||
self.note_and_explain_region(db, "expected concrete lifetime is ",
|
||||
conc_region, "");
|
||||
}
|
||||
Sorts(values) => {
|
||||
let expected_str = values.expected.sort_string(self);
|
||||
let found_str = values.found.sort_string(self);
|
||||
if expected_str == found_str && expected_str == "closure" {
|
||||
self.sess.span_note(sp,
|
||||
db.span_note(sp,
|
||||
"no two closures, even if identical, have the same type");
|
||||
self.sess.span_help(sp,
|
||||
db.span_help(sp,
|
||||
"consider boxing your closure and/or using it as a trait object");
|
||||
}
|
||||
},
|
||||
TyParamDefaultMismatch(values) => {
|
||||
let expected = values.expected;
|
||||
let found = values.found;
|
||||
self.sess.span_note(sp,
|
||||
&format!("conflicting type parameter defaults `{}` and `{}`",
|
||||
expected.ty,
|
||||
found.ty));
|
||||
db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`",
|
||||
expected.ty,
|
||||
found.ty));
|
||||
|
||||
match
|
||||
self.map.as_local_node_id(expected.def_id)
|
||||
.and_then(|node_id| self.map.opt_span(node_id))
|
||||
{
|
||||
Some(span) => {
|
||||
self.sess.span_note(span, "a default was defined here...");
|
||||
db.span_note(span, "a default was defined here...");
|
||||
}
|
||||
None => {
|
||||
self.sess.note(
|
||||
&format!("a default is defined on `{}`",
|
||||
self.item_path_str(expected.def_id)));
|
||||
db.note(&format!("a default is defined on `{}`",
|
||||
self.item_path_str(expected.def_id)));
|
||||
}
|
||||
}
|
||||
|
||||
self.sess.span_note(
|
||||
db.span_note(
|
||||
expected.origin_span,
|
||||
"...that was applied to an unconstrained type variable here");
|
||||
|
||||
@ -324,18 +326,16 @@ impl<'tcx> ty::ctxt<'tcx> {
|
||||
.and_then(|node_id| self.map.opt_span(node_id))
|
||||
{
|
||||
Some(span) => {
|
||||
self.sess.span_note(span, "a second default was defined here...");
|
||||
db.span_note(span, "a second default was defined here...");
|
||||
}
|
||||
None => {
|
||||
self.sess.note(
|
||||
&format!("a second default is defined on `{}`",
|
||||
self.item_path_str(found.def_id)));
|
||||
db.note(&format!("a second default is defined on `{}`",
|
||||
self.item_path_str(found.def_id)));
|
||||
}
|
||||
}
|
||||
|
||||
self.sess.span_note(
|
||||
found.origin_span,
|
||||
"...that also applies to the same type variable here");
|
||||
db.span_note(found.origin_span,
|
||||
"...that also applies to the same type variable here");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use util::nodemap::{NodeMap, FnvHashMap};
|
||||
|
||||
use syntax::ast::{NodeId, NodeIdAssigner, Name};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::errors;
|
||||
use syntax::errors::{self, DiagnosticBuilder};
|
||||
use syntax::errors::emitter::{Emitter, BasicEmitter};
|
||||
use syntax::diagnostics;
|
||||
use syntax::feature_gate;
|
||||
@ -80,6 +80,61 @@ pub struct Session {
|
||||
}
|
||||
|
||||
impl Session {
|
||||
pub fn struct_span_warn<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.diagnostic().struct_span_warn(sp, msg)
|
||||
}
|
||||
pub fn struct_span_warn_with_code<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.diagnostic().struct_span_warn_with_code(sp, msg, code)
|
||||
}
|
||||
pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.diagnostic().struct_warn(msg)
|
||||
}
|
||||
pub fn struct_span_err<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
match split_msg_into_multilines(msg) {
|
||||
Some(ref msg) => self.diagnostic().struct_span_err(sp, msg),
|
||||
None => self.diagnostic().struct_span_err(sp, msg),
|
||||
}
|
||||
}
|
||||
pub fn struct_span_err_with_code<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
match split_msg_into_multilines(msg) {
|
||||
Some(ref msg) => self.diagnostic().struct_span_err_with_code(sp, msg, code),
|
||||
None => self.diagnostic().struct_span_err_with_code(sp, msg, code),
|
||||
}
|
||||
}
|
||||
pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.diagnostic().struct_err(msg)
|
||||
}
|
||||
pub fn struct_span_fatal<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.diagnostic().struct_span_fatal(sp, msg)
|
||||
}
|
||||
pub fn struct_span_fatal_with_code<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
|
||||
}
|
||||
pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.diagnostic().struct_fatal(msg)
|
||||
}
|
||||
|
||||
pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
|
||||
panic!(self.diagnostic().span_fatal(sp, msg))
|
||||
}
|
||||
@ -98,13 +153,13 @@ impl Session {
|
||||
}
|
||||
pub fn span_err(&self, sp: Span, msg: &str) {
|
||||
match split_msg_into_multilines(msg) {
|
||||
Some(msg) => self.diagnostic().span_err(sp, &msg[..]),
|
||||
Some(msg) => self.diagnostic().span_err(sp, &msg),
|
||||
None => self.diagnostic().span_err(sp, msg)
|
||||
}
|
||||
}
|
||||
pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
|
||||
match split_msg_into_multilines(msg) {
|
||||
Some(msg) => self.diagnostic().span_err_with_code(sp, &msg[..], code),
|
||||
Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code),
|
||||
None => self.diagnostic().span_err_with_code(sp, msg, code)
|
||||
}
|
||||
}
|
||||
@ -144,34 +199,6 @@ impl Session {
|
||||
None => self.warn(msg),
|
||||
}
|
||||
}
|
||||
pub fn span_note(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().span_note(sp, msg)
|
||||
}
|
||||
pub fn span_end_note(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().span_end_note(sp, msg)
|
||||
}
|
||||
|
||||
/// Prints out a message with a suggested edit of the code.
|
||||
///
|
||||
/// See `errors::RenderSpan::Suggestion` for more information.
|
||||
pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) {
|
||||
self.diagnostic().span_suggestion(sp, msg, suggestion)
|
||||
}
|
||||
pub fn span_help(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().span_help(sp, msg)
|
||||
}
|
||||
pub fn fileline_note(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().fileline_note(sp, msg)
|
||||
}
|
||||
pub fn fileline_help(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().fileline_help(sp, msg)
|
||||
}
|
||||
pub fn note(&self, msg: &str) {
|
||||
self.diagnostic().note(msg)
|
||||
}
|
||||
pub fn help(&self, msg: &str) {
|
||||
self.diagnostic().help(msg)
|
||||
}
|
||||
pub fn opt_span_bug(&self, opt_sp: Option<Span>, msg: &str) -> ! {
|
||||
match opt_sp {
|
||||
Some(sp) => self.span_bug(sp, msg),
|
||||
@ -188,6 +215,12 @@ impl Session {
|
||||
pub fn bug(&self, msg: &str) -> ! {
|
||||
self.diagnostic().bug(msg)
|
||||
}
|
||||
pub fn note_without_error(&self, msg: &str) {
|
||||
self.diagnostic().note_without_error(msg)
|
||||
}
|
||||
pub fn span_note_without_error(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().span_note_without_error(sp, msg)
|
||||
}
|
||||
pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
|
||||
self.diagnostic().span_unimpl(sp, msg)
|
||||
}
|
||||
|
@ -465,44 +465,44 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
format!("`{}`", ol)
|
||||
};
|
||||
|
||||
match (new_loan.kind, old_loan.kind) {
|
||||
let mut err = match (new_loan.kind, old_loan.kind) {
|
||||
(ty::MutBorrow, ty::MutBorrow) => {
|
||||
span_err!(self.bccx, new_loan.span, E0499,
|
||||
"cannot borrow `{}`{} as mutable \
|
||||
more than once at a time",
|
||||
nl, new_loan_msg);
|
||||
struct_span_err!(self.bccx, new_loan.span, E0499,
|
||||
"cannot borrow `{}`{} as mutable \
|
||||
more than once at a time",
|
||||
nl, new_loan_msg)
|
||||
}
|
||||
|
||||
(ty::UniqueImmBorrow, _) => {
|
||||
span_err!(self.bccx, new_loan.span, E0500,
|
||||
"closure requires unique access to `{}` \
|
||||
but {} is already borrowed{}",
|
||||
nl, ol_pronoun, old_loan_msg);
|
||||
struct_span_err!(self.bccx, new_loan.span, E0500,
|
||||
"closure requires unique access to `{}` \
|
||||
but {} is already borrowed{}",
|
||||
nl, ol_pronoun, old_loan_msg)
|
||||
}
|
||||
|
||||
(_, ty::UniqueImmBorrow) => {
|
||||
span_err!(self.bccx, new_loan.span, E0501,
|
||||
"cannot borrow `{}`{} as {} because \
|
||||
previous closure requires unique access",
|
||||
nl, new_loan_msg, new_loan.kind.to_user_str());
|
||||
struct_span_err!(self.bccx, new_loan.span, E0501,
|
||||
"cannot borrow `{}`{} as {} because \
|
||||
previous closure requires unique access",
|
||||
nl, new_loan_msg, new_loan.kind.to_user_str())
|
||||
}
|
||||
|
||||
(_, _) => {
|
||||
span_err!(self.bccx, new_loan.span, E0502,
|
||||
"cannot borrow `{}`{} as {} because \
|
||||
{} is also borrowed as {}{}",
|
||||
nl,
|
||||
new_loan_msg,
|
||||
new_loan.kind.to_user_str(),
|
||||
ol_pronoun,
|
||||
old_loan.kind.to_user_str(),
|
||||
old_loan_msg);
|
||||
struct_span_err!(self.bccx, new_loan.span, E0502,
|
||||
"cannot borrow `{}`{} as {} because \
|
||||
{} is also borrowed as {}{}",
|
||||
nl,
|
||||
new_loan_msg,
|
||||
new_loan.kind.to_user_str(),
|
||||
ol_pronoun,
|
||||
old_loan.kind.to_user_str(),
|
||||
old_loan_msg)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match new_loan.cause {
|
||||
euv::ClosureCapture(span) => {
|
||||
self.bccx.span_note(
|
||||
err.span_note(
|
||||
span,
|
||||
&format!("borrow occurs due to use of `{}` in closure",
|
||||
nl));
|
||||
@ -553,15 +553,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
self.bccx.span_note(
|
||||
err.span_note(
|
||||
old_loan.span,
|
||||
&format!("{}; {}", borrow_summary, rule_summary));
|
||||
|
||||
let old_loan_span = self.tcx().map.span(
|
||||
old_loan.kill_scope.node_id(&self.tcx().region_maps));
|
||||
self.bccx.span_end_note(old_loan_span,
|
||||
"previous borrow ends here");
|
||||
|
||||
err.span_end_note(old_loan_span,
|
||||
"previous borrow ends here");
|
||||
err.emit();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -616,14 +616,14 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
|
||||
UseOk => { }
|
||||
UseWhileBorrowed(loan_path, loan_span) => {
|
||||
span_err!(self.bccx, span, E0503,
|
||||
"cannot use `{}` because it was mutably borrowed",
|
||||
&self.bccx.loan_path_to_string(copy_path));
|
||||
self.bccx.span_note(
|
||||
loan_span,
|
||||
&format!("borrow of `{}` occurs here",
|
||||
&self.bccx.loan_path_to_string(&*loan_path))
|
||||
);
|
||||
struct_span_err!(self.bccx, span, E0503,
|
||||
"cannot use `{}` because it was mutably borrowed",
|
||||
&self.bccx.loan_path_to_string(copy_path))
|
||||
.span_note(loan_span,
|
||||
&format!("borrow of `{}` occurs here",
|
||||
&self.bccx.loan_path_to_string(&*loan_path))
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -639,24 +639,25 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
match self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow) {
|
||||
UseOk => { }
|
||||
UseWhileBorrowed(loan_path, loan_span) => {
|
||||
match move_kind {
|
||||
let mut err = match move_kind {
|
||||
move_data::Captured =>
|
||||
span_err!(self.bccx, span, E0504,
|
||||
"cannot move `{}` into closure because it is borrowed",
|
||||
&self.bccx.loan_path_to_string(move_path)),
|
||||
struct_span_err!(self.bccx, span, E0504,
|
||||
"cannot move `{}` into closure because it is borrowed",
|
||||
&self.bccx.loan_path_to_string(move_path)),
|
||||
move_data::Declared |
|
||||
move_data::MoveExpr |
|
||||
move_data::MovePat =>
|
||||
span_err!(self.bccx, span, E0505,
|
||||
"cannot move out of `{}` because it is borrowed",
|
||||
&self.bccx.loan_path_to_string(move_path))
|
||||
struct_span_err!(self.bccx, span, E0505,
|
||||
"cannot move out of `{}` because it is borrowed",
|
||||
&self.bccx.loan_path_to_string(move_path))
|
||||
};
|
||||
|
||||
self.bccx.span_note(
|
||||
err.span_note(
|
||||
loan_span,
|
||||
&format!("borrow of `{}` occurs here",
|
||||
&self.bccx.loan_path_to_string(&*loan_path))
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -818,12 +819,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
span: Span,
|
||||
loan_path: &LoanPath<'tcx>,
|
||||
loan: &Loan) {
|
||||
span_err!(self.bccx, span, E0506,
|
||||
"cannot assign to `{}` because it is borrowed",
|
||||
self.bccx.loan_path_to_string(loan_path));
|
||||
self.bccx.span_note(
|
||||
loan.span,
|
||||
&format!("borrow of `{}` occurs here",
|
||||
self.bccx.loan_path_to_string(loan_path)));
|
||||
struct_span_err!(self.bccx, span, E0506,
|
||||
"cannot assign to `{}` because it is borrowed",
|
||||
self.bccx.loan_path_to_string(loan_path))
|
||||
.span_note(loan.span,
|
||||
&format!("borrow of `{}` occurs here",
|
||||
self.bccx.loan_path_to_string(loan_path)))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
|
||||
use rustc::middle::ty;
|
||||
use syntax::ast;
|
||||
use syntax::codemap;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use rustc_front::hir;
|
||||
|
||||
pub struct MoveErrorCollector<'tcx> {
|
||||
@ -68,13 +69,14 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
errors: &Vec<MoveError<'tcx>>) {
|
||||
let grouped_errors = group_errors_with_same_origin(errors);
|
||||
for error in &grouped_errors {
|
||||
report_cannot_move_out_of(bccx, error.move_from.clone());
|
||||
let mut err = report_cannot_move_out_of(bccx, error.move_from.clone());
|
||||
let mut is_first_note = true;
|
||||
for move_to in &error.move_to_places {
|
||||
note_move_destination(bccx, move_to.span,
|
||||
note_move_destination(&mut err, move_to.span,
|
||||
move_to.name, is_first_note);
|
||||
is_first_note = false;
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,24 +114,28 @@ fn group_errors_with_same_origin<'tcx>(errors: &Vec<MoveError<'tcx>>)
|
||||
|
||||
// (keep in sync with gather_moves::check_and_get_illegal_move_origin )
|
||||
fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
move_from: mc::cmt<'tcx>) {
|
||||
move_from: mc::cmt<'tcx>)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
match move_from.cat {
|
||||
Categorization::Deref(_, _, mc::BorrowedPtr(..)) |
|
||||
Categorization::Deref(_, _, mc::Implicit(..)) |
|
||||
Categorization::Deref(_, _, mc::UnsafePtr(..)) |
|
||||
Categorization::StaticItem => {
|
||||
span_err!(bccx, move_from.span, E0507,
|
||||
"cannot move out of {}",
|
||||
move_from.descriptive_string(bccx.tcx));
|
||||
struct_span_err!(bccx, move_from.span, E0507,
|
||||
"cannot move out of {}",
|
||||
move_from.descriptive_string(bccx.tcx))
|
||||
}
|
||||
|
||||
Categorization::Interior(ref b, mc::InteriorElement(Kind::Index, _)) => {
|
||||
let expr = bccx.tcx.map.expect_expr(move_from.id);
|
||||
if let hir::ExprIndex(..) = expr.node {
|
||||
span_err!(bccx, move_from.span, E0508,
|
||||
"cannot move out of type `{}`, \
|
||||
a non-copy fixed-size array",
|
||||
b.ty);
|
||||
struct_span_err!(bccx, move_from.span, E0508,
|
||||
"cannot move out of type `{}`, \
|
||||
a non-copy fixed-size array",
|
||||
b.ty)
|
||||
} else {
|
||||
bccx.span_bug(move_from.span, "this path should not cause illegal move");
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,39 +144,41 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
match b.ty.sty {
|
||||
ty::TyStruct(def, _) |
|
||||
ty::TyEnum(def, _) if def.has_dtor() => {
|
||||
span_err!(bccx, move_from.span, E0509,
|
||||
"cannot move out of type `{}`, \
|
||||
which defines the `Drop` trait",
|
||||
b.ty);
|
||||
struct_span_err!(bccx, move_from.span, E0509,
|
||||
"cannot move out of type `{}`, \
|
||||
which defines the `Drop` trait",
|
||||
b.ty)
|
||||
},
|
||||
_ => {
|
||||
bccx.span_bug(move_from.span, "this path should not cause illegal move")
|
||||
bccx.span_bug(move_from.span, "this path should not cause illegal move");
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
bccx.span_bug(move_from.span, "this path should not cause illegal move")
|
||||
bccx.span_bug(move_from.span, "this path should not cause illegal move");
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn note_move_destination(bccx: &BorrowckCtxt,
|
||||
fn note_move_destination(err: &mut DiagnosticBuilder,
|
||||
move_to_span: codemap::Span,
|
||||
pat_name: ast::Name,
|
||||
is_first_note: bool) {
|
||||
if is_first_note {
|
||||
bccx.span_note(
|
||||
err.span_note(
|
||||
move_to_span,
|
||||
"attempting to move value to here");
|
||||
bccx.fileline_help(
|
||||
err.fileline_help(
|
||||
move_to_span,
|
||||
&format!("to prevent the move, \
|
||||
use `ref {0}` or `ref mut {0}` to capture value by \
|
||||
reference",
|
||||
pat_name));
|
||||
use `ref {0}` or `ref mut {0}` to capture value by \
|
||||
reference",
|
||||
pat_name));
|
||||
} else {
|
||||
bccx.span_note(move_to_span,
|
||||
&format!("and here (use `ref {0}` or `ref mut {0}`)",
|
||||
err.span_note(move_to_span,
|
||||
&format!("and here (use `ref {0}` or `ref mut {0}`)",
|
||||
pat_name));
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ use std::mem;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
|
||||
use rustc_front::hir;
|
||||
use rustc_front::hir::{FnDecl, Block};
|
||||
@ -591,10 +592,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
// General fallback.
|
||||
self.span_err(
|
||||
let mut db = self.struct_span_err(
|
||||
err.span,
|
||||
&self.bckerr_to_string(&err));
|
||||
self.note_and_explain_bckerr(err);
|
||||
self.note_and_explain_bckerr(&mut db, err);
|
||||
db.emit();
|
||||
}
|
||||
|
||||
pub fn report_use_of_moved_value<'b>(&self,
|
||||
@ -609,16 +611,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
MovedInCapture => "capture",
|
||||
};
|
||||
|
||||
let (ol, moved_lp_msg) = match the_move.kind {
|
||||
let (ol, moved_lp_msg, mut err) = match the_move.kind {
|
||||
move_data::Declared => {
|
||||
span_err!(
|
||||
let err = struct_span_err!(
|
||||
self.tcx.sess, use_span, E0381,
|
||||
"{} of possibly uninitialized variable: `{}`",
|
||||
verb,
|
||||
self.loan_path_to_string(lp));
|
||||
|
||||
(self.loan_path_to_string(moved_lp),
|
||||
String::new())
|
||||
String::new(),
|
||||
err)
|
||||
}
|
||||
_ => {
|
||||
// If moved_lp is something like `x.a`, and lp is something like `x.b`, we would
|
||||
@ -653,11 +656,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
let msg = if !has_fork && partial { "partially " }
|
||||
else if has_fork && !has_common { "collaterally "}
|
||||
else { "" };
|
||||
span_err!(
|
||||
let err = struct_span_err!(
|
||||
self.tcx.sess, use_span, E0382,
|
||||
"{} of {}moved value: `{}`",
|
||||
verb, msg, nl);
|
||||
(ol, moved_lp_msg)
|
||||
(ol, moved_lp_msg, err)
|
||||
}
|
||||
};
|
||||
|
||||
@ -684,7 +687,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
// multiple times. Avoid printing the same span and adjust the wording so it makes
|
||||
// more sense that it's from multiple evalutations.
|
||||
if expr_span == use_span {
|
||||
self.tcx.sess.note(
|
||||
err.note(
|
||||
&format!("`{}` was previously moved here{} because it has type `{}`, \
|
||||
which is {}",
|
||||
ol,
|
||||
@ -692,7 +695,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
expr_ty,
|
||||
suggestion));
|
||||
} else {
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
expr_span,
|
||||
&format!("`{}` moved here{} because it has type `{}`, which is {}",
|
||||
ol,
|
||||
@ -705,7 +708,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
move_data::MovePat => {
|
||||
let pat_ty = self.tcx.node_id_to_type(the_move.id);
|
||||
let span = self.tcx.map.span(the_move.id);
|
||||
self.tcx.sess.span_note(span,
|
||||
err.span_note(span,
|
||||
&format!("`{}` moved here{} because it has type `{}`, \
|
||||
which is moved by default",
|
||||
ol,
|
||||
@ -713,14 +716,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
pat_ty));
|
||||
match self.tcx.sess.codemap().span_to_snippet(span) {
|
||||
Ok(string) => {
|
||||
self.tcx.sess.span_suggestion(
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&format!("if you would like to borrow the value instead, \
|
||||
use a `ref` binding as shown:"),
|
||||
format!("ref {}", string));
|
||||
},
|
||||
Err(_) => {
|
||||
self.tcx.sess.fileline_help(span,
|
||||
err.fileline_help(span,
|
||||
"use `ref` to override");
|
||||
},
|
||||
}
|
||||
@ -746,7 +749,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
expr_ty,
|
||||
("moved by default",
|
||||
"make a copy and capture that instead to override"));
|
||||
self.tcx.sess.span_note(
|
||||
err.span_note(
|
||||
expr_span,
|
||||
&format!("`{}` moved into closure environment here{} because it \
|
||||
has type `{}`, which is {}",
|
||||
@ -754,9 +757,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
moved_lp_msg,
|
||||
moved_lp.ty,
|
||||
suggestion));
|
||||
self.tcx.sess.fileline_help(expr_span, help);
|
||||
err.fileline_help(expr_span, help);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
|
||||
fn move_suggestion<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
|
||||
span: Span,
|
||||
@ -791,17 +795,30 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
lp: &LoanPath<'tcx>,
|
||||
assign:
|
||||
&move_data::Assignment) {
|
||||
span_err!(
|
||||
struct_span_err!(
|
||||
self.tcx.sess, span, E0384,
|
||||
"re-assignment of immutable variable `{}`",
|
||||
self.loan_path_to_string(lp));
|
||||
self.tcx.sess.span_note(assign.span, "prior assignment occurs here");
|
||||
self.loan_path_to_string(lp))
|
||||
.span_note(assign.span, "prior assignment occurs here")
|
||||
.emit();
|
||||
}
|
||||
|
||||
pub fn span_err(&self, s: Span, m: &str) {
|
||||
self.tcx.sess.span_err(s, m);
|
||||
}
|
||||
|
||||
pub fn struct_span_err(&self, s: Span, m: &str) -> DiagnosticBuilder<'a> {
|
||||
self.tcx.sess.struct_span_err(s, m)
|
||||
}
|
||||
|
||||
pub fn struct_span_err_with_code(&self,
|
||||
s: Span,
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.tcx.sess.struct_span_err_with_code(s, msg, code)
|
||||
}
|
||||
|
||||
pub fn span_err_with_code(&self, s: Span, msg: &str, code: &str) {
|
||||
self.tcx.sess.span_err_with_code(s, msg, code);
|
||||
}
|
||||
@ -810,18 +827,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
self.tcx.sess.span_bug(s, m);
|
||||
}
|
||||
|
||||
pub fn span_note(&self, s: Span, m: &str) {
|
||||
self.tcx.sess.span_note(s, m);
|
||||
}
|
||||
|
||||
pub fn span_end_note(&self, s: Span, m: &str) {
|
||||
self.tcx.sess.span_end_note(s, m);
|
||||
}
|
||||
|
||||
pub fn fileline_help(&self, s: Span, m: &str) {
|
||||
self.tcx.sess.fileline_help(s, m);
|
||||
}
|
||||
|
||||
pub fn bckerr_to_string(&self, err: &BckError<'tcx>) -> String {
|
||||
match err.code {
|
||||
err_mutbl => {
|
||||
@ -913,19 +918,19 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
match cause {
|
||||
let mut err = match cause {
|
||||
mc::AliasableOther => {
|
||||
span_err!(
|
||||
struct_span_err!(
|
||||
self.tcx.sess, span, E0385,
|
||||
"{} in an aliasable location", prefix);
|
||||
"{} in an aliasable location", prefix)
|
||||
}
|
||||
mc::AliasableReason::UnaliasableImmutable => {
|
||||
span_err!(
|
||||
struct_span_err!(
|
||||
self.tcx.sess, span, E0386,
|
||||
"{} in an immutable container", prefix);
|
||||
"{} in an immutable container", prefix)
|
||||
}
|
||||
mc::AliasableClosure(id) => {
|
||||
span_err!(
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess, span, E0387,
|
||||
"{} in a captured outer variable in an `Fn` closure", prefix);
|
||||
if let BorrowViolation(euv::ClosureCapture(_)) = kind {
|
||||
@ -933,31 +938,32 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
// happen for nested closures, so we know the enclosing
|
||||
// closure incorrectly accepts an `Fn` while it needs to
|
||||
// be `FnMut`.
|
||||
span_help!(self.tcx.sess, self.tcx.map.span(id),
|
||||
span_help!(&mut err, self.tcx.map.span(id),
|
||||
"consider changing this to accept closures that implement `FnMut`");
|
||||
} else {
|
||||
span_help!(self.tcx.sess, self.tcx.map.span(id),
|
||||
span_help!(&mut err, self.tcx.map.span(id),
|
||||
"consider changing this closure to take self by mutable reference");
|
||||
}
|
||||
err
|
||||
}
|
||||
mc::AliasableStatic |
|
||||
mc::AliasableStaticMut => {
|
||||
span_err!(
|
||||
struct_span_err!(
|
||||
self.tcx.sess, span, E0388,
|
||||
"{} in a static location", prefix);
|
||||
"{} in a static location", prefix)
|
||||
}
|
||||
mc::AliasableBorrowed => {
|
||||
span_err!(
|
||||
struct_span_err!(
|
||||
self.tcx.sess, span, E0389,
|
||||
"{} in a `&` reference", prefix);
|
||||
"{} in a `&` reference", prefix)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if is_closure {
|
||||
self.tcx.sess.fileline_help(
|
||||
span,
|
||||
"closures behind references must be called via `&mut`");
|
||||
err.fileline_help(span,
|
||||
"closures behind references must be called via `&mut`");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn report_out_of_scope_escaping_closure_capture(&self,
|
||||
@ -966,34 +972,30 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
{
|
||||
let cmt_path_or_string = self.cmt_to_path_or_string(&err.cmt);
|
||||
|
||||
span_err!(
|
||||
self.tcx.sess, err.span, E0373,
|
||||
"closure may outlive the current function, \
|
||||
but it borrows {}, \
|
||||
which is owned by the current function",
|
||||
cmt_path_or_string);
|
||||
|
||||
self.tcx.sess.span_note(
|
||||
capture_span,
|
||||
&format!("{} is borrowed here",
|
||||
cmt_path_or_string));
|
||||
|
||||
let suggestion =
|
||||
match self.tcx.sess.codemap().span_to_snippet(err.span) {
|
||||
Ok(string) => format!("move {}", string),
|
||||
Err(_) => format!("move |<args>| <body>")
|
||||
};
|
||||
|
||||
self.tcx.sess.span_suggestion(
|
||||
err.span,
|
||||
&format!("to force the closure to take ownership of {} \
|
||||
(and any other referenced variables), \
|
||||
use the `move` keyword, as shown:",
|
||||
cmt_path_or_string),
|
||||
suggestion);
|
||||
struct_span_err!(self.tcx.sess, err.span, E0373,
|
||||
"closure may outlive the current function, \
|
||||
but it borrows {}, \
|
||||
which is owned by the current function",
|
||||
cmt_path_or_string)
|
||||
.span_note(capture_span,
|
||||
&format!("{} is borrowed here",
|
||||
cmt_path_or_string))
|
||||
.span_suggestion(err.span,
|
||||
&format!("to force the closure to take ownership of {} \
|
||||
(and any other referenced variables), \
|
||||
use the `move` keyword, as shown:",
|
||||
cmt_path_or_string),
|
||||
suggestion)
|
||||
.emit();
|
||||
}
|
||||
|
||||
pub fn note_and_explain_bckerr(&self, err: BckError<'tcx>) {
|
||||
pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
|
||||
let code = err.code;
|
||||
match code {
|
||||
err_mutbl => {
|
||||
@ -1007,7 +1009,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
_ => unreachable!()
|
||||
};
|
||||
if kind == ty::FnClosureKind {
|
||||
self.tcx.sess.span_help(
|
||||
db.span_help(
|
||||
self.tcx.map.span(upvar_id.closure_expr_id),
|
||||
"consider changing this closure to take \
|
||||
self by mutable reference");
|
||||
@ -1017,7 +1019,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
if let Categorization::Local(local_id) = err.cmt.cat {
|
||||
let span = self.tcx.map.span(local_id);
|
||||
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
|
||||
self.tcx.sess.span_suggestion(
|
||||
db.span_suggestion(
|
||||
span,
|
||||
&format!("to make the {} mutable, use `mut` as shown:",
|
||||
self.cmt_to_string(&err.cmt)),
|
||||
@ -1030,16 +1032,18 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
err_out_of_scope(super_scope, sub_scope) => {
|
||||
self.tcx.note_and_explain_region(
|
||||
db,
|
||||
"reference must be valid for ",
|
||||
sub_scope,
|
||||
"...");
|
||||
self.tcx.note_and_explain_region(
|
||||
db,
|
||||
"...but borrowed value is only valid for ",
|
||||
super_scope,
|
||||
"");
|
||||
if let Some(span) = statement_scope_span(self.tcx, super_scope) {
|
||||
self.tcx.sess.span_help(span,
|
||||
"consider using a `let` binding to increase its lifetime");
|
||||
db.span_help(span,
|
||||
"consider using a `let` binding to increase its lifetime");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1051,11 +1055,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
None => self.cmt_to_string(&*err.cmt),
|
||||
};
|
||||
self.tcx.note_and_explain_region(
|
||||
db,
|
||||
&format!("{} would have to be valid for ",
|
||||
descr),
|
||||
loan_scope,
|
||||
"...");
|
||||
self.tcx.note_and_explain_region(
|
||||
db,
|
||||
&format!("...but {} is only valid for ", descr),
|
||||
ptr_scope,
|
||||
"");
|
||||
|
@ -1001,8 +1001,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
session.span_err(a.span, "`crate_type` requires a value");
|
||||
session.note("for example: `#![crate_type=\"lib\"]`");
|
||||
session.struct_span_err(a.span, "`crate_type` requires a value")
|
||||
.note("for example: `#![crate_type=\"lib\"]`")
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ struct ExpectErrorEmitter {
|
||||
fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
|
||||
match lvl {
|
||||
Level::Bug | Level::Fatal | Level::Error => {}
|
||||
Level::Warning | Level::Note | Level::Help => {
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -752,19 +752,19 @@ impl LateLintPass for UnconditionalRecursion {
|
||||
// no break */ }`) shouldn't be linted unless it actually
|
||||
// recurs.
|
||||
if !reached_exit_without_self_call && !self_call_spans.is_empty() {
|
||||
cx.span_lint(UNCONDITIONAL_RECURSION, sp,
|
||||
"function cannot return without recurring");
|
||||
let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp,
|
||||
"function cannot return without recurring");
|
||||
|
||||
// FIXME #19668: these could be span_lint_note's instead of this manual guard.
|
||||
if cx.current_level(UNCONDITIONAL_RECURSION) != Level::Allow {
|
||||
let sess = cx.sess();
|
||||
// offer some help to the programmer.
|
||||
for call in &self_call_spans {
|
||||
sess.span_note(*call, "recursive call site")
|
||||
db.span_note(*call, "recursive call site");
|
||||
}
|
||||
sess.fileline_help(sp, "a `loop` may express intention \
|
||||
better if this is on purpose")
|
||||
db.fileline_help(sp, "a `loop` may express intention \
|
||||
better if this is on purpose");
|
||||
}
|
||||
db.emit();
|
||||
}
|
||||
|
||||
// all done
|
||||
|
@ -35,6 +35,7 @@ use syntax::codemap::{self, Span, mk_sp, Pos};
|
||||
use syntax::parse;
|
||||
use syntax::attr;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::errors::FatalError;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::util::small_vector::SmallVector;
|
||||
use rustc_front::intravisit::Visitor;
|
||||
@ -504,7 +505,10 @@ impl<'a> CrateReader<'a> {
|
||||
let lo = p.span.lo;
|
||||
let body = match p.parse_all_token_trees() {
|
||||
Ok(body) => body,
|
||||
Err(err) => panic!(err),
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
panic!(FatalError);
|
||||
}
|
||||
};
|
||||
let span = mk_sp(lo, p.last_span.hi);
|
||||
p.abort_if_errors();
|
||||
|
@ -226,7 +226,7 @@ use rustc_llvm as llvm;
|
||||
use rustc_llvm::{False, ObjectFile, mk_section_iter};
|
||||
use rustc_llvm::archive_ro::ArchiveRO;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::errors::Handler;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use rustc_back::target::Target;
|
||||
|
||||
use std::cmp;
|
||||
@ -315,38 +315,38 @@ impl<'a> Context<'a> {
|
||||
&Some(ref r) => format!(" which `{}` depends on",
|
||||
r.ident)
|
||||
};
|
||||
if !self.rejected_via_hash.is_empty() {
|
||||
span_err!(self.sess, self.span, E0460,
|
||||
"found possibly newer version of crate `{}`{}",
|
||||
self.ident, add);
|
||||
let mut err = if !self.rejected_via_hash.is_empty() {
|
||||
struct_span_err!(self.sess, self.span, E0460,
|
||||
"found possibly newer version of crate `{}`{}",
|
||||
self.ident, add)
|
||||
} else if !self.rejected_via_triple.is_empty() {
|
||||
span_err!(self.sess, self.span, E0461,
|
||||
"couldn't find crate `{}` with expected target triple {}{}",
|
||||
self.ident, self.triple, add);
|
||||
struct_span_err!(self.sess, self.span, E0461,
|
||||
"couldn't find crate `{}` with expected target triple {}{}",
|
||||
self.ident, self.triple, add)
|
||||
} else if !self.rejected_via_kind.is_empty() {
|
||||
span_err!(self.sess, self.span, E0462,
|
||||
"found staticlib `{}` instead of rlib or dylib{}",
|
||||
self.ident, add);
|
||||
struct_span_err!(self.sess, self.span, E0462,
|
||||
"found staticlib `{}` instead of rlib or dylib{}",
|
||||
self.ident, add)
|
||||
} else {
|
||||
span_err!(self.sess, self.span, E0463,
|
||||
"can't find crate for `{}`{}",
|
||||
self.ident, add);
|
||||
}
|
||||
struct_span_err!(self.sess, self.span, E0463,
|
||||
"can't find crate for `{}`{}",
|
||||
self.ident, add)
|
||||
};
|
||||
|
||||
if !self.rejected_via_triple.is_empty() {
|
||||
let mismatches = self.rejected_via_triple.iter();
|
||||
for (i, &CrateMismatch{ ref path, ref got }) in mismatches.enumerate() {
|
||||
self.sess.fileline_note(self.span,
|
||||
err.fileline_note(self.span,
|
||||
&format!("crate `{}`, path #{}, triple {}: {}",
|
||||
self.ident, i+1, got, path.display()));
|
||||
}
|
||||
}
|
||||
if !self.rejected_via_hash.is_empty() {
|
||||
self.sess.span_note(self.span, "perhaps this crate needs \
|
||||
err.span_note(self.span, "perhaps this crate needs \
|
||||
to be recompiled?");
|
||||
let mismatches = self.rejected_via_hash.iter();
|
||||
for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() {
|
||||
self.sess.fileline_note(self.span,
|
||||
err.fileline_note(self.span,
|
||||
&format!("crate `{}` path #{}: {}",
|
||||
self.ident, i+1, path.display()));
|
||||
}
|
||||
@ -354,7 +354,7 @@ impl<'a> Context<'a> {
|
||||
&None => {}
|
||||
&Some(ref r) => {
|
||||
for (i, path) in r.paths().iter().enumerate() {
|
||||
self.sess.fileline_note(self.span,
|
||||
err.fileline_note(self.span,
|
||||
&format!("crate `{}` path #{}: {}",
|
||||
r.ident, i+1, path.display()));
|
||||
}
|
||||
@ -362,15 +362,17 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
}
|
||||
if !self.rejected_via_kind.is_empty() {
|
||||
self.sess.fileline_help(self.span, "please recompile this crate using \
|
||||
--crate-type lib");
|
||||
err.fileline_help(self.span, "please recompile this crate using \
|
||||
--crate-type lib");
|
||||
let mismatches = self.rejected_via_kind.iter();
|
||||
for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() {
|
||||
self.sess.fileline_note(self.span,
|
||||
&format!("crate `{}` path #{}: {}",
|
||||
self.ident, i+1, path.display()));
|
||||
err.fileline_note(self.span,
|
||||
&format!("crate `{}` path #{}: {}",
|
||||
self.ident, i+1, path.display()));
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
self.sess.abort_if_errors();
|
||||
}
|
||||
|
||||
@ -480,29 +482,30 @@ impl<'a> Context<'a> {
|
||||
0 => None,
|
||||
1 => Some(libraries.into_iter().next().unwrap()),
|
||||
_ => {
|
||||
span_err!(self.sess, self.span, E0464,
|
||||
"multiple matching crates for `{}`",
|
||||
self.crate_name);
|
||||
self.sess.note("candidates:");
|
||||
let mut err = struct_span_err!(self.sess, self.span, E0464,
|
||||
"multiple matching crates for `{}`",
|
||||
self.crate_name);
|
||||
err.note("candidates:");
|
||||
for lib in &libraries {
|
||||
match lib.dylib {
|
||||
Some((ref p, _)) => {
|
||||
self.sess.note(&format!("path: {}",
|
||||
p.display()));
|
||||
err.note(&format!("path: {}",
|
||||
p.display()));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
match lib.rlib {
|
||||
Some((ref p, _)) => {
|
||||
self.sess.note(&format!("path: {}",
|
||||
p.display()));
|
||||
err.note(&format!("path: {}",
|
||||
p.display()));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
let data = lib.metadata.as_slice();
|
||||
let name = decoder::get_crate_name(data);
|
||||
note_crate_name(self.sess.diagnostic(), &name);
|
||||
note_crate_name(&mut err, &name);
|
||||
}
|
||||
err.emit();
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -533,6 +536,7 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let mut err: Option<DiagnosticBuilder> = None;
|
||||
for (lib, kind) in m {
|
||||
info!("{} reading metadata from: {}", flavor, lib.display());
|
||||
let metadata = match get_metadata_section(self.target, &lib) {
|
||||
@ -555,27 +559,37 @@ impl<'a> Context<'a> {
|
||||
// candidates have the same hash, so they're not actually
|
||||
// duplicates that we should warn about.
|
||||
if ret.is_some() && self.hash.is_none() {
|
||||
span_err!(self.sess, self.span, E0465,
|
||||
"multiple {} candidates for `{}` found",
|
||||
flavor, self.crate_name);
|
||||
self.sess.span_note(self.span,
|
||||
&format!(r"candidate #1: {}",
|
||||
ret.as_ref().unwrap().0
|
||||
.display()));
|
||||
let mut e = struct_span_err!(self.sess, self.span, E0465,
|
||||
"multiple {} candidates for `{}` found",
|
||||
flavor, self.crate_name);
|
||||
e.span_note(self.span,
|
||||
&format!(r"candidate #1: {}",
|
||||
ret.as_ref().unwrap().0
|
||||
.display()));
|
||||
if let Some(ref mut e) = err {
|
||||
e.emit();
|
||||
}
|
||||
err = Some(e);
|
||||
error = 1;
|
||||
ret = None;
|
||||
}
|
||||
if error > 0 {
|
||||
error += 1;
|
||||
self.sess.span_note(self.span,
|
||||
&format!(r"candidate #{}: {}", error,
|
||||
lib.display()));
|
||||
err.as_mut().unwrap().span_note(self.span,
|
||||
&format!(r"candidate #{}: {}", error,
|
||||
lib.display()));
|
||||
continue
|
||||
}
|
||||
*slot = Some(metadata);
|
||||
ret = Some((lib, kind));
|
||||
}
|
||||
return if error > 0 {None} else {ret}
|
||||
|
||||
if error > 0 {
|
||||
err.unwrap().emit();
|
||||
None
|
||||
} else {
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> bool {
|
||||
@ -662,10 +676,11 @@ impl<'a> Context<'a> {
|
||||
return true
|
||||
}
|
||||
}
|
||||
sess.err(&format!("extern location for {} is of an unknown type: {}",
|
||||
self.crate_name, loc.display()));
|
||||
sess.help(&format!("file name should be lib*.rlib or {}*.{}",
|
||||
dylibname.0, dylibname.1));
|
||||
sess.struct_err(&format!("extern location for {} is of an unknown type: {}",
|
||||
self.crate_name, loc.display()))
|
||||
.help(&format!("file name should be lib*.rlib or {}*.{}",
|
||||
dylibname.0, dylibname.1))
|
||||
.emit();
|
||||
false
|
||||
});
|
||||
|
||||
@ -699,8 +714,8 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn note_crate_name(diag: &Handler, name: &str) {
|
||||
diag.note(&format!("crate name: {}", name));
|
||||
pub fn note_crate_name(err: &mut DiagnosticBuilder, name: &str) {
|
||||
err.note(&format!("crate name: {}", name));
|
||||
}
|
||||
|
||||
impl ArchiveMetadata {
|
||||
|
@ -46,10 +46,11 @@ pub fn find_plugin_registrar(diagnostic: &errors::Handler,
|
||||
Some(node_id)
|
||||
},
|
||||
_ => {
|
||||
diagnostic.err("multiple plugin registration functions found");
|
||||
let mut e = diagnostic.struct_err("multiple plugin registration functions found");
|
||||
for &(_, span) in &finder.registrars {
|
||||
diagnostic.span_note(span, "one is here");
|
||||
e.span_note(span, "one is here");
|
||||
}
|
||||
e.emit();
|
||||
diagnostic.abort_if_errors();
|
||||
unreachable!();
|
||||
}
|
||||
|
@ -597,13 +597,11 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
|
||||
match result {
|
||||
None => true,
|
||||
Some((span, msg, note)) => {
|
||||
self.tcx.sess.span_err(span, &msg[..]);
|
||||
match note {
|
||||
Some((span, msg)) => {
|
||||
self.tcx.sess.span_note(span, &msg[..])
|
||||
}
|
||||
None => {},
|
||||
let mut err = self.tcx.sess.struct_span_err(span, &msg[..]);
|
||||
if let Some((span, msg)) = note {
|
||||
err.span_note(span, &msg[..]);
|
||||
}
|
||||
err.emit();
|
||||
false
|
||||
},
|
||||
}
|
||||
@ -1028,10 +1026,12 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
|
||||
fn check_sane_privacy(&self, item: &hir::Item) {
|
||||
let check_inherited = |sp, vis, note: &str| {
|
||||
if vis != hir::Inherited {
|
||||
span_err!(self.tcx.sess, sp, E0449, "unnecessary visibility qualifier");
|
||||
let mut err = struct_span_err!(self.tcx.sess, sp, E0449,
|
||||
"unnecessary visibility qualifier");
|
||||
if !note.is_empty() {
|
||||
self.tcx.sess.span_note(sp, note);
|
||||
err.span_note(sp, note);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -24,7 +24,7 @@ use {names_to_string, module_to_string};
|
||||
use ParentLink::{self, ModuleParentLink, BlockParentLink};
|
||||
use Resolver;
|
||||
use resolve_imports::Shadowable;
|
||||
use {resolve_error, ResolutionError};
|
||||
use {resolve_error, resolve_struct_error, ResolutionError};
|
||||
|
||||
use self::DuplicateCheckingMode::*;
|
||||
|
||||
@ -137,12 +137,16 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||
|
||||
// Record an error here by looking up the namespace that had the duplicate
|
||||
let ns_str = match ns { TypeNS => "type or module", ValueNS => "value" };
|
||||
resolve_error(self, sp, ResolutionError::DuplicateDefinition(ns_str, name));
|
||||
let mut err = resolve_struct_error(self,
|
||||
sp,
|
||||
ResolutionError::DuplicateDefinition(ns_str,
|
||||
name));
|
||||
|
||||
if let Some(sp) = child[ns].span() {
|
||||
let note = format!("first definition of {} `{}` here", ns_str, name);
|
||||
self.session.span_note(sp, ¬e);
|
||||
err.span_note(sp, ¬e);
|
||||
}
|
||||
err.emit();
|
||||
child
|
||||
}
|
||||
}
|
||||
@ -253,13 +257,13 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||
})
|
||||
.collect::<Vec<Span>>();
|
||||
if mod_spans.len() > 1 {
|
||||
resolve_error(self,
|
||||
let mut e = resolve_struct_error(self,
|
||||
mod_spans[0],
|
||||
ResolutionError::SelfImportCanOnlyAppearOnceInTheList);
|
||||
for other_span in mod_spans.iter().skip(1) {
|
||||
self.session
|
||||
.span_note(*other_span, "another `self` import appears here");
|
||||
e.span_note(*other_span, "another `self` import appears here");
|
||||
}
|
||||
e.emit();
|
||||
}
|
||||
|
||||
for source_item in source_items {
|
||||
|
@ -63,8 +63,9 @@ use syntax::ast;
|
||||
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64};
|
||||
use syntax::ast::{TyUs, TyU8, TyU16, TyU32, TyU64, TyF64, TyF32};
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::parse::token::{self, special_names, special_idents};
|
||||
use syntax::codemap::{self, Span, Pos};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::parse::token::{self, special_names, special_idents};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
|
||||
use rustc_front::intravisit::{self, FnKind, Visitor};
|
||||
@ -215,210 +216,221 @@ pub enum UnresolvedNameContext {
|
||||
fn resolve_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
|
||||
span: syntax::codemap::Span,
|
||||
resolution_error: ResolutionError<'b>) {
|
||||
resolve_struct_error(resolver, span, resolution_error).emit();
|
||||
}
|
||||
|
||||
fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
|
||||
span: syntax::codemap::Span,
|
||||
resolution_error: ResolutionError<'b>)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
if !resolver.emit_errors {
|
||||
return;
|
||||
return resolver.session.diagnostic().struct_dummy();
|
||||
}
|
||||
|
||||
match resolution_error {
|
||||
ResolutionError::TypeParametersFromOuterFunction => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0401,
|
||||
"can't use type parameters from outer function; try using a local type \
|
||||
parameter instead");
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0401,
|
||||
"can't use type parameters from outer function; try using a local \
|
||||
type parameter instead")
|
||||
}
|
||||
ResolutionError::OuterTypeParameterContext => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0402,
|
||||
"cannot use an outer type parameter in this context");
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0402,
|
||||
"cannot use an outer type parameter in this context")
|
||||
}
|
||||
ResolutionError::NameAlreadyUsedInTypeParameterList(name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0403,
|
||||
"the name `{}` is already used for a type parameter in this type parameter \
|
||||
list",
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0403,
|
||||
"the name `{}` is already used for a type parameter in this type \
|
||||
parameter list",
|
||||
name)
|
||||
}
|
||||
ResolutionError::IsNotATrait(name) => {
|
||||
span_err!(resolver.session, span, E0404, "`{}` is not a trait", name);
|
||||
struct_span_err!(resolver.session, span, E0404, "`{}` is not a trait", name)
|
||||
}
|
||||
ResolutionError::UndeclaredTraitName(name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0405,
|
||||
"use of undeclared trait name `{}`",
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0405,
|
||||
"use of undeclared trait name `{}`",
|
||||
name)
|
||||
}
|
||||
ResolutionError::UndeclaredAssociatedType => {
|
||||
span_err!(resolver.session, span, E0406, "undeclared associated type");
|
||||
struct_span_err!(resolver.session, span, E0406, "undeclared associated type")
|
||||
}
|
||||
ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0407,
|
||||
"method `{}` is not a member of trait `{}`",
|
||||
method,
|
||||
trait_);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0407,
|
||||
"method `{}` is not a member of trait `{}`",
|
||||
method,
|
||||
trait_)
|
||||
}
|
||||
ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0437,
|
||||
"type `{}` is not a member of trait `{}`",
|
||||
type_,
|
||||
trait_);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0437,
|
||||
"type `{}` is not a member of trait `{}`",
|
||||
type_,
|
||||
trait_)
|
||||
}
|
||||
ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0438,
|
||||
"const `{}` is not a member of trait `{}`",
|
||||
const_,
|
||||
trait_);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0438,
|
||||
"const `{}` is not a member of trait `{}`",
|
||||
const_,
|
||||
trait_)
|
||||
}
|
||||
ResolutionError::VariableNotBoundInPattern(variable_name, pattern_number) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0408,
|
||||
"variable `{}` from pattern #1 is not bound in pattern #{}",
|
||||
variable_name,
|
||||
pattern_number);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0408,
|
||||
"variable `{}` from pattern #1 is not bound in pattern #{}",
|
||||
variable_name,
|
||||
pattern_number)
|
||||
}
|
||||
ResolutionError::VariableBoundWithDifferentMode(variable_name, pattern_number) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0409,
|
||||
"variable `{}` is bound with different mode in pattern #{} than in pattern \
|
||||
#1",
|
||||
variable_name,
|
||||
pattern_number);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0409,
|
||||
"variable `{}` is bound with different mode in pattern #{} than in \
|
||||
pattern #1",
|
||||
variable_name,
|
||||
pattern_number)
|
||||
}
|
||||
ResolutionError::VariableNotBoundInParentPattern(variable_name, pattern_number) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0410,
|
||||
"variable `{}` from pattern #{} is not bound in pattern #1",
|
||||
variable_name,
|
||||
pattern_number);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0410,
|
||||
"variable `{}` from pattern #{} is not bound in pattern #1",
|
||||
variable_name,
|
||||
pattern_number)
|
||||
}
|
||||
ResolutionError::SelfUsedOutsideImplOrTrait => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0411,
|
||||
"use of `Self` outside of an impl or trait");
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0411,
|
||||
"use of `Self` outside of an impl or trait")
|
||||
}
|
||||
ResolutionError::UseOfUndeclared(kind, name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0412,
|
||||
"use of undeclared {} `{}`",
|
||||
kind,
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0412,
|
||||
"use of undeclared {} `{}`",
|
||||
kind,
|
||||
name)
|
||||
}
|
||||
ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0413,
|
||||
"declaration of `{}` shadows an enum variant or unit-like struct in scope",
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0413,
|
||||
"declaration of `{}` shadows an enum variant \
|
||||
or unit-like struct in scope",
|
||||
name)
|
||||
}
|
||||
ResolutionError::OnlyIrrefutablePatternsAllowedHere(did, name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0414,
|
||||
"only irrefutable patterns allowed here");
|
||||
resolver.session.span_note(span,
|
||||
"there already is a constant in scope sharing the same \
|
||||
name as this pattern");
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0414,
|
||||
"only irrefutable patterns allowed here");
|
||||
err.span_note(span,
|
||||
"there already is a constant in scope sharing the same \
|
||||
name as this pattern");
|
||||
if let Some(sp) = resolver.ast_map.span_if_local(did) {
|
||||
resolver.session.span_note(sp, "constant defined here");
|
||||
err.span_note(sp, "constant defined here");
|
||||
}
|
||||
if let Some(directive) = resolver.current_module
|
||||
.import_resolutions
|
||||
.borrow()
|
||||
.get(&name) {
|
||||
let item = resolver.ast_map.expect_item(directive.value_ns.id);
|
||||
resolver.session.span_note(item.span, "constant imported here");
|
||||
err.span_note(item.span, "constant imported here");
|
||||
}
|
||||
err
|
||||
}
|
||||
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0415,
|
||||
"identifier `{}` is bound more than once in this parameter list",
|
||||
identifier);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0415,
|
||||
"identifier `{}` is bound more than once in this parameter list",
|
||||
identifier)
|
||||
}
|
||||
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0416,
|
||||
"identifier `{}` is bound more than once in the same pattern",
|
||||
identifier);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0416,
|
||||
"identifier `{}` is bound more than once in the same pattern",
|
||||
identifier)
|
||||
}
|
||||
ResolutionError::StaticVariableReference => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0417,
|
||||
"static variables cannot be referenced in a pattern, use a `const` instead");
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0417,
|
||||
"static variables cannot be referenced in a pattern, use a \
|
||||
`const` instead")
|
||||
}
|
||||
ResolutionError::NotAnEnumVariantStructOrConst(name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0418,
|
||||
"`{}` is not an enum variant, struct or const",
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0418,
|
||||
"`{}` is not an enum variant, struct or const",
|
||||
name)
|
||||
}
|
||||
ResolutionError::UnresolvedEnumVariantStructOrConst(name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0419,
|
||||
"unresolved enum variant, struct or const `{}`",
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0419,
|
||||
"unresolved enum variant, struct or const `{}`",
|
||||
name)
|
||||
}
|
||||
ResolutionError::NotAnAssociatedConst(name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0420,
|
||||
"`{}` is not an associated const",
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0420,
|
||||
"`{}` is not an associated const",
|
||||
name)
|
||||
}
|
||||
ResolutionError::UnresolvedAssociatedConst(name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0421,
|
||||
"unresolved associated const `{}`",
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0421,
|
||||
"unresolved associated const `{}`",
|
||||
name)
|
||||
}
|
||||
ResolutionError::DoesNotNameAStruct(name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0422,
|
||||
"`{}` does not name a structure",
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0422,
|
||||
"`{}` does not name a structure",
|
||||
name)
|
||||
}
|
||||
ResolutionError::StructVariantUsedAsFunction(path_name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0423,
|
||||
"`{}` is the name of a struct or struct variant, but this expression uses \
|
||||
it like a function name",
|
||||
path_name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0423,
|
||||
"`{}` is the name of a struct or struct variant, but this expression \
|
||||
uses it like a function name",
|
||||
path_name)
|
||||
}
|
||||
ResolutionError::SelfNotAvailableInStaticMethod => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0424,
|
||||
"`self` is not available in a static method. Maybe a `self` argument is \
|
||||
missing?");
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0424,
|
||||
"`self` is not available in a static method. Maybe a `self` \
|
||||
argument is missing?")
|
||||
}
|
||||
ResolutionError::UnresolvedName(path, msg, context) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0425,
|
||||
"unresolved name `{}`{}",
|
||||
path,
|
||||
msg);
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0425,
|
||||
"unresolved name `{}`{}",
|
||||
path,
|
||||
msg);
|
||||
|
||||
match context {
|
||||
UnresolvedNameContext::Other => {} // no help available
|
||||
@ -448,75 +460,77 @@ fn resolve_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
|
||||
}
|
||||
|
||||
if !help_msg.is_empty() {
|
||||
resolver.session.fileline_help(span, &help_msg);
|
||||
err.fileline_help(span, &help_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
err
|
||||
}
|
||||
ResolutionError::UndeclaredLabel(name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0426,
|
||||
"use of undeclared label `{}`",
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0426,
|
||||
"use of undeclared label `{}`",
|
||||
name)
|
||||
}
|
||||
ResolutionError::CannotUseRefBindingModeWith(descr) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0427,
|
||||
"cannot use `ref` binding mode with {}",
|
||||
descr);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0427,
|
||||
"cannot use `ref` binding mode with {}",
|
||||
descr)
|
||||
}
|
||||
ResolutionError::DuplicateDefinition(namespace, name) => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0428,
|
||||
"duplicate definition of {} `{}`",
|
||||
namespace,
|
||||
name);
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0428,
|
||||
"duplicate definition of {} `{}`",
|
||||
namespace,
|
||||
name)
|
||||
}
|
||||
ResolutionError::SelfImportsOnlyAllowedWithin => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0429,
|
||||
"{}",
|
||||
"`self` imports are only allowed within a { } list");
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0429,
|
||||
"{}",
|
||||
"`self` imports are only allowed within a { } list")
|
||||
}
|
||||
ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0430,
|
||||
"`self` import can only appear once in the list");
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0430,
|
||||
"`self` import can only appear once in the list")
|
||||
}
|
||||
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0431,
|
||||
"`self` import can only appear in an import list with a non-empty prefix");
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0431,
|
||||
"`self` import can only appear in an import list with a \
|
||||
non-empty prefix")
|
||||
}
|
||||
ResolutionError::UnresolvedImport(name) => {
|
||||
let msg = match name {
|
||||
Some((n, p)) => format!("unresolved import `{}`{}", n, p),
|
||||
None => "unresolved import".to_owned(),
|
||||
};
|
||||
span_err!(resolver.session, span, E0432, "{}", msg);
|
||||
struct_span_err!(resolver.session, span, E0432, "{}", msg)
|
||||
}
|
||||
ResolutionError::FailedToResolve(msg) => {
|
||||
span_err!(resolver.session, span, E0433, "failed to resolve. {}", msg);
|
||||
struct_span_err!(resolver.session, span, E0433, "failed to resolve. {}", msg)
|
||||
}
|
||||
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0434,
|
||||
"{}",
|
||||
"can't capture dynamic environment in a fn item; use the || { ... } \
|
||||
closure form instead");
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0434,
|
||||
"{}",
|
||||
"can't capture dynamic environment in a fn item; use the || { ... } \
|
||||
closure form instead")
|
||||
}
|
||||
ResolutionError::AttemptToUseNonConstantValueInConstant => {
|
||||
span_err!(resolver.session,
|
||||
span,
|
||||
E0435,
|
||||
"attempt to use a non-constant value in a constant");
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0435,
|
||||
"attempt to use a non-constant value in a constant")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2180,16 +2194,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
debug!("(resolving trait) found trait def: {:?}", path_res);
|
||||
Ok(path_res)
|
||||
} else {
|
||||
resolve_error(self,
|
||||
trait_path.span,
|
||||
ResolutionError::IsNotATrait(&*path_names_to_string(trait_path,
|
||||
path_depth)));
|
||||
let mut err =
|
||||
resolve_struct_error(self,
|
||||
trait_path.span,
|
||||
ResolutionError::IsNotATrait(&*path_names_to_string(trait_path,
|
||||
path_depth)));
|
||||
|
||||
// If it's a typedef, give a note
|
||||
if let DefTy(..) = path_res.base_def {
|
||||
self.session
|
||||
.span_note(trait_path.span, "`type` aliases cannot be used for traits");
|
||||
err.span_note(trait_path.span,
|
||||
"`type` aliases cannot be used for traits");
|
||||
}
|
||||
err.emit();
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
@ -3470,17 +3486,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
if let DefVariant(_, _, true) = path_res.base_def {
|
||||
let path_name = path_names_to_string(path, 0);
|
||||
|
||||
resolve_error(self,
|
||||
expr.span,
|
||||
ResolutionError::StructVariantUsedAsFunction(&*path_name));
|
||||
let mut err = resolve_struct_error(self,
|
||||
expr.span,
|
||||
ResolutionError::StructVariantUsedAsFunction(&*path_name));
|
||||
|
||||
let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
|
||||
path_name);
|
||||
if self.emit_errors {
|
||||
self.session.fileline_help(expr.span, &msg);
|
||||
err.fileline_help(expr.span, &msg);
|
||||
} else {
|
||||
self.session.span_help(expr.span, &msg);
|
||||
err.span_help(expr.span, &msg);
|
||||
}
|
||||
err.emit();
|
||||
self.record_def(expr.id, err_path_resolution());
|
||||
} else {
|
||||
// Write the result into the def map.
|
||||
@ -3510,20 +3527,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
self.record_def(expr.id, err_path_resolution());
|
||||
match type_res.map(|r| r.base_def) {
|
||||
Some(DefTy(struct_id, _)) if self.structs.contains_key(&struct_id) => {
|
||||
resolve_error(
|
||||
self,
|
||||
expr.span,
|
||||
ResolutionError::StructVariantUsedAsFunction(
|
||||
&*path_name)
|
||||
);
|
||||
let mut err = resolve_struct_error(self,
|
||||
expr.span,
|
||||
ResolutionError::StructVariantUsedAsFunction(&*path_name));
|
||||
|
||||
let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
|
||||
path_name);
|
||||
if self.emit_errors {
|
||||
self.session.fileline_help(expr.span, &msg);
|
||||
err.fileline_help(expr.span, &msg);
|
||||
} else {
|
||||
self.session.span_help(expr.span, &msg);
|
||||
err.span_help(expr.span, &msg);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
_ => {
|
||||
// Keep reporting some errors even if they're ignored above.
|
||||
|
@ -454,8 +454,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
let note_msg = format!("Consider marking `{}` as `pub` in the imported \
|
||||
module",
|
||||
source);
|
||||
span_err!(self.resolver.session, directive.span, E0364, "{}", &msg);
|
||||
self.resolver.session.span_note(directive.span, ¬e_msg);
|
||||
struct_span_err!(self.resolver.session, directive.span, E0364, "{}", &msg)
|
||||
.span_note(directive.span, ¬e_msg)
|
||||
.emit();
|
||||
pub_err = true;
|
||||
}
|
||||
if directive.is_public && child_name_bindings.value_ns.
|
||||
@ -479,8 +480,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
let msg = format!("`{}` is private, and cannot be reexported", source);
|
||||
let note_msg = format!("Consider declaring module `{}` as a `pub mod`",
|
||||
source);
|
||||
span_err!(self.resolver.session, directive.span, E0365, "{}", &msg);
|
||||
self.resolver.session.span_note(directive.span, ¬e_msg);
|
||||
struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg)
|
||||
.span_note(directive.span, ¬e_msg)
|
||||
.emit();
|
||||
}
|
||||
if !pub_err && directive.is_public && child_name_bindings.type_ns.
|
||||
defined_with(DefModifiers::PRIVATE_VARIANT) {
|
||||
@ -959,19 +961,20 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
}
|
||||
ValueNS => "value",
|
||||
};
|
||||
span_err!(self.resolver.session,
|
||||
import_span,
|
||||
E0252,
|
||||
"a {} named `{}` has already been imported in this module",
|
||||
ns_word,
|
||||
name);
|
||||
let use_id = import_resolution[namespace].id;
|
||||
let item = self.resolver.ast_map.expect_item(use_id);
|
||||
// item is syntax::ast::Item;
|
||||
span_note!(self.resolver.session,
|
||||
let mut err = struct_span_err!(self.resolver.session,
|
||||
import_span,
|
||||
E0252,
|
||||
"a {} named `{}` has already been imported \
|
||||
in this module",
|
||||
ns_word,
|
||||
name);
|
||||
span_note!(&mut err,
|
||||
item.span,
|
||||
"previous import of `{}` here",
|
||||
name);
|
||||
err.emit();
|
||||
}
|
||||
Some(_) | None => {}
|
||||
}
|
||||
@ -1022,14 +1025,16 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
match import.value_ns.target {
|
||||
Some(ref target) if target.shadowable != Shadowable::Always => {
|
||||
if let Some(ref value) = *name_bindings.value_ns.borrow() {
|
||||
span_err!(self.resolver.session,
|
||||
import_span,
|
||||
E0255,
|
||||
"import `{}` conflicts with value in this module",
|
||||
name);
|
||||
let mut err = struct_span_err!(self.resolver.session,
|
||||
import_span,
|
||||
E0255,
|
||||
"import `{}` conflicts with \
|
||||
value in this module",
|
||||
name);
|
||||
if let Some(span) = value.span {
|
||||
self.resolver.session.span_note(span, "conflicting value here");
|
||||
err.span_note(span, "conflicting value here");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
Some(_) | None => {}
|
||||
@ -1045,15 +1050,16 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
("trait in this module", "note conflicting trait here"),
|
||||
_ => ("type in this module", "note conflicting type here"),
|
||||
};
|
||||
span_err!(self.resolver.session,
|
||||
import_span,
|
||||
E0256,
|
||||
"import `{}` conflicts with {}",
|
||||
name,
|
||||
what);
|
||||
let mut err = struct_span_err!(self.resolver.session,
|
||||
import_span,
|
||||
E0256,
|
||||
"import `{}` conflicts with {}",
|
||||
name,
|
||||
what);
|
||||
if let Some(span) = ty.span {
|
||||
self.resolver.session.span_note(span, note);
|
||||
err.span_note(span, note);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
Some(_) | None => {}
|
||||
|
@ -406,11 +406,12 @@ impl<'a> ArchiveBuilder<'a> {
|
||||
Ok(prog) => {
|
||||
let o = prog.wait_with_output().unwrap();
|
||||
if !o.status.success() {
|
||||
sess.err(&format!("{:?} failed with: {}", cmd, o.status));
|
||||
sess.note(&format!("stdout ---\n{}",
|
||||
str::from_utf8(&o.stdout).unwrap()));
|
||||
sess.note(&format!("stderr ---\n{}",
|
||||
str::from_utf8(&o.stderr).unwrap()));
|
||||
sess.struct_err(&format!("{:?} failed with: {}", cmd, o.status))
|
||||
.note(&format!("stdout ---\n{}",
|
||||
str::from_utf8(&o.stdout).unwrap()))
|
||||
.note(&format!("stderr ---\n{}",
|
||||
str::from_utf8(&o.stderr).unwrap()))
|
||||
.emit();
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
o
|
||||
|
@ -817,10 +817,10 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
|
||||
ab.build();
|
||||
|
||||
if !all_native_libs.is_empty() {
|
||||
sess.note("link against the following native artifacts when linking against \
|
||||
this static library");
|
||||
sess.note("the order and any duplication can be significant on some platforms, \
|
||||
and so may need to be preserved");
|
||||
sess.note_without_error("link against the following native artifacts when linking against \
|
||||
this static library");
|
||||
sess.note_without_error("the order and any duplication can be significant on some \
|
||||
platforms, and so may need to be preserved");
|
||||
}
|
||||
|
||||
for &(kind, ref lib) in &all_native_libs {
|
||||
@ -829,7 +829,7 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
|
||||
NativeLibraryKind::NativeUnknown => "library",
|
||||
NativeLibraryKind::NativeFramework => "framework",
|
||||
};
|
||||
sess.note(&format!("{}: {}", name, *lib));
|
||||
sess.note_without_error(&format!("{}: {}", name, *lib));
|
||||
}
|
||||
}
|
||||
|
||||
@ -902,13 +902,14 @@ fn link_natively(sess: &Session, dylib: bool,
|
||||
})
|
||||
}
|
||||
if !prog.status.success() {
|
||||
sess.err(&format!("linking with `{}` failed: {}",
|
||||
pname,
|
||||
prog.status));
|
||||
sess.note(&format!("{:?}", &cmd));
|
||||
let mut output = prog.stderr.clone();
|
||||
output.extend_from_slice(&prog.stdout);
|
||||
sess.note(&*escape_string(&output[..]));
|
||||
sess.struct_err(&format!("linking with `{}` failed: {}",
|
||||
pname,
|
||||
prog.status))
|
||||
.note(&format!("{:?}", &cmd))
|
||||
.note(&*escape_string(&output[..]))
|
||||
.emit();
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
info!("linker stderr:\n{}", escape_string(&prog.stderr[..]));
|
||||
|
@ -29,8 +29,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
|
||||
name_extra: &str,
|
||||
output_names: &config::OutputFilenames) {
|
||||
if sess.opts.cg.prefer_dynamic {
|
||||
sess.err("cannot prefer dynamic linking when performing LTO");
|
||||
sess.note("only 'staticlib' and 'bin' outputs are supported with LTO");
|
||||
sess.struct_err("cannot prefer dynamic linking when performing LTO")
|
||||
.note("only 'staticlib' and 'bin' outputs are supported with LTO")
|
||||
.emit();
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
|
||||
|
@ -359,8 +359,9 @@ unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>,
|
||||
}
|
||||
|
||||
None => {
|
||||
cgcx.handler.err(msg);
|
||||
cgcx.handler.note("build without -C codegen-units for more exact errors");
|
||||
cgcx.handler.struct_err(msg)
|
||||
.note("build without -C codegen-units for more exact errors")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -397,11 +398,11 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
|
||||
|
||||
if enabled {
|
||||
let loc = llvm::debug_loc_to_string(llcx, opt.debug_loc);
|
||||
cgcx.handler.note(&format!("optimization {} for {} at {}: {}",
|
||||
opt.kind.describe(),
|
||||
pass_name,
|
||||
if loc.is_empty() { "[unknown]" } else { &*loc },
|
||||
llvm::twine_to_string(opt.message)));
|
||||
cgcx.handler.note_without_error(&format!("optimization {} for {} at {}: {}",
|
||||
opt.kind.describe(),
|
||||
pass_name,
|
||||
if loc.is_empty() { "[unknown]" } else { &*loc },
|
||||
llvm::twine_to_string(opt.message)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -931,13 +932,15 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
|
||||
match cmd.output() {
|
||||
Ok(prog) => {
|
||||
if !prog.status.success() {
|
||||
sess.err(&format!("linking with `{}` failed: {}",
|
||||
pname,
|
||||
prog.status));
|
||||
sess.note(&format!("{:?}", &cmd));
|
||||
let mut note = prog.stderr.clone();
|
||||
note.extend_from_slice(&prog.stdout);
|
||||
sess.note(str::from_utf8(¬e[..]).unwrap());
|
||||
|
||||
sess.struct_err(&format!("linking with `{}` failed: {}",
|
||||
pname,
|
||||
prog.status))
|
||||
.note(&format!("{:?}", &cmd))
|
||||
.note(str::from_utf8(¬e[..]).unwrap())
|
||||
.emit();
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
},
|
||||
|
@ -2181,17 +2181,20 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &hir::EnumDef, sp: Span,
|
||||
}
|
||||
);
|
||||
|
||||
// FIXME(#30505) Should use logging for this.
|
||||
if print_info {
|
||||
let llty = type_of::sizing_type_of(ccx, ty);
|
||||
|
||||
let sess = &ccx.tcx().sess;
|
||||
sess.span_note(sp, &*format!("total size: {} bytes", llsize_of_real(ccx, llty)));
|
||||
sess.span_note_without_error(sp,
|
||||
&*format!("total size: {} bytes", llsize_of_real(ccx, llty)));
|
||||
match *avar {
|
||||
adt::General(..) => {
|
||||
for (i, var) in enum_def.variants.iter().enumerate() {
|
||||
ccx.tcx()
|
||||
.sess
|
||||
.span_note(var.span, &*format!("variant data: {} bytes", sizes[i]));
|
||||
.span_note_without_error(var.span,
|
||||
&*format!("variant data: {} bytes", sizes[i]));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -2203,16 +2206,16 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &hir::EnumDef, sp: Span,
|
||||
if !is_allow && largest > slargest * 3 && slargest > 0 {
|
||||
// Use lint::raw_emit_lint rather than sess.add_lint because the lint-printing
|
||||
// pass for the latter already ran.
|
||||
lint::raw_emit_lint(&ccx.tcx().sess,
|
||||
lint::builtin::VARIANT_SIZE_DIFFERENCES,
|
||||
*lvlsrc.unwrap(),
|
||||
Some(sp),
|
||||
&format!("enum variant is more than three times larger ({} bytes) \
|
||||
than the next largest (ignoring padding)",
|
||||
largest));
|
||||
|
||||
ccx.sess().span_note(enum_def.variants[largest_index].span,
|
||||
"this variant is the largest");
|
||||
lint::raw_struct_lint(&ccx.tcx().sess,
|
||||
lint::builtin::VARIANT_SIZE_DIFFERENCES,
|
||||
*lvlsrc.unwrap(),
|
||||
Some(sp),
|
||||
&format!("enum variant is more than three times larger ({} bytes) \
|
||||
than the next largest (ignoring padding)",
|
||||
largest))
|
||||
.span_note(enum_def.variants[largest_index].span,
|
||||
"this variant is the largest")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2489,9 +2492,10 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) {
|
||||
let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], &ccx.int_type());
|
||||
|
||||
let llfn = declare::define_cfn(ccx, "main", llfty, ccx.tcx().mk_nil()).unwrap_or_else(|| {
|
||||
ccx.sess().span_err(sp, "entry symbol `main` defined multiple times");
|
||||
// FIXME: We should be smart and show a better diagnostic here.
|
||||
ccx.sess().help("did you use #[no_mangle] on `fn main`? Use #[start] instead");
|
||||
ccx.sess().struct_span_err(sp, "entry symbol `main` defined multiple times")
|
||||
.help("did you use #[no_mangle] on `fn main`? Use #[start] instead")
|
||||
.emit();
|
||||
ccx.sess().abort_if_errors();
|
||||
panic!();
|
||||
});
|
||||
|
@ -460,12 +460,13 @@ fn gate_simd_ffi(tcx: &ty::ctxt, decl: &hir::FnDecl, ty: &ty::BareFnTy) {
|
||||
if !tcx.sess.features.borrow().simd_ffi {
|
||||
let check = |ast_ty: &hir::Ty, ty: ty::Ty| {
|
||||
if ty.is_simd() {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
tcx.sess.struct_span_err(ast_ty.span,
|
||||
&format!("use of SIMD type `{}` in FFI is highly experimental and \
|
||||
may result in invalid code",
|
||||
pprust::ty_to_string(ast_ty)));
|
||||
tcx.sess.fileline_help(ast_ty.span,
|
||||
"add #![feature(simd_ffi)] to the crate attributes to enable");
|
||||
pprust::ty_to_string(ast_ty)))
|
||||
.fileline_help(ast_ty.span,
|
||||
"add #![feature(simd_ffi)] to the crate attributes to enable")
|
||||
.emit();
|
||||
}
|
||||
};
|
||||
let sig = &ty.sig.0;
|
||||
|
@ -68,6 +68,7 @@ use util::nodemap::FnvHashSet;
|
||||
|
||||
use syntax::{abi, ast};
|
||||
use syntax::codemap::{Span, Pos};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::feature_gate::{GateIssue, emit_feature_err};
|
||||
use syntax::parse::token;
|
||||
|
||||
@ -195,7 +196,7 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &hir::Lifetime)
|
||||
}
|
||||
|
||||
fn report_elision_failure(
|
||||
tcx: &ty::ctxt,
|
||||
db: &mut DiagnosticBuilder,
|
||||
default_span: Span,
|
||||
params: Vec<ElisionFailureInfo>)
|
||||
{
|
||||
@ -233,26 +234,26 @@ fn report_elision_failure(
|
||||
}
|
||||
|
||||
if len == 0 {
|
||||
fileline_help!(tcx.sess, default_span,
|
||||
fileline_help!(db, default_span,
|
||||
"this function's return type contains a borrowed value, but \
|
||||
there is no value for it to be borrowed from");
|
||||
fileline_help!(tcx.sess, default_span,
|
||||
fileline_help!(db, default_span,
|
||||
"consider giving it a 'static lifetime");
|
||||
} else if !any_lifetimes {
|
||||
fileline_help!(tcx.sess, default_span,
|
||||
fileline_help!(db, default_span,
|
||||
"this function's return type contains a borrowed value with \
|
||||
an elided lifetime, but the lifetime cannot be derived from \
|
||||
the arguments");
|
||||
fileline_help!(tcx.sess, default_span,
|
||||
fileline_help!(db, default_span,
|
||||
"consider giving it an explicit bounded or 'static \
|
||||
lifetime");
|
||||
} else if len == 1 {
|
||||
fileline_help!(tcx.sess, default_span,
|
||||
fileline_help!(db, default_span,
|
||||
"this function's return type contains a borrowed value, but \
|
||||
the signature does not say which {} it is borrowed from",
|
||||
m);
|
||||
} else {
|
||||
fileline_help!(tcx.sess, default_span,
|
||||
fileline_help!(db, default_span,
|
||||
"this function's return type contains a borrowed value, but \
|
||||
the signature does not say whether it is borrowed from {}",
|
||||
m);
|
||||
@ -273,11 +274,12 @@ pub fn opt_ast_region_to_region<'tcx>(
|
||||
None => match rscope.anon_regions(default_span, 1) {
|
||||
Ok(rs) => rs[0],
|
||||
Err(params) => {
|
||||
span_err!(this.tcx().sess, default_span, E0106,
|
||||
"missing lifetime specifier");
|
||||
let mut err = struct_span_err!(this.tcx().sess, default_span, E0106,
|
||||
"missing lifetime specifier");
|
||||
if let Some(params) = params {
|
||||
report_elision_failure(this.tcx(), default_span, params);
|
||||
report_elision_failure(&mut err, default_span, params);
|
||||
}
|
||||
err.emit();
|
||||
ty::ReStatic
|
||||
}
|
||||
}
|
||||
@ -1044,9 +1046,9 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
span_err!(this.tcx().sess, ty.span, E0178,
|
||||
"expected a path on the left-hand side of `+`, not `{}`",
|
||||
pprust::ty_to_string(ty));
|
||||
let mut err = struct_span_err!(this.tcx().sess, ty.span, E0178,
|
||||
"expected a path on the left-hand side of `+`, not `{}`",
|
||||
pprust::ty_to_string(ty));
|
||||
let hi = bounds.iter().map(|x| match *x {
|
||||
hir::TraitTyParamBound(ref tr, _) => tr.span.hi,
|
||||
hir::RegionTyParamBound(ref r) => r.span.hi,
|
||||
@ -1059,29 +1061,28 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
|
||||
match (&ty.node, full_span) {
|
||||
(&hir::TyRptr(None, ref mut_ty), Some(full_span)) => {
|
||||
let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
|
||||
this.tcx().sess
|
||||
.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
|
||||
format!("&{}({} +{})",
|
||||
mutbl_str,
|
||||
pprust::ty_to_string(&*mut_ty.ty),
|
||||
pprust::bounds_to_string(bounds)));
|
||||
err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
|
||||
format!("&{}({} +{})",
|
||||
mutbl_str,
|
||||
pprust::ty_to_string(&*mut_ty.ty),
|
||||
pprust::bounds_to_string(bounds)));
|
||||
}
|
||||
(&hir::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
|
||||
let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
|
||||
this.tcx().sess
|
||||
.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
|
||||
format!("&{} {}({} +{})",
|
||||
pprust::lifetime_to_string(lt),
|
||||
mutbl_str,
|
||||
pprust::ty_to_string(&*mut_ty.ty),
|
||||
pprust::bounds_to_string(bounds)));
|
||||
err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
|
||||
format!("&{} {}({} +{})",
|
||||
pprust::lifetime_to_string(lt),
|
||||
mutbl_str,
|
||||
pprust::ty_to_string(&*mut_ty.ty),
|
||||
pprust::bounds_to_string(bounds)));
|
||||
}
|
||||
|
||||
_ => {
|
||||
fileline_help!(this.tcx().sess, ty.span,
|
||||
fileline_help!(&mut err, ty.span,
|
||||
"perhaps you forgot parentheses? (per RFC 438)");
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
Err(ErrorReported)
|
||||
}
|
||||
}
|
||||
@ -1134,7 +1135,8 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>,
|
||||
traits::astconv_object_safety_violations(tcx, principal.def_id());
|
||||
if !object_safety_violations.is_empty() {
|
||||
traits::report_object_safety_error(
|
||||
tcx, span, principal.def_id(), object_safety_violations);
|
||||
tcx, span, principal.def_id(), object_safety_violations)
|
||||
.emit();
|
||||
return tcx.types.err;
|
||||
}
|
||||
|
||||
@ -1235,17 +1237,18 @@ fn one_bound_for_assoc_type<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
}
|
||||
|
||||
if bounds.len() > 1 {
|
||||
span_err!(tcx.sess, span, E0221,
|
||||
"ambiguous associated type `{}` in bounds of `{}`",
|
||||
assoc_name,
|
||||
ty_param_name);
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0221,
|
||||
"ambiguous associated type `{}` in bounds of `{}`",
|
||||
assoc_name,
|
||||
ty_param_name);
|
||||
|
||||
for bound in &bounds {
|
||||
span_note!(tcx.sess, span,
|
||||
span_note!(&mut err, span,
|
||||
"associated type `{}` could derive from `{}`",
|
||||
ty_param_name,
|
||||
bound);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
Ok(bounds[0].clone())
|
||||
@ -1707,12 +1710,13 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
|
||||
}
|
||||
}
|
||||
Err(ref r) => {
|
||||
span_err!(tcx.sess, r.span, E0250,
|
||||
"array length constant evaluation error: {}",
|
||||
r.description());
|
||||
let mut err = struct_span_err!(tcx.sess, r.span, E0250,
|
||||
"array length constant evaluation error: {}",
|
||||
r.description());
|
||||
if !ast_ty.span.contains(r.span) {
|
||||
span_note!(tcx.sess, ast_ty.span, "for array length here")
|
||||
span_note!(&mut err, ast_ty.span, "for array length here")
|
||||
}
|
||||
err.emit();
|
||||
this.tcx().types.err
|
||||
}
|
||||
}
|
||||
|
@ -700,7 +700,9 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
||||
if !is_special_case {
|
||||
return
|
||||
} else {
|
||||
span_note!(tcx.sess, pat.span,
|
||||
// Boo! Too painful to attach this to the actual warning,
|
||||
// it should go away at some point though.
|
||||
tcx.sess.span_note_without_error(pat.span,
|
||||
"this warning will become a HARD ERROR in a future release. \
|
||||
See RFC 218 for details.");
|
||||
}
|
||||
@ -786,12 +788,13 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
||||
for &Spanned { node: ref field, span } in fields {
|
||||
let field_ty = match used_fields.entry(field.name) {
|
||||
Occupied(occupied) => {
|
||||
span_err!(tcx.sess, span, E0025,
|
||||
"field `{}` bound multiple times in the pattern",
|
||||
field.name);
|
||||
span_note!(tcx.sess, *occupied.get(),
|
||||
"field `{}` previously bound here",
|
||||
field.name);
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0025,
|
||||
"field `{}` bound multiple times in the pattern",
|
||||
field.name);
|
||||
span_note!(&mut err, *occupied.get(),
|
||||
"field `{}` previously bound here",
|
||||
field.name);
|
||||
err.emit();
|
||||
tcx.types.err
|
||||
}
|
||||
Vacant(vacant) => {
|
||||
|
@ -61,11 +61,12 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id:
|
||||
return // not a closure method, everything is OK.
|
||||
};
|
||||
|
||||
span_err!(tcx.sess, span, E0174,
|
||||
"explicit use of unboxed closure method `{}` is experimental",
|
||||
method);
|
||||
fileline_help!(tcx.sess, span,
|
||||
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
|
||||
struct_span_err!(tcx.sess, span, E0174,
|
||||
"explicit use of unboxed closure method `{}` is experimental",
|
||||
method)
|
||||
.fileline_help(span, "add `#![feature(unboxed_closures)]` to the crate \
|
||||
attributes to enable")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +229,7 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
sig
|
||||
}
|
||||
_ => {
|
||||
fcx.type_error_message(call_expr.span, |actual| {
|
||||
let mut err = fcx.type_error_struct(call_expr.span, |actual| {
|
||||
format!("expected function, found `{}`", actual)
|
||||
}, callee_ty, None);
|
||||
|
||||
@ -237,12 +238,14 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
if let Some(pr) = tcx.def_map.borrow().get(&expr.id) {
|
||||
if pr.depth == 0 && pr.base_def != def::DefErr {
|
||||
if let Some(span) = tcx.map.span_if_local(pr.def_id()) {
|
||||
tcx.sess.span_note(span, "defined here")
|
||||
err.span_note(span, "defined here");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
|
||||
// This is the "default" function signature, used in case of error.
|
||||
// In that case, we check each argument against "error" in order to
|
||||
// set up all the node type bindings.
|
||||
|
@ -127,23 +127,25 @@ impl<'tcx> CastCheck<'tcx> {
|
||||
CastError::NeedViaThinPtr |
|
||||
CastError::NeedViaInt |
|
||||
CastError::NeedViaUsize => {
|
||||
fcx.type_error_message(self.span, |actual| {
|
||||
fcx.type_error_struct(self.span, |actual| {
|
||||
format!("casting `{}` as `{}` is invalid",
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(self.cast_ty))
|
||||
}, self.expr_ty, None);
|
||||
fcx.ccx.tcx.sess.fileline_help(self.span,
|
||||
&format!("cast through {} first", match e {
|
||||
CastError::NeedViaPtr => "a raw pointer",
|
||||
CastError::NeedViaThinPtr => "a thin pointer",
|
||||
CastError::NeedViaInt => "an integer",
|
||||
CastError::NeedViaUsize => "a usize",
|
||||
_ => unreachable!()
|
||||
}));
|
||||
}, self.expr_ty, None)
|
||||
.fileline_help(self.span,
|
||||
&format!("cast through {} first", match e {
|
||||
CastError::NeedViaPtr => "a raw pointer",
|
||||
CastError::NeedViaThinPtr => "a thin pointer",
|
||||
CastError::NeedViaInt => "an integer",
|
||||
CastError::NeedViaUsize => "a usize",
|
||||
_ => unreachable!()
|
||||
}))
|
||||
.emit();
|
||||
}
|
||||
CastError::CastToBool => {
|
||||
span_err!(fcx.tcx().sess, self.span, E0054, "cannot cast as `bool`");
|
||||
fcx.ccx.tcx.sess.fileline_help(self.span, "compare with zero instead");
|
||||
struct_span_err!(fcx.tcx().sess, self.span, E0054, "cannot cast as `bool`")
|
||||
.fileline_help(self.span, "compare with zero instead")
|
||||
.emit();
|
||||
}
|
||||
CastError::CastToChar => {
|
||||
fcx.type_error_message(self.span, |actual| {
|
||||
@ -165,12 +167,13 @@ impl<'tcx> CastCheck<'tcx> {
|
||||
}, self.expr_ty, None);
|
||||
}
|
||||
CastError::DifferingKinds => {
|
||||
fcx.type_error_message(self.span, |actual| {
|
||||
fcx.type_error_struct(self.span, |actual| {
|
||||
format!("casting `{}` as `{}` is invalid",
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(self.cast_ty))
|
||||
}, self.expr_ty, None);
|
||||
fcx.ccx.tcx.sess.fileline_note(self.span, "vtable kinds may not match");
|
||||
}, self.expr_ty, None)
|
||||
.fileline_note(self.span, "vtable kinds may not match")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,12 +95,13 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
|
||||
|
||||
if let Err(_) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span),
|
||||
named_type, fresh_impl_self_ty) {
|
||||
span_err!(tcx.sess, drop_impl_span, E0366,
|
||||
"Implementations of Drop cannot be specialized");
|
||||
let item_span = tcx.map.span(self_type_node_id);
|
||||
tcx.sess.span_note(item_span,
|
||||
"Use same sequence of generic type and region \
|
||||
parameters that is on the struct/enum definition");
|
||||
struct_span_err!(tcx.sess, drop_impl_span, E0366,
|
||||
"Implementations of Drop cannot be specialized")
|
||||
.span_note(item_span,
|
||||
"Use same sequence of generic type and region \
|
||||
parameters that is on the struct/enum definition")
|
||||
.emit();
|
||||
return Err(());
|
||||
}
|
||||
|
||||
@ -197,11 +198,12 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
|
||||
if !assumptions_in_impl_context.contains(&predicate) {
|
||||
let item_span = tcx.map.span(self_type_node_id);
|
||||
span_err!(tcx.sess, drop_impl_span, E0367,
|
||||
"The requirement `{}` is added only by the Drop impl.", predicate);
|
||||
tcx.sess.span_note(item_span,
|
||||
"The same requirement must be part of \
|
||||
the struct/enum definition");
|
||||
struct_span_err!(tcx.sess, drop_impl_span, E0367,
|
||||
"The requirement `{}` is added only by the Drop impl.", predicate)
|
||||
.span_note(item_span,
|
||||
"The same requirement must be part of \
|
||||
the struct/enum definition")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,8 +291,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>
|
||||
Ok(()) => {}
|
||||
Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => {
|
||||
let tcx = rcx.tcx();
|
||||
span_err!(tcx.sess, span, E0320,
|
||||
"overflow while adding drop-check rules for {}", typ);
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0320,
|
||||
"overflow while adding drop-check rules for {}", typ);
|
||||
match *ctxt {
|
||||
TypeContext::Root => {
|
||||
// no need for an additional note if the overflow
|
||||
@ -311,7 +313,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>
|
||||
format!("`{}`", field)
|
||||
};
|
||||
span_note!(
|
||||
rcx.tcx().sess,
|
||||
&mut err,
|
||||
span,
|
||||
"overflowed on {} field {} type: {}",
|
||||
variant_name,
|
||||
@ -319,6 +321,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>
|
||||
detected_on_typ);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ use util::nodemap::{FnvHashSet};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use rustc_front::print::pprust;
|
||||
use rustc_front::hir;
|
||||
|
||||
@ -55,7 +56,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
mode }) => {
|
||||
let cx = fcx.tcx();
|
||||
|
||||
fcx.type_error_message(
|
||||
let mut err = fcx.type_error_struct(
|
||||
span,
|
||||
|actual| {
|
||||
format!("no {} named `{}` found for type `{}` \
|
||||
@ -78,17 +79,21 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
// snippet
|
||||
};
|
||||
|
||||
let span_stored_function = || {
|
||||
cx.sess.span_note(span,
|
||||
macro_rules! span_stored_function {
|
||||
() => {
|
||||
err.span_note(span,
|
||||
&format!("use `({0}.{1})(...)` if you meant to call \
|
||||
the function stored in the `{1}` field",
|
||||
expr_string, item_name));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let span_did_you_mean = || {
|
||||
cx.sess.span_note(span, &format!("did you mean to write `{0}.{1}`?",
|
||||
macro_rules! span_did_you_mean {
|
||||
() => {
|
||||
err.span_note(span, &format!("did you mean to write `{0}.{1}`?",
|
||||
expr_string, item_name));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if the field can be used as a function in some way
|
||||
let field_ty = field.ty(cx, substs);
|
||||
@ -96,19 +101,22 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
match field_ty.sty {
|
||||
// Not all of these (e.g. unsafe fns) implement FnOnce
|
||||
// so we look for these beforehand
|
||||
ty::TyClosure(..) | ty::TyBareFn(..) => span_stored_function(),
|
||||
ty::TyClosure(..) | ty::TyBareFn(..) => {
|
||||
span_stored_function!();
|
||||
}
|
||||
// If it's not a simple function, look for things which implement FnOnce
|
||||
_ => {
|
||||
if let Ok(fn_once_trait_did) =
|
||||
cx.lang_items.require(FnOnceTraitLangItem) {
|
||||
let infcx = fcx.infcx();
|
||||
infcx.probe(|_| {
|
||||
let fn_once_substs = Substs::new_trait(vec![
|
||||
infcx.next_ty_var()],
|
||||
Vec::new(),
|
||||
field_ty);
|
||||
let trait_ref = ty::TraitRef::new(fn_once_trait_did,
|
||||
cx.mk_substs(fn_once_substs));
|
||||
let fn_once_substs =
|
||||
Substs::new_trait(vec![infcx.next_ty_var()],
|
||||
Vec::new(),
|
||||
field_ty);
|
||||
let trait_ref =
|
||||
ty::TraitRef::new(fn_once_trait_did,
|
||||
cx.mk_substs(fn_once_substs));
|
||||
let poly_trait_ref = trait_ref.to_poly_trait_ref();
|
||||
let obligation = Obligation::misc(span,
|
||||
fcx.body_id,
|
||||
@ -117,13 +125,13 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
let mut selcx = SelectionContext::new(infcx);
|
||||
|
||||
if selcx.evaluate_obligation(&obligation) {
|
||||
span_stored_function();
|
||||
span_stored_function!();
|
||||
} else {
|
||||
span_did_you_mean();
|
||||
span_did_you_mean!();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
span_did_you_mean()
|
||||
span_did_you_mean!();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -131,11 +139,11 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
if !static_sources.is_empty() {
|
||||
cx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
span,
|
||||
"found defined static methods, maybe a `self` is missing?");
|
||||
|
||||
report_candidates(fcx, span, item_name, static_sources);
|
||||
report_candidates(fcx, &mut err, span, item_name, static_sources);
|
||||
}
|
||||
|
||||
if !unsatisfied_predicates.is_empty() {
|
||||
@ -145,7 +153,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
p))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
cx.sess.fileline_note(
|
||||
err.fileline_note(
|
||||
span,
|
||||
&format!("the method `{}` exists but the \
|
||||
following trait bounds were not satisfied: {}",
|
||||
@ -153,15 +161,17 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
bound_list));
|
||||
}
|
||||
|
||||
suggest_traits_to_import(fcx, span, rcvr_ty, item_name,
|
||||
rcvr_expr, out_of_scope_traits)
|
||||
suggest_traits_to_import(fcx, &mut err, span, rcvr_ty, item_name,
|
||||
rcvr_expr, out_of_scope_traits);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
MethodError::Ambiguity(sources) => {
|
||||
span_err!(fcx.sess(), span, E0034,
|
||||
"multiple applicable items in scope");
|
||||
let mut err = struct_span_err!(fcx.sess(), span, E0034,
|
||||
"multiple applicable items in scope");
|
||||
|
||||
report_candidates(fcx, span, item_name, sources);
|
||||
report_candidates(fcx, &mut err, span, item_name, sources);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
MethodError::ClosureAmbiguity(trait_def_id) => {
|
||||
@ -181,6 +191,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
fn report_candidates(fcx: &FnCtxt,
|
||||
err: &mut DiagnosticBuilder,
|
||||
span: Span,
|
||||
item_name: ast::Name,
|
||||
mut sources: Vec<CandidateSource>) {
|
||||
@ -213,7 +224,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
};
|
||||
|
||||
span_note!(fcx.sess(), item_span,
|
||||
span_note!(err, item_span,
|
||||
"candidate #{} is defined in an impl{} for the type `{}`",
|
||||
idx + 1,
|
||||
insertion,
|
||||
@ -222,7 +233,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
CandidateSource::TraitSource(trait_did) => {
|
||||
let item = trait_item(fcx.tcx(), trait_did, item_name).unwrap();
|
||||
let item_span = fcx.tcx().map.def_id_span(item.def_id(), span);
|
||||
span_note!(fcx.sess(), item_span,
|
||||
span_note!(err, item_span,
|
||||
"candidate #{} is defined in the trait `{}`",
|
||||
idx + 1,
|
||||
fcx.tcx().item_path_str(trait_did));
|
||||
@ -236,6 +247,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
pub type AllTraitsVec = Vec<TraitInfo>;
|
||||
|
||||
fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
err: &mut DiagnosticBuilder,
|
||||
span: Span,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: ast::Name,
|
||||
@ -255,14 +267,13 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"},
|
||||
one_of_them = if candidates.len() == 1 {"it"} else {"one of them"});
|
||||
|
||||
fcx.sess().fileline_help(span, &msg[..]);
|
||||
err.fileline_help(span, &msg[..]);
|
||||
|
||||
for (i, trait_did) in candidates.iter().enumerate() {
|
||||
fcx.sess().fileline_help(span,
|
||||
&*format!("candidate #{}: use `{}`",
|
||||
i + 1,
|
||||
fcx.tcx().item_path_str(*trait_did)))
|
||||
|
||||
err.fileline_help(span,
|
||||
&*format!("candidate #{}: use `{}`",
|
||||
i + 1,
|
||||
fcx.tcx().item_path_str(*trait_did)));
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -301,13 +312,13 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
one_of_them = if candidates.len() == 1 {"it"} else {"one of them"},
|
||||
name = item_name);
|
||||
|
||||
fcx.sess().fileline_help(span, &msg[..]);
|
||||
err.fileline_help(span, &msg[..]);
|
||||
|
||||
for (i, trait_info) in candidates.iter().enumerate() {
|
||||
fcx.sess().fileline_help(span,
|
||||
&*format!("candidate #{}: `{}`",
|
||||
i + 1,
|
||||
fcx.tcx().item_path_str(trait_info.def_id)))
|
||||
err.fileline_help(span,
|
||||
&*format!("candidate #{}: `{}`",
|
||||
i + 1,
|
||||
fcx.tcx().item_path_str(trait_info.def_id)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +119,7 @@ use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::codemap::{self, Span, Spanned};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::parse::token::{self, InternedString};
|
||||
use syntax::ptr::P;
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
@ -702,11 +703,12 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
|
||||
for item in &m.items {
|
||||
let pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(item.id));
|
||||
if !pty.generics.types.is_empty() {
|
||||
span_err!(ccx.tcx.sess, item.span, E0044,
|
||||
let mut err = struct_span_err!(ccx.tcx.sess, item.span, E0044,
|
||||
"foreign items may not have type parameters");
|
||||
span_help!(ccx.tcx.sess, item.span,
|
||||
span_help!(&mut err, item.span,
|
||||
"consider using specialization instead of \
|
||||
type parameters");
|
||||
err.emit();
|
||||
}
|
||||
|
||||
if let hir::ForeignItemFn(ref fn_decl, _) = item.node {
|
||||
@ -1037,7 +1039,7 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
t_expr: Ty<'tcx>,
|
||||
id: ast::NodeId) {
|
||||
let tstr = fcx.infcx().ty_to_string(t_cast);
|
||||
fcx.type_error_message(span, |actual| {
|
||||
let mut err = fcx.type_error_struct(span, |actual| {
|
||||
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
|
||||
}, t_expr, None);
|
||||
match t_expr.sty {
|
||||
@ -1049,16 +1051,16 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
if t_cast.is_trait() {
|
||||
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
|
||||
Ok(s) => {
|
||||
fcx.tcx().sess.span_suggestion(t_span,
|
||||
"try casting to a reference instead:",
|
||||
format!("&{}{}", mtstr, s));
|
||||
err.span_suggestion(t_span,
|
||||
"try casting to a reference instead:",
|
||||
format!("&{}{}", mtstr, s));
|
||||
},
|
||||
Err(_) =>
|
||||
span_help!(fcx.tcx().sess, t_span,
|
||||
span_help!(err, t_span,
|
||||
"did you mean `&{}{}`?", mtstr, tstr),
|
||||
}
|
||||
} else {
|
||||
span_help!(fcx.tcx().sess, span,
|
||||
span_help!(err, span,
|
||||
"consider using an implicit coercion to `&{}{}` instead",
|
||||
mtstr, tstr);
|
||||
}
|
||||
@ -1066,19 +1068,20 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
ty::TyBox(..) => {
|
||||
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
|
||||
Ok(s) => {
|
||||
fcx.tcx().sess.span_suggestion(t_span,
|
||||
"try casting to a `Box` instead:",
|
||||
format!("Box<{}>", s));
|
||||
err.span_suggestion(t_span,
|
||||
"try casting to a `Box` instead:",
|
||||
format!("Box<{}>", s));
|
||||
},
|
||||
Err(_) =>
|
||||
span_help!(fcx.tcx().sess, t_span, "did you mean `Box<{}>`?", tstr),
|
||||
span_help!(err, t_span, "did you mean `Box<{}>`?", tstr),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
span_help!(fcx.tcx().sess, e_span,
|
||||
span_help!(err, e_span,
|
||||
"consider using a box or reference as appropriate");
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
fcx.write_error(id);
|
||||
}
|
||||
|
||||
@ -1443,10 +1446,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
Some((adt, variant))
|
||||
} else if var_kind == ty::VariantKind::Unit {
|
||||
if !self.tcx().sess.features.borrow().braced_empty_structs {
|
||||
self.tcx().sess.span_err(span, "empty structs and enum variants \
|
||||
with braces are unstable");
|
||||
fileline_help!(self.tcx().sess, span, "add #![feature(braced_empty_structs)] to \
|
||||
the crate features to enable");
|
||||
let mut err = self.tcx().sess.struct_span_err(span,
|
||||
"empty structs and enum variants \
|
||||
with braces are unstable");
|
||||
fileline_help!(&mut err, span, "add #![feature(braced_empty_structs)] to \
|
||||
the crate features to enable");
|
||||
err.emit();
|
||||
}
|
||||
|
||||
Some((adt, variant))
|
||||
@ -1614,12 +1619,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
actual_ty: Ty<'tcx>,
|
||||
err: Option<&TypeError<'tcx>>) where
|
||||
M: FnOnce(String) -> String,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
where M: FnOnce(String) -> String,
|
||||
{
|
||||
self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
|
||||
}
|
||||
|
||||
pub fn type_error_struct<M>(&self,
|
||||
sp: Span,
|
||||
mk_msg: M,
|
||||
actual_ty: Ty<'tcx>,
|
||||
err: Option<&TypeError<'tcx>>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
where M: FnOnce(String) -> String,
|
||||
{
|
||||
self.infcx().type_error_struct(sp, mk_msg, actual_ty, err)
|
||||
}
|
||||
|
||||
pub fn report_mismatched_types(&self,
|
||||
sp: Span,
|
||||
e: Ty<'tcx>,
|
||||
@ -2913,7 +2929,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
lvalue_pref: LvaluePreference,
|
||||
base: &'tcx hir::Expr,
|
||||
field: &Spanned<ast::Name>) {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
|
||||
let expr_t = structurally_resolved_type(fcx, expr.span,
|
||||
fcx.expr_ty(base));
|
||||
@ -2945,19 +2960,18 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
|
||||
fcx.type_error_message(
|
||||
field.span,
|
||||
|actual| {
|
||||
format!("attempted to take value of method `{}` on type \
|
||||
`{}`", field.node, actual)
|
||||
},
|
||||
expr_t, None);
|
||||
|
||||
tcx.sess.fileline_help(field.span,
|
||||
fcx.type_error_struct(field.span,
|
||||
|actual| {
|
||||
format!("attempted to take value of method `{}` on type \
|
||||
`{}`", field.node, actual)
|
||||
},
|
||||
expr_t, None)
|
||||
.fileline_help(field.span,
|
||||
"maybe a `()` to call it is missing? \
|
||||
If not, try an anonymous function");
|
||||
If not, try an anonymous function")
|
||||
.emit();
|
||||
} else {
|
||||
fcx.type_error_message(
|
||||
let mut err = fcx.type_error_struct(
|
||||
expr.span,
|
||||
|actual| {
|
||||
format!("attempted access of field `{}` on \
|
||||
@ -2968,17 +2982,18 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
},
|
||||
expr_t, None);
|
||||
if let ty::TyStruct(def, _) = expr_t.sty {
|
||||
suggest_field_names(def.struct_variant(), field, tcx, vec![]);
|
||||
suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fcx.write_error(expr.id);
|
||||
}
|
||||
|
||||
// displays hints about the closest matches in field names
|
||||
fn suggest_field_names<'tcx>(variant: ty::VariantDef<'tcx>,
|
||||
fn suggest_field_names<'tcx>(err: &mut DiagnosticBuilder,
|
||||
variant: ty::VariantDef<'tcx>,
|
||||
field: &Spanned<ast::Name>,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
skip : Vec<InternedString>) {
|
||||
let name = field.node.as_str();
|
||||
let names = variant.fields
|
||||
@ -2995,8 +3010,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
|
||||
// only find fits with at least one matching letter
|
||||
if let Some(name) = find_best_match_for_name(names, &name, Some(name.len())) {
|
||||
tcx.sess.span_help(field.span,
|
||||
&format!("did you mean `{}`?", name));
|
||||
err.span_help(field.span,
|
||||
&format!("did you mean `{}`?", name));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3071,7 +3086,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
variant: ty::VariantDef<'tcx>,
|
||||
field: &hir::Field,
|
||||
skip_fields: &[hir::Field]) {
|
||||
fcx.type_error_message(
|
||||
let mut err = fcx.type_error_struct(
|
||||
field.name.span,
|
||||
|actual| if let ty::TyEnum(..) = ty.sty {
|
||||
format!("struct variant `{}::{}` has no field named `{}`",
|
||||
@ -3084,7 +3099,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
None);
|
||||
// prevent all specified fields from being suggested
|
||||
let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str());
|
||||
suggest_field_names(variant, &field.name, fcx.tcx(), skip_fields.collect());
|
||||
suggest_field_names(&mut err, variant, &field.name, skip_fields.collect());
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn check_expr_struct_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
@ -4146,9 +4162,9 @@ pub fn check_representable(tcx: &ty::ctxt,
|
||||
// caught by case 1.
|
||||
match rty.is_representable(tcx, sp) {
|
||||
Representability::SelfRecursive => {
|
||||
span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation);
|
||||
tcx.sess.fileline_help(
|
||||
sp, "wrap the inner value in a box to make it representable");
|
||||
struct_span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation)
|
||||
.fileline_help(sp, "wrap the inner value in a box to make it representable")
|
||||
.emit();
|
||||
return false
|
||||
}
|
||||
Representability::Representable | Representability::ContainsRecursive => (),
|
||||
@ -4245,11 +4261,12 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
// Check for duplicate discriminant values
|
||||
match disr_vals.iter().position(|&x| x == current_disr_val) {
|
||||
Some(i) => {
|
||||
span_err!(ccx.tcx.sess, v.span, E0081,
|
||||
let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0081,
|
||||
"discriminant value `{}` already exists", disr_vals[i]);
|
||||
let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
|
||||
span_note!(ccx.tcx.sess, ccx.tcx.map.span(variant_i_node_id),
|
||||
"conflicting discriminant here")
|
||||
span_note!(&mut err, ccx.tcx.map.span(variant_i_node_id),
|
||||
"conflicting discriminant here");
|
||||
err.emit();
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
@ -4258,10 +4275,11 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
attr::ReprAny | attr::ReprExtern => (),
|
||||
attr::ReprInt(sp, ity) => {
|
||||
if !disr_in_range(ccx, ity, current_disr_val) {
|
||||
span_err!(ccx.tcx.sess, v.span, E0082,
|
||||
let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0082,
|
||||
"discriminant value outside specified type");
|
||||
span_note!(ccx.tcx.sess, sp,
|
||||
span_note!(&mut err, sp,
|
||||
"discriminant type specified here");
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
attr::ReprSimd => {
|
||||
|
@ -187,10 +187,10 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
hir_util::binop_to_string(op.node),
|
||||
lhs_ty);
|
||||
} else {
|
||||
span_err!(fcx.tcx().sess, lhs_expr.span, E0369,
|
||||
"binary operation `{}` cannot be applied to type `{}`",
|
||||
hir_util::binop_to_string(op.node),
|
||||
lhs_ty);
|
||||
let mut err = struct_span_err!(fcx.tcx().sess, lhs_expr.span, E0369,
|
||||
"binary operation `{}` cannot be applied to type `{}`",
|
||||
hir_util::binop_to_string(op.node),
|
||||
lhs_ty);
|
||||
let missing_trait = match op.node {
|
||||
hir::BiAdd => Some("std::ops::Add"),
|
||||
hir::BiSub => Some("std::ops::Sub"),
|
||||
@ -208,10 +208,11 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
};
|
||||
|
||||
if let Some(missing_trait) = missing_trait {
|
||||
span_note!(fcx.tcx().sess, lhs_expr.span,
|
||||
span_note!(&mut err, lhs_expr.span,
|
||||
"an implementation of `{}` might be missing for `{}`",
|
||||
missing_trait, lhs_ty);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
fcx.tcx().types.err
|
||||
|
@ -23,6 +23,7 @@ use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{Span};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::parse::token::{special_idents};
|
||||
use rustc_front::intravisit::{self, Visitor};
|
||||
use rustc_front::hir;
|
||||
@ -496,12 +497,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
||||
span: Span,
|
||||
param_name: ast::Name)
|
||||
{
|
||||
error_392(self.tcx(), span, param_name);
|
||||
let mut err = error_392(self.tcx(), span, param_name);
|
||||
|
||||
let suggested_marker_id = self.tcx().lang_items.phantom_data();
|
||||
match suggested_marker_id {
|
||||
Some(def_id) => {
|
||||
self.tcx().sess.fileline_help(
|
||||
err.fileline_help(
|
||||
span,
|
||||
&format!("consider removing `{}` or using a marker such as `{}`",
|
||||
param_name,
|
||||
@ -511,6 +512,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
||||
// no lang items, no help!
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -621,9 +623,10 @@ pub fn error_380<'ccx,'tcx>(ccx: &'ccx CrateCtxt<'ccx, 'tcx>, span: Span) {
|
||||
Trait for ..`) must have no methods or associated items")
|
||||
}
|
||||
|
||||
pub fn error_392<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, param_name: ast::Name) {
|
||||
span_err!(tcx.sess, span, E0392,
|
||||
"parameter `{}` is never used", param_name);
|
||||
pub fn error_392<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, param_name: ast::Name)
|
||||
-> DiagnosticBuilder<'tcx> {
|
||||
struct_span_err!(tcx.sess, span, E0392,
|
||||
"parameter `{}` is never used", param_name)
|
||||
}
|
||||
|
||||
pub fn error_194<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, name: ast::Name) {
|
||||
|
@ -129,13 +129,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||
!self.fcx.expr_ty(lhs).references_error() &&
|
||||
!self.fcx.expr_ty(rhs).references_error()
|
||||
{
|
||||
tcx.sess.span_err(
|
||||
e.span,
|
||||
"overloaded augmented assignments are not stable");
|
||||
fileline_help!(
|
||||
tcx.sess, e.span,
|
||||
"add #![feature(augmented_assignments)] to the crate root \
|
||||
to enable");
|
||||
tcx.sess.struct_span_err(e.span,
|
||||
"overloaded augmented assignments \
|
||||
are not stable")
|
||||
.fileline_help(e.span,
|
||||
"add #![feature(augmented_assignments)] to the \
|
||||
crate root to enable")
|
||||
.emit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -502,9 +502,14 @@ fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id:
|
||||
} else {
|
||||
return // everything OK
|
||||
};
|
||||
span_err!(tcx.sess, sp, E0183, "manual implementations of `{}` are experimental", trait_name);
|
||||
fileline_help!(tcx.sess, sp,
|
||||
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
|
||||
let mut err = struct_span_err!(tcx.sess,
|
||||
sp,
|
||||
E0183,
|
||||
"manual implementations of `{}` are experimental",
|
||||
trait_name);
|
||||
fileline_help!(&mut err, sp,
|
||||
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
|
||||
err.emit();
|
||||
}
|
||||
|
||||
pub fn check_coherence(crate_context: &CrateCtxt) {
|
||||
|
@ -48,11 +48,11 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
match lang_def_id {
|
||||
Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ },
|
||||
_ => {
|
||||
span_err!(self.tcx.sess, span, E0390,
|
||||
struct_span_err!(self.tcx.sess, span, E0390,
|
||||
"only a single inherent implementation marked with `#[lang = \"{}\"]` \
|
||||
is allowed for the `{}` primitive", lang, ty);
|
||||
span_help!(self.tcx.sess, span,
|
||||
"consider using a trait to implement these methods");
|
||||
is allowed for the `{}` primitive", lang, ty)
|
||||
.span_help(span, "consider using a trait to implement these methods")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,18 +150,19 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||
}).unwrap_or(String::new())
|
||||
};
|
||||
|
||||
span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119,
|
||||
"conflicting implementations of trait `{}`{}:",
|
||||
trait_ref,
|
||||
self_type);
|
||||
let mut err = struct_span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119,
|
||||
"conflicting implementations of trait `{}`{}:",
|
||||
trait_ref,
|
||||
self_type);
|
||||
|
||||
if impl2.is_local() {
|
||||
span_note!(self.tcx.sess, self.span_of_impl(impl2),
|
||||
span_note!(&mut err, self.span_of_impl(impl2),
|
||||
"conflicting implementation is here:");
|
||||
} else {
|
||||
let cname = self.tcx.sess.cstore.crate_name(impl2.krate);
|
||||
self.tcx.sess.note(&format!("conflicting implementation in crate `{}`", cname));
|
||||
err.note(&format!("conflicting implementation in crate `{}`", cname));
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn span_of_impl(&self, impl_did: DefId) -> Span {
|
||||
|
@ -225,24 +225,24 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
|
||||
assert!(!cycle.is_empty());
|
||||
let tcx = self.tcx;
|
||||
|
||||
span_err!(tcx.sess, span, E0391,
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0391,
|
||||
"unsupported cyclic reference between types/traits detected");
|
||||
|
||||
match cycle[0] {
|
||||
AstConvRequest::GetItemTypeScheme(def_id) |
|
||||
AstConvRequest::GetTraitDef(def_id) => {
|
||||
tcx.sess.note(
|
||||
err.note(
|
||||
&format!("the cycle begins when processing `{}`...",
|
||||
tcx.item_path_str(def_id)));
|
||||
}
|
||||
AstConvRequest::EnsureSuperPredicates(def_id) => {
|
||||
tcx.sess.note(
|
||||
err.note(
|
||||
&format!("the cycle begins when computing the supertraits of `{}`...",
|
||||
tcx.item_path_str(def_id)));
|
||||
}
|
||||
AstConvRequest::GetTypeParameterBounds(id) => {
|
||||
let def = tcx.type_parameter_def(id);
|
||||
tcx.sess.note(
|
||||
err.note(
|
||||
&format!("the cycle begins when computing the bounds \
|
||||
for type parameter `{}`...",
|
||||
def.name));
|
||||
@ -253,18 +253,18 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
|
||||
match *request {
|
||||
AstConvRequest::GetItemTypeScheme(def_id) |
|
||||
AstConvRequest::GetTraitDef(def_id) => {
|
||||
tcx.sess.note(
|
||||
err.note(
|
||||
&format!("...which then requires processing `{}`...",
|
||||
tcx.item_path_str(def_id)));
|
||||
}
|
||||
AstConvRequest::EnsureSuperPredicates(def_id) => {
|
||||
tcx.sess.note(
|
||||
err.note(
|
||||
&format!("...which then requires computing the supertraits of `{}`...",
|
||||
tcx.item_path_str(def_id)));
|
||||
}
|
||||
AstConvRequest::GetTypeParameterBounds(id) => {
|
||||
let def = tcx.type_parameter_def(id);
|
||||
tcx.sess.note(
|
||||
err.note(
|
||||
&format!("...which then requires computing the bounds \
|
||||
for type parameter `{}`...",
|
||||
def.name));
|
||||
@ -275,24 +275,25 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
|
||||
match cycle[0] {
|
||||
AstConvRequest::GetItemTypeScheme(def_id) |
|
||||
AstConvRequest::GetTraitDef(def_id) => {
|
||||
tcx.sess.note(
|
||||
err.note(
|
||||
&format!("...which then again requires processing `{}`, completing the cycle.",
|
||||
tcx.item_path_str(def_id)));
|
||||
}
|
||||
AstConvRequest::EnsureSuperPredicates(def_id) => {
|
||||
tcx.sess.note(
|
||||
err.note(
|
||||
&format!("...which then again requires computing the supertraits of `{}`, \
|
||||
completing the cycle.",
|
||||
tcx.item_path_str(def_id)));
|
||||
}
|
||||
AstConvRequest::GetTypeParameterBounds(id) => {
|
||||
let def = tcx.type_parameter_def(id);
|
||||
tcx.sess.note(
|
||||
err.note(
|
||||
&format!("...which then again requires computing the bounds \
|
||||
for type parameter `{}`, completing the cycle.",
|
||||
def.name));
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
/// Loads the trait def for a given trait, returning ErrorReported if a cycle arises.
|
||||
@ -1012,10 +1013,11 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
hir::NamedField(name, vis) => {
|
||||
let dup_span = seen_fields.get(&name).cloned();
|
||||
if let Some(prev_span) = dup_span {
|
||||
span_err!(tcx.sess, f.span, E0124,
|
||||
"field `{}` is already declared",
|
||||
name);
|
||||
span_note!(tcx.sess, prev_span, "previously declared here");
|
||||
let mut err = struct_span_err!(tcx.sess, f.span, E0124,
|
||||
"field `{}` is already declared",
|
||||
name);
|
||||
span_note!(&mut err, prev_span, "previously declared here");
|
||||
err.emit();
|
||||
} else {
|
||||
seen_fields.insert(name, f.span);
|
||||
}
|
||||
@ -1080,12 +1082,13 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
None
|
||||
},
|
||||
Err(err) => {
|
||||
span_err!(tcx.sess, err.span, E0080,
|
||||
"constant evaluation error: {}",
|
||||
err.description());
|
||||
let mut diag = struct_span_err!(tcx.sess, err.span, E0080,
|
||||
"constant evaluation error: {}",
|
||||
err.description());
|
||||
if !e.span.contains(err.span) {
|
||||
tcx.sess.span_note(e.span, "for enum discriminant here");
|
||||
diag.span_note(e.span, "for enum discriminant here");
|
||||
}
|
||||
diag.emit();
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -1254,13 +1257,14 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
|
||||
let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar");
|
||||
if paren_sugar && !ccx.tcx.sess.features.borrow().unboxed_closures {
|
||||
ccx.tcx.sess.span_err(
|
||||
let mut err = ccx.tcx.sess.struct_span_err(
|
||||
it.span,
|
||||
"the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
|
||||
which traits can use parenthetical notation");
|
||||
fileline_help!(ccx.tcx.sess, it.span,
|
||||
fileline_help!(&mut err, it.span,
|
||||
"add `#![feature(unboxed_closures)]` to \
|
||||
the crate attributes to use it");
|
||||
err.emit();
|
||||
}
|
||||
|
||||
let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, generics));
|
||||
|
@ -203,8 +203,9 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
|
||||
match result {
|
||||
Ok(_) => true,
|
||||
Err(ref terr) => {
|
||||
span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
|
||||
tcx.note_and_explain_type_err(terr, span);
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
|
||||
tcx.note_and_explain_type_err(&mut err, terr, span);
|
||||
err.emit();
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -305,8 +305,10 @@ pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option<Inte
|
||||
if let s@Some(_) = attr.value_str() {
|
||||
s
|
||||
} else {
|
||||
diag.span_err(attr.span, "export_name attribute has invalid format");
|
||||
diag.help("use #[export_name=\"*\"]");
|
||||
diag.struct_span_err(attr.span,
|
||||
"export_name attribute has invalid format")
|
||||
.help("use #[export_name=\"*\"]")
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
} else {
|
||||
|
@ -30,6 +30,14 @@ macro_rules! span_err {
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! span_warn {
|
||||
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
|
||||
__diagnostic_used!($code);
|
||||
$session.span_warn_with_code($span, &format!($($message)*), stringify!($code))
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! span_err_or_warn {
|
||||
($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
|
||||
@ -43,31 +51,59 @@ macro_rules! span_err_or_warn {
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! span_warn {
|
||||
macro_rules! struct_span_fatal {
|
||||
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
|
||||
__diagnostic_used!($code);
|
||||
$session.span_warn_with_code($span, &format!($($message)*), stringify!($code))
|
||||
$session.struct_span_fatal_with_code($span, &format!($($message)*), stringify!($code))
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! struct_span_err {
|
||||
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
|
||||
__diagnostic_used!($code);
|
||||
$session.struct_span_err_with_code($span, &format!($($message)*), stringify!($code))
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! struct_span_warn {
|
||||
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
|
||||
__diagnostic_used!($code);
|
||||
$session.struct_span_warn_with_code($span, &format!($($message)*), stringify!($code))
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! struct_span_err_or_warn {
|
||||
($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
|
||||
__diagnostic_used!($code);
|
||||
if $is_warning {
|
||||
$session.struct_span_warn_with_code($span, &format!($($message)*), stringify!($code))
|
||||
} else {
|
||||
$session.struct_span_err_with_code($span, &format!($($message)*), stringify!($code))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! span_note {
|
||||
($session:expr, $span:expr, $($message:tt)*) => ({
|
||||
($session).span_note($span, &format!($($message)*))
|
||||
($err:expr, $span:expr, $($message:tt)*) => ({
|
||||
($err).span_note($span, &format!($($message)*));
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! span_help {
|
||||
($session:expr, $span:expr, $($message:tt)*) => ({
|
||||
($session).span_help($span, &format!($($message)*))
|
||||
($err:expr, $span:expr, $($message:tt)*) => ({
|
||||
($err).span_help($span, &format!($($message)*));
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! fileline_help {
|
||||
($session:expr, $span:expr, $($message:tt)*) => ({
|
||||
($session).fileline_help($span, &format!($($message)*))
|
||||
($err:expr, $span:expr, $($message:tt)*) => ({
|
||||
($err).fileline_help($span, &format!($($message)*));
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -62,10 +62,10 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt,
|
||||
match diagnostics.get_mut(&code.name) {
|
||||
// Previously used errors.
|
||||
Some(&mut ErrorInfo { description: _, use_site: Some(previous_span) }) => {
|
||||
ecx.span_warn(span, &format!(
|
||||
ecx.struct_span_warn(span, &format!(
|
||||
"diagnostic code {} already used", code
|
||||
));
|
||||
ecx.span_note(previous_span, "previous invocation");
|
||||
)).span_note(previous_span, "previous invocation")
|
||||
.emit();
|
||||
}
|
||||
// Newly used errors.
|
||||
Some(ref mut info) => {
|
||||
|
@ -13,7 +13,7 @@ use self::Destination::*;
|
||||
use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span};
|
||||
use diagnostics;
|
||||
|
||||
use errors::{Level, RenderSpan};
|
||||
use errors::{Level, RenderSpan, DiagnosticBuilder};
|
||||
use errors::RenderSpan::*;
|
||||
use errors::Level::*;
|
||||
|
||||
@ -27,6 +27,17 @@ use term;
|
||||
pub trait Emitter {
|
||||
fn emit(&mut self, span: Option<Span>, msg: &str, code: Option<&str>, lvl: Level);
|
||||
fn custom_emit(&mut self, sp: RenderSpan, msg: &str, lvl: Level);
|
||||
|
||||
/// Emit a structured diagnostic.
|
||||
fn emit_struct(&mut self, db: &DiagnosticBuilder) {
|
||||
self.emit(db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level);
|
||||
for child in &db.children {
|
||||
match child.render_span {
|
||||
Some(ref sp) => self.custom_emit(sp.clone(), &child.message, child.level),
|
||||
None => self.emit(child.span, &child.message, None, child.level),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// maximum number of lines we will print for each error; arbitrary.
|
||||
@ -49,8 +60,8 @@ impl ColorConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// A basic emitter for when we don't have access to a codemap or registry. Used
|
||||
// for reporting very early errors, etc.
|
||||
/// A basic emitter for when we don't have access to a codemap or registry. Used
|
||||
/// for reporting very early errors, etc.
|
||||
pub struct BasicEmitter {
|
||||
dst: Destination,
|
||||
}
|
||||
@ -111,9 +122,8 @@ impl Emitter for EmitterWriter {
|
||||
sp: RenderSpan,
|
||||
msg: &str,
|
||||
lvl: Level) {
|
||||
match self.emit_(sp, msg, None, lvl) {
|
||||
Ok(()) => {}
|
||||
Err(e) => panic!("failed to print diagnostics: {:?}", e),
|
||||
if let Err(e) = self.emit_(sp, msg, None, lvl) {
|
||||
panic!("failed to print diagnostics: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,171 @@ impl error::Error for ExplicitBug {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used for emitting structured error messages and other diagnostic information.
|
||||
#[must_use]
|
||||
pub struct DiagnosticBuilder<'a> {
|
||||
emitter: &'a RefCell<Box<Emitter>>,
|
||||
level: Level,
|
||||
message: String,
|
||||
code: Option<String>,
|
||||
span: Option<Span>,
|
||||
children: Vec<SubDiagnostic>,
|
||||
}
|
||||
|
||||
/// For example a note attached to an error.
|
||||
struct SubDiagnostic {
|
||||
level: Level,
|
||||
message: String,
|
||||
span: Option<Span>,
|
||||
render_span: Option<RenderSpan>,
|
||||
}
|
||||
|
||||
impl<'a> DiagnosticBuilder<'a> {
|
||||
/// Emit the diagnostic.
|
||||
pub fn emit(&mut self) {
|
||||
if self.cancelled() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.emitter.borrow_mut().emit_struct(&self);
|
||||
self.cancel();
|
||||
|
||||
// if self.is_fatal() {
|
||||
// panic!(FatalError);
|
||||
// }
|
||||
}
|
||||
|
||||
/// Cancel the diagnostic (a structured diagnostic must either be emitted or
|
||||
/// 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) {
|
||||
self.level = Level::Cancelled;
|
||||
}
|
||||
|
||||
pub fn cancelled(&self) -> bool {
|
||||
self.level == Level::Cancelled
|
||||
}
|
||||
|
||||
pub fn is_fatal(&self) -> bool {
|
||||
self.level == Level::Fatal
|
||||
}
|
||||
|
||||
pub fn note(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Note, msg, None, None);
|
||||
self
|
||||
}
|
||||
pub fn span_note(&mut self ,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Note, msg, Some(sp), None);
|
||||
self
|
||||
}
|
||||
pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Help, msg, None, None);
|
||||
self
|
||||
}
|
||||
pub fn span_help(&mut self ,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Help, msg, Some(sp), None);
|
||||
self
|
||||
}
|
||||
/// Prints out a message with a suggested edit of the code.
|
||||
///
|
||||
/// See `diagnostic::RenderSpan::Suggestion` for more information.
|
||||
pub fn span_suggestion(&mut self ,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestion: String)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Help, msg, Some(sp), Some(Suggestion(sp, suggestion)));
|
||||
self
|
||||
}
|
||||
pub fn span_end_note(&mut self ,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Note, msg, Some(sp), Some(EndSpan(sp)));
|
||||
self
|
||||
}
|
||||
pub fn fileline_note(&mut self ,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Note, msg, Some(sp), Some(FileLine(sp)));
|
||||
self
|
||||
}
|
||||
pub fn fileline_help(&mut self ,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Help, msg, Some(sp), Some(FileLine(sp)));
|
||||
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
|
||||
/// struct_* methods on Handler.
|
||||
fn new(emitter: &'a RefCell<Box<Emitter>>,
|
||||
level: Level,
|
||||
message: &str) -> DiagnosticBuilder<'a> {
|
||||
DiagnosticBuilder {
|
||||
emitter: emitter,
|
||||
level: level,
|
||||
message: message.to_owned(),
|
||||
code: None,
|
||||
span: None,
|
||||
children: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// public methods above.
|
||||
fn sub(&mut self,
|
||||
level: Level,
|
||||
message: &str,
|
||||
span: Option<Span>,
|
||||
render_span: Option<RenderSpan>) {
|
||||
let sub = SubDiagnostic {
|
||||
level: level,
|
||||
message: message.to_owned(),
|
||||
span: span,
|
||||
render_span: render_span,
|
||||
};
|
||||
self.children.push(sub);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.message.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or
|
||||
/// we emit a bug.
|
||||
impl<'a> Drop for DiagnosticBuilder<'a> {
|
||||
fn drop(&mut self) {
|
||||
if !self.cancelled() {
|
||||
self.emitter.borrow_mut().emit(None, "Error constructed but not emitted", None, Bug);
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A handler deals with errors; certain errors
|
||||
/// (fatal, bug, unimpl) may cause immediate exit,
|
||||
/// others log errors for later reporting.
|
||||
@ -132,11 +297,104 @@ 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,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
|
||||
result.span(sp);
|
||||
if !self.can_emit_warnings {
|
||||
result.cancel();
|
||||
}
|
||||
result
|
||||
}
|
||||
pub fn struct_span_warn_with_code<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
|
||||
result.span(sp);
|
||||
result.code(code.to_owned());
|
||||
if !self.can_emit_warnings {
|
||||
result.cancel();
|
||||
}
|
||||
result
|
||||
}
|
||||
pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
|
||||
if !self.can_emit_warnings {
|
||||
result.cancel();
|
||||
}
|
||||
result
|
||||
}
|
||||
pub fn struct_span_err<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
|
||||
result.span(sp);
|
||||
result
|
||||
}
|
||||
pub fn struct_span_err_with_code<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
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> {
|
||||
self.bump_err_count();
|
||||
DiagnosticBuilder::new(&self.emit, Level::Error, msg)
|
||||
}
|
||||
pub fn struct_span_fatal<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
|
||||
result.span(sp);
|
||||
result
|
||||
}
|
||||
pub fn struct_span_fatal_with_code<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
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> {
|
||||
self.bump_err_count();
|
||||
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 {
|
||||
if self.treat_err_as_bug {
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
self.emit(Some(sp), msg, Fatal);
|
||||
self.bump_err_count();
|
||||
return FatalError;
|
||||
}
|
||||
pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError {
|
||||
@ -144,6 +402,7 @@ impl Handler {
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
self.emit_with_code(Some(sp), msg, code, Fatal);
|
||||
self.bump_err_count();
|
||||
return FatalError;
|
||||
}
|
||||
pub fn span_err(&self, sp: Span, msg: &str) {
|
||||
@ -166,27 +425,6 @@ impl Handler {
|
||||
pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) {
|
||||
self.emit_with_code(Some(sp), msg, code, Warning);
|
||||
}
|
||||
pub fn span_note(&self, sp: Span, msg: &str) {
|
||||
self.emit(Some(sp), msg, Note);
|
||||
}
|
||||
pub fn span_end_note(&self, sp: Span, msg: &str) {
|
||||
self.custom_emit(EndSpan(sp), msg, Note);
|
||||
}
|
||||
pub fn span_help(&self, sp: Span, msg: &str) {
|
||||
self.emit(Some(sp), msg, Help);
|
||||
}
|
||||
/// Prints out a message with a suggested edit of the code.
|
||||
///
|
||||
/// See `diagnostic::RenderSpan::Suggestion` for more information.
|
||||
pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) {
|
||||
self.custom_emit(Suggestion(sp, suggestion), msg, Help);
|
||||
}
|
||||
pub fn fileline_note(&self, sp: Span, msg: &str) {
|
||||
self.custom_emit(FileLine(sp), msg, Note);
|
||||
}
|
||||
pub fn fileline_help(&self, sp: Span, msg: &str) {
|
||||
self.custom_emit(FileLine(sp), msg, Help);
|
||||
}
|
||||
pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
|
||||
self.emit(Some(sp), msg, Bug);
|
||||
panic!(ExplicitBug);
|
||||
@ -199,6 +437,9 @@ impl Handler {
|
||||
self.emit(Some(sp), msg, Bug);
|
||||
self.bump_err_count();
|
||||
}
|
||||
pub fn span_note_without_error(&self, sp: Span, msg: &str) {
|
||||
self.emit.borrow_mut().emit(Some(sp), msg, None, Note);
|
||||
}
|
||||
pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
|
||||
self.span_bug(sp, &format!("unimplemented {}", msg));
|
||||
}
|
||||
@ -207,6 +448,7 @@ impl Handler {
|
||||
self.bug(msg);
|
||||
}
|
||||
self.emit.borrow_mut().emit(None, msg, None, Fatal);
|
||||
self.bump_err_count();
|
||||
FatalError
|
||||
}
|
||||
pub fn err(&self, msg: &str) {
|
||||
@ -219,12 +461,9 @@ impl Handler {
|
||||
pub fn warn(&self, msg: &str) {
|
||||
self.emit.borrow_mut().emit(None, msg, None, Warning);
|
||||
}
|
||||
pub fn note(&self, msg: &str) {
|
||||
pub fn note_without_error(&self, msg: &str) {
|
||||
self.emit.borrow_mut().emit(None, msg, None, Note);
|
||||
}
|
||||
pub fn help(&self, msg: &str) {
|
||||
self.emit.borrow_mut().emit(None, msg, None, Help);
|
||||
}
|
||||
pub fn bug(&self, msg: &str) -> ! {
|
||||
self.emit.borrow_mut().emit(None, msg, None, Bug);
|
||||
panic!(ExplicitBug);
|
||||
@ -266,7 +505,7 @@ impl Handler {
|
||||
}
|
||||
}
|
||||
|
||||
panic!(self.fatal(&s[..]));
|
||||
panic!(self.fatal(&s));
|
||||
}
|
||||
|
||||
pub fn emit(&self,
|
||||
@ -301,6 +540,7 @@ pub enum Level {
|
||||
Warning,
|
||||
Note,
|
||||
Help,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
impl fmt::Display for Level {
|
||||
@ -313,6 +553,7 @@ impl fmt::Display for Level {
|
||||
Warning => "warning".fmt(f),
|
||||
Note => "note".fmt(f),
|
||||
Help => "help".fmt(f),
|
||||
Cancelled => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -324,6 +565,7 @@ impl Level {
|
||||
Warning => term::color::BRIGHT_YELLOW,
|
||||
Note => term::color::BRIGHT_GREEN,
|
||||
Help => term::color::BRIGHT_CYAN,
|
||||
Cancelled => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use ast;
|
||||
use ast::Name;
|
||||
use codemap;
|
||||
use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
|
||||
use errors::DiagnosticBuilder;
|
||||
use ext;
|
||||
use ext::expand;
|
||||
use ext::tt::macro_rules;
|
||||
@ -678,6 +679,25 @@ impl<'a> ExtCtxt<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn struct_span_warn(&self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.parse_sess.span_diagnostic.struct_span_warn(sp, msg)
|
||||
}
|
||||
pub fn struct_span_err(&self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.parse_sess.span_diagnostic.struct_span_err(sp, msg)
|
||||
}
|
||||
pub fn struct_span_fatal(&self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.parse_sess.span_diagnostic.struct_span_fatal(sp, msg)
|
||||
}
|
||||
|
||||
/// Emit `msg` attached to `sp`, and stop compilation immediately.
|
||||
///
|
||||
/// `span_err` should be strongly preferred where-ever possible:
|
||||
@ -710,15 +730,6 @@ impl<'a> ExtCtxt<'a> {
|
||||
pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
|
||||
self.parse_sess.span_diagnostic.span_bug(sp, msg);
|
||||
}
|
||||
pub fn span_note(&self, sp: Span, msg: &str) {
|
||||
self.parse_sess.span_diagnostic.span_note(sp, msg);
|
||||
}
|
||||
pub fn span_help(&self, sp: Span, msg: &str) {
|
||||
self.parse_sess.span_diagnostic.span_help(sp, msg);
|
||||
}
|
||||
pub fn fileline_help(&self, sp: Span, msg: &str) {
|
||||
self.parse_sess.span_diagnostic.fileline_help(sp, msg);
|
||||
}
|
||||
pub fn bug(&self, msg: &str) -> ! {
|
||||
self.parse_sess.span_diagnostic.bug(msg);
|
||||
}
|
||||
@ -743,10 +754,13 @@ impl<'a> ExtCtxt<'a> {
|
||||
token::intern(st)
|
||||
}
|
||||
|
||||
pub fn suggest_macro_name(&mut self, name: &str, span: Span) {
|
||||
pub fn suggest_macro_name(&mut self,
|
||||
name: &str,
|
||||
span: Span,
|
||||
err: &mut DiagnosticBuilder<'a>) {
|
||||
let names = &self.syntax_env.names;
|
||||
if let Some(suggestion) = find_best_match_for_name(names.iter(), name, None) {
|
||||
self.fileline_help(span, &format!("did you mean `{}!`?", suggestion));
|
||||
err.fileline_help(span, &format!("did you mean `{}!`?", suggestion));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -201,11 +201,12 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
|
||||
let extname = pth.segments[0].identifier.name;
|
||||
match fld.cx.syntax_env.find(extname) {
|
||||
None => {
|
||||
fld.cx.span_err(
|
||||
let mut err = fld.cx.struct_span_err(
|
||||
pth.span,
|
||||
&format!("macro undefined: '{}!'",
|
||||
&extname));
|
||||
fld.cx.suggest_macro_name(&extname.as_str(), pth.span);
|
||||
fld.cx.suggest_macro_name(&extname.as_str(), pth.span, &mut err);
|
||||
err.emit();
|
||||
|
||||
// let compilation continue
|
||||
None
|
||||
@ -334,11 +335,15 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool
|
||||
for attr in attrs {
|
||||
let mut is_use = attr.check_name("macro_use");
|
||||
if attr.check_name("macro_escape") {
|
||||
fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use");
|
||||
let mut err =
|
||||
fld.cx.struct_span_warn(attr.span,
|
||||
"macro_escape is a deprecated synonym for macro_use");
|
||||
is_use = true;
|
||||
if let ast::AttrStyle::Inner = attr.node.style {
|
||||
fld.cx.fileline_help(attr.span, "consider an outer attribute, \
|
||||
#[macro_use] mod ...");
|
||||
err.fileline_help(attr.span, "consider an outer attribute, \
|
||||
#[macro_use] mod ...").emit();
|
||||
} else {
|
||||
err.emit();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -802,7 +802,7 @@ fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[TokenTree])
|
||||
|
||||
let cx_expr = panictry!(p.parse_expr());
|
||||
if !panictry!(p.eat(&token::Comma)) {
|
||||
panic!(p.fatal("expected token `,`"));
|
||||
let _ = p.diagnostic().fatal("expected token `,`");
|
||||
}
|
||||
|
||||
let tts = panictry!(p.parse_all_token_trees());
|
||||
|
@ -117,11 +117,9 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree
|
||||
while self.p.token != token::Eof {
|
||||
match panictry!(self.p.parse_item()) {
|
||||
Some(item) => ret.push(item),
|
||||
None => panic!(self.p.span_fatal(
|
||||
self.p.span,
|
||||
&format!("expected item, found `{}`",
|
||||
self.p.this_token_to_string())
|
||||
))
|
||||
None => panic!(self.p.diagnostic().span_fatal(self.p.span,
|
||||
&format!("expected item, found `{}`",
|
||||
self.p.this_token_to_string())))
|
||||
}
|
||||
}
|
||||
Some(ret)
|
||||
|
@ -82,6 +82,7 @@ use ast;
|
||||
use ast::{TokenTree, Name, Ident};
|
||||
use codemap::{BytePos, mk_sp, Span, Spanned};
|
||||
use codemap;
|
||||
use errors::FatalError;
|
||||
use parse::lexer::*; //resolve bug?
|
||||
use parse::ParseSess;
|
||||
use parse::parser::{LifetimeAndTypesWithoutColons, Parser};
|
||||
@ -499,11 +500,12 @@ pub fn parse(sess: &ParseSess,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal {
|
||||
pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
|
||||
match name {
|
||||
"tt" => {
|
||||
p.quote_depth += 1; //but in theory, non-quoted tts might be useful
|
||||
let res = token::NtTT(P(panictry!(p.parse_token_tree())));
|
||||
let res: ::parse::PResult<'a, _> = p.parse_token_tree();
|
||||
let res = token::NtTT(P(panictry!(res)));
|
||||
p.quote_depth -= 1;
|
||||
return res;
|
||||
}
|
||||
@ -514,12 +516,18 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal {
|
||||
match name {
|
||||
"item" => match panictry!(p.parse_item()) {
|
||||
Some(i) => token::NtItem(i),
|
||||
None => panic!(p.fatal("expected an item keyword"))
|
||||
None => {
|
||||
p.fatal("expected an item keyword").emit();
|
||||
panic!(FatalError);
|
||||
}
|
||||
},
|
||||
"block" => token::NtBlock(panictry!(p.parse_block())),
|
||||
"stmt" => match panictry!(p.parse_stmt()) {
|
||||
Some(s) => token::NtStmt(s),
|
||||
None => panic!(p.fatal("expected a statement"))
|
||||
None => {
|
||||
p.fatal("expected a statement").emit();
|
||||
panic!(FatalError);
|
||||
}
|
||||
},
|
||||
"pat" => token::NtPat(panictry!(p.parse_pat())),
|
||||
"expr" => token::NtExpr(panictry!(p.parse_expr())),
|
||||
@ -532,8 +540,9 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal {
|
||||
}
|
||||
_ => {
|
||||
let token_str = pprust::token_to_string(&p.token);
|
||||
panic!(p.fatal(&format!("expected ident, found {}",
|
||||
&token_str[..])))
|
||||
p.fatal(&format!("expected ident, found {}",
|
||||
&token_str[..])).emit();
|
||||
panic!(FatalError)
|
||||
}
|
||||
},
|
||||
"path" => {
|
||||
@ -541,11 +550,12 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal {
|
||||
},
|
||||
"meta" => token::NtMeta(panictry!(p.parse_meta_item())),
|
||||
_ => {
|
||||
panic!(p.span_fatal_help(sp,
|
||||
&format!("invalid fragment specifier `{}`", name),
|
||||
"valid fragment specifiers are `ident`, `block`, \
|
||||
`stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
|
||||
and `item`"))
|
||||
p.span_fatal_help(sp,
|
||||
&format!("invalid fragment specifier `{}`", name),
|
||||
"valid fragment specifiers are `ident`, `block`, \
|
||||
`stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
|
||||
and `item`").emit();
|
||||
panic!(FatalError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,12 +55,12 @@ impl<'a> ParserAnyMacro<'a> {
|
||||
following",
|
||||
token_str);
|
||||
let span = parser.span;
|
||||
parser.span_err(span, &msg[..]);
|
||||
|
||||
let mut err = parser.diagnostic().struct_span_err(span, &msg[..]);
|
||||
let msg = format!("caused by the macro expansion here; the usage \
|
||||
of `{}!` is likely invalid in {} context",
|
||||
self.macro_ident, context);
|
||||
parser.span_note(self.site_span, &msg[..]);
|
||||
err.span_note(self.site_span, &msg[..])
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,7 +111,10 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
|
||||
Some(stmt) => ret.push(stmt),
|
||||
None => (),
|
||||
},
|
||||
Err(_) => break,
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -725,17 +725,21 @@ pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIs
|
||||
GateIssue::Library(lib) => lib,
|
||||
};
|
||||
|
||||
if let Some(n) = issue {
|
||||
diag.span_err(span, &format!("{} (see issue #{})", explain, n));
|
||||
let mut err = if let Some(n) = issue {
|
||||
diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
|
||||
} else {
|
||||
diag.span_err(span, explain);
|
||||
}
|
||||
diag.struct_span_err(span, explain)
|
||||
};
|
||||
|
||||
// #23973: do not suggest `#![feature(...)]` if we are in beta/stable
|
||||
if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; }
|
||||
diag.fileline_help(span, &format!("add #![feature({})] to the \
|
||||
crate attributes to enable",
|
||||
feature));
|
||||
if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
|
||||
err.emit();
|
||||
return;
|
||||
}
|
||||
err.fileline_help(span, &format!("add #![feature({})] to the \
|
||||
crate attributes to enable",
|
||||
feature));
|
||||
err.emit();
|
||||
}
|
||||
|
||||
pub const EXPLAIN_ASM: &'static str =
|
||||
@ -942,11 +946,13 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
|
||||
self.gate_feature("braced_empty_structs", span,
|
||||
"empty structs and enum variants with braces are unstable");
|
||||
} else if s.is_tuple() {
|
||||
self.context.span_handler.span_err(span, "empty tuple structs and enum variants \
|
||||
are not allowed, use unit structs and \
|
||||
enum variants instead");
|
||||
self.context.span_handler.span_help(span, "remove trailing `()` to make a unit \
|
||||
struct or unit enum variant");
|
||||
self.context.span_handler.struct_span_err(span, "empty tuple structs and enum \
|
||||
variants are not allowed, use \
|
||||
unit structs and enum variants \
|
||||
instead")
|
||||
.span_help(span, "remove trailing `()` to make a unit \
|
||||
struct or unit enum variant")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
visit::walk_struct_def(self, s)
|
||||
|
@ -40,17 +40,22 @@ extern crate libc;
|
||||
|
||||
extern crate serialize as rustc_serialize; // used by deriving
|
||||
|
||||
// A variant of 'try!' that panics on Err(FatalError). This is used as a
|
||||
// crutch on the way towards a non-panic!-prone parser. It should be used
|
||||
// for fatal parsing errors; eventually we plan to convert all code using
|
||||
// panictry to just use normal try
|
||||
// A variant of 'try!' that panics on an Err. This is used as a crutch on the
|
||||
// way towards a non-panic!-prone parser. It should be used for fatal parsing
|
||||
// errors; eventually we plan to convert all code using panictry to just use
|
||||
// normal try.
|
||||
// Exported for syntax_ext, not meant for general use.
|
||||
#[macro_export]
|
||||
macro_rules! panictry {
|
||||
($e:expr) => ({
|
||||
use std::result::Result::{Ok, Err};
|
||||
use errors::FatalError;
|
||||
use $crate::errors::FatalError;
|
||||
match $e {
|
||||
Ok(e) => e,
|
||||
Err(FatalError) => panic!(FatalError)
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
panic!(FatalError);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use ptr::P;
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
/// Parse attributes that appear before an item
|
||||
pub fn parse_outer_attributes(&mut self) -> PResult<Vec<ast::Attribute>> {
|
||||
pub fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
|
||||
let mut attrs: Vec<ast::Attribute> = Vec::new();
|
||||
loop {
|
||||
debug!("parse_outer_attributes: self.token={:?}",
|
||||
@ -51,7 +51,7 @@ impl<'a> Parser<'a> {
|
||||
///
|
||||
/// If permit_inner is true, then a leading `!` indicates an inner
|
||||
/// attribute
|
||||
pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<ast::Attribute> {
|
||||
pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
|
||||
debug!("parse_attributes: permit_inner={:?} self.token={:?}",
|
||||
permit_inner, self.token);
|
||||
let (span, value, mut style) = match self.token {
|
||||
@ -64,11 +64,13 @@ impl<'a> Parser<'a> {
|
||||
try!(self.bump());
|
||||
if !permit_inner {
|
||||
let span = self.span;
|
||||
self.span_err(span,
|
||||
"an inner attribute is not permitted in \
|
||||
this context");
|
||||
self.fileline_help(span,
|
||||
"place inner attribute at the top of the module or block");
|
||||
self.diagnostic().struct_span_err(span,
|
||||
"an inner attribute is not permitted in \
|
||||
this context")
|
||||
.fileline_help(span,
|
||||
"place inner attribute at the top of \
|
||||
the module or block")
|
||||
.emit()
|
||||
}
|
||||
ast::AttrStyle::Inner
|
||||
} else {
|
||||
@ -111,7 +113,7 @@ impl<'a> Parser<'a> {
|
||||
/// terminated by a semicolon.
|
||||
|
||||
/// matches inner_attrs*
|
||||
pub fn parse_inner_attributes(&mut self) -> PResult<Vec<ast::Attribute>> {
|
||||
pub fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
|
||||
let mut attrs: Vec<ast::Attribute> = vec![];
|
||||
loop {
|
||||
match self.token {
|
||||
@ -146,7 +148,7 @@ impl<'a> Parser<'a> {
|
||||
/// matches meta_item = IDENT
|
||||
/// | IDENT = lit
|
||||
/// | IDENT meta_seq
|
||||
pub fn parse_meta_item(&mut self) -> PResult<P<ast::MetaItem>> {
|
||||
pub fn parse_meta_item(&mut self) -> PResult<'a, P<ast::MetaItem>> {
|
||||
let nt_meta = match self.token {
|
||||
token::Interpolated(token::NtMeta(ref e)) => {
|
||||
Some(e.clone())
|
||||
@ -195,10 +197,10 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// matches meta_seq = ( COMMASEP(meta_item) )
|
||||
fn parse_meta_seq(&mut self) -> PResult<Vec<P<ast::MetaItem>>> {
|
||||
fn parse_meta_seq(&mut self) -> PResult<'a, Vec<P<ast::MetaItem>>> {
|
||||
self.parse_unspanned_seq(&token::OpenDelim(token::Paren),
|
||||
&token::CloseDelim(token::Paren),
|
||||
seq_sep_trailing_allowed(token::Comma),
|
||||
|p| p.parse_meta_item())
|
||||
|p: &mut Parser<'a>| p.parse_meta_item())
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
use ast;
|
||||
use codemap::{BytePos, CharPos, CodeMap, Pos, Span};
|
||||
use codemap;
|
||||
use errors::{FatalError, Handler};
|
||||
use errors::{FatalError, Handler, DiagnosticBuilder};
|
||||
use ext::tt::transcribe::tt_next_token;
|
||||
use parse::token::str_to_ident;
|
||||
use parse::token;
|
||||
@ -173,10 +173,6 @@ impl<'a> StringReader<'a> {
|
||||
self.span_diagnostic.span_err(sp, m)
|
||||
}
|
||||
|
||||
/// Suggest some help with a given span.
|
||||
pub fn help_span(&self, sp: Span, m: &str) {
|
||||
self.span_diagnostic.span_help(sp, m)
|
||||
}
|
||||
|
||||
/// Report a fatal error spanning [`from_pos`, `to_pos`).
|
||||
fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError {
|
||||
@ -188,11 +184,6 @@ impl<'a> StringReader<'a> {
|
||||
self.err_span(codemap::mk_sp(from_pos, to_pos), m)
|
||||
}
|
||||
|
||||
/// Suggest some help spanning [`from_pos`, `to_pos`).
|
||||
fn help_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) {
|
||||
self.help_span(codemap::mk_sp(from_pos, to_pos), m)
|
||||
}
|
||||
|
||||
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
|
||||
/// escaped character to the error message
|
||||
fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> FatalError {
|
||||
@ -201,6 +192,17 @@ impl<'a> StringReader<'a> {
|
||||
for c in c.escape_default() { m.push(c) }
|
||||
self.fatal_span_(from_pos, to_pos, &m[..])
|
||||
}
|
||||
fn struct_fatal_span_char(&self,
|
||||
from_pos: BytePos,
|
||||
to_pos: BytePos,
|
||||
m: &str,
|
||||
c: char)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
let mut m = m.to_string();
|
||||
m.push_str(": ");
|
||||
for c in c.escape_default() { m.push(c) }
|
||||
self.span_diagnostic.struct_span_fatal(codemap::mk_sp(from_pos, to_pos), &m[..])
|
||||
}
|
||||
|
||||
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
|
||||
/// escaped character to the error message
|
||||
@ -210,6 +212,17 @@ impl<'a> StringReader<'a> {
|
||||
for c in c.escape_default() { m.push(c) }
|
||||
self.err_span_(from_pos, to_pos, &m[..]);
|
||||
}
|
||||
fn struct_err_span_char(&self,
|
||||
from_pos: BytePos,
|
||||
to_pos: BytePos,
|
||||
m: &str,
|
||||
c: char)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
let mut m = m.to_string();
|
||||
m.push_str(": ");
|
||||
for c in c.escape_default() { m.push(c) }
|
||||
self.span_diagnostic.struct_span_err(codemap::mk_sp(from_pos, to_pos), &m[..])
|
||||
}
|
||||
|
||||
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending the
|
||||
/// offending string to the error message
|
||||
@ -746,10 +759,12 @@ impl<'a> StringReader<'a> {
|
||||
let valid = if self.curr_is('{') {
|
||||
self.scan_unicode_escape(delim) && !ascii_only
|
||||
} else {
|
||||
self.err_span_(start, self.last_pos,
|
||||
"incorrect unicode escape sequence");
|
||||
self.help_span_(start, self.last_pos,
|
||||
"format of unicode escape sequences is `\\u{…}`");
|
||||
let span = codemap::mk_sp(start, self.last_pos);
|
||||
self.span_diagnostic.struct_span_err(span,
|
||||
"incorrect unicode escape sequence")
|
||||
.span_help(span,
|
||||
"format of unicode escape sequences is `\\u{…}`")
|
||||
.emit();
|
||||
false
|
||||
};
|
||||
if ascii_only {
|
||||
@ -771,21 +786,22 @@ impl<'a> StringReader<'a> {
|
||||
}
|
||||
c => {
|
||||
let last_pos = self.last_pos;
|
||||
self.err_span_char(
|
||||
let mut err = self.struct_err_span_char(
|
||||
escaped_pos, last_pos,
|
||||
if ascii_only { "unknown byte escape" }
|
||||
else { "unknown character escape" },
|
||||
c);
|
||||
if e == '\r' {
|
||||
self.help_span_(escaped_pos, last_pos,
|
||||
err.span_help(codemap::mk_sp(escaped_pos, last_pos),
|
||||
"this is an isolated carriage return; consider checking \
|
||||
your editor and version control settings")
|
||||
your editor and version control settings");
|
||||
}
|
||||
if (e == '{' || e == '}') && !ascii_only {
|
||||
self.help_span_(escaped_pos, last_pos,
|
||||
err.span_help(codemap::mk_sp(escaped_pos, last_pos),
|
||||
"if used in a formatting string, \
|
||||
curly braces are escaped with `{{` and `}}`")
|
||||
curly braces are escaped with `{{` and `}}`");
|
||||
}
|
||||
err.emit();
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -1224,8 +1240,13 @@ impl<'a> StringReader<'a> {
|
||||
c => {
|
||||
let last_bpos = self.last_pos;
|
||||
let bpos = self.pos;
|
||||
unicode_chars::check_for_substitution(&self, c);
|
||||
panic!(self.fatal_span_char(last_bpos, bpos, "unknown start of token", c))
|
||||
let mut err = self.struct_fatal_span_char(last_bpos,
|
||||
bpos,
|
||||
"unknown start of token",
|
||||
c);
|
||||
unicode_chars::check_for_substitution(&self, c, &mut err);
|
||||
err.emit();
|
||||
panic!(FatalError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
// http://www.unicode.org/Public/security/revision-06/confusables.txt
|
||||
|
||||
use codemap::mk_sp as make_span;
|
||||
use errors::DiagnosticBuilder;
|
||||
use super::StringReader;
|
||||
|
||||
const UNICODE_ARRAY: &'static [(char, &'static str, char)] = &[
|
||||
@ -179,7 +180,9 @@ const ASCII_ARRAY: &'static [(char, &'static str)] = &[
|
||||
('=', "Equals Sign"),
|
||||
('>', "Greater-Than Sign"), ];
|
||||
|
||||
pub fn check_for_substitution(reader: &StringReader, ch: char) {
|
||||
pub fn check_for_substitution<'a>(reader: &StringReader<'a>,
|
||||
ch: char,
|
||||
err: &mut DiagnosticBuilder<'a>) {
|
||||
UNICODE_ARRAY
|
||||
.iter()
|
||||
.find(|&&(c, _, _)| c == ch)
|
||||
@ -190,7 +193,7 @@ pub fn check_for_substitution(reader: &StringReader, ch: char) {
|
||||
let msg =
|
||||
format!("unicode character '{}' ({}) looks much like '{}' ({}), but it's not",
|
||||
ch, u_name, ascii_char, ascii_name);
|
||||
reader.help_span(span, &msg);
|
||||
err.span_help(span, &msg);
|
||||
},
|
||||
None => {
|
||||
reader
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
use ast;
|
||||
use codemap::{self, Span, CodeMap, FileMap};
|
||||
use errors::{Handler, ColorConfig, FatalError};
|
||||
use errors::{Handler, ColorConfig, DiagnosticBuilder};
|
||||
use parse::parser::Parser;
|
||||
use parse::token::InternedString;
|
||||
use ptr::P;
|
||||
@ -25,7 +25,7 @@ use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
use std::str;
|
||||
|
||||
pub type PResult<T> = Result<T, FatalError>;
|
||||
pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
|
||||
|
||||
#[macro_use]
|
||||
pub mod parser;
|
||||
@ -76,8 +76,8 @@ pub fn parse_crate_from_file(
|
||||
cfg: ast::CrateConfig,
|
||||
sess: &ParseSess
|
||||
) -> ast::Crate {
|
||||
panictry!(new_parser_from_file(sess, cfg, input).parse_crate_mod())
|
||||
// why is there no p.abort_if_errors here?
|
||||
let mut parser = new_parser_from_file(sess, cfg, input);
|
||||
abort_if_errors(parser.parse_crate_mod(), &parser)
|
||||
}
|
||||
|
||||
pub fn parse_crate_attrs_from_file(
|
||||
@ -85,8 +85,8 @@ pub fn parse_crate_attrs_from_file(
|
||||
cfg: ast::CrateConfig,
|
||||
sess: &ParseSess
|
||||
) -> Vec<ast::Attribute> {
|
||||
// FIXME: maybe_aborted?
|
||||
panictry!(new_parser_from_file(sess, cfg, input).parse_inner_attributes())
|
||||
let mut parser = new_parser_from_file(sess, cfg, input);
|
||||
abort_if_errors(parser.parse_inner_attributes(), &parser)
|
||||
}
|
||||
|
||||
pub fn parse_crate_from_source_str(name: String,
|
||||
@ -271,6 +271,20 @@ pub fn maybe_aborted<T>(result: T, p: Parser) -> T {
|
||||
result
|
||||
}
|
||||
|
||||
fn abort_if_errors<'a, T>(result: PResult<'a, T>, p: &Parser) -> T {
|
||||
match result {
|
||||
Ok(c) => {
|
||||
p.abort_if_errors();
|
||||
c
|
||||
}
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
p.abort_if_errors();
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a string representing a character literal into its final form.
|
||||
/// Rather than just accepting/rejecting a given literal, unescapes it as
|
||||
/// well. Can take any slice prefixed by a character escape. Returns the
|
||||
@ -449,11 +463,13 @@ fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>,
|
||||
Some(suf) => {
|
||||
if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) {
|
||||
// if it looks like a width, lets try to be helpful.
|
||||
sd.span_err(sp, &format!("invalid width `{}` for float literal", &suf[1..]));
|
||||
sd.fileline_help(sp, "valid widths are 32 and 64");
|
||||
sd.struct_span_err(sp, &format!("invalid width `{}` for float literal", &suf[1..]))
|
||||
.fileline_help(sp, "valid widths are 32 and 64")
|
||||
.emit();
|
||||
} else {
|
||||
sd.span_err(sp, &format!("invalid suffix `{}` for float literal", suf));
|
||||
sd.fileline_help(sp, "valid suffixes are `f32` and `f64`");
|
||||
sd.struct_span_err(sp, &format!("invalid suffix `{}` for float literal", suf))
|
||||
.fileline_help(sp, "valid suffixes are `f32` and `f64`")
|
||||
.emit();
|
||||
}
|
||||
|
||||
ast::LitFloatUnsuffixed(data)
|
||||
@ -622,13 +638,15 @@ pub fn integer_lit(s: &str,
|
||||
// i<digits> and u<digits> look like widths, so lets
|
||||
// give an error message along those lines
|
||||
if looks_like_width_suffix(&['i', 'u'], suf) {
|
||||
sd.span_err(sp, &format!("invalid width `{}` for integer literal",
|
||||
&suf[1..]));
|
||||
sd.fileline_help(sp, "valid widths are 8, 16, 32 and 64");
|
||||
sd.struct_span_err(sp, &format!("invalid width `{}` for integer literal",
|
||||
&suf[1..]))
|
||||
.fileline_help(sp, "valid widths are 8, 16, 32 and 64")
|
||||
.emit();
|
||||
} else {
|
||||
sd.span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf));
|
||||
sd.fileline_help(sp, "the suffix must be one of the integral types \
|
||||
(`u32`, `isize`, etc)");
|
||||
sd.struct_span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf))
|
||||
.fileline_help(sp, "the suffix must be one of the integral types \
|
||||
(`u32`, `isize`, etc)")
|
||||
.emit();
|
||||
}
|
||||
|
||||
ty
|
||||
|
@ -59,18 +59,17 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
|
||||
kind_str: &str,
|
||||
desc: &str,
|
||||
error: bool) {
|
||||
if error {
|
||||
self.span_err(sp, &format!("obsolete syntax: {}", kind_str));
|
||||
let mut err = if error {
|
||||
self.diagnostic().struct_span_err(sp, &format!("obsolete syntax: {}", kind_str))
|
||||
} else {
|
||||
self.span_warn(sp, &format!("obsolete syntax: {}", kind_str));
|
||||
}
|
||||
self.diagnostic().struct_span_warn(sp, &format!("obsolete syntax: {}", kind_str))
|
||||
};
|
||||
|
||||
if !self.obsolete_set.contains(&kind) &&
|
||||
(error || self.sess.span_diagnostic.can_emit_warnings) {
|
||||
self.sess
|
||||
.span_diagnostic
|
||||
.note(&format!("{}", desc));
|
||||
err.note(&format!("{}", desc));
|
||||
self.obsolete_set.insert(kind);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -47,21 +47,21 @@ struct ShowSpanVisitor<'a> {
|
||||
impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> {
|
||||
fn visit_expr(&mut self, e: &ast::Expr) {
|
||||
if let Mode::Expression = self.mode {
|
||||
self.span_diagnostic.span_note(e.span, "expression");
|
||||
self.span_diagnostic.span_warn(e.span, "expression");
|
||||
}
|
||||
visit::walk_expr(self, e);
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &ast::Pat) {
|
||||
if let Mode::Pattern = self.mode {
|
||||
self.span_diagnostic.span_note(p.span, "pattern");
|
||||
self.span_diagnostic.span_warn(p.span, "pattern");
|
||||
}
|
||||
visit::walk_pat(self, p);
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &ast::Ty) {
|
||||
if let Mode::Type = self.mode {
|
||||
self.span_diagnostic.span_note(t.span, "type");
|
||||
self.span_diagnostic.span_warn(t.span, "type");
|
||||
}
|
||||
visit::walk_ty(self, t);
|
||||
}
|
||||
|
@ -30,10 +30,9 @@ pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a>
|
||||
source_str)
|
||||
}
|
||||
|
||||
fn with_error_checking_parse<T, F>(s: String, f: F) -> T where
|
||||
F: FnOnce(&mut Parser) -> PResult<T>,
|
||||
fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T where
|
||||
F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
{
|
||||
let ps = ParseSess::new();
|
||||
let mut p = string_to_parser(&ps, s);
|
||||
let x = panictry!(f(&mut p));
|
||||
p.abort_if_errors();
|
||||
@ -42,28 +41,32 @@ fn with_error_checking_parse<T, F>(s: String, f: F) -> T where
|
||||
|
||||
/// Parse a string, return a crate.
|
||||
pub fn string_to_crate (source_str : String) -> ast::Crate {
|
||||
with_error_checking_parse(source_str, |p| {
|
||||
let ps = ParseSess::new();
|
||||
with_error_checking_parse(source_str, &ps, |p| {
|
||||
p.parse_crate_mod()
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a string, return an expr
|
||||
pub fn string_to_expr (source_str : String) -> P<ast::Expr> {
|
||||
with_error_checking_parse(source_str, |p| {
|
||||
let ps = ParseSess::new();
|
||||
with_error_checking_parse(source_str, &ps, |p| {
|
||||
p.parse_expr()
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a string, return an item
|
||||
pub fn string_to_item (source_str : String) -> Option<P<ast::Item>> {
|
||||
with_error_checking_parse(source_str, |p| {
|
||||
let ps = ParseSess::new();
|
||||
with_error_checking_parse(source_str, &ps, |p| {
|
||||
p.parse_item()
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a string, return a stmt
|
||||
pub fn string_to_stmt(source_str : String) -> Option<P<ast::Stmt>> {
|
||||
with_error_checking_parse(source_str, |p| {
|
||||
let ps = ParseSess::new();
|
||||
with_error_checking_parse(source_str, &ps, |p| {
|
||||
p.parse_stmt()
|
||||
})
|
||||
}
|
||||
@ -71,7 +74,8 @@ pub fn string_to_stmt(source_str : String) -> Option<P<ast::Stmt>> {
|
||||
/// Parse a string, return a pat. Uses "irrefutable"... which doesn't
|
||||
/// (currently) affect parsing.
|
||||
pub fn string_to_pat(source_str: String) -> P<ast::Pat> {
|
||||
with_error_checking_parse(source_str, |p| {
|
||||
let ps = ParseSess::new();
|
||||
with_error_checking_parse(source_str, &ps, |p| {
|
||||
p.parse_pat()
|
||||
})
|
||||
}
|
||||
|
@ -130,10 +130,11 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||
match names.get(name) {
|
||||
None => {}
|
||||
Some(prev) => {
|
||||
ecx.span_err(e.span,
|
||||
&format!("duplicate argument named `{}`",
|
||||
name));
|
||||
ecx.parse_sess.span_diagnostic.span_note(prev.span, "previously here");
|
||||
ecx.struct_span_err(e.span,
|
||||
&format!("duplicate argument named `{}`",
|
||||
name))
|
||||
.span_note(prev.span, "previously here")
|
||||
.emit();
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -24,26 +24,13 @@
|
||||
#![feature(str_char)]
|
||||
|
||||
extern crate fmt_macros;
|
||||
#[macro_use]
|
||||
extern crate syntax;
|
||||
|
||||
use syntax::ext::base::{MacroExpanderFn, NormalTT};
|
||||
use syntax::ext::base::{SyntaxEnv, SyntaxExtension};
|
||||
use syntax::parse::token::intern;
|
||||
|
||||
// A variant of 'try!' that panics on Err(FatalError). This is used as a
|
||||
// crutch on the way towards a non-panic!-prone parser. It should be used
|
||||
// for fatal parsing errors; eventually we plan to convert all code using
|
||||
// panictry to just use normal try
|
||||
macro_rules! panictry {
|
||||
($e:expr) => ({
|
||||
use std::result::Result::{Ok, Err};
|
||||
use syntax::errors::FatalError;
|
||||
match $e {
|
||||
Ok(e) => e,
|
||||
Err(FatalError) => panic!(FatalError)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mod asm;
|
||||
mod cfg;
|
||||
|
@ -37,34 +37,36 @@ pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a>
|
||||
source_str)
|
||||
}
|
||||
|
||||
fn with_error_checking_parse<T, F>(s: String, f: F) -> PResult<T> where
|
||||
F: FnOnce(&mut Parser) -> PResult<T>,
|
||||
fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> PResult<'a, T> where
|
||||
F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
{
|
||||
let ps = ParseSess::new();
|
||||
let mut p = string_to_parser(&ps, s);
|
||||
let x = f(&mut p);
|
||||
|
||||
if ps.span_diagnostic.has_errors() || p.token != token::Eof {
|
||||
if let Err(mut e) = x {
|
||||
e.cancel();
|
||||
}
|
||||
return Err(p.fatal("parse error"));
|
||||
}
|
||||
|
||||
x
|
||||
}
|
||||
|
||||
fn expr(s: &str) -> PResult<P<ast::Expr>> {
|
||||
with_error_checking_parse(s.to_string(), |p| {
|
||||
fn expr<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, P<ast::Expr>> {
|
||||
with_error_checking_parse(s.to_string(), ps, |p| {
|
||||
p.parse_expr()
|
||||
})
|
||||
}
|
||||
|
||||
fn stmt(s: &str) -> PResult<P<ast::Stmt>> {
|
||||
with_error_checking_parse(s.to_string(), |p| {
|
||||
fn stmt<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, P<ast::Stmt>> {
|
||||
with_error_checking_parse(s.to_string(), ps, |p| {
|
||||
p.parse_stmt().map(|s| s.unwrap())
|
||||
})
|
||||
}
|
||||
|
||||
fn attr(s: &str) -> PResult<ast::Attribute> {
|
||||
with_error_checking_parse(s.to_string(), |p| {
|
||||
fn attr<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, ast::Attribute> {
|
||||
with_error_checking_parse(s.to_string(), ps, |p| {
|
||||
p.parse_attribute(true)
|
||||
})
|
||||
}
|
||||
@ -79,29 +81,39 @@ fn str_compare<T, F: Fn(&T) -> String>(e: &str, expected: &[T], actual: &[T], f:
|
||||
}
|
||||
|
||||
fn check_expr_attrs(es: &str, expected: &[&str]) {
|
||||
let e = expr(es).expect("parse error");
|
||||
let ps = ParseSess::new();
|
||||
let e = expr(es, &ps).expect("parse error");
|
||||
let actual = &e.attrs;
|
||||
str_compare(es,
|
||||
&expected.iter().map(|r| attr(r).unwrap()).collect::<Vec<_>>(),
|
||||
&expected.iter().map(|r| attr(r, &ps).unwrap()).collect::<Vec<_>>(),
|
||||
actual.as_attr_slice(),
|
||||
pprust::attribute_to_string);
|
||||
}
|
||||
|
||||
fn check_stmt_attrs(es: &str, expected: &[&str]) {
|
||||
let e = stmt(es).expect("parse error");
|
||||
let ps = ParseSess::new();
|
||||
let e = stmt(es, &ps).expect("parse error");
|
||||
let actual = e.node.attrs();
|
||||
str_compare(es,
|
||||
&expected.iter().map(|r| attr(r).unwrap()).collect::<Vec<_>>(),
|
||||
&expected.iter().map(|r| attr(r, &ps).unwrap()).collect::<Vec<_>>(),
|
||||
actual,
|
||||
pprust::attribute_to_string);
|
||||
}
|
||||
|
||||
fn reject_expr_parse(es: &str) {
|
||||
assert!(expr(es).is_err(), "parser did not reject `{}`", es);
|
||||
let ps = ParseSess::new();
|
||||
match expr(es, &ps) {
|
||||
Ok(_) => panic!("parser did not reject `{}`", es),
|
||||
Err(mut e) => e.cancel(),
|
||||
};
|
||||
}
|
||||
|
||||
fn reject_stmt_parse(es: &str) {
|
||||
assert!(stmt(es).is_err(), "parser did not reject `{}`", es);
|
||||
let ps = ParseSess::new();
|
||||
match stmt(es, &ps) {
|
||||
Ok(_) => panic!("parser did not reject `{}`", es),
|
||||
Err(mut e) => e.cancel(),
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
Loading…
Reference in New Issue
Block a user