Skip to content

Commit 49489dc

Browse files
committed
Add basic infrastructure for assoc type projection
1 parent 6f946f9 commit 49489dc

File tree

9 files changed

+190
-21
lines changed

9 files changed

+190
-21
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_hir/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ ra_prof = { path = "../ra_prof" }
2525
chalk-solve = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" }
2626
chalk-rust-ir = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" }
2727
chalk-ir = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" }
28+
lalrpop-intern = "0.15.1"
2829

2930
[dev-dependencies]
3031
flexi_logger = "0.11.0"

crates/ra_hir/src/code_model.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,19 @@ impl Trait {
779779
self.trait_data(db).items().to_vec()
780780
}
781781

782+
pub fn associated_type_by_name(self, db: &impl DefDatabase, name: Name) -> Option<TypeAlias> {
783+
let trait_data = self.trait_data(db);
784+
trait_data
785+
.items()
786+
.iter()
787+
.filter_map(|item| match item {
788+
TraitItem::TypeAlias(t) => Some(*t),
789+
_ => None,
790+
})
791+
.filter(|t| t.name(db) == name)
792+
.next()
793+
}
794+
782795
pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
783796
db.trait_data(self)
784797
}
@@ -831,8 +844,12 @@ impl TypeAlias {
831844
}
832845
}
833846

834-
pub fn type_ref(self, db: &impl DefDatabase) -> Arc<TypeRef> {
835-
db.type_alias_ref(self)
847+
pub fn type_ref(self, db: &impl DefDatabase) -> Option<TypeRef> {
848+
db.type_alias_data(self).type_ref.clone()
849+
}
850+
851+
pub fn name(self, db: &impl DefDatabase) -> Name {
852+
db.type_alias_data(self).name.clone()
836853
}
837854

838855
/// Builds a resolver for the type references in this type alias.

crates/ra_hir/src/db.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@ use crate::{
1616
adt::{StructData, EnumData},
1717
impl_block::{ModuleImplBlocks, ImplSourceMap, ImplBlock},
1818
generics::{GenericParams, GenericDef},
19-
type_ref::TypeRef,
2019
traits::TraitData,
21-
lang_item::{LangItems, LangItemTarget},
20+
lang_item::{LangItems, LangItemTarget}, type_alias::TypeAliasData,
2221
};
2322

2423
// This database has access to source code, so queries here are not really
@@ -113,8 +112,8 @@ pub trait DefDatabase: SourceDatabase {
113112
#[salsa::invoke(crate::FnSignature::fn_signature_query)]
114113
fn fn_signature(&self, func: Function) -> Arc<FnSignature>;
115114

116-
#[salsa::invoke(crate::type_alias::type_alias_ref_query)]
117-
fn type_alias_ref(&self, typ: TypeAlias) -> Arc<TypeRef>;
115+
#[salsa::invoke(crate::type_alias::type_alias_data_query)]
116+
fn type_alias_data(&self, typ: TypeAlias) -> Arc<TypeAliasData>;
118117

119118
#[salsa::invoke(crate::ConstSignature::const_signature_query)]
120119
fn const_signature(&self, konst: Const) -> Arc<ConstSignature>;
@@ -185,6 +184,13 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
185184
krate: Crate,
186185
goal: crate::ty::Canonical<crate::ty::TraitRef>,
187186
) -> Option<crate::ty::traits::Solution>;
187+
188+
#[salsa::invoke(crate::ty::traits::normalize)]
189+
fn normalize(
190+
&self,
191+
krate: Crate,
192+
goal: crate::ty::Canonical<crate::ty::traits::ProjectionPredicate>,
193+
) -> Option<crate::ty::traits::Solution>;
188194
}
189195

190196
#[test]

crates/ra_hir/src/ty.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::sync::Arc;
1616
use std::ops::Deref;
1717
use std::{fmt, mem};
1818

19-
use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams};
19+
use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams, TypeAlias};
2020
use display::{HirDisplay, HirFormatter};
2121

