Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/autoderef.rs')
| -rw-r--r-- | crates/hir-ty/src/autoderef.rs | 65 |
1 files changed, 44 insertions, 21 deletions
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs index 4d348ec6b7..6dd3cdb745 100644 --- a/crates/hir-ty/src/autoderef.rs +++ b/crates/hir-ty/src/autoderef.rs @@ -5,20 +5,21 @@ use std::fmt; -use hir_def::{TypeAliasId, lang_item::LangItem}; +use hir_def::{TraitId, TypeAliasId, lang_item::LangItem}; use rustc_type_ir::inherent::{IntoKind, Ty as _}; use tracing::debug; use triomphe::Arc; -use crate::next_solver::infer::InferOk; use crate::{ TraitEnvironment, db::HirDatabase, infer::unify::InferenceTable, next_solver::{ - Ty, TyKind, - infer::traits::{ObligationCause, PredicateObligations}, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + Canonical, TraitRef, Ty, TyKind, + infer::{ + InferOk, + traits::{Obligation, ObligationCause, PredicateObligations}, + }, obligation_ctxt::ObligationCtxt, }, }; @@ -35,17 +36,16 @@ const AUTODEREF_RECURSION_LIMIT: usize = 20; pub fn autoderef<'db>( db: &'db dyn HirDatabase, env: Arc<TraitEnvironment<'db>>, - ty: crate::Canonical<crate::Ty>, -) -> impl Iterator<Item = crate::Ty> + use<> { + ty: Canonical<'db, Ty<'db>>, +) -> impl Iterator<Item = Ty<'db>> + use<'db> { let mut table = InferenceTable::new(db, env); - let interner = table.interner; let ty = table.instantiate_canonical(ty); - let mut autoderef = Autoderef::new_no_tracking(&mut table, ty.to_nextsolver(interner)); + let mut autoderef = Autoderef::new_no_tracking(&mut table, ty); let mut v = Vec::new(); while let Some((ty, _steps)) = autoderef.next() { // `ty` may contain unresolved inference variables. Since there's no chance they would be // resolved, just replace with fallback type. - let resolved = autoderef.table.resolve_completely(ty.to_chalk(interner)); + let resolved = autoderef.table.resolve_completely(ty); // If the deref chain contains a cycle (e.g. `A` derefs to `B` and `B` derefs to `A`), we // would revisit some already visited types. Stop here to avoid duplication. @@ -101,6 +101,7 @@ struct AutoderefSnapshot<'db, Steps> { #[derive(Clone, Copy)] struct AutoderefTraits { + trait_: TraitId, trait_target: TypeAliasId, } @@ -215,16 +216,26 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> { Some(it) => Some(*it), None => { let traits = if self.use_receiver_trait { - AutoderefTraits { - trait_target: LangItem::ReceiverTarget - .resolve_type_alias(self.table.db, self.table.trait_env.krate) - .or_else(|| { - LangItem::DerefTarget - .resolve_type_alias(self.table.db, self.table.trait_env.krate) - })?, - } + (|| { + Some(AutoderefTraits { + trait_: LangItem::Receiver + .resolve_trait(self.table.db, self.table.trait_env.krate)?, + trait_target: LangItem::ReceiverTarget + .resolve_type_alias(self.table.db, self.table.trait_env.krate)?, + }) + })() + .or_else(|| { + Some(AutoderefTraits { + trait_: LangItem::Deref + .resolve_trait(self.table.db, self.table.trait_env.krate)?, + trait_target: LangItem::DerefTarget + .resolve_type_alias(self.table.db, self.table.trait_env.krate)?, + }) + })? } else { AutoderefTraits { + trait_: LangItem::Deref + .resolve_trait(self.table.db, self.table.trait_env.krate)?, trait_target: LangItem::DerefTarget .resolve_type_alias(self.table.db, self.table.trait_env.krate)?, } @@ -236,10 +247,22 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> { fn overloaded_deref_ty(&mut self, ty: Ty<'db>) -> Option<Ty<'db>> { debug!("overloaded_deref_ty({:?})", ty); - let interner = self.table.interner; + let interner = self.table.interner(); // <ty as Deref>, or whatever the equivalent trait is that we've been asked to walk. - let AutoderefTraits { trait_target } = self.autoderef_traits()?; + let AutoderefTraits { trait_, trait_target } = self.autoderef_traits()?; + + let trait_ref = TraitRef::new(interner, trait_.into(), [ty]); + let obligation = + Obligation::new(interner, ObligationCause::new(), self.table.trait_env.env, trait_ref); + // We detect whether the self type implements `Deref` before trying to + // structurally normalize. We use `predicate_may_hold_opaque_types_jank` + // to support not-yet-defined opaque types. It will succeed for `impl Deref` + // but fail for `impl OtherTrait`. + if !self.table.infer_ctxt.predicate_may_hold_opaque_types_jank(&obligation) { + debug!("overloaded_deref_ty: cannot match obligation"); + return None; + } let (normalized_ty, obligations) = structurally_normalize_ty( self.table, @@ -316,7 +339,7 @@ pub(crate) fn overloaded_deref_ty<'db>( table: &InferenceTable<'db>, ty: Ty<'db>, ) -> Option<InferOk<'db, Ty<'db>>> { - let interner = table.interner; + let interner = table.interner(); let trait_target = LangItem::DerefTarget.resolve_type_alias(table.db, table.trait_env.krate)?; |