From c9fcbda389adfffd72405905de67be1aa444820f Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Fri, 18 Jun 2021 14:13:12 -0500 Subject: [PATCH 1/2] check where clause before suggesting unsized --- .../src/traits/error_reporting/mod.rs | 19 +++++++++++++++++++ ...-where-clause-before-suggesting-unsized.rs | 8 ++++++++ ...re-clause-before-suggesting-unsized.stderr | 18 ++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs create mode 100644 src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 79194718d1efd..305af6db29833 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -14,6 +14,7 @@ use crate::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; @@ -2009,6 +2010,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { Some(param) => param, _ => return, }; + let param_def_id = self.tcx.hir().local_def_id(param.hir_id).to_def_id(); + let preds = generics.where_clause.predicates.iter(); + let explicitly_sized = preds + .filter_map(|pred| match pred { + hir::WherePredicate::BoundPredicate(bp) => Some(bp), + _ => None, + }) + .flat_map(|bp| match bp.bounded_ty.kind { + hir::TyKind::Path(hir::QPath::Resolved( + None, + &hir::Path { res: Res::Def(DefKind::TyParam, def_id), .. }, + )) if def_id == param_def_id => bp.bounds, + _ => &[][..], + }) + .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait); + if explicitly_sized { + return; + } debug!("maybe_suggest_unsized_generics: param={:?}", param); match node { hir::Node::Item( diff --git a/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs b/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs new file mode 100644 index 0000000000000..5cfaf4be96aeb --- /dev/null +++ b/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs @@ -0,0 +1,8 @@ +// Regression test for #85945: Don't suggest `?Sized` bound if an explicit +// `Sized` bound is already in a `where` clause. +fn foo(_: &T) where T: Sized {} +fn bar() { foo(""); } +//~^ERROR the size for values of type + +pub fn main() { +} diff --git a/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr b/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr new file mode 100644 index 0000000000000..92be9f764cc4b --- /dev/null +++ b/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr @@ -0,0 +1,18 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/issue-85945-check-where-clause-before-suggesting-unsized.rs:4:16 + | +LL | fn bar() { foo(""); } + | --- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `str` +note: required by a bound in `foo` + --> $DIR/issue-85945-check-where-clause-before-suggesting-unsized.rs:3:8 + | +LL | fn foo(_: &T) where T: Sized {} + | ^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 1a50725a4d6814abe0f2a03551bb60ba90412959 Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Fri, 18 Jun 2021 19:24:22 -0500 Subject: [PATCH 2/2] refactor is_param_bound --- compiler/rustc_hir/src/hir.rs | 16 ++++++++++++++ .../src/traits/error_reporting/mod.rs | 10 ++------- compiler/rustc_typeck/src/collect.rs | 22 +++---------------- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a441a635c1eb3..e00c5789fe9c7 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -647,6 +647,22 @@ pub struct WhereBoundPredicate<'hir> { pub bounds: GenericBounds<'hir>, } +impl WhereBoundPredicate<'hir> { + /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate. + pub fn is_param_bound(&self, param_def_id: DefId) -> bool { + let path = match self.bounded_ty.kind { + TyKind::Path(QPath::Resolved(None, path)) => path, + _ => return false, + }; + match path.res { + Res::Def(DefKind::TyParam, def_id) | Res::SelfTy(Some(def_id), None) => { + def_id == param_def_id + } + _ => false, + } + } +} + /// A lifetime predicate (e.g., `'a: 'b + 'c`). #[derive(Debug, HashStable_Generic)] pub struct WhereRegionPredicate<'hir> { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 305af6db29833..f8df0e2595973 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -14,7 +14,6 @@ use crate::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; @@ -2017,13 +2016,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { hir::WherePredicate::BoundPredicate(bp) => Some(bp), _ => None, }) - .flat_map(|bp| match bp.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved( - None, - &hir::Path { res: Res::Def(DefKind::TyParam, def_id), .. }, - )) if def_id == param_def_id => bp.bounds, - _ => &[][..], - }) + .filter(|bp| bp.is_param_bound(param_def_id)) + .flat_map(|bp| bp.bounds) .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait); if explicitly_sized { return; diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 2274db76c05fb..2f427305782c5 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -28,7 +28,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::weak_lang_items; @@ -668,6 +668,7 @@ impl ItemCtxt<'tcx> { }) .flat_map(|b| predicates_from_bound(self, ty, b)); + let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id(); let from_where_clauses = ast_generics .where_clause .predicates @@ -677,7 +678,7 @@ impl ItemCtxt<'tcx> { _ => None, }) .flat_map(|bp| { - let bt = if is_param(self.tcx, bp.bounded_ty, param_id) { + let bt = if bp.is_param_bound(param_def_id) { Some(ty) } else if !only_self_bounds.0 { Some(self.to_ty(bp.bounded_ty)) @@ -714,23 +715,6 @@ impl ItemCtxt<'tcx> { } } -/// Tests whether this is the AST for a reference to the type -/// parameter with ID `param_id`. We use this so as to avoid running -/// `ast_ty_to_ty`, because we want to avoid triggering an all-out -/// conversion of the type to avoid inducing unnecessary cycles. -fn is_param(tcx: TyCtxt<'_>, ast_ty: &hir::Ty<'_>, param_id: hir::HirId) -> bool { - if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ast_ty.kind { - match path.res { - Res::SelfTy(Some(def_id), None) | Res::Def(DefKind::TyParam, def_id) => { - def_id == tcx.hir().local_def_id(param_id).to_def_id() - } - _ => false, - } - } else { - false - } -} - fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { let it = tcx.hir().item(item_id); debug!("convert: item {} with id {}", it.ident, it.hir_id());