use the correct node args for substitution
This commit is contained in:
parent
cf10690ad4
commit
18f36897ef
@ -12,7 +12,7 @@
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty};
|
||||
use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
@ -93,27 +93,35 @@ fn into_iter_bound<'tcx>(
|
||||
|
||||
for (pred, span) in cx.tcx.explicit_predicates_of(fn_did).predicates {
|
||||
if let ty::ClauseKind::Trait(tr) = pred.kind().skip_binder() {
|
||||
if tr.def_id() == into_iter_did && tr.self_ty().is_param(param_index) {
|
||||
into_iter_span = Some(*span);
|
||||
} else {
|
||||
// Substitute generics in the predicate and replace the IntoIterator type parameter with the
|
||||
// `.into_iter()` receiver to see if the bound also holds for that type.
|
||||
let args = cx.tcx.mk_args_from_iter(node_args.iter().enumerate().map(|(i, arg)| {
|
||||
if i == param_index as usize {
|
||||
GenericArg::from(into_iter_receiver)
|
||||
} else {
|
||||
arg
|
||||
if tr.self_ty().is_param(param_index) {
|
||||
if tr.def_id() == into_iter_did {
|
||||
into_iter_span = Some(*span);
|
||||
} else {
|
||||
let tr = cx.tcx.erase_regions(tr);
|
||||
if tr.has_escaping_bound_vars() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Substitute generics in the predicate and replace the IntoIterator type parameter with the
|
||||
// `.into_iter()` receiver to see if the bound also holds for that type.
|
||||
let args = cx.tcx.mk_args_from_iter(node_args.iter().enumerate().map(|(i, arg)| {
|
||||
if i == param_index as usize {
|
||||
GenericArg::from(into_iter_receiver)
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
}));
|
||||
|
||||
let predicate = EarlyBinder::bind(tr).instantiate(cx.tcx, args);
|
||||
let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), param_env, predicate);
|
||||
if !cx
|
||||
.tcx
|
||||
.infer_ctxt()
|
||||
.build()
|
||||
.predicate_must_hold_modulo_regions(&obligation)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
}));
|
||||
let predicate = EarlyBinder::bind(tr).instantiate(cx.tcx, args);
|
||||
let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), param_env, predicate);
|
||||
if !cx
|
||||
.tcx
|
||||
.infer_ctxt()
|
||||
.build()
|
||||
.predicate_must_hold_modulo_regions(&obligation)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -216,7 +224,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
return (
|
||||
did,
|
||||
args,
|
||||
cx.typeck_results().node_args(recv.hir_id),
|
||||
cx.typeck_results().node_args(parent.hir_id),
|
||||
MethodOrFunction::Method
|
||||
);
|
||||
})
|
||||
|
@ -244,6 +244,47 @@ mod issue11300 {
|
||||
// and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unncessary.
|
||||
foo3([1, 2, 3]);
|
||||
}
|
||||
|
||||
fn ice() {
|
||||
struct S1;
|
||||
impl S1 {
|
||||
pub fn foo<I: IntoIterator>(&self, _: I) {}
|
||||
}
|
||||
|
||||
S1.foo([1, 2]);
|
||||
|
||||
// ICE that occured in itertools
|
||||
trait Itertools {
|
||||
fn interleave_shortest<J>(self, other: J)
|
||||
where
|
||||
J: IntoIterator,
|
||||
Self: Sized;
|
||||
}
|
||||
impl<I: Iterator> Itertools for I {
|
||||
fn interleave_shortest<J>(self, other: J)
|
||||
where
|
||||
J: IntoIterator,
|
||||
Self: Sized,
|
||||
{
|
||||
}
|
||||
}
|
||||
let v0: Vec<i32> = vec![0, 2, 4];
|
||||
let v1: Vec<i32> = vec![1, 3, 5, 7];
|
||||
v0.into_iter().interleave_shortest(v1);
|
||||
|
||||
trait TraitWithLifetime<'a> {}
|
||||
impl<'a> TraitWithLifetime<'a> for std::array::IntoIter<&'a i32, 2> {}
|
||||
|
||||
struct Helper;
|
||||
impl<'a> Helper {
|
||||
fn with_lt<I>(&self, _: I)
|
||||
where
|
||||
I: IntoIterator + TraitWithLifetime<'a>,
|
||||
{
|
||||
}
|
||||
}
|
||||
Helper.with_lt([&1, &2].into_iter());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -244,6 +244,47 @@ pub fn bar() {
|
||||
// and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unncessary.
|
||||
foo3([1, 2, 3].into_iter());
|
||||
}
|
||||
|
||||
fn ice() {
|
||||
struct S1;
|
||||
impl S1 {
|
||||
pub fn foo<I: IntoIterator>(&self, _: I) {}
|
||||
}
|
||||
|
||||
S1.foo([1, 2].into_iter());
|
||||
|
||||
// ICE that occured in itertools
|
||||
trait Itertools {
|
||||
fn interleave_shortest<J>(self, other: J)
|
||||
where
|
||||
J: IntoIterator,
|
||||
Self: Sized;
|
||||
}
|
||||
impl<I: Iterator> Itertools for I {
|
||||
fn interleave_shortest<J>(self, other: J)
|
||||
where
|
||||
J: IntoIterator,
|
||||
Self: Sized,
|
||||
{
|
||||
}
|
||||
}
|
||||
let v0: Vec<i32> = vec![0, 2, 4];
|
||||
let v1: Vec<i32> = vec![1, 3, 5, 7];
|
||||
v0.into_iter().interleave_shortest(v1.into_iter());
|
||||
|
||||
trait TraitWithLifetime<'a> {}
|
||||
impl<'a> TraitWithLifetime<'a> for std::array::IntoIter<&'a i32, 2> {}
|
||||
|
||||
struct Helper;
|
||||
impl<'a> Helper {
|
||||
fn with_lt<I>(&self, _: I)
|
||||
where
|
||||
I: IntoIterator + TraitWithLifetime<'a>,
|
||||
{
|
||||
}
|
||||
}
|
||||
Helper.with_lt([&1, &2].into_iter());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -202,5 +202,29 @@ note: this parameter accepts any `IntoIterator`, so you don't need to call `.int
|
||||
LL | I: IntoIterator<Item = i32>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 26 previous errors
|
||||
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
|
||||
--> $DIR/useless_conversion.rs:254:16
|
||||
|
|
||||
LL | S1.foo([1, 2].into_iter());
|
||||
| ^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2]`
|
||||
|
|
||||
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
|
||||
--> $DIR/useless_conversion.rs:251:27
|
||||
|
|
||||
LL | pub fn foo<I: IntoIterator>(&self, _: I) {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
|
||||
--> $DIR/useless_conversion.rs:273:44
|
||||
|
|
||||
LL | v0.into_iter().interleave_shortest(v1.into_iter());
|
||||
| ^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `v1`
|
||||
|
|
||||
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
|
||||
--> $DIR/useless_conversion.rs:260:20
|
||||
|
|
||||
LL | J: IntoIterator,
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 28 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user