diff options
Diffstat (limited to 'compiler')
36 files changed, 360 insertions, 993 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e9e1095a4ae..a5be91bb872 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -57,6 +57,7 @@ use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{ConstArg, GenericArg, ItemLocalMap, ParamName, TraitCandidate}; use rustc_index::{Idx, IndexSlice, IndexVec}; +use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::parse::{add_feature_diagnostics, feature_err}; @@ -190,16 +191,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } -trait ResolverAstLoweringExt { - fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>; - fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>; - fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>; - fn get_label_res(&self, id: NodeId) -> Option<NodeId>; - fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>; - fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>; -} - -impl ResolverAstLoweringExt for ResolverAstLowering { +#[extension(trait ResolverAstLoweringExt)] +impl ResolverAstLowering { fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> { if let ExprKind::Path(None, path) = &expr.kind { // Don't perform legacy const generics rewriting if the path already diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 68dc9a6764b..e7faec7bbac 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -2,6 +2,7 @@ use crate::location::{LocationIndex, LocationTable}; use crate::BorrowIndex; use polonius_engine::AllFacts as PoloniusFacts; use polonius_engine::Atom; +use rustc_macros::extension; use rustc_middle::mir::Local; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::move_paths::MovePathIndex; @@ -24,20 +25,10 @@ impl polonius_engine::FactTypes for RustcFacts { pub type AllFacts = PoloniusFacts<RustcFacts>; -pub(crate) trait AllFactsExt { +#[extension(pub(crate) trait AllFactsExt)] +impl AllFacts { /// Returns `true` if there is a need to gather `AllFacts` given the /// current `-Z` flags. - fn enabled(tcx: TyCtxt<'_>) -> bool; - - fn write_to_dir( - &self, - dir: impl AsRef<Path>, - location_table: &LocationTable, - ) -> Result<(), Box<dyn Error>>; -} - -impl AllFactsExt for AllFacts { - /// Return fn enabled(tcx: TyCtxt<'_>) -> bool { tcx.sess.opts.unstable_opts.nll_facts || tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled() diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs index b59ab7fafa5..0f806df9da1 100644 --- a/compiler/rustc_borrowck/src/place_ext.rs +++ b/compiler/rustc_borrowck/src/place_ext.rs @@ -1,11 +1,12 @@ use crate::borrow_set::LocalsStateAtExit; use rustc_hir as hir; +use rustc_macros::extension; use rustc_middle::mir::ProjectionElem; use rustc_middle::mir::{Body, Mutability, Place}; use rustc_middle::ty::{self, TyCtxt}; -/// Extension methods for the `Place` type. -pub trait PlaceExt<'tcx> { +#[extension(pub trait PlaceExt<'tcx>)] +impl<'tcx> Place<'tcx> { /// Returns `true` if we can safely ignore borrows of this place. /// This is true whenever there is no action that the user can do /// to the place `self` that would invalidate the borrow. This is true @@ -15,15 +16,6 @@ pub trait PlaceExt<'tcx> { tcx: TyCtxt<'tcx>, body: &Body<'tcx>, locals_state_at_exit: &LocalsStateAtExit, - ) -> bool; -} - -impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { - fn ignore_borrow( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - locals_state_at_exit: &LocalsStateAtExit, ) -> bool { // If a local variable is immutable, then we only need to track borrows to guard // against two kinds of errors: diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index cd2fe56ca49..a5a906658b8 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -6,6 +6,7 @@ use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::InferCtxt; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_infer::traits::{Obligation, ObligationCause}; +use rustc_macros::extension; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; @@ -225,15 +226,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } -pub trait InferCtxtExt<'tcx> { - fn infer_opaque_definition_from_instantiation( - &self, - opaque_type_key: OpaqueTypeKey<'tcx>, - instantiated_ty: OpaqueHiddenType<'tcx>, - ) -> Ty<'tcx>; -} - -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { /// Given the fully resolved, instantiated type for an opaque /// type, i.e., the value of an inference variable like C1 or C2 /// (*), computes the "definition type" for an opaque type diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 90e8f1b93b2..a69f5335f71 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -22,6 +22,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::BodyOwnerKind; use rustc_index::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_macros::extension; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt}; @@ -793,27 +794,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } } -trait InferCtxtExt<'tcx> { - fn replace_free_regions_with_nll_infer_vars<T>( - &self, - origin: NllRegionVariableOrigin, - value: T, - ) -> T - where - T: TypeFoldable<TyCtxt<'tcx>>; - - fn replace_bound_regions_with_nll_infer_vars<T>( - &self, - origin: NllRegionVariableOrigin, - all_outlive_scope: LocalDefId, - value: ty::Binder<'tcx, T>, - indices: &mut UniversalRegionIndices<'tcx>, - ) -> T - where - T: TypeFoldable<TyCtxt<'tcx>>; -} - -impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { +#[extension(trait InferCtxtExt<'tcx>)] +impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { #[instrument(skip(self), level = "debug")] fn replace_free_regions_with_nll_infer_vars<T>( &self, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 96c9e740568..a3c4734f0a3 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -344,7 +344,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { visitor.visit_ty(ty); } - fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) { + fn check_mut_borrow(&mut self, place: &Place<'_>, kind: hir::BorrowKind) { match self.const_kind() { // In a const fn all borrows are transient or point to the places given via // references in the arguments (so we already checked them with @@ -355,10 +355,19 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { // to mutable memory. hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)), _ => { + // For indirect places, we are not creating a new permanent borrow, it's just as + // transient as the already existing one. For reborrowing references this is handled + // at the top of `visit_rvalue`, but for raw pointers we handle it here. + // Pointers/references to `static mut` and cases where the `*` is not the first + // projection also end up here. // Locals with StorageDead do not live beyond the evaluation and can // thus safely be borrowed without being able to be leaked to the final // value of the constant. - if self.local_has_storage_dead(local) { + // Note: This is only sound if every local that has a `StorageDead` has a + // `StorageDead` in every control flow path leading to a `return` terminator. + // The good news is that interning will detect if any unexpected mutable + // pointer slips through. + if place.is_indirect() || self.local_has_storage_dead(place.local) { self.check_op(ops::TransientMutBorrow(kind)); } else { self.check_op(ops::MutBorrow(kind)); @@ -390,6 +399,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location); // Special-case reborrows to be more like a copy of a reference. + // FIXME: this does not actually handle all reborrows. It only detects cases where `*` is the outermost + // projection of the borrowed place, it skips deref'ing raw pointers and it skips `static`. + // All those cases are handled below with shared/mutable borrows. + // Once `const_mut_refs` is stable, we should be able to entirely remove this special case. + // (`const_refs_to_cell` is not needed, we already allow all borrows of indirect places anyway.) match *rvalue { Rvalue::Ref(_, kind, place) => { if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { @@ -460,7 +474,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if !is_allowed { self.check_mut_borrow( - place.local, + place, if matches!(rvalue, Rvalue::Ref(..)) { hir::BorrowKind::Ref } else { @@ -478,7 +492,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { place.as_ref(), ); - if borrowed_place_has_mut_interior { + // If the place is indirect, this is basically a reborrow. We have a reborrow + // special case above, but for raw pointers and pointers/references to `static` and + // when the `*` is not the first projection, `place_as_reborrow` does not recognize + // them as such, so we end up here. This should probably be considered a + // `TransientCellBorrow` (we consider the equivalent mutable case a + // `TransientMutBorrow`), but such reborrows got accidentally stabilized already and + // it is too much of a breaking change to take back. + if borrowed_place_has_mut_interior && !place.is_indirect() { match self.const_kind() { // In a const fn all borrows are transient or point to the places given via // references in the arguments (so we already checked them with @@ -495,6 +516,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // final value. // Note: This is only sound if every local that has a `StorageDead` has a // `StorageDead` in every control flow path leading to a `return` terminator. + // The good news is that interning will detect if any unexpected mutable + // pointer slips through. if self.local_has_storage_dead(place.local) { self.check_op(ops::TransientCellBorrow); } else { @@ -948,6 +971,12 @@ fn place_as_reborrow<'tcx>( ) -> Option<PlaceRef<'tcx>> { match place.as_ref().last_projection() { Some((place_base, ProjectionElem::Deref)) => { + // FIXME: why do statics and raw pointers get excluded here? This makes + // some code involving mutable pointers unstable, but it is unclear + // why that code is treated differently from mutable references. + // Once TransientMutBorrow and TransientCellBorrow are stable, + // this can probably be cleaned up without any behavioral changes. + // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` // that points to the allocation for the static. Don't treat these as reborrows. if body.local_decls[place_base.local].is_ref_to_static() { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 67fef208079..7eb3c181d69 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -74,6 +74,13 @@ pub trait Qualif { adt: AdtDef<'tcx>, args: GenericArgsRef<'tcx>, ) -> bool; + + /// Returns `true` if this `Qualif` behaves sructurally for pointers and references: + /// the pointer/reference qualifies if and only if the pointee qualifies. + /// + /// (This is currently `false` for all our instances, but that may change in the future. Also, + /// by keeping it abstract, the handling of `Deref` in `in_place` becomes more clear.) + fn deref_structural<'tcx>(cx: &ConstCx<'_, 'tcx>) -> bool; } /// Constant containing interior mutability (`UnsafeCell<T>`). @@ -103,6 +110,10 @@ impl Qualif for HasMutInterior { // It arises structurally for all other types. adt.is_unsafe_cell() } + + fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool { + false + } } /// Constant containing an ADT that implements `Drop`. @@ -131,6 +142,10 @@ impl Qualif for NeedsDrop { ) -> bool { adt.has_dtor(cx.tcx) } + + fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool { + false + } } /// Constant containing an ADT that implements non-const `Drop`. @@ -210,6 +225,10 @@ impl Qualif for NeedsNonConstDrop { ) -> bool { adt.has_non_const_dtor(cx.tcx) } + + fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool { + false + } } // FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return. @@ -303,6 +322,11 @@ where return false; } + if matches!(elem, ProjectionElem::Deref) && !Q::deref_structural(cx) { + // We have to assume that this qualifies. + return true; + } + place = place_base; } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index f0f6bfff64a..903c98e8317 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -407,9 +407,9 @@ pub fn check_intrinsic_type( } sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), - sym::assume => (0, 0, vec![tcx.types.bool], Ty::new_unit(tcx)), - sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool), - sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool), + sym::assume => (0, 1, vec![tcx.types.bool], Ty::new_unit(tcx)), + sym::likely => (0, 1, vec![tcx.types.bool], tcx.types.bool), + sym::unlikely => (0, 1, vec![tcx.types.bool], tcx.types.bool), sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), sym::write_via_move => { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 287cb880908..325a0ee9a18 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -14,6 +14,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node}; +use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::*; @@ -27,17 +28,8 @@ use std::fmt; use crate::errors; -trait RegionExt { - fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg); - - fn late(index: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg); - - fn id(&self) -> Option<DefId>; - - fn shifted(self, amount: u32) -> ResolvedArg; -} - -impl RegionExt for ResolvedArg { +#[extension(trait RegionExt)] +impl ResolvedArg { fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { debug!("ResolvedArg::early: def_id={:?}", param.def_id); (param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id())) diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index f6b583151fd..c8adbf7f57a 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -13,12 +13,16 @@ use rustc_middle::ty::{self, TyCtxt}; /// FIXME(-Znext-solver): This or public because it is shared with the /// new trait solver implementation. We should deduplicate canonicalization. -pub trait CanonicalExt<'tcx, V> { +#[extension(pub trait CanonicalExt<'tcx, V>)] +impl<'tcx, V> Canonical<'tcx, V> { /// Instantiate the wrapped value, replacing each canonical value /// with the value given in `var_values`. fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V where - V: TypeFoldable<TyCtxt<'tcx>>; + V: TypeFoldable<TyCtxt<'tcx>>, + { + self.instantiate_projected(tcx, var_values, |value| value.clone()) + } /// Allows one to apply a instantiation to some subset of /// `self.value`. Invoke `projection_fn` with `self.value` to get @@ -33,24 +37,6 @@ pub trait CanonicalExt<'tcx, V> { projection_fn: impl FnOnce(&V) -> T, ) -> T where - T: TypeFoldable<TyCtxt<'tcx>>; -} - -impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { - fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V - where - V: TypeFoldable<TyCtxt<'tcx>>, - { - self.instantiate_projected(tcx, var_values, |value| value.clone()) - } - - fn instantiate_projected<T>( - &self, - tcx: TyCtxt<'tcx>, - var_values: &CanonicalVarValues<'tcx>, - projection_fn: impl FnOnce(&V) -> T, - ) -> T - where T: TypeFoldable<TyCtxt<'tcx>>, { assert_eq!(self.variables.len(), var_values.len()); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 104bf4a5be8..8f06a5eeb5f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2786,19 +2786,8 @@ pub enum FailureCode { Error0644, } -pub trait ObligationCauseExt<'tcx> { - fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode; - - fn as_failure_code_diag( - &self, - terr: TypeError<'tcx>, - span: Span, - subdiags: Vec<TypeErrorAdditionalDiags>, - ) -> ObligationCauseFailureCode; - fn as_requirement_str(&self) -> &'static str; -} - -impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { +#[extension(pub trait ObligationCauseExt<'tcx>)] +impl<'tcx> ObligationCause<'tcx> { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode { use self::FailureCode::*; use crate::traits::ObligationCauseCode::*; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2caf3b3cc93..243558b11a8 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -626,11 +626,8 @@ pub struct InferCtxtBuilder<'tcx> { next_trait_solver: bool, } -pub trait TyCtxtInferExt<'tcx> { - fn infer_ctxt(self) -> InferCtxtBuilder<'tcx>; -} - -impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { +#[extension(pub trait TyCtxtInferExt<'tcx>)] +impl<'tcx> TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { InferCtxtBuilder { tcx: self, diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 64b9714c7c0..c495810858f 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -52,18 +52,8 @@ pub trait TraitEngine<'tcx>: 'tcx { ) -> Vec<PredicateObligation<'tcx>>; } -pub trait TraitEngineExt<'tcx> { - fn register_predicate_obligations( - &mut self, - infcx: &InferCtxt<'tcx>, - obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, - ); - - #[must_use] - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; -} - -impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { +#[extension(pub trait TraitEngineExt<'tcx>)] +impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T { fn register_predicate_obligations( &mut self, infcx: &InferCtxt<'tcx>, @@ -74,6 +64,7 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { } } + #[must_use] fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { let errors = self.select_where_possible(infcx); if !errors.is_empty() { diff --git a/compiler/rustc_macros/src/extension.rs b/compiler/rustc_macros/src/extension.rs new file mode 100644 index 00000000000..5377bbdfeab --- /dev/null +++ b/compiler/rustc_macros/src/extension.rs @@ -0,0 +1,154 @@ +use proc_macro2::Ident; +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::{ + braced, parse_macro_input, Attribute, Generics, ImplItem, Pat, PatIdent, Path, Signature, + Token, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility, +}; + +pub(crate) fn extension( + attr: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + let ExtensionAttr { vis, trait_ } = parse_macro_input!(attr as ExtensionAttr); + let Impl { attrs, generics, self_ty, items } = parse_macro_input!(input as Impl); + let headers: Vec<_> = items + .iter() + .map(|item| match item { + ImplItem::Fn(f) => TraitItem::Fn(TraitItemFn { + attrs: scrub_attrs(&f.attrs), + sig: scrub_header(f.sig.clone()), + default: None, + semi_token: Some(Token)), + }), + ImplItem::Const(ct) => TraitItem::Const(TraitItemConst { + attrs: scrub_attrs(&ct.attrs), + const_token: ct.const_token, + ident: ct.ident.clone(), + generics: ct.generics.clone(), + colon_token: ct.colon_token, + ty: ct.ty.clone(), + default: None, + semi_token: ct.semi_token, + }), + ImplItem::Type(ty) => TraitItem::Type(TraitItemType { + attrs: scrub_attrs(&ty.attrs), + type_token: ty.type_token, + ident: ty.ident.clone(), + generics: ty.generics.clone(), + colon_token: None, + bounds: Punctuated::new(), + default: None, + semi_token: ty.semi_token, + }), + ImplItem::Macro(mac) => TraitItem::Macro(TraitItemMacro { + attrs: scrub_attrs(&mac.attrs), + mac: mac.mac.clone(), + semi_token: mac.semi_token, + }), + ImplItem::Verbatim(stream) => TraitItem::Verbatim(stream.clone()), + _ => unimplemented!(), + }) + .collect(); + + quote! { + #(#attrs)* + #vis trait #trait_ { + #(#headers)* + } + + impl #generics #trait_ for #self_ty { + #(#items)* + } + } + .into() +} + +/// Only keep `#[doc]` attrs. +fn scrub_attrs(attrs: &[Attribute]) -> Vec<Attribute> { + attrs + .into_iter() + .cloned() + .filter(|attr| { + let ident = &attr.path().segments[0].ident; + ident == "doc" || ident == "must_use" + }) + .collect() +} + +/// Scrub arguments so that they're valid for trait signatures. +fn scrub_header(mut sig: Signature) -> Signature { + for (idx, input) in sig.inputs.iter_mut().enumerate() { + match input { + syn::FnArg::Receiver(rcvr) => { + // `mut self` -> `self` + if rcvr.reference.is_none() { + rcvr.mutability.take(); + } + } + syn::FnArg::Typed(arg) => match &mut *arg.pat { + Pat::Ident(arg) => { + // `ref mut ident @ pat` -> `ident` + arg.by_ref.take(); + arg.mutability.take(); + arg.subpat.take(); + } + _ => { + // `pat` -> `__arg0` + arg.pat = Box::new( + PatIdent { + attrs: vec![], + by_ref: None, + mutability: None, + ident: Ident::new(&format!("__arg{idx}"), arg.pat.span()), + subpat: None, + } + .into(), + ) + } + }, + } + } + sig +} + +struct ExtensionAttr { + vis: Visibility, + trait_: Path, +} + +impl Parse for ExtensionAttr { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let vis = input.parse()?; + let _: Token![trait] = input.parse()?; + let trait_ = input.parse()?; + Ok(ExtensionAttr { vis, trait_ }) + } +} + +struct Impl { + attrs: Vec<Attribute>, + generics: Generics, + self_ty: Type, + items: Vec<ImplItem>, +} + +impl Parse for Impl { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let _: Token![impl] = input.parse()?; + let generics = input.parse()?; + let self_ty = input.parse()?; + + let content; + let _brace_token = braced!(content in input); + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(Impl { attrs, generics, self_ty, items }) + } +} diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index af65c908ee6..619f93c8a53 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -14,6 +14,7 @@ use proc_macro::TokenStream; mod current_version; mod diagnostics; +mod extension; mod hash_stable; mod lift; mod query; @@ -40,6 +41,11 @@ pub fn symbols(input: TokenStream) -> TokenStream { symbols::symbols(input.into()).into() } +#[proc_macro_attribute] +pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream { + extension::extension(attr, input) +} + decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); decl_derive!( [HashStable_Generic, attributes(stable_hasher)] => diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 2b34f5daaf6..c1e33fe114f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -23,20 +23,8 @@ use std::fmt; use std::num::NonZero; use std::ops::Bound; -pub trait IntegerExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>; - fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer; - fn from_uint_ty<C: HasDataLayout>(cx: &C, uty: ty::UintTy) -> Integer; - fn repr_discr<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - repr: &ReprOptions, - min: i128, - max: i128, - ) -> (Integer, bool); -} - -impl IntegerExt for Integer { +#[extension(pub trait IntegerExt)] +impl Integer { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> { match (*self, signed) { @@ -123,12 +111,8 @@ impl IntegerExt for Integer { } } -pub trait PrimitiveExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; - fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; -} - -impl PrimitiveExt for Primitive { +#[extension(pub trait PrimitiveExt)] +impl Primitive { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 2addfa37f8b..3f539945841 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -96,13 +96,8 @@ impl<'tcx> Discr<'tcx> { } } -pub trait IntTypeExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; - fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option<Discr<'tcx>>) -> Option<Discr<'tcx>>; - fn initial_discriminant<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Discr<'tcx>; -} - -impl IntTypeExt for IntegerType { +#[extension(pub trait IntTypeExt)] +impl IntegerType { fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self { IntegerType::Pointer(true) => tcx.types.isize, diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index f8e6905282c..6212155a8fe 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -32,11 +32,6 @@ impl<'tcx> MirLint<'tcx> for ConstPropLint { return; } - // will be evaluated by miri and produce its errors there - if body.source.promoted.is_some() { - return; - } - let def_id = body.source.def_id().expect_local(); let def_kind = tcx.def_kind(def_id); let is_fn_like = def_kind.is_fn_like(); diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 9517ede288f..2db358379fe 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -132,18 +132,23 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( bcb_data.basic_blocks.iter().flat_map(move |&bb| { let data = &mir_body[bb]; + let unexpand = move |expn_span| { + unexpand_into_body_span_with_visible_macro(expn_span, body_span) + // Discard any spans that fill the entire body, because they tend + // to represent compiler-inserted code, e.g. implicitly returning `()`. + .filter(|(span, _)| !span.source_equal(body_span)) + }; + let statement_spans = data.statements.iter().filter_map(move |statement| { let expn_span = filtered_statement_span(statement)?; - let (span, visible_macro) = - unexpand_into_body_span_with_visible_macro(expn_span, body_span)?; + let (span, visible_macro) = unexpand(expn_span)?; Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_like(statement))) }); let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { let expn_span = filtered_terminator_span(terminator)?; - let (span, visible_macro) = - unexpand_into_body_span_with_visible_macro(expn_span, body_span)?; + let (span, visible_macro) = unexpand(expn_span)?; Some(SpanFromMir::new(span, visible_macro, bcb, false)) }); diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index ef4a0f52f9e..f694dd00703 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -17,49 +17,8 @@ use std::fmt::Debug; pub use rustc_infer::infer::*; -pub trait InferCtxtExt<'tcx> { - fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool; - - fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool; - - /// Check whether a `ty` implements given trait(trait_def_id) without side-effects. - /// - /// The inputs are: - /// - /// - the def-id of the trait - /// - the type parameters of the trait, including the self-type - /// - the parameter environment - /// - /// Invokes `evaluate_obligation`, so in the event that evaluating - /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent - /// (or EvaluatedToAmbigStackDependent) will be returned. - fn type_implements_trait( - &self, - trait_def_id: DefId, - params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, - param_env: ty::ParamEnv<'tcx>, - ) -> traits::EvaluationResult; - - /// Returns `Some` if a type implements a trait shallowly, without side-effects, - /// along with any errors that would have been reported upon further obligation - /// processing. - /// - /// - If this returns `Some([])`, then the trait holds modulo regions. - /// - If this returns `Some([errors..])`, then the trait has an impl for - /// the self type, but some nested obligations do not hold. - /// - If this returns `None`, no implementation that applies could be found. - /// - /// FIXME(-Znext-solver): Due to the recursive nature of the new solver, - /// this will probably only ever return `Some([])` or `None`. - fn type_implements_trait_shallow( - &self, - trait_def_id: DefId, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Option<Vec<traits::FulfillmentError<'tcx>>>; -} - -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); @@ -81,6 +40,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) } + /// Check whether a `ty` implements given trait(trait_def_id) without side-effects. + /// + /// The inputs are: + /// + /// - the def-id of the trait + /// - the type parameters of the trait, including the self-type + /// - the parameter environment + /// + /// Invokes `evaluate_obligation`, so in the event that evaluating + /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent + /// (or EvaluatedToAmbigStackDependent) will be returned. #[instrument(level = "debug", skip(self, params), ret)] fn type_implements_trait( &self, @@ -99,6 +69,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr) } + /// Returns `Some` if a type implements a trait shallowly, without side-effects, + /// along with any errors that would have been reported upon further obligation + /// processing. + /// + /// - If this returns `Some([])`, then the trait holds modulo regions. + /// - If this returns `Some([errors..])`, then the trait has an impl for + /// the self type, but some nested obligations do not hold. + /// - If this returns `None`, no implementation that applies could be found. + /// + /// FIXME(-Znext-solver): Due to the recursive nature of the new solver, + /// this will probably only ever return `Some([])` or `None`. fn type_implements_trait_shallow( &self, trait_def_id: DefId, @@ -124,19 +105,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { } } -pub trait InferCtxtBuilderExt<'tcx> { - fn enter_canonical_trait_query<K, R>( - self, - canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>, - ) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution> - where - K: TypeFoldable<TyCtxt<'tcx>>, - R: Debug + TypeFoldable<TyCtxt<'tcx>>, - Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>; -} - -impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { +#[extension(pub trait InferCtxtBuilderExt<'tcx>)] +impl<'tcx> InferCtxtBuilder<'tcx> { /// The "main method" for a canonicalized trait query. Given the /// canonical key `canonical_key`, this method will create a new /// inference context, instantiate the key, and run your operation diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 756db7cc206..222d0b4d5e7 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -3,7 +3,8 @@ use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; -pub trait InferCtxtRegionExt<'tcx> { +#[extension(pub trait InferCtxtRegionExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { /// Resolve regions, using the deep normalizer to normalize any type-outlives /// obligations in the process. This is in `rustc_trait_selection` because /// we need to normalize. @@ -13,13 +14,6 @@ pub trait InferCtxtRegionExt<'tcx> { fn resolve_regions( &self, outlives_env: &OutlivesEnvironment<'tcx>, - ) -> Vec<RegionResolutionError<'tcx>>; -} - -impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> { - fn resolve_regions( - &self, - outlives_env: &OutlivesEnvironment<'tcx>, ) -> Vec<RegionResolutionError<'tcx>> { self.resolve_regions_with_normalize(outlives_env, |ty, origin| { let ty = self.resolve_vars_if_possible(ty); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 803379af005..5c1e8bf616f 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -131,22 +131,12 @@ pub enum GenerateProofTree { Never, } -pub trait InferCtxtEvalExt<'tcx> { +#[extension(pub trait InferCtxtEvalExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { /// Evaluates a goal from **outside** of the trait solver. /// /// Using this while inside of the solver is wrong as it uses a new /// search graph which would break cycle detection. - fn evaluate_root_goal( - &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - generate_proof_tree: GenerateProofTree, - ) -> ( - Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>, - Option<inspect::GoalEvaluation<'tcx>>, - ); -} - -impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { #[instrument(level = "debug", skip(self))] fn evaluate_root_goal( &self, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index eab59624436..7196a5af259 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -17,14 +17,8 @@ use crate::solve::inspect::ProofTreeBuilder; use crate::traits::StructurallyNormalizeExt; use crate::traits::TraitEngineExt; -pub trait InferCtxtSelectExt<'tcx> { - fn select_in_new_trait_solver( - &self, - obligation: &PolyTraitObligation<'tcx>, - ) -> SelectionResult<'tcx, Selection<'tcx>>; -} - -impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtSelectExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { fn select_in_new_trait_solver( &self, obligation: &PolyTraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index f33d0f397ce..47f207e1d75 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -216,15 +216,8 @@ pub trait ProofTreeVisitor<'tcx> { fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::BreakTy>; } -pub trait ProofTreeInferCtxtExt<'tcx> { - fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>( - &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - visitor: &mut V, - ) -> ControlFlow<V::BreakTy>; -} - -impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait ProofTreeInferCtxtExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 94a3cef8ad1..8b163d47d34 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -61,11 +61,8 @@ enum GoalEvaluationKind { Nested { is_normalizes_to_hack: IsNormalizesToHack }, } -trait CanonicalResponseExt { - fn has_no_inference_or_external_constraints(&self) -> bool; -} - -impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { +#[extension(trait CanonicalResponseExt)] +impl<'tcx> Canonical<'tcx, Response<'tcx>> { fn has_no_inference_or_external_constraints(&self) -> bool { self.value.external_constraints.region_constraints.is_empty() && self.value.var_values.is_identity() diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index caf950037fd..1aaadf6cf04 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -27,11 +27,8 @@ use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::Variance; use rustc_middle::ty::{self, Ty, TyCtxt}; -pub trait TraitEngineExt<'tcx> { - fn new(infcx: &InferCtxt<'tcx>) -> Box<Self>; -} - -impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { +#[extension(pub trait TraitEngineExt<'tcx>)] +impl<'tcx> dyn TraitEngine<'tcx> { fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> { if infcx.next_trait_solver() { Box::new(NextFulfillmentCtxt::new(infcx)) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index 15d064d4036..4788ecbe3e2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -11,38 +11,8 @@ use super::ArgKind; pub use rustc_infer::traits::error_reporting::*; -pub trait InferCtxtExt<'tcx> { - /// Given some node representing a fn-like thing in the HIR map, - /// returns a span and `ArgKind` information that describes the - /// arguments it expects. This can be supplied to - /// `report_arg_count_mismatch`. - fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)>; - - /// Reports an error when the number of arguments needed by a - /// trait match doesn't match the number that the expression - /// provides. - fn report_arg_count_mismatch( - &self, - span: Span, - found_span: Option<Span>, - expected_args: Vec<ArgKind>, - found_args: Vec<ArgKind>, - is_closure: bool, - closure_pipe_span: Option<Span>, - ) -> DiagnosticBuilder<'tcx>; - - /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` - /// in that order, and returns the generic type corresponding to the - /// argument of that trait (corresponding to the closure arguments). - fn type_implements_fn_trait( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: ty::Binder<'tcx, Ty<'tcx>>, - polarity: ty::ImplPolarity, - ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>; -} - -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { /// Given some node representing a fn-like thing in the HIR map, /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to @@ -229,6 +199,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { err } + /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` + /// in that order, and returns the generic type corresponding to the + /// argument of that trait (corresponding to the closure arguments). fn type_implements_fn_trait( &self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index f0773fd1671..4ba2da95fb3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -23,24 +23,6 @@ use crate::errors::{ use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt; -pub trait TypeErrCtxtExt<'tcx> { - /*private*/ - fn impl_similar_to( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) -> Option<(DefId, GenericArgsRef<'tcx>)>; - - /*private*/ - fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str>; - - fn on_unimplemented_note( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) -> OnUnimplementedNote; -} - /// The symbols which are always allowed in a format string static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ kw::SelfUpper, @@ -56,7 +38,8 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ sym::Trait, ]; -impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension(pub trait TypeErrCtxtExt<'tcx>)] +impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn impl_similar_to( &self, trait_ref: ty::PolyTraitRef<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 335e6ff2822..7de13bf0c02 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -106,279 +106,6 @@ impl<'tcx, 'a> CoroutineData<'tcx, 'a> { } } -// This trait is public to expose the diagnostics methods to clippy. -pub trait TypeErrCtxtExt<'tcx> { - fn suggest_restricting_param_bound( - &self, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - associated_item: Option<(&'static str, Ty<'tcx>)>, - body_id: LocalDefId, - ); - - fn suggest_dereferences( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn get_closure_name( - &self, - def_id: DefId, - err: &mut Diagnostic, - msg: Cow<'static, str>, - ) -> Option<Symbol>; - - fn suggest_fn_call( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn check_for_binding_assigned_block_without_tail_expression( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ); - - fn suggest_add_clone_to_arg( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn extract_callable_info( - &self, - body_id: LocalDefId, - param_env: ty::ParamEnv<'tcx>, - found: Ty<'tcx>, - ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>; - - fn suggest_add_reference_to_arg( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - has_custom_message: bool, - ) -> bool; - - fn suggest_borrowing_for_object_cast( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - self_ty: Ty<'tcx>, - object_ty: Ty<'tcx>, - ); - - fn suggest_remove_reference( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic); - - fn suggest_change_mut( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ); - - fn suggest_semicolon_removal( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - span: Span, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>; - - fn suggest_impl_trait( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn point_at_returns_when_relevant( - &self, - err: &mut DiagnosticBuilder<'tcx>, - obligation: &PredicateObligation<'tcx>, - ); - - fn report_closure_arg_mismatch( - &self, - span: Span, - found_span: Option<Span>, - found: ty::PolyTraitRef<'tcx>, - expected: ty::PolyTraitRef<'tcx>, - cause: &ObligationCauseCode<'tcx>, - found_node: Option<Node<'_>>, - param_env: ty::ParamEnv<'tcx>, - ) -> DiagnosticBuilder<'tcx>; - - fn note_conflicting_fn_args( - &self, - err: &mut Diagnostic, - cause: &ObligationCauseCode<'tcx>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ); - - fn note_conflicting_closure_bounds( - &self, - cause: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - ); - - fn suggest_fully_qualified_path( - &self, - err: &mut Diagnostic, - item_def_id: DefId, - span: Span, - trait_ref: DefId, - ); - - fn maybe_note_obligation_cause_for_async_await( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - ) -> bool; - - fn note_obligation_cause_for_async_await( - &self, - err: &mut Diagnostic, - interior_or_upvar_span: CoroutineInteriorOrUpvar, - is_async: bool, - outer_coroutine: Option<DefId>, - trait_pred: ty::TraitPredicate<'tcx>, - target_ty: Ty<'tcx>, - obligation: &PredicateObligation<'tcx>, - next_code: Option<&ObligationCauseCode<'tcx>>, - ); - - fn note_obligation_cause_code<T>( - &self, - body_id: LocalDefId, - err: &mut Diagnostic, - predicate: T, - param_env: ty::ParamEnv<'tcx>, - cause_code: &ObligationCauseCode<'tcx>, - obligated_types: &mut Vec<Ty<'tcx>>, - seen_requirements: &mut FxHashSet<DefId>, - ) where - T: ToPredicate<'tcx>; - - /// Suggest to await before try: future? => future.await? - fn suggest_await_before_try( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - trait_pred: ty::PolyTraitPredicate<'tcx>, - span: Span, - ); - - fn suggest_floating_point_literal( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_ref: &ty::PolyTraitRef<'tcx>, - ); - - fn suggest_derive( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ); - - fn suggest_dereferencing_index( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ); - - fn suggest_option_method_if_applicable( - &self, - failed_pred: ty::Predicate<'tcx>, - param_env: ty::ParamEnv<'tcx>, - err: &mut Diagnostic, - expr: &hir::Expr<'_>, - ); - - fn note_function_argument_obligation( - &self, - body_id: LocalDefId, - err: &mut Diagnostic, - arg_hir_id: HirId, - parent_code: &ObligationCauseCode<'tcx>, - param_env: ty::ParamEnv<'tcx>, - predicate: ty::Predicate<'tcx>, - call_hir_id: HirId, - ); - - fn look_for_iterator_item_mistakes( - &self, - assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>], - typeck_results: &TypeckResults<'tcx>, - type_diffs: &[TypeError<'tcx>], - param_env: ty::ParamEnv<'tcx>, - path_segment: &hir::PathSegment<'_>, - args: &[hir::Expr<'_>], - err: &mut Diagnostic, - ); - - fn point_at_chain( - &self, - expr: &hir::Expr<'_>, - typeck_results: &TypeckResults<'tcx>, - type_diffs: Vec<TypeError<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - err: &mut Diagnostic, - ); - - fn probe_assoc_types_at_expr( - &self, - type_diffs: &[TypeError<'tcx>], - span: Span, - prev_ty: Ty<'tcx>, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>; - - fn suggest_convert_to_slice( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - candidate_impls: &[ImplCandidate<'tcx>], - span: Span, - ); - - fn explain_hrtb_projection( - &self, - diag: &mut Diagnostic, - pred: ty::PolyTraitPredicate<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: &ObligationCause<'tcx>, - ); - - fn suggest_desugaring_async_fn_in_trait( - &self, - err: &mut Diagnostic, - trait_ref: ty::PolyTraitRef<'tcx>, - ); -} - fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) { ( generics.tail_span_for_predicate_suggestion(), @@ -509,7 +236,8 @@ pub fn suggest_restriction<'tcx>( } } -impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension(pub trait TypeErrCtxtExt<'tcx>)] +impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_restricting_param_bound( &self, err: &mut Diagnostic, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 661a444d049..67bd18d7404 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -57,78 +57,8 @@ use super::{ pub use rustc_infer::traits::error_reporting::*; -pub trait TypeErrCtxtExt<'tcx> { - fn build_overflow_error<T>( - &self, - predicate: &T, - span: Span, - suggest_increasing_limit: bool, - ) -> DiagnosticBuilder<'tcx> - where - T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>; - - fn report_overflow_error<T>( - &self, - predicate: &T, - span: Span, - suggest_increasing_limit: bool, - mutate: impl FnOnce(&mut Diagnostic), - ) -> ! - where - T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>; - - fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed; - - fn report_fulfillment_errors(&self, errors: Vec<FulfillmentError<'tcx>>) -> ErrorGuaranteed; - - fn report_overflow_obligation<T>( - &self, - obligation: &Obligation<'tcx, T>, - suggest_increasing_limit: bool, - ) -> ! - where - T: ToPredicate<'tcx> + Clone; - - fn suggest_new_overflow_limit(&self, err: &mut Diagnostic); - - fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !; - - /// The `root_obligation` parameter should be the `root_obligation` field - /// from a `FulfillmentError`. If no `FulfillmentError` is available, - /// then it should be the same as `obligation`. - fn report_selection_error( - &self, - obligation: PredicateObligation<'tcx>, - root_obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>, - ) -> ErrorGuaranteed; - - fn emit_specialized_closure_kind_error( - &self, - obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Option<ErrorGuaranteed>; - - fn fn_arg_obligation( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> Result<(), ErrorGuaranteed>; - - fn try_conversion_context( - &self, - obligation: &PredicateObligation<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - err: &mut Diagnostic, - ) -> bool; - - fn report_const_param_not_wf( - &self, - ty: Ty<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) -> DiagnosticBuilder<'tcx>; -} - -impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension(pub trait TypeErrCtxtExt<'tcx>)] +impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn report_fulfillment_errors( &self, mut errors: Vec<FulfillmentError<'tcx>>, @@ -382,6 +312,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.emit() } + /// The `root_obligation` parameter should be the `root_obligation` field + /// from a `FulfillmentError`. If no `FulfillmentError` is available, + /// then it should be the same as `obligation`. fn report_selection_error( &self, mut obligation: PredicateObligation<'tcx>, @@ -1393,209 +1326,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } -pub(super) trait InferCtxtPrivExt<'tcx> { - // returns if `cond` not occurring implies that `error` does not occur - i.e., that - // `error` occurring implies that `cond` occurs. - fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool; - - fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed; - - fn report_projection_error( - &self, - obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>, - ) -> ErrorGuaranteed; - - fn maybe_detailed_projection_msg( - &self, - pred: ty::ProjectionPredicate<'tcx>, - normalized_ty: ty::Term<'tcx>, - expected_ty: ty::Term<'tcx>, - ) -> Option<String>; - - fn fuzzy_match_tys( - &self, - a: Ty<'tcx>, - b: Ty<'tcx>, - ignoring_lifetimes: bool, - ) -> Option<CandidateSimilarity>; - - fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str; - - fn find_similar_impl_candidates( - &self, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> Vec<ImplCandidate<'tcx>>; - - fn report_similar_impl_candidates( - &self, - impl_candidates: &[ImplCandidate<'tcx>], - trait_ref: ty::PolyTraitRef<'tcx>, - body_def_id: LocalDefId, - err: &mut Diagnostic, - other: bool, - param_env: ty::ParamEnv<'tcx>, - ) -> bool; - - fn report_similar_impl_candidates_for_root_obligation( - &self, - obligation: &PredicateObligation<'tcx>, - trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, - body_def_id: LocalDefId, - err: &mut Diagnostic, - ); - - /// Gets the parent trait chain start - fn get_parent_trait_ref( - &self, - code: &ObligationCauseCode<'tcx>, - ) -> Option<(Ty<'tcx>, Option<Span>)>; - - /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait - /// with the same path as `trait_ref`, a help message about - /// a probable version mismatch is added to `err` - fn note_version_mismatch( - &self, - err: &mut Diagnostic, - trait_ref: &ty::PolyTraitRef<'tcx>, - ) -> bool; - - /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the - /// `trait_ref`. - /// - /// For this to work, `new_self_ty` must have no escaping bound variables. - fn mk_trait_obligation_with_new_self_ty( - &self, - param_env: ty::ParamEnv<'tcx>, - trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, - ) -> PredicateObligation<'tcx>; - - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed; - - fn predicate_can_apply( - &self, - param_env: ty::ParamEnv<'tcx>, - pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>); - - fn suggest_unsized_bound_if_applicable( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - ); - - fn annotate_source_of_ambiguity( - &self, - err: &mut Diagnostic, - impls: &[ambiguity::Ambiguity], - predicate: ty::Predicate<'tcx>, - ); - - fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>); - - fn maybe_indirection_for_unsized( - &self, - err: &mut Diagnostic, - item: &'tcx Item<'tcx>, - param: &'tcx GenericParam<'tcx>, - ) -> bool; - - fn is_recursive_obligation( - &self, - obligated_types: &mut Vec<Ty<'tcx>>, - cause_code: &ObligationCauseCode<'tcx>, - ) -> bool; - - fn get_standard_error_message( - &self, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, - message: Option<String>, - predicate_is_const: bool, - append_const_msg: Option<AppendConstMessage>, - post_message: String, - ) -> String; - - fn get_safe_transmute_error_and_reason( - &self, - obligation: PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - span: Span, - ) -> GetSafeTransmuteErrorAndReason; - - fn add_tuple_trait_message( - &self, - obligation_cause_code: &ObligationCauseCode<'tcx>, - err: &mut Diagnostic, - ); - - fn try_to_add_help_message( - &self, - obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, - err: &mut Diagnostic, - span: Span, - is_fn_trait: bool, - suggested: bool, - unsatisfied_const: bool, - ); - - fn add_help_message_for_fn_trait( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - err: &mut Diagnostic, - implemented_kind: ty::ClosureKind, - params: ty::Binder<'tcx, Ty<'tcx>>, - ); - - fn maybe_add_note_for_unsatisfied_const( - &self, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, - err: &mut Diagnostic, - span: Span, - ) -> UnsatisfiedConst; - - fn report_closure_error( - &self, - obligation: &PredicateObligation<'tcx>, - closure_def_id: DefId, - found_kind: ty::ClosureKind, - kind: ty::ClosureKind, - trait_prefix: &'static str, - ) -> DiagnosticBuilder<'tcx>; - - fn report_cyclic_signature_error( - &self, - obligation: &PredicateObligation<'tcx>, - found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - terr: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx>; - - fn report_opaque_type_auto_trait_leakage( - &self, - obligation: &PredicateObligation<'tcx>, - def_id: DefId, - ) -> DiagnosticBuilder<'tcx>; - - fn report_signature_mismatch_error( - &self, - obligation: &PredicateObligation<'tcx>, - span: Span, - found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - ) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed>; - - fn report_not_const_evaluatable_error( - &self, - obligation: &PredicateObligation<'tcx>, - span: Span, - ) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed>; -} - -impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension(pub(super) trait InferCtxtPrivExt<'tcx>)] +impl<'tcx> TypeErrCtxt<'_, 'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e., that // `error` occurring implies that `cond` occurs. fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool { @@ -2414,6 +2146,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { suggested } + /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the + /// `trait_ref`. + /// + /// For this to work, `new_self_ty` must have no escaping bound variables. fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 52631d4353b..6825dd4ac71 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -11,25 +11,6 @@ pub use rustc_middle::traits::query::OutlivesBound; pub type BoundsCompat<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a; pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a; -pub trait InferCtxtExt<'a, 'tcx> { - /// Do *NOT* call this directly. - fn implied_bounds_tys_compat( - &'a self, - param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, - tys: &'a FxIndexSet<Ty<'tcx>>, - compat: bool, - ) -> BoundsCompat<'a, 'tcx>; - - /// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat` - /// with `compat` set to `true`, otherwise `false`. - fn implied_bounds_tys( - &'a self, - param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, - tys: &'a FxIndexSet<Ty<'tcx>>, - ) -> Bounds<'a, 'tcx>; -} /// Implied bounds are region relationships that we deduce /// automatically. The idea is that (e.g.) a caller must check that a @@ -130,7 +111,9 @@ fn implied_outlives_bounds<'a, 'tcx>( bounds } -impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtExt<'a, 'tcx>)] +impl<'a, 'tcx: 'a> InferCtxt<'tcx> { + /// Do *NOT* call this directly. fn implied_bounds_tys_compat( &'a self, param_env: ParamEnv<'tcx>, @@ -142,6 +125,8 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, *ty, compat)) } + /// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat` + /// with `compat` set to `true`, otherwise `false`. fn implied_bounds_tys( &'a self, param_env: ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 049877bc5fe..279c0003187 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -52,12 +52,22 @@ pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::AliasTy<'tcx>>; pub(super) struct InProgress; -pub trait NormalizeExt<'tcx> { +#[extension(pub trait NormalizeExt<'tcx>)] +impl<'tcx> At<'_, 'tcx> { /// Normalize a value using the `AssocTypeNormalizer`. /// /// This normalization should be used when the type contains inference variables or the /// projection may be fallible. - fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> InferOk<'tcx, T>; + fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> { + if self.infcx.next_trait_solver() { + InferOk { value, obligations: Vec::new() } + } else { + let mut selcx = SelectionContext::new(self.infcx); + let Normalized { value, obligations } = + normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value); + InferOk { value, obligations } + } + } /// Deeply normalizes `value`, replacing all aliases which can by normalized in /// the current environment. In the new solver this errors in case normalization @@ -77,25 +87,6 @@ pub trait NormalizeExt<'tcx> { self, value: T, fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Result<T, Vec<FulfillmentError<'tcx>>>; -} - -impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> { - fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> { - if self.infcx.next_trait_solver() { - InferOk { value, obligations: Vec::new() } - } else { - let mut selcx = SelectionContext::new(self.infcx); - let Normalized { value, obligations } = - normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value); - InferOk { value, obligations } - } - } - - fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>( - self, - value: T, - fulfill_cx: &mut dyn TraitEngine<'tcx>, ) -> Result<T, Vec<FulfillmentError<'tcx>>> { if self.infcx.next_trait_solver() { crate::solve::deeply_normalize(self, value) diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index a050b30317a..16ee9fadab4 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -4,32 +4,8 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext}; -pub trait InferCtxtExt<'tcx> { - fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool; - - fn predicate_must_hold_considering_regions( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> bool; - - fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool; - - fn evaluate_obligation( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> Result<EvaluationResult, OverflowError>; - - // Helper function that canonicalizes and runs the query. If an - // overflow results, we re-run it in the local context so we can - // report a nice error. - /*crate*/ - fn evaluate_obligation_no_overflow( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> EvaluationResult; -} - -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { /// Evaluates whether the predicate can be satisfied (by any means) /// in the given `ParamEnv`. fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { @@ -114,9 +90,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { } } - // Helper function that canonicalizes and runs the query. If an - // overflow results, we re-run it in the local context so we can - // report a nice error. + /// Helper function that canonicalizes and runs the query. If an + /// overflow results, we re-run it in the local context so we can + /// report a nice error. fn evaluate_obligation_no_overflow( &self, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 0b73fefd2da..0f6c0abd280 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -22,20 +22,8 @@ use super::NoSolution; pub use rustc_middle::traits::query::NormalizationResult; -pub trait QueryNormalizeExt<'tcx> { - /// Normalize a value using the `QueryNormalizer`. - /// - /// This normalization should *only* be used when the projection does not - /// have possible ambiguity or may not be well-formed. - /// - /// After codegen, when lifetimes do not matter, it is preferable to instead - /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure. - fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution> - where - T: TypeFoldable<TyCtxt<'tcx>>; -} - -impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { +#[extension(pub trait QueryNormalizeExt<'tcx>)] +impl<'cx, 'tcx> At<'cx, 'tcx> { /// Normalize `value` in the context of the inference context, /// yielding a resulting type, or an error if `value` cannot be /// normalized. If you don't care about regions, you should prefer @@ -49,6 +37,12 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { /// normalizing, but for now should be used only when we actually /// know that normalization will succeed, since error reporting /// and other details are still "under development". + /// + /// This normalization should *only* be used when the projection does not + /// have possible ambiguity or may not be well-formed. + /// + /// After codegen, when lifetimes do not matter, it is preferable to instead + /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure. fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution> where T: TypeFoldable<TyCtxt<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index e9a592bdee7..f3b77d68922 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -33,20 +33,8 @@ enum Inserted<'tcx> { ShouldRecurseOn(DefId), } -trait ChildrenExt<'tcx> { - fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId); - fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId); - - fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - impl_def_id: DefId, - simplified_self: Option<SimplifiedType>, - overlap_mode: OverlapMode, - ) -> Result<Inserted<'tcx>, OverlapError<'tcx>>; -} - -impl<'tcx> ChildrenExt<'tcx> for Children { +#[extension(trait ChildrenExt<'tcx>)] +impl<'tcx> Children { /// Insert an impl into this set of children without comparing to any existing impls. fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder(); @@ -247,22 +235,8 @@ where } } -pub trait GraphExt<'tcx> { - /// Insert a local impl into the specialization graph. If an existing impl - /// conflicts with it (has overlap, but neither specializes the other), - /// information about the area of overlap is returned in the `Err`. - fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - impl_def_id: DefId, - overlap_mode: OverlapMode, - ) -> Result<Option<FutureCompatOverlapError<'tcx>>, OverlapError<'tcx>>; - - /// Insert cached metadata mapping from a child impl back to its parent. - fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId); -} - -impl<'tcx> GraphExt<'tcx> for Graph { +#[extension(pub trait GraphExt<'tcx>)] +impl<'tcx> Graph { /// Insert a local impl into the specialization graph. If an existing impl /// conflicts with it (has overlap, but neither specializes the other), /// information about the area of overlap is returned in the `Err`. diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index ed5d01d7048..2f428564ae7 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -5,15 +5,8 @@ use rustc_middle::ty::{self, Ty}; use crate::traits::{NormalizeExt, Obligation}; -pub trait StructurallyNormalizeExt<'tcx> { - fn structurally_normalize( - &self, - ty: Ty<'tcx>, - fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>>; -} - -impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { +#[extension(pub trait StructurallyNormalizeExt<'tcx>)] +impl<'tcx> At<'_, 'tcx> { fn structurally_normalize( &self, ty: Ty<'tcx>, |