2222
pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig, generic_predicates, generic_defaults};
@@ -100,6 +100,15 @@ pub struct ApplicationTy {
100100
pub parameters: Substs,
101101
}
102102

103+
/// A "projection" type corresponds to an (unnormalized)
104+
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
105+
/// trait and all its parameters are fully known.
106+
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
107+
pub struct ProjectionTy {
108+
pub associated_ty: TypeAlias,
109+
pub parameters: Substs,
110+
}
111+
103112
/// A type.
104113
///
105114
/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents

crates/ra_hir/src/ty/lower.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty {
460460
let resolver = t.resolver(db);
461461
let type_ref = t.type_ref(db);
462462
let substs = Substs::identity(&generics);
463-
let inner = Ty::from_hir(db, &resolver, &type_ref);
463+
let inner = Ty::from_hir(db, &resolver, &type_ref.unwrap_or(TypeRef::Error));
464464
inner.subst(&substs)
465465
}
466466

crates/ra_hir/src/ty/traits.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use chalk_ir::cast::Cast;
88
use ra_prof::profile;
99

1010
use crate::{Crate, Trait, db::HirDatabase, ImplBlock};
11-
use super::{TraitRef, Ty, Canonical};
11+
use super::{TraitRef, Ty, Canonical, ProjectionTy};
1212

1313
use self::chalk::{ToChalk, from_chalk};
1414

@@ -75,6 +75,13 @@ pub enum Obligation {
7575
/// Prove that a certain type implements a trait (the type is the `Self` type
7676
/// parameter to the `TraitRef`).
7777
Trait(TraitRef),
78+
// Projection(ProjectionPredicate),
79+
}
80+
81+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
82+
pub struct ProjectionPredicate {
83+
projection_ty: ProjectionTy,
84+
ty: Ty,
7885
}
7986

8087
/// Check using Chalk whether trait is implemented for given parameters including `Self` type.
@@ -98,6 +105,30 @@ pub(crate) fn implements_query(
98105
solution.map(|solution| solution_from_chalk(db, solution))
99106
}
100107

108+
pub(crate) fn normalize(
109+
db: &impl HirDatabase,
110+
krate: Crate,
111+
projection: Canonical<ProjectionPredicate>,
112+
) -> Option<Solution> {
113+
let goal: chalk_ir::Goal = chalk_ir::Normalize {
114+
projection: projection.value.projection_ty.to_chalk(db),
115+
ty: projection.value.ty.to_chalk(db),
116+
}
117+
.cast();
118+
debug!("goal: {:?}", goal);
119+
// FIXME unify with `implements`
120+
let env = chalk_ir::Environment::new();
121+
let in_env = chalk_ir::InEnvironment::new(&env, goal);
122+
let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT);
123+
let canonical =
124+
chalk_ir::Canonical { value: in_env, binders: vec![parameter; projection.num_vars] };
125+
// We currently don't deal with universes (I think / hope they're not yet
126+
// relevant for our use cases?)
127+
let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
128+
let solution = solve(db, krate, &u_canonical);
129+
solution.map(|solution| solution_from_chalk(db, solution))
130+
}
131+
101132
fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution {
102133
let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution>| {
103134
let value = subst

crates/ra_hir/src/ty/traits/chalk.rs

Lines changed: 102 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::sync::Arc;
33

44
use log::debug;
55

6-
use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName};
6+
use chalk_ir::{TypeId, ImplId, TypeKindId, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName};
77
use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum};
88

99
use test_utils::tested_by;
@@ -12,9 +12,9 @@ use ra_db::salsa::{InternId, InternKey};
1212
use crate::{
1313
Trait, HasGenericParams, ImplBlock,
1414
db::HirDatabase,
15-
ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs, GenericPredicate, CallableDef},
15+
ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs, GenericPredicate, CallableDef, ProjectionTy},
1616
ty::display::HirDisplay,
17-
generics::GenericDef,
17+
generics::GenericDef, TypeAlias, ImplItem,
1818
};
1919
use super::ChalkContext;
2020

@@ -156,6 +156,18 @@ impl ToChalk for ImplBlock {
156156
}
157157
}
158158

159+
impl ToChalk for TypeAlias {
160+
type Chalk = chalk_ir::TypeId;
161+
162+
fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TypeId {
163+
self.id.into()
164+
}
165+
166+
fn from_chalk(_db: &impl HirDatabase, impl_id: chalk_ir::TypeId) -> TypeAlias {
167+
TypeAlias { id: impl_id.into() }
168+
}
169+
}
170+
159171
impl ToChalk for GenericPredicate {
160172
type Chalk = chalk_ir::QuantifiedWhereClause;
161173

@@ -183,6 +195,24 @@ impl ToChalk for GenericPredicate {
183195
}
184196
}
185197

198+
impl ToChalk for ProjectionTy {
199+
type Chalk = chalk_ir::ProjectionTy;
200+
201+
fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy {
202+
chalk_ir::ProjectionTy {
203+
associated_ty_id: self.associated_ty.to_chalk(db),
204+
parameters: self.parameters.to_chalk(db),
205+
}
206+
}
207+
208+
fn from_chalk(db: &impl HirDatabase, projection_ty: chalk_ir::ProjectionTy) -> ProjectionTy {
209+
ProjectionTy {
210+
associated_ty: from_chalk(db, projection_ty.associated_ty_id),
211+
parameters: from_chalk(db, projection_ty.parameters),
212+
}
213+
}
214+
}
215+
186216
fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
187217
chalk_ir::Binders {
188218
value,
@@ -225,8 +255,28 @@ impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB>
225255
where
226256
DB: HirDatabase,
227257
{
228-
fn associated_ty_data(&self, _ty: TypeId) -> Arc<AssociatedTyDatum> {
229-
unimplemented!()
258+
fn associated_ty_data(&self, id: TypeId) -> Arc<AssociatedTyDatum> {
259+
debug!("associated_ty_data {:?}", id);
260+
let type_alias: TypeAlias = from_chalk(self.db, id);
261+
let trait_ = match type_alias.container(self.db) {
262+
Some(crate::Container::Trait(t)) => t,
263+
_ => panic!("associated type not in trait"),
264+
};
265+
let generic_params = type_alias.generic_params(self.db);
266+
let parameter_kinds = generic_params
267+
.params_including_parent()
268+
.into_iter()
269+
.map(|p| chalk_ir::ParameterKind::Ty(lalrpop_intern::intern(&p.name.to_string())))
270+
.collect();
271+
let datum = AssociatedTyDatum {
272+
trait_id: trait_.to_chalk(self.db),
273+
id,
274+
name: lalrpop_intern::intern(&type_alias.name(self.db).to_string()),
275+
parameter_kinds,
276+
bounds: vec![], // FIXME
277+
where_clauses: vec![], // FIXME
278+
};
279+
Arc::new(datum)
230280
}
231281
fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> {
232282
debug!("trait_datum {:?}", trait_id);
@@ -260,7 +310,15 @@ where
260310
fundamental: false,
261311
};
262312
let where_clauses = convert_where_clauses(self.db, trait_.into(), &bound_vars);
263-
let associated_ty_ids = Vec::new(); // FIXME add associated tys
313+
let associated_ty_ids = trait_
314+
.items(self.db)
315+
.into_iter()
316+
.filter_map(|trait_item| match trait_item {
317+
crate::traits::TraitItem::TypeAlias(type_alias) => Some(type_alias),
318+
_ => None,
319+
})
320+
.map(|type_alias| type_alias.to_chalk(self.db))
321+
.collect();
264322
let trait_datum_bound =
265323
chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids };
266324
let trait_datum = TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()) };
@@ -359,17 +417,41 @@ where
359417
trait_ref.display(self.db),
360418
where_clauses
361419
);
420+
let trait_ = trait_ref.trait_;
362421
let trait_ref = trait_ref.to_chalk(self.db);
422+
let associated_ty_values = impl_block
423+
.items(self.db)
424+
.into_iter()
425+
.filter_map(|item| match item {
426+
ImplItem::TypeAlias(t) => Some(t),
427+
_ => None,
428+
})
429+
.filter_map(|t| {
430+
let assoc_ty = trait_.associated_type_by_name(self.db, t.name(self.db))?;
431+
let ty = self.db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars);
432+
debug!("ty = {}", ty.display(self.db));
433+
Some(chalk_rust_ir::AssociatedTyValue {
434+
impl_id,
435+
associated_ty_id: assoc_ty.to_chalk(self.db),
436+
value: chalk_ir::Binders {
437+
value: chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(self.db) },
438+
binders: vec![], // FIXME add generic params (generic associated types)
439+
},
440+
})
441+
})
442+
.collect();
443+
363444
let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
364445
trait_ref: if negative {
365446
chalk_rust_ir::PolarizedTraitRef::Negative(trait_ref)
366447
} else {
367448
chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref)
368449
},
369450
where_clauses,
370-
associated_ty_values: Vec::new(), // FIXME add associated type values
451+
associated_ty_values,
371452
impl_type,
372453
};
454+
debug!("impl_datum: {:?}", impl_datum_bound);
373455
let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, bound_vars.len()) };
374456
Arc::new(impl_datum)
375457
}
@@ -405,7 +487,7 @@ where
405487
}
406488
fn split_projection<'p>(
407489
&self,
408-
projection: &'p ProjectionTy,
490+
projection: &'p chalk_ir::ProjectionTy,
409491
) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) {
410492
debug!("split_projection {:?}", projection);
411493
unimplemented!()
@@ -440,6 +522,18 @@ impl From<crate::ids::TraitId> for chalk_ir::TraitId {
440522
}
441523
}
442524

525+
impl From<chalk_ir::TypeId> for crate::ids::TypeAliasId {
526+
fn from(type_id: chalk_ir::TypeId) -> Self {
527+
id_from_chalk(type_id.0)
528+
}
529+
}
530+
531+
impl From<crate::ids::TypeAliasId> for chalk_ir::TypeId {
532+
fn from(type_id: crate::ids::TypeAliasId) -> Self {
533+
chalk_ir::TypeId(id_to_chalk(type_id))
534+
}
535+
}
536+
443537
impl From<chalk_ir::StructId> for crate::ids::TypeCtorId {
444538
fn from(struct_id: chalk_ir::StructId) -> Self {
445539
id_from_chalk(struct_id.0)

crates/ra_hir/src/type_alias.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,22 @@
22
33
use std::sync::Arc;
44

5-
use crate::{TypeAlias, DefDatabase, AstDatabase, HasSource, type_ref::TypeRef};
5+
use ra_syntax::ast::NameOwner;
66

7-
pub(crate) fn type_alias_ref_query(
7+
use crate::{TypeAlias, db::{DefDatabase, AstDatabase}, type_ref::TypeRef, name::{Name, AsName}, HasSource};
8+
9+
#[derive(Debug, Clone, PartialEq, Eq)]
10+
pub struct TypeAliasData {
11+
pub(crate) name: Name,
12+
pub(crate) type_ref: Option<TypeRef>,
13+
}
14+
15+
pub(crate) fn type_alias_data_query(
816
db: &(impl DefDatabase + AstDatabase),
917
typ: TypeAlias,
10-
) -> Arc<TypeRef> {
18+
) -> Arc<TypeAliasData> {
1119
let node = typ.source(db).ast;
12-
Arc::new(TypeRef::from_ast_opt(node.type_ref()))
20+
let name = node.name().map_or_else(Name::missing, |n| n.as_name());
21+
let type_ref = node.type_ref().map(TypeRef::from_ast);
22+
Arc::new(TypeAliasData { name, type_ref })
1323
}

0 commit comments

Comments
 (0)