Skip to content

Commit 2cefd99

Browse files
committed
Pull is_range_literal out into lowering
1 parent 5b7baa5 commit 2cefd99

File tree

2 files changed

+64
-66
lines changed

2 files changed

+64
-66
lines changed

src/librustc/hir/lowering.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5400,3 +5400,65 @@ fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
54005400
body_ids.sort_by_key(|b| bodies[b].value.span);
54015401
body_ids
54025402
}
5403+
5404+
/// This function checks if the specified expression is a built-in range literal.
5405+
/// (See: `LoweringContext::lower_expr()`).
5406+
pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool {
5407+
use hir::{Path, QPath, ExprKind, TyKind};
5408+
5409+
// We support `::std::ops::Range` and `::core::ops::Range` prefixes.
5410+
let is_range_path = |path: &Path| {
5411+
let mut segs = path.segments.iter().map(|seg| seg.ident.as_str());
5412+
5413+
if let (Some(root), Some(std_core), Some(ops), Some(range), None) =
5414+
(segs.next(), segs.next(), segs.next(), segs.next(), segs.next())
5415+
{
5416+
// "{{root}}" is the equivalent of `::` prefix in `Path`.
5417+
root == "{{root}}" && (std_core == "std" || std_core == "core")
5418+
&& ops == "ops" && range.starts_with("Range")
5419+
} else {
5420+
false
5421+
}
5422+
};
5423+
5424+
let span_is_range_literal = |span: &Span| {
5425+
// Check whether a span corresponding to a range expression
5426+
// is a range literal, rather than an explicit struct or `new()` call.
5427+
let source_map = sess.source_map();
5428+
let end_point = source_map.end_point(*span);
5429+
5430+
if let Ok(end_string) = source_map.span_to_snippet(end_point) {
5431+
!(end_string.ends_with("}") || end_string.ends_with(")"))
5432+
} else {
5433+
false
5434+
}
5435+
};
5436+
5437+
match expr.node {
5438+
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
5439+
ExprKind::Struct(ref qpath, _, _) => {
5440+
if let QPath::Resolved(None, ref path) = **qpath {
5441+
return is_range_path(&path) && span_is_range_literal(&expr.span);
5442+
}
5443+
}
5444+
5445+
// `..` desugars to its struct path.
5446+
ExprKind::Path(QPath::Resolved(None, ref path)) => {
5447+
return is_range_path(&path) && span_is_range_literal(&expr.span);
5448+
}
5449+
5450+
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
5451+
ExprKind::Call(ref func, _) => {
5452+
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
5453+
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
5454+
let call_to_new = segment.ident.as_str() == "new";
5455+
return is_range_path(&path) && span_is_range_literal(&expr.span) && call_to_new;
5456+
}
5457+
}
5458+
}
5459+
5460+
_ => {}
5461+
}
5462+
5463+
false
5464+
}

src/librustc_typeck/check/demand.rs

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use syntax_pos::Span;
77
use rustc::hir;
88
use rustc::hir::def::Def;
99
use rustc::hir::Node;
10-
use rustc::hir::print;
10+
use rustc::hir::{print, lowering::is_range_literal};
1111
use rustc::ty::{self, Ty, AssociatedItem};
1212
use rustc::ty::adjustment::AllowTwoPhase;
1313
use errors::{Applicability, DiagnosticBuilder};
@@ -380,7 +380,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
380380
hir::ExprKind::Cast(_, _) |
381381
hir::ExprKind::Binary(_, _, _) => true,
382382
// parenthesize borrows of range literals (Issue #54505)
383-
_ if self.is_range_literal(expr) => true,
383+
_ if is_range_literal(self.tcx.sess, expr) => true,
384384
_ => false,
385385
};
386386
let sugg_expr = if needs_parens {
@@ -479,70 +479,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
479479
None
480480
}
481481

482-
/// This function checks if the specified expression is a built-in range literal.
483-
/// (See: `LoweringContext::lower_expr()` in `src/librustc/hir/lowering.rs`).
484-
fn is_range_literal(&self, expr: &hir::Expr) -> bool {
485-
use hir::{Path, QPath, ExprKind, TyKind};
486-
487-
// We support `::std::ops::Range` and `::core::ops::Range` prefixes
488-
let is_range_path = |path: &Path| {
489-
let mut segs = path.segments.iter()
490-
.map(|seg| seg.ident.as_str());
491-
492-
if let (Some(root), Some(std_core), Some(ops), Some(range), None) =
493-
(segs.next(), segs.next(), segs.next(), segs.next(), segs.next())
494-
{
495-
// "{{root}}" is the equivalent of `::` prefix in Path
496-
root == "{{root}}" && (std_core == "std" || std_core == "core")
497-
&& ops == "ops" && range.starts_with("Range")
498-
} else {
499-
false
500-
}
501-
};
502-
503-
let span_is_range_literal = |span: &Span| {
504-
// Check whether a span corresponding to a range expression
505-
// is a range literal, rather than an explicit struct or `new()` call.
506-
let source_map = self.tcx.sess.source_map();
507-
let end_point = source_map.end_point(*span);
508-
509-
if let Ok(end_string) = source_map.span_to_snippet(end_point) {
510-
!(end_string.ends_with("}") || end_string.ends_with(")"))
511-
} else {
512-
false
513-
}
514-
};
515-
516-
match expr.node {
517-
// All built-in range literals but `..=` and `..` desugar to Structs
518-
ExprKind::Struct(ref qpath, _, _) => {
519-
if let QPath::Resolved(None, ref path) = **qpath {
520-
return is_range_path(&path) && span_is_range_literal(&expr.span);
521-
}
522-
}
523-
// `..` desugars to its struct path
524-
ExprKind::Path(QPath::Resolved(None, ref path)) => {
525-
return is_range_path(&path) && span_is_range_literal(&expr.span);
526-
}
527-
528-
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`
529-
ExprKind::Call(ref func, _) => {
530-
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
531-
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
532-
let call_to_new = segment.ident.as_str() == "new";
533-
534-
return is_range_path(&path) && span_is_range_literal(&expr.span)
535-
&& call_to_new;
536-
}
537-
}
538-
}
539-
540-
_ => {}
541-
}
542-
543-
false
544-
}
545-
546482
pub fn check_for_cast(
547483
&self,
548484
err: &mut DiagnosticBuilder<'tcx>,

0 commit comments

Comments
 (0)