Skip to content

Commit 0a8275f

Browse files
committed
Auto merge of #52244 - glandium:issue52097, r=estebank
Don't display default generic parameters in diagnostics that compare types In errors like: ``` expected type: `RawVec<foo, Global>` found type: `foo` ``` `RawVec` being defined as `RawVec<T, A: Alloc = Global>`, the error is better written as ``` expected type: `RawVec<foo>` found type: `foo` ``` In fact, that is already what happens when `foo` is not an ADT, because in that case, the diagnostic handler doesn't try to highlight something, and just uses the `Display` trait instead of its own logic. e.g. ``` expected type: `RawVec<usize>` found type: `usize` ```
2 parents ccade97 + b5c2b79 commit 0a8275f

File tree

3 files changed

+581
-7
lines changed

3 files changed

+581
-7
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};
@@ -652,6 +652,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
652652
}
653653
}
654654

655+
/// For generic types with parameters with defaults, remove the parameters corresponding to
656+
/// the defaults. This repeats a lot of the logic found in `PrintContext::parameterized`.
657+
fn strip_generic_default_params(
658+
&self,
659+
def_id: DefId,
660+
substs: &ty::subst::Substs<'tcx>
661+
) -> &'tcx ty::subst::Substs<'tcx> {
662+
let generics = self.tcx.generics_of(def_id);
663+
let mut num_supplied_defaults = 0;
664+
let mut type_params = generics.params.iter().rev().filter_map(|param| match param.kind {
665+
ty::GenericParamDefKind::Lifetime => None,
666+
ty::GenericParamDefKind::Type { has_default, .. } => {
667+
Some((param.def_id, has_default))
668+
}
669+
}).peekable();
670+
let has_default = {
671+
let has_default = type_params.peek().map(|(_, has_default)| has_default);
672+
*has_default.unwrap_or(&false)
673+
};
674+
if has_default {
675+
let types = substs.types().rev();
676+
for ((def_id, has_default), actual) in type_params.zip(types) {
677+
if !has_default {
678+
break;
679+
}
680+
if self.tcx.type_of(def_id).subst(self.tcx, substs) != actual {
681+
break;
682+
}
683+
num_supplied_defaults += 1;
684+
}
685+
}
686+
let len = generics.params.len();
687+
let mut generics = generics.clone();
688+
generics.params.truncate(len - num_supplied_defaults);
689+
substs.truncate_to(self.tcx, &generics)
690+
}
691+
655692
/// Compare two given types, eliding parts that are the same between them and highlighting
656693
/// relevant differences, and return two representation of those types for highlighted printing.
657694
fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) {
@@ -693,6 +730,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
693730

694731
match (&t1.sty, &t2.sty) {
695732
(&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => {
733+
let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1);
734+
let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2);
696735
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
697736
let path1 = self.tcx.item_path_str(def1.did.clone());
698737
let path2 = self.tcx.item_path_str(def2.did.clone());
@@ -708,8 +747,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
708747
values.0.push_normal(path1);
709748
values.1.push_normal(path2);
710749

750+
// Avoid printing out default generic parameters that are common to both
751+
// types.
752+
let len1 = sub_no_defaults_1.len();
753+
let len2 = sub_no_defaults_2.len();
754+
let common_len = cmp::min(len1, len2);
755+
let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
756+
let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
757+
let common_default_params =
758+
remainder1.iter().rev().zip(remainder2.iter().rev())
759+
.filter(|(a, b)| a == b).count();
760+
let len = sub1.len() - common_default_params;
761+
711762
// Only draw `<...>` if there're lifetime/type arguments.
712-
let len = sub1.len();
713763
if len > 0 {
714764
values.0.push_normal("<");
715765
values.1.push_normal("<");
@@ -754,7 +804,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
754804
// ^ elided type as this type argument was the same in both sides
755805
let type_arguments = sub1.types().zip(sub2.types());
756806
let regions_len = sub1.regions().collect::<Vec<_>>().len();
757-
for (i, (ta1, ta2)) in type_arguments.enumerate() {
807+
for (i, (ta1, ta2)) in type_arguments.take(len).enumerate() {
758808
let i = i + regions_len;
759809
if ta1 == ta2 {
760810
values.0.push_normal("_");
@@ -784,7 +834,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
784834
&mut values.0,
785835
&mut values.1,
786836
path1.clone(),
787-
sub1,
837+
sub_no_defaults_1,
788838
path2.clone(),
789839
&t2,
790840
).is_some()
@@ -796,8 +846,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
796846
// Bar<Qux>
797847
// Foo<Bar<Qux>>
798848
// ------- this type argument is exactly the same as the other type
799-
if self.cmp_type_arg(&mut values.1, &mut values.0, path2, sub2, path1, &t1)
800-
.is_some()
849+
if self.cmp_type_arg(
850+
&mut values.1,
851+
&mut values.0,
852+
path2,
853+
sub_no_defaults_2,
854+
path1,
855+
&t1,
856+
).is_some()
801857
{
802858
return values;
803859
}

src/test/ui/type-mismatch.rs

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
trait Qux {}
12+
struct A;
13+
struct B;
14+
impl Qux for A {}
15+
impl Qux for B {}
16+
17+
struct Foo<T, U: Qux = A, V: Qux = B>(T, U, V);
18+
19+
struct foo;
20+
struct bar;
21+
22+
fn want<T>(t: T) {}
23+
24+
fn have_usize(f: usize) {
25+
want::<foo>(f); //~ ERROR mismatched types
26+
want::<bar>(f); //~ ERROR mismatched types
27+
want::<Foo<usize>>(f); //~ ERROR mismatched types
28+
want::<Foo<usize, B>>(f); //~ ERROR mismatched types
29+
want::<Foo<foo>>(f); //~ ERROR mismatched types
30+
want::<Foo<foo, B>>(f); //~ ERROR mismatched types
31+
want::<Foo<bar>>(f); //~ ERROR mismatched types
32+
want::<Foo<bar, B>>(f); //~ ERROR mismatched types
33+
}
34+
35+
fn have_foo(f: foo) {
36+
want::<usize>(f); //~ ERROR mismatched types
37+
want::<bar>(f); //~ ERROR mismatched types
38+
want::<Foo<usize>>(f); //~ ERROR mismatched types
39+
want::<Foo<usize, B>>(f); //~ ERROR mismatched types
40+
want::<Foo<foo>>(f); //~ ERROR mismatched types
41+
want::<Foo<foo, B>>(f); //~ ERROR mismatched types
42+
want::<Foo<bar>>(f); //~ ERROR mismatched types
43+
want::<Foo<bar, B>>(f); //~ ERROR mismatched types
44+
}
45+
46+
fn have_foo_foo(f: Foo<foo>) {
47+
want::<usize>(f); //~ ERROR mismatched types
48+
want::<foo>(f); //~ ERROR mismatched types
49+
want::<bar>(f); //~ ERROR mismatched types
50+
want::<Foo<usize>>(f); //~ ERROR mismatched types
51+
want::<Foo<usize, B>>(f); //~ ERROR mismatched types
52+
want::<Foo<foo, B>>(f); //~ ERROR mismatched types
53+
want::<Foo<bar>>(f); //~ ERROR mismatched types
54+
want::<Foo<bar, B>>(f); //~ ERROR mismatched types
55+
want::<&Foo<foo>>(f); //~ ERROR mismatched types
56+
want::<&Foo<foo, B>>(f); //~ ERROR mismatched types
57+
}
58+
59+
fn have_foo_foo_b(f: Foo<foo, B>) {
60+
want::<usize>(f); //~ ERROR mismatched types
61+
want::<foo>(f); //~ ERROR mismatched types
62+
want::<bar>(f); //~ ERROR mismatched types
63+
want::<Foo<usize>>(f); //~ ERROR mismatched types
64+
want::<Foo<usize, B>>(f); //~ ERROR mismatched types
65+
want::<Foo<foo>>(f); //~ ERROR mismatched types
66+
want::<Foo<bar>>(f); //~ ERROR mismatched types
67+
want::<Foo<bar, B>>(f); //~ ERROR mismatched types
68+
want::<&Foo<foo>>(f); //~ ERROR mismatched types
69+
want::<&Foo<foo, B>>(f); //~ ERROR mismatched types
70+
}
71+
72+
fn have_foo_foo_b_a(f: Foo<foo, B, A>) {
73+
want::<usize>(f); //~ ERROR mismatched types
74+
want::<foo>(f); //~ ERROR mismatched types
75+
want::<bar>(f); //~ ERROR mismatched types
76+
want::<Foo<usize>>(f); //~ ERROR mismatched types
77+
want::<Foo<usize, B>>(f); //~ ERROR mismatched types
78+
want::<Foo<foo>>(f); //~ ERROR mismatched types
79+
want::<Foo<foo, B>>(f); //~ ERROR mismatched types
80+
want::<Foo<bar>>(f); //~ ERROR mismatched types
81+
want::<Foo<bar, B>>(f); //~ ERROR mismatched types
82+
want::<&Foo<foo>>(f); //~ ERROR mismatched types
83+
want::<&Foo<foo, B>>(f); //~ ERROR mismatched types
84+
}
85+
86+
fn main() {}

0 commit comments

Comments
 (0)