about summary refs log tree commit diff
diff options
context:
space:
mode:
authoryukang <moorekang@gmail.com>2022-10-03 04:22:59 +0800
committeryukang <moorekang@gmail.com>2022-10-04 21:02:07 +0800
commite747201ad83d384a418dc2b31bf3d3024e2c2a3c (patch)
treecb59993f8896f444f4a766db912a828e024b1cb3
parent5dd44d4d4c4545f65f15f890e93fac68214cfe54 (diff)
downloadrust-e747201ad83d384a418dc2b31bf3d3024e2c2a3c.tar.gz
rust-e747201ad83d384a418dc2b31bf3d3024e2c2a3c.zip
find the correct lang item for ranges
-rw-r--r--compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl3
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/suggest.rs76
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs3
-rw-r--r--src/test/ui/methods/issues/issue-90315.rs28
-rw-r--r--src/test/ui/methods/issues/issue-90315.stderr66
5 files changed, 108 insertions, 68 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
index 827c3c93a73..5a7aee9c1c1 100644
--- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
@@ -133,8 +133,7 @@ hir_analysis_extern_crate_not_idiomatic =
     .suggestion = convert it to a `{$msg_code}`
 
 hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
-hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
 
-hir_analysis_missing_parentheses_in_range = `{$ty_str}` is not an iterator
+hir_analysis_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
 
 hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call the `{$func_name}` function
diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
index d7189e70d06..9aa1b2e2c0a 100644
--- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
@@ -13,7 +13,7 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{is_range_literal, ExprKind, Node, QPath};
+use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::traits::util::supertraits;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
@@ -1214,50 +1214,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty_str: &str,
     ) -> bool {
         if let SelfSource::MethodCall(expr) = source {
-            let mut search_limit = 5;
-            for (_, parent) in tcx.hir().parent_iter(expr.hir_id) {
-                search_limit -= 1;
-                if search_limit == 0 {
-                    break;
-                }
+            for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
+                if let Node::Expr(parent_expr) = parent {
+                    let lang_item = match parent_expr.kind {
+                        ExprKind::Struct(ref qpath, _, _) => match **qpath {
+                            QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
+                            QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
+                            QPath::LangItem(LangItem::RangeToInclusive, ..) => {
+                                Some(LangItem::RangeToInclusive)
+                            }
+                            _ => None,
+                        },
+                        ExprKind::Call(ref func, _) => match func.kind {
+                            // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+                            ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
+                                Some(LangItem::RangeInclusiveStruct)
+                            }
+                            _ => None,
+                        },
+                        _ => None,
+                    };
+
+                    if lang_item.is_none() {
+                        continue;
+                    }
 
-                if let Node::Expr(parent_expr) = parent && is_range_literal(parent_expr) {
                     let span_included = match parent_expr.kind {
-                            hir::ExprKind::Struct(_, eps, _) =>
-                                eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span)),
-                            // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
-                            hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
-                            _ => false,
+                        hir::ExprKind::Struct(_, eps, _) => {
+                            eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span))
+                        }
+                        // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+                        hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
+                        _ => false,
                     };
 
                     if !span_included {
                         continue;
                     }
 
-                    let range_def_id = self.tcx.lang_items().range_struct().unwrap();
-                    let range_ty = self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
-
-                    // avoid suggesting when the method name is not implemented for a `range`
-                    let pick =  self.lookup_probe(
-                        span,
-                        item_name,
-                        range_ty,
-                        expr,
-                        ProbeScope::AllTraits
-                    );
+                    debug!("lang_item: {:?}", lang_item);
+                    let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None);
+                    let range_ty =
+                        self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
 
+                    let pick =
+                        self.lookup_probe(span, item_name, range_ty, expr, ProbeScope::AllTraits);
                     if pick.is_ok() {
                         let range_span = parent_expr.span.with_hi(expr.span.hi());
                         tcx.sess.emit_err(errors::MissingParentheseInRange {
-                            span: span,
+                            span,
                             ty_str: ty_str.to_string(),
-                            add_missing_parentheses: Some(
-                                errors::AddMissingParenthesesInRange {
-                                    func_name: item_name.name.as_str().to_string(),
-                                    left: range_span.shrink_to_lo(),
-                                    right: range_span.shrink_to_hi(),
-                                }
-                            )
+                            method_name: item_name.as_str().to_string(),
+                            add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
+                                func_name: item_name.name.as_str().to_string(),
+                                left: range_span.shrink_to_lo(),
+                                right: range_span.shrink_to_hi(),
+                            }),
                         });
                         return true;
                     }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 6634444c636..41f73323d9a 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -348,12 +348,13 @@ pub struct ExpectedUsedSymbol {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::missing_parentheses_in_range, code = "E0599")]
