]> git.lizzy.rs Git - rust.git/commitdiff
Handle cycles in impl types better
authorFlorian Diebold <flodiebold@gmail.com>
Sat, 30 Nov 2019 11:35:37 +0000 (12:35 +0100)
committerFlorian Diebold <flodiebold@gmail.com>
Sat, 30 Nov 2019 11:57:32 +0000 (12:57 +0100)
 - impl Trait<Self> for S is allowed
 - impl Trait for S<Self> is an invalid cycle, but we can add cycle recovery for
   it in Salsa now

crates/ra_hir_ty/src/db.rs
crates/ra_hir_ty/src/infer/coerce.rs
crates/ra_hir_ty/src/infer/path.rs
crates/ra_hir_ty/src/lib.rs
crates/ra_hir_ty/src/lower.rs
crates/ra_hir_ty/src/method_resolution.rs
crates/ra_hir_ty/src/tests.rs
crates/ra_hir_ty/src/traits/chalk.rs

index 9ce154593980737874d4248022690e07a4b79757..6ecc0b09664c940365732f6241f2dfb5b4965bc9 100644 (file)
@@ -11,7 +11,7 @@
 use crate::{
     method_resolution::CrateImplBlocks,
     traits::{AssocTyValue, Impl},
-    CallableDef, FnSig, GenericPredicate, ImplTy, InferenceResult, Substs, Ty, TyDefId, TypeCtor,
+    CallableDef, FnSig, GenericPredicate, InferenceResult, Substs, TraitRef, Ty, TyDefId, TypeCtor,
     ValueTyDefId,
 };
 
@@ -27,8 +27,12 @@ pub trait HirDatabase: DefDatabase {
     #[salsa::invoke(crate::lower::value_ty_query)]
     fn value_ty(&self, def: ValueTyDefId) -> Ty;
 
-    #[salsa::invoke(crate::lower::impl_ty_query)]
-    fn impl_ty(&self, def: ImplId) -> ImplTy;
+    #[salsa::invoke(crate::lower::impl_self_ty_query)]
+    #[salsa::cycle(crate::lower::impl_self_ty_recover)]
+    fn impl_self_ty(&self, def: ImplId) -> Ty;
+
+    #[salsa::invoke(crate::lower::impl_trait_query)]
+    fn impl_trait(&self, def: ImplId) -> Option<TraitRef>;
 
     #[salsa::invoke(crate::lower::field_types_query)]
     fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalStructFieldId, Ty>>;
index 719a0f395753735f3b62eda1795e4de91d618380..064993d34fac0e47877ce91d681e53e4d0c53332 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_hash::FxHashMap;
 use test_utils::tested_by;
 
-use crate::{autoderef, db::HirDatabase, ImplTy, Substs, Ty, TypeCtor, TypeWalk};
+use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk};
 
 use super::{InEnvironment, InferTy, InferenceContext, TypeVarValue};
 
@@ -54,10 +54,7 @@ pub(super) fn init_coerce_unsized_map(
         impls
             .iter()
             .filter_map(|&impl_id| {
-                let trait_ref = match db.impl_ty(impl_id) {
-                    ImplTy::TraitRef(it) => it,
-                    ImplTy::Inherent(_) => return None,
-                };
+                let trait_ref = db.impl_trait(impl_id)?;
 
                 // `CoerseUnsized` has one generic parameter for the target type.
                 let cur_from_ty = trait_ref.substs.0.get(0)?;
index 14be668365038719ee37d1109d76ceb4a5412b38..bbf146418e14fdf6ff7ae78eaefa2e2d4469773e 100644 (file)
@@ -244,7 +244,7 @@ fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
                 ContainerId::ImplId(it) => it,
                 _ => return None,
             };
-            let self_ty = self.db.impl_ty(impl_id).self_type().clone();
+            let self_ty = self.db.impl_self_ty(impl_id).clone();
             let self_ty_substs = self_ty.substs()?;
             let actual_substs = actual_def_ty.substs()?;
 
index b45c8f82f4106bca0126e00f0800583322cf891f..3c1f738dfc43c75cd207ce79b2cd513f2575c200 100644 (file)
@@ -486,21 +486,6 @@ fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usiz
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub enum ImplTy {
-    Inherent(Ty),
-    TraitRef(TraitRef),
-}
-
-impl ImplTy {
-    pub(crate) fn self_type(&self) -> &Ty {
-        match self {
-            ImplTy::Inherent(it) => it,
-            ImplTy::TraitRef(tr) => &tr.substs[0],
-        }
-    }
-}
-
 /// Like `generics::WherePredicate`, but with resolved types: A condition on the
 /// parameters of a generic item.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
index 091c60f4fef783f310a9bfc890c65f1ec827b5a5..a646406f18e61c71268936ccfd15a3dd2868f0f8 100644 (file)
@@ -27,8 +27,8 @@
         all_super_traits, associated_type_by_name_including_super_traits, make_mut_slice,
         variant_data,
     },
-    FnSig, GenericPredicate, ImplTy, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment,
-    TraitRef, Ty, TypeCtor, TypeWalk,
+    FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef,
+    Ty, TypeCtor, TypeWalk,
 };
 
 impl Ty {
@@ -179,7 +179,7 @@ pub(crate) fn from_partly_resolved_hir_path(
                 let name = resolved_segment.name.clone();
                 Ty::Param { idx, name }
             }
-            TypeNs::SelfType(impl_id) => db.impl_ty(impl_id).self_type().clone(),
+            TypeNs::SelfType(impl_id) => db.impl_self_ty(impl_id).clone(),
             TypeNs::AdtSelfType(adt) => db.ty(adt.into()),
 
             TypeNs::AdtId(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()),
@@ -743,17 +743,24 @@ pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty {
     }
 }
 
