Skip to content

Commit 500e022

Browse files
bors[bot]matklad
andauthored
Merge #2398
2398: WIP: introduce hir::Type r=matklad a=matklad This introduces `hir::Type` wrapper over `hir::Ty`, with two purposes: * bind `Ty` and it's corresponding environment * Am I correct that `Ty` without an env doesn't make much sense, because the meaning of type parameters is unclear * Am I correct that we can safely re-use the same environment for all types derived from the given type? * hide representation defails of `Ty`. Specifically, I want to change `Ty::Adt` to use `hir_def::AdtId` instead of `hir::Adt`, but IDE doesn't know about underlying IDs. More generally, I feel like IDE shouldn't know that `Ty` is enum. @flodiebold what do you think about this? Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 5901cc7 + e5eadb3 commit 500e022

File tree

15 files changed

+253
-136
lines changed

15 files changed

+253
-136
lines changed

crates/ra_assists/src/assists/add_explicit_type.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use hir::{db::HirDatabase, HirDisplay, Ty};
1+
use hir::{db::HirDatabase, HirDisplay};
22
use ra_syntax::{
33
ast::{self, AstNode, LetStmt, NameOwner},
44
T,
@@ -43,7 +43,7 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
4343
let analyzer = ctx.source_analyzer(stmt.syntax(), None);
4444
let ty = analyzer.type_of(db, &expr)?;
4545
// Assist not applicable if the type is unknown
46-
if is_unknown(&ty) {
46+
if ty.contains_unknown() {
4747
return None;
4848
}
4949

@@ -53,15 +53,6 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
5353
})
5454
}
5555

56-
/// Returns true if any type parameter is unknown
57-
fn is_unknown(ty: &Ty) -> bool {
58-
match ty {
59-
Ty::Unknown => true,
60-
Ty::Apply(a_ty) => a_ty.parameters.iter().any(is_unknown),
61-
_ => false,
62-
}
63-
}
64-
6556
#[cfg(test)]
6657
mod tests {
6758
use super::*;

crates/ra_assists/src/assists/fill_match_arms.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,11 @@ fn resolve_enum_def(
8383
) -> Option<ast::EnumDef> {
8484
let expr_ty = analyzer.type_of(db, &expr)?;
8585

86-
analyzer.autoderef(db, expr_ty).find_map(|ty| match ty.as_adt() {
87-
Some((Adt::Enum(e), _)) => Some(e.source(db).value),
86+
let res = expr_ty.autoderef(db).find_map(|ty| match ty.as_adt() {
87+
Some(Adt::Enum(e)) => Some(e.source(db).value),
8888
_ => None,
89-
})
89+
});
90+
res
9091
}
9192

9293
fn build_pat(var: ast::EnumVariant) -> Option<ast::Pat> {

crates/ra_hir/src/code_model.rs

Lines changed: 159 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use hir_def::{
1010
docs::Documentation,
1111
per_ns::PerNs,
1212
resolver::{HasResolver, TypeNs},
13-
type_ref::TypeRef,
14-
AstItemDef, ConstId, ContainerId, EnumId, FunctionId, GenericDefId, HasModule, ImplId,
15-
LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId,
13+
type_ref::{Mutability, TypeRef},
14+
AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule,
15+
ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId,
1616
StaticId, StructId, TraitId, TypeAliasId, UnionId,
1717
};
1818
use hir_expand::{
@@ -26,8 +26,12 @@ use ra_syntax::{ast, AstNode, SyntaxNode};
2626
use crate::{
2727
db::{DefDatabase, HirDatabase},
2828
expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId},
29-
ty::{InferenceResult, Namespace, TraitRef},
30-
Either, Name, Source, Ty,
29+
ty::display::HirFormatter,
30+
ty::{
31+
self, InEnvironment, InferenceResult, Namespace, TraitEnvironment, TraitRef, Ty, TypeCtor,
32+
TypeWalk,
33+
},
34+
CallableDef, Either, HirDisplay, Name, Source,
3135
};
3236

3337
/// hir::Crate describes a single crate. It's the main interface with which
@@ -469,6 +473,10 @@ pub enum Adt {
469473
impl_froms!(Adt: Struct, Union, Enum);
470474

471475
impl Adt {
476+
pub fn has_non_default_type_params(self, db: &impl HirDatabase) -> bool {
477+
let subst = db.generic_defaults(self.into());
478+
subst.iter().any(|ty| ty == &Ty::Unknown)
479+
}
472480
pub fn ty(self, db: &impl HirDatabase) -> Ty {
473481
match self {
474482
Adt::Struct(it) => it.ty(db),
@@ -777,6 +785,11 @@ pub struct TypeAlias {
777785
}
778786

779787
impl TypeAlias {
788+
pub fn has_non_default_type_params(self, db: &impl HirDatabase) -> bool {
789+
let subst = db.generic_defaults(self.id.into());
790+
subst.iter().any(|ty| ty == &Ty::Unknown)
791+
}
792+
780793
pub fn module(self, db: &impl DefDatabase) -> Module {
781794
Module { id: self.id.lookup(db).module(db) }
782795
}
@@ -927,9 +940,14 @@ impl Local {
927940
self.parent.module(db)
928941
}
929942

930-
pub fn ty(self, db: &impl HirDatabase) -> Ty {
943+
pub fn ty(self, db: &impl HirDatabase) -> Type {
931944
let infer = db.infer(self.parent);
932-
infer[self.pat_id].clone()
945+
let ty = infer[self.pat_id].clone();
946+
let def = DefWithBodyId::from(self.parent);
947+
let resolver = def.resolver(db);
948+
let krate = def.module(db).krate;
949+
let environment = TraitEnvironment::lower(db, &resolver);
950+
Type { krate, ty: InEnvironment { value: ty, environment } }
933951
}
934952

935953
pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> {
@@ -986,6 +1004,140 @@ impl ImplBlock {
9861004
}
9871005
}
9881006

1007+
#[derive(Clone, PartialEq, Eq)]
1008+
pub struct Type {
1009+
pub(crate) krate: CrateId,
1010+
pub(crate) ty: InEnvironment<Ty>,
1011+
}
1012+
1013+
impl Type {
1014+
pub fn is_bool(&self) -> bool {
1015+
match &self.ty.value {
1016+
Ty::Apply(a_ty) => match a_ty.ctor {
1017+
TypeCtor::Bool => true,
1018+
_ => false,
1019+
},
1020+
_ => false,
1021+
}
1022+
}
1023+
1024+
pub fn is_mutable_reference(&self) -> bool {
1025+
match &self.ty.value {
1026+
Ty::Apply(a_ty) => match a_ty.ctor {
1027+
TypeCtor::Ref(Mutability::Mut) => true,
1028+
_ => false,
1029+
},
1030+
_ => false,
1031+
}
1032+
}
1033+
1034+
pub fn is_unknown(&self) -> bool {
1035+
match &self.ty.value {
1036+
Ty::Unknown => true,
1037+
_ => false,
1038+
}
1039+
}
1040+
1041+
// FIXME: this method is broken, as it doesn't take closures into account.
1042+
pub fn as_callable(&self) -> Option<CallableDef> {
1043+
Some(self.ty.value.as_callable()?.0)
1044+
}
1045+
1046+
pub fn contains_unknown(&self) -> bool {
1047+
return go(&self.ty.value);
1048+
1049+
fn go(ty: &Ty) -> bool {
1050+
match ty {
1051+
Ty::Unknown => true,
1052+
Ty::Apply(a_ty) => a_ty.parameters.iter().any(go),
1053+
_ => false,
1054+
}
1055+
}
1056+
}
1057+
1058+
pub fn fields(&self, db: &impl HirDatabase) -> Vec<(StructField, Type)> {
1059+
let mut res = Vec::new();
1060+
if let Ty::Apply(a_ty) = &self.ty.value {
1061+
match a_ty.ctor {
1062+
ty::TypeCtor::Adt(Adt::Struct(s)) => {
1063+
for field in s.fields(db) {
1064+
let ty = field.ty(db).subst(&a_ty.parameters);
1065+
res.push((field, self.derived(ty)));
1066+
}
1067+
}
1068+
_ => {}
1069+
}
1070+
};
1071+
res
1072+
}
1073+
1074+
pub fn tuple_fields(&self, _db: &impl HirDatabase) -> Vec<Type> {
1075+
let mut res = Vec::new();
1076+
if let Ty::Apply(a_ty) = &self.ty.value {
1077+
match a_ty.ctor {
1078+
ty::TypeCtor::Tuple { .. } => {
1079+
for ty in a_ty.parameters.iter() {
1080+
let ty = ty.clone().subst(&a_ty.parameters);
1081+
res.push(self.derived(ty));
1082+
}
1083+
}
1084+
_ => {}
1085+
}
1086+
};
1087+
res
1088+
}
1089+
1090+
pub fn variant_fields(
1091+
&self,
1092+
db: &impl HirDatabase,
1093+
def: VariantDef,
1094+
) -> Vec<(StructField, Type)> {
1095+
// FIXME: check that ty and def match
1096+
match &self.ty.value {
1097+
Ty::Apply(a_ty) => def
1098+
.fields(db)
1099+
.into_iter()
1100+
.map(|it| (it, self.derived(it.ty(db).subst(&a_ty.parameters))))
1101+
.collect(),
1102+
_ => Vec::new(),
1103+
}
1104+
}
1105+
1106+
pub fn autoderef<'a>(&'a self, db: &'a impl HirDatabase) -> impl Iterator<Item = Type> + 'a {
1107+
// There should be no inference vars in types passed here
1108+
// FIXME check that?
1109+
let canonical = crate::ty::Canonical { value: self.ty.value.clone(), num_vars: 0 };
1110+
let environment = self.ty.environment.clone();
1111+
let ty = InEnvironment { value: canonical, environment: environment.clone() };
1112+
ty::autoderef(db, Some(self.krate), ty)
1113+
.map(|canonical| canonical.value)
1114+
.map(move |ty| self.derived(ty))
1115+
}
1116+
1117+
// FIXME: remove
1118+
pub fn into_ty(self) -> Ty {
1119+
self.ty.value
1120+
}
1121+
1122+
pub fn as_adt(&self) -> Option<Adt> {
1123+
let (adt, _subst) = self.ty.value.as_adt()?;
1124+
Some(adt)
1125+
}
1126+
1127+
fn derived(&self, ty: Ty) -> Type {
1128+
Type {
1129+
krate: self.krate,
1130+
ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
1131+
}
1132+
}
1133+
}
1134+
1135+
impl HirDisplay for Type {
1136+
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> std::fmt::Result {
1137+
self.ty.value.hir_fmt(f)
1138+
}
1139+
}
1140+
9891141
/// For IDE only
9901142
pub enum ScopeDef {
9911143
ModuleDef(ModuleDef),

crates/ra_hir/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub use crate::{
5151
src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency,
5252
DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, GenericParam,
5353
HasAttrs, ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef,
54-
Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
54+
Static, Struct, StructField, Trait, Type, TypeAlias, Union, VariantDef,
5555
},
5656
expr::ExprScopes,
5757
from_source::FromSource,

crates/ra_hir/src/source_binder.rs

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ use crate::{
2828
expr::{BodySourceMap, ExprScopes, ScopeId},
2929
ty::{
3030
method_resolution::{self, implements_trait},
31-
TraitEnvironment,
31+
InEnvironment, TraitEnvironment, Ty,
3232
},
3333
Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function,
34-
GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Ty, TypeAlias,
34+
GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias,
3535
};
3636

3737
fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> {
@@ -198,14 +198,18 @@ impl SourceAnalyzer {
198198
self.body_source_map.as_ref()?.node_pat(src)
199199
}
200200

201-
pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> {
201+
pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> {
202202
let expr_id = self.expr_id(expr)?;
203-
Some(self.infer.as_ref()?[expr_id].clone())
203+
let ty = self.infer.as_ref()?[expr_id].clone();
204+
let environment = TraitEnvironment::lower(db, &self.resolver);
205+
Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
204206
}
205207

206-
pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> {
208+
pub fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option<Type> {
207209
let pat_id = self.pat_id(pat)?;
208-
Some(self.infer.as_ref()?[pat_id].clone())
210+
let ty = self.infer.as_ref()?[pat_id].clone();
211+
let environment = TraitEnvironment::lower(db, &self.resolver);
212+
Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
209213
}
210214

211215
pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
@@ -361,14 +365,14 @@ impl SourceAnalyzer {
361365
pub fn iterate_method_candidates<T>(
362366
&self,
363367
db: &impl HirDatabase,
364-
ty: Ty,
368+
ty: &Type,
365369
name: Option<&Name>,
366370
mut callback: impl FnMut(&Ty, Function) -> Option<T>,
367371
) -> Option<T> {
368372
// There should be no inference vars in types passed here
369373
// FIXME check that?
370374
// FIXME replace Unknown by bound vars here
371-
let canonical = crate::ty::Canonical { value: ty, num_vars: 0 };
375+
let canonical = crate::ty::Canonical { value: ty.ty.value.clone(), num_vars: 0 };
372376
method_resolution::iterate_method_candidates(
373377
&canonical,
374378
db,
@@ -403,19 +407,19 @@ impl SourceAnalyzer {
403407
)
404408
}
405409

406-
pub fn autoderef<'a>(
407-
&'a self,
408-
db: &'a impl HirDatabase,
409-
ty: Ty,
410-
) -> impl Iterator<Item = Ty> + 'a {
411-
// There should be no inference vars in types passed here
412-
// FIXME check that?
413-
let canonical = crate::ty::Canonical { value: ty, num_vars: 0 };
414-
let krate = self.resolver.krate();
415-
let environment = TraitEnvironment::lower(db, &self.resolver);
416-
let ty = crate::ty::InEnvironment { value: canonical, environment };
417-
crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value)
418-
}
410+
// pub fn autoderef<'a>(
411+
// &'a self,
412+
// db: &'a impl HirDatabase,
413+
// ty: Ty,
414+
// ) -> impl Iterator<Item = Ty> + 'a {
415+
// // There should be no inference vars in types passed here
416+
// // FIXME check that?
417+
// let canonical = crate::ty::Canonical { value: ty, num_vars: 0 };
418+
// let krate = self.resolver.krate();
419+
// let environment = TraitEnvironment::lower(db, &self.resolver);
420+
// let ty = crate::ty::InEnvironment { value: canonical, environment };
421+
// crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value)
422+
// }
419423

420424
/// Checks that particular type `ty` implements `std::future::Future`.
421425
/// This function is used in `.await` syntax completion.

crates/ra_hir_def/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,16 @@ impl HasModule for AdtId {
489489
}
490490
}
491491

492+
impl HasModule for DefWithBodyId {
493+
fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
494+
match self {
495+
DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
496+
DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
497+
DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
498+
}
499+
}
500+
}
501+
492502
impl HasModule for StaticLoc {
493503
fn module(&self, _db: &impl db::DefDatabase) -> ModuleId {
494504
self.container

crates/ra_ide_api/src/call_info.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
2626
);
2727
let (mut call_info, has_self) = match &calling_node {
2828
FnCallNode::CallExpr(expr) => {
29-
//FIXME: don't poke into Ty
30-
let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?;
29+
//FIXME: Type::as_callable is broken
30+
let callable_def = analyzer.type_of(db, &expr.expr()?)?.as_callable()?;
3131
match callable_def {
3232
hir::CallableDef::FunctionId(it) => {
3333
let fn_def = it.into();

0 commit comments

Comments
 (0)