Skip to content

Commit b5c2b79

Browse files
committed
Don't display default generic parameters in diagnostics that compare types.
Fixes #52097
1 parent 5336df7 commit b5c2b79

File tree

2 files changed

+87
-31
lines changed

2 files changed

+87
-31
lines changed

src/librustc/infer/error_reporting/mod.rs

+63-7
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
6060
use super::region_constraints::GenericKind;
6161
use super::lexical_region_resolve::RegionResolutionError;
6262

63-
use std::fmt;
63+
use std::{cmp, fmt};
6464
use hir;
6565
use hir::map as hir_map;
6666
use hir::def_id::DefId;
6767
use middle::region;
6868
use traits::{ObligationCause, ObligationCauseCode};
69-
use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants};
69+
use ty::{self, subst::Subst, Region, Ty, TyCtxt, TypeFoldable, TypeVariants};
7070
use ty::error::TypeError;
7171
use syntax::ast::DUMMY_NODE_ID;
7272
use syntax_pos::{Pos, Span};
@@ -672,6 +672,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
672672
}
673673
}
674674

675+
/// For generic types with parameters with defaults, remove the parameters corresponding to
676+
/// the defaults. This repeats a lot of the logic found in `PrintContext::parameterized`.
677+
fn strip_generic_default_params(
678+
&self,
679+
def_id: DefId,
680+
substs: &ty::subst::Substs<'tcx>
681+
) -> &'tcx ty::subst::Substs<'tcx> {
682+
let generics = self.tcx.generics_of(def_id);
683+
let mut num_supplied_defaults = 0;
684+
let mut type_params = generics.params.iter().rev().filter_map(|param| match param.kind {
685+
ty::GenericParamDefKind::Lifetime => None,
686+
ty::GenericParamDefKind::Type { has_default, .. } => {
687+
Some((param.def_id, has_default))
688+
}
689+
}).peekable();
690+
let has_default = {
691+
let has_default = type_params.peek().map(|(_, has_default)| has_default);
692+
*has_default.unwrap_or(&false)
693+
};
694+
if has_default {
695+
let types = substs.types().rev();
696+
for ((def_id, has_default), actual) in type_params.zip(types) {
697+
if !has_default {
698+
break;
699+
}
700+
if self.tcx.type_of(def_id).subst(self.tcx, substs) != actual {
701+
break;
702+
}
703+
num_supplied_defaults += 1;
704+
}
705+
}
706+
let len = generics.params.len();
707+
let mut generics = generics.clone();
708+
generics.params.truncate(len - num_supplied_defaults);
709+
substs.truncate_to(self.tcx, &generics)
710+
}
711+
675712
/// Compare two given types, eliding parts that are the same between them and highlighting
676713
/// relevant differences, and return two representation of those types for highlighted printing.
677714
fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) {
@@ -713,6 +750,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
713750

714751
match (&t1.sty, &t2.sty) {
715752
(&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => {
753+
let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1);
754+
let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2);
716755
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
717756
let path1 = self.tcx.item_path_str(def1.did.clone());
718757
let path2 = self.tcx.item_path_str(def2.did.clone());
@@ -728,8 +767,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
728767
values.0.push_normal(path1);
729768
values.1.push_normal(path2);
730769

770+
// Avoid printing out default generic parameters that are common to both
771+
// types.
772+
let len1 = sub_no_defaults_1.len();
773+
let len2 = sub_no_defaults_2.len();
774+
let common_len = cmp::min(len1, len2);
775+
let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
776+
let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
777+
let common_default_params =
778+
remainder1.iter().rev().zip(remainder2.iter().rev())
779+
.filter(|(a, b)| a == b).count();
780+
let len = sub1.len() - common_default_params;
781+
731782
// Only draw `<...>` if there're lifetime/type arguments.
732-
let len = sub1.len();
733783
if len > 0 {
734784
values.0.push_normal("<");
735785
values.1.push_normal("<");
@@ -774,7 +824,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
774824
// ^ elided type as this type argument was the same in both sides
775825
let type_arguments = sub1.types().zip(sub2.types());
776826
let regions_len = sub1.regions().collect::<Vec<_>>().len();
777-
for (i, (ta1, ta2)) in type_arguments.enumerate() {
827+
for (i, (ta1, ta2)) in type_arguments.take(len).enumerate() {
778828
let i = i + regions_len;
779829
if ta1 == ta2 {
780830
values.0.push_normal("_");
@@ -804,7 +854,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
804854
&mut values.0,
805855
&mut values.1,
806856
path1.clone(),
807-
sub1,
857+
sub_no_defaults_1,
808858
path2.clone(),
809859
&t2,
810860
).is_some()
@@ -816,8 +866,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
816866
// Bar<Qux>
817867
// Foo<Bar<Qux>>
818868
// ------- this type argument is exactly the same as the other type
819-
if self.cmp_type_arg(&mut values.1, &mut values.0, path2, sub2, path1, &t1)
820-
.is_some()
869+
if self.cmp_type_arg(
870+
&mut values.1,
871+
&mut values.0,
872+
path2,
873+
sub_no_defaults_2,
874+
path1,
875+
&t1,
876+
).is_some()
821877
{
822878
return values;
823879
}

src/test/ui/type-mismatch.stderr

+24-24
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ error[E0308]: mismatched types
112112
LL | want::<Foo<foo>>(f); //~ ERROR mismatched types
113113
| ^ expected struct `Foo`, found struct `foo`
114114
|
115-
= note: expected type `Foo<foo, A, B>`
115+
= note: expected type `Foo<foo>`
116116
found type `foo`
117117

118118
error[E0308]: mismatched types
@@ -121,7 +121,7 @@ error[E0308]: mismatched types
121121
LL | want::<Foo<foo, B>>(f); //~ ERROR mismatched types
122122
| ^ expected struct `Foo`, found struct `foo`
123123
|
124-
= note: expected type `Foo<foo, B, B>`
124+
= note: expected type `Foo<foo, B>`
125125
found type `foo`
126126

127127
error[E0308]: mismatched types
@@ -158,7 +158,7 @@ LL | want::<foo>(f); //~ ERROR mismatched types
158158
| ^ expected struct `foo`, found struct `Foo`
159159
|
160160
= note: expected type `foo`
161-
found type `Foo<foo, A, B>`
161+
found type `Foo<foo>`
162162

163163
error[E0308]: mismatched types
164164
--> $DIR/type-mismatch.rs:49:17
@@ -175,44 +175,44 @@ error[E0308]: mismatched types
175175
LL | want::<Foo<usize>>(f); //~ ERROR mismatched types
176176
| ^ expected usize, found struct `foo`
177177
|
178-
= note: expected type `Foo<usize, _, _>`
179-
found type `Foo<foo, _, _>`
178+
= note: expected type `Foo<usize>`
179+
found type `Foo<foo>`
180180

181181
error[E0308]: mismatched types
182182
--> $DIR/type-mismatch.rs:51:27
183183
|
184184
LL | want::<Foo<usize, B>>(f); //~ ERROR mismatched types
185185
| ^ expected usize, found struct `foo`
186186
|
187-
= note: expected type `Foo<usize, B, _>`
188-
found type `Foo<foo, A, _>`
187+
= note: expected type `Foo<usize, B>`
188+
found type `Foo<foo, A>`
189189

190190
error[E0308]: mismatched types
191191
--> $DIR/type-mismatch.rs:52:25
192192
|
193193
LL | want::<Foo<foo, B>>(f); //~ ERROR mismatched types
194194
| ^ expected struct `B`, found struct `A`
195195
|
196-
= note: expected type `Foo<_, B, _>`
197-
found type `Foo<_, A, _>`
196+
= note: expected type `Foo<_, B>`
197+
found type `Foo<_, A>`
198198

199199
error[E0308]: mismatched types
200200
--> $DIR/type-mismatch.rs:53:22
201201
|
202202
LL | want::<Foo<bar>>(f); //~ ERROR mismatched types
203203
| ^ expected struct `bar`, found struct `foo`
204204
|
205-
= note: expected type `Foo<bar, _, _>`
206-
found type `Foo<foo, _, _>`
205+
= note: expected type `Foo<bar>`
206+
found type `Foo<foo>`
207207

208208
error[E0308]: mismatched types
209209
--> $DIR/type-mismatch.rs:54:25
210210
|
211211
LL | want::<Foo<bar, B>>(f); //~ ERROR mismatched types
212212
| ^ expected struct `bar`, found struct `foo`
213213
|
214-
= note: expected type `Foo<bar, B, _>`
215-
found type `Foo<foo, A, _>`
214+
= note: expected type `Foo<bar, B>`
215+
found type `Foo<foo, A>`
216216

217217
error[E0308]: mismatched types
218218
--> $DIR/type-mismatch.rs:55:23
@@ -251,7 +251,7 @@ LL | want::<foo>(f); //~ ERROR mismatched types
251251
| ^ expected struct `foo`, found struct `Foo`
252252
|
253253
= note: expected type `foo`
254-
found type `Foo<foo, B, B>`
254+
found type `Foo<foo, B>`
255255

256256
error[E0308]: mismatched types
257257
--> $DIR/type-mismatch.rs:62:17
@@ -268,44 +268,44 @@ error[E0308]: mismatched types
268268
LL | want::<Foo<usize>>(f); //~ ERROR mismatched types
269269
| ^ expected usize, found struct `foo`
270270
|
271-
= note: expected type `Foo<usize, A, _>`
272-
found type `Foo<foo, B, _>`
271+
= note: expected type `Foo<usize, A>`
272+
found type `Foo<foo, B>`
273273

274274
error[E0308]: mismatched types
275275
--> $DIR/type-mismatch.rs:64:27
276276
|
277277
LL | want::<Foo<usize, B>>(f); //~ ERROR mismatched types
278278
| ^ expected usize, found struct `foo`
279279
|
280-
= note: expected type `Foo<usize, _, _>`
281-
found type `Foo<foo, _, _>`
280+
= note: expected type `Foo<usize, _>`
281+
found type `Foo<foo, _>`
282282

283283
error[E0308]: mismatched types
284284
--> $DIR/type-mismatch.rs:65:22
285285
|
286286
LL | want::<Foo<foo>>(f); //~ ERROR mismatched types
287287
| ^ expected struct `A`, found struct `B`
288288
|
289-
= note: expected type `Foo<_, A, _>`
290-
found type `Foo<_, B, _>`
289+
= note: expected type `Foo<_, A>`
290+
found type `Foo<_, B>`
291291

292292
error[E0308]: mismatched types
293293
--> $DIR/type-mismatch.rs:66:22
294294
|
295295
LL | want::<Foo<bar>>(f); //~ ERROR mismatched types
296296
| ^ expected struct `bar`, found struct `foo`
297297
|
298-
= note: expected type `Foo<bar, A, _>`
299-
found type `Foo<foo, B, _>`
298+
= note: expected type `Foo<bar, A>`
299+
found type `Foo<foo, B>`
300300

301301
error[E0308]: mismatched types
302302
--> $DIR/type-mismatch.rs:67:25
303303
|
304304
LL | want::<Foo<bar, B>>(f); //~ ERROR mismatched types
305305
| ^ expected struct `bar`, found struct `foo`
306306
|
307-
= note: expected type `Foo<bar, _, _>`
308-
found type `Foo<foo, _, _>`
307+
= note: expected type `Foo<bar, _>`
308+
found type `Foo<foo, _>`
309309

310310
error[E0308]: mismatched types
311311
--> $DIR/type-mismatch.rs:68:23

0 commit comments

Comments
 (0)