From 2cefd9987b36488a3d6f0e2b350a8abd84cfce25 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 27 Apr 2019 12:44:32 +0100 Subject: [PATCH] Pull `is_range_literal` out into `lowering` --- src/librustc/hir/lowering.rs | 62 ++++++++++++++++++++++++++ src/librustc_typeck/check/demand.rs | 68 +---------------------------- 2 files changed, 64 insertions(+), 66 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index df455a725c5..b84ee579a10 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -5400,3 +5400,65 @@ fn body_ids(bodies: &BTreeMap) -> Vec { body_ids.sort_by_key(|b| bodies[b].value.span); body_ids } + +/// This function checks if the specified expression is a built-in range literal. +/// (See: `LoweringContext::lower_expr()`). +pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool { + use hir::{Path, QPath, ExprKind, TyKind}; + + // We support `::std::ops::Range` and `::core::ops::Range` prefixes. + let is_range_path = |path: &Path| { + let mut segs = path.segments.iter().map(|seg| seg.ident.as_str()); + + if let (Some(root), Some(std_core), Some(ops), Some(range), None) = + (segs.next(), segs.next(), segs.next(), segs.next(), segs.next()) + { + // "{{root}}" is the equivalent of `::` prefix in `Path`. + root == "{{root}}" && (std_core == "std" || std_core == "core") + && ops == "ops" && range.starts_with("Range") + } else { + false + } + }; + + let span_is_range_literal = |span: &Span| { + // Check whether a span corresponding to a range expression + // is a range literal, rather than an explicit struct or `new()` call. + let source_map = sess.source_map(); + let end_point = source_map.end_point(*span); + + if let Ok(end_string) = source_map.span_to_snippet(end_point) { + !(end_string.ends_with("}") || end_string.ends_with(")")) + } else { + false + } + }; + + match expr.node { + // All built-in range literals but `..=` and `..` desugar to `Struct`s. + ExprKind::Struct(ref qpath, _, _) => { + if let QPath::Resolved(None, ref path) = **qpath { + return is_range_path(&path) && span_is_range_literal(&expr.span); + } + } + + // `..` desugars to its struct path. + ExprKind::Path(QPath::Resolved(None, ref path)) => { + return is_range_path(&path) && span_is_range_literal(&expr.span); + } + + // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. + ExprKind::Call(ref func, _) => { + if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node { + if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node { + let call_to_new = segment.ident.as_str() == "new"; + return is_range_path(&path) && span_is_range_literal(&expr.span) && call_to_new; + } + } + } + + _ => {} + } + + false +} diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 689996ccb25..8ae66a96c76 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -7,7 +7,7 @@ use syntax_pos::Span; use rustc::hir; use rustc::hir::def::Def; use rustc::hir::Node; -use rustc::hir::print; +use rustc::hir::{print, lowering::is_range_literal}; use rustc::ty::{self, Ty, AssociatedItem}; use rustc::ty::adjustment::AllowTwoPhase; use errors::{Applicability, DiagnosticBuilder}; @@ -380,7 +380,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, // parenthesize borrows of range literals (Issue #54505) - _ if self.is_range_literal(expr) => true, + _ if is_range_literal(self.tcx.sess, expr) => true, _ => false, }; let sugg_expr = if needs_parens { @@ -479,70 +479,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } - /// This function checks if the specified expression is a built-in range literal. - /// (See: `LoweringContext::lower_expr()` in `src/librustc/hir/lowering.rs`). - fn is_range_literal(&self, expr: &hir::Expr) -> bool { - use hir::{Path, QPath, ExprKind, TyKind}; - - // We support `::std::ops::Range` and `::core::ops::Range` prefixes - let is_range_path = |path: &Path| { - let mut segs = path.segments.iter() - .map(|seg| seg.ident.as_str()); - - if let (Some(root), Some(std_core), Some(ops), Some(range), None) = - (segs.next(), segs.next(), segs.next(), segs.next(), segs.next()) - { - // "{{root}}" is the equivalent of `::` prefix in Path - root == "{{root}}" && (std_core == "std" || std_core == "core") - && ops == "ops" && range.starts_with("Range") - } else { - false - } - }; - - let span_is_range_literal = |span: &Span| { - // Check whether a span corresponding to a range expression - // is a range literal, rather than an explicit struct or `new()` call. - let source_map = self.tcx.sess.source_map(); - let end_point = source_map.end_point(*span); - - if let Ok(end_string) = source_map.span_to_snippet(end_point) { - !(end_string.ends_with("}") || end_string.ends_with(")")) - } else { - false - } - }; - - match expr.node { - // All built-in range literals but `..=` and `..` desugar to Structs - ExprKind::Struct(ref qpath, _, _) => { - if let QPath::Resolved(None, ref path) = **qpath { - return is_range_path(&path) && span_is_range_literal(&expr.span); - } - } - // `..` desugars to its struct path - ExprKind::Path(QPath::Resolved(None, ref path)) => { - return is_range_path(&path) && span_is_range_literal(&expr.span); - } - - // `..=` desugars into `::std::ops::RangeInclusive::new(...)` - ExprKind::Call(ref func, _) => { - if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node { - if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node { - let call_to_new = segment.ident.as_str() == "new"; - - return is_range_path(&path) && span_is_range_literal(&expr.span) - && call_to_new; - } - } - } - - _ => {} - } - - false - } - pub fn check_for_cast( &self, err: &mut DiagnosticBuilder<'tcx>,