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.rs | 193 |
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>( |