diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index e1e8f6a61adb817038607d3c103394d97c29e531..70c74940d6235e117b8400a96d8d6eba851f643a 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -259,7 +259,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { // We add implied bounds from both the unnormalized and normalized ty // See issue #87748 let constraints_implied_1 = self.add_implied_bounds(ty); - let TypeOpOutput { output: ty, constraints: constraints1, .. } = self + let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self .param_env .and(type_op::normalize::Normalize::new(ty)) .fully_perform(self.infcx) @@ -286,8 +286,9 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { // } // ``` // Both &Self::Bar and &() are WF - let constraints_implied_2 = self.add_implied_bounds(ty); - normalized_inputs_and_output.push(ty); + let constraints_implied_2 = + if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None }; + normalized_inputs_and_output.push(norm_ty); constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2) }) .collect(); diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index c90649353e80f391b5739378a3bd29813bd5e22f..42cbed600d5bf92229ca6f6ff55002ded9d53d2c 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -2,6 +2,7 @@ use crate::traits::query::outlives_bounds::InferCtxtExt as _; use crate::traits::{self, TraitEngine, TraitEngineExt}; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; @@ -184,7 +185,7 @@ pub trait OutlivesEnvironmentExt<'tcx> { fn add_implied_bounds( &mut self, infcx: &InferCtxt<'a, 'tcx>, - fn_sig_tys: &[Ty<'tcx>], + fn_sig_tys: FxHashSet>, body_id: hir::HirId, span: Span, ); @@ -210,13 +211,13 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { fn add_implied_bounds( &mut self, infcx: &InferCtxt<'a, 'tcx>, - fn_sig_tys: &[Ty<'tcx>], + fn_sig_tys: FxHashSet>, body_id: hir::HirId, span: Span, ) { debug!("add_implied_bounds()"); - for &ty in fn_sig_tys { + for ty in fn_sig_tys { let ty = infcx.resolve_vars_if_possible(ty); debug!("add_implied_bounds: ty = {}", ty); let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 3c9d5b4def4e7a83a67655167919346a98b78eb7..1fd1253e5277d88a11a57dcf08887d3be94df09c 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -688,7 +688,7 @@ fn check_opaque_meets_bounds<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let fcx = FnCtxt::new(&inh, param_env, hir_id); - fcx.regionck_item(hir_id, span, &[]); + fcx.regionck_item(hir_id, span, FxHashSet::default()); }); } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index d59291b8fd493e1a1c2106e7c629585ac3ff167a..d5b631df058aef9c12428677dbfa52f7aec344d3 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1,4 +1,5 @@ use crate::errors::LifetimesOrBoundsMismatchOnTrait; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -250,7 +251,7 @@ fn compare_predicate_entailment<'tcx>( // Compute placeholder form of impl and trait method tys. let tcx = infcx.tcx; - let mut wf_tys = vec![]; + let mut wf_tys = FxHashSet::default(); let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, @@ -398,7 +399,7 @@ fn compare_predicate_entailment<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id); - fcx.regionck_item(impl_m_hir_id, impl_m_span, &wf_tys); + fcx.regionck_item(impl_m_hir_id, impl_m_span, wf_tys); Ok(()) }) @@ -1098,7 +1099,7 @@ fn compare_const_param_types<'tcx>( } let fcx = FnCtxt::new(&inh, param_env, impl_c_hir_id); - fcx.regionck_item(impl_c_hir_id, impl_c_span, &[]); + fcx.regionck_item(impl_c_hir_id, impl_c_span, FxHashSet::default()); }); } @@ -1216,7 +1217,7 @@ fn compare_type_predicate_entailment<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id); - fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]); + fcx.regionck_item(impl_ty_hir_id, impl_ty_span, FxHashSet::default()); Ok(()) }) @@ -1436,10 +1437,10 @@ pub fn check_type_bounds<'tcx>( // lifetime parameters. let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id); let implied_bounds = match impl_ty.container { - ty::TraitContainer(_) => vec![], + ty::TraitContainer(_) => FxHashSet::default(), ty::ImplContainer(def_id) => fcx.impl_implied_bounds(def_id, impl_ty_span), }; - fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &implied_bounds); + fcx.regionck_item(impl_ty_hir_id, impl_ty_span, implied_bounds); Ok(()) }) diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 803c440bbc98b3ae6f06aed391238390d38ea9df..a10490a9a15c7b75a4db20790d62c4bad5e0f394 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -388,7 +388,7 @@ fn typeck_with_fallback<'tcx>( // from normalization. We could just discard these, but to align with // compare_method and elsewhere, we just add implied bounds for // these types. - let mut wf_tys = vec![]; + let mut wf_tys = FxHashSet::default(); // Compute the fty from point of view of inside the fn. let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); wf_tys.extend(fn_sig.inputs_and_output.iter()); @@ -451,7 +451,7 @@ fn typeck_with_fallback<'tcx>( fcx.write_ty(id, expected_type); - (fcx, vec![]) + (fcx, FxHashSet::default()) }; let fallback_has_occurred = fcx.type_inference_fallback(); @@ -475,7 +475,7 @@ fn typeck_with_fallback<'tcx>( fcx.select_all_obligations_or_error(); if fn_sig.is_some() { - fcx.regionck_fn(id, body, span, &wf_tys); + fcx.regionck_fn(id, body, span, wf_tys); } else { fcx.regionck_expr(body); } diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 290fa5fc36719278954ab0e9963399234d2d9ff3..134604a0e32b41ffea5e291c32ac60097f9011da 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -76,6 +76,7 @@ use crate::check::FnCtxt; use crate::mem_categorization as mc; use crate::middle::region; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; @@ -126,7 +127,7 @@ pub fn regionck_expr(&self, body: &'tcx hir::Body<'tcx>) { /// Region checking during the WF phase for items. `wf_tys` are the /// types from which we should derive implied bounds, if any. - pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: &[Ty<'tcx>]) { + pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: FxHashSet>) { debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys); let subject = self.tcx.hir().local_def_id(item_id); let mut rcx = RegionCtxt::new(self, item_id, Subject(subject), self.param_env); @@ -149,7 +150,7 @@ pub(crate) fn regionck_fn( fn_id: hir::HirId, body: &'tcx hir::Body<'tcx>, span: Span, - wf_tys: &[Ty<'tcx>], + wf_tys: FxHashSet>, ) { debug!("regionck_fn(id={})", fn_id); let subject = self.tcx.hir().body_owner_def_id(body.id()); @@ -286,15 +287,10 @@ fn visit_fn_body( // because it will have no effect. // // FIXME(#27579) return types should not be implied bounds - let fn_sig_tys: Vec<_> = + let fn_sig_tys: FxHashSet<_> = fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect(); - self.outlives_environment.add_implied_bounds( - self.fcx, - &fn_sig_tys[..], - body_id.hir_id, - span, - ); + self.outlives_environment.add_implied_bounds(self.fcx, fn_sig_tys, body_id.hir_id, span); self.outlives_environment.save_implied_bounds(body_id.hir_id); self.link_fn_params(&body.params); self.visit_body(body); diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 17716afe3208fee68882fa83bdeb4d45cd6e6730..cb07fcf5fef5813fba8341be925567b9d55df4cc 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -44,7 +44,7 @@ struct CheckWfFcxBuilder<'tcx> { impl<'tcx> CheckWfFcxBuilder<'tcx> { fn with_fcx(&mut self, f: F) where - F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> Vec>, + F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> FxHashSet>, { let id = self.id; let span = self.span; @@ -59,7 +59,7 @@ fn with_fcx(&mut self, f: F) } let wf_tys = f(&fcx); fcx.select_all_obligations_or_error(); - fcx.regionck_item(id, span, &wf_tys); + fcx.regionck_item(id, span, wf_tys); }); } } @@ -394,7 +394,7 @@ fn check_associated_item( let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id)); let (mut implied_bounds, self_ty) = match item.container { - ty::TraitContainer(_) => (vec![], fcx.tcx.types.self_param), + ty::TraitContainer(_) => (FxHashSet::default(), fcx.tcx.types.self_param), ty::ImplContainer(def_id) => { (fcx.impl_implied_bounds(def_id, span), fcx.tcx.type_of(def_id)) } @@ -553,7 +553,7 @@ fn check_type_defn<'tcx, F>( check_where_clauses(fcx, item.span, item.def_id.to_def_id(), None); // No implied bounds in a struct definition. - vec![] + FxHashSet::default() }); } @@ -579,7 +579,7 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { for_item(tcx, item).with_fcx(|fcx| { check_where_clauses(fcx, item.span, item.def_id.to_def_id(), None); - vec![] + FxHashSet::default() }); } @@ -620,7 +620,7 @@ fn check_item_fn( for_id(tcx, item_id, span).with_fcx(|fcx| { let def_id = tcx.hir().local_def_id(item_id); let sig = tcx.fn_sig(def_id); - let mut implied_bounds = vec![]; + let mut implied_bounds = FxHashSet::default(); check_fn_or_method(fcx, ident.span, sig, decl, def_id.to_def_id(), &mut implied_bounds); implied_bounds }) @@ -659,7 +659,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo } // No implied bounds in a const, etc. - vec![] + FxHashSet::default() }); } @@ -918,14 +918,14 @@ fn check_fn_or_method<'fcx, 'tcx>( sig: ty::PolyFnSig<'tcx>, hir_decl: &hir::FnDecl<'_>, def_id: DefId, - implied_bounds: &mut Vec>, + implied_bounds: &mut FxHashSet>, ) { let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig); // Unnormalized types in signature are WF too implied_bounds.extend(sig.inputs()); // FIXME(#27579) return types should not be implied bounds - implied_bounds.push(sig.output()); + implied_bounds.insert(sig.output()); // Normalize the input and output types one at a time, using a different // `WellFormedLoc` for each. We cannot call `normalize_associated_types` @@ -977,7 +977,7 @@ fn check_fn_or_method<'fcx, 'tcx>( ); // FIXME(#27579) return types should not be implied bounds - implied_bounds.push(sig.output()); + implied_bounds.insert(sig.output()); debug!(?implied_bounds); @@ -1513,7 +1513,11 @@ fn enum_variants(&self, enum_def: &hir::EnumDef<'_>) -> Vec> { .collect() } - pub(super) fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec> { + pub(super) fn impl_implied_bounds( + &self, + impl_def_id: DefId, + span: Span, + ) -> FxHashSet> { match self.tcx.impl_trait_ref(impl_def_id) { Some(trait_ref) => { // Trait impl: take implied bounds from all types that @@ -1526,7 +1530,7 @@ pub(super) fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec< // Inherent impl: take implied bounds from the `self` type. let self_ty = self.tcx.type_of(impl_def_id); let self_ty = self.normalize_associated_types_in(span, self_ty); - vec![self_ty] + std::array::IntoIter::new([self_ty]).collect() } } }