about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-06-24 14:28:39 +0200
committerGitHub <noreply@github.com>2020-06-24 14:28:39 +0200
commit1d1c40032429d681fcd6bb0cf071ffecdaeeab02 (patch)
tree40a67c3c4549cc7505a46f325606374ac2606174
parent38c85b739314e2b5dedf8ff11feec53463261de4 (diff)
parent7930f9a368c055db249a0378c1533aaedc7b037b (diff)
downloadrust-1d1c40032429d681fcd6bb0cf071ffecdaeeab02.tar.gz
rust-1d1c40032429d681fcd6bb0cf071ffecdaeeab02.zip
Rollup merge of #73639 - ayazhafiz:i/73553, r=davidtwco
Change heuristic for determining range literal

Currently, rustc uses a heuristic to determine if a range expression is
not a literal based on whether the expression looks like a function call
or struct initialization. This fails for range literals whose
lower/upper bounds are the results of function calls. A possibly-better
heuristic is to check if the expression contains `..`, required in range
literals.

Of course, this is also not perfect; for example, if the range
expression is a struct which includes some text with `..` this will
fail, but in general I believe it is a better heuristic.

A better alternative altogether is to add the `QPath::LangItem` enum
variant suggested in #60607. I would be happy to do this as a precursor
to this patch if someone is able to provide general suggestions on how
usages of `QPath` need to be changed later in the compiler with the
`LangItem` variant.

Closes #73553
-rw-r--r--src/librustc_hir/hir.rs8
-rw-r--r--src/test/ui/range/issue-73553-misinterp-range-literal.rs16
-rw-r--r--src/test/ui/range/issue-73553-misinterp-range-literal.stderr27
3 files changed, 44 insertions, 7 deletions
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index 7d1cb7738c3..f3dfec7ca72 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -1511,13 +1511,7 @@ pub fn is_range_literal(sm: &SourceMap, expr: &Expr<'_>) -> bool {
     // Check whether a span corresponding to a range expression is a
     // range literal, rather than an explicit struct or `new()` call.
     fn is_lit(sm: &SourceMap, span: &Span) -> bool {
-        let end_point = sm.end_point(*span);
-
-        if let Ok(end_string) = sm.span_to_snippet(end_point) {
-            !(end_string.ends_with('}') || end_string.ends_with(')'))
-        } else {
-            false
-        }
+        sm.span_to_snippet(*span).map(|range_src| range_src.contains("..")).unwrap_or(false)
     };
 
     match expr.kind {
diff --git a/src/test/ui/range/issue-73553-misinterp-range-literal.rs b/src/test/ui/range/issue-73553-misinterp-range-literal.rs
new file mode 100644
index 00000000000..e65dba0a038
--- /dev/null
+++ b/src/test/ui/range/issue-73553-misinterp-range-literal.rs
@@ -0,0 +1,16 @@
+type Range = std::ops::Range<usize>;
+
+fn demo(r: &Range) {
+    println!("{:?}", r);
+}
+
+fn tell(x: usize) -> usize {
+    x
+}
+
+fn main() {
+    demo(tell(1)..tell(10));
+    //~^ ERROR mismatched types
+    demo(1..10);
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/range/issue-73553-misinterp-range-literal.stderr b/src/test/ui/range/issue-73553-misinterp-range-literal.stderr
new file mode 100644
index 00000000000..5167b87fd27
--- /dev/null
+++ b/src/test/ui/range/issue-73553-misinterp-range-literal.stderr
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-73553-misinterp-range-literal.rs:12:10
+   |
+LL |     demo(tell(1)..tell(10));
+   |          ^^^^^^^^^^^^^^^^^
+   |          |
+   |          expected reference, found struct `std::ops::Range`
+   |          help: consider borrowing here: `&(tell(1)..tell(10))`
+   |
+   = note: expected reference `&std::ops::Range<usize>`
+                 found struct `std::ops::Range<usize>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-73553-misinterp-range-literal.rs:14:10
+   |
+LL |     demo(1..10);
+   |          ^^^^^
+   |          |
+   |          expected reference, found struct `std::ops::Range`
+   |          help: consider borrowing here: `&(1..10)`
+   |
+   = note: expected reference `&std::ops::Range<usize>`
+                 found struct `std::ops::Range<{integer}>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.