Skip to content

Commit d43ede1

Browse files
committed
Use more accurate spans for trait/impl method arg divergence
1 parent 010c236 commit d43ede1

File tree

8 files changed

+53
-96
lines changed

8 files changed

+53
-96
lines changed

compiler/rustc_middle/src/ty/error.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub enum TypeError<'tcx> {
3636
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
3737
AbiMismatch(ExpectedFound<abi::Abi>),
3838
Mutability,
39+
ArgumentMutability(usize),
3940
TupleSize(ExpectedFound<usize>),
4041
FixedArraySize(ExpectedFound<u64>),
4142
ArgCount,
@@ -46,6 +47,7 @@ pub enum TypeError<'tcx> {
4647
RegionsPlaceholderMismatch,
4748

4849
Sorts(ExpectedFound<Ty<'tcx>>),
50+
ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize),
4951
IntMismatch(ExpectedFound<ty::IntVarValue>),
5052
FloatMismatch(ExpectedFound<ty::FloatTy>),
5153
Traits(ExpectedFound<DefId>),
@@ -110,7 +112,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
110112
AbiMismatch(values) => {
111113
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
112114
}
113-
Mutability => write!(f, "types differ in mutability"),
115+
ArgumentMutability(_) | Mutability => write!(f, "types differ in mutability"),
114116
TupleSize(values) => write!(
115117
f,
116118
"expected a tuple with {} element{}, \
@@ -142,7 +144,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
142144
br_string(br)
143145
),
144146
RegionsPlaceholderMismatch => write!(f, "one type is more general than the other"),
145-
Sorts(values) => ty::tls::with(|tcx| {
147+
ArgumentSorts(values, _) | Sorts(values) => ty::tls::with(|tcx| {
146148
report_maybe_different(
147149
f,
148150
&values.expected.sort_string(tcx),
@@ -199,10 +201,11 @@ impl<'tcx> TypeError<'tcx> {
199201
use self::TypeError::*;
200202
match self {
201203
CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_)
202-
| FixedArraySize(_) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
203-
| VariadicMismatch(_) | TargetFeatureCast(_) => false,
204+
| FixedArraySize(_) | ArgumentSorts(..) | Sorts(_) | IntMismatch(_)
205+
| FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false,
204206

205207
Mutability
208+
| ArgumentMutability(_)
206209
| TupleSize(_)
207210
| ArgCount
208211
| RegionsDoesNotOutlive(..)
@@ -339,7 +342,7 @@ impl<'tcx> TyCtxt<'tcx> {
339342
use self::TypeError::*;
340343
debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
341344
match err {
342-
Sorts(values) => {
345+
ArgumentSorts(values, _) | Sorts(values) => {
343346
match (values.expected.kind(), values.found.kind()) {
344347
(ty::Closure(..), ty::Closure(..)) => {
345348
db.note("no two closures, even if identical, have the same type");

compiler/rustc_middle/src/ty/relate.rs

+6
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,12 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
179179
} else {
180180
relation.relate_with_variance(ty::Contravariant, a, b)
181181
}
182+
})
183+
.enumerate()
184+
.map(|(i, r)| match r {
185+
Err(TypeError::Sorts(exp_found)) => Err(TypeError::ArgumentSorts(exp_found, i)),
186+
Err(TypeError::Mutability) => Err(TypeError::ArgumentMutability(i)),
187+
r => r,
182188
});
183189
Ok(ty::FnSig {
184190
inputs_and_output: tcx.mk_type_list(inputs_and_output)?,

compiler/rustc_middle/src/ty/structural_impls.rs

+2
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
587587
UnsafetyMismatch(x) => UnsafetyMismatch(x),
588588
AbiMismatch(x) => AbiMismatch(x),
589589
Mutability => Mutability,
590+
ArgumentMutability(i) => ArgumentMutability(i),
590591
TupleSize(x) => TupleSize(x),
591592
FixedArraySize(x) => FixedArraySize(x),
592593
ArgCount => ArgCount,
@@ -607,6 +608,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
607608
CyclicTy(t) => return tcx.lift(t).map(|t| CyclicTy(t)),
608609
CyclicConst(ct) => return tcx.lift(ct).map(|ct| CyclicConst(ct)),
609610
ProjectionMismatched(x) => ProjectionMismatched(x),
611+
ArgumentSorts(x, i) => return tcx.lift(x).map(|x| ArgumentSorts(x, i)),
610612
Sorts(x) => return tcx.lift(x).map(Sorts),
611613
ExistentialMismatch(x) => return tcx.lift(x).map(ExistentialMismatch),
612614
ConstMismatch(x) => return tcx.lift(x).map(ConstMismatch),

compiler/rustc_typeck/src/check/compare_method.rs

+21-75
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,8 @@ fn compare_predicate_entailment<'tcx>(
278278
if let Err(terr) = sub_result {
279279
debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
280280

281-
let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(
282-
&infcx, param_env, &terr, &cause, impl_m, impl_sig, trait_m, trait_sig,
283-
);
281+
let (impl_err_span, trait_err_span) =
282+
extract_spans_for_error_reporting(&infcx, &terr, &cause, impl_m, trait_m);
284283

285284
cause.make_mut().span = impl_err_span;
286285

@@ -291,7 +290,7 @@ fn compare_predicate_entailment<'tcx>(
291290
"method `{}` has an incompatible type for trait",
292291
trait_m.ident
293292
);
294-
if let TypeError::Mutability = terr {
293+
if let TypeError::ArgumentMutability(_) = terr {
295294
if let Some(trait_err_span) = trait_err_span {
296295
if let Ok(trait_err_str) = tcx.sess.source_map().span_to_snippet(trait_err_span)
297296
{
@@ -385,86 +384,35 @@ fn check_region_bounds_on_impl_item<'tcx>(
385384

386385
fn extract_spans_for_error_reporting<'a, 'tcx>(
387386
infcx: &infer::InferCtxt<'a, 'tcx>,
388-
param_env: ty::ParamEnv<'tcx>,
389387
terr: &TypeError<'_>,
390388
cause: &ObligationCause<'tcx>,
391389
impl_m: &ty::AssocItem,
392-
impl_sig: ty::FnSig<'tcx>,
393390
trait_m: &ty::AssocItem,
394-
trait_sig: ty::FnSig<'tcx>,
395391
) -> (Span, Option<Span>) {
396392
let tcx = infcx.tcx;
397393
let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
398-
let (impl_m_output, impl_m_iter) = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
399-
ImplItemKind::Fn(ref impl_m_sig, _) => {
400-
(&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
394+
let mut impl_args = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
395+
ImplItemKind::Fn(ref sig, _) => {
396+
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
401397
}
402398
_ => bug!("{:?} is not a method", impl_m),
403399
};
400+
let trait_args = trait_m.def_id.as_local().map(|def_id| {
401+
let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
402+
match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
403+
TraitItemKind::Fn(ref sig, _) => {
404+
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
405+
}
406+
_ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
407+
}
408+
});
404409

405410
match *terr {
406-
TypeError::Mutability => {
407-
if let Some(def_id) = trait_m.def_id.as_local() {
408-
let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
409-
let trait_m_iter = match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
410-
TraitItemKind::Fn(ref trait_m_sig, _) => trait_m_sig.decl.inputs.iter(),
411-
_ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
412-
};
413-
414-
iter::zip(impl_m_iter, trait_m_iter)
415-
.find(|&(ref impl_arg, ref trait_arg)| {
416-
match (&impl_arg.kind, &trait_arg.kind) {
417-
(
418-
&hir::TyKind::Rptr(_, ref impl_mt),
419-
&hir::TyKind::Rptr(_, ref trait_mt),
420-
)
421-
| (&hir::TyKind::Ptr(ref impl_mt), &hir::TyKind::Ptr(ref trait_mt)) => {
422-
impl_mt.mutbl != trait_mt.mutbl
423-
}
424-
_ => false,
425-
}
426-
})
427-
.map(|(ref impl_arg, ref trait_arg)| (impl_arg.span, Some(trait_arg.span)))
428-
.unwrap_or_else(|| (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)))
429-
} else {
430-
(cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
431-
}
411+
TypeError::ArgumentMutability(i) => {
412+
(impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
432413
}
433-
TypeError::Sorts(ExpectedFound { .. }) => {
434-
if let Some(def_id) = trait_m.def_id.as_local() {
435-
let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
436-
let (trait_m_output, trait_m_iter) =
437-
match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
438-
TraitItemKind::Fn(ref trait_m_sig, _) => {
439-
(&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
440-
}
441-
_ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
442-
};
443-
444-
let impl_iter = impl_sig.inputs().iter();
445-
let trait_iter = trait_sig.inputs().iter();
446-
iter::zip(iter::zip(impl_iter, trait_iter), iter::zip(impl_m_iter, trait_m_iter))
447-
.find_map(|((&impl_arg_ty, &trait_arg_ty), (impl_arg, trait_arg))| match infcx
448-
.at(&cause, param_env)
449-
.sub(trait_arg_ty, impl_arg_ty)
450-
{
451-
Ok(_) => None,
452-
Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
453-
})
454-
.unwrap_or_else(|| {
455-
if infcx
456-
.at(&cause, param_env)
457-
.sup(trait_sig.output(), impl_sig.output())
458-
.is_err()
459-
{
460-
(impl_m_output.span(), Some(trait_m_output.span()))
461-
} else {
462-
(cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
463-
}
464-
})
465-
} else {
466-
(cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
467-
}
414+
TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
415+
(impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
468416
}
469417
_ => (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)),
470418
}
@@ -514,8 +462,7 @@ fn compare_self_type<'tcx>(
514462
tcx.sess,
515463
impl_m_span,
516464
E0185,
517-
"method `{}` has a `{}` declaration in the impl, but \
518-
not in the trait",
465+
"method `{}` has a `{}` declaration in the impl, but not in the trait",
519466
trait_m.ident,
520467
self_descr
521468
);
@@ -993,8 +940,7 @@ crate fn compare_const_impl<'tcx>(
993940
tcx.sess,
994941
cause.span,
995942
E0326,
996-
"implemented const `{}` has an incompatible type for \
997-
trait",
943+
"implemented const `{}` has an incompatible type for trait",
998944
trait_c.ident
999945
);
1000946

src/test/ui/impl-trait/trait_type.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0053]: method `fmt` has an incompatible type for trait
2-
--> $DIR/trait_type.rs:7:4
2+
--> $DIR/trait_type.rs:7:21
33
|
44
LL | fn fmt(&self, x: &str) -> () { }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
5+
| ^^^^ types differ in mutability
66
|
77
= note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
88
found fn pointer `fn(&MyType, &str)`

src/test/ui/issues/issue-20225.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
error[E0053]: method `call` has an incompatible type for trait
2-
--> $DIR/issue-20225.rs:6:3
2+
--> $DIR/issue-20225.rs:6:43
33
|
44
LL | impl<'a, T> Fn<(&'a T,)> for Foo {
55
| - this type parameter
66
LL | extern "rust-call" fn call(&self, (_,): (T,)) {}
7-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T`
7+
| ^^^^ expected `&T`, found type parameter `T`
88
|
99
= note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))`
1010
found fn pointer `extern "rust-call" fn(&Foo, (T,))`
1111

1212
error[E0053]: method `call_mut` has an incompatible type for trait
13-
--> $DIR/issue-20225.rs:11:3
13+
--> $DIR/issue-20225.rs:11:51
1414
|
1515
LL | impl<'a, T> FnMut<(&'a T,)> for Foo {
1616
| - this type parameter
1717
LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {}
18-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T`
18+
| ^^^^ expected `&T`, found type parameter `T`
1919
|
2020
= note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))`
2121
found fn pointer `extern "rust-call" fn(&mut Foo, (T,))`
2222

2323
error[E0053]: method `call_once` has an incompatible type for trait
24-
--> $DIR/issue-20225.rs:18:3
24+
--> $DIR/issue-20225.rs:18:47
2525
|
2626
LL | impl<'a, T> FnOnce<(&'a T,)> for Foo {
2727
| - this type parameter
2828
...
2929
LL | extern "rust-call" fn call_once(self, (_,): (T,)) {}
30-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T`
30+
| ^^^^ expected `&T`, found type parameter `T`
3131
|
3232
= note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))`
3333
found fn pointer `extern "rust-call" fn(Foo, (T,))`

src/test/ui/issues/issue-21332.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0053]: method `next` has an incompatible type for trait
2-
--> $DIR/issue-21332.rs:5:5
2+
--> $DIR/issue-21332.rs:5:27
33
|
44
LL | fn next(&mut self) -> Result<i32, i32> { Ok(7) }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found enum `Result`
5+
| ^^^^^^^^^^^^^^^^ expected enum `Option`, found enum `Result`
66
|
77
= note: expected fn pointer `fn(&mut S) -> Option<i32>`
88
found fn pointer `fn(&mut S) -> Result<i32, i32>`

src/test/ui/wrong-mul-method-signature.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
error[E0053]: method `mul` has an incompatible type for trait
2-
--> $DIR/wrong-mul-method-signature.rs:16:5
2+
--> $DIR/wrong-mul-method-signature.rs:16:21
33
|
44
LL | fn mul(self, s: &f64) -> Vec1 {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found `&f64`
5+
| ^^^^ expected `f64`, found `&f64`
66
|
77
= note: expected fn pointer `fn(Vec1, f64) -> Vec1`
88
found fn pointer `fn(Vec1, &f64) -> Vec1`
99

1010
error[E0053]: method `mul` has an incompatible type for trait
11-
--> $DIR/wrong-mul-method-signature.rs:33:5
11+
--> $DIR/wrong-mul-method-signature.rs:33:21
1212
|
1313
LL | fn mul(self, s: f64) -> Vec2 {
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Vec2`, found `f64`
14+
| ^^^ expected struct `Vec2`, found `f64`
1515
|
1616
= note: expected fn pointer `fn(Vec2, Vec2) -> f64`
1717
found fn pointer `fn(Vec2, f64) -> Vec2`
1818

1919
error[E0053]: method `mul` has an incompatible type for trait
20-
--> $DIR/wrong-mul-method-signature.rs:52:5
20+
--> $DIR/wrong-mul-method-signature.rs:52:29
2121
|
2222
LL | fn mul(self, s: f64) -> f64 {
23-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `f64`
23+
| ^^^ expected `i32`, found `f64`
2424
|
2525
= note: expected fn pointer `fn(Vec3, _) -> i32`
2626
found fn pointer `fn(Vec3, _) -> f64`

0 commit comments

Comments
 (0)