@@ -5400,3 +5400,65 @@ fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
54005400 body_ids. sort_by_key ( |b| bodies[ b] . value . span ) ;
54015401 body_ids
54025402}
5403+
5404+ /// Checks if the specified expression is a built-in range literal.
5405+ /// (See: `LoweringContext::lower_expr()`).
5406+ pub fn is_range_literal ( sess : & Session , expr : & hir:: Expr ) -> bool {
5407+ use hir:: { Path , QPath , ExprKind , TyKind } ;
5408+
5409+ // Returns whether the given path represents a (desugared) range,
5410+ // either in std or core, i.e. has either a `::std::ops::Range` or
5411+ // `::core::ops::Range` prefix.
5412+ fn is_range_path ( path : & Path ) -> bool {
5413+ let segs: Vec < _ > = path. segments . iter ( ) . map ( |seg| seg. ident . as_str ( ) . to_string ( ) ) . collect ( ) ;
5414+ let segs: Vec < _ > = segs. iter ( ) . map ( |seg| & * * seg) . collect ( ) ;
5415+
5416+ // "{{root}}" is the equivalent of `::` prefix in `Path`.
5417+ if let [ "{{root}}" , std_core, "ops" , range] = segs. as_slice ( ) {
5418+ ( * std_core == "std" || * std_core == "core" ) && range. starts_with ( "Range" )
5419+ } else {
5420+ false
5421+ }
5422+ } ;
5423+
5424+ // Check whether a span corresponding to a range expression is a
5425+ // range literal, rather than an explicit struct or `new()` call.
5426+ fn is_lit ( sess : & Session , span : & Span ) -> bool {
5427+ let source_map = sess. source_map ( ) ;
5428+ let end_point = source_map. end_point ( * span) ;
5429+
5430+ if let Ok ( end_string) = source_map. span_to_snippet ( end_point) {
5431+ !( end_string. ends_with ( "}" ) || end_string. ends_with ( ")" ) )
5432+ } else {
5433+ false
5434+ }
5435+ } ;
5436+
5437+ match expr. node {
5438+ // All built-in range literals but `..=` and `..` desugar to `Struct`s.
5439+ ExprKind :: Struct ( ref qpath, _, _) => {
5440+ if let QPath :: Resolved ( None , ref path) = * * qpath {
5441+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) ;
5442+ }
5443+ }
5444+
5445+ // `..` desugars to its struct path.
5446+ ExprKind :: Path ( QPath :: Resolved ( None , ref path) ) => {
5447+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) ;
5448+ }
5449+
5450+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
5451+ ExprKind :: Call ( ref func, _) => {
5452+ if let ExprKind :: Path ( QPath :: TypeRelative ( ref ty, ref segment) ) = func. node {
5453+ if let TyKind :: Path ( QPath :: Resolved ( None , ref path) ) = ty. node {
5454+ let new_call = segment. ident . as_str ( ) == "new" ;
5455+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) && new_call;
5456+ }
5457+ }
5458+ }
5459+
5460+ _ => { }
5461+ }
5462+
5463+ false
5464+ }
0 commit comments