Skip to content

Commit

Permalink
Change heuristic for determining range literal
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ayazhafiz committed Jun 23, 2020
1 parent cbf356a commit 7930f9a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 7 deletions.
8 changes: 1 addition & 7 deletions src/librustc_hir/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/range/issue-73553-misinterp-range-literal.rs
Original file line number Diff line number Diff line change
@@ -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
}
27 changes: 27 additions & 0 deletions src/test/ui/range/issue-73553-misinterp-range-literal.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 7930f9a

Please sign in to comment.