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.rs56
1 files changed, 41 insertions, 15 deletions
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 21a86d3e43..0be00afe7b 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -5,12 +5,15 @@
use std::fmt;
+use hir_def::TraitId;
use hir_def::{TypeAliasId, lang_item::LangItem};
use rustc_type_ir::inherent::{IntoKind, Ty as _};
use tracing::debug;
use triomphe::Arc;
+use crate::next_solver::TraitRef;
use crate::next_solver::infer::InferOk;
+use crate::next_solver::infer::traits::Obligation;
use crate::{
TraitEnvironment,
db::HirDatabase,
@@ -38,14 +41,14 @@ pub fn autoderef<'db>(
ty: crate::Canonical<crate::Ty>,
) -> impl Iterator<Item = crate::Ty> + use<> {
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 interner = table.interner();
+ let ty = table.instantiate_canonical(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).to_chalk(interner);
// 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 +104,7 @@ struct AutoderefSnapshot<'db, Steps> {
#[derive(Clone, Copy)]
struct AutoderefTraits {
+ trait_: TraitId,
trait_target: TypeAliasId,
}
@@ -215,16 +219,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 +250,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 +342,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)?;