about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2017-11-24 14:47:40 -0800
committerEsteban Küber <esteban@kuber.com.ar>2017-11-25 06:08:30 -0800
commitfa6ae4c82872d4cd325072400a04e386f4004dc3 (patch)
treef962b080a96d91f5096334c22b3a3d3c44c645f8 /src
parent71da1c21ebc79f19e749344c8b4e2c13f533872e (diff)
downloadrust-fa6ae4c82872d4cd325072400a04e386f4004dc3.tar.gz
rust-fa6ae4c82872d4cd325072400a04e386f4004dc3.zip
Suggest using slice when encountering `let x = ""[..];`
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/mod.rs17
-rw-r--r--src/librustc/traits/error_reporting.rs29
-rw-r--r--src/test/ui/suggestions/str-array-assignment.rs17
-rw-r--r--src/test/ui/suggestions/str-array-assignment.stderr44
4 files changed, 107 insertions, 0 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 39ec33eef1f..986f1b9e419 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -244,6 +244,23 @@ impl Path {
     pub fn is_global(&self) -> bool {
         !self.segments.is_empty() && self.segments[0].name == keywords::CrateRoot.name()
     }
+
+    /// Wether this path is any of `::std::ops::{Range, RangeTo, RangeFrom}`.
+    pub fn is_range(&self) -> bool {
+        let mut base = ["{{root}}", "std", "ops"].iter().map(|p| p.to_string()).collect::<Vec<_>>();
+        let range_paths = ["Range", "RangeTo", "RangeFrom"];
+        let segments = self.segments.iter()
+            .map(|segment| format!("{}", segment.name))
+            .collect::<Vec<String>>();
+        for path in &range_paths {
+            base.push(path.to_string());
+            if base == segments {
+                return true;
+            }
+            base.pop();
+        }
+        false
+    }
 }
 
 impl fmt::Debug for Path {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 46ec2be4a1f..a8a8b20012b 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -581,6 +581,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                      trait_ref.self_ty()));
                         }
 
+                        self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
+
                         // Try to report a help message
                         if !trait_ref.has_infer_types() &&
                             self.predicate_can_apply(obligation.param_env, trait_ref) {
@@ -821,6 +823,33 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         err.emit();
     }
 
+    /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
+    /// suggestion to borrow the initializer in order to use have a slice instead.
+    fn suggest_borrow_on_unsized_slice(&self,
+                                       code: &ObligationCauseCode<'tcx>,
+                                       err: &mut DiagnosticBuilder<'tcx>) {
+        if let &ObligationCauseCode::VariableType(node_id) = code {
+            let parent_node = self.tcx.hir.get_parent_node(node_id);
+            if let Some(hir::map::NodeLocal(ref local)) = self.tcx.hir.find(parent_node) {
+                if let Some(ref expr) = local.init {
+                    if let hir::ExprIndex(_, ref index) = expr.node {
+                        if let hir::ExprStruct(hir::QPath::Resolved(None, ref path),
+                                               ..) = index.node {
+                            if let (Ok(snippet), true) = (
+                                self.tcx.sess.codemap().span_to_snippet(expr.span),
+                                path.is_range()
+                            ) {
+                                err.span_suggestion(expr.span,
+                                                    "consider a slice instead",
+                                                    format!("&{}", snippet));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     fn report_arg_count_mismatch(
         &self,
         span: Span,
diff --git a/src/test/ui/suggestions/str-array-assignment.rs b/src/test/ui/suggestions/str-array-assignment.rs
new file mode 100644
index 00000000000..523e7bea622
--- /dev/null
+++ b/src/test/ui/suggestions/str-array-assignment.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+  let s = "abc";
+  let t = if true { s[..2] } else { s };
+  let u: &str = if true { s[..2] } else { s };
+  let v = s[..2];
+  let w: &str = s[..2];
+}
diff --git a/src/test/ui/suggestions/str-array-assignment.stderr b/src/test/ui/suggestions/str-array-assignment.stderr
new file mode 100644
index 00000000000..225dfbd98fd
--- /dev/null
+++ b/src/test/ui/suggestions/str-array-assignment.stderr
@@ -0,0 +1,44 @@
+error[E0308]: if and else have incompatible types
+  --> $DIR/str-array-assignment.rs:13:11
+   |
+13 |   let t = if true { s[..2] } else { s };
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected str, found &str
+   |
+   = note: expected type `str`
+              found type `&str`
+
+error[E0308]: mismatched types
+  --> $DIR/str-array-assignment.rs:14:27
+   |
+11 | fn main() {
+   |           - expected `()` because of default return type
+...
+14 |   let u: &str = if true { s[..2] } else { s };
+   |                           ^^^^^^ expected &str, found str
+   |
+   = note: expected type `&str`
+              found type `str`
+
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+  --> $DIR/str-array-assignment.rs:15:7
+   |
+15 |   let v = s[..2];
+   |       ^   ------ help: consider a slice instead: `&s[..2]`
+   |       |
+   |       `str` does not have a constant size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `str`
+   = note: all local variables must have a statically known size
+
+error[E0308]: mismatched types
+  --> $DIR/str-array-assignment.rs:16:17
+   |
+16 |   let w: &str = s[..2];
+   |                 ^^^^^^ expected &str, found str
+   |
+   = note: expected type `&str`
+              found type `str`
+   = help: try with `&s[..2]`
+
+error: aborting due to 4 previous errors
+