From 7930f9a368c055db249a0378c1533aaedc7b037b Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 22 Jun 2020 20:52:44 -0700 Subject: [PATCH] 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 --- src/librustc_hir/hir.rs | 8 +----- .../issue-73553-misinterp-range-literal.rs | 16 +++++++++++ ...issue-73553-misinterp-range-literal.stderr | 27 +++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/range/issue-73553-misinterp-range-literal.rs create mode 100644 src/test/ui/range/issue-73553-misinterp-range-literal.stderr 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 @@ fn is_range_path(path: &Path<'_>) -> 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; + +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` + found struct `std::ops::Range` + +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` + found struct `std::ops::Range<{integer}>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. -- 2.44.0