Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/lib.rs')
-rw-r--r--crates/hir/src/lib.rs193
1 files changed, 163 insertions, 30 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 1a3becdf50..58340c74fe 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -78,7 +78,8 @@ use hir_ty::{
use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind;
use rustc_hash::FxHashSet;
-use span::{Edition, EditionedFileId, FileId, MacroCallId};
+use smallvec::SmallVec;
+use span::{Edition, EditionedFileId, FileId, MacroCallId, SyntaxContextId};
use stdx::{impl_from, never};
use syntax::{
ast::{self, HasAttrs as _, HasGenericParams, HasName},
@@ -93,8 +94,7 @@ pub use crate::{
diagnostics::*,
has_source::HasSource,
semantics::{
- DescendPreference, PathResolution, Semantics, SemanticsImpl, SemanticsScope, TypeInfo,
- VisibleTraits,
+ PathResolution, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, VisibleTraits,
},
};
pub use hir_ty::method_resolution::TyFingerprint;
@@ -340,13 +340,13 @@ impl ModuleDef {
}
}
- pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> {
+ pub fn canonical_path(&self, db: &dyn HirDatabase, edition: Edition) -> Option<String> {
let mut segments = vec![self.name(db)?];
for m in self.module(db)?.path_to_root(db) {
segments.extend(m.name(db))
}
segments.reverse();
- Some(segments.iter().map(|it| it.display(db.upcast())).join("::"))
+ Some(segments.iter().map(|it| it.display(db.upcast(), edition)).join("::"))
}
pub fn canonical_module_path(
@@ -556,13 +556,14 @@ impl Module {
style_lints: bool,
) {
let _p = tracing::info_span!("Module::diagnostics", name = ?self.name(db)).entered();
+ let edition = db.crate_graph()[self.id.krate()].edition;
let def_map = self.id.def_map(db.upcast());
for diag in def_map.diagnostics() {
if diag.in_module != self.id.local_id {
// FIXME: This is accidentally quadratic.
continue;
}
- emit_def_diagnostic(db, acc, diag);
+ emit_def_diagnostic(db, acc, diag, edition);
}
if !self.id.is_block_module() {
@@ -582,7 +583,7 @@ impl Module {
}
ModuleDef::Trait(t) => {
for diag in db.trait_data_with_diagnostics(t.id).1.iter() {
- emit_def_diagnostic(db, acc, diag);
+ emit_def_diagnostic(db, acc, diag, edition);
}
for item in t.items(db) {
@@ -599,19 +600,19 @@ impl Module {
match adt {
Adt::Struct(s) => {
for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
- emit_def_diagnostic(db, acc, diag);
+ emit_def_diagnostic(db, acc, diag, edition);
}
}
Adt::Union(u) => {
for diag in db.union_data_with_diagnostics(u.id).1.iter() {
- emit_def_diagnostic(db, acc, diag);
+ emit_def_diagnostic(db, acc, diag, edition);
}
}
Adt::Enum(e) => {
for v in e.variants(db) {
acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints));
for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() {
- emit_def_diagnostic(db, acc, diag);
+ emit_def_diagnostic(db, acc, diag, edition);
}
}
}
@@ -645,7 +646,7 @@ impl Module {
let ast_id_map = db.ast_id_map(file_id);
for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
- emit_def_diagnostic(db, acc, diag);
+ emit_def_diagnostic(db, acc, diag, edition);
}
if inherent_impls.invalid_impls().contains(&impl_def.id) {
@@ -869,23 +870,32 @@ fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>
never!("declarative expander for non decl-macro: {:?}", e);
return;
};
+ let krate = HasModule::krate(&m.id, db.upcast());
+ let edition = db.crate_graph()[krate].edition;
emit_def_diagnostic_(
db,
acc,
&DefDiagnosticKind::MacroDefError { ast, message: e.to_string() },
+ edition,
);
}
}
}
-fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) {
- emit_def_diagnostic_(db, acc, &diag.kind)
+fn emit_def_diagnostic(
+ db: &dyn HirDatabase,
+ acc: &mut Vec<AnyDiagnostic>,
+ diag: &DefDiagnostic,
+ edition: Edition,
+) {
+ emit_def_diagnostic_(db, acc, &diag.kind, edition)
}
fn emit_def_diagnostic_(
db: &dyn HirDatabase,
acc: &mut Vec<AnyDiagnostic>,
diag: &DefDiagnosticKind,
+ edition: Edition,
) {
match diag {
DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
@@ -910,7 +920,7 @@ fn emit_def_diagnostic_(
MacroError {
node: InFile::new(ast.file_id, item.syntax_node_ptr()),
precise_location: None,
- message: format!("{}: {message}", path.display(db.upcast())),
+ message: format!("{}: {message}", path.display(db.upcast(), edition)),
error,
}
.into(),
@@ -1764,7 +1774,7 @@ impl DefWithBody {
/// 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())
+ body.pretty_print(db.upcast(), self.id(), Edition::CURRENT)
}
/// A textual representation of the MIR of this def's body for debugging purposes.
@@ -2259,6 +2269,8 @@ impl Function {
db: &dyn HirDatabase,
span_formatter: impl Fn(FileId, TextRange) -> String,
) -> String {
+ let krate = HasModule::krate(&self.id, db.upcast());
+ let edition = db.crate_graph()[krate].edition;
let body = match db.monomorphized_mir_body(
self.id.into(),
Substitution::empty(Interner),
@@ -2267,7 +2279,7 @@ impl Function {
Ok(body) => body,
Err(e) => {
let mut r = String::new();
- _ = e.pretty_print(&mut r, db, &span_formatter);
+ _ = e.pretty_print(&mut r, db, &span_formatter, edition);
return r;
}
};
@@ -2276,7 +2288,7 @@ impl Function {
Ok(_) => "pass".to_owned(),
Err(e) => {
let mut r = String::new();
- _ = e.pretty_print(&mut r, db, &span_formatter);
+ _ = e.pretty_print(&mut r, db, &span_formatter, edition);
r
}
};
@@ -2510,7 +2522,11 @@ impl Const {
Type::from_value_def(db, self.id)
}
- pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
+ pub fn render_eval(
+ self,
+ db: &dyn HirDatabase,
+ edition: Edition,
+ ) -> Result<String, ConstEvalError> {
let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?;
let data = &c.data(Interner);
if let TyKind::Scalar(s) = data.ty.kind(Interner) {
@@ -2532,7 +2548,7 @@ impl Const {
if let Ok(s) = mir::render_const_using_debug_impl(db, self.id, &c) {
Ok(s)
} else {
- Ok(format!("{}", c.display(db)))
+ Ok(format!("{}", c.display(db, edition)))
}
}
}
@@ -3728,9 +3744,9 @@ impl ConstParam {
Type::new(db, self.id.parent(), db.const_param_ty(self.id))
}
- pub fn default(self, db: &dyn HirDatabase) -> Option<ast::ConstArg> {
+ pub fn default(self, db: &dyn HirDatabase, edition: Edition) -> Option<ast::ConstArg> {
let arg = generic_arg_from_param(db, self.id.into())?;
- known_const_to_ast(arg.constant(Interner)?, db)
+ known_const_to_ast(arg.constant(Interner)?, db, edition)
}
}
@@ -4038,12 +4054,20 @@ impl Closure {
TyKind::Closure(self.id, self.subst).intern(Interner)
}
- pub fn display_with_id(&self, db: &dyn HirDatabase) -> String {
- self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ClosureWithId).to_string()
+ pub fn display_with_id(&self, db: &dyn HirDatabase, edition: Edition) -> String {
+ self.clone()
+ .as_ty()
+ .display(db, edition)
+ .with_closure_style(ClosureStyle::ClosureWithId)
+ .to_string()
}
- pub fn display_with_impl(&self, db: &dyn HirDatabase) -> String {
- self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ImplFn).to_string()
+ pub fn display_with_impl(&self, db: &dyn HirDatabase, edition: Edition) -> String {
+ self.clone()
+ .as_ty()
+ .display(db, edition)
+ .with_closure_style(ClosureStyle::ImplFn)
+ .to_string()
}
pub fn captured_items(&self, db: &dyn HirDatabase) -> Vec<ClosureCapture> {
@@ -4090,6 +4114,15 @@ impl ClosureCapture {
Local { parent: self.owner, binding_id: self.capture.local() }
}
+ /// Returns whether this place has any field (aka. non-deref) projections.
+ pub fn has_field_projections(&self) -> bool {
+ self.capture.has_field_projections()
+ }
+
+ pub fn usages(&self) -> CaptureUsages {
+ CaptureUsages { parent: self.owner, spans: self.capture.spans() }
+ }
+
pub fn kind(&self) -> CaptureKind {
match self.capture.kind() {
hir_ty::CaptureKind::ByRef(
@@ -4105,11 +4138,21 @@ impl ClosureCapture {
}
}
+ /// Converts the place to a name that can be inserted into source code.
+ pub fn place_to_name(&self, db: &dyn HirDatabase) -> String {
+ self.capture.place_to_name(self.owner, db)
+ }
+
+ pub fn display_place_source_code(&self, db: &dyn HirDatabase) -> String {
+ self.capture.display_place_source_code(self.owner, db)
+ }
+
pub fn display_place(&self, db: &dyn HirDatabase) -> String {
self.capture.display_place(self.owner, db)
}
}
+#[derive(Clone, Copy, PartialEq, Eq)]
pub enum CaptureKind {
SharedRef,
UniqueSharedRef,
@@ -4117,6 +4160,74 @@ pub enum CaptureKind {
Move,
}
+#[derive(Debug, Clone)]
+pub struct CaptureUsages {
+ parent: DefWithBodyId,
+ spans: SmallVec<[mir::MirSpan; 3]>,
+}
+
+impl CaptureUsages {
+ pub fn sources(&self, db: &dyn HirDatabase) -> Vec<CaptureUsageSource> {
+ let (body, source_map) = db.body_with_source_map(self.parent);
+ let mut result = Vec::with_capacity(self.spans.len());
+ for &span in self.spans.iter() {
+ let is_ref = span.is_ref_span(&body);
+ match span {
+ mir::MirSpan::ExprId(expr) => {
+ if let Ok(expr) = source_map.expr_syntax(expr) {
+ result.push(CaptureUsageSource {
+ is_ref,
+ source: expr.map(AstPtr::wrap_left),
+ })
+ }
+ }
+ mir::MirSpan::PatId(pat) => {
+ if let Ok(pat) = source_map.pat_syntax(pat) {
+ result.push(CaptureUsageSource {
+ is_ref,
+ source: pat.map(AstPtr::wrap_right),
+ });
+ }
+ }
+ mir::MirSpan::BindingId(binding) => result.extend(
+ source_map
+ .patterns_for_binding(binding)
+ .iter()
+ .filter_map(|&pat| source_map.pat_syntax(pat).ok())
+ .map(|pat| CaptureUsageSource {
+ is_ref,
+ source: pat.map(AstPtr::wrap_right),
+ }),
+ ),
+ mir::MirSpan::SelfParam | mir::MirSpan::Unknown => {
+ unreachable!("invalid capture usage span")
+ }
+ }
+ }
+ result
+ }
+}
+
+#[derive(Debug)]
+pub struct CaptureUsageSource {
+ is_ref: bool,
+ source: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+}
+
+impl CaptureUsageSource {
+ pub fn source(&self) -> AstPtr<Either<ast::Expr, ast::Pat>> {
+ self.source.value
+ }
+
+ pub fn file_id(&self) -> HirFileId {
+ self.source.file_id
+ }
+
+ pub fn is_ref(&self) -> bool {
+ self.is_ref
+ }
+}
+
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Type {
env: Arc<TraitEnvironment>,
@@ -4355,6 +4466,22 @@ impl Type {
method_resolution::implements_trait(&canonical_ty, db, &self.env, trait_)
}
+ /// This does **not** resolve `IntoFuture`, only `Future`.
+ pub fn future_output(self, db: &dyn HirDatabase) -> Option<Type> {
+ let future_output =
+ db.lang_item(self.env.krate, LangItem::FutureOutput)?.as_type_alias()?;
+ self.normalize_trait_assoc_type(db, &[], future_output.into())
+ }
+
+ /// This does **not** resolve `IntoIterator`, only `Iterator`.
+ pub fn iterator_item(self, db: &dyn HirDatabase) -> Option<Type> {
+ let iterator_trait = db.lang_item(self.env.krate, LangItem::Iterator)?.as_trait()?;
+ let iterator_item = db
+ .trait_data(iterator_trait)
+ .associated_type_by_name(&Name::new_symbol(sym::Item.clone(), SyntaxContextId::ROOT))?;
+ self.normalize_trait_assoc_type(db, &[], iterator_item.into())
+ }
+
/// Checks that particular type `ty` implements `std::ops::FnOnce`.
///
/// This function can be used to check if a particular type is callable, since FnOnce is a
@@ -4704,18 +4831,20 @@ impl Type {
pub fn type_and_const_arguments<'a>(
&'a self,
db: &'a dyn HirDatabase,
+ edition: Edition,
) -> impl Iterator<Item = SmolStr> + 'a {
self.ty
.strip_references()
.as_adt()
.into_iter()
.flat_map(|(_, substs)| substs.iter(Interner))
- .filter_map(|arg| {
+ .filter_map(move |arg| {
// arg can be either a `Ty` or `constant`
if let Some(ty) = arg.ty(Interner) {
- Some(format_smolstr!("{}", ty.display(db)))
+ Some(format_smolstr!("{}", ty.display(db, edition)))
} else {
- arg.constant(Interner).map(|const_| format_smolstr!("{}", const_.display(db)))
+ arg.constant(Interner)
+ .map(|const_| format_smolstr!("{}", const_.display(db, edition)))
}
})
}
@@ -4724,13 +4853,17 @@ impl Type {
pub fn generic_parameters<'a>(
&'a self,
db: &'a dyn HirDatabase,
+ edition: Edition,
) -> impl Iterator<Item = SmolStr> + 'a {
// iterate the lifetime
self.as_adt()
- .and_then(|a| a.lifetime(db).map(|lt| lt.name.display_no_db().to_smolstr()))
+ .and_then(|a| {
+ // Lifetimes do not need edition-specific handling as they cannot be escaped.
+ a.lifetime(db).map(|lt| lt.name.display_no_db(Edition::Edition2015).to_smolstr())
+ })
.into_iter()
// add the type and const parameters
- .chain(self.type_and_const_arguments(db))
+ .chain(self.type_and_const_arguments(db, edition))
}
pub fn iterate_method_candidates_with_traits<T>(