Merge #1352
1352: Builtins r=matklad a=matklad closes #1340 Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
3cf841e1bc
21 changed files with 261 additions and 118 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1084,6 +1084,7 @@ dependencies = [
|
|||
"insta 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"once_cell 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ra_arena 0.1.0",
|
||||
"ra_db 0.1.0",
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ parking_lot = "0.8.0"
|
|||
ena = "0.11"
|
||||
join_to_string = "0.1.3"
|
||||
either = "1.5.2"
|
||||
once_cell = "0.2"
|
||||
|
||||
ra_syntax = { path = "../ra_syntax" }
|
||||
ra_arena = { path = "../ra_arena" }
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ use ra_db::{CrateId, SourceRootId, Edition, FileId};
|
|||
use ra_syntax::{ast::{self, NameOwner, TypeAscriptionOwner}, TreeArc};
|
||||
|
||||
use crate::{
|
||||
Name, AsName, AstId, Ty, HirFileId, Either,
|
||||
Name, AsName, AstId, Ty, HirFileId, Either, KnownName,
|
||||
HirDatabase, DefDatabase,
|
||||
type_ref::TypeRef,
|
||||
nameres::{ModuleScope, Namespace, ImportId, CrateModuleId},
|
||||
expr::{Body, BodySourceMap, validation::ExprValidator},
|
||||
ty::{TraitRef, InferenceResult},
|
||||
ty::{TraitRef, InferenceResult, primitive::{IntTy, FloatTy, Signedness, IntBitness, FloatBitness}},
|
||||
adt::{EnumVariantId, StructFieldId, VariantDef},
|
||||
generics::HasGenericParams,
|
||||
docs::{Documentation, Docs, docs_from_ast},
|
||||
|
|
@ -75,6 +75,41 @@ pub struct Module {
|
|||
pub(crate) module_id: CrateModuleId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum BuiltinType {
|
||||
Char,
|
||||
Bool,
|
||||
Str,
|
||||
Int(IntTy),
|
||||
Float(FloatTy),
|
||||
}
|
||||
|
||||
impl BuiltinType {
|
||||
#[rustfmt::skip]
|
||||
pub(crate) const ALL: &'static [(KnownName, BuiltinType)] = &[
|
||||
(KnownName::Char, BuiltinType::Char),
|
||||
(KnownName::Bool, BuiltinType::Bool),
|
||||
(KnownName::Str, BuiltinType::Str),
|
||||
|
||||
(KnownName::Isize, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::Xsize })),
|
||||
(KnownName::I8, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X8 })),
|
||||
(KnownName::I16, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X16 })),
|
||||
(KnownName::I32, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X32 })),
|
||||
(KnownName::I64, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X64 })),
|
||||
(KnownName::I128, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X128 })),
|
||||
|
||||
(KnownName::Usize, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize })),
|
||||
(KnownName::U8, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X8 })),
|
||||
(KnownName::U16, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X16 })),
|
||||
(KnownName::U32, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X32 })),
|
||||
(KnownName::U64, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X64 })),
|
||||
(KnownName::U128, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X128 })),
|
||||
|
||||
(KnownName::F32, BuiltinType::Float(FloatTy { bitness: FloatBitness::X32 })),
|
||||
(KnownName::F64, BuiltinType::Float(FloatTy { bitness: FloatBitness::X64 })),
|
||||
];
|
||||
}
|
||||
|
||||
/// The defs which can be visible in the module.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ModuleDef {
|
||||
|
|
@ -89,6 +124,7 @@ pub enum ModuleDef {
|
|||
Static(Static),
|
||||
Trait(Trait),
|
||||
TypeAlias(TypeAlias),
|
||||
BuiltinType(BuiltinType),
|
||||
}
|
||||
impl_froms!(
|
||||
ModuleDef: Module,
|
||||
|
|
@ -100,7 +136,8 @@ impl_froms!(
|
|||
Const,
|
||||
Static,
|
||||
Trait,
|
||||
TypeAlias
|
||||
TypeAlias,
|
||||
BuiltinType
|
||||
);
|
||||
|
||||
pub enum ModuleSource {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
//! applied. So, the relation between syntax and HIR is many-to-one.
|
||||
|
||||
macro_rules! impl_froms {
|
||||
($e:ident: $($v:ident), *) => {
|
||||
($e:ident: $($v:ident),*) => {
|
||||
$(
|
||||
impl From<$v> for $e {
|
||||
fn from(it: $v) -> $e {
|
||||
|
|
@ -80,5 +80,6 @@ pub use self::code_model::{
|
|||
Function, FnSignature,
|
||||
StructField, FieldSource,
|
||||
Static, Const, ConstSignature,
|
||||
Trait, TypeAlias, MacroDef, Container
|
||||
Trait, TypeAlias, MacroDef, Container,
|
||||
BuiltinType,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ impl AsName for ra_db::Dependency {
|
|||
// const ISIZE: Name = Name::new("isize")
|
||||
// ```
|
||||
// but const-fn is not that powerful yet.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum KnownName {
|
||||
Isize,
|
||||
I8,
|
||||
|
|
@ -151,3 +151,31 @@ pub(crate) enum KnownName {
|
|||
|
||||
MacroRules,
|
||||
}
|
||||
|
||||
impl AsName for KnownName {
|
||||
fn as_name(&self) -> Name {
|
||||
let s = match self {
|
||||
KnownName::Isize => "isize",
|
||||
KnownName::I8 => "i8",
|
||||
KnownName::I16 => "i16",
|
||||
KnownName::I32 => "i32",
|
||||
KnownName::I64 => "i64",
|
||||
KnownName::I128 => "i128",
|
||||
KnownName::Usize => "usize",
|
||||
KnownName::U8 => "u8",
|
||||
KnownName::U16 => "u16",
|
||||
KnownName::U32 => "u32",
|
||||
KnownName::U64 => "u64",
|
||||
KnownName::U128 => "u128",
|
||||
KnownName::F32 => "f32",
|
||||
KnownName::F64 => "f64",
|
||||
KnownName::Bool => "bool",
|
||||
KnownName::Char => "char",
|
||||
KnownName::Str => "str",
|
||||
KnownName::SelfType => "Self",
|
||||
KnownName::SelfParam => "self",
|
||||
KnownName::MacroRules => "macro_rules",
|
||||
};
|
||||
Name::new(s.into())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,9 +62,10 @@ use ra_db::{FileId, Edition};
|
|||
use test_utils::tested_by;
|
||||
use ra_syntax::ast;
|
||||
use ra_prof::profile;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::{
|
||||
ModuleDef, Name, Crate, Module, MacroDef,
|
||||
ModuleDef, Name, Crate, Module, MacroDef, AsName, BuiltinType,
|
||||
DefDatabase, Path, PathKind, HirFileId, Trait,
|
||||
ids::MacroDefId,
|
||||
diagnostics::DiagnosticSink,
|
||||
|
|
@ -140,12 +141,22 @@ pub struct ModuleScope {
|
|||
macros: FxHashMap<Name, MacroDef>,
|
||||
}
|
||||
|
||||
static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
|
||||
BuiltinType::ALL
|
||||
.iter()
|
||||
.map(|&(known_name, ty)| {
|
||||
(known_name.as_name(), Resolution { def: PerNs::types(ty.into()), import: None })
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
impl ModuleScope {
|
||||
pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
|
||||
self.items.iter()
|
||||
//FIXME: shadowing
|
||||
self.items.iter().chain(BUILTIN_SCOPE.iter())
|
||||
}
|
||||
pub fn get(&self, name: &Name) -> Option<&Resolution> {
|
||||
self.items.get(name)
|
||||
self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
|
||||
}
|
||||
pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
|
||||
self.items.values().filter_map(|r| match r.def.take_types() {
|
||||
|
|
@ -154,7 +165,7 @@ impl ModuleScope {
|
|||
})
|
||||
}
|
||||
fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> {
|
||||
match (self.items.get(name), self.macros.get(name)) {
|
||||
match (self.get(name), self.macros.get(name)) {
|
||||
(Some(item), _) if !item.def.is_none() => Some(Either::Left(item.def)),
|
||||
(_, Some(macro_)) => Some(Either::Right(*macro_)),
|
||||
_ => None,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
mod macros;
|
||||
mod globs;
|
||||
mod incremental;
|
||||
mod primitives;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
|
|||
let events = db.log_executed(|| {
|
||||
let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap();
|
||||
let decls = module.declarations(&db);
|
||||
assert_eq!(decls.len(), 1);
|
||||
assert_eq!(decls.len(), 18);
|
||||
});
|
||||
assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
|
||||
}
|
||||
|
|
@ -126,7 +126,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
|
|||
let events = db.log_executed(|| {
|
||||
let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap();
|
||||
let decls = module.declarations(&db);
|
||||
assert_eq!(decls.len(), 1);
|
||||
assert_eq!(decls.len(), 18);
|
||||
});
|
||||
assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
|
||||
}
|
||||
|
|
|
|||
24
crates/ra_hir/src/nameres/tests/primitives.rs
Normal file
24
crates/ra_hir/src/nameres/tests/primitives.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn primitive_reexport() {
|
||||
let map = def_map(
|
||||
"
|
||||
//- /lib.rs
|
||||
mod foo;
|
||||
use foo::int;
|
||||
|
||||
//- /foo.rs
|
||||
pub use i32 as int;
|
||||
",
|
||||
);
|
||||
assert_snapshot_matches!(map, @r###"
|
||||
⋮crate
|
||||
⋮foo: t
|
||||
⋮int: t
|
||||
⋮
|
||||
⋮crate::foo
|
||||
⋮int: t
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
|
@ -649,7 +649,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
| TypableDef::Function(_)
|
||||
| TypableDef::Enum(_)
|
||||
| TypableDef::Const(_)
|
||||
| TypableDef::Static(_) => (Ty::Unknown, None),
|
||||
| TypableDef::Static(_)
|
||||
| TypableDef::BuiltinType(_) => (Ty::Unknown, None),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,8 @@ use std::iter;
|
|||
|
||||
use crate::{
|
||||
Function, Struct, Union, StructField, Enum, EnumVariant, Path, ModuleDef, TypeAlias, Const, Static,
|
||||
HirDatabase,
|
||||
HirDatabase, BuiltinType,
|
||||
type_ref::TypeRef,
|
||||
name::KnownName,
|
||||
nameres::Namespace,
|
||||
resolve::{Resolver, Resolution},
|
||||
path::{PathSegment, GenericArg},
|
||||
|
|
@ -22,7 +21,7 @@ use crate::{
|
|||
generics::{WherePredicate, GenericDef},
|
||||
ty::AdtDef,
|
||||
};
|
||||
use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef, GenericPredicate};
|
||||
use super::{Ty, FnSig, Substs, TypeCtor, TraitRef, GenericPredicate};
|
||||
|
||||
impl Ty {
|
||||
pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self {
|
||||
|
|
@ -65,22 +64,6 @@ impl Ty {
|
|||
}
|
||||
|
||||
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self {
|
||||
if let Some(name) = path.as_ident() {
|
||||
// FIXME handle primitive type names in resolver as well?
|
||||
if let Some(int_ty) = primitive::IntTy::from_type_name(name) {
|
||||
return Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known(int_ty)));
|
||||
} else if let Some(float_ty) = primitive::FloatTy::from_type_name(name) {
|
||||
return Ty::simple(TypeCtor::Float(primitive::UncertainFloatTy::Known(float_ty)));
|
||||
} else if let Some(known) = name.as_known_name() {
|
||||
match known {
|
||||
KnownName::Bool => return Ty::simple(TypeCtor::Bool),
|
||||
KnownName::Char => return Ty::simple(TypeCtor::Char),
|
||||
KnownName::Str => return Ty::simple(TypeCtor::Str),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the path (in type namespace)
|
||||
let resolution = resolver.resolve_path(db, path).take_types();
|
||||
|
||||
|
|
@ -128,7 +111,7 @@ impl Ty {
|
|||
TypableDef::Enum(e) => Some(e.into()),
|
||||
TypableDef::EnumVariant(var) => Some(var.parent_enum(db).into()),
|
||||
TypableDef::TypeAlias(t) => Some(t.into()),
|
||||
TypableDef::Const(_) | TypableDef::Static(_) => None,
|
||||
TypableDef::Const(_) | TypableDef::Static(_) | TypableDef::BuiltinType(_) => None,
|
||||
};
|
||||
substs_from_path_segment(db, resolver, segment, def_generic, false)
|
||||
}
|
||||
|
|
@ -149,7 +132,8 @@ impl Ty {
|
|||
| TypableDef::Enum(_)
|
||||
| TypableDef::Const(_)
|
||||
| TypableDef::Static(_)
|
||||
| TypableDef::TypeAlias(_) => last,
|
||||
| TypableDef::TypeAlias(_)
|
||||
| TypableDef::BuiltinType(_) => last,
|
||||
TypableDef::EnumVariant(_) => {
|
||||
// the generic args for an enum variant may be either specified
|
||||
// on the segment referring to the enum, or on the segment
|
||||
|
|
@ -299,6 +283,7 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace
|
|||
(TypableDef::TypeAlias(t), Namespace::Types) => type_for_type_alias(db, t),
|
||||
(TypableDef::Const(c), Namespace::Values) => type_for_const(db, c),
|
||||
(TypableDef::Static(c), Namespace::Values) => type_for_static(db, c),
|
||||
(TypableDef::BuiltinType(t), Namespace::Types) => type_for_builtin(t),
|
||||
|
||||
// 'error' cases:
|
||||
(TypableDef::Function(_), Namespace::Types) => Ty::Unknown,
|
||||
|
|
@ -308,6 +293,7 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace
|
|||
(TypableDef::TypeAlias(_), Namespace::Values) => Ty::Unknown,
|
||||
(TypableDef::Const(_), Namespace::Types) => Ty::Unknown,
|
||||
(TypableDef::Static(_), Namespace::Types) => Ty::Unknown,
|
||||
(TypableDef::BuiltinType(_), Namespace::Values) => Ty::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -399,6 +385,17 @@ fn type_for_static(db: &impl HirDatabase, def: Static) -> Ty {
|
|||
Ty::from_hir(db, &resolver, signature.type_ref())
|
||||
}
|
||||
|
||||
/// Build the declared type of a static.
|
||||
fn type_for_builtin(def: BuiltinType) -> Ty {
|
||||
Ty::simple(match def {
|
||||
BuiltinType::Char => TypeCtor::Char,
|
||||
BuiltinType::Bool => TypeCtor::Bool,
|
||||
BuiltinType::Str => TypeCtor::Str,
|
||||
BuiltinType::Int(ty) => TypeCtor::Int(ty.into()),
|
||||
BuiltinType::Float(ty) => TypeCtor::Float(ty.into()),
|
||||
})
|
||||
}
|
||||
|
||||
fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
|
||||
let var_data = def.variant_data(db);
|
||||
let fields = match var_data.fields() {
|
||||
|
|
@ -477,8 +474,19 @@ pub enum TypableDef {
|
|||
TypeAlias(TypeAlias),
|
||||
Const(Const),
|
||||
Static(Static),
|
||||
BuiltinType(BuiltinType),
|
||||
}
|
||||
impl_froms!(TypableDef: Function, Struct, Union, Enum, EnumVariant, TypeAlias, Const, Static);
|
||||
impl_froms!(
|
||||
TypableDef: Function,
|
||||
Struct,
|
||||
Union,
|
||||
Enum,
|
||||
EnumVariant,
|
||||
TypeAlias,
|
||||
Const,
|
||||
Static,
|
||||
BuiltinType
|
||||
);
|
||||
|
||||
impl From<ModuleDef> for Option<TypableDef> {
|
||||
fn from(def: ModuleDef) -> Option<TypableDef> {
|
||||
|
|
@ -491,6 +499,7 @@ impl From<ModuleDef> for Option<TypableDef> {
|
|||
ModuleDef::TypeAlias(t) => t.into(),
|
||||
ModuleDef::Const(v) => v.into(),
|
||||
ModuleDef::Static(v) => v.into(),
|
||||
ModuleDef::BuiltinType(t) => t.into(),
|
||||
ModuleDef::Module(_) | ModuleDef::Trait(_) => return None,
|
||||
};
|
||||
Some(res)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use std::fmt;
|
||||
|
||||
use crate::{Name, KnownName};
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Signedness {
|
||||
Signed,
|
||||
|
|
@ -30,6 +28,12 @@ pub enum UncertainIntTy {
|
|||
Known(IntTy),
|
||||
}
|
||||
|
||||
impl From<IntTy> for UncertainIntTy {
|
||||
fn from(ty: IntTy) -> Self {
|
||||
UncertainIntTy::Known(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for UncertainIntTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
|
@ -45,6 +49,12 @@ pub enum UncertainFloatTy {
|
|||
Known(FloatTy),
|
||||
}
|
||||
|
||||
impl From<FloatTy> for UncertainFloatTy {
|
||||
fn from(ty: FloatTy) -> Self {
|
||||
UncertainFloatTy::Known(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for UncertainFloatTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
|
@ -138,24 +148,6 @@ impl IntTy {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_type_name(name: &Name) -> Option<IntTy> {
|
||||
match name.as_known_name()? {
|
||||
KnownName::Isize => Some(IntTy::isize()),
|
||||
KnownName::I8 => Some(IntTy::i8()),
|
||||
KnownName::I16 => Some(IntTy::i16()),
|
||||
KnownName::I32 => Some(IntTy::i32()),
|
||||
KnownName::I64 => Some(IntTy::i64()),
|
||||
KnownName::I128 => Some(IntTy::i128()),
|
||||
KnownName::Usize => Some(IntTy::usize()),
|
||||
KnownName::U8 => Some(IntTy::u8()),
|
||||
KnownName::U16 => Some(IntTy::u16()),
|
||||
KnownName::U32 => Some(IntTy::u32()),
|
||||
KnownName::U64 => Some(IntTy::u64()),
|
||||
KnownName::U128 => Some(IntTy::u128()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_suffix(suffix: &str) -> Option<IntTy> {
|
||||
match suffix {
|
||||
"isize" => Some(IntTy::isize()),
|
||||
|
|
@ -208,14 +200,6 @@ impl FloatTy {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_type_name(name: &Name) -> Option<FloatTy> {
|
||||
match name.as_known_name()? {
|
||||
KnownName::F32 => Some(FloatTy::f32()),
|
||||
KnownName::F64 => Some(FloatTy::f64()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_suffix(suffix: &str) -> Option<FloatTy> {
|
||||
match suffix {
|
||||
"f32" => Some(FloatTy::f32()),
|
||||
|
|
|
|||
|
|
@ -2717,6 +2717,24 @@ fn test() { (S {}).method()<|>; }
|
|||
assert_eq!(t, "{unknown}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shadowing_primitive() {
|
||||
let t = type_at(
|
||||
r#"
|
||||
//- /main.rs
|
||||
struct i32;
|
||||
struct Foo;
|
||||
|
||||
impl i32 { fn foo(&self) -> Foo { Foo } }
|
||||
|
||||
fn main() {
|
||||
let x: i32 = i32;
|
||||
x.foo()<|>;
|
||||
}"#,
|
||||
);
|
||||
assert_eq!(t, "Foo");
|
||||
}
|
||||
|
||||
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
||||
let file = db.parse(pos.file_id).ok().unwrap();
|
||||
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
|
|||
hir::ModuleDef::Module(module) => {
|
||||
let module_scope = module.scope(ctx.db);
|
||||
for (name, res) in module_scope.entries() {
|
||||
if let Some(hir::ModuleDef::BuiltinType(..)) = res.def.as_ref().take_types() {
|
||||
if ctx.use_item_syntax.is_some() {
|
||||
tested_by!(dont_complete_primitive_in_use);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if Some(module) == ctx.module {
|
||||
if let Some(import) = res.import {
|
||||
if let Either::A(use_tree) = module.import_source(ctx.db, import) {
|
||||
|
|
@ -88,6 +94,20 @@ mod tests {
|
|||
assert_eq!(completions.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dont_complete_primitive_in_use() {
|
||||
covers!(dont_complete_primitive_in_use);
|
||||
let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType);
|
||||
assert!(completions.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_primitives() {
|
||||
let completions =
|
||||
do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType);
|
||||
assert_eq!(completions.len(), 17);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_mod_with_docs() {
|
||||
check_reference_completion(
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ pub enum CompletionItemKind {
|
|||
Keyword,
|
||||
Module,
|
||||
Function,
|
||||
BuiltinType,
|
||||
Struct,
|
||||
Enum,
|
||||
EnumVariant,
|
||||
|
|
@ -102,6 +103,7 @@ pub(crate) enum CompletionKind {
|
|||
Magic,
|
||||
Snippet,
|
||||
Postfix,
|
||||
BuiltinType,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ impl Completions {
|
|||
}
|
||||
Some(it) => it,
|
||||
};
|
||||
let mut completion_kind = CompletionKind::Reference;
|
||||
let (kind, docs) = match def {
|
||||
Resolution::Def(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)),
|
||||
Resolution::Def(Function(func)) => {
|
||||
|
|
@ -70,6 +71,10 @@ impl Completions {
|
|||
Resolution::Def(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)),
|
||||
Resolution::Def(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)),
|
||||
Resolution::Def(TypeAlias(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
|
||||
Resolution::Def(BuiltinType(..)) => {
|
||||
completion_kind = CompletionKind::BuiltinType;
|
||||
(CompletionItemKind::BuiltinType, None)
|
||||
}
|
||||
Resolution::GenericParam(..) => (CompletionItemKind::TypeParam, None),
|
||||
Resolution::LocalBinding(..) => (CompletionItemKind::Binding, None),
|
||||
Resolution::SelfType(..) => (
|
||||
|
|
@ -77,7 +82,7 @@ impl Completions {
|
|||
None,
|
||||
),
|
||||
};
|
||||
CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name)
|
||||
CompletionItem::new(completion_kind, ctx.source_range(), local_name)
|
||||
.kind(kind)
|
||||
.set_documentation(docs)
|
||||
.add_to(self)
|
||||
|
|
|
|||
|
|
@ -165,8 +165,11 @@ impl NavigationTarget {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_def(db: &RootDatabase, module_def: hir::ModuleDef) -> NavigationTarget {
|
||||
match module_def {
|
||||
pub(crate) fn from_def(
|
||||
db: &RootDatabase,
|
||||
module_def: hir::ModuleDef,
|
||||
) -> Option<NavigationTarget> {
|
||||
let nav = match module_def {
|
||||
hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module),
|
||||
hir::ModuleDef::Function(func) => NavigationTarget::from_function(db, func),
|
||||
hir::ModuleDef::Struct(s) => {
|
||||
|
|
@ -201,7 +204,11 @@ impl NavigationTarget {
|
|||
let (file_id, node) = e.source(db);
|
||||
NavigationTarget::from_named(file_id.original_file(db), &*node)
|
||||
}
|
||||
}
|
||||
hir::ModuleDef::BuiltinType(..) => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
Some(nav)
|
||||
}
|
||||
|
||||
pub(crate) fn from_impl_block(
|
||||
|
|
|
|||
|
|
@ -62,7 +62,10 @@ pub(crate) fn reference_definition(
|
|||
Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)),
|
||||
Some(FieldAccess(field)) => return Exact(NavigationTarget::from_field(db, field)),
|
||||
Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_impl_item(db, assoc)),
|
||||
Some(Def(def)) => return Exact(NavigationTarget::from_def(db, def)),
|
||||
Some(Def(def)) => match NavigationTarget::from_def(db, def) {
|
||||
Some(nav) => return Exact(nav),
|
||||
None => return Approximate(vec![]),
|
||||
},
|
||||
Some(SelfType(ty)) => {
|
||||
if let Some((def_id, _)) = ty.as_adt() {
|
||||
return Exact(NavigationTarget::from_adt_def(db, def_id));
|
||||
|
|
|
|||
|
|
@ -6,4 +6,5 @@ test_utils::marks!(
|
|||
goto_definition_works_for_named_fields
|
||||
call_info_bad_offset
|
||||
dont_complete_current_use
|
||||
dont_complete_primitive_in_use
|
||||
);
|
||||
|
|
|
|||
|
|
@ -30,14 +30,6 @@ fn is_control_keyword(kind: SyntaxKind) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_prim_type(node: &ast::NameRef) -> bool {
|
||||
match node.text().as_str() {
|
||||
"u8" | "i8" | "u16" | "i16" | "u32" | "i32" | "u64" | "i64" | "u128" | "i128" | "usize"
|
||||
| "isize" | "f32" | "f64" | "bool" | "char" | "str" => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
|
||||
let _p = profile("highlight");
|
||||
let source_file = db.parse(file_id).tree;
|
||||
|
|
@ -71,51 +63,47 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
|
|||
NAME_REF => {
|
||||
if let Some(name_ref) = node.as_node().and_then(ast::NameRef::cast) {
|
||||
// FIXME: revisit this after #1340
|
||||
if is_prim_type(name_ref) {
|
||||
"type"
|
||||
} else {
|
||||
use crate::name_ref_kind::{classify_name_ref, NameRefKind::*};
|
||||
use hir::{ModuleDef, ImplItem};
|
||||
use crate::name_ref_kind::{classify_name_ref, NameRefKind::*};
|
||||
use hir::{ModuleDef, ImplItem};
|
||||
|
||||
// FIXME: try to reuse the SourceAnalyzers
|
||||
let analyzer =
|
||||
hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
|
||||
match classify_name_ref(db, &analyzer, name_ref) {
|
||||
Some(Method(_)) => "function",
|
||||
Some(Macro(_)) => "macro",
|
||||
Some(FieldAccess(_)) => "field",
|
||||
Some(AssocItem(ImplItem::Method(_))) => "function",
|
||||
Some(AssocItem(ImplItem::Const(_))) => "constant",
|
||||
Some(AssocItem(ImplItem::TypeAlias(_))) => "type",
|
||||
Some(Def(ModuleDef::Module(_))) => "module",
|
||||
Some(Def(ModuleDef::Function(_))) => "function",
|
||||
Some(Def(ModuleDef::Struct(_))) => "type",
|
||||
Some(Def(ModuleDef::Union(_))) => "type",
|
||||
Some(Def(ModuleDef::Enum(_))) => "type",
|
||||
Some(Def(ModuleDef::EnumVariant(_))) => "constant",
|
||||
Some(Def(ModuleDef::Const(_))) => "constant",
|
||||
Some(Def(ModuleDef::Static(_))) => "constant",
|
||||
Some(Def(ModuleDef::Trait(_))) => "type",
|
||||
Some(Def(ModuleDef::TypeAlias(_))) => "type",
|
||||
Some(SelfType(_)) => "type",
|
||||
Some(Pat(ptr)) => {
|
||||
binding_hash = Some({
|
||||
let text = ptr
|
||||
.syntax_node_ptr()
|
||||
.to_node(&source_file.syntax())
|
||||
.text()
|
||||
.to_smol_string();
|
||||
let shadow_count =
|
||||
bindings_shadow_count.entry(text.clone()).or_default();
|
||||
calc_binding_hash(file_id, &text, *shadow_count)
|
||||
});
|
||||
// FIXME: try to reuse the SourceAnalyzers
|
||||
let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
|
||||
match classify_name_ref(db, &analyzer, name_ref) {
|
||||
Some(Method(_)) => "function",
|
||||
Some(Macro(_)) => "macro",
|
||||
Some(FieldAccess(_)) => "field",
|
||||
Some(AssocItem(ImplItem::Method(_))) => "function",
|
||||
Some(AssocItem(ImplItem::Const(_))) => "constant",
|
||||
Some(AssocItem(ImplItem::TypeAlias(_))) => "type",
|
||||
Some(Def(ModuleDef::Module(_))) => "module",
|
||||
Some(Def(ModuleDef::Function(_))) => "function",
|
||||
Some(Def(ModuleDef::Struct(_))) => "type",
|
||||
Some(Def(ModuleDef::Union(_))) => "type",
|
||||
Some(Def(ModuleDef::Enum(_))) => "type",
|
||||
Some(Def(ModuleDef::EnumVariant(_))) => "constant",
|
||||
Some(Def(ModuleDef::Const(_))) => "constant",
|
||||
Some(Def(ModuleDef::Static(_))) => "constant",
|
||||
Some(Def(ModuleDef::Trait(_))) => "type",
|
||||
Some(Def(ModuleDef::TypeAlias(_))) => "type",
|
||||
Some(Def(ModuleDef::BuiltinType(_))) => "type",
|
||||
Some(SelfType(_)) => "type",
|
||||
Some(Pat(ptr)) => {
|
||||
binding_hash = Some({
|
||||
let text = ptr
|
||||
.syntax_node_ptr()
|
||||
.to_node(&source_file.syntax())
|
||||
.text()
|
||||
.to_smol_string();
|
||||
let shadow_count =
|
||||
bindings_shadow_count.entry(text.clone()).or_default();
|
||||
calc_binding_hash(file_id, &text, *shadow_count)
|
||||
});
|
||||
|
||||
"variable"
|
||||
}
|
||||
Some(SelfParam(_)) => "type",
|
||||
Some(GenericParam(_)) => "type",
|
||||
None => "text",
|
||||
"variable"
|
||||
}
|
||||
Some(SelfParam(_)) => "type",
|
||||
Some(GenericParam(_)) => "type",
|
||||
None => "text",
|
||||
}
|
||||
} else {
|
||||
"text"
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ impl Conv for CompletionItemKind {
|
|||
CompletionItemKind::Struct => Struct,
|
||||
CompletionItemKind::Enum => Enum,
|
||||
CompletionItemKind::EnumVariant => EnumMember,
|
||||
CompletionItemKind::BuiltinType => Struct,
|
||||
CompletionItemKind::Binding => Variable,
|
||||
CompletionItemKind::Field => Field,
|
||||
CompletionItemKind::Trait => Interface,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue