@@ -1595,6 +1595,68 @@ impl fmt::Debug for Expr {
15951595 }
15961596}
15971597
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+
15981660#[ derive( RustcEncodable , RustcDecodable , Debug , HashStable ) ]
15991661pub enum ExprKind {
16001662 /// A `box x` expression.
0 commit comments