summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir')
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs72
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs159
4 files changed, 240 insertions, 33 deletions
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 6c6c11ea4..5edc16d8b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -14,6 +14,7 @@ use crate::{MacroKind, Type};
macro_rules! diagnostics {
($($diag:ident,)*) => {
+ #[derive(Debug)]
pub enum AnyDiagnostic {$(
$diag(Box<$diag>),
)*}
@@ -123,6 +124,7 @@ pub struct NoSuchField {
#[derive(Debug)]
pub struct BreakOutsideOfLoop {
pub expr: InFile<AstPtr<ast::Expr>>,
+ pub is_break: bool,
}
#[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 8f984210e..e4bb63a86 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -72,7 +72,7 @@ use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind;
use once_cell::unsync::Lazy;
use rustc_hash::FxHashSet;
-use stdx::{format_to, impl_from, never};
+use stdx::{impl_from, never};
use syntax::{
ast::{self, HasAttrs as _, HasDocComments, HasName},
AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
@@ -511,6 +511,7 @@ impl Module {
.collect()
}
+ /// Fills `acc` with the module's diagnostics.
pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
let _p = profile::span("Module::diagnostics").detail(|| {
format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
@@ -531,11 +532,21 @@ impl Module {
m.diagnostics(db, acc)
}
}
+ ModuleDef::Trait(t) => {
+ for diag in db.trait_data_with_diagnostics(t.id).1.iter() {
+ emit_def_diagnostic(db, acc, diag);
+ }
+ acc.extend(decl.diagnostics(db))
+ }
_ => acc.extend(decl.diagnostics(db)),
}
}
for impl_def in self.impl_defs(db) {
+ for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
+ emit_def_diagnostic(db, acc, diag);
+ }
+
for item in impl_def.items(db) {
let def: DefWithBody = match item {
AssocItem::Function(it) => it.into(),
@@ -1136,6 +1147,20 @@ impl DefWithBody {
}
}
+ fn id(&self) -> DefWithBodyId {
+ match self {
+ DefWithBody::Function(it) => it.id.into(),
+ DefWithBody::Static(it) => it.id.into(),
+ DefWithBody::Const(it) => it.id.into(),
+ }
+ }
+
+ /// A textual representation of the HIR of this def's body for debugging purposes.
+ pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
+ let body = db.body(self.id());
+ body.pretty_print(db.upcast(), self.id())
+ }
+
pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
let krate = self.module(db).id.krate();
@@ -1191,11 +1216,11 @@ impl DefWithBody {
let field = source_map.field_syntax(*expr);
acc.push(NoSuchField { field }.into())
}
- hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
+ &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
let expr = source_map
- .expr_syntax(*expr)
+ .expr_syntax(expr)
.expect("break outside of loop in synthetic syntax");
- acc.push(BreakOutsideOfLoop { expr }.into())
+ acc.push(BreakOutsideOfLoop { expr, is_break }.into())
}
hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
match source_map.expr_syntax(*call_expr) {
@@ -1470,19 +1495,6 @@ impl Function {
let def_map = db.crate_def_map(loc.krate(db).into());
def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
}
-
- /// A textual representation of the HIR of this function for debugging purposes.
- pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
- let body = db.body(self.id.into());
-
- let mut result = String::new();
- format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db));
- for (id, expr) in body.exprs.iter() {
- format_to!(result, "{:?}: {:?}\n", id, expr);
- }
-
- result
- }
}
// Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
@@ -2777,20 +2789,32 @@ impl Type {
self.ty.is_unknown()
}
- /// Checks that particular type `ty` implements `std::future::Future`.
+ /// Checks that particular type `ty` implements `std::future::IntoFuture` or
+ /// `std::future::Future`.
/// This function is used in `.await` syntax completion.
- pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
- let std_future_trait = db
- .lang_item(self.env.krate, SmolStr::new_inline("future_trait"))
- .and_then(|it| it.as_trait());
- let std_future_trait = match std_future_trait {
+ pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool {
+ let trait_ = db
+ .lang_item(self.env.krate, SmolStr::new_inline("into_future"))
+ .and_then(|it| {
+ let into_future_fn = it.as_function()?;
+ let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?;
+ let into_future_trait = assoc_item.containing_trait_or_trait_impl(db)?;
+ Some(into_future_trait.id)
+ })
+ .or_else(|| {
+ let future_trait =
+ db.lang_item(self.env.krate, SmolStr::new_inline("future_trait"))?;
+ future_trait.as_trait()
+ });
+
+ let trait_ = match trait_ {
Some(it) => it,
None => return false,
};
let canonical_ty =
Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
- method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), std_future_trait)
+ method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), trait_)
}
/// Checks that particular type `ty` implements `std::ops::FnOnce`.
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index c84318b2f..416b6f580 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -357,6 +357,26 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.resolve_method_call(call).map(Function::from)
}
+ pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
+ self.imp.resolve_await_to_poll(await_expr).map(Function::from)
+ }
+
+ pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
+ self.imp.resolve_prefix_expr(prefix_expr).map(Function::from)
+ }
+
+ pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
+ self.imp.resolve_index_expr(index_expr).map(Function::from)
+ }
+
+ pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
+ self.imp.resolve_bin_expr(bin_expr).map(Function::from)
+ }
+
+ pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
+ self.imp.resolve_try_expr(try_expr).map(Function::from)
+ }
+
pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
self.imp.resolve_method_call_as_callable(call)
}
@@ -1066,6 +1086,26 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(call.syntax())?.resolve_method_call(self.db, call)
}
+ fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
+ self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
+ }
+
+ fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<FunctionId> {
+ self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr)
+ }
+
+ fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<FunctionId> {
+ self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr)
+ }
+
+ fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<FunctionId> {
+ self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr)
+ }
+
+ fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<FunctionId> {
+ self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
+ }
+
fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
}
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 1eb51b20c..342912b67 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -25,15 +25,21 @@ use hir_def::{
Lookup, ModuleDefId, VariantId,
};
use hir_expand::{
- builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name::AsName, HirFileId, InFile,
+ builtin_fn_macro::BuiltinFnLikeExpander,
+ hygiene::Hygiene,
+ mod_path::path,
+ name,
+ name::{AsName, Name},
+ HirFileId, InFile,
};
use hir_ty::{
diagnostics::{
record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
UnsafeExpr,
},
- method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution,
- TyExt, TyKind, TyLoweringContext,
+ method_resolution::{self, lang_names_for_bin_op},
+ Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
+ TyLoweringContext,
};
use itertools::Itertools;
use smallvec::SmallVec;
@@ -134,11 +140,19 @@ impl SourceAnalyzer {
) -> Option<InFile<ast::Expr>> {
let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
let expanded = db.parse_or_expand(macro_file)?;
-
- let res = match ast::MacroCall::cast(expanded.clone()) {
- Some(call) => self.expand_expr(db, InFile::new(macro_file, call))?,
- _ => InFile::new(macro_file, ast::Expr::cast(expanded)?),
+ let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
+ match stmts.expr()? {
+ ast::Expr::MacroExpr(mac) => {
+ self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))?
+ }
+ expr => InFile::new(macro_file, expr),
+ }
+ } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) {
+ self.expand_expr(db, InFile::new(macro_file, call))?
+ } else {
+ InFile::new(macro_file, ast::Expr::cast(expanded)?)
};
+
Some(res)
}
@@ -255,8 +269,111 @@ impl SourceAnalyzer {
) -> Option<FunctionId> {
let expr_id = self.expr_id(db, &call.clone().into())?;
let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
- let f_in_impl = self.resolve_impl_method(db, f_in_trait, &substs);
- f_in_impl.or(Some(f_in_trait))
+
+ Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs))
+ }
+
+ pub(crate) fn resolve_await_to_poll(
+ &self,
+ db: &dyn HirDatabase,
+ await_expr: &ast::AwaitExpr,
+ ) -> Option<FunctionId> {
+ let mut ty = self.ty_of_expr(db, &await_expr.expr()?.into())?.clone();
+
+ let into_future_trait = self
+ .resolver
+ .resolve_known_trait(db.upcast(), &path![core::future::IntoFuture])
+ .map(Trait::from);
+
+ if let Some(into_future_trait) = into_future_trait {
+ let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone());
+ if type_.impls_trait(db, into_future_trait, &[]) {
+ let items = into_future_trait.items(db);
+ let into_future_type = items.into_iter().find_map(|item| match item {
+ AssocItem::TypeAlias(alias)
+ if alias.name(db) == hir_expand::name![IntoFuture] =>
+ {
+ Some(alias)
+ }
+ _ => None,
+ })?;
+ let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?;
+ ty = future_trait.ty;
+ }
+ }
+
+ let poll_fn = db
+ .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
+ .as_function()?;
+ let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
+ Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
+ }
+
+ pub(crate) fn resolve_prefix_expr(
+ &self,
+ db: &dyn HirDatabase,
+ prefix_expr: &ast::PrefixExpr,
+ ) -> Option<FunctionId> {
+ let lang_item_name = match prefix_expr.op_kind()? {
+ ast::UnaryOp::Deref => name![deref],
+ ast::UnaryOp::Not => name![not],
+ ast::UnaryOp::Neg => name![neg],
+ };
+ let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
+
+ let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ }
+
+ pub(crate) fn resolve_index_expr(
+ &self,
+ db: &dyn HirDatabase,
+ index_expr: &ast::IndexExpr,
+ ) -> Option<FunctionId> {
+ let base_ty = self.ty_of_expr(db, &index_expr.base()?.into())?;
+ let index_ty = self.ty_of_expr(db, &index_expr.index()?.into())?;
+
+ let lang_item_name = name![index];
+
+ let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
+ .push(base_ty.clone())
+ .push(index_ty.clone())
+ .build();
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ }
+
+ pub(crate) fn resolve_bin_expr(
+ &self,
+ db: &dyn HirDatabase,
+ binop_expr: &ast::BinExpr,
+ ) -> Option<FunctionId> {
+ let op = binop_expr.op_kind()?;
+ let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
+ let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
+
+ let op_fn = lang_names_for_bin_op(op)
+ .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
+ let substs =
+ hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
+
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ }
+
+ pub(crate) fn resolve_try_expr(
+ &self,
+ db: &dyn HirDatabase,
+ try_expr: &ast::TryExpr,
+ ) -> Option<FunctionId> {
+ let ty = self.ty_of_expr(db, &try_expr.expr()?.into())?;
+
+ let op_fn =
+ db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
}
pub(crate) fn resolve_field(
@@ -281,6 +398,7 @@ impl SourceAnalyzer {
let local = if field.name_ref().is_some() {
None
} else {
+ // Shorthand syntax, resolve to the local
let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone()));
match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
Some(ValueNs::LocalBinding(pat_id)) => {
@@ -666,6 +784,29 @@ impl SourceAnalyzer {
let fun_data = db.function_data(func);
method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name)
}
+
+ fn resolve_impl_method_or_trait_def(
+ &self,
+ db: &dyn HirDatabase,
+ func: FunctionId,
+ substs: &Substitution,
+ ) -> FunctionId {
+ self.resolve_impl_method(db, func, substs).unwrap_or(func)
+ }
+
+ fn lang_trait_fn(
+ &self,
+ db: &dyn HirDatabase,
+ lang_trait: &Name,
+ method_name: &Name,
+ ) -> Option<FunctionId> {
+ db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
+ .method_by_name(method_name)
+ }
+
+ fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
+ self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, &expr)?)
+ }
}
fn scope_for(