diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2023-05-02 11:44:50 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-05-02 11:44:50 +0530 |
| commit | b727132e23aaa4e80eb82816d95c20023940f916 (patch) | |
| tree | 95fb9d868e6a15a303950217f2519a381bf5b805 /compiler/rustc_trait_selection/src | |
| parent | f916c44aecfc6c610f2d23cf929644aa08123547 (diff) | |
| parent | c31754651da17b207fa7fb94c2f3ba2c188aa0b1 (diff) | |
| download | rust-b727132e23aaa4e80eb82816d95c20023940f916.tar.gz rust-b727132e23aaa4e80eb82816d95c20023940f916.zip | |
Rollup merge of #108161 - WaffleLapkin:const_param_ty, r=BoxyUwU
Add `ConstParamTy` trait This is a bit sketch, but idk. r? `@BoxyUwU` Yet to be done: - [x] ~~Figure out if it's okay to implement `StructuralEq` for primitives / possibly remove their special casing~~ (it should be okay, but maybe not in this PR...) - [ ] Maybe refactor the code a little bit - [x] Use a macro to make impls a bit nicer Future work: - [ ] Actuallyâ„¢ use the trait when checking if a `const` generic type is allowed - [ ] _Really_ refactor the surrounding code - [ ] Refactor `marker.rs` into multiple modules for each "theme" of markers
Diffstat (limited to 'compiler/rustc_trait_selection/src')
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/misc.rs | 101 |
1 files changed, 86 insertions, 15 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 63949843aed..2210ef975e6 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -2,13 +2,14 @@ use crate::traits::{self, ObligationCause, ObligationCtxt}; +use hir::LangItem; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError}; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, AdtDef, GenericArg, List, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::DUMMY_SP; use super::outlives_bounds::InferCtxtExt; @@ -19,6 +20,11 @@ pub enum CopyImplementationError<'tcx> { HasDestructor, } +pub enum ConstParamTyImplementationError<'tcx> { + InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>), + NotAnAdtOrBuiltinAllowed, +} + pub enum InfringingFieldsReason<'tcx> { Fulfill(Vec<FulfillmentError<'tcx>>), Regions(Vec<RegionResolutionError<'tcx>>), @@ -27,7 +33,10 @@ pub enum InfringingFieldsReason<'tcx> { /// Checks that the fields of the type (an ADT) all implement copy. /// /// If fields don't implement copy, return an error containing a list of -/// those violating fields. If it's not an ADT, returns `Err(NotAnAdt)`. +/// those violating fields. +/// +/// If it's not an ADT, int ty, `bool`, float ty, `char`, raw pointer, `!`, +/// a reference or an array returns `Err(NotAnAdt)`. pub fn type_allowed_to_implement_copy<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -47,12 +56,82 @@ pub fn type_allowed_to_implement_copy<'tcx>( | ty::Ref(_, _, hir::Mutability::Not) | ty::Array(..) => return Ok(()), - ty::Adt(adt, substs) => (adt, substs), + &ty::Adt(adt, substs) => (adt, substs), _ => return Err(CopyImplementationError::NotAnAdt), }; - let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span)); + all_fields_implement_trait( + tcx, + param_env, + self_type, + adt, + substs, + parent_cause, + hir::LangItem::Copy, + ) + .map_err(CopyImplementationError::InfringingFields)?; + + if adt.has_dtor(tcx) { + return Err(CopyImplementationError::HasDestructor); + } + + Ok(()) +} + +/// Checks that the fields of the type (an ADT) all implement `ConstParamTy`. +/// +/// If fields don't implement `ConstParamTy`, return an error containing a list of +/// those violating fields. +/// +/// If it's not an ADT, int ty, `bool` or `char`, returns `Err(NotAnAdtOrBuiltinAllowed)`. +pub fn type_allowed_to_implement_const_param_ty<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + self_type: Ty<'tcx>, + parent_cause: ObligationCause<'tcx>, +) -> Result<(), ConstParamTyImplementationError<'tcx>> { + let (adt, substs) = match self_type.kind() { + // `core` provides these impls. + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Char + | ty::Str + | ty::Array(..) + | ty::Slice(_) + | ty::Ref(.., hir::Mutability::Not) => return Ok(()), + + &ty::Adt(adt, substs) => (adt, substs), + + _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed), + }; + + all_fields_implement_trait( + tcx, + param_env, + self_type, + adt, + substs, + parent_cause, + hir::LangItem::ConstParamTy, + ) + .map_err(ConstParamTyImplementationError::InfrigingFields)?; + + Ok(()) +} + +/// Check that all fields of a given `adt` implement `lang_item` trait. +pub fn all_fields_implement_trait<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + self_type: Ty<'tcx>, + adt: AdtDef<'tcx>, + substs: &'tcx List<GenericArg<'tcx>>, + parent_cause: ObligationCause<'tcx>, + lang_item: LangItem, +) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> { + let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span)); let mut infringing = Vec::new(); for variant in adt.variants() { @@ -93,7 +172,7 @@ pub fn type_allowed_to_implement_copy<'tcx>( // between expected and found const-generic types. Don't report an // additional copy error here, since it's not typically useful. if !normalization_errors.is_empty() || ty.references_error() { - tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking Copy implementation")); + tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id))); continue; } @@ -101,7 +180,7 @@ pub fn type_allowed_to_implement_copy<'tcx>( ObligationCause::dummy_with_span(field_ty_span), param_env, ty, - copy_def_id, + trait_def_id, ); let errors = ocx.select_all_or_error(); if !errors.is_empty() { @@ -124,15 +203,7 @@ pub fn type_allowed_to_implement_copy<'tcx>( } } - if !infringing.is_empty() { - return Err(CopyImplementationError::InfringingFields(infringing)); - } - - if adt.has_dtor(tcx) { - return Err(CopyImplementationError::HasDestructor); - } - - Ok(()) + if infringing.is_empty() { Ok(()) } else { Err(infringing) } } pub fn check_tys_might_be_eq<'tcx>( |
