@@ -1595,6 +1595,68 @@ impl fmt::Debug for Expr {
1595
1595
}
1596
1596
}
1597
1597
1598
+ /// Checks if the specified expression is a built-in range literal.
1599
+ /// (See: `LoweringContext::lower_expr()`).
1600
+ pub fn is_range_literal ( sess : & Session , expr : & hir:: Expr ) -> bool {
1601
+ use hir:: { Path , QPath , ExprKind , TyKind } ;
1602
+
1603
+ // Returns whether the given path represents a (desugared) range,
1604
+ // either in std or core, i.e. has either a `::std::ops::Range` or
1605
+ // `::core::ops::Range` prefix.
1606
+ fn is_range_path ( path : & Path ) -> bool {
1607
+ let segs: Vec < _ > = path. segments . iter ( ) . map ( |seg| seg. ident . to_string ( ) ) . collect ( ) ;
1608
+ let segs: Vec < _ > = segs. iter ( ) . map ( |seg| & * * seg) . collect ( ) ;
1609
+
1610
+ // "{{root}}" is the equivalent of `::` prefix in `Path`.
1611
+ if let [ "{{root}}" , std_core, "ops" , range] = segs. as_slice ( ) {
1612
+ ( * std_core == "std" || * std_core == "core" ) && range. starts_with ( "Range" )
1613
+ } else {
1614
+ false
1615
+ }
1616
+ } ;
1617
+
1618
+ // Check whether a span corresponding to a range expression is a
1619
+ // range literal, rather than an explicit struct or `new()` call.
1620
+ fn is_lit ( sess : & Session , span : & Span ) -> bool {
1621
+ let source_map = sess. source_map ( ) ;
1622
+ let end_point = source_map. end_point ( * span) ;
1623
+
1624
+ if let Ok ( end_string) = source_map. span_to_snippet ( end_point) {
1625
+ !( end_string. ends_with ( "}" ) || end_string. ends_with ( ")" ) )
1626
+ } else {
1627
+ false
1628
+ }
1629
+ } ;
1630
+
1631
+ match expr. kind {
1632
+ // All built-in range literals but `..=` and `..` desugar to `Struct`s.
1633
+ ExprKind :: Struct ( ref qpath, _, _) => {
1634
+ if let QPath :: Resolved ( None , ref path) = * * qpath {
1635
+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) ;
1636
+ }
1637
+ }
1638
+
1639
+ // `..` desugars to its struct path.
1640
+ ExprKind :: Path ( QPath :: Resolved ( None , ref path) ) => {
1641
+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) ;
1642
+ }
1643
+
1644
+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
1645
+ ExprKind :: Call ( ref func, _) => {
1646
+ if let ExprKind :: Path ( QPath :: TypeRelative ( ref ty, ref segment) ) = func. kind {
1647
+ if let TyKind :: Path ( QPath :: Resolved ( None , ref path) ) = ty. kind {
1648
+ let new_call = segment. ident . name == sym:: new;
1649
+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) && new_call;
1650
+ }
1651
+ }
1652
+ }
1653
+
1654
+ _ => { }
1655
+ }
1656
+
1657
+ false
1658
+ }
1659
+
1598
1660
#[ derive( RustcEncodable , RustcDecodable , Debug , HashStable ) ]
1599
1661
pub enum ExprKind {
1600
1662
/// A `box x` expression.
0 commit comments