@@ -1564,6 +1564,68 @@ impl fmt::Debug for Expr {
1564
1564
}
1565
1565
}
1566
1566
1567
+ /// Checks if the specified expression is a built-in range literal.
1568
+ /// (See: `LoweringContext::lower_expr()`).
1569
+ pub fn is_range_literal ( sess : & Session , expr : & hir:: Expr ) -> bool {
1570
+ use hir:: { Path , QPath , ExprKind , TyKind } ;
1571
+
1572
+ // Returns whether the given path represents a (desugared) range,
1573
+ // either in std or core, i.e. has either a `::std::ops::Range` or
1574
+ // `::core::ops::Range` prefix.
1575
+ fn is_range_path ( path : & Path ) -> bool {
1576
+ let segs: Vec < _ > = path. segments . iter ( ) . map ( |seg| seg. ident . to_string ( ) ) . collect ( ) ;
1577
+ let segs: Vec < _ > = segs. iter ( ) . map ( |seg| & * * seg) . collect ( ) ;
1578
+
1579
+ // "{{root}}" is the equivalent of `::` prefix in `Path`.
1580
+ if let [ "{{root}}" , std_core, "ops" , range] = segs. as_slice ( ) {
1581
+ ( * std_core == "std" || * std_core == "core" ) && range. starts_with ( "Range" )
1582
+ } else {
1583
+ false
1584
+ }
1585
+ } ;
1586
+
1587
+ // Check whether a span corresponding to a range expression is a
1588
+ // range literal, rather than an explicit struct or `new()` call.
1589
+ fn is_lit ( sess : & Session , span : & Span ) -> bool {
1590
+ let source_map = sess. source_map ( ) ;
1591
+ let end_point = source_map. end_point ( * span) ;
1592
+
1593
+ if let Ok ( end_string) = source_map. span_to_snippet ( end_point) {
1594
+ !( end_string. ends_with ( "}" ) || end_string. ends_with ( ")" ) )
1595
+ } else {
1596
+ false
1597
+ }
1598
+ } ;
1599
+
1600
+ match expr. kind {
1601
+ // All built-in range literals but `..=` and `..` desugar to `Struct`s.
1602
+ ExprKind :: Struct ( ref qpath, _, _) => {
1603
+ if let QPath :: Resolved ( None , ref path) = * * qpath {
1604
+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) ;
1605
+ }
1606
+ }
1607
+
1608
+ // `..` desugars to its struct path.
1609
+ ExprKind :: Path ( QPath :: Resolved ( None , ref path) ) => {
1610
+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) ;
1611
+ }
1612
+
1613
+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
1614
+ ExprKind :: Call ( ref func, _) => {
1615
+ if let ExprKind :: Path ( QPath :: TypeRelative ( ref ty, ref segment) ) = func. kind {
1616
+ if let TyKind :: Path ( QPath :: Resolved ( None , ref path) ) = ty. kind {
1617
+ let new_call = segment. ident . name == sym:: new;
1618
+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) && new_call;
1619
+ }
1620
+ }
1621
+ }
1622
+
1623
+ _ => { }
1624
+ }
1625
+
1626
+ false
1627
+ }
1628
+
1567
1629
#[ derive( RustcEncodable , RustcDecodable , Debug , HashStable ) ]
1568
1630
pub enum ExprKind {
1569
1631
/// A `box x` expression.
0 commit comments