diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 1377176bc7f..06214505819 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -60,13 +60,13 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa use super::region_constraints::GenericKind; use super::lexical_region_resolve::RegionResolutionError; -use std::fmt; +use std::{cmp, fmt}; use hir; use hir::map as hir_map; use hir::def_id::DefId; use middle::region; use traits::{ObligationCause, ObligationCauseCode}; -use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants}; +use ty::{self, subst::Subst, Region, Ty, TyCtxt, TypeFoldable, TypeVariants}; use ty::error::TypeError; use syntax::ast::DUMMY_NODE_ID; use syntax_pos::{Pos, Span}; @@ -672,6 +672,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + /// For generic types with parameters with defaults, remove the parameters corresponding to + /// the defaults. This repeats a lot of the logic found in `PrintContext::parameterized`. + fn strip_generic_default_params( + &self, + def_id: DefId, + substs: &ty::subst::Substs<'tcx> + ) -> &'tcx ty::subst::Substs<'tcx> { + let generics = self.tcx.generics_of(def_id); + let mut num_supplied_defaults = 0; + let mut type_params = generics.params.iter().rev().filter_map(|param| match param.kind { + ty::GenericParamDefKind::Lifetime => None, + ty::GenericParamDefKind::Type { has_default, .. } => { + Some((param.def_id, has_default)) + } + }).peekable(); + let has_default = { + let has_default = type_params.peek().map(|(_, has_default)| has_default); + *has_default.unwrap_or(&false) + }; + if has_default { + let types = substs.types().rev(); + for ((def_id, has_default), actual) in type_params.zip(types) { + if !has_default { + break; + } + if self.tcx.type_of(def_id).subst(self.tcx, substs) != actual { + break; + } + num_supplied_defaults += 1; + } + } + let len = generics.params.len(); + let mut generics = generics.clone(); + generics.params.truncate(len - num_supplied_defaults); + substs.truncate_to(self.tcx, &generics) + } + /// Compare two given types, eliding parts that are the same between them and highlighting /// relevant differences, and return two representation of those types for highlighted printing. fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) { @@ -713,6 +750,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match (&t1.sty, &t2.sty) { (&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => { + let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1); + let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2); let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); let path1 = self.tcx.item_path_str(def1.did.clone()); let path2 = self.tcx.item_path_str(def2.did.clone()); @@ -728,8 +767,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { values.0.push_normal(path1); values.1.push_normal(path2); + // Avoid printing out default generic parameters that are common to both + // types. + let len1 = sub_no_defaults_1.len(); + let len2 = sub_no_defaults_2.len(); + let common_len = cmp::min(len1, len2); + let remainder1: Vec<_> = sub1.types().skip(common_len).collect(); + let remainder2: Vec<_> = sub2.types().skip(common_len).collect(); + let common_default_params = + remainder1.iter().rev().zip(remainder2.iter().rev()) + .filter(|(a, b)| a == b).count(); + let len = sub1.len() - common_default_params; + // Only draw `<...>` if there're lifetime/type arguments. - let len = sub1.len(); if len > 0 { values.0.push_normal("<"); values.1.push_normal("<"); @@ -774,7 +824,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // ^ elided type as this type argument was the same in both sides let type_arguments = sub1.types().zip(sub2.types()); let regions_len = sub1.regions().collect::>().len(); - for (i, (ta1, ta2)) in type_arguments.enumerate() { + for (i, (ta1, ta2)) in type_arguments.take(len).enumerate() { let i = i + regions_len; if ta1 == ta2 { values.0.push_normal("_"); @@ -804,7 +854,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &mut values.0, &mut values.1, path1.clone(), - sub1, + sub_no_defaults_1, path2.clone(), &t2, ).is_some() @@ -816,8 +866,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Bar // Foo> // ------- this type argument is exactly the same as the other type - if self.cmp_type_arg(&mut values.1, &mut values.0, path2, sub2, path1, &t1) - .is_some() + if self.cmp_type_arg( + &mut values.1, + &mut values.0, + path2, + sub_no_defaults_2, + path1, + &t1, + ).is_some() { return values; } diff --git a/src/test/ui/type-mismatch.stderr b/src/test/ui/type-mismatch.stderr index 634f3b402a1..4ba1a7f37c4 100644 --- a/src/test/ui/type-mismatch.stderr +++ b/src/test/ui/type-mismatch.stderr @@ -112,7 +112,7 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected struct `Foo`, found struct `foo` | - = note: expected type `Foo` + = note: expected type `Foo` found type `foo` error[E0308]: mismatched types @@ -121,7 +121,7 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected struct `Foo`, found struct `foo` | - = note: expected type `Foo` + = note: expected type `Foo` found type `foo` error[E0308]: mismatched types @@ -158,7 +158,7 @@ LL | want::(f); //~ ERROR mismatched types | ^ expected struct `foo`, found struct `Foo` | = note: expected type `foo` - found type `Foo` + found type `Foo` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:49:17 @@ -175,8 +175,8 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected usize, found struct `foo` | - = note: expected type `Foo` - found type `Foo` + = note: expected type `Foo` + found type `Foo` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:51:27 @@ -184,8 +184,8 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected usize, found struct `foo` | - = note: expected type `Foo` - found type `Foo` + = note: expected type `Foo` + found type `Foo` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:52:25 @@ -193,8 +193,8 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected struct `B`, found struct `A` | - = note: expected type `Foo<_, B, _>` - found type `Foo<_, A, _>` + = note: expected type `Foo<_, B>` + found type `Foo<_, A>` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:53:22 @@ -202,8 +202,8 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected struct `bar`, found struct `foo` | - = note: expected type `Foo` - found type `Foo` + = note: expected type `Foo` + found type `Foo` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:54:25 @@ -211,8 +211,8 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected struct `bar`, found struct `foo` | - = note: expected type `Foo` - found type `Foo` + = note: expected type `Foo` + found type `Foo` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:55:23 @@ -251,7 +251,7 @@ LL | want::(f); //~ ERROR mismatched types | ^ expected struct `foo`, found struct `Foo` | = note: expected type `foo` - found type `Foo` + found type `Foo` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:62:17 @@ -268,8 +268,8 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected usize, found struct `foo` | - = note: expected type `Foo` - found type `Foo` + = note: expected type `Foo` + found type `Foo` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:64:27 @@ -277,8 +277,8 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected usize, found struct `foo` | - = note: expected type `Foo` - found type `Foo` + = note: expected type `Foo` + found type `Foo` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:65:22 @@ -286,8 +286,8 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected struct `A`, found struct `B` | - = note: expected type `Foo<_, A, _>` - found type `Foo<_, B, _>` + = note: expected type `Foo<_, A>` + found type `Foo<_, B>` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:66:22 @@ -295,8 +295,8 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected struct `bar`, found struct `foo` | - = note: expected type `Foo` - found type `Foo` + = note: expected type `Foo` + found type `Foo` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:67:25 @@ -304,8 +304,8 @@ error[E0308]: mismatched types LL | want::>(f); //~ ERROR mismatched types | ^ expected struct `bar`, found struct `foo` | - = note: expected type `Foo` - found type `Foo` + = note: expected type `Foo` + found type `Foo` error[E0308]: mismatched types --> $DIR/type-mismatch.rs:68:23