Skip to content

Commit e747201

Browse files
committed
find the correct lang item for ranges
1 parent 5dd44d4 commit e747201

File tree

5 files changed

+108
-68
lines changed

5 files changed

+108
-68
lines changed

compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl

+1-2
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ hir_analysis_extern_crate_not_idiomatic =
133133
.suggestion = convert it to a `{$msg_code}`
134134
135135
hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
136-
hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
137136
138-
hir_analysis_missing_parentheses_in_range = `{$ty_str}` is not an iterator
137+
hir_analysis_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
139138
140139
hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call the `{$func_name}` function

compiler/rustc_hir_analysis/src/check/method/suggest.rs

+44-32
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_hir as hir;
1313
use rustc_hir::def::DefKind;
1414
use rustc_hir::def_id::DefId;
1515
use rustc_hir::lang_items::LangItem;
16-
use rustc_hir::{is_range_literal, ExprKind, Node, QPath};
16+
use rustc_hir::{ExprKind, Node, QPath};
1717
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1818
use rustc_middle::traits::util::supertraits;
1919
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
@@ -1214,50 +1214,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12141214
ty_str: &str,
12151215
) -> bool {
12161216
if let SelfSource::MethodCall(expr) = source {
1217-
let mut search_limit = 5;
1218-
for (_, parent) in tcx.hir().parent_iter(expr.hir_id) {
1219-
search_limit -= 1;
1220-
if search_limit == 0 {
1221-
break;
1222-
}
1217+
for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
1218+
if let Node::Expr(parent_expr) = parent {
1219+
let lang_item = match parent_expr.kind {
1220+
ExprKind::Struct(ref qpath, _, _) => match **qpath {
1221+
QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
1222+
QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
1223+
QPath::LangItem(LangItem::RangeToInclusive, ..) => {
1224+
Some(LangItem::RangeToInclusive)
1225+
}
1226+
_ => None,
1227+
},
1228+
ExprKind::Call(ref func, _) => match func.kind {
1229+
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
1230+
ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
1231+
Some(LangItem::RangeInclusiveStruct)
1232+
}
1233+
_ => None,
1234+
},
1235+
_ => None,
1236+
};
1237+
1238+
if lang_item.is_none() {
1239+
continue;
1240+
}
12231241

1224-
if let Node::Expr(parent_expr) = parent && is_range_literal(parent_expr) {
12251242
let span_included = match parent_expr.kind {
1226-
hir::ExprKind::Struct(_, eps, _) =>
1227-
eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span)),
1228-
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
1229-
hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
1230-
_ => false,
1243+
hir::ExprKind::Struct(_, eps, _) => {
1244+
eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span))
1245+
}
1246+
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
1247+
hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
1248+
_ => false,
12311249
};
12321250

12331251
if !span_included {
12341252
continue;
12351253
}
12361254

1237-
let range_def_id = self.tcx.lang_items().range_struct().unwrap();
1238-
let range_ty = self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
1239-
1240-
// avoid suggesting when the method name is not implemented for a `range`
1241-
let pick = self.lookup_probe(
1242-
span,
1243-
item_name,
1244-
range_ty,
1245-
expr,
1246-
ProbeScope::AllTraits
1247-
);
1255+
debug!("lang_item: {:?}", lang_item);
1256+
let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None);
1257+
let range_ty =
1258+
self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
12481259

1260+
let pick =
1261+
self.lookup_probe(span, item_name, range_ty, expr, ProbeScope::AllTraits);
12491262
if pick.is_ok() {
12501263
let range_span = parent_expr.span.with_hi(expr.span.hi());
12511264
tcx.sess.emit_err(errors::MissingParentheseInRange {
1252-
span: span,
1265+
span,
12531266
ty_str: ty_str.to_string(),
1254-
add_missing_parentheses: Some(
1255-
errors::AddMissingParenthesesInRange {
1256-
func_name: item_name.name.as_str().to_string(),
1257-
left: range_span.shrink_to_lo(),
1258-
right: range_span.shrink_to_hi(),
1259-
}
1260-
)
1267+
method_name: item_name.as_str().to_string(),
1268+
add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
1269+
func_name: item_name.name.as_str().to_string(),
1270+
left: range_span.shrink_to_lo(),
1271+
right: range_span.shrink_to_hi(),
1272+
}),
12611273
});
12621274
return true;
12631275
}

compiler/rustc_hir_analysis/src/errors.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,13 @@ pub struct ExpectedUsedSymbol {
348348
}
349349

