@@ -1564,6 +1564,68 @@ impl fmt::Debug for Expr {
15641564 }
15651565}
15661566
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+
15671629#[ derive( RustcEncodable , RustcDecodable , Debug , HashStable ) ]
15681630pub enum ExprKind {
15691631 /// A `box x` expression.
0 commit comments