1
Fork 0

end_point handling multibyte characters correctly.

This commit is contained in:
David Wood 2018-01-14 17:29:07 +00:00
parent c6e6428d1a
commit c71cec8834
No known key found for this signature in database
GPG key ID: 01760B4F9F53F154
11 changed files with 61 additions and 35 deletions

View file

@ -958,7 +958,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// `sp` only covers `T`, change it so that it covers // `sp` only covers `T`, change it so that it covers
// `T:` when appropriate // `T:` when appropriate
let sp = if has_lifetimes { let sp = if has_lifetimes {
sp.to(sp.next_point().next_point()) sp.to(self.tcx.sess.codemap().next_point(
self.tcx.sess.codemap().next_point(sp)))
} else { } else {
sp sp
}; };

View file

@ -591,8 +591,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
// 3. Where does old loan expire. // 3. Where does old loan expire.
let previous_end_span = let previous_end_span =
Some(old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree) Some(self.tcx().sess.codemap().end_point(
.end_point()); old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree)));
let mut err = match (new_loan.kind, old_loan.kind) { let mut err = match (new_loan.kind, old_loan.kind) {
(ty::MutBorrow, ty::MutBorrow) => (ty::MutBorrow, ty::MutBorrow) =>

View file

@ -1276,7 +1276,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> { fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> {
match *region { match *region {
ty::ReScope(scope) => { ty::ReScope(scope) => {
Some(scope.span(self.tcx, &self.region_scope_tree).end_point()) Some(self.tcx.sess.codemap().end_point(
scope.span(self.tcx, &self.region_scope_tree)))
} }
_ => None _ => None
} }

View file

@ -1112,10 +1112,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
debug!("check_for_invalidation_at_exit({:?}): INVALID", place); debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
// FIXME: should be talking about the region lifetime instead // FIXME: should be talking about the region lifetime instead
// of just a span here. // of just a span here.
let span = self.tcx.sess.codemap().end_point(span);
self.report_borrowed_value_does_not_live_long_enough( self.report_borrowed_value_does_not_live_long_enough(
context, context,
borrow, borrow,
span.end_point(), span,
flow_state.borrows.operator(), flow_state.borrows.operator(),
) )
} }

View file

@ -699,7 +699,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let region_scope_span = region_scope.span(self.hir.tcx(), let region_scope_span = region_scope.span(self.hir.tcx(),
&self.hir.region_scope_tree); &self.hir.region_scope_tree);
// Attribute scope exit drops to scope's closing brace. // Attribute scope exit drops to scope's closing brace.
let scope_end = region_scope_span.end_point(); let scope_end = self.hir.tcx().sess.codemap().end_point(region_scope_span);
scope.drops.push(DropData { scope.drops.push(DropData {
span: scope_end, span: scope_end,

View file

@ -537,8 +537,8 @@ impl<'a, 'gcx, 'tcx> ActiveBorrows<'a, 'gcx, 'tcx> {
Some(_) => None, Some(_) => None,
None => { None => {
match self.0.region_span_map.get(region) { match self.0.region_span_map.get(region) {
Some(span) => Some(span.end_point()), Some(span) => Some(self.0.tcx.sess.codemap().end_point(*span)),
None => Some(self.0.mir.span.end_point()) None => Some(self.0.tcx.sess.codemap().end_point(self.0.mir.span))
} }
} }
} }

View file

@ -2871,8 +2871,8 @@ impl<'a> Resolver<'a> {
if let Some(sp) = self.current_type_ascription.last() { if let Some(sp) = self.current_type_ascription.last() {
let mut sp = *sp; let mut sp = *sp;
loop { // try to find the `:`, bail on first non-':'/non-whitespace loop { // try to find the `:`, bail on first non-':'/non-whitespace
sp = sp.next_point(); sp = cm.next_point(sp);
if let Ok(snippet) = cm.span_to_snippet(sp.to(sp.next_point())) { if let Ok(snippet) = cm.span_to_snippet(sp.to(cm.next_point(sp))) {
debug!("snippet {:?}", snippet); debug!("snippet {:?}", snippet);
let line_sp = cm.lookup_char_pos(sp.hi()).line; let line_sp = cm.lookup_char_pos(sp.hi()).line;
let line_base_sp = cm.lookup_char_pos(base_span.lo()).line; let line_base_sp = cm.lookup_char_pos(base_span.lo()).line;

View file

@ -2457,7 +2457,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
err.span_label(def_s, "defined here"); err.span_label(def_s, "defined here");
} }
if sugg_unit { if sugg_unit {
let sugg_span = expr_sp.end_point(); let sugg_span = sess.codemap().end_point(expr_sp);
// remove closing `)` from the span // remove closing `)` from the span
let sugg_span = sugg_span.with_hi(sugg_span.lo()); let sugg_span = sugg_span.with_hi(sugg_span.lo());
err.span_suggestion( err.span_suggestion(
@ -4446,10 +4446,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// statement and the return type has been left as default or has been specified as `()`. If so, /// statement and the return type has been left as default or has been specified as `()`. If so,
/// it suggests adding a semicolon. /// it suggests adding a semicolon.
fn suggest_missing_semicolon(&self, fn suggest_missing_semicolon(&self,
err: &mut DiagnosticBuilder<'tcx>, err: &mut DiagnosticBuilder<'tcx>,
expression: &'gcx hir::Expr, expression: &'gcx hir::Expr,
expected: Ty<'tcx>, expected: Ty<'tcx>,
cause_span: Span) { cause_span: Span) {
if expected.is_nil() { if expected.is_nil() {
// `BlockTailExpression` only relevant if the tail expr would be // `BlockTailExpression` only relevant if the tail expr would be
// useful on its own. // useful on its own.
@ -4461,7 +4461,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
hir::ExprLoop(..) | hir::ExprLoop(..) |
hir::ExprMatch(..) | hir::ExprMatch(..) |
hir::ExprBlock(..) => { hir::ExprBlock(..) => {
let sp = cause_span.next_point(); let sp = self.tcx.sess.codemap().next_point(cause_span);
err.span_suggestion(sp, err.span_suggestion(sp,
"try adding a semicolon", "try adding a semicolon",
";".to_string()); ";".to_string());

View file

@ -25,6 +25,7 @@ pub use self::ExpnFormat::*;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::stable_hasher::StableHasher;
use std::cell::{RefCell, Ref}; use std::cell::{RefCell, Ref};
use std::cmp;
use std::hash::Hash; use std::hash::Hash;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc; use std::rc::Rc;
@ -607,6 +608,42 @@ impl CodeMap {
self.span_until_char(sp, '{') self.span_until_char(sp, '{')
} }
/// Returns a new span representing just the end-point of this span
pub fn end_point(&self, sp: Span) -> Span {
let hi = sp.hi().0.checked_sub(1).unwrap_or(sp.hi().0);
let hi = self.get_start_of_char_bytepos(BytePos(hi));
let lo = cmp::max(hi.0, sp.lo().0);
sp.with_lo(BytePos(lo))
}
/// Returns a new span representing the next character after the end-point of this span
pub fn next_point(&self, sp: Span) -> Span {
let hi = sp.lo().0.checked_add(1).unwrap_or(sp.lo().0);
let hi = self.get_start_of_char_bytepos(BytePos(hi));
let lo = cmp::max(sp.hi().0, hi.0);
Span::new(BytePos(lo), BytePos(lo), sp.ctxt())
}
fn get_start_of_char_bytepos(&self, bpos: BytePos) -> BytePos {
let idx = self.lookup_filemap_idx(bpos);
let files = self.files.borrow();
let map = &(*files)[idx];
for mbc in map.multibyte_chars.borrow().iter() {
if mbc.pos < bpos {
if bpos.to_usize() >= mbc.pos.to_usize() + mbc.bytes {
// If we do, then return the start of the character.
return mbc.pos;
}
} else {
break;
}
}
// If this isn't a multibyte character, return the original position.
return bpos;
}
pub fn get_filemap(&self, filename: &FileName) -> Option<Rc<FileMap>> { pub fn get_filemap(&self, filename: &FileName) -> Option<Rc<FileMap>> {
for fm in self.files.borrow().iter() { for fm in self.files.borrow().iter() {
if *filename == fm.name { if *filename == fm.name {

View file

@ -704,13 +704,15 @@ impl<'a> Parser<'a> {
expect.clone() expect.clone()
}; };
(format!("expected one of {}, found `{}`", expect, actual), (format!("expected one of {}, found `{}`", expect, actual),
(self.prev_span.next_point(), format!("expected one of {} here", short_expect))) (self.sess.codemap().next_point(self.prev_span),
format!("expected one of {} here", short_expect)))
} else if expected.is_empty() { } else if expected.is_empty() {
(format!("unexpected token: `{}`", actual), (format!("unexpected token: `{}`", actual),
(self.prev_span, "unexpected token after this".to_string())) (self.prev_span, "unexpected token after this".to_string()))
} else { } else {
(format!("expected {}, found `{}`", expect, actual), (format!("expected {}, found `{}`", expect, actual),
(self.prev_span.next_point(), format!("expected {} here", expect))) (self.sess.codemap().next_point(self.prev_span),
format!("expected {} here", expect)))
}; };
let mut err = self.fatal(&msg_exp); let mut err = self.fatal(&msg_exp);
let sp = if self.token == token::Token::Eof { let sp = if self.token == token::Token::Eof {
@ -3190,7 +3192,7 @@ impl<'a> Parser<'a> {
// return. This won't catch blocks with an explicit `return`, but that would be caught by // return. This won't catch blocks with an explicit `return`, but that would be caught by
// the dead code lint. // the dead code lint.
if self.eat_keyword(keywords::Else) || !cond.returns() { if self.eat_keyword(keywords::Else) || !cond.returns() {
let sp = lo.next_point(); let sp = self.sess.codemap().next_point(lo);
let mut err = self.diagnostic() let mut err = self.diagnostic()
.struct_span_err(sp, "missing condition for `if` statemement"); .struct_span_err(sp, "missing condition for `if` statemement");
err.span_label(sp, "expected if condition here"); err.span_label(sp, "expected if condition here");

View file

@ -216,22 +216,6 @@ impl Span {
self.data().with_ctxt(ctxt) self.data().with_ctxt(ctxt)
} }
/// Returns a new span representing just the end-point of this span
pub fn end_point(self) -> Span {
let span = self.data();
// We can avoid an ICE by checking if subtraction would cause an overflow.
let hi = if span.hi.0 == u32::min_value() { span.hi.0 } else { span.hi.0 - 1 };
let lo = cmp::max(hi, span.lo.0);
span.with_lo(BytePos(lo))
}
/// Returns a new span representing the next character after the end-point of this span
pub fn next_point(self) -> Span {
let span = self.data();
let lo = cmp::max(span.hi.0, span.lo.0 + 1);
Span::new(BytePos(lo), BytePos(lo), span.ctxt)
}
/// Returns `self` if `self` is not the dummy span, and `other` otherwise. /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
pub fn substitute_dummy(self, other: Span) -> Span { pub fn substitute_dummy(self, other: Span) -> Span {
if self.source_equal(&DUMMY_SP) { other } else { self } if self.source_equal(&DUMMY_SP) { other } else { self }