From 5dd44d4d4c4545f65f15f890e93fac68214cfe54 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 29 Sep 2022 13:16:47 +0800 Subject: [PATCH 1/3] fix #102396, suggest parentheses for possible range methods --- .../locales/en-US/hir_analysis.ftl | 5 + .../src/check/method/suggest.rs | 75 +++++++- compiler/rustc_hir_analysis/src/errors.rs | 25 +++ src/test/ui/methods/issues/issue-90315.rs | 73 +++++++- src/test/ui/methods/issues/issue-90315.stderr | 176 +++++++++++++++++- 5 files changed, 339 insertions(+), 15 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 c6a4ff6f0e0..827c3c93a73 100644 --- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl +++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl @@ -133,3 +133,8 @@ 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_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 0e82e4956c7..d7189e70d06 100644 --- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs +++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs @@ -2,6 +2,7 @@ //! found or is otherwise invalid. use crate::check::FnCtxt; +use crate::errors; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ @@ -12,7 +13,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, Node, QPath}; +use rustc_hir::{is_range_literal, 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}; @@ -271,9 +272,11 @@ pub fn report_method_error( } }; - if self.suggest_constraining_numerical_ty( - tcx, actual, source, span, item_kind, item_name, &ty_str, - ) { + if self.suggest_range_for_iter(tcx, actual, source, span, item_name, &ty_str) + || self.suggest_constraining_numerical_ty( + tcx, actual, source, span, item_kind, item_name, &ty_str, + ) + { return None; } @@ -1201,6 +1204,69 @@ fn suggest_field_call( false } + fn suggest_range_for_iter( + &self, + tcx: TyCtxt<'tcx>, + actual: Ty<'tcx>, + source: SelfSource<'tcx>, + span: Span, + item_name: Ident, + 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; + } + + 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, + }; + + 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 + ); + + if pick.is_ok() { + let range_span = parent_expr.span.with_hi(expr.span.hi()); + tcx.sess.emit_err(errors::MissingParentheseInRange { + 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(), + } + ) + }); + return true; + } + } + } + } + false + } + fn suggest_constraining_numerical_ty( &self, tcx: TyCtxt<'tcx>, @@ -1263,7 +1329,6 @@ fn suggest_constraining_numerical_ty( // If this is a floating point literal that ends with '.', // get rid of it to stop this from becoming a member access. let snippet = snippet.strip_suffix('.').unwrap_or(&snippet); - err.span_suggestion( lit.span, &format!( diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index d891171b824..6634444c636 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -346,3 +346,28 @@ pub struct ExpectedUsedSymbol { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis::missing_parentheses_in_range, code = "E0599")] +pub struct MissingParentheseInRange { + #[primary_span] + #[label(hir_analysis::missing_parentheses_in_range)] + pub span: Span, + pub ty_str: String, + + #[subdiagnostic] + pub add_missing_parentheses: Option, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion_verbose( + hir_analysis::add_missing_parentheses_in_range, + applicability = "maybe-incorrect" +)] +pub struct AddMissingParenthesesInRange { + pub func_name: String, + #[suggestion_part(code = "(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} diff --git a/src/test/ui/methods/issues/issue-90315.rs b/src/test/ui/methods/issues/issue-90315.rs index 01bf9f48402..74cd2b35834 100644 --- a/src/test/ui/methods/issues/issue-90315.rs +++ b/src/test/ui/methods/issues/issue-90315.rs @@ -1,7 +1,70 @@ +#![allow(unused)] fn main() { - let arr = &[0,1,2,3]; - for _i in 0..arr.len().rev() { //~ERROR not an iterator - // The above error used to say “the method `rev` exists for type `usize`”. - // This regression test ensures it doesn't say that any more. - } + let arr = &[0, 1, 2, 3]; + for _i in 0..arr.len().rev() { + //~^ ERROR not an iterator + //~| 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. + } + + // Test for #102396 + for i in 1..11.rev() { + //~^ ERROR not an iterator + //~| HELP surround the range in parentheses + } + + let end: usize = 10; + for i in 1..end.rev() { + //~^ ERROR not an iterator + //~| HELP surround the range in parentheses + } + + for i in 1..(end + 1).rev() { + //~^ ERROR not an iterator + //~| HELP surround the range in parentheses + } + + if 1..(end + 1).is_empty() { + //~^ ERROR not an iterator + //~| 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] + //~| HELP surround the range in parentheses + } + + let _res: i32 = 3..6.take(2).sum(); + //~^ ERROR `{integer}` is not an iterator [E0599] + //~| ERROR mismatched types [E0308] + //~| HELP surround the range in parentheses + + let _sum: i32 = 3..6.sum(); + //~^ ERROR `{integer}` is not an iterator [E0599] + //~| ERROR mismatched types [E0308] + //~| HELP surround the range in parentheses + + let a = 1 as usize; + let b = 10 as usize; + + for _a in a..=b.rev() { + //~^ ERROR not an iterator + //~| HELP surround the range in parentheses + } + + let _res = ..10.contains(3); + //~^ ERROR not an iterator + //~| HELP surround the range in parentheses + + if 1..end.error_method() { + //~^ ERROR no method named `error_method` + //~| ERROR mismatched types [E0308] + // Won't suggest + } + + let _res = b.take(1)..a; + //~^ ERROR not an iterator } diff --git a/src/test/ui/methods/issues/issue-90315.stderr b/src/test/ui/methods/issues/issue-90315.stderr index c6a76c9e790..f2084b593c2 100644 --- a/src/test/ui/methods/issues/issue-90315.stderr +++ b/src/test/ui/methods/issues/issue-90315.stderr @@ -1,13 +1,179 @@ error[E0599]: `usize` is not an iterator - --> $DIR/issue-90315.rs:3:26 + --> $DIR/issue-90315.rs:4:28 | -LL | for _i in 0..arr.len().rev() { - | ^^^ `usize` is not an iterator +LL | for _i in 0..arr.len().rev() { + | ^^^ `usize` is not an iterator + | +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 + --> $DIR/issue-90315.rs:12:20 + | +LL | for i in 1..11.rev() { + | ^^^ `{integer}` is not an iterator + | +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 + --> $DIR/issue-90315.rs:18:21 + | +LL | for i in 1..end.rev() { + | ^^^ `usize` is not an iterator + | +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 + --> $DIR/issue-90315.rs:23:27 + | +LL | for i in 1..(end + 1).rev() { + | ^^^ `usize` is not an iterator + | +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 + --> $DIR/issue-90315.rs:28:21 + | +LL | if 1..(end + 1).is_empty() { + | ^^^^^^^^ `usize` is not an iterator + | +help: you must surround the range in parentheses to call the `is_empty` function + | +LL | if (1..(end + 1)).is_empty() { + | + + + +error[E0308]: mismatched types + --> $DIR/issue-90315.rs:28:8 + | +LL | if 1..(end + 1).is_empty() { + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` + | + = note: expected type `bool` + found struct `std::ops::Range<{integer}>` + +error[E0599]: `usize` is not an iterator + --> $DIR/issue-90315.rs:34:21 + | +LL | if 1..(end + 1).is_sorted() { + | ^^^^^^^^^ `usize` is not an iterator + | +help: you must surround the range in parentheses to call the `is_sorted` function + | +LL | if (1..(end + 1)).is_sorted() { + | + + + +error[E0308]: mismatched types + --> $DIR/issue-90315.rs:34:8 + | +LL | if 1..(end + 1).is_sorted() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` + | + = note: expected type `bool` + found struct `std::ops::Range<{integer}>` + +error[E0599]: `{integer}` is not an iterator + --> $DIR/issue-90315.rs:40:26 + | +LL | let _res: i32 = 3..6.take(2).sum(); + | ^^^^ `{integer}` is not an iterator + | +help: you must surround the range in parentheses to call the `take` function + | +LL | let _res: i32 = (3..6).take(2).sum(); + | + + + +error[E0308]: mismatched types + --> $DIR/issue-90315.rs:40:21 + | +LL | let _res: i32 = 3..6.take(2).sum(); + | --- ^^^^^^^^^^^^^^^^^^ expected `i32`, found struct `std::ops::Range` + | | + | expected due to this + | + = note: expected type `i32` + found struct `std::ops::Range<{integer}>` + +error[E0599]: `{integer}` is not an iterator + --> $DIR/issue-90315.rs:45:26 + | +LL | let _sum: i32 = 3..6.sum(); + | ^^^ `{integer}` is not an iterator + | +help: you must surround the range in parentheses to call the `sum` function + | +LL | let _sum: i32 = (3..6).sum(); + | + + + +error[E0308]: mismatched types + --> $DIR/issue-90315.rs:45:21 + | +LL | let _sum: i32 = 3..6.sum(); + | --- ^^^^^^^^^^ expected `i32`, found struct `std::ops::Range` + | | + | expected due to this + | + = note: expected type `i32` + found struct `std::ops::Range<{integer}>` + +error[E0599]: `usize` is not an iterator + --> $DIR/issue-90315.rs:53:21 + | +LL | for _a in a..=b.rev() { + | ^^^ `usize` is not an iterator + | +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 + --> $DIR/issue-90315.rs:58:21 + | +LL | let _res = ..10.contains(3); + | ^^^^^^^^ `{integer}` is not an iterator + | +help: you must surround the range in parentheses to call the `contains` function + | +LL | let _res = (..10).contains(3); + | + + + +error[E0599]: no method named `error_method` found for type `usize` in the current scope + --> $DIR/issue-90315.rs:62:15 + | +LL | if 1..end.error_method() { + | ^^^^^^^^^^^^ method not found in `usize` + +error[E0308]: mismatched types + --> $DIR/issue-90315.rs:62:8 + | +LL | if 1..end.error_method() { + | ^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` + | + = note: expected type `bool` + found struct `std::ops::Range<{integer}>` + +error[E0599]: `usize` is not an iterator + --> $DIR/issue-90315.rs:68:18 + | +LL | let _res = b.take(1)..a; + | ^^^^ `usize` is not an iterator | = note: the following trait bounds were not satisfied: `usize: Iterator` which is required by `&mut usize: Iterator` -error: aborting due to previous error +error: aborting due to 17 previous errors -For more information about this error, try `rustc --explain E0599`. +Some errors have detailed explanations: E0308, E0599. +For more information about an error, try `rustc --explain E0308`. From e747201ad83d384a418dc2b31bf3d3024e2c2a3c Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 3 Oct 2022 04:22:59 +0800 Subject: [PATCH 2/3] find the correct lang item for ranges --- .../locales/en-US/hir_analysis.ftl | 3 +- .../src/check/method/suggest.rs | 78 +++++++++++-------- compiler/rustc_hir_analysis/src/errors.rs | 3 +- src/test/ui/methods/issues/issue-90315.rs | 28 ++++--- src/test/ui/methods/issues/issue-90315.stderr | 66 ++++++++++------ 5 files changed, 109 insertions(+), 69 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::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 @@ fn suggest_range_for_iter( 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; - } - - 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)), + 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(...)`. - hir::ExprKind::Call(ref func, ..) => func.span.contains(span), - _ => false, + ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => { + Some(LangItem::RangeInclusiveStruct) + } + _ => None, + }, + _ => None, + }; + + if lang_item.is_none() { + continue; + } + + 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, }; 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, 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(); + | ~~~~~ -Some errors have detailed explanations: E0308, E0599. +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, E0689. For more information about an error, try `rustc --explain E0308`. From 151001c1cb1c054d7f259e90ed44b31c25ba2db7 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 17 Oct 2022 08:32:08 +0800 Subject: [PATCH 3/3] trivial fix for comments feedback --- .../locales/en-US/hir_analysis.ftl | 2 +- .../src/check/method/suggest.rs | 26 ++++++++++++------- src/test/ui/methods/issues/issue-90315.stderr | 20 +++++++------- 3 files changed, 28 insertions(+), 20 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 5a7aee9c1c1..357c6900a70 100644 --- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl +++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl @@ -136,4 +136,4 @@ hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(l 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 +hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$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 9aa1b2e2c0a..6e9ea5d7f52 100644 --- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs +++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs @@ -272,11 +272,11 @@ pub fn report_method_error( } }; - if self.suggest_range_for_iter(tcx, actual, source, span, item_name, &ty_str) - || self.suggest_constraining_numerical_ty( - tcx, actual, source, span, item_kind, item_name, &ty_str, - ) - { + if self.suggest_wrapping_range_with_parens( + tcx, actual, source, span, item_name, &ty_str, + ) || self.suggest_constraining_numerical_ty( + tcx, actual, source, span, item_kind, item_name, &ty_str, + ) { return None; } @@ -1204,7 +1204,9 @@ fn suggest_field_call( false } - fn suggest_range_for_iter( + /// Suggest possible range with adding parentheses, for example: + /// when encountering `0..1.map(|i| i + 1)` suggest `(0..1).map(|i| i + 1)`. + fn suggest_wrapping_range_with_parens( &self, tcx: TyCtxt<'tcx>, actual: Ty<'tcx>, @@ -1252,13 +1254,19 @@ fn suggest_range_for_iter( continue; } - 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); + let pick = self.probe_for_name( + span, + Mode::MethodCall, + item_name, + IsSuggestion(true), + range_ty, + expr.hir_id, + ProbeScope::AllTraits, + ); if pick.is_ok() { let range_span = parent_expr.span.with_hi(expr.span.hi()); tcx.sess.emit_err(errors::MissingParentheseInRange { diff --git a/src/test/ui/methods/issues/issue-90315.stderr b/src/test/ui/methods/issues/issue-90315.stderr index 581d6fb4fc9..070cd305436 100644 --- a/src/test/ui/methods/issues/issue-90315.stderr +++ b/src/test/ui/methods/issues/issue-90315.stderr @@ -4,7 +4,7 @@ error[E0689]: can't call method `rev` on type `usize` LL | for _i in 0..arr.len().rev() { | ^^^ can't call method `rev` on type `usize` | -help: you must surround the range in parentheses to call the `rev` function +help: you must surround the range in parentheses to call its `rev` function | LL | for _i in (0..arr.len()).rev() { | + + @@ -15,7 +15,7 @@ error[E0689]: can't call method `rev` on type `{integer}` LL | for i in 1..11.rev() { | ^^^ can't call method `rev` on type `{integer}` | -help: you must surround the range in parentheses to call the `rev` function +help: you must surround the range in parentheses to call its `rev` function | LL | for i in (1..11).rev() { | + + @@ -26,7 +26,7 @@ error[E0689]: can't call method `rev` on type `usize` LL | for i in 1..end.rev() { | ^^^ can't call method `rev` on type `usize` | -help: you must surround the range in parentheses to call the `rev` function +help: you must surround the range in parentheses to call its `rev` function | LL | for i in (1..end).rev() { | + + @@ -37,7 +37,7 @@ error[E0689]: can't call method `rev` on type `usize` LL | for i in 1..(end + 1).rev() { | ^^^ can't call method `rev` on type `usize` | -help: you must surround the range in parentheses to call the `rev` function +help: you must surround the range in parentheses to call its `rev` function | LL | for i in (1..(end + 1)).rev() { | + + @@ -48,7 +48,7 @@ error[E0689]: can't call method `is_empty` on type `usize` LL | if 1..(end + 1).is_empty() { | ^^^^^^^^ can't call method `is_empty` on type `usize` | -help: you must surround the range in parentheses to call the `is_empty` function +help: you must surround the range in parentheses to call its `is_empty` function | LL | if (1..(end + 1)).is_empty() { | + + @@ -68,7 +68,7 @@ error[E0689]: can't call method `is_sorted` on type `usize` LL | if 1..(end + 1).is_sorted() { | ^^^^^^^^^ can't call method `is_sorted` on type `usize` | -help: you must surround the range in parentheses to call the `is_sorted` function +help: you must surround the range in parentheses to call its `is_sorted` function | LL | if (1..(end + 1)).is_sorted() { | + + @@ -88,7 +88,7 @@ error[E0689]: can't call method `take` on type `{integer}` LL | let _res: i32 = 3..6.take(2).sum(); | ^^^^ can't call method `take` on type `{integer}` | -help: you must surround the range in parentheses to call the `take` function +help: you must surround the range in parentheses to call its `take` function | LL | let _res: i32 = (3..6).take(2).sum(); | + + @@ -110,7 +110,7 @@ error[E0689]: can't call method `sum` on type `{integer}` LL | let _sum: i32 = 3..6.sum(); | ^^^ can't call method `sum` on type `{integer}` | -help: you must surround the range in parentheses to call the `sum` function +help: you must surround the range in parentheses to call its `sum` function | LL | let _sum: i32 = (3..6).sum(); | + + @@ -132,7 +132,7 @@ error[E0689]: can't call method `rev` on type `usize` LL | for _a in a..=b.rev() { | ^^^ can't call method `rev` on type `usize` | -help: you must surround the range in parentheses to call the `rev` function +help: you must surround the range in parentheses to call its `rev` function | LL | for _a in (a..=b).rev() { | + + @@ -143,7 +143,7 @@ error[E0689]: can't call method `contains` on type `{integer}` LL | let _res = ..10.contains(3); | ^^^^^^^^ can't call method `contains` on type `{integer}` | -help: you must surround the range in parentheses to call the `contains` function +help: you must surround the range in parentheses to call its `contains` function | LL | let _res = (..10).contains(3); | + +