From f3f68324cc0eddf115270a71147738eb94cbcad0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 23 Mar 2022 09:41:31 +0100 Subject: [PATCH] move unique param check into `rustc_middle` --- compiler/rustc_middle/src/ty/util.rs | 119 +++++++++++++----- compiler/rustc_typeck/src/coherence/orphan.rs | 58 +-------- 2 files changed, 93 insertions(+), 84 deletions(-) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 55f08b5678a..bf066f65aeb 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -5,10 +5,7 @@ use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; -use crate::ty::{ - self, DebruijnIndex, DefIdTree, EarlyBinder, List, ReEarlyBound, Ty, TyCtxt, TyKind::*, - TypeFoldable, -}; +use crate::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable}; use rustc_apfloat::Float as _; use rustc_ast as ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; @@ -18,6 +15,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_index::bit_set::GrowableBitSet; use rustc_macros::HashStable; use rustc_span::{sym, DUMMY_SP}; use rustc_target::abi::{Integer, Size, TargetDataLayout}; @@ -32,6 +30,12 @@ pub struct Discr<'tcx> { pub ty: Ty<'tcx>, } +#[derive(Copy, Clone, Debug)] +pub enum NotUniqueParam<'tcx> { + DuplicateParam(ty::GenericArg<'tcx>), + NotParam(ty::GenericArg<'tcx>), +} + impl<'tcx> fmt::Display for Discr<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match *self.ty.kind() { @@ -49,8 +53,8 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) { let (int, signed) = match *ty.kind() { - Int(ity) => (Integer::from_int_ty(&tcx, ity), true), - Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false), + ty::Int(ity) => (Integer::from_int_ty(&tcx, ity), true), + ty::Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false), _ => bug!("non integer discriminant"), }; (int.size(), signed) @@ -176,7 +180,7 @@ pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { if let ty::Adt(def, substs) = *ty.kind() { for field in def.all_fields() { let field_ty = field.ty(self, substs); - if let Error(_) = field_ty.kind() { + if let ty::Error(_) = field_ty.kind() { return true; } } @@ -311,7 +315,7 @@ pub fn struct_lockstep_tails_with_normalize( let (mut a, mut b) = (source, target); loop { match (&a.kind(), &b.kind()) { - (&Adt(a_def, a_substs), &Adt(b_def, b_substs)) + (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def && a_def.is_struct() => { if let Some(f) = a_def.non_enum_variant().fields.last() { @@ -321,7 +325,7 @@ pub fn struct_lockstep_tails_with_normalize( break; } } - (&Tuple(a_tys), &Tuple(b_tys)) if a_tys.len() == b_tys.len() => { + (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) if a_tys.len() == b_tys.len() => { if let Some(&a_last) = a_tys.last() { a = a_last; b = *b_tys.last().unwrap(); @@ -427,7 +431,7 @@ pub fn destructor_constraints(self, def: ty::AdtDef<'tcx>) -> Vec match region.kind() { - ReEarlyBound(ref ebr) => { + ty::ReEarlyBound(ref ebr) => { !impl_generics.region_param(ebr, self).pure_wrt_drop } // Error: not a region param @@ -453,6 +457,49 @@ pub fn destructor_constraints(self, def: ty::AdtDef<'tcx>) -> Vec, + ignore_regions: bool, + ) -> Result<(), NotUniqueParam<'tcx>> { + let mut seen = GrowableBitSet::default(); + for arg in substs { + match arg.unpack() { + GenericArgKind::Lifetime(lt) => { + if !ignore_regions { + match lt.kind() { + ty::ReEarlyBound(p) => { + if !seen.insert(p.index) { + return Err(NotUniqueParam::DuplicateParam(lt.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(lt.into())), + } + } + } + GenericArgKind::Type(t) => match t.kind() { + ty::Param(p) => { + if !seen.insert(p.index) { + return Err(NotUniqueParam::DuplicateParam(t.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(t.into())), + }, + GenericArgKind::Const(c) => match c.val() { + ty::ConstKind::Param(p) => { + if !seen.insert(p.index) { + return Err(NotUniqueParam::DuplicateParam(c.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(c.into())), + }, + } + } + + Ok(()) + } + /// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note /// that closures have a `DefId`, but the closure *expression* also /// has a `HirId` that is located within the context where the @@ -594,30 +641,33 @@ pub fn try_expand_impl_trait_type( if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - pub fn bound_type_of(self, def_id: DefId) -> EarlyBinder> { - EarlyBinder(self.type_of(def_id)) + pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder> { + ty::EarlyBinder(self.type_of(def_id)) } - pub fn bound_fn_sig(self, def_id: DefId) -> EarlyBinder> { - EarlyBinder(self.fn_sig(def_id)) + pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder> { + ty::EarlyBinder(self.fn_sig(def_id)) } - pub fn bound_impl_trait_ref(self, def_id: DefId) -> Option>> { - self.impl_trait_ref(def_id).map(|i| EarlyBinder(i)) + pub fn bound_impl_trait_ref( + self, + def_id: DefId, + ) -> Option>> { + self.impl_trait_ref(def_id).map(|i| ty::EarlyBinder(i)) } pub fn bound_explicit_item_bounds( self, def_id: DefId, - ) -> EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> { - EarlyBinder(self.explicit_item_bounds(def_id)) + ) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> { + ty::EarlyBinder(self.explicit_item_bounds(def_id)) } pub fn bound_item_bounds( self, def_id: DefId, - ) -> EarlyBinder<&'tcx ty::List>> { - EarlyBinder(self.item_bounds(def_id)) + ) -> ty::EarlyBinder<&'tcx ty::List>> { + ty::EarlyBinder(self.item_bounds(def_id)) } } @@ -930,35 +980,40 @@ pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tc pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { // Look for an impl of both `PartialStructuralEq` and `StructuralEq`. - Adt(..) => tcx.has_structural_eq_impls(self), + ty::Adt(..) => tcx.has_structural_eq_impls(self), // Primitive types that satisfy `Eq`. - Bool | Char | Int(_) | Uint(_) | Str | Never => true, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => true, // Composite types that satisfy `Eq` when all of their fields do. // // Because this function is "shallow", we return `true` for these composites regardless // of the type(s) contained within. - Ref(..) | Array(..) | Slice(_) | Tuple(..) => true, + ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true, // Raw pointers use bitwise comparison. - RawPtr(_) | FnPtr(_) => true, + ty::RawPtr(_) | ty::FnPtr(_) => true, // Floating point numbers are not `Eq`. - Float(_) => false, + ty::Float(_) => false, // Conservatively return `false` for all others... // Anonymous function types - FnDef(..) | Closure(..) | Dynamic(..) | Generator(..) => false, + ty::FnDef(..) | ty::Closure(..) | ty::Dynamic(..) | ty::Generator(..) => false, // Generic or inferred types // // FIXME(ecstaticmorse): Maybe we should `bug` here? This should probably only be // called for known, fully-monomorphized types. - Projection(_) | Opaque(..) | Param(_) | Bound(..) | Placeholder(_) | Infer(_) => false, + ty::Projection(_) + | ty::Opaque(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(_) => false, - Foreign(_) | GeneratorWitness(..) | Error(_) => false, + ty::Foreign(_) | ty::GeneratorWitness(..) | ty::Error(_) => false, } } @@ -974,13 +1029,13 @@ pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool { /// - `&'a *const &'b u8 -> *const &'b u8` pub fn peel_refs(self) -> Ty<'tcx> { let mut ty = self; - while let Ref(_, inner_ty, _) = ty.kind() { + while let ty::Ref(_, inner_ty, _) = ty.kind() { ty = *inner_ty; } ty } - pub fn outer_exclusive_binder(self) -> DebruijnIndex { + pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { self.0.outer_exclusive_binder } } @@ -1177,8 +1232,8 @@ pub fn fold_list<'tcx, F, T>( /// with their underlying types. pub fn normalize_opaque_types<'tcx>( tcx: TyCtxt<'tcx>, - val: &'tcx List>, -) -> &'tcx List> { + val: &'tcx ty::List>, +) -> &'tcx ty::List> { let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), expanded_cache: FxHashMap::default(), diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index f57986a985c..ad8a84d536f 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -5,10 +5,9 @@ use rustc_errors::struct_span_err; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; +use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_session::lint; use rustc_span::def_id::{DefId, LocalDefId}; @@ -325,51 +324,6 @@ fn emit_orphan_check_error<'tcx>( }) } -#[derive(Default)] -struct AreUniqueParamsVisitor { - seen: GrowableBitSet, -} - -#[derive(Copy, Clone)] -enum NotUniqueParam<'tcx> { - DuplicateParam(GenericArg<'tcx>), - NotParam(GenericArg<'tcx>), -} - -impl<'tcx> TypeVisitor<'tcx> for AreUniqueParamsVisitor { - type BreakTy = NotUniqueParam<'tcx>; - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - match t.kind() { - ty::Param(p) => { - if self.seen.insert(p.index) { - ControlFlow::CONTINUE - } else { - ControlFlow::Break(NotUniqueParam::DuplicateParam(t.into())) - } - } - _ => ControlFlow::Break(NotUniqueParam::NotParam(t.into())), - } - } - fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow { - // We don't drop candidates during candidate assembly because of region - // constraints, so the behavior for impls only constrained by regions - // will not change. - ControlFlow::CONTINUE - } - fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { - match c.val() { - ty::ConstKind::Param(p) => { - if self.seen.insert(p.index) { - ControlFlow::CONTINUE - } else { - ControlFlow::Break(NotUniqueParam::DuplicateParam(c.into())) - } - } - _ => ControlFlow::Break(NotUniqueParam::NotParam(c.into())), - } - } -} - /// Lint impls of auto traits if they are likely to have /// unsound or surprising effects on auto impls. fn lint_auto_trait_impls(tcx: TyCtxt<'_>, trait_def_id: DefId, impls: &[LocalDefId]) { @@ -400,9 +354,9 @@ fn lint_auto_trait_impls(tcx: TyCtxt<'_>, trait_def_id: DefId, impls: &[LocalDef // Impls which completely cover a given root type are fine as they // disable auto impls entirely. So only lint if the substs // are not a permutation of the identity substs. - match substs.visit_with(&mut AreUniqueParamsVisitor::default()) { - ControlFlow::Continue(()) => {} // ok - ControlFlow::Break(arg) => { + match tcx.uses_unique_generic_params(substs, true) { + Ok(()) => {} // ok + Err(arg) => { // Ideally: // // - compute the requirements for the auto impl candidate @@ -444,10 +398,10 @@ fn lint_auto_trait_impls(tcx: TyCtxt<'_>, trait_def_id: DefId, impls: &[LocalDef ), ); match arg { - NotUniqueParam::DuplicateParam(arg) => { + ty::util::NotUniqueParam::DuplicateParam(arg) => { err.note(&format!("`{}` is mentioned multiple times", arg)); } - NotUniqueParam::NotParam(arg) => { + ty::util::NotUniqueParam::NotParam(arg) => { err.note(&format!("`{}` is not a generic parameter", arg)); } }