Skip to content

Commit 0626afb

Browse files
committed
First stab at fixing #54505
1 parent 7e7bc06 commit 0626afb

File tree

6 files changed

+378
-3
lines changed

6 files changed

+378
-3
lines changed

src/librustc_typeck/check/demand.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
310310
if self.can_coerce(ref_ty, expected) {
311311
if let Ok(src) = cm.span_to_snippet(sp) {
312312
let sugg_expr = match expr.node { // parenthesize if needed (Issue #46756)
313-
hir::ExprKind::Cast(_, _) |
314-
hir::ExprKind::Binary(_, _, _) => format!("({})", src),
315-
_ => src,
313+
hir::ExprKind::Cast(_, _) |
314+
hir::ExprKind::Binary(_, _, _) |
315+
_ if self.is_range_literal(expr) => format!("({})", src),
316+
_ => src,
316317
};
317318
if let Some(sugg) = self.can_use_as_ref(expr) {
318319
return Some(sugg);
@@ -374,6 +375,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
374375
None
375376
}
376377

378+
// This function checks if the specified expression is a built-in range literal
379+
// (See: librustc/hir/lowering.rs::LoweringContext::lower_expr() )
380+
fn is_range_literal(&self, expr: &hir::Expr) -> bool {
381+
use hir::{Path, QPath, ExprKind, TyKind};
382+
383+
// TODO how to work out std vs core here?
384+
let ops_path = ["{{root}}", "std", "ops"];
385+
386+
let is_range_path = |path: &Path| {
387+
let ident_names: Vec<_> = path.segments
388+
.iter()
389+
.map(|seg| seg.ident.as_str())
390+
.collect();
391+
392+
if let Some((last, preceding)) = ident_names.split_last() {
393+
last.starts_with("Range") &&
394+
preceding.len() == 3 &&
395+
preceding.iter()
396+
.zip(ops_path.iter())
397+
.all(|(a, b)| a == b)
398+
} else {
399+
false
400+
}
401+
};
402+
403+
match expr.node {
404+
ExprKind::Struct(QPath::Resolved(None, ref path), _, _) |
405+
ExprKind::Path(QPath::Resolved(None, ref path)) => {
406+
return is_range_path(&path);
407+
}
408+
409+
ExprKind::Call(ref func, _) => {
410+
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
411+
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
412+
let calls_new = segment.ident.as_str() == "new";
413+
414+
return is_range_path(&path) && calls_new;
415+
}
416+
}
417+
}
418+
419+
_ => {}
420+
}
421+
422+
false
423+
}
424+
377425
pub fn check_for_cast(&self,
378426
err: &mut DiagnosticBuilder<'tcx>,
379427
expr: &hir::Expr,
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// run-rustfix
12+
13+
// Regression test for changes introduced while fixing #54505
14+
15+
// This test uses non-literals for Ranges
16+
// (expecting no parens with borrow suggestion)
17+
18+
use std::ops::RangeBounds;
19+
20+
21+
// take a reference to any built-in range
22+
fn take_range(_r: &impl RangeBounds<i8>) {}
23+
24+
25+
fn main() {
26+
take_range(std::ops::Range { start: 0, end: 1 });
27+
//~^ ERROR mismatched types [E0308]
28+
//~| HELP consider borrowing here
29+
//~| SUGGESTION &std::ops::Range { start: 0, end: 1 }
30+
31+
take_range(::std::ops::Range { start: 0, end: 1 });
32+
//~^ ERROR mismatched types [E0308]
33+
//~| HELP consider borrowing here
34+
//~| SUGGESTION &::std::ops::Range { start: 0, end: 1 }
35+
36+
take_range(std::ops::RangeFrom { start: 1 });
37+
//~^ ERROR mismatched types [E0308]
38+
//~| HELP consider borrowing here
39+
//~| SUGGESTION &std::ops::RangeFrom { start: 1 }
40+
41+
take_range(::std::ops::RangeFrom { start: 1 });
42+
//~^ ERROR mismatched types [E0308]
43+
//~| HELP consider borrowing here
44+
//~| SUGGESTION &::std::ops::RangeFrom { start: 1 }
45+
46+
take_range(std::ops::RangeFull {});
47+
//~^ ERROR mismatched types [E0308]
48+
//~| HELP consider borrowing here
49+
//~| SUGGESTION &std::ops::RangeFull {}
50+
51+
take_range(::std::ops::RangeFull {});
52+
//~^ ERROR mismatched types [E0308]
53+
//~| HELP consider borrowing here
54+
//~| SUGGESTION &::std::ops::RangeFull {}
55+
56+
take_range(std::ops::RangeInclusive::new(0, 1));
57+
//~^ ERROR mismatched types [E0308]
58+
//~| HELP consider borrowing here
59+
//~| SUGGESTION &std::ops::RangeInclusive::new(0, 1)
60+
61+
take_range(::std::ops::RangeInclusive::new(0, 1));
62+
//~^ ERROR mismatched types [E0308]
63+
//~| HELP consider borrowing here
64+
//~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1)
65+
66+
take_range(std::ops::RangeTo { end: 5 });
67+
//~^ ERROR mismatched types [E0308]
68+
//~| HELP consider borrowing here
69+
//~| SUGGESTION &std::ops::RangeTo { end: 5 }
70+
71+
take_range(::std::ops::RangeTo { end: 5 });
72+
//~^ ERROR mismatched types [E0308]
73+
//~| HELP consider borrowing here
74+
//~| SUGGESTION &::std::ops::RangeTo { end: 5 }
75+
76+
take_range(std::ops::RangeToInclusive { end: 5 });
77+
//~^ ERROR mismatched types [E0308]
78+
//~| HELP consider borrowing here
79+
//~| SUGGESTION &std::ops::RangeToInclusive { end: 5 }
80+
81+
take_range(::std::ops::RangeToInclusive { end: 5 });
82+
//~^ ERROR mismatched types [E0308]
83+
//~| HELP consider borrowing here
84+
//~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 }
85+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// run-rustfix
12+
// error-pattern: error: `#[panic_handler]` function required, but not found
13+
// error-pattern: language item required, but not found: `panic_info`
14+
15+
16+
// Regression test for #54505 - range borrowing suggestion had
17+
// incorrect syntax (missing parentheses).
18+
19+
// This test doesn't use std
20+
// (so all Ranges resolve to core::ops::Range...)
21+
22+
#![no_std]
23+
24+
use core::ops::RangeBounds;
25+
26+
27+
// take a reference to any built-in range
28+
fn take_range(_r: &impl RangeBounds<i8>) {}
29+
30+
31+
fn main() {
32+
take_range(0..1);
33+
//~^ ERROR mismatched types [E0308]
34+
//~| HELP consider borrowing here
35+
//~| SUGGESTION &(0..1)
36+
37+
take_range(1..);
38+
//~^ ERROR mismatched types [E0308]
39+
//~| HELP consider borrowing here
40+
//~| SUGGESTION &(1..)
41+
42+
take_range(..);
43+
//~^ ERROR mismatched types [E0308]
44+
//~| HELP consider borrowing here
45+
//~| SUGGESTION &(..)
46+
47+
take_range(0..=1);
48+
//~^ ERROR mismatched types [E0308]
49+
//~| HELP consider borrowing here
50+
//~| SUGGESTION &(0..=1)
51+
52+
take_range(..5);
53+
//~^ ERROR mismatched types [E0308]
54+
//~| HELP consider borrowing here
55+
//~| SUGGESTION &(..5)
56+
57+
take_range(..=42);
58+
//~^ ERROR mismatched types [E0308]
59+
//~| HELP consider borrowing here
60+
//~| SUGGESTION &(..=42)
61+
}

src/test/ui/range/issue-54505.fixed

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// run-rustfix
12+
13+
// Regression test for #54505 - range borrowing suggestion had
14+
// incorrect syntax (missing parentheses).
15+
16+
use std::ops::RangeBounds;
17+
18+
19+
// take a reference to any built-in range
20+
fn take_range(_r: &impl RangeBounds<i8>) {}
21+
22+
23+
fn main() {
24+
take_range(&(0..1));
25+
//~^ ERROR mismatched types [E0308]
26+
//~| HELP consider borrowing here
27+
//~| SUGGESTION &(0..1)
28+
29+
take_range(&(1..));
30+
//~^ ERROR mismatched types [E0308]
31+
//~| HELP consider borrowing here
32+
//~| SUGGESTION &(1..)
33+
34+
take_range(&(..));
35+
//~^ ERROR mismatched types [E0308]
36+
//~| HELP consider borrowing here
37+
//~| SUGGESTION &(..)
38+
39+
take_range(&(0..=1));
40+
//~^ ERROR mismatched types [E0308]
41+
//~| HELP consider borrowing here
42+
//~| SUGGESTION &(0..=1)
43+
44+
take_range(&(..5));
45+
//~^ ERROR mismatched types [E0308]
46+
//~| HELP consider borrowing here
47+
//~| SUGGESTION &(..5)
48+
49+
take_range(&(..=42));
50+
//~^ ERROR mismatched types [E0308]
51+
//~| HELP consider borrowing here
52+
//~| SUGGESTION &(..=42)
53+
}

src/test/ui/range/issue-54505.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// run-rustfix
12+
13+
// Regression test for #54505 - range borrowing suggestion had
14+
// incorrect syntax (missing parentheses).
15+
16+
use std::ops::RangeBounds;
17+
18+
19+
// take a reference to any built-in range
20+
fn take_range(_r: &impl RangeBounds<i8>) {}
21+
22+
23+
fn main() {
24+
take_range(0..1);
25+
//~^ ERROR mismatched types [E0308]
26+
//~| HELP consider borrowing here
27+
//~| SUGGESTION &(0..1)
28+
29+
take_range(1..);
30+
//~^ ERROR mismatched types [E0308]
31+
//~| HELP consider borrowing here
32+
//~| SUGGESTION &(1..)
33+
34+
take_range(..);
35+
//~^ ERROR mismatched types [E0308]
36+
//~| HELP consider borrowing here
37+
//~| SUGGESTION &(..)
38+
39+
take_range(0..=1);
40+
//~^ ERROR mismatched types [E0308]
41+
//~| HELP consider borrowing here
42+
//~| SUGGESTION &(0..=1)
43+
44+
take_range(..5);
45+
//~^ ERROR mismatched types [E0308]
46+
//~| HELP consider borrowing here
47+
//~| SUGGESTION &(..5)
48+
49+
take_range(..=42);
50+
//~^ ERROR mismatched types [E0308]
51+
//~| HELP consider borrowing here
52+
//~| SUGGESTION &(..=42)
53+
}

src/test/ui/range/issue-54505.stderr

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-54505.rs:24:16
3+
|
4+
LL | take_range(0..1);
5+
| ^^^^
6+
| |
7+
| expected reference, found struct `std::ops::Range`
8+
| help: consider borrowing here: `&(0..1)`
9+
|
10+
= note: expected type `&_`
11+
found type `std::ops::Range<{integer}>`
12+
13+
error[E0308]: mismatched types
14+
--> $DIR/issue-54505.rs:29:16
15+
|
16+
LL | take_range(1..);
17+
| ^^^
18+
| |
19+
| expected reference, found struct `std::ops::RangeFrom`
20+
| help: consider borrowing here: `&(1..)`
21+
|
22+
= note: expected type `&_`
23+
found type `std::ops::RangeFrom<{integer}>`
24+
25+
error[E0308]: mismatched types
26+
--> $DIR/issue-54505.rs:34:16
27+
|
28+
LL | take_range(..);
29+
| ^^
30+
| |
31+
| expected reference, found struct `std::ops::RangeFull`
32+
| help: consider borrowing here: `&(..)`
33+
|
34+
= note: expected type `&_`
35+
found type `std::ops::RangeFull`
36+
37+
error[E0308]: mismatched types
38+
--> $DIR/issue-54505.rs:39:16
39+
|
40+
LL | take_range(0..=1);
41+
| ^^^^^
42+
| |
43+
| expected reference, found struct `std::ops::RangeInclusive`
44+
| help: consider borrowing here: `&(0..=1)`
45+
|
46+
= note: expected type `&_`
47+
found type `std::ops::RangeInclusive<{integer}>`
48+
49+
error[E0308]: mismatched types
50+
--> $DIR/issue-54505.rs:44:16
51+
|
52+
LL | take_range(..5);
53+
| ^^^
54+
| |
55+
| expected reference, found struct `std::ops::RangeTo`
56+
| help: consider borrowing here: `&(..5)`
57+
|
58+
= note: expected type `&_`
59+
found type `std::ops::RangeTo<{integer}>`
60+
61+
error[E0308]: mismatched types
62+
--> $DIR/issue-54505.rs:49:16
63+
|
64+
LL | take_range(..=42);
65+
| ^^^^^
66+
| |
67+
| expected reference, found struct `std::ops::RangeToInclusive`
68+
| help: consider borrowing here: `&(..=42)`
69+
|
70+
= note: expected type `&_`
71+
found type `std::ops::RangeToInclusive<{integer}>`
72+
73+
error: aborting due to 6 previous errors
74+
75+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)