+#[diag(hir_analysis::missing_parentheses_in_range, code = "E0689")]
 pub struct MissingParentheseInRange {
     #[primary_span]
     #[label(hir_analysis::missing_parentheses_in_range)]
     pub span: Span,
     pub ty_str: String,
+    pub method_name: String,
 
     #[subdiagnostic]
     pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
diff --git a/src/test/ui/methods/issues/issue-90315.rs b/src/test/ui/methods/issues/issue-90315.rs
index 74cd2b35834..79cdc41959a 100644
--- a/src/test/ui/methods/issues/issue-90315.rs
+++ b/src/test/ui/methods/issues/issue-90315.rs
@@ -2,7 +2,7 @@
 fn main() {
     let arr = &[0, 1, 2, 3];
     for _i in 0..arr.len().rev() {
-        //~^ ERROR not an iterator
+        //~^ ERROR can't call method
         //~| surround the range in parentheses
         // The above error used to say “the method `rev` exists for type `usize`”.
         // This regression test ensures it doesn't say that any more.
@@ -10,40 +10,40 @@ fn main() {
 
     // Test for #102396
     for i in 1..11.rev() {
-        //~^ ERROR not an iterator
+        //~^ ERROR can't call method
         //~| HELP surround the range in parentheses
     }
 
     let end: usize = 10;
     for i in 1..end.rev() {
-        //~^ ERROR not an iterator
+        //~^ ERROR can't call method
         //~| HELP surround the range in parentheses
     }
 
     for i in 1..(end + 1).rev() {
-        //~^ ERROR not an iterator
+        //~^ ERROR can't call method
         //~| HELP surround the range in parentheses
     }
 
     if 1..(end + 1).is_empty() {
-        //~^ ERROR not an iterator
+        //~^ ERROR can't call method
         //~| ERROR mismatched types [E0308]
         //~| HELP surround the range in parentheses
     }
 
     if 1..(end + 1).is_sorted() {
         //~^ ERROR mismatched types [E0308]
-        //~| ERROR `usize` is not an iterator [E0599]
+        //~| ERROR can't call method
         //~| HELP surround the range in parentheses
     }
 
     let _res: i32 = 3..6.take(2).sum();
-    //~^ ERROR `{integer}` is not an iterator [E0599]
+    //~^ ERROR can't call method
     //~| ERROR mismatched types [E0308]
     //~| HELP surround the range in parentheses
 
     let _sum: i32 = 3..6.sum();
-    //~^ ERROR `{integer}` is not an iterator [E0599]
+    //~^ ERROR can't call method
     //~| ERROR mismatched types [E0308]
     //~| HELP surround the range in parentheses
 
@@ -51,12 +51,12 @@ fn main() {
     let b = 10 as usize;
 
     for _a in a..=b.rev() {
-        //~^ ERROR not an iterator
+        //~^ ERROR can't call method
         //~| HELP surround the range in parentheses
     }
 
     let _res = ..10.contains(3);
-    //~^ ERROR not an iterator
+    //~^ ERROR can't call method
     //~| HELP surround the range in parentheses
 
     if 1..end.error_method() {
@@ -66,5 +66,11 @@ fn main() {
     }
 
     let _res = b.take(1)..a;
-    //~^ ERROR not an iterator
+    //~^ ERROR `usize` is not an iterator
+
+    let _res: i32 = ..6.take(2).sum();
+    //~^ can't call method `take` on ambiguous numeric type
+    //~| ERROR mismatched types [E0308]
+    //~| HELP you must specify a concrete type for this numeric value
+    // Won't suggest because `RangeTo` dest not implemented `take`
 }
diff --git a/src/test/ui/methods/issues/issue-90315.stderr b/src/test/ui/methods/issues/issue-90315.stderr
index f2084b593c2..581d6fb4fc9 100644
--- a/src/test/ui/methods/issues/issue-90315.stderr
+++ b/src/test/ui/methods/issues/issue-90315.stderr
@@ -1,52 +1,52 @@
-error[E0599]: `usize` is not an iterator
+error[E0689]: can't call method `rev` on type `usize`
   --> $DIR/issue-90315.rs:4:28
    |
 LL |     for _i in 0..arr.len().rev() {
-   |                            ^^^ `usize` is not an iterator
+   |                            ^^^ can't call method `rev` on type `usize`
    |
 help: you must surround the range in parentheses to call the `rev` function
    |
 LL |     for _i in (0..arr.len()).rev() {
    |               +            +
 
-error[E0599]: `{integer}` is not an iterator
+error[E0689]: can't call method `rev` on type `{integer}`
   --> $DIR/issue-90315.rs:12:20
    |
 LL |     for i in 1..11.rev() {
-   |                    ^^^ `{integer}` is not an iterator
+   |                    ^^^ can't call method `rev` on type `{integer}`
    |
 help: you must surround the range in parentheses to call the `rev` function
    |
 LL |     for i in (1..11).rev() {
    |              +     +
 
-error[E0599]: `usize` is not an iterator
+error[E0689]: can't call method `rev` on type `usize`
   --> $DIR/issue-90315.rs:18:21
    |
 LL |     for i in 1..end.rev() {
-   |                     ^^^ `usize` is not an iterator
+   |                     ^^^ can't call method `rev` on type `usize`
    |
 help: you must surround the range in parentheses to call the `rev` function
    |
 LL |     for i in (1..end).rev() {
    |              +      +
 
-error[E0599]: `usize` is not an iterator
+error[E0689]: can't call method `rev` on type `usize`
   --> $DIR/issue-90315.rs:23:27
    |
 LL |     for i in 1..(end + 1).rev() {
-   |                           ^^^ `usize` is not an iterator
+   |                           ^^^ can't call method `rev` on type `usize`
    |
 help: you must surround the range in parentheses to call the `rev` function
    |
 LL |     for i in (1..(end + 1)).rev() {
    |              +            +
 
-error[E0599]: `usize` is not an iterator
+error[E0689]: can't call method `is_empty` on type `usize`
   --> $DIR/issue-90315.rs:28:21
    |
 LL |     if 1..(end + 1).is_empty() {
-   |                     ^^^^^^^^ `usize` is not an iterator
+   |                     ^^^^^^^^ can't call method `is_empty` on type `usize`
    |
 help: you must surround the range in parentheses to call the `is_empty` function
    |
@@ -62,11 +62,11 @@ LL |     if 1..(end + 1).is_empty() {
    = note: expected type `bool`
             found struct `std::ops::Range<{integer}>`
 
-error[E0599]: `usize` is not an iterator
+error[E0689]: can't call method `is_sorted` on type `usize`
   --> $DIR/issue-90315.rs:34:21
    |
 LL |     if 1..(end + 1).is_sorted() {
-   |                     ^^^^^^^^^ `usize` is not an iterator
+   |                     ^^^^^^^^^ can't call method `is_sorted` on type `usize`
    |
 help: you must surround the range in parentheses to call the `is_sorted` function
    |
@@ -82,11 +82,11 @@ LL |     if 1..(end + 1).is_sorted() {
    = note: expected type `bool`
             found struct `std::ops::Range<{integer}>`
 
-error[E0599]: `{integer}` is not an iterator
+error[E0689]: can't call method `take` on type `{integer}`
   --> $DIR/issue-90315.rs:40:26
    |
 LL |     let _res: i32 = 3..6.take(2).sum();
-   |                          ^^^^ `{integer}` is not an iterator
+   |                          ^^^^ can't call method `take` on type `{integer}`
    |
 help: you must surround the range in parentheses to call the `take` function
    |
@@ -104,11 +104,11 @@ LL |     let _res: i32 = 3..6.take(2).sum();
    = note: expected type `i32`
             found struct `std::ops::Range<{integer}>`
 
-error[E0599]: `{integer}` is not an iterator
+error[E0689]: can't call method `sum` on type `{integer}`
   --> $DIR/issue-90315.rs:45:26
    |
 LL |     let _sum: i32 = 3..6.sum();
-   |                          ^^^ `{integer}` is not an iterator
+   |                          ^^^ can't call method `sum` on type `{integer}`
    |
 help: you must surround the range in parentheses to call the `sum` function
    |
@@ -126,22 +126,22 @@ LL |     let _sum: i32 = 3..6.sum();
    = note: expected type `i32`
             found struct `std::ops::Range<{integer}>`
 
-error[E0599]: `usize` is not an iterator
+error[E0689]: can't call method `rev` on type `usize`
   --> $DIR/issue-90315.rs:53:21
    |
 LL |     for _a in a..=b.rev() {
-   |                     ^^^ `usize` is not an iterator
+   |                     ^^^ can't call method `rev` on type `usize`
    |
 help: you must surround the range in parentheses to call the `rev` function
    |
 LL |     for _a in (a..=b).rev() {
    |               +     +
 
-error[E0599]: `{integer}` is not an iterator
+error[E0689]: can't call method `contains` on type `{integer}`
   --> $DIR/issue-90315.rs:58:21
    |
 LL |     let _res = ..10.contains(3);
-   |                     ^^^^^^^^ `{integer}` is not an iterator
+   |                     ^^^^^^^^ can't call method `contains` on type `{integer}`
    |
 help: you must surround the range in parentheses to call the `contains` function
    |
@@ -173,7 +173,29 @@ LL |     let _res = b.take(1)..a;
            `usize: Iterator`
            which is required by `&mut usize: Iterator`
 
-error: aborting due to 17 previous errors
+error[E0689]: can't call method `take` on ambiguous numeric type `{integer}`
+  --> $DIR/issue-90315.rs:71:25
+   |
+LL |     let _res: i32 = ..6.take(2).sum();
+   |                         ^^^^
+   |
+help: you must specify a concrete type for this numeric value, like `i32`
+   |
+LL |     let _res: i32 = ..6_i32.take(2).sum();
+   |                       ~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:71:21
+   |
+LL |     let _res: i32 = ..6.take(2).sum();
+   |               ---   ^^^^^^^^^^^^^^^^^ expected `i32`, found struct `RangeTo`
+   |               |
+   |               expected due to this
+   |
+   = note: expected type `i32`
+            found struct `RangeTo<_>`
+
+error: aborting due to 19 previous errors
 
-Some errors have detailed explanations: E0308, E0599.
+Some errors have detailed explanations: E0308, E0599, E0689.
 For more information about an error, try `rustc --explain E0308`.