-pub(crate) fn impl_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> ImplTy {
+pub(crate) fn impl_self_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> Ty {
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db);
-    let self_ty = Ty::from_hir(db, &resolver, &impl_data.target_type);
-    match impl_data.target_trait.as_ref() {
-        Some(trait_ref) => {
-            match TraitRef::from_hir(db, &resolver, trait_ref, Some(self_ty.clone())) {
-                Some(it) => ImplTy::TraitRef(it),
-                None => ImplTy::Inherent(self_ty),
-            }
-        }
-        None => ImplTy::Inherent(self_ty),
-    }
+    Ty::from_hir(db, &resolver, &impl_data.target_type)
+}
+
+pub(crate) fn impl_self_ty_recover(
+    _db: &impl HirDatabase,
+    _cycle: &[String],
+    _impl_id: &ImplId,
+) -> Ty {
+    Ty::Unknown
+}
+
+pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option<TraitRef> {
+    let impl_data = db.impl_data(impl_id);
+    let resolver = impl_id.resolver(db);
+    let self_ty = db.impl_self_ty(impl_id);
+    let target_trait = impl_data.target_trait.as_ref()?;
+    TraitRef::from_hir(db, &resolver, target_trait, Some(self_ty.clone()))
 }
index ee1936b0e5410d8e02c217b269eabe42cfaaaebd..2bded3dbdc028719433ee7219fccf2067590c522 100644 (file)
@@ -19,7 +19,7 @@
     db::HirDatabase,
     primitive::{FloatBitness, Uncertain},
     utils::all_super_traits,
-    Canonical, ImplTy, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor,
+    Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor,
 };
 
 /// This is used as a key for indexing impls.
@@ -58,11 +58,12 @@ pub(crate) fn impls_in_crate_query(
         let crate_def_map = db.crate_def_map(krate);
         for (_module_id, module_data) in crate_def_map.modules.iter() {
             for &impl_id in module_data.impls.iter() {
-                match db.impl_ty(impl_id) {
-                    ImplTy::TraitRef(tr) => {
+                match db.impl_trait(impl_id) {
+                    Some(tr) => {
                         res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id);
                     }
-                    ImplTy::Inherent(self_ty) => {
+                    None => {
+                        let self_ty = db.impl_self_ty(impl_id);
                         if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty) {
                             res.impls.entry(self_ty_fp).or_default().push(impl_id);
                         }
index 4ba87e667ad6f4a5d81c2cee5af26a2fdabdbe58..b72f0f2797034b652c22fbb458178e6023560684 100644 (file)
@@ -4675,6 +4675,48 @@ fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
     assert_eq!(t, "u32");
 }
 
+#[test]
+fn trait_impl_self_ty() {
+    let t = type_at(
+        r#"
+//- /main.rs
+trait Trait<T> {
+   fn foo(&self);
+}
+
+struct S;
+
+impl Trait<Self> for S {}
+
+fn test() {
+    S.foo()<|>;
+}
+"#,
+    );
+    assert_eq!(t, "()");
+}
+
+#[test]
+fn trait_impl_self_ty_cycle() {
+    let t = type_at(
+        r#"
+//- /main.rs
+trait Trait {
+   fn foo(&self);
+}
+
+struct S<T>;
+
+impl Trait for S<Self> {}
+
+fn test() {
+    S.foo()<|>;
+}
+"#,
+    );
+    assert_eq!(t, "{unknown}");
+}
+
 #[test]
 // FIXME this is currently a Salsa panic; it would be nicer if it just returned
 // in Unknown, and we should be able to do that once Salsa allows us to handle
index 35de37e6b625688226d3a9799e5d45541c579b39..104346ada5afb2eab4968ffda2d63eb645e155a1 100644 (file)
@@ -20,8 +20,8 @@
 
 use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
 use crate::{
-    db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ImplTy, ProjectionTy,
-    Substs, TraitRef, Ty, TypeCtor, TypeWalk,
+    db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ProjectionTy, Substs,
+    TraitRef, Ty, TypeCtor, TypeWalk,
 };
 
 /// This represents a trait whose name we could not resolve.
@@ -630,10 +630,7 @@ fn impl_block_datum(
     chalk_id: chalk_ir::ImplId,
     impl_id: ImplId,
 ) -> Option<Arc<ImplDatum<ChalkIr>>> {
-    let trait_ref = match db.impl_ty(impl_id) {
-        ImplTy::TraitRef(it) => it,
-        ImplTy::Inherent(_) => return None,
-    };
+    let trait_ref = db.impl_trait(impl_id)?;
     let impl_data = db.impl_data(impl_id);
 
     let generic_params = db.generic_params(impl_id.into());
@@ -787,11 +784,7 @@ fn type_alias_associated_ty_value(
         _ => panic!("assoc ty value should be in impl"),
     };
 
-    let trait_ref = match db.impl_ty(impl_id) {
-        ImplTy::TraitRef(it) => it,
-        // we don't return any assoc ty values if the impl'd trait can't be resolved
-        ImplTy::Inherent(_) => panic!("assoc ty value should not exist"),
-    };
+    let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist"); // we don't return any assoc ty values if the impl'd trait can't be resolved
 
     let assoc_ty = db
         .trait_data(trait_ref.trait_)