Skip to content

Commit fa6ae4c

Browse files
committed
Suggest using slice when encountering let x = ""[..];
1 parent 71da1c2 commit fa6ae4c

File tree

4 files changed

+107
-0
lines changed

4 files changed

+107
-0
lines changed

src/librustc/hir/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,23 @@ impl Path {
244244
pub fn is_global(&self) -> bool {
245245
!self.segments.is_empty() && self.segments[0].name == keywords::CrateRoot.name()
246246
}
247+
248+
/// Wether this path is any of `::std::ops::{Range, RangeTo, RangeFrom}`.
249+
pub fn is_range(&self) -> bool {
250+
let mut base = ["{{root}}", "std", "ops"].iter().map(|p| p.to_string()).collect::<Vec<_>>();
251+
let range_paths = ["Range", "RangeTo", "RangeFrom"];
252+
let segments = self.segments.iter()
253+
.map(|segment| format!("{}", segment.name))
254+
.collect::<Vec<String>>();
255+
for path in &range_paths {
256+
base.push(path.to_string());
257+
if base == segments {
258+
return true;
259+
}
260+
base.pop();
261+
}
262+
false
263+
}
247264
}
248265

249266
impl fmt::Debug for Path {

src/librustc/traits/error_reporting.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
581581
trait_ref.self_ty()));
582582
}
583583

584+
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
585+
584586
// Try to report a help message
585587
if !trait_ref.has_infer_types() &&
586588
self.predicate_can_apply(obligation.param_env, trait_ref) {
@@ -821,6 +823,33 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
821823
err.emit();
822824
}
823825

826+
/// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
827+
/// suggestion to borrow the initializer in order to use have a slice instead.
828+
fn suggest_borrow_on_unsized_slice(&self,
829+
code: &ObligationCauseCode<'tcx>,
830+
err: &mut DiagnosticBuilder<'tcx>) {
831+
if let &ObligationCauseCode::VariableType(node_id) = code {
832+
let parent_node = self.tcx.hir.get_parent_node(node_id);
833+
if let Some(hir::map::NodeLocal(ref local)) = self.tcx.hir.find(parent_node) {
834+
if let Some(ref expr) = local.init {
835+
if let hir::ExprIndex(_, ref index) = expr.node {
836+
if let hir::ExprStruct(hir::QPath::Resolved(None, ref path),
837+
..) = index.node {
838+
if let (Ok(snippet), true) = (
839+
self.tcx.sess.codemap().span_to_snippet(expr.span),
840+
path.is_range()
841+
) {
842+
err.span_suggestion(expr.span,
843+
"consider a slice instead",
844+
format!("&{}", snippet));
845+
}
846+
}
847+
}
848+
}
849+
}
850+
}
851+
}
852+
824853
fn report_arg_count_mismatch(
825854
&self,
826855
span: Span,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2017 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+
fn main() {
12+
let s = "abc";
13+
let t = if true { s[..2] } else { s };
14+
let u: &str = if true { s[..2] } else { s };
15+
let v = s[..2];
16+
let w: &str = s[..2];
17+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error[E0308]: if and else have incompatible types
2+
--> $DIR/str-array-assignment.rs:13:11
3+
|
4+
13 | let t = if true { s[..2] } else { s };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected str, found &str
6+
|
7+
= note: expected type `str`
8+
found type `&str`
9+
10+
error[E0308]: mismatched types
11+
--> $DIR/str-array-assignment.rs:14:27
12+
|
13+
11 | fn main() {
14+
| - expected `()` because of default return type
15+
...
16+
14 | let u: &str = if true { s[..2] } else { s };
17+
| ^^^^^^ expected &str, found str
18+
|
19+
= note: expected type `&str`
20+
found type `str`
21+
22+
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
23+
--> $DIR/str-array-assignment.rs:15:7
24+
|
25+
15 | let v = s[..2];
26+
| ^ ------ help: consider a slice instead: `&s[..2]`
27+
| |
28+
| `str` does not have a constant size known at compile-time
29+
|
30+
= help: the trait `std::marker::Sized` is not implemented for `str`
31+
= note: all local variables must have a statically known size
32+
33+
error[E0308]: mismatched types
34+
--> $DIR/str-array-assignment.rs:16:17
35+
|
36+
16 | let w: &str = s[..2];
37+
| ^^^^^^ expected &str, found str
38+
|
39+
= note: expected type `&str`
40+
found type `str`
41+
= help: try with `&s[..2]`
42+
43+
error: aborting due to 4 previous errors
44+

0 commit comments

Comments
 (0)