Skip to content

Commit 9712889

Browse files
Merge #2453
2453: Handle various cycles r=matklad a=flodiebold - handle `impl Trait<Self> for SomeType`, which is allowed. This necessitated splitting the `impl_ty` query, but I think the result actually makes a lot of code nicer. This should fix #2446. - add recovery for `impl Trait for SomeType<Self>` - add recovery for `type Type = Foo<Type>` - add recovery for cycles in generic param env Co-authored-by: Florian Diebold <flodiebold@gmail.com>
2 parents 7cecd0f + 1c622e9 commit 9712889

File tree

8 files changed

+102
-63
lines changed

8 files changed

+102
-63
lines changed

crates/ra_hir_ty/src/db.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use ra_db::{salsa, CrateId};
1111
use crate::{
1212
method_resolution::CrateImplBlocks,
1313
traits::{AssocTyValue, Impl},
14-
CallableDef, FnSig, GenericPredicate, ImplTy, InferenceResult, Substs, Ty, TyDefId, TypeCtor,
14+
CallableDef, FnSig, GenericPredicate, InferenceResult, Substs, TraitRef, Ty, TyDefId, TypeCtor,
1515
ValueTyDefId,
1616
};
1717

@@ -22,13 +22,18 @@ pub trait HirDatabase: DefDatabase {
2222
fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
2323

2424
#[salsa::invoke(crate::lower::ty_query)]
25+
#[salsa::cycle(crate::lower::ty_recover)]
2526
fn ty(&self, def: TyDefId) -> Ty;
2627

2728
#[salsa::invoke(crate::lower::value_ty_query)]
2829
fn value_ty(&self, def: ValueTyDefId) -> Ty;
2930

30-
#[salsa::invoke(crate::lower::impl_ty_query)]
31-
fn impl_ty(&self, def: ImplId) -> ImplTy;
31+
#[salsa::invoke(crate::lower::impl_self_ty_query)]
32+
#[salsa::cycle(crate::lower::impl_self_ty_recover)]
33+
fn impl_self_ty(&self, def: ImplId) -> Ty;
34+
35+
#[salsa::invoke(crate::lower::impl_trait_query)]
36+
fn impl_trait(&self, def: ImplId) -> Option<TraitRef>;
3237

3338
#[salsa::invoke(crate::lower::field_types_query)]
3439
fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalStructFieldId, Ty>>;
@@ -37,6 +42,7 @@ pub trait HirDatabase: DefDatabase {
3742
fn callable_item_signature(&self, def: CallableDef) -> FnSig;
3843

3944
#[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
45+
#[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
4046
fn generic_predicates_for_param(
4147
&self,
4248
def: GenericDefId,

crates/ra_hir_ty/src/infer/coerce.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use hir_def::{lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutabilit
88
use rustc_hash::FxHashMap;
99
use test_utils::tested_by;
1010

11-
use crate::{autoderef, db::HirDatabase, ImplTy, Substs, Ty, TypeCtor, TypeWalk};
11+
use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk};
1212

1313
use super::{InEnvironment, InferTy, InferenceContext, TypeVarValue};
1414

@@ -54,10 +54,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
5454
impls
5555
.iter()
5656
.filter_map(|&impl_id| {
57-
let trait_ref = match db.impl_ty(impl_id) {
58-
ImplTy::TraitRef(it) => it,
59-
ImplTy::Inherent(_) => return None,
60-
};
57+
let trait_ref = db.impl_trait(impl_id)?;
6158

6259
// `CoerseUnsized` has one generic parameter for the target type.
6360
let cur_from_ty = trait_ref.substs.0.get(0)?;

crates/ra_hir_ty/src/infer/path.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
244244
ContainerId::ImplId(it) => it,
245245
_ => return None,
246246
};
247-
let self_ty = self.db.impl_ty(impl_id).self_type().clone();
247+
let self_ty = self.db.impl_self_ty(impl_id).clone();
248248
let self_ty_substs = self_ty.substs()?;
249249
let actual_substs = actual_def_ty.substs()?;
250250

crates/ra_hir_ty/src/lib.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -486,21 +486,6 @@ impl TypeWalk for TraitRef {
486486
}
487487
}
488488

489-
#[derive(Clone, PartialEq, Eq, Debug)]
490-
pub enum ImplTy {
491-
Inherent(Ty),
492-
TraitRef(TraitRef),
493-
}
494-
495-
impl ImplTy {
496-
pub(crate) fn self_type(&self) -> &Ty {
497-
match self {
498-
ImplTy::Inherent(it) => it,
499-
ImplTy::TraitRef(tr) => &tr.substs[0],
500-
}
501-
}
502-
}
503-
504489
/// Like `generics::WherePredicate`, but with resolved types: A condition on the
505490
/// parameters of a generic item.
506491
#[derive(Debug, Clone, PartialEq, Eq, Hash)]

crates/ra_hir_ty/src/lower.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use crate::{
2727
all_super_traits, associated_type_by_name_including_super_traits, make_mut_slice,
2828
variant_data,
2929
},
30-
FnSig, GenericPredicate, ImplTy, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment,
31-
TraitRef, Ty, TypeCtor, TypeWalk,
30+
FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef,
31+
Ty, TypeCtor, TypeWalk,
3232
};
3333

3434
impl Ty {
@@ -179,7 +179,7 @@ impl Ty {
179179
let name = resolved_segment.name.clone();
180180
Ty::Param { idx, name }
181181
}
182-
TypeNs::SelfType(impl_id) => db.impl_ty(impl_id).self_type().clone(),
182+
TypeNs::SelfType(impl_id) => db.impl_self_ty(impl_id).clone(),
183183
TypeNs::AdtSelfType(adt) => db.ty(adt.into()),
184184

185185
TypeNs::AdtId(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()),
@@ -532,6 +532,15 @@ pub(crate) fn generic_predicates_for_param_query(
532532
.collect()
533533
}
534534

535+
pub(crate) fn generic_predicates_for_param_recover(
536+
_db: &impl HirDatabase,
537+
_cycle: &[String],
538+
_def: &GenericDefId,
539+
_param_idx: &u32,
540+
) -> Arc<[GenericPredicate]> {
541+
Arc::new([])
542+
}
543+
535544
impl TraitEnvironment {
536545
pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> {
537546
let predicates = resolver
@@ -733,6 +742,11 @@ pub(crate) fn ty_query(db: &impl HirDatabase, def: TyDefId) -> Ty {
733742
TyDefId::TypeAliasId(it) => type_for_type_alias(db, it),
734743
}
735744
}
745+
746+
pub(crate) fn ty_recover(_db: &impl HirDatabase, _cycle: &[String], _def: &TyDefId) -> Ty {
747+
Ty::Unknown
748+
}
749+
736750
pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty {
737751
match def {
738752
ValueTyDefId::FunctionId(it) => type_for_fn(db, it),
@@ -743,17 +757,24 @@ pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty {
743757
}
744758
}
745759

746-
pub(crate) fn impl_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> ImplTy {
760+
pub(crate) fn impl_self_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> Ty {
747761
let impl_data = db.impl_data(impl_id);
748762
let resolver = impl_id.resolver(db);
749-
let self_ty = Ty::from_hir(db, &resolver, &impl_data.target_type);
750-
match impl_data.target_trait.as_ref() {
751-
Some(trait_ref) => {
752-
match TraitRef::from_hir(db, &resolver, trait_ref, Some(self_ty.clone())) {
753-
Some(it) => ImplTy::TraitRef(it),
754-
None => ImplTy::Inherent(self_ty),
755-
}
756-
}
757-
None => ImplTy::Inherent(self_ty),
758-
}
763+
Ty::from_hir(db, &resolver, &impl_data.target_type)
764+
}
765+
766+
pub(crate) fn impl_self_ty_recover(
767+
_db: &impl HirDatabase,
768+
_cycle: &[String],
769+
_impl_id: &ImplId,
770+
) -> Ty {
771+
Ty::Unknown
772+
}
773+
774+
pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option<TraitRef> {
775+
let impl_data = db.impl_data(impl_id);
776+
let resolver = impl_id.resolver(db);
777+
let self_ty = db.impl_self_ty(impl_id);
778+
let target_trait = impl_data.target_trait.as_ref()?;
779+
TraitRef::from_hir(db, &resolver, target_trait, Some(self_ty.clone()))
759780
}

crates/ra_hir_ty/src/method_resolution.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
db::HirDatabase,
2020
primitive::{FloatBitness, Uncertain},
2121
utils::all_super_traits,
22-
Canonical, ImplTy, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor,
22+
Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor,
2323
};
2424

2525
/// This is used as a key for indexing impls.
@@ -58,11 +58,12 @@ impl CrateImplBlocks {
5858
let crate_def_map = db.crate_def_map(krate);
5959
for (_module_id, module_data) in crate_def_map.modules.iter() {
6060
for &impl_id in module_data.impls.iter() {
61-
match db.impl_ty(impl_id) {
62-
ImplTy::TraitRef(tr) => {
61+
match db.impl_trait(impl_id) {
62+
Some(tr) => {
6363
res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id);
6464
}
65-
ImplTy::Inherent(self_ty) => {
65+
None => {
66+
let self_ty = db.impl_self_ty(impl_id);
6667
if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty) {
6768
res.impls.entry(self_ty_fp).or_default().push(impl_id);
6869
}

crates/ra_hir_ty/src/tests.rs

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,7 +2154,6 @@ fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) {
21542154
}
21552155

21562156
#[test]
2157-
#[should_panic] // we currently can't handle this
21582157
fn recursive_type_alias() {
21592158
assert_snapshot!(
21602159
infer(r#"
@@ -2163,7 +2162,10 @@ type Foo = Foo;
21632162
type Bar = A<Bar>;
21642163
fn test(x: Foo) {}
21652164
"#),
2166-
@""
2165+
@r###"
2166+
[59; 60) 'x': {unknown}
2167+
[67; 69) '{}': ()
2168+
"###
21672169
)
21682170
}
21692171

@@ -4676,10 +4678,48 @@ fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
46764678
}
46774679

46784680
#[test]
4679-
// FIXME this is currently a Salsa panic; it would be nicer if it just returned
4680-
// in Unknown, and we should be able to do that once Salsa allows us to handle
4681-
// the cycle. But at least it doesn't overflow for now.
4682-
#[should_panic]
4681+
fn trait_impl_self_ty() {
4682+
let t = type_at(
4683+
r#"
4684+
//- /main.rs
4685+
trait Trait<T> {
4686+
fn foo(&self);
4687+
}
4688+
4689+
struct S;
4690+
4691+
impl Trait<Self> for S {}
4692+
4693+
fn test() {
4694+
S.foo()<|>;
4695+
}
4696+
"#,
4697+
);
4698+
assert_eq!(t, "()");
4699+
}
4700+
4701+
#[test]
4702+
fn trait_impl_self_ty_cycle() {
4703+
let t = type_at(
4704+
r#"
4705+
//- /main.rs
4706+
trait Trait {
4707+
fn foo(&self);
4708+
}
4709+
4710+
struct S<T>;
4711+
4712+
impl Trait for S<Self> {}
4713+
4714+
fn test() {
4715+
S.foo()<|>;
4716+
}
4717+
"#,
4718+
);
4719+
assert_eq!(t, "{unknown}");
4720+
}
4721+
4722+
#[test]
46834723
fn unselected_projection_in_trait_env_cycle_1() {
46844724
let t = type_at(
46854725
r#"
@@ -4700,10 +4740,6 @@ fn test<T: Trait>() where T: Trait2<T::Item> {
47004740
}
47014741

47024742
#[test]
4703-
// FIXME this is currently a Salsa panic; it would be nicer if it just returned
4704-
// in Unknown, and we should be able to do that once Salsa allows us to handle
4705-
// the cycle. But at least it doesn't overflow for now.
4706-
#[should_panic]
47074743
fn unselected_projection_in_trait_env_cycle_2() {
47084744
let t = type_at(
47094745
r#"

crates/ra_hir_ty/src/traits/chalk.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use ra_db::salsa::{InternId, InternKey};
2020

2121
use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
2222
use crate::{
23-
db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ImplTy, ProjectionTy,
24-
Substs, TraitRef, Ty, TypeCtor, TypeWalk,
23+
db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ProjectionTy, Substs,
24+
TraitRef, Ty, TypeCtor, TypeWalk,
2525
};
2626

2727
/// This represents a trait whose name we could not resolve.
@@ -630,10 +630,7 @@ fn impl_block_datum(
630630
chalk_id: chalk_ir::ImplId,
631631
impl_id: ImplId,
632632
) -> Option<Arc<ImplDatum<ChalkIr>>> {
633-
let trait_ref = match db.impl_ty(impl_id) {
634-
ImplTy::TraitRef(it) => it,
635-
ImplTy::Inherent(_) => return None,
636-
};
633+
let trait_ref = db.impl_trait(impl_id)?;
637634
let impl_data = db.impl_data(impl_id);
638635

639636
let generic_params = db.generic_params(impl_id.into());
@@ -787,11 +784,7 @@ fn type_alias_associated_ty_value(
787784
_ => panic!("assoc ty value should be in impl"),
788785
};
789786

790-
let trait_ref = match db.impl_ty(impl_id) {
791-
ImplTy::TraitRef(it) => it,
792-
// we don't return any assoc ty values if the impl'd trait can't be resolved
793-
ImplTy::Inherent(_) => panic!("assoc ty value should not exist"),
794-
};
787+
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
795788

796789
let assoc_ty = db
797790
.trait_data(trait_ref.trait_)

0 commit comments

Comments
 (0)