let struct_ty = {
let src = InFile { file_id: ctx.frange.file_id.into(), value: strukt.clone() };
- hir::Struct::from_source(db, src).unwrap().ty(db)
+ hir::Struct::from_source(db, src)?.ty(db)
};
- let mut found_new_fn = false;
-
- let block = module.descendants().filter_map(ast::ImplBlock::cast).find(|impl_blk| {
- if found_new_fn {
- return false;
- }
-
+ let block = module.descendants().filter_map(ast::ImplBlock::cast).find_map(|impl_blk| {
let src = InFile { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
- let blk = hir::ImplBlock::from_source(db, src).unwrap();
+ let blk = hir::ImplBlock::from_source(db, src)?;
let same_ty = blk.target_ty(db) == struct_ty;
let not_trait_impl = blk.target_trait(db).is_none();
if !(same_ty && not_trait_impl) {
- return false;
+ None
+ } else {
+ Some(impl_blk)
}
-
- found_new_fn = has_new_fn(impl_blk);
- true
});
- if found_new_fn {
- None
- } else {
- Some(block)
+ if let Some(ref impl_blk) = block {
+ if has_new_fn(impl_blk) {
+ return None;
+ }
}
+
+ Some(block)
}
fn has_new_fn(imp: &ast::ImplBlock) -> bool {
if let Some(il) = imp.item_list() {
for item in il.impl_items() {
if let ast::ImplItem::FnDef(f) = item {
- if f.name().unwrap().text().eq_ignore_ascii_case("new") {
- return true;
+ if let Some(name) = f.name() {
+ if name.text().eq_ignore_ascii_case("new") {
+ return true;
+ }
}
}
}
pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> {
let root = std::env::current_dir()?.join(root);
- let ws = ProjectWorkspace::discover(root.as_ref())?;
+ let ws = ProjectWorkspace::discover(root.as_ref(), &Default::default())?;
let project_roots = ws.to_roots();
let (sender, receiver) = unbounded();
let sender = Box::new(move |t| sender.send(t).unwrap());
};
use hir_expand::{
diagnostics::DiagnosticSink,
- name::{self, AsName},
+ name::{name, AsName},
MacroDefId,
};
use hir_ty::{
}
pub fn is_self(self, db: &impl HirDatabase) -> bool {
- self.name(db) == Some(name::SELF_PARAM)
+ self.name(db) == Some(name![self])
}
pub fn is_mut(self, db: &impl HirDatabase) -> bool {
},
expr::{ExprId, PatId},
nameres::ModuleSource,
- path::known,
+ path::path,
resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs},
AssocItemId, DefWithBodyId,
};
/// Checks that particular type `ty` implements `std::future::Future`.
/// This function is used in `.await` syntax completion.
pub fn impls_future(&self, db: &impl HirDatabase, ty: Type) -> bool {
- let std_future_path = known::std_future_future();
+ let std_future_path = path![std::future::Future];
let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) {
Some(it) => it.into(),
//! representation.
use either::Either;
-use hir_expand::name::{self, AsName, Name};
+use hir_expand::name::{name, AsName, Name};
use ra_arena::Arena;
use ra_syntax::{
ast::{
let ptr = AstPtr::new(&self_param);
let param_pat = self.alloc_pat(
Pat::Bind {
- name: name::SELF_PARAM,
+ name: name![self],
mode: BindingAnnotation::Unannotated,
subpat: None,
},
use std::fmt;
-use hir_expand::name::{self, Name};
+use hir_expand::name::{name, Name};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Signedness {
impl BuiltinType {
#[rustfmt::skip]
pub const ALL: &'static [(Name, BuiltinType)] = &[
- (name::CHAR, BuiltinType::Char),
- (name::BOOL, BuiltinType::Bool),
- (name::STR, BuiltinType::Str ),
-
- (name::ISIZE, BuiltinType::Int(BuiltinInt::ISIZE)),
- (name::I8, BuiltinType::Int(BuiltinInt::I8)),
- (name::I16, BuiltinType::Int(BuiltinInt::I16)),
- (name::I32, BuiltinType::Int(BuiltinInt::I32)),
- (name::I64, BuiltinType::Int(BuiltinInt::I64)),
- (name::I128, BuiltinType::Int(BuiltinInt::I128)),
-
- (name::USIZE, BuiltinType::Int(BuiltinInt::USIZE)),
- (name::U8, BuiltinType::Int(BuiltinInt::U8)),
- (name::U16, BuiltinType::Int(BuiltinInt::U16)),
- (name::U32, BuiltinType::Int(BuiltinInt::U32)),
- (name::U64, BuiltinType::Int(BuiltinInt::U64)),
- (name::U128, BuiltinType::Int(BuiltinInt::U128)),
-
- (name::F32, BuiltinType::Float(BuiltinFloat::F32)),
- (name::F64, BuiltinType::Float(BuiltinFloat::F64)),
+ (name![char], BuiltinType::Char),
+ (name![bool], BuiltinType::Bool),
+ (name![str], BuiltinType::Str),
+
+ (name![isize], BuiltinType::Int(BuiltinInt::ISIZE)),
+ (name![i8], BuiltinType::Int(BuiltinInt::I8)),
+ (name![i16], BuiltinType::Int(BuiltinInt::I16)),
+ (name![i32], BuiltinType::Int(BuiltinInt::I32)),
+ (name![i64], BuiltinType::Int(BuiltinInt::I64)),
+ (name![i128], BuiltinType::Int(BuiltinInt::I128)),
+
+ (name![usize], BuiltinType::Int(BuiltinInt::USIZE)),
+ (name![u8], BuiltinType::Int(BuiltinInt::U8)),
+ (name![u16], BuiltinType::Int(BuiltinInt::U16)),
+ (name![u32], BuiltinType::Int(BuiltinInt::U32)),
+ (name![u64], BuiltinType::Int(BuiltinInt::U64)),
+ (name![u128], BuiltinType::Int(BuiltinInt::U128)),
+
+ (name![f32], BuiltinType::Float(BuiltinFloat::F32)),
+ (name![f64], BuiltinType::Float(BuiltinFloat::F64)),
];
}
use std::sync::Arc;
use hir_expand::{
- name::{self, AsName, Name},
+ name::{name, AsName, Name},
AstId,
};
use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
let self_type = if let Some(type_ref) = self_param.ascribed_type() {
TypeRef::from_ast(type_ref)
} else {
- let self_type = TypeRef::Path(name::SELF_TYPE.into());
+ let self_type = TypeRef::Path(name![Self].into());
match self_param.kind() {
ast::SelfParamKind::Owned => self_type,
ast::SelfParamKind::Ref => {
use either::Either;
use hir_expand::{
- name::{self, AsName, Name},
+ name::{name, AsName, Name},
InFile,
};
use ra_arena::{map::ArenaMap, Arena};
// traits get the Self type as an implicit first type parameter
let self_param_id =
- generics.types.alloc(TypeParamData { name: name::SELF_TYPE, default: None });
+ generics.types.alloc(TypeParamData { name: name![Self], default: None });
sm.insert(self_param_id, Either::Left(src.value.clone()));
// add super traits as bounds on Self
// i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
- let self_param = TypeRef::Path(name::SELF_TYPE.into());
+ let self_param = TypeRef::Path(name![Self].into());
generics.fill_bounds(&src.value, self_param);
generics.fill(&mut sm, &src.value);
use hir_expand::{
builtin_derive::find_builtin_derive,
builtin_macro::find_builtin_macro,
- name::{self, AsName, Name},
+ name::{name, AsName, Name},
HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
};
use ra_cfg::CfgOptions;
}
fn is_macro_rules(path: &Path) -> bool {
- path.as_ident() == Some(&name::MACRO_RULES)
+ path.as_ident() == Some(&name![macro_rules])
}
#[cfg(test)]
use either::Either;
use hir_expand::{
hygiene::Hygiene,
- name::{self, AsName, Name},
+ name::{name, AsName, Name},
};
use ra_db::CrateId;
use ra_syntax::{
}
}
- pub(crate) fn from_simple_segments(
- kind: PathKind,
- segments: impl IntoIterator<Item = Name>,
- ) -> Path {
+ pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> Path {
Path {
kind,
segments: segments
}
if let Some(ret_type) = ret_type {
let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
- bindings.push((name::OUTPUT_TYPE, type_ref))
+ bindings.push((name![Output], type_ref))
}
if args.is_empty() && bindings.is_empty() {
None
}
}
-pub mod known {
- use hir_expand::name;
-
- use super::{Path, PathKind};
-
- pub fn std_iter_into_iterator() -> Path {
- Path::from_simple_segments(
- PathKind::Abs,
- vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE],
- )
- }
-
- pub fn std_ops_try() -> Path {
- Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE])
- }
-
- pub fn std_ops_range() -> Path {
- Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_TYPE])
- }
-
- pub fn std_ops_range_from() -> Path {
- Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_FROM_TYPE])
- }
-
- pub fn std_ops_range_full() -> Path {
- Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_FULL_TYPE])
- }
-
- pub fn std_ops_range_inclusive() -> Path {
- Path::from_simple_segments(
- PathKind::Abs,
- vec![name::STD, name::OPS, name::RANGE_INCLUSIVE_TYPE],
- )
- }
-
- pub fn std_ops_range_to() -> Path {
- Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_TO_TYPE])
- }
-
- pub fn std_ops_range_to_inclusive() -> Path {
- Path::from_simple_segments(
- PathKind::Abs,
- vec![name::STD, name::OPS, name::RANGE_TO_INCLUSIVE_TYPE],
- )
- }
-
- pub fn std_result_result() -> Path {
- Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE])
- }
-
- pub fn std_future_future() -> Path {
- Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE])
- }
+pub use hir_expand::name as __name;
+
+#[macro_export]
+macro_rules! __known_path {
+ (std::iter::IntoIterator) => {};
+ (std::result::Result) => {};
+ (std::ops::Range) => {};
+ (std::ops::RangeFrom) => {};
+ (std::ops::RangeFull) => {};
+ (std::ops::RangeTo) => {};
+ (std::ops::RangeToInclusive) => {};
+ (std::ops::RangeInclusive) => {};
+ (std::boxed::Box) => {};
+ (std::future::Future) => {};
+ (std::ops::Try) => {};
+ (std::ops::Neg) => {};
+ (std::ops::Not) => {};
+ ($path:path) => {
+ compile_error!("Please register your known path in the path module")
+ };
+}
- pub fn std_boxed_box() -> Path {
- Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE])
- }
+#[macro_export]
+macro_rules! __path {
+ ($start:ident $(:: $seg:ident)*) => ({
+ $crate::__known_path!($start $(:: $seg)*);
+ $crate::path::Path::from_simple_segments($crate::path::PathKind::Abs, vec![
+ $crate::path::__name![$start], $($crate::path::__name![$seg],)*
+ ])
+ });
}
+
+pub use crate::__path as path;
use std::sync::Arc;
use hir_expand::{
- name::{self, Name},
+ name::{name, Name},
MacroDefId,
};
use ra_db::CrateId;
}
}
Scope::ImplBlockScope(impl_) => {
- if first_name == &name::SELF_TYPE {
+ if first_name == &name![Self] {
let idx = if path.segments.len() == 1 { None } else { Some(1) };
return Some((TypeNs::SelfType(*impl_), idx));
}
}
Scope::AdtScope(adt) => {
- if first_name == &name::SELF_TYPE {
+ if first_name == &name![Self] {
let idx = if path.segments.len() == 1 { None } else { Some(1) };
return Some((TypeNs::AdtSelfType(*adt), idx));
}
return None;
}
let n_segments = path.segments.len();
- let tmp = name::SELF_PARAM;
+ let tmp = name![self];
let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name };
let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
for scope in self.scopes.iter().rev() {
Scope::GenericParams { .. } => continue,
Scope::ImplBlockScope(impl_) if n_segments > 1 => {
- if first_name == &name::SELF_TYPE {
+ if first_name == &name![Self] {
let ty = TypeNs::SelfType(*impl_);
return Some(ResolveValueResult::Partial(ty, 1));
}
}
Scope::AdtScope(adt) if n_segments > 1 => {
- if first_name == &name::SELF_TYPE {
+ if first_name == &name![Self] {
let ty = TypeNs::AdtSelfType(*adt);
return Some(ResolveValueResult::Partial(ty, 1));
}
}
}
Scope::ImplBlockScope(i) => {
- f(name::SELF_TYPE, ScopeDef::ImplSelfType((*i).into()));
+ f(name![Self], ScopeDef::ImplSelfType((*i).into()));
}
Scope::AdtScope(i) => {
- f(name::SELF_TYPE, ScopeDef::AdtSelfType((*i).into()));
+ f(name![Self], ScopeDef::AdtSelfType((*i).into()));
}
Scope::ExprScope(scope) => {
scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| {
use crate::{name, quote, MacroCallId, MacroDefId, MacroDefKind};
macro_rules! register_builtin {
- ( $(($name:ident, $kind: ident) => $expand:ident),* ) => {
+ ( $($trait:ident => $expand:ident),* ) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuiltinDeriveExpander {
- $($kind),*
+ $($trait),*
}
impl BuiltinDeriveExpander {
tt: &tt::Subtree,
) -> Result<tt::Subtree, mbe::ExpandError> {
let expander = match *self {
- $( BuiltinDeriveExpander::$kind => $expand, )*
+ $( BuiltinDeriveExpander::$trait => $expand, )*
};
expander(db, id, tt)
}
pub fn find_builtin_derive(ident: &name::Name) -> Option<MacroDefId> {
let kind = match ident {
- $( id if id == &name::$name => BuiltinDeriveExpander::$kind, )*
+ $( id if id == &name::name![$trait] => BuiltinDeriveExpander::$trait, )*
_ => return None,
};
}
register_builtin! {
- (COPY_TRAIT, Copy) => copy_expand,
- (CLONE_TRAIT, Clone) => clone_expand,
- (DEFAULT_TRAIT, Default) => default_expand,
- (DEBUG_TRAIT, Debug) => debug_expand,
- (HASH_TRAIT, Hash) => hash_expand,
- (ORD_TRAIT, Ord) => ord_expand,
- (PARTIAL_ORD_TRAIT, PartialOrd) => partial_ord_expand,
- (EQ_TRAIT, Eq) => eq_expand,
- (PARTIAL_EQ_TRAIT, PartialEq) => partial_eq_expand
+ Copy => copy_expand,
+ Clone => clone_expand,
+ Default => default_expand,
+ Debug => debug_expand,
+ Hash => hash_expand,
+ Ord => ord_expand,
+ PartialOrd => partial_ord_expand,
+ Eq => eq_expand,
+ PartialEq => partial_eq_expand
}
struct BasicAdtInfo {
ast_id: AstId<ast::MacroCall>,
) -> Option<MacroDefId> {
let kind = match ident {
- $( id if id == &name::$name => BuiltinFnLikeExpander::$kind, )*
+ $( id if id == &name::name![$name] => BuiltinFnLikeExpander::$kind, )*
_ => return None,
};
}
register_builtin! {
- (COLUMN_MACRO, Column) => column_expand,
- (COMPILE_ERROR_MACRO, CompileError) => compile_error_expand,
- (FILE_MACRO, File) => file_expand,
- (LINE_MACRO, Line) => line_expand,
- (STRINGIFY_MACRO, Stringify) => stringify_expand,
- (FORMAT_ARGS_MACRO, FormatArgs) => format_args_expand,
+ (column, Column) => column_expand,
+ (compile_error, CompileError) => compile_error_expand,
+ (file, File) => file_expand,
+ (line, Line) => line_expand,
+ (stringify, Stringify) => stringify_expand,
+ (format_args, FormatArgs) => format_args_expand,
// format_args_nl only differs in that it adds a newline in the end,
// so we use the same stub expansion for now
- (FORMAT_ARGS_NL_MACRO, FormatArgsNl) => format_args_expand
+ (format_args_nl, FormatArgsNl) => format_args_expand
}
fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
}
}
-// Primitives
-pub const ISIZE: Name = Name::new_inline_ascii(b"isize");
-pub const I8: Name = Name::new_inline_ascii(b"i8");
-pub const I16: Name = Name::new_inline_ascii(b"i16");
-pub const I32: Name = Name::new_inline_ascii(b"i32");
-pub const I64: Name = Name::new_inline_ascii(b"i64");
-pub const I128: Name = Name::new_inline_ascii(b"i128");
-pub const USIZE: Name = Name::new_inline_ascii(b"usize");
-pub const U8: Name = Name::new_inline_ascii(b"u8");
-pub const U16: Name = Name::new_inline_ascii(b"u16");
-pub const U32: Name = Name::new_inline_ascii(b"u32");
-pub const U64: Name = Name::new_inline_ascii(b"u64");
-pub const U128: Name = Name::new_inline_ascii(b"u128");
-pub const F32: Name = Name::new_inline_ascii(b"f32");
-pub const F64: Name = Name::new_inline_ascii(b"f64");
-pub const BOOL: Name = Name::new_inline_ascii(b"bool");
-pub const CHAR: Name = Name::new_inline_ascii(b"char");
-pub const STR: Name = Name::new_inline_ascii(b"str");
-
-// Special names
-pub const SELF_PARAM: Name = Name::new_inline_ascii(b"self");
-pub const SELF_TYPE: Name = Name::new_inline_ascii(b"Self");
-pub const MACRO_RULES: Name = Name::new_inline_ascii(b"macro_rules");
-
-// Components of known path (value or mod name)
-pub const STD: Name = Name::new_inline_ascii(b"std");
-pub const ITER: Name = Name::new_inline_ascii(b"iter");
-pub const OPS: Name = Name::new_inline_ascii(b"ops");
-pub const FUTURE: Name = Name::new_inline_ascii(b"future");
-pub const RESULT: Name = Name::new_inline_ascii(b"result");
-pub const BOXED: Name = Name::new_inline_ascii(b"boxed");
-
-// Components of known path (type name)
-pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(b"IntoIterator");
-pub const ITEM_TYPE: Name = Name::new_inline_ascii(b"Item");
-pub const TRY_TYPE: Name = Name::new_inline_ascii(b"Try");
-pub const OK_TYPE: Name = Name::new_inline_ascii(b"Ok");
-pub const FUTURE_TYPE: Name = Name::new_inline_ascii(b"Future");
-pub const RESULT_TYPE: Name = Name::new_inline_ascii(b"Result");
-pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(b"Output");
-pub const TARGET_TYPE: Name = Name::new_inline_ascii(b"Target");
-pub const BOX_TYPE: Name = Name::new_inline_ascii(b"Box");
-pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(b"RangeFrom");
-pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(b"RangeFull");
-pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeInclusive");
-pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive");
-pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo");
-pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range");
-
-// Builtin Macros
-pub const FILE_MACRO: Name = Name::new_inline_ascii(b"file");
-pub const COLUMN_MACRO: Name = Name::new_inline_ascii(b"column");
-pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(b"compile_error");
-pub const LINE_MACRO: Name = Name::new_inline_ascii(b"line");
-pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(b"stringify");
-pub const FORMAT_ARGS_MACRO: Name = Name::new_inline_ascii(b"format_args");
-pub const FORMAT_ARGS_NL_MACRO: Name = Name::new_inline_ascii(b"format_args_nl");
-
-// Builtin derives
-pub const COPY_TRAIT: Name = Name::new_inline_ascii(b"Copy");
-pub const CLONE_TRAIT: Name = Name::new_inline_ascii(b"Clone");
-pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(b"Default");
-pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(b"Debug");
-pub const HASH_TRAIT: Name = Name::new_inline_ascii(b"Hash");
-pub const ORD_TRAIT: Name = Name::new_inline_ascii(b"Ord");
-pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(b"PartialOrd");
-pub const EQ_TRAIT: Name = Name::new_inline_ascii(b"Eq");
-pub const PARTIAL_EQ_TRAIT: Name = Name::new_inline_ascii(b"PartialEq");
+pub mod known {
+ macro_rules! known_names {
+ ($($ident:ident),* $(,)?) => {
+ $(
+ #[allow(bad_style)]
+ pub const $ident: super::Name =
+ super::Name::new_inline_ascii(stringify!($ident).as_bytes());
+ )*
+ };
+ }
+
+ known_names!(
+ // Primitives
+ isize,
+ i8,
+ i16,
+ i32,
+ i64,
+ i128,
+ usize,
+ u8,
+ u16,
+ u32,
+ u64,
+ u128,
+ f32,
+ f64,
+ bool,
+ char,
+ str,
+ // Special names
+ macro_rules,
+ // Components of known path (value or mod name)
+ std,
+ iter,
+ ops,
+ future,
+ result,
+ boxed,
+ // Components of known path (type name)
+ IntoIterator,
+ Item,
+ Try,
+ Ok,
+ Future,
+ Result,
+ Output,
+ Target,
+ Box,
+ RangeFrom,
+ RangeFull,
+ RangeInclusive,
+ RangeToInclusive,
+ RangeTo,
+ Range,
+ Neg,
+ Not,
+ // Builtin macros
+ file,
+ column,
+ compile_error,
+ line,
+ stringify,
+ format_args,
+ format_args_nl,
+ // Builtin derives
+ Copy,
+ Clone,
+ Default,
+ Debug,
+ Hash,
+ Ord,
+ PartialOrd,
+ Eq,
+ PartialEq,
+ );
+
+ // self/Self cannot be used as an identifier
+ pub const SELF_PARAM: super::Name = super::Name::new_inline_ascii(b"self");
+ pub const SELF_TYPE: super::Name = super::Name::new_inline_ascii(b"Self");
+
+ #[macro_export]
+ macro_rules! name {
+ (self) => {
+ $crate::name::known::SELF_PARAM
+ };
+ (Self) => {
+ $crate::name::known::SELF_TYPE
+ };
+ ($ident:ident) => {
+ $crate::name::known::$ident
+ };
+ }
+}
+
+pub use crate::name;
use std::iter::successors;
use hir_def::lang_item::LangItemTarget;
-use hir_expand::name;
+use hir_expand::name::name;
use log::{info, warn};
use ra_db::CrateId;
LangItemTarget::TraitId(it) => it,
_ => return None,
};
- let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?;
+ let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
let generic_params = generics(db, target.into());
if generic_params.len() != 1 {
use std::sync::Arc;
use hir_def::{
- path::{known, Path},
+ path::{path, Path},
resolver::HasResolver,
AdtId, FunctionId,
};
None => return,
};
- let std_result_path = known::std_result_result();
+ let std_result_path = path![std::result::Result];
let resolver = self.func.resolver(db);
let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) {
body::Body,
data::{ConstData, FunctionData},
expr::{BindingAnnotation, ExprId, PatId},
- path::{known, Path},
+ path::{path, Path},
resolver::{HasResolver, Resolver, TypeNs},
type_ref::{Mutability, TypeRef},
AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId,
};
-use hir_expand::{diagnostics::DiagnosticSink, name};
+use hir_expand::{diagnostics::DiagnosticSink, name::name};
use ra_arena::map::ArenaMap;
use ra_prof::profile;
use super::{
primitive::{FloatTy, IntTy},
traits::{Guidance, Obligation, ProjectionPredicate, Solution},
- ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
- Uncertain,
+ ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
+ TypeWalk, Uncertain,
};
use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic};
self.table.resolve_ty_shallow(ty)
}
+ fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
+ match assoc_ty {
+ Some(res_assoc_ty) => {
+ let ty = self.table.new_type_var();
+ let projection = ProjectionPredicate {
+ ty: ty.clone(),
+ projection_ty: ProjectionTy {
+ associated_ty: res_assoc_ty,
+ parameters: Substs::single(inner_ty),
+ },
+ };
+ self.obligations.push(Obligation::Projection(projection));
+ self.resolve_ty_as_possible(ty)
+ }
+ None => Ty::Unknown,
+ }
+ }
+
/// Recurses through the given type, normalizing associated types mentioned
/// in it by replacing them by type variables and registering obligations to
/// resolve later. This should be done once for every type we get from some
}
fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
- let path = known::std_iter_into_iterator();
+ let path = path![std::iter::IntoIterator];
let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
- self.db.trait_data(trait_).associated_type_by_name(&name::ITEM_TYPE)
+ self.db.trait_data(trait_).associated_type_by_name(&name![Item])
}
fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
- let path = known::std_ops_try();
+ let path = path![std::ops::Try];
+ let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
+ self.db.trait_data(trait_).associated_type_by_name(&name![Ok])
+ }
+
+ fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
+ let path = path![std::ops::Neg];
+ let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
+ self.db.trait_data(trait_).associated_type_by_name(&name![Output])
+ }
+
+ fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
+ let path = path![std::ops::Not];
let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
- self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE)
+ self.db.trait_data(trait_).associated_type_by_name(&name![Output])
}
fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
- let path = known::std_future_future();
+ let path = path![std::future::Future];
let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
- self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE)
+ self.db.trait_data(trait_).associated_type_by_name(&name![Output])
}
fn resolve_boxed_box(&self) -> Option<AdtId> {
- let path = known::std_boxed_box();
+ let path = path![std::boxed::Box];
let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
Some(struct_.into())
}
fn resolve_range_full(&self) -> Option<AdtId> {
- let path = known::std_ops_range_full();
+ let path = path![std::ops::RangeFull];
let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
Some(struct_.into())
}
fn resolve_range(&self) -> Option<AdtId> {
- let path = known::std_ops_range();
+ let path = path![std::ops::Range];
let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
Some(struct_.into())
}
fn resolve_range_inclusive(&self) -> Option<AdtId> {
- let path = known::std_ops_range_inclusive();
+ let path = path![std::ops::RangeInclusive];
let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
Some(struct_.into())
}
fn resolve_range_from(&self) -> Option<AdtId> {
- let path = known::std_ops_range_from();
+ let path = path![std::ops::RangeFrom];
let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
Some(struct_.into())
}
fn resolve_range_to(&self) -> Option<AdtId> {
- let path = known::std_ops_range_to();
+ let path = path![std::ops::RangeTo];
let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
Some(struct_.into())
}
fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
- let path = known::std_ops_range_to_inclusive();
+ let path = path![std::ops::RangeToInclusive];
let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
Some(struct_.into())
}
resolver::resolver_for_expr,
AdtId, ContainerId, Lookup, StructFieldId,
};
-use hir_expand::name::{self, Name};
+use hir_expand::name::{name, Name};
use ra_syntax::ast::RangeOp;
use crate::{
method_resolution, op,
traits::InEnvironment,
utils::{generics, variant_data, Generics},
- CallableDef, InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs,
- TraitRef, Ty, TypeCtor, TypeWalk, Uncertain,
+ ApplicationTy, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, Ty,
+ TypeCtor, TypeWalk, Uncertain,
};
use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
Expr::For { iterable, body, pat } => {
let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
- let pat_ty = match self.resolve_into_iter_item() {
- Some(into_iter_item_alias) => {
- let pat_ty = self.table.new_type_var();
- let projection = ProjectionPredicate {
- ty: pat_ty.clone(),
- projection_ty: ProjectionTy {
- associated_ty: into_iter_item_alias,
- parameters: Substs::single(iterable_ty),
- },
- };
- self.obligations.push(Obligation::Projection(projection));
- self.resolve_ty_as_possible(pat_ty)
- }
- None => Ty::Unknown,
- };
+ let pat_ty =
+ self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
self.infer_pat(*pat, &pat_ty, BindingMode::default());
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
}
Expr::Await { expr } => {
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
- let ty = match self.resolve_future_future_output() {
- Some(future_future_output_alias) => {
- let ty = self.table.new_type_var();
- let projection = ProjectionPredicate {
- ty: ty.clone(),
- projection_ty: ProjectionTy {
- associated_ty: future_future_output_alias,
- parameters: Substs::single(inner_ty),
- },
- };
- self.obligations.push(Obligation::Projection(projection));
- self.resolve_ty_as_possible(ty)
- }
- None => Ty::Unknown,
- };
+ let ty =
+ self.resolve_associated_type(inner_ty, self.resolve_future_future_output());
ty
}
Expr::Try { expr } => {
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
- let ty = match self.resolve_ops_try_ok() {
- Some(ops_try_ok_alias) => {
- let ty = self.table.new_type_var();
- let projection = ProjectionPredicate {
- ty: ty.clone(),
- projection_ty: ProjectionTy {
- associated_ty: ops_try_ok_alias,
- parameters: Substs::single(inner_ty),
- },
- };
- self.obligations.push(Obligation::Projection(projection));
- self.resolve_ty_as_possible(ty)
- }
- None => Ty::Unknown,
- };
+ let ty = self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok());
ty
}
Expr::Cast { expr, type_ref } => {
},
UnaryOp::Neg => {
match &inner_ty {
- Ty::Apply(a_ty) => match a_ty.ctor {
- TypeCtor::Int(Uncertain::Unknown)
- | TypeCtor::Int(Uncertain::Known(IntTy {
- signedness: Signedness::Signed,
- ..
- }))
- | TypeCtor::Float(..) => inner_ty,
- _ => Ty::Unknown,
- },
- Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => {
- inner_ty
- }
- // FIXME: resolve ops::Neg trait
- _ => Ty::Unknown,
+ // Fast path for builtins
+ Ty::Apply(ApplicationTy {
+ ctor:
+ TypeCtor::Int(Uncertain::Known(IntTy {
+ signedness: Signedness::Signed,
+ ..
+ })),
+ ..
+ })
+ | Ty::Apply(ApplicationTy {
+ ctor: TypeCtor::Int(Uncertain::Unknown),
+ ..
+ })
+ | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. })
+ | Ty::Infer(InferTy::IntVar(..))
+ | Ty::Infer(InferTy::FloatVar(..)) => inner_ty,
+ // Otherwise we resolve via the std::ops::Neg trait
+ _ => self
+ .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
}
}
UnaryOp::Not => {
match &inner_ty {
- Ty::Apply(a_ty) => match a_ty.ctor {
- TypeCtor::Bool | TypeCtor::Int(_) => inner_ty,
- _ => Ty::Unknown,
- },
- Ty::Infer(InferTy::IntVar(..)) => inner_ty,
- // FIXME: resolve ops::Not trait for inner_ty
- _ => Ty::Unknown,
+ // Fast path for builtins
+ Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })
+ | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(_), .. })
+ | Ty::Infer(InferTy::IntVar(..)) => inner_ty,
+ // Otherwise we resolve via the std::ops::Not trait
+ _ => self
+ .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
}
}
}
// Parent arguments are unknown, except for the receiver type
if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
for (_id, param) in parent_generics {
- if param.name == name::SELF_TYPE {
+ if param.name == name![Self] {
substs.push(receiver_ty.clone());
} else {
substs.push(Ty::Unknown);
assert_eq!("&str", type_at_pos(&db, pos));
}
+#[test]
+fn infer_ops_neg() {
+ let (db, pos) = TestDB::with_position(
+ r#"
+//- /main.rs crate:main deps:std
+
+struct Bar;
+struct Foo;
+
+impl std::ops::Neg for Bar {
+ type Output = Foo;
+}
+
+fn test() {
+ let a = Bar;
+ let b = -a;
+ b<|>;
+}
+
+//- /std.rs crate:std
+
+#[prelude_import] use ops::*;
+mod ops {
+ pub trait Neg {
+ type Output;
+ }
+}
+"#,
+ );
+ assert_eq!("Foo", type_at_pos(&db, pos));
+}
+
+#[test]
+fn infer_ops_not() {
+ let (db, pos) = TestDB::with_position(
+ r#"
+//- /main.rs crate:main deps:std
+
+struct Bar;
+struct Foo;
+
+impl std::ops::Not for Bar {
+ type Output = Foo;
+}
+
+fn test() {
+ let a = Bar;
+ let b = !a;
+ b<|>;
+}
+
+//- /std.rs crate:std
+
+#[prelude_import] use ops::*;
+mod ops {
+ pub trait Not {
+ type Output;
+ }
+}
+"#,
+ );
+ assert_eq!("Foo", type_at_pos(&db, pos));
+}
+
#[test]
fn infer_from_bound_1() {
assert_snapshot!(
//! This module provides the built-in trait implementations, e.g. to make
//! closures implement `Fn`.
use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId};
-use hir_expand::name;
+use hir_expand::name::name;
use ra_db::CrateId;
use super::{AssocTyValue, Impl};
// and don't want to return a valid value only to find out later that FnOnce
// is broken
let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
- let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?;
+ let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
let num_args: u16 = match &db.body(data.def.into())[data.expr] {
Expr::Lambda { args, .. } => args.len() as u16,
let output_ty_id = db
.trait_data(fn_once_trait)
- .associated_type_by_name(&name::OUTPUT_TYPE)
+ .associated_type_by_name(&name![Output])
.expect("assoc ty value should not exist");
BuiltinImplAssocTyValueData {
type_ref::TypeRef,
ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
};
-use hir_expand::name::{self, Name};
+use hir_expand::name::{name, Name};
-// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`.
-// We should return a `TraitREf` here.
fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
let resolver = trait_.resolver(db);
// returning the iterator directly doesn't easily work because of
.where_predicates
.iter()
.filter_map(|pred| match &pred.type_ref {
- TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(),
+ TypeRef::Path(p) if p.as_ident() == Some(&name![Self]) => pred.bound.as_path(),
_ => None,
})
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
use rustc_hash::FxHashMap;
+use ra_project_model::CargoFeatures;
use serde::{Deserialize, Deserializer};
/// Client provided initialization options
/// Fine grained feature flags to disable specific features.
pub feature_flags: FxHashMap<String, bool>,
+
+ /// Cargo feature configurations.
+ pub cargo_features: CargoFeatures,
}
impl Default for ServerConfig {
max_inlay_hint_length: None,
with_sysroot: true,
feature_flags: FxHashMap::default(),
+ cargo_features: Default::default(),
}
}
}
deprecated: Some(self.deprecated()),
..Default::default()
};
+
+ if self.deprecated() {
+ res.tags = Some(vec![lsp_types::CompletionItemTag::Deprecated])
+ }
+
res.insert_text_format = Some(match self.insert_text_format() {
InsertTextFormat::Snippet => lsp_types::InsertTextFormat::Snippet,
InsertTextFormat::PlainText => lsp_types::InsertTextFormat::PlainText,
let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot(
ws_root.as_path(),
config.with_sysroot,
+ &config.cargo_features,
);
match workspace {
Ok(workspace) => loaded_workspaces.push(workspace),
use ra_arena::{impl_arena_id, Arena, RawId};
use ra_db::Edition;
use rustc_hash::FxHashMap;
+use serde::Deserialize;
use crate::Result;
pub(crate) workspace_root: PathBuf,
}
+#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Default)]
+#[serde(rename_all = "camelCase", default)]
+pub struct CargoFeatures {
+ /// Do not activate the `default` feature.
+ pub no_default_features: bool,
+
+ /// Activate all available features
+ pub all_features: bool,
+
+ /// List of features to activate.
+ /// This will be ignored if `cargo_all_features` is true.
+ pub features: Vec<String>,
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Package(RawId);
impl_arena_id!(Package);
}
impl CargoWorkspace {
- pub fn from_cargo_metadata(cargo_toml: &Path) -> Result<CargoWorkspace> {
+ pub fn from_cargo_metadata(
+ cargo_toml: &Path,
+ cargo_features: &CargoFeatures,
+ ) -> Result<CargoWorkspace> {
let mut meta = MetadataCommand::new();
- meta.manifest_path(cargo_toml).features(CargoOpt::AllFeatures);
+ meta.manifest_path(cargo_toml);
+ if cargo_features.all_features {
+ meta.features(CargoOpt::AllFeatures);
+ } else if cargo_features.no_default_features {
+ // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
+ // https://github.com/oli-obk/cargo_metadata/issues/79
+ meta.features(CargoOpt::NoDefaultFeatures);
+ } else {
+ meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
+ }
if let Some(parent) = cargo_toml.parent() {
meta.current_dir(parent);
}
use serde_json::from_reader;
pub use crate::{
- cargo_workspace::{CargoWorkspace, Package, Target, TargetKind},
+ cargo_workspace::{CargoFeatures, CargoWorkspace, Package, Target, TargetKind},
json_project::JsonProject,
sysroot::Sysroot,
};
}
impl ProjectWorkspace {
- pub fn discover(path: &Path) -> Result<ProjectWorkspace> {
- ProjectWorkspace::discover_with_sysroot(path, true)
+ pub fn discover(path: &Path, cargo_features: &CargoFeatures) -> Result<ProjectWorkspace> {
+ ProjectWorkspace::discover_with_sysroot(path, true, cargo_features)
}
- pub fn discover_with_sysroot(path: &Path, with_sysroot: bool) -> Result<ProjectWorkspace> {
+ pub fn discover_with_sysroot(
+ path: &Path,
+ with_sysroot: bool,
+ cargo_features: &CargoFeatures,
+ ) -> Result<ProjectWorkspace> {
match find_rust_project_json(path) {
Some(json_path) => {
let file = File::open(json_path)?;
}
None => {
let cargo_toml = find_cargo_toml(path)?;
- let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?;
+ let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features)?;
let sysroot =
if with_sysroot { Sysroot::discover(&cargo_toml)? } else { Sysroot::default() };
Ok(ProjectWorkspace::Cargo { cargo, sysroot })
"type": "number",
"default": 20,
"description": "Maximum length for inlay hints"
+ },
+ "rust-analyzer.cargoFeatures.noDefaultFeatures": {
+ "type": "boolean",
+ "default": false,
+ "description": "Do not activate the `default` feature"
+ },
+ "rust-analyzer.cargoFeatures.allFeatures": {
+ "type": "boolean",
+ "default": true,
+ "description": "Activate all available features"
+ },
+ "rust-analyzer.cargoFeatures.features": {
+ "type": "array",
+ "default": [],
+ "description": "List of features to activate"
}
}
},
ignore: string[];
}
+export interface CargoFeatures {
+ noDefaultFeatures: boolean;
+ allFeatures: boolean;
+ features: string[];
+}
+
export class Config {
public highlightingOn = true;
public rainbowHighlightingOn = false;
command: '',
ignore: [],
};
+ public cargoFeatures: CargoFeatures = {
+ noDefaultFeatures: false,
+ allFeatures: true,
+ features: [],
+ };
private prevEnhancedTyping: null | boolean = null;
+ private prevCargoFeatures: null | CargoFeatures = null;
constructor() {
vscode.workspace.onDidChangeConfiguration(_ =>
public userConfigChanged() {
const config = vscode.workspace.getConfiguration('rust-analyzer');
+ let requireReloadMessage = null;
+
if (config.has('highlightingOn')) {
this.highlightingOn = config.get('highlightingOn') as boolean;
}
}
if (this.prevEnhancedTyping !== this.enableEnhancedTyping) {
- const reloadAction = 'Reload now';
- vscode.window
- .showInformationMessage(
- 'Changing enhanced typing setting requires a reload',
- reloadAction,
- )
- .then(selectedAction => {
- if (selectedAction === reloadAction) {
- vscode.commands.executeCommand(
- 'workbench.action.reloadWindow',
- );
- }
- });
+ requireReloadMessage =
+ 'Changing enhanced typing setting requires a reload';
this.prevEnhancedTyping = this.enableEnhancedTyping;
}
if (config.has('withSysroot')) {
this.withSysroot = config.get('withSysroot') || false;
}
+
+ if (config.has('cargoFeatures.noDefaultFeatures')) {
+ this.cargoFeatures.noDefaultFeatures = config.get(
+ 'cargoFeatures.noDefaultFeatures',
+ false,
+ );
+ }
+ if (config.has('cargoFeatures.allFeatures')) {
+ this.cargoFeatures.allFeatures = config.get(
+ 'cargoFeatures.allFeatures',
+ true,
+ );
+ }
+ if (config.has('cargoFeatures.features')) {
+ this.cargoFeatures.features = config.get(
+ 'cargoFeatures.features',
+ [],
+ );
+ }
+
+ if (
+ this.prevCargoFeatures !== null &&
+ (this.cargoFeatures.allFeatures !==
+ this.prevCargoFeatures.allFeatures ||
+ this.cargoFeatures.noDefaultFeatures !==
+ this.prevCargoFeatures.noDefaultFeatures ||
+ this.cargoFeatures.features.length !==
+ this.prevCargoFeatures.features.length ||
+ this.cargoFeatures.features.some(
+ (v, i) => v !== this.prevCargoFeatures!.features[i],
+ ))
+ ) {
+ requireReloadMessage = 'Changing cargo features requires a reload';
+ }
+ this.prevCargoFeatures = { ...this.cargoFeatures };
+
+ if (requireReloadMessage !== null) {
+ const reloadAction = 'Reload now';
+ vscode.window
+ .showInformationMessage(requireReloadMessage, reloadAction)
+ .then(selectedAction => {
+ if (selectedAction === reloadAction) {
+ vscode.commands.executeCommand(
+ 'workbench.action.reloadWindow',
+ );
+ }
+ });
+ }
}
}
useClientWatching: Server.config.useClientWatching,
featureFlags: Server.config.featureFlags,
withSysroot: Server.config.withSysroot,
+ cargoFeatures: Server.config.cargoFeatures,
},
traceOutputChannel,
};