From e5eadb339039e21718d382c0b3d02a4bf053b3f4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 26 Nov 2019 14:02:57 +0300 Subject: Introduce hir::Type It should provide a convenient API over more low-level Ty --- crates/ra_assists/src/assists/add_explicit_type.rs | 13 +- crates/ra_assists/src/assists/fill_match_arms.rs | 7 +- crates/ra_hir/src/code_model.rs | 166 ++++++++++++++++++++- crates/ra_hir/src/lib.rs | 2 +- crates/ra_hir/src/source_binder.rs | 46 +++--- crates/ra_hir_def/src/lib.rs | 10 ++ crates/ra_ide_api/src/call_info.rs | 4 +- crates/ra_ide_api/src/completion/complete_dot.rs | 36 ++--- .../ra_ide_api/src/completion/complete_postfix.rs | 16 +- .../src/completion/complete_record_literal.rs | 7 +- .../src/completion/complete_record_pattern.rs | 7 +- crates/ra_ide_api/src/completion/presentation.rs | 39 ++--- crates/ra_ide_api/src/goto_type_definition.rs | 4 +- crates/ra_ide_api/src/inlay_hints.rs | 23 +-- crates/ra_ide_api/src/syntax_highlighting.rs | 9 +- 15 files changed, 253 insertions(+), 136 deletions(-) diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index 562a09685..eeb4ff39f 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs @@ -1,4 +1,4 @@ -use hir::{db::HirDatabase, HirDisplay, Ty}; +use hir::{db::HirDatabase, HirDisplay}; use ra_syntax::{ ast::{self, AstNode, LetStmt, NameOwner}, T, @@ -43,7 +43,7 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option) -> Option bool { - match ty { - Ty::Unknown => true, - Ty::Apply(a_ty) => a_ty.parameters.iter().any(is_unknown), - _ => false, - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index 8482897c5..b75bd44eb 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs @@ -83,10 +83,11 @@ fn resolve_enum_def( ) -> Option { let expr_ty = analyzer.type_of(db, &expr)?; - analyzer.autoderef(db, expr_ty).find_map(|ty| match ty.as_adt() { - Some((Adt::Enum(e), _)) => Some(e.source(db).value), + let res = expr_ty.autoderef(db).find_map(|ty| match ty.as_adt() { + Some(Adt::Enum(e)) => Some(e.source(db).value), _ => None, - }) + }); + res } fn build_pat(var: ast::EnumVariant) -> Option { diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index f7fc80d4e..a7bba85e1 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -10,9 +10,9 @@ use hir_def::{ docs::Documentation, per_ns::PerNs, resolver::{HasResolver, TypeNs}, - type_ref::TypeRef, - AstItemDef, ConstId, ContainerId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, - LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, + type_ref::{Mutability, TypeRef}, + AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, + ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, }; use hir_expand::{ @@ -26,8 +26,12 @@ use ra_syntax::{ast, AstNode, SyntaxNode}; use crate::{ db::{DefDatabase, HirDatabase}, expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, - ty::{InferenceResult, Namespace, TraitRef}, - Either, Name, Source, Ty, + ty::display::HirFormatter, + ty::{ + self, InEnvironment, InferenceResult, Namespace, TraitEnvironment, TraitRef, Ty, TypeCtor, + TypeWalk, + }, + CallableDef, Either, HirDisplay, Name, Source, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -469,6 +473,10 @@ pub enum Adt { impl_froms!(Adt: Struct, Union, Enum); impl Adt { + pub fn has_non_default_type_params(self, db: &impl HirDatabase) -> bool { + let subst = db.generic_defaults(self.into()); + subst.iter().any(|ty| ty == &Ty::Unknown) + } pub fn ty(self, db: &impl HirDatabase) -> Ty { match self { Adt::Struct(it) => it.ty(db), @@ -777,6 +785,11 @@ pub struct TypeAlias { } impl TypeAlias { + pub fn has_non_default_type_params(self, db: &impl HirDatabase) -> bool { + let subst = db.generic_defaults(self.id.into()); + subst.iter().any(|ty| ty == &Ty::Unknown) + } + pub fn module(self, db: &impl DefDatabase) -> Module { Module { id: self.id.lookup(db).module(db) } } @@ -927,9 +940,14 @@ impl Local { self.parent.module(db) } - pub fn ty(self, db: &impl HirDatabase) -> Ty { + pub fn ty(self, db: &impl HirDatabase) -> Type { let infer = db.infer(self.parent); - infer[self.pat_id].clone() + let ty = infer[self.pat_id].clone(); + let def = DefWithBodyId::from(self.parent); + let resolver = def.resolver(db); + let krate = def.module(db).krate; + let environment = TraitEnvironment::lower(db, &resolver); + Type { krate, ty: InEnvironment { value: ty, environment } } } pub fn source(self, db: &impl HirDatabase) -> Source> { @@ -986,6 +1004,140 @@ impl ImplBlock { } } +#[derive(Clone, PartialEq, Eq)] +pub struct Type { + pub(crate) krate: CrateId, + pub(crate) ty: InEnvironment, +} + +impl Type { + pub fn is_bool(&self) -> bool { + match &self.ty.value { + Ty::Apply(a_ty) => match a_ty.ctor { + TypeCtor::Bool => true, + _ => false, + }, + _ => false, + } + } + + pub fn is_mutable_reference(&self) -> bool { + match &self.ty.value { + Ty::Apply(a_ty) => match a_ty.ctor { + TypeCtor::Ref(Mutability::Mut) => true, + _ => false, + }, + _ => false, + } + } + + pub fn is_unknown(&self) -> bool { + match &self.ty.value { + Ty::Unknown => true, + _ => false, + } + } + + // FIXME: this method is broken, as it doesn't take closures into account. + pub fn as_callable(&self) -> Option { + Some(self.ty.value.as_callable()?.0) + } + + pub fn contains_unknown(&self) -> bool { + return go(&self.ty.value); + + fn go(ty: &Ty) -> bool { + match ty { + Ty::Unknown => true, + Ty::Apply(a_ty) => a_ty.parameters.iter().any(go), + _ => false, + } + } + } + + pub fn fields(&self, db: &impl HirDatabase) -> Vec<(StructField, Type)> { + let mut res = Vec::new(); + if let Ty::Apply(a_ty) = &self.ty.value { + match a_ty.ctor { + ty::TypeCtor::Adt(Adt::Struct(s)) => { + for field in s.fields(db) { + let ty = field.ty(db).subst(&a_ty.parameters); + res.push((field, self.derived(ty))); + } + } + _ => {} + } + }; + res + } + + pub fn tuple_fields(&self, _db: &impl HirDatabase) -> Vec { + let mut res = Vec::new(); + if let Ty::Apply(a_ty) = &self.ty.value { + match a_ty.ctor { + ty::TypeCtor::Tuple { .. } => { + for ty in a_ty.parameters.iter() { + let ty = ty.clone().subst(&a_ty.parameters); + res.push(self.derived(ty)); + } + } + _ => {} + } + }; + res + } + + pub fn variant_fields( + &self, + db: &impl HirDatabase, + def: VariantDef, + ) -> Vec<(StructField, Type)> { + // FIXME: check that ty and def match + match &self.ty.value { + Ty::Apply(a_ty) => def + .fields(db) + .into_iter() + .map(|it| (it, self.derived(it.ty(db).subst(&a_ty.parameters)))) + .collect(), + _ => Vec::new(), + } + } + + pub fn autoderef<'a>(&'a self, db: &'a impl HirDatabase) -> impl Iterator + 'a { + // There should be no inference vars in types passed here + // FIXME check that? + let canonical = crate::ty::Canonical { value: self.ty.value.clone(), num_vars: 0 }; + let environment = self.ty.environment.clone(); + let ty = InEnvironment { value: canonical, environment: environment.clone() }; + ty::autoderef(db, Some(self.krate), ty) + .map(|canonical| canonical.value) + .map(move |ty| self.derived(ty)) + } + + // FIXME: remove + pub fn into_ty(self) -> Ty { + self.ty.value + } + + pub fn as_adt(&self) -> Option { + let (adt, _subst) = self.ty.value.as_adt()?; + Some(adt) + } + + fn derived(&self, ty: Ty) -> Type { + Type { + krate: self.krate, + ty: InEnvironment { value: ty, environment: self.ty.environment.clone() }, + } + } +} + +impl HirDisplay for Type { + fn hir_fmt(&self, f: &mut HirFormatter) -> std::fmt::Result { + self.ty.value.hir_fmt(f) + } +} + /// For IDE only pub enum ScopeDef { ModuleDef(ModuleDef), diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 843ce6a88..b88e4c745 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -51,7 +51,7 @@ pub use crate::{ src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, GenericParam, HasAttrs, ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef, - Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, + Static, Struct, StructField, Trait, Type, TypeAlias, Union, VariantDef, }, expr::ExprScopes, from_source::FromSource, diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index cbfeca3ab..95a94c3f0 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -28,10 +28,10 @@ use crate::{ expr::{BodySourceMap, ExprScopes, ScopeId}, ty::{ method_resolution::{self, implements_trait}, - TraitEnvironment, + InEnvironment, TraitEnvironment, Ty, }, Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function, - GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Ty, TypeAlias, + GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, }; fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option { @@ -198,14 +198,18 @@ impl SourceAnalyzer { self.body_source_map.as_ref()?.node_pat(src) } - pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option { + pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option { let expr_id = self.expr_id(expr)?; - Some(self.infer.as_ref()?[expr_id].clone()) + let ty = self.infer.as_ref()?[expr_id].clone(); + let environment = TraitEnvironment::lower(db, &self.resolver); + Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) } - pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option { + pub fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option { let pat_id = self.pat_id(pat)?; - Some(self.infer.as_ref()?[pat_id].clone()) + let ty = self.infer.as_ref()?[pat_id].clone(); + let environment = TraitEnvironment::lower(db, &self.resolver); + Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) } pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { @@ -361,14 +365,14 @@ impl SourceAnalyzer { pub fn iterate_method_candidates( &self, db: &impl HirDatabase, - ty: Ty, + ty: &Type, name: Option<&Name>, mut callback: impl FnMut(&Ty, Function) -> Option, ) -> Option { // There should be no inference vars in types passed here // FIXME check that? // FIXME replace Unknown by bound vars here - let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; + let canonical = crate::ty::Canonical { value: ty.ty.value.clone(), num_vars: 0 }; method_resolution::iterate_method_candidates( &canonical, db, @@ -403,19 +407,19 @@ impl SourceAnalyzer { ) } - pub fn autoderef<'a>( - &'a self, - db: &'a impl HirDatabase, - ty: Ty, - ) -> impl Iterator + 'a { - // There should be no inference vars in types passed here - // FIXME check that? - let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; - let krate = self.resolver.krate(); - let environment = TraitEnvironment::lower(db, &self.resolver); - let ty = crate::ty::InEnvironment { value: canonical, environment }; - crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value) - } + // pub fn autoderef<'a>( + // &'a self, + // db: &'a impl HirDatabase, + // ty: Ty, + // ) -> impl Iterator + 'a { + // // There should be no inference vars in types passed here + // // FIXME check that? + // let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; + // let krate = self.resolver.krate(); + // let environment = TraitEnvironment::lower(db, &self.resolver); + // let ty = crate::ty::InEnvironment { value: canonical, environment }; + // crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value) + // } /// Checks that particular type `ty` implements `std::future::Future`. /// This function is used in `.await` syntax completion. diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index a88a78b38..274dd1467 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -489,6 +489,16 @@ impl HasModule for AdtId { } } +impl HasModule for DefWithBodyId { + fn module(&self, db: &impl db::DefDatabase) -> ModuleId { + match self { + DefWithBodyId::FunctionId(it) => it.lookup(db).module(db), + DefWithBodyId::StaticId(it) => it.lookup(db).module(db), + DefWithBodyId::ConstId(it) => it.lookup(db).module(db), + } + } +} + impl HasModule for StaticLoc { fn module(&self, _db: &impl db::DefDatabase) -> ModuleId { self.container diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 9beceb29c..d0283e410 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -26,8 +26,8 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { - //FIXME: don't poke into Ty - let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; + //FIXME: Type::as_callable is broken + let callable_def = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; match callable_def { hir::CallableDef::FunctionId(it) => { let fn_def = it.into(); diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 5a3f9b5f6..b6fe48627 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -1,6 +1,6 @@ //! FIXME: write short doc here -use hir::{Adt, Ty, TypeCtor}; +use hir::Type; use crate::completion::completion_item::CompletionKind; use crate::{ @@ -22,12 +22,12 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { }; if !ctx.is_call { - complete_fields(acc, ctx, receiver_ty.clone()); + complete_fields(acc, ctx, &receiver_ty); } - complete_methods(acc, ctx, receiver_ty.clone()); + complete_methods(acc, ctx, &receiver_ty); // Suggest .await syntax for types that implement Future trait - if ctx.analyzer.impls_future(ctx.db, receiver_ty) { + if ctx.analyzer.impls_future(ctx.db, receiver_ty.into_ty()) { CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") .detail("expr.await") .insert_text("await") @@ -35,28 +35,18 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { } } -fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { - for receiver in ctx.analyzer.autoderef(ctx.db, receiver) { - if let Ty::Apply(a_ty) = receiver { - match a_ty.ctor { - TypeCtor::Adt(Adt::Struct(s)) => { - for field in s.fields(ctx.db) { - acc.add_field(ctx, field, &a_ty.parameters); - } - } - // FIXME unions - TypeCtor::Tuple { .. } => { - for (i, ty) in a_ty.parameters.iter().enumerate() { - acc.add_tuple_field(ctx, i, ty); - } - } - _ => {} - } - }; +fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { + for receiver in receiver.autoderef(ctx.db) { + for (field, ty) in receiver.fields(ctx.db) { + acc.add_field(ctx, field, &ty); + } + for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { + acc.add_tuple_field(ctx, i, &ty); + } } } -fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { +fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { let mut seen_methods = FxHashSet::default(); ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| { if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) { diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs index 17b75cf7e..646a30c76 100644 --- a/crates/ra_ide_api/src/completion/complete_postfix.rs +++ b/crates/ra_ide_api/src/completion/complete_postfix.rs @@ -1,6 +1,5 @@ //! FIXME: write short doc here -use hir::{Ty, TypeCtor}; use ra_syntax::{ast::AstNode, TextRange, TextUnit}; use ra_text_edit::TextEdit; @@ -30,9 +29,12 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { dot_receiver.syntax().text().to_string() }; - let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); + let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) { + Some(it) => it, + None => return, + }; - if is_bool_or_unknown(receiver_ty) { + if receiver_ty.is_bool() || receiver_ty.is_unknown() { postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) .add_to(acc); postfix_snippet( @@ -75,14 +77,6 @@ fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: .snippet_edit(edit) } -fn is_bool_or_unknown(ty: Option) -> bool { - match &ty { - Some(Ty::Apply(app)) if app.ctor == TypeCtor::Bool => true, - Some(Ty::Unknown) | None => true, - Some(_) => false, - } -} - #[cfg(test)] mod tests { use insta::assert_debug_snapshot; diff --git a/crates/ra_ide_api/src/completion/complete_record_literal.rs b/crates/ra_ide_api/src/completion/complete_record_literal.rs index 45a4a9738..577c394d2 100644 --- a/crates/ra_ide_api/src/completion/complete_record_literal.rs +++ b/crates/ra_ide_api/src/completion/complete_record_literal.rs @@ -1,7 +1,5 @@ //! FIXME: write short doc here -use hir::Substs; - use crate::completion::{CompletionContext, Completions}; /// Complete fields in fields literals. @@ -15,10 +13,9 @@ pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionCon Some(it) => it, _ => return, }; - let substs = &ty.substs().unwrap_or_else(Substs::empty); - for field in variant.fields(ctx.db) { - acc.add_field(ctx, field, substs); + for (field, field_ty) in ty.variant_fields(ctx.db, variant) { + acc.add_field(ctx, field, &field_ty); } } diff --git a/crates/ra_ide_api/src/completion/complete_record_pattern.rs b/crates/ra_ide_api/src/completion/complete_record_pattern.rs index aa0fd6d24..a56c7e3a1 100644 --- a/crates/ra_ide_api/src/completion/complete_record_pattern.rs +++ b/crates/ra_ide_api/src/completion/complete_record_pattern.rs @@ -1,7 +1,5 @@ //! FIXME: write short doc here -use hir::Substs; - use crate::completion::{CompletionContext, Completions}; pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionContext) { @@ -14,10 +12,9 @@ pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionCon Some(it) => it, _ => return, }; - let substs = &ty.substs().unwrap_or_else(Substs::empty); - for field in variant.fields(ctx.db) { - acc.add_field(ctx, field, substs); + for (field, field_ty) in ty.variant_fields(ctx.db, variant) { + acc.add_field(ctx, field, &field_ty); } } diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index 85b053a6e..5f056730a 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs @@ -1,12 +1,12 @@ //! This modules takes care of rendering various definitions as completion items. -use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; +use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, Type}; use join_to_string::join; use ra_syntax::ast::NameOwner; use test_utils::tested_by; use crate::completion::{ - db, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, + CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, }; use crate::display::{const_label, function_label, macro_label, type_label}; @@ -16,7 +16,7 @@ impl Completions { &mut self, ctx: &CompletionContext, field: hir::StructField, - substs: &hir::Substs, + ty: &Type, ) { let is_deprecated = is_deprecated(field, ctx.db); CompletionItem::new( @@ -25,13 +25,13 @@ impl Completions { field.name(ctx.db).to_string(), ) .kind(CompletionItemKind::Field) - .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string()) + .detail(ty.display(ctx.db).to_string()) .set_documentation(field.docs(ctx.db)) .set_deprecated(is_deprecated) .add_to(self); } - pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) { + pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string()) .kind(CompletionItemKind::Field) .detail(ty.display(ctx.db).to_string()) @@ -98,7 +98,7 @@ impl Completions { CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone()); if let ScopeDef::Local(local) = resolution { let ty = local.ty(ctx.db); - if ty != Ty::Unknown { + if !ty.is_unknown() { completion_item = completion_item.detail(ty.display(ctx.db).to_string()); } }; @@ -108,19 +108,17 @@ impl Completions { && !ctx.has_type_args && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") { - let generic_def: Option = match resolution { - ScopeDef::ModuleDef(Adt(it)) => Some((*it).into()), - ScopeDef::ModuleDef(TypeAlias(it)) => Some((*it).into()), - _ => None, + let has_non_default_type_params = match resolution { + ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), + ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), + _ => false, }; - if let Some(def) = generic_def { - if has_non_default_type_params(def, ctx.db) { - tested_by!(inserts_angle_brackets_for_generics); - completion_item = completion_item - .lookup_by(local_name.clone()) - .label(format!("{}<…>", local_name)) - .insert_snippet(format!("{}<$0>", local_name)); - } + if has_non_default_type_params { + tested_by!(inserts_angle_brackets_for_generics); + completion_item = completion_item + .lookup_by(local_name.clone()) + .label(format!("{}<…>", local_name)) + .insert_snippet(format!("{}<$0>", local_name)); } } @@ -291,11 +289,6 @@ fn is_deprecated(node: impl HasAttrs, db: &impl HirDatabase) -> bool { node.attrs(db).by_key("deprecated").exists() } -fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { - let subst = db.generic_defaults(def.into()); - subst.iter().any(|ty| ty == &Ty::Unknown) -} - #[cfg(test)] mod tests { use insta::assert_debug_snapshot; diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs index 28a83a3e2..992a08809 100644 --- a/crates/ra_ide_api/src/goto_type_definition.rs +++ b/crates/ra_ide_api/src/goto_type_definition.rs @@ -24,7 +24,7 @@ pub(crate) fn goto_type_definition( let analyzer = hir::SourceAnalyzer::new(db, token.with_value(&node), None); - let ty: hir::Ty = if let Some(ty) = + let ty: hir::Type = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e)) { ty @@ -35,7 +35,7 @@ pub(crate) fn goto_type_definition( return None; }; - let adt_def = analyzer.autoderef(db, ty).find_map(|ty| ty.as_adt().map(|adt| adt.0))?; + let adt_def = ty.autoderef(db).find_map(|ty| ty.as_adt())?; let nav = adt_def.to_nav(db); Some(RangeInfo::new(node.text_range(), vec![nav])) diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs index 24a7ca5e7..45149bf0c 100644 --- a/crates/ra_ide_api/src/inlay_hints.rs +++ b/crates/ra_ide_api/src/inlay_hints.rs @@ -1,7 +1,7 @@ //! FIXME: write short doc here use crate::{db::RootDatabase, FileId}; -use hir::{HirDisplay, SourceAnalyzer, Ty}; +use hir::{HirDisplay, SourceAnalyzer}; use ra_syntax::{ ast::{self, AstNode, TypeAscriptionOwner}, match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, @@ -100,8 +100,11 @@ fn get_pat_type_hints( .into_iter() .filter(|pat| !skip_root_pat_hint || pat != original_pat) .filter_map(|pat| { - get_node_displayable_type(db, &analyzer, &pat) - .map(|pat_type| (pat.syntax().text_range(), pat_type)) + let ty = analyzer.type_of_pat(db, &pat)?; + if ty.is_unknown() { + return None; + } + Some((pat.syntax().text_range(), ty)) }) .map(|(range, pat_type)| InlayHint { range, @@ -158,20 +161,6 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec { leaf_pats } -fn get_node_displayable_type( - db: &RootDatabase, - analyzer: &SourceAnalyzer, - node_pat: &ast::Pat, -) -> Option { - analyzer.type_of_pat(db, node_pat).and_then(|resolved_type| { - if let Ty::Apply(_) = resolved_type { - Some(resolved_type) - } else { - None - } - }) -} - #[cfg(test)] mod tests { use crate::mock_analysis::single_file; diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 2b653fe8f..10165a9bb 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -2,7 +2,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; -use hir::{Mutability, Name, Source}; +use hir::{Name, Source}; use ra_db::SourceDatabase; use ra_prof::profile; use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; @@ -230,11 +230,10 @@ fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str { Local(local) => { if local.is_mut(db) { "variable.mut" + } else if local.ty(db).is_mutable_reference() { + "variable.mut" } else { - match local.ty(db).as_reference() { - Some((_, Mutability::Mut)) => "variable.mut", - _ => "variable", - } + "variable" } } } -- cgit v1.2.3