350350
#[derive(Diagnostic)]
351-
#[diag(hir_analysis::missing_parentheses_in_range, code = "E0599")]
351+
#[diag(hir_analysis::missing_parentheses_in_range, code = "E0689")]
352352
pub struct MissingParentheseInRange {
353353
#[primary_span]
354354
#[label(hir_analysis::missing_parentheses_in_range)]
355355
pub span: Span,
356356
pub ty_str: String,
357+
pub method_name: String,
357358

358359
#[subdiagnostic]
359360
pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,

src/test/ui/methods/issues/issue-90315.rs

+17-11
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,61 @@
22
fn main() {
33
let arr = &[0, 1, 2, 3];
44
for _i in 0..arr.len().rev() {
5-
//~^ ERROR not an iterator
5+
//~^ ERROR can't call method
66
//~| surround the range in parentheses
77
// The above error used to say “the method `rev` exists for type `usize`”.
88
// This regression test ensures it doesn't say that any more.
99
}
1010

1111
// Test for #102396
1212
for i in 1..11.rev() {
13-
//~^ ERROR not an iterator
13+
//~^ ERROR can't call method
1414
//~| HELP surround the range in parentheses
1515
}
1616

1717
let end: usize = 10;
1818
for i in 1..end.rev() {
19-
//~^ ERROR not an iterator
19+
//~^ ERROR can't call method
2020
//~| HELP surround the range in parentheses
2121
}
2222

2323
for i in 1..(end + 1).rev() {
24-
//~^ ERROR not an iterator
24+
//~^ ERROR can't call method
2525
//~| HELP surround the range in parentheses
2626
}
2727

2828
if 1..(end + 1).is_empty() {
29-
//~^ ERROR not an iterator
29+
//~^ ERROR can't call method
3030
//~| ERROR mismatched types [E0308]
3131
//~| HELP surround the range in parentheses
3232
}
3333

3434
if 1..(end + 1).is_sorted() {
3535
//~^ ERROR mismatched types [E0308]
36-
//~| ERROR `usize` is not an iterator [E0599]
36+
//~| ERROR can't call method
3737
//~| HELP surround the range in parentheses
3838
}
3939

4040
let _res: i32 = 3..6.take(2).sum();
41-
//~^ ERROR `{integer}` is not an iterator [E0599]
41+
//~^ ERROR can't call method
4242
//~| ERROR mismatched types [E0308]
4343
//~| HELP surround the range in parentheses
4444

4545
let _sum: i32 = 3..6.sum();
46-
//~^ ERROR `{integer}` is not an iterator [E0599]
46+
//~^ ERROR can't call method
4747
//~| ERROR mismatched types [E0308]
4848
//~| HELP surround the range in parentheses
4949

5050
let a = 1 as usize;
5151
let b = 10 as usize;
5252

5353
for _a in a..=b.rev() {
54-
//~^ ERROR not an iterator
54+
//~^ ERROR can't call method
5555
//~| HELP surround the range in parentheses
5656
}
5757

5858
let _res = ..10.contains(3);
59-
//~^ ERROR not an iterator
59+
//~^ ERROR can't call method
6060
//~| HELP surround the range in parentheses
6161

6262
if 1..end.error_method() {
@@ -66,5 +66,11 @@ fn main() {
6666
}
6767

6868
let _res = b.take(1)..a;
69-
//~^ ERROR not an iterator
69+
//~^ ERROR `usize` is not an iterator
70+
71+
let _res: i32 = ..6.take(2).sum();
72+
//~^ can't call method `take` on ambiguous numeric type
73+
//~| ERROR mismatched types [E0308]
74+
//~| HELP you must specify a concrete type for this numeric value
75+
// Won't suggest because `RangeTo` dest not implemented `take`
7076
}

src/test/ui/methods/issues/issue-90315.stderr

+44-22
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,52 @@
1-
error[E0599]: `usize` is not an iterator
1+
error[E0689]: can't call method `rev` on type `usize`
22
--> $DIR/issue-90315.rs:4:28
33
|
44
LL | for _i in 0..arr.len().rev() {
5-
| ^^^ `usize` is not an iterator
5+
| ^^^ can't call method `rev` on type `usize`
66
|
77
help: you must surround the range in parentheses to call the `rev` function
88
|
99
LL | for _i in (0..arr.len()).rev() {
1010
| + +
1111

12-
error[E0599]: `{integer}` is not an iterator
12+
error[E0689]: can't call method `rev` on type `{integer}`
1313
--> $DIR/issue-90315.rs:12:20
1414
|
1515
LL | for i in 1..11.rev() {
16-
| ^^^ `{integer}` is not an iterator
16+
| ^^^ can't call method `rev` on type `{integer}`
1717
|
1818
help: you must surround the range in parentheses to call the `rev` function
1919
|
2020
LL | for i in (1..11).rev() {
2121
| + +
2222

23-
error[E0599]: `usize` is not an iterator
23+
error[E0689]: can't call method `rev` on type `usize`
2424
--> $DIR/issue-90315.rs:18:21
2525
|
2626
LL | for i in 1..end.rev() {
27-
| ^^^ `usize` is not an iterator
27+
| ^^^ can't call method `rev` on type `usize`
2828
|
2929
help: you must surround the range in parentheses to call the `rev` function
3030
|
3131
LL | for i in (1..end).rev() {
3232
| + +
3333

34-
error[E0599]: `usize` is not an iterator
34+
error[E0689]: can't call method `rev` on type `usize`
3535
--> $DIR/issue-90315.rs:23:27
3636
|
3737
LL | for i in 1..(end + 1).rev() {
38-
| ^^^ `usize` is not an iterator
38+
| ^^^ can't call method `rev` on type `usize`
3939
|
4040
help: you must surround the range in parentheses to call the `rev` function
4141
|
4242
LL | for i in (1..(end + 1)).rev() {
4343
| + +
4444

45-
error[E0599]: `usize` is not an iterator
45+
error[E0689]: can't call method `is_empty` on type `usize`
4646
--> $DIR/issue-90315.rs:28:21
4747
|
4848
LL | if 1..(end + 1).is_empty() {
49-
| ^^^^^^^^ `usize` is not an iterator
49+
| ^^^^^^^^ can't call method `is_empty` on type `usize`
5050
|
5151
help: you must surround the range in parentheses to call the `is_empty` function
5252
|
@@ -62,11 +62,11 @@ LL | if 1..(end + 1).is_empty() {
6262
= note: expected type `bool`
6363
found struct `std::ops::Range<{integer}>`
6464

65-
error[E0599]: `usize` is not an iterator
65+
error[E0689]: can't call method `is_sorted` on type `usize`
6666
--> $DIR/issue-90315.rs:34:21
6767
|
6868
LL | if 1..(end + 1).is_sorted() {
69-
| ^^^^^^^^^ `usize` is not an iterator
69+
| ^^^^^^^^^ can't call method `is_sorted` on type `usize`
7070
|
7171
help: you must surround the range in parentheses to call the `is_sorted` function
7272
|
@@ -82,11 +82,11 @@ LL | if 1..(end + 1).is_sorted() {
8282
= note: expected type `bool`
8383
found struct `std::ops::Range<{integer}>`
8484

85-
error[E0599]: `{integer}` is not an iterator
85+
error[E0689]: can't call method `take` on type `{integer}`
8686
--> $DIR/issue-90315.rs:40:26
8787
|
8888
LL | let _res: i32 = 3..6.take(2).sum();
89-
| ^^^^ `{integer}` is not an iterator
89+
| ^^^^ can't call method `take` on type `{integer}`
9090
|
9191
help: you must surround the range in parentheses to call the `take` function
9292
|
@@ -104,11 +104,11 @@ LL | let _res: i32 = 3..6.take(2).sum();
104104
= note: expected type `i32`
105105
found struct `std::ops::Range<{integer}>`
106106

107-
error[E0599]: `{integer}` is not an iterator
107+
error[E0689]: can't call method `sum` on type `{integer}`
108108
--> $DIR/issue-90315.rs:45:26
109109
|
110110
LL | let _sum: i32 = 3..6.sum();
111-
| ^^^ `{integer}` is not an iterator
111+
| ^^^ can't call method `sum` on type `{integer}`
112112
|
113113
help: you must surround the range in parentheses to call the `sum` function
114114
|
@@ -126,22 +126,22 @@ LL | let _sum: i32 = 3..6.sum();
126126
= note: expected type `i32`
127127
found struct `std::ops::Range<{integer}>`
128128

129-
error[E0599]: `usize` is not an iterator
129+
error[E0689]: can't call method `rev` on type `usize`
130130
--> $DIR/issue-90315.rs:53:21
131131
|
132132
LL | for _a in a..=b.rev() {
133-
| ^^^ `usize` is not an iterator
133+
| ^^^ can't call method `rev` on type `usize`
134134
|
135135
help: you must surround the range in parentheses to call the `rev` function
136136
|
137137
LL | for _a in (a..=b).rev() {
138138
| + +
139139

140-
error[E0599]: `{integer}` is not an iterator
140+
error[E0689]: can't call method `contains` on type `{integer}`
141141
--> $DIR/issue-90315.rs:58:21
142142
|
143143
LL | let _res = ..10.contains(3);
144-
| ^^^^^^^^ `{integer}` is not an iterator
144+
| ^^^^^^^^ can't call method `contains` on type `{integer}`
145145
|
146146
help: you must surround the range in parentheses to call the `contains` function
147147
|
@@ -173,7 +173,29 @@ LL | let _res = b.take(1)..a;
173173
`usize: Iterator`
174174
which is required by `&mut usize: Iterator`
175175

176-
error: aborting due to 17 previous errors
176+
error[E0689]: can't call method `take` on ambiguous numeric type `{integer}`
177+
--> $DIR/issue-90315.rs:71:25
178+
|
179+
LL | let _res: i32 = ..6.take(2).sum();
180+
| ^^^^
181+
|
182+
help: you must specify a concrete type for this numeric value, like `i32`
183+
|
184+
LL | let _res: i32 = ..6_i32.take(2).sum();
185+
| ~~~~~
186+
187+
error[E0308]: mismatched types
188+
--> $DIR/issue-90315.rs:71:21
189+
|
190+
LL | let _res: i32 = ..6.take(2).sum();
191+
| --- ^^^^^^^^^^^^^^^^^ expected `i32`, found struct `RangeTo`
192+
| |
193+
| expected due to this
194+
|
195+
= note: expected type `i32`
196+
found struct `RangeTo<_>`
197+
198+
error: aborting due to 19 previous errors
177199

178-
Some errors have detailed explanations: E0308, E0599.
200+
Some errors have detailed explanations: E0308, E0599, E0689.
179201
For more information about an error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)