From 2ea468e386230375229c68a09affcba23cd79487 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 3 Jun 2022 20:00:39 +0200 Subject: [PATCH] dedup diagnostics default params handling --- .../src/infer/error_reporting/mod.rs | 56 ++++--------------- .../infer/error_reporting/need_type_info.rs | 24 +------- compiler/rustc_middle/src/ty/generics.rs | 37 +++++++++++- compiler/rustc_middle/src/ty/print/mod.rs | 39 +------------ compiler/rustc_middle/src/ty/print/pretty.rs | 27 ++++----- .../defaults/rp_impl_trait_fail.rs | 4 +- .../defaults/rp_impl_trait_fail.stderr | 8 +-- .../defaults/trait_objects_fail.rs | 2 +- .../defaults/trait_objects_fail.stderr | 6 +- 9 files changed, 72 insertions(+), 131 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 18fc1158b042..1181925dd967 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -67,10 +67,8 @@ use rustc_hir::{Item, ItemKind, Node}; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, - error::TypeError, - subst::{GenericArgKind, Subst, SubstsRef}, - Binder, EarlyBinder, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable, + TypeSuperFoldable, }; use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; @@ -926,10 +924,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { mut t1_out: &mut DiagnosticStyledString, mut t2_out: &mut DiagnosticStyledString, path: String, - sub: ty::subst::SubstsRef<'tcx>, + sub: &'tcx [ty::GenericArg<'tcx>], other_path: String, other_ty: Ty<'tcx>, ) -> Option<()> { + // FIXME/HACK: Go back to `SubstsRef` to use its inherent methods, + // ideally that shouldn't be necessary. + let sub = self.tcx.intern_substs(sub); for (i, ta) in sub.types().enumerate() { if ta == other_ty { self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, other_ty); @@ -960,45 +961,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - /// For generic types with parameters with defaults, remove the parameters corresponding to - /// the defaults. This repeats a lot of the logic found in `ty::print::pretty`. - fn strip_generic_default_params( - &self, - def_id: DefId, - substs: ty::subst::SubstsRef<'tcx>, - ) -> SubstsRef<'tcx> { - let generics = self.tcx.generics_of(def_id); - let mut num_supplied_defaults = 0; - - let default_params = generics.params.iter().rev().filter_map(|param| match param.kind { - ty::GenericParamDefKind::Type { has_default: true, .. } => Some(param.def_id), - ty::GenericParamDefKind::Const { has_default: true } => Some(param.def_id), - _ => None, - }); - for (def_id, actual) in iter::zip(default_params, substs.iter().rev()) { - match actual.unpack() { - GenericArgKind::Const(c) => { - if EarlyBinder(self.tcx.const_param_default(def_id)).subst(self.tcx, substs) - != c - { - break; - } - } - GenericArgKind::Type(ty) => { - if self.tcx.bound_type_of(def_id).subst(self.tcx, substs) != ty { - break; - } - } - _ => 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) - } - /// Given two `fn` signatures highlight only sub-parts that are different. fn cmp_fn_sig( &self, @@ -1156,8 +1118,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => { let did1 = def1.did(); let did2 = def2.did(); - let sub_no_defaults_1 = self.strip_generic_default_params(did1, sub1); - let sub_no_defaults_2 = self.strip_generic_default_params(did2, sub2); + let sub_no_defaults_1 = + self.tcx.generics_of(did1).own_substs_no_defaults(self.tcx, sub1); + let sub_no_defaults_2 = + self.tcx.generics_of(did2).own_substs_no_defaults(self.tcx, sub2); let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); let path1 = self.tcx.def_path_str(did1); let path2 = self.tcx.def_path_str(did2); diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 7b5c377f7b4c..7c4477b61728 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -11,7 +11,7 @@ use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; -use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, InferConst}; +use rustc_middle::ty::{self, DefIdTree, InferConst}; use rustc_middle::ty::{Ty, TyCtxt, TypeckResults}; use rustc_span::symbol::{kw, Ident}; use rustc_span::{BytePos, Span}; @@ -958,26 +958,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { generics.own_substs(substs).iter().position(|&arg| self.generic_arg_is_target(arg)) { let substs = self.infcx.resolve_vars_if_possible(substs); - let num_args = generics - .params - .iter() - .rev() - .filter(|&p| !matches!(p.kind, GenericParamDefKind::Lifetime)) - .skip_while(|¶m| { - if let Some(default) = param.default_value(tcx) { - // FIXME: Using structural comparisions has a bunch of false negatives. - // - // We should instead try to replace inference variables with placeholders and - // then use `infcx.can_eq`. That probably should be a separate method - // generally used during error reporting. - default.subst(tcx, substs) == substs[param.index as usize] - } else { - false - } - }) - .count(); - let generic_args = - &generics.own_substs(substs)[generics.own_counts().lifetimes..][..num_args]; + let generic_args = &generics.own_substs_no_defaults(tcx, substs) + [generics.own_counts().lifetimes..]; let span = match expr.kind { ExprKind::MethodCall(path, _, _) => path.ident.span, _ => expr.span, diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 1feabb2d6b12..5b0b56933ec0 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -228,8 +228,43 @@ impl<'tcx> Generics { }) } + /// Returns the substs corresponding to the generic parameters + /// of this item, excluding `Self`. + pub fn own_substs_no_defaults( + &'tcx self, + tcx: TyCtxt<'tcx>, + substs: &'tcx [ty::GenericArg<'tcx>], + ) -> &'tcx [ty::GenericArg<'tcx>] { + let mut own_params = self.parent_count..self.count(); + if self.has_self && self.parent.is_none() { + own_params.start = 1; + } + + // Filter the default arguments. + // + // This currently uses structural equality instead + // of semantic equivalance. While not ideal, that's + // good enough for now as this should only be used + // for diagnostics anyways. + own_params.end -= self + .params + .iter() + .rev() + .take_while(|param| { + param.default_value(tcx).map_or(false, |default| { + default.subst(tcx, substs) == substs[param.index as usize] + }) + }) + .count(); + + &substs[own_params] + } + /// Returns the substs corresponding to the generic parameters of this item, excluding `Self`. - pub fn own_substs(&'tcx self, substs: SubstsRef<'tcx>) -> &'tcx [ty::GenericArg<'tcx>] { + pub fn own_substs( + &'tcx self, + substs: &'tcx [ty::GenericArg<'tcx>], + ) -> &'tcx [ty::GenericArg<'tcx>] { let own = &substs[self.parent_count..][..self.params.len()]; if self.has_self && self.parent.is_none() { &own[1..] } else { &own } } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 9d8124eb25db..5ad93d778208 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -149,7 +149,7 @@ pub trait Printer<'tcx>: Sized { // on top of the same path, but without its own generics. _ => { if !generics.params.is_empty() && substs.len() >= generics.count() { - let args = self.generic_args_to_print(generics, substs); + let args = generics.own_substs_no_defaults(self.tcx(), substs); return self.path_generic_args( |cx| cx.print_def_path(def_id, parent_substs), args, @@ -184,43 +184,6 @@ pub trait Printer<'tcx>: Sized { } } - fn generic_args_to_print( - &self, - generics: &'tcx ty::Generics, - substs: &'tcx [GenericArg<'tcx>], - ) -> &'tcx [GenericArg<'tcx>] { - let mut own_params = generics.parent_count..generics.count(); - - // Don't print args for `Self` parameters (of traits). - if generics.has_self && own_params.start == 0 { - own_params.start = 1; - } - - // Don't print args that are the defaults of their respective parameters. - own_params.end -= generics - .params - .iter() - .rev() - .take_while(|param| match param.kind { - ty::GenericParamDefKind::Lifetime => false, - ty::GenericParamDefKind::Type { has_default, .. } => { - has_default - && substs[param.index as usize] - == GenericArg::from( - self.tcx().bound_type_of(param.def_id).subst(self.tcx(), substs), - ) - } - ty::GenericParamDefKind::Const { has_default } => { - has_default - && substs[param.index as usize] - == GenericArg::from(self.tcx().const_param_default(param.def_id)) - } - }) - .count(); - - &substs[own_params] - } - fn default_print_impl_path( self, impl_def_id: DefId, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7328b18a3283..53a97a46b2d2 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -825,12 +825,11 @@ pub trait PrettyPrinter<'tcx>: for (fn_once_trait_ref, entry) in fn_traits { // Get the (single) generic ty (the args) of this FnOnce trait ref. - let generics = self.generic_args_to_print( - self.tcx().generics_of(fn_once_trait_ref.def_id()), - fn_once_trait_ref.skip_binder().substs, - ); + let generics = self.tcx().generics_of(fn_once_trait_ref.def_id()); + let args = + generics.own_substs_no_defaults(self.tcx(), fn_once_trait_ref.skip_binder().substs); - match (entry.return_ty, generics[0].expect_ty()) { + match (entry.return_ty, args[0].expect_ty()) { // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded // a return type. (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => { @@ -892,15 +891,13 @@ pub trait PrettyPrinter<'tcx>: print(trait_ref.skip_binder().print_only_trait_name()) ); - let generics = self.generic_args_to_print( - self.tcx().generics_of(trait_ref.def_id()), - trait_ref.skip_binder().substs, - ); + let generics = self.tcx().generics_of(trait_ref.def_id()); + let args = generics.own_substs_no_defaults(self.tcx(), trait_ref.skip_binder().substs); - if !generics.is_empty() || !assoc_items.is_empty() { + if !args.is_empty() || !assoc_items.is_empty() { let mut first = true; - for ty in generics { + for ty in args { if first { p!("<"); first = false; @@ -1071,10 +1068,10 @@ pub trait PrettyPrinter<'tcx>: let dummy_cx = cx.tcx().mk_ty_infer(ty::FreshTy(0)); let principal = principal.with_self_ty(cx.tcx(), dummy_cx); - let args = cx.generic_args_to_print( - cx.tcx().generics_of(principal.def_id), - principal.substs, - ); + let args = cx + .tcx() + .generics_of(principal.def_id) + .own_substs_no_defaults(cx.tcx(), principal.substs); // Don't print `'_` if there's no unerased regions. let print_regions = args.iter().any(|arg| match arg.unpack() { diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs index 308c121a9411..f633e56b0ec1 100644 --- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs +++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs @@ -15,12 +15,12 @@ impl Traitor<1, 2> for u64 {} fn uwu() -> impl Traitor { - //~^ error: the trait bound `u32: Traitor` is not satisfied + //~^ error: the trait bound `u32: Traitor` is not satisfied 1_u32 } fn owo() -> impl Traitor { - //~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied + //~^ error: the trait bound `u64: Traitor` is not satisfied 1_u64 } diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr index 8031da28ca1f..cbe4a4ac0d65 100644 --- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr +++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr @@ -6,21 +6,21 @@ LL | fn rawr() -> impl Trait { | = help: the trait `Trait` is implemented for `Uwu` -error[E0277]: the trait bound `u32: Traitor` is not satisfied +error[E0277]: the trait bound `u32: Traitor` is not satisfied --> $DIR/rp_impl_trait_fail.rs:17:26 | LL | fn uwu() -> impl Traitor { - | ^^^^^^^^^^^^^^^ the trait `Traitor` is not implemented for `u32` + | ^^^^^^^^^^^^^^^ the trait `Traitor` is not implemented for `u32` | = help: the following other types implement trait `Traitor`: > > -error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied +error[E0277]: the trait bound `u64: Traitor` is not satisfied --> $DIR/rp_impl_trait_fail.rs:22:13 | LL | fn owo() -> impl Traitor { - | ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64` + | ^^^^^^^^^^^^ the trait `Traitor` is not implemented for `u64` | = help: the following other types implement trait `Traitor`: > diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.rs b/src/test/ui/const-generics/defaults/trait_objects_fail.rs index 7ba12d02b6e7..5e779d2e8de5 100644 --- a/src/test/ui/const-generics/defaults/trait_objects_fail.rs +++ b/src/test/ui/const-generics/defaults/trait_objects_fail.rs @@ -26,5 +26,5 @@ fn main() { foo(&10_u32); //~^ error: the trait bound `u32: Trait` is not satisfied bar(&true); - //~^ error: the trait bound `bool: Traitor<{_: u8}, {_: u8}>` is not satisfied + //~^ error: the trait bound `bool: Traitor<{_: u8}>` is not satisfied } diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr index 7f8a1f742d84..60dc96f675a8 100644 --- a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr +++ b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr @@ -9,16 +9,16 @@ LL | foo(&10_u32); = help: the trait `Trait<2_u8>` is implemented for `u32` = note: required for the cast to the object type `dyn Trait` -error[E0277]: the trait bound `bool: Traitor<{_: u8}, {_: u8}>` is not satisfied +error[E0277]: the trait bound `bool: Traitor<{_: u8}>` is not satisfied --> $DIR/trait_objects_fail.rs:28:9 | LL | bar(&true); - | --- ^^^^^ the trait `Traitor<{_: u8}, {_: u8}>` is not implemented for `bool` + | --- ^^^^^ the trait `Traitor<{_: u8}>` is not implemented for `bool` | | | required by a bound introduced by this call | = help: the trait `Traitor<2_u8, 3_u8>` is implemented for `bool` - = note: required for the cast to the object type `dyn Traitor<{_: u8}, {_: u8}>` + = note: required for the cast to the object type `dyn Traitor<{_: u8}>` error: aborting due to 2 previous errors