Auto merge of #17905 - ChayimFriedman2:edition-dependent-raw-keyword, r=Veykril

fix: Properly account for editions in names

This PR touches a lot of parts. But the main changes are changing `hir_expand::Name` to be raw edition-dependently and only when necessary (unrelated to how the user originally wrote the identifier), and changing `is_keyword()` and `is_raw_identifier()` to be edition-aware (this was done in #17896, but the FIXMEs were fixed here).

It is possible that I missed some cases, but most IDE parts should properly escape (or not escape) identifiers now.

The rules of thumb are:

 - If we show the identifier to the user, its rawness should be determined by the edition of the edited crate. This is nice for IDE features, but really important for changes we insert to the source code.
 - For tests, I chose `Edition::CURRENT` (so we only have to (maybe) update tests when an edition becomes stable, to avoid churn).
 - For debugging tools (helper methods and logs), I used `Edition::LATEST`.

Reviewing notes:

This is a really big PR but most of it is mechanical translation. I changed `Name` displayers to require an edition, and followed the compiler errors. Most methods just propagate the edition requirement. The interesting cases are mostly in `ide-assists`, as sometimes the correct crate to fetch the edition from requires awareness (there may be two). `ide-completions` and `ide-diagnostics` were solved pretty easily by introducing an edition field to their context. `ide` contains many features, for most of them it was propagated to the top level function and there the edition was fetched based on the file.

I also fixed all FIXMEs from #17896. Some required introducing an edition parameter (usually not for many methods after the changes to `Name`), some were changed to a new method `is_any_identifier()` because they really want any possible keyword.

Fixes #17895.
Fixes #17774.
This commit is contained in:
bors 2024-08-16 13:49:32 +00:00
commit c9ee892263
179 changed files with 2485 additions and 1250 deletions

View file

@ -14,7 +14,7 @@ use hir_expand::{name::Name, ExpandError, InFile};
use la_arena::{Arena, ArenaMap, Idx, RawIdx}; use la_arena::{Arena, ArenaMap, Idx, RawIdx};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use smallvec::SmallVec; use smallvec::SmallVec;
use span::MacroFileId; use span::{Edition, MacroFileId};
use syntax::{ast, AstPtr, SyntaxNodePtr}; use syntax::{ast, AstPtr, SyntaxNodePtr};
use triomphe::Arc; use triomphe::Arc;
@ -201,8 +201,13 @@ impl Body {
self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block))) self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block)))
} }
pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String { pub fn pretty_print(
pretty::print_body_hir(db, self, owner) &self,
db: &dyn DefDatabase,
owner: DefWithBodyId,
edition: Edition,
) -> String {
pretty::print_body_hir(db, self, owner, edition)
} }
pub fn pretty_print_expr( pub fn pretty_print_expr(
@ -210,8 +215,9 @@ impl Body {
db: &dyn DefDatabase, db: &dyn DefDatabase,
owner: DefWithBodyId, owner: DefWithBodyId,
expr: ExprId, expr: ExprId,
edition: Edition,
) -> String { ) -> String {
pretty::print_expr_hir(db, self, owner, expr) pretty::print_expr_hir(db, self, owner, expr, edition)
} }
fn new( fn new(

View file

@ -3,6 +3,7 @@
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use itertools::Itertools; use itertools::Itertools;
use span::Edition;
use crate::{ use crate::{
hir::{ hir::{
@ -15,20 +16,26 @@ use crate::{
use super::*; use super::*;
pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String { pub(super) fn print_body_hir(
db: &dyn DefDatabase,
body: &Body,
owner: DefWithBodyId,
edition: Edition,
) -> String {
let header = match owner { let header = match owner {
DefWithBodyId::FunctionId(it) => { DefWithBodyId::FunctionId(it) => it
it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db.upcast()))) .lookup(db)
} .id
.resolved(db, |it| format!("fn {}", it.name.display(db.upcast(), edition))),
DefWithBodyId::StaticId(it) => it DefWithBodyId::StaticId(it) => it
.lookup(db) .lookup(db)
.id .id
.resolved(db, |it| format!("static {} = ", it.name.display(db.upcast()))), .resolved(db, |it| format!("static {} = ", it.name.display(db.upcast(), edition))),
DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| { DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| {
format!( format!(
"const {} = ", "const {} = ",
match &it.name { match &it.name {
Some(name) => name.display(db.upcast()).to_string(), Some(name) => name.display(db.upcast(), edition).to_string(),
None => "_".to_owned(), None => "_".to_owned(),
} }
) )
@ -39,13 +46,13 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
let enum_loc = loc.parent.lookup(db); let enum_loc = loc.parent.lookup(db);
format!( format!(
"enum {}::{}", "enum {}::{}",
enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition),
loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition),
) )
} }
}; };
let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false }; let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false, edition };
if let DefWithBodyId::FunctionId(it) = owner { if let DefWithBodyId::FunctionId(it) = owner {
p.buf.push('('); p.buf.push('(');
let function_data = &db.function_data(it); let function_data = &db.function_data(it);
@ -86,8 +93,10 @@ pub(super) fn print_expr_hir(
body: &Body, body: &Body,
_owner: DefWithBodyId, _owner: DefWithBodyId,
expr: ExprId, expr: ExprId,
edition: Edition,
) -> String { ) -> String {
let mut p = Printer { db, body, buf: String::new(), indent_level: 0, needs_indent: false }; let mut p =
Printer { db, body, buf: String::new(), indent_level: 0, needs_indent: false, edition };
p.print_expr(expr); p.print_expr(expr);
p.buf p.buf
} }
@ -113,6 +122,7 @@ struct Printer<'a> {
buf: String, buf: String,
indent_level: usize, indent_level: usize,
needs_indent: bool, needs_indent: bool,
edition: Edition,
} }
impl Write for Printer<'_> { impl Write for Printer<'_> {
@ -173,13 +183,14 @@ impl Printer<'_> {
Expr::OffsetOf(offset_of) => { Expr::OffsetOf(offset_of) => {
w!(self, "builtin#offset_of("); w!(self, "builtin#offset_of(");
self.print_type_ref(&offset_of.container); self.print_type_ref(&offset_of.container);
let edition = self.edition;
w!( w!(
self, self,
", {})", ", {})",
offset_of offset_of
.fields .fields
.iter() .iter()
.format_with(".", |field, f| f(&field.display(self.db.upcast()))) .format_with(".", |field, f| f(&field.display(self.db.upcast(), edition)))
); );
} }
Expr::Path(path) => self.print_path(path), Expr::Path(path) => self.print_path(path),
@ -201,7 +212,7 @@ impl Printer<'_> {
} }
Expr::Loop { body, label } => { Expr::Loop { body, label } => {
if let Some(lbl) = label { if let Some(lbl) = label {
w!(self, "{}: ", self.body[*lbl].name.display(self.db.upcast())); w!(self, "{}: ", self.body[*lbl].name.display(self.db.upcast(), self.edition));
} }
w!(self, "loop "); w!(self, "loop ");
self.print_expr(*body); self.print_expr(*body);
@ -221,10 +232,11 @@ impl Printer<'_> {
} }
Expr::MethodCall { receiver, method_name, args, generic_args } => { Expr::MethodCall { receiver, method_name, args, generic_args } => {
self.print_expr(*receiver); self.print_expr(*receiver);
w!(self, ".{}", method_name.display(self.db.upcast())); w!(self, ".{}", method_name.display(self.db.upcast(), self.edition));
if let Some(args) = generic_args { if let Some(args) = generic_args {
w!(self, "::<"); w!(self, "::<");
print_generic_args(self.db, args, self).unwrap(); let edition = self.edition;
print_generic_args(self.db, args, self, edition).unwrap();
w!(self, ">"); w!(self, ">");
} }
w!(self, "("); w!(self, "(");
@ -259,13 +271,13 @@ impl Printer<'_> {
Expr::Continue { label } => { Expr::Continue { label } => {
w!(self, "continue"); w!(self, "continue");
if let Some(lbl) = label { if let Some(lbl) = label {
w!(self, " {}", self.body[*lbl].name.display(self.db.upcast())); w!(self, " {}", self.body[*lbl].name.display(self.db.upcast(), self.edition));
} }
} }
Expr::Break { expr, label } => { Expr::Break { expr, label } => {
w!(self, "break"); w!(self, "break");
if let Some(lbl) = label { if let Some(lbl) = label {
w!(self, " {}", self.body[*lbl].name.display(self.db.upcast())); w!(self, " {}", self.body[*lbl].name.display(self.db.upcast(), self.edition));
} }
if let Some(expr) = expr { if let Some(expr) = expr {
self.whitespace(); self.whitespace();
@ -307,9 +319,10 @@ impl Printer<'_> {
} }
w!(self, "{{"); w!(self, "{{");
let edition = self.edition;
self.indented(|p| { self.indented(|p| {
for field in &**fields { for field in &**fields {
w!(p, "{}: ", field.name.display(self.db.upcast())); w!(p, "{}: ", field.name.display(self.db.upcast(), edition));
p.print_expr(field.expr); p.print_expr(field.expr);
wln!(p, ","); wln!(p, ",");
} }
@ -326,7 +339,7 @@ impl Printer<'_> {
} }
Expr::Field { expr, name } => { Expr::Field { expr, name } => {
self.print_expr(*expr); self.print_expr(*expr);
w!(self, ".{}", name.display(self.db.upcast())); w!(self, ".{}", name.display(self.db.upcast(), self.edition));
} }
Expr::Await { expr } => { Expr::Await { expr } => {
self.print_expr(*expr); self.print_expr(*expr);
@ -464,8 +477,9 @@ impl Printer<'_> {
} }
Expr::Literal(lit) => self.print_literal(lit), Expr::Literal(lit) => self.print_literal(lit),
Expr::Block { id: _, statements, tail, label } => { Expr::Block { id: _, statements, tail, label } => {
let label = let label = label.map(|lbl| {
label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db.upcast()))); format!("{}: ", self.body[lbl].name.display(self.db.upcast(), self.edition))
});
self.print_block(label.as_deref(), statements, tail); self.print_block(label.as_deref(), statements, tail);
} }
Expr::Unsafe { id: _, statements, tail } => { Expr::Unsafe { id: _, statements, tail } => {
@ -539,9 +553,10 @@ impl Printer<'_> {
} }
w!(self, " {{"); w!(self, " {{");
let edition = self.edition;
self.indented(|p| { self.indented(|p| {
for arg in args.iter() { for arg in args.iter() {
w!(p, "{}: ", arg.name.display(self.db.upcast())); w!(p, "{}: ", arg.name.display(self.db.upcast(), edition));
p.print_pat(arg.pat); p.print_pat(arg.pat);
wln!(p, ","); wln!(p, ",");
} }
@ -686,11 +701,13 @@ impl Printer<'_> {
} }
fn print_type_ref(&mut self, ty: &TypeRef) { fn print_type_ref(&mut self, ty: &TypeRef) {
print_type_ref(self.db, ty, self).unwrap(); let edition = self.edition;
print_type_ref(self.db, ty, self, edition).unwrap();
} }
fn print_path(&mut self, path: &Path) { fn print_path(&mut self, path: &Path) {
print_path(self.db, path, self).unwrap(); let edition = self.edition;
print_path(self.db, path, self, edition).unwrap();
} }
fn print_binding(&mut self, id: BindingId) { fn print_binding(&mut self, id: BindingId) {
@ -701,6 +718,6 @@ impl Printer<'_> {
BindingAnnotation::Ref => "ref ", BindingAnnotation::Ref => "ref ",
BindingAnnotation::RefMut => "ref mut ", BindingAnnotation::RefMut => "ref mut ",
}; };
w!(self, "{}{}", mode, name.display(self.db.upcast())); w!(self, "{}{}", mode, name.display(self.db.upcast(), self.edition));
} }
} }

View file

@ -219,7 +219,7 @@ fn main() {
}, },
); );
}"#]] }"#]]
.assert_eq(&body.pretty_print(&db, def)) .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
} }
#[test] #[test]
@ -285,7 +285,7 @@ impl SsrError {
), ),
); );
}"#]] }"#]]
.assert_eq(&body.pretty_print(&db, def)) .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
} }
#[test] #[test]
@ -333,5 +333,5 @@ fn f(a: i32, b: u32) -> String {
); );
}; };
}"#]] }"#]]
.assert_eq(&body.pretty_print(&db, def)) .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
} }

View file

@ -651,6 +651,7 @@ mod tests {
use expect_test::{expect, Expect}; use expect_test::{expect, Expect};
use hir_expand::db::ExpandDatabase; use hir_expand::db::ExpandDatabase;
use itertools::Itertools; use itertools::Itertools;
use span::Edition;
use stdx::format_to; use stdx::format_to;
use syntax::ast::AstNode; use syntax::ast::AstNode;
use test_fixture::WithFixture; use test_fixture::WithFixture;
@ -717,8 +718,10 @@ mod tests {
"{:7}(imports {}): {}\n", "{:7}(imports {}): {}\n",
format!("{:?}", prefix), format!("{:?}", prefix),
if ignore_local_imports { '✖' } else { '✔' }, if ignore_local_imports { '✖' } else { '✔' },
found_path found_path.map_or_else(
.map_or_else(|| "<unresolvable>".to_owned(), |it| it.display(&db).to_string()), || "<unresolvable>".to_owned(),
|it| it.display(&db, Edition::CURRENT).to_string()
),
); );
} }
expect.assert_eq(&res); expect.assert_eq(&res);

View file

@ -250,7 +250,7 @@ pub(crate) fn parse(
} }
} }
ArgRef::Name(name, span) => { ArgRef::Name(name, span) => {
let name = Name::new(name, tt::IdentIsRaw::No, call_ctx); let name = Name::new(name, call_ctx);
if let Some((index, _)) = args.by_name(&name) { if let Some((index, _)) = args.by_name(&name) {
record_usage(name, span); record_usage(name, span);
// Name found in `args`, so we resolve it to its index. // Name found in `args`, so we resolve it to its index.

View file

@ -10,6 +10,7 @@ use hir_expand::{
AstId, AstId,
}; };
use intern::{sym, Interned, Symbol}; use intern::{sym, Interned, Symbol};
use span::Edition;
use syntax::ast::{self, HasGenericArgs, HasName, IsString}; use syntax::ast::{self, HasGenericArgs, HasName, IsString};
use crate::{ use crate::{
@ -419,18 +420,22 @@ impl ConstRef {
param.default_val().map(|default| Self::from_const_arg(lower_ctx, Some(default))) param.default_val().map(|default| Self::from_const_arg(lower_ctx, Some(default)))
} }
pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a { pub fn display<'a>(
struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef); &'a self,
db: &'a dyn ExpandDatabase,
edition: Edition,
) -> impl fmt::Display + 'a {
struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef, Edition);
impl fmt::Display for Display<'_> { impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.1 { match self.1 {
ConstRef::Scalar(s) => s.fmt(f), ConstRef::Scalar(s) => s.fmt(f),
ConstRef::Path(n) => n.display(self.0).fmt(f), ConstRef::Path(n) => n.display(self.0, self.2).fmt(f),
ConstRef::Complex(_) => f.write_str("{const}"), ConstRef::Complex(_) => f.write_str("{const}"),
} }
} }
} }
Display(db, self) Display(db, self, edition)
} }
// We special case literals and single identifiers, to speed up things. // We special case literals and single identifiers, to speed up things.

View file

@ -8,6 +8,7 @@ use hir_expand::name::Name;
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use smallvec::SmallVec; use smallvec::SmallVec;
use span::Edition;
use stdx::{format_to, TupleExt}; use stdx::{format_to, TupleExt};
use syntax::ToSmolStr; use syntax::ToSmolStr;
use triomphe::Arc; use triomphe::Arc;
@ -66,7 +67,12 @@ impl ImportMap {
for (k, v) in self.item_to_info_map.iter() { for (k, v) in self.item_to_info_map.iter() {
format_to!(out, "{:?} ({:?}) -> ", k, v.1); format_to!(out, "{:?} ({:?}) -> ", k, v.1);
for v in &v.0 { for v in &v.0 {
format_to!(out, "{}:{:?}, ", v.name.display(db.upcast()), v.container); format_to!(
out,
"{}:{:?}, ",
v.name.display(db.upcast(), Edition::CURRENT),
v.container
);
} }
format_to!(out, "\n"); format_to!(out, "\n");
} }
@ -83,7 +89,7 @@ impl ImportMap {
// We've only collected items, whose name cannot be tuple field so unwrapping is fine. // We've only collected items, whose name cannot be tuple field so unwrapping is fine.
.flat_map(|(&item, (info, _))| { .flat_map(|(&item, (info, _))| {
info.iter().enumerate().map(move |(idx, info)| { info.iter().enumerate().map(move |(idx, info)| {
(item, info.name.display(db.upcast()).to_smolstr(), idx as u32) (item, info.name.unescaped().display(db.upcast()).to_smolstr(), idx as u32)
}) })
}) })
.collect(); .collect();
@ -461,7 +467,7 @@ fn search_maps(
query.search_mode.check( query.search_mode.check(
&query.query, &query.query,
query.case_sensitive, query.case_sensitive,
&info.name.display(db.upcast()).to_smolstr(), &info.name.unescaped().display(db.upcast()).to_smolstr(),
) )
}); });
res.extend(iter.map(TupleExt::head)); res.extend(iter.map(TupleExt::head));
@ -577,7 +583,7 @@ mod tests {
Some(format!( Some(format!(
"{}::{}", "{}::{}",
render_path(db, &trait_info[0]), render_path(db, &trait_info[0]),
assoc_item_name.display(db.upcast()) assoc_item_name.display(db.upcast(), Edition::CURRENT)
)) ))
} }
@ -616,7 +622,7 @@ mod tests {
module = parent; module = parent;
} }
segments.iter().rev().map(|it| it.display(db.upcast())).join("::") segments.iter().rev().map(|it| it.display(db.upcast(), Edition::CURRENT)).join("::")
} }
#[test] #[test]

View file

@ -10,6 +10,7 @@ use itertools::Itertools;
use la_arena::Idx; use la_arena::Idx;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use span::Edition;
use stdx::format_to; use stdx::format_to;
use syntax::ast; use syntax::ast;
@ -707,7 +708,7 @@ impl ItemScope {
format_to!( format_to!(
buf, buf,
"{}:", "{}:",
name.map_or("_".to_owned(), |name| name.display(db).to_string()) name.map_or("_".to_owned(), |name| name.display(db, Edition::LATEST).to_string())
); );
if let Some((.., i)) = def.types { if let Some((.., i)) = def.types {

View file

@ -51,7 +51,7 @@ use intern::{Interned, Symbol};
use la_arena::{Arena, Idx, RawIdx}; use la_arena::{Arena, Idx, RawIdx};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use smallvec::SmallVec; use smallvec::SmallVec;
use span::{AstIdNode, FileAstId, SyntaxContextId}; use span::{AstIdNode, Edition, FileAstId, SyntaxContextId};
use stdx::never; use stdx::never;
use syntax::{ast, match_ast, SyntaxKind}; use syntax::{ast, match_ast, SyntaxKind};
use triomphe::Arc; use triomphe::Arc;
@ -199,8 +199,8 @@ impl ItemTree {
Attrs::filter(db, krate, self.raw_attrs(of).clone()) Attrs::filter(db, krate, self.raw_attrs(of).clone())
} }
pub fn pretty_print(&self, db: &dyn DefDatabase) -> String { pub fn pretty_print(&self, db: &dyn DefDatabase, edition: Edition) -> String {
pretty::print_item_tree(db, self) pretty::print_item_tree(db, self, edition)
} }
fn data(&self) -> &ItemTreeData { fn data(&self) -> &ItemTreeData {

View file

@ -3,7 +3,7 @@
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use la_arena::{Idx, RawIdx}; use la_arena::{Idx, RawIdx};
use span::ErasedFileAstId; use span::{Edition, ErasedFileAstId};
use crate::{ use crate::{
generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget}, generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
@ -18,8 +18,9 @@ use crate::{
visibility::RawVisibility, visibility::RawVisibility,
}; };
pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree) -> String { pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree, edition: Edition) -> String {
let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true }; let mut p =
Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true, edition };
if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) { if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
p.print_attrs(attrs, true, "\n"); p.print_attrs(attrs, true, "\n");
@ -56,6 +57,7 @@ struct Printer<'a> {
buf: String, buf: String,
indent_level: usize, indent_level: usize,
needs_indent: bool, needs_indent: bool,
edition: Edition,
} }
impl Printer<'_> { impl Printer<'_> {
@ -97,7 +99,7 @@ impl Printer<'_> {
self, self,
"#{}[{}{}]{}", "#{}[{}{}]{}",
inner, inner,
attr.path.display(self.db.upcast()), attr.path.display(self.db.upcast(), self.edition),
attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(), attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
separated_by, separated_by,
); );
@ -113,13 +115,14 @@ impl Printer<'_> {
fn print_visibility(&mut self, vis: RawVisibilityId) { fn print_visibility(&mut self, vis: RawVisibilityId) {
match &self.tree[vis] { match &self.tree[vis] {
RawVisibility::Module(path, _expl) => { RawVisibility::Module(path, _expl) => {
w!(self, "pub({}) ", path.display(self.db.upcast())) w!(self, "pub({}) ", path.display(self.db.upcast(), self.edition))
} }
RawVisibility::Public => w!(self, "pub "), RawVisibility::Public => w!(self, "pub "),
}; };
} }
fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) { fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
let edition = self.edition;
match kind { match kind {
FieldsShape::Record => { FieldsShape::Record => {
self.whitespace(); self.whitespace();
@ -131,7 +134,7 @@ impl Printer<'_> {
"\n", "\n",
); );
this.print_visibility(*visibility); this.print_visibility(*visibility);
w!(this, "{}: ", name.display(self.db.upcast())); w!(this, "{}: ", name.display(self.db.upcast(), edition));
this.print_type_ref(type_ref); this.print_type_ref(type_ref);
wln!(this, ","); wln!(this, ",");
} }
@ -147,7 +150,7 @@ impl Printer<'_> {
"\n", "\n",
); );
this.print_visibility(*visibility); this.print_visibility(*visibility);
w!(this, "{}: ", name.display(self.db.upcast())); w!(this, "{}: ", name.display(self.db.upcast(), edition));
this.print_type_ref(type_ref); this.print_type_ref(type_ref);
wln!(this, ","); wln!(this, ",");
} }
@ -186,20 +189,20 @@ impl Printer<'_> {
fn print_use_tree(&mut self, use_tree: &UseTree) { fn print_use_tree(&mut self, use_tree: &UseTree) {
match &use_tree.kind { match &use_tree.kind {
UseTreeKind::Single { path, alias } => { UseTreeKind::Single { path, alias } => {
w!(self, "{}", path.display(self.db.upcast())); w!(self, "{}", path.display(self.db.upcast(), self.edition));
if let Some(alias) = alias { if let Some(alias) = alias {
w!(self, " as {}", alias); w!(self, " as {}", alias.display(self.edition));
} }
} }
UseTreeKind::Glob { path } => { UseTreeKind::Glob { path } => {
if let Some(path) = path { if let Some(path) = path {
w!(self, "{}::", path.display(self.db.upcast())); w!(self, "{}::", path.display(self.db.upcast(), self.edition));
} }
w!(self, "*"); w!(self, "*");
} }
UseTreeKind::Prefixed { prefix, list } => { UseTreeKind::Prefixed { prefix, list } => {
if let Some(prefix) = prefix { if let Some(prefix) = prefix {
w!(self, "{}::", prefix.display(self.db.upcast())); w!(self, "{}::", prefix.display(self.db.upcast(), self.edition));
} }
w!(self, "{{"); w!(self, "{{");
for (i, tree) in list.iter().enumerate() { for (i, tree) in list.iter().enumerate() {
@ -229,9 +232,9 @@ impl Printer<'_> {
let ExternCrate { name, alias, visibility, ast_id } = &self.tree[it]; let ExternCrate { name, alias, visibility, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase()); self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility); self.print_visibility(*visibility);
w!(self, "extern crate {}", name.display(self.db.upcast())); w!(self, "extern crate {}", name.display(self.db.upcast(), self.edition));
if let Some(alias) = alias { if let Some(alias) = alias {
w!(self, " as {}", alias); w!(self, " as {}", alias.display(self.edition));
} }
wln!(self, ";"); wln!(self, ";");
} }
@ -278,7 +281,7 @@ impl Printer<'_> {
if let Some(abi) = abi { if let Some(abi) = abi {
w!(self, "extern \"{}\" ", abi); w!(self, "extern \"{}\" ", abi);
} }
w!(self, "fn {}", name.display(self.db.upcast())); w!(self, "fn {}", name.display(self.db.upcast(), self.edition));
self.print_generic_params(explicit_generic_params, it.into()); self.print_generic_params(explicit_generic_params, it.into());
w!(self, "("); w!(self, "(");
if !params.is_empty() { if !params.is_empty() {
@ -314,7 +317,7 @@ impl Printer<'_> {
&self.tree[it]; &self.tree[it];
self.print_ast_id(ast_id.erase()); self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility); self.print_visibility(*visibility);
w!(self, "struct {}", name.display(self.db.upcast())); w!(self, "struct {}", name.display(self.db.upcast(), self.edition));
self.print_generic_params(generic_params, it.into()); self.print_generic_params(generic_params, it.into());
self.print_fields_and_where_clause( self.print_fields_and_where_clause(
FieldParent::Struct(it), FieldParent::Struct(it),
@ -332,7 +335,7 @@ impl Printer<'_> {
let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it]; let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase()); self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility); self.print_visibility(*visibility);
w!(self, "union {}", name.display(self.db.upcast())); w!(self, "union {}", name.display(self.db.upcast(), self.edition));
self.print_generic_params(generic_params, it.into()); self.print_generic_params(generic_params, it.into());
self.print_fields_and_where_clause( self.print_fields_and_where_clause(
FieldParent::Union(it), FieldParent::Union(it),
@ -346,15 +349,16 @@ impl Printer<'_> {
let Enum { name, visibility, variants, generic_params, ast_id } = &self.tree[it]; let Enum { name, visibility, variants, generic_params, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase()); self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility); self.print_visibility(*visibility);
w!(self, "enum {}", name.display(self.db.upcast())); w!(self, "enum {}", name.display(self.db.upcast(), self.edition));
self.print_generic_params(generic_params, it.into()); self.print_generic_params(generic_params, it.into());
self.print_where_clause_and_opening_brace(generic_params); self.print_where_clause_and_opening_brace(generic_params);
let edition = self.edition;
self.indented(|this| { self.indented(|this| {
for variant in FileItemTreeId::range_iter(variants.clone()) { for variant in FileItemTreeId::range_iter(variants.clone()) {
let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant]; let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
this.print_ast_id(ast_id.erase()); this.print_ast_id(ast_id.erase());
this.print_attrs_of(variant, "\n"); this.print_attrs_of(variant, "\n");
w!(this, "{}", name.display(self.db.upcast())); w!(this, "{}", name.display(self.db.upcast(), edition));
this.print_fields(FieldParent::Variant(variant), *kind, fields); this.print_fields(FieldParent::Variant(variant), *kind, fields);
wln!(this, ","); wln!(this, ",");
} }
@ -367,7 +371,7 @@ impl Printer<'_> {
self.print_visibility(*visibility); self.print_visibility(*visibility);
w!(self, "const "); w!(self, "const ");
match name { match name {
Some(name) => w!(self, "{}", name.display(self.db.upcast())), Some(name) => w!(self, "{}", name.display(self.db.upcast(), self.edition)),
None => w!(self, "_"), None => w!(self, "_"),
} }
w!(self, ": "); w!(self, ": ");
@ -382,7 +386,7 @@ impl Printer<'_> {
if *mutable { if *mutable {
w!(self, "mut "); w!(self, "mut ");
} }
w!(self, "{}: ", name.display(self.db.upcast())); w!(self, "{}: ", name.display(self.db.upcast(), self.edition));
self.print_type_ref(type_ref); self.print_type_ref(type_ref);
w!(self, " = _;"); w!(self, " = _;");
wln!(self); wln!(self);
@ -398,7 +402,7 @@ impl Printer<'_> {
if *is_auto { if *is_auto {
w!(self, "auto "); w!(self, "auto ");
} }
w!(self, "trait {}", name.display(self.db.upcast())); w!(self, "trait {}", name.display(self.db.upcast(), self.edition));
self.print_generic_params(generic_params, it.into()); self.print_generic_params(generic_params, it.into());
self.print_where_clause_and_opening_brace(generic_params); self.print_where_clause_and_opening_brace(generic_params);
self.indented(|this| { self.indented(|this| {
@ -412,7 +416,7 @@ impl Printer<'_> {
let TraitAlias { name, visibility, generic_params, ast_id } = &self.tree[it]; let TraitAlias { name, visibility, generic_params, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase()); self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility); self.print_visibility(*visibility);
w!(self, "trait {}", name.display(self.db.upcast())); w!(self, "trait {}", name.display(self.db.upcast(), self.edition));
self.print_generic_params(generic_params, it.into()); self.print_generic_params(generic_params, it.into());
w!(self, " = "); w!(self, " = ");
self.print_where_clause(generic_params); self.print_where_clause(generic_params);
@ -457,7 +461,7 @@ impl Printer<'_> {
&self.tree[it]; &self.tree[it];
self.print_ast_id(ast_id.erase()); self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility); self.print_visibility(*visibility);
w!(self, "type {}", name.display(self.db.upcast())); w!(self, "type {}", name.display(self.db.upcast(), self.edition));
self.print_generic_params(generic_params, it.into()); self.print_generic_params(generic_params, it.into());
if !bounds.is_empty() { if !bounds.is_empty() {
w!(self, ": "); w!(self, ": ");
@ -475,7 +479,7 @@ impl Printer<'_> {
let Mod { name, visibility, kind, ast_id } = &self.tree[it]; let Mod { name, visibility, kind, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase()); self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility); self.print_visibility(*visibility);
w!(self, "mod {}", name.display(self.db.upcast())); w!(self, "mod {}", name.display(self.db.upcast(), self.edition));
match kind { match kind {
ModKind::Inline { items } => { ModKind::Inline { items } => {
w!(self, " {{"); w!(self, " {{");
@ -500,18 +504,22 @@ impl Printer<'_> {
ctxt, ctxt,
expand_to expand_to
); );
wln!(self, "{}!(...);", path.display(self.db.upcast())); wln!(self, "{}!(...);", path.display(self.db.upcast(), self.edition));
} }
ModItem::MacroRules(it) => { ModItem::MacroRules(it) => {
let MacroRules { name, ast_id } = &self.tree[it]; let MacroRules { name, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase()); self.print_ast_id(ast_id.erase());
wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db.upcast())); wln!(
self,
"macro_rules! {} {{ ... }}",
name.display(self.db.upcast(), self.edition)
);
} }
ModItem::Macro2(it) => { ModItem::Macro2(it) => {
let Macro2 { name, visibility, ast_id } = &self.tree[it]; let Macro2 { name, visibility, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase()); self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility); self.print_visibility(*visibility);
wln!(self, "macro {} {{ ... }}", name.display(self.db.upcast())); wln!(self, "macro {} {{ ... }}", name.display(self.db.upcast(), self.edition));
} }
} }
@ -519,15 +527,18 @@ impl Printer<'_> {
} }
fn print_type_ref(&mut self, type_ref: &TypeRef) { fn print_type_ref(&mut self, type_ref: &TypeRef) {
print_type_ref(self.db, type_ref, self).unwrap(); let edition = self.edition;
print_type_ref(self.db, type_ref, self, edition).unwrap();
} }
fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) { fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
print_type_bounds(self.db, bounds, self).unwrap(); let edition = self.edition;
print_type_bounds(self.db, bounds, self, edition).unwrap();
} }
fn print_path(&mut self, path: &Path) { fn print_path(&mut self, path: &Path) {
print_path(self.db, path, self).unwrap(); let edition = self.edition;
print_path(self.db, path, self, edition).unwrap();
} }
fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) { fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
@ -543,7 +554,7 @@ impl Printer<'_> {
} }
first = false; first = false;
self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " "); self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " ");
w!(self, "{}", lt.name.display(self.db.upcast())); w!(self, "{}", lt.name.display(self.db.upcast(), self.edition));
} }
for (idx, x) in params.iter_type_or_consts() { for (idx, x) in params.iter_type_or_consts() {
if !first { if !first {
@ -553,11 +564,11 @@ impl Printer<'_> {
self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " "); self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " ");
match x { match x {
TypeOrConstParamData::TypeParamData(ty) => match &ty.name { TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
Some(name) => w!(self, "{}", name.display(self.db.upcast())), Some(name) => w!(self, "{}", name.display(self.db.upcast(), self.edition)),
None => w!(self, "_anon_{}", idx.into_raw()), None => w!(self, "_anon_{}", idx.into_raw()),
}, },
TypeOrConstParamData::ConstParamData(konst) => { TypeOrConstParamData::ConstParamData(konst) => {
w!(self, "const {}: ", konst.name.display(self.db.upcast())); w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition));
self.print_type_ref(&konst.ty); self.print_type_ref(&konst.ty);
} }
} }
@ -580,6 +591,7 @@ impl Printer<'_> {
} }
w!(self, "\nwhere"); w!(self, "\nwhere");
let edition = self.edition;
self.indented(|this| { self.indented(|this| {
for (i, pred) in params.where_predicates().enumerate() { for (i, pred) in params.where_predicates().enumerate() {
if i != 0 { if i != 0 {
@ -592,8 +604,8 @@ impl Printer<'_> {
wln!( wln!(
this, this,
"{}: {},", "{}: {},",
target.name.display(self.db.upcast()), target.name.display(self.db.upcast(), edition),
bound.name.display(self.db.upcast()) bound.name.display(self.db.upcast(), edition)
); );
continue; continue;
} }
@ -603,7 +615,7 @@ impl Printer<'_> {
if i != 0 { if i != 0 {
w!(this, ", "); w!(this, ", ");
} }
w!(this, "{}", lt.display(self.db.upcast())); w!(this, "{}", lt.display(self.db.upcast(), edition));
} }
w!(this, "> "); w!(this, "> ");
(target, bound) (target, bound)
@ -613,7 +625,7 @@ impl Printer<'_> {
match target { match target {
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty), WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() { WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
Some(name) => w!(this, "{}", name.display(self.db.upcast())), Some(name) => w!(this, "{}", name.display(self.db.upcast(), edition)),
None => w!(this, "_anon_{}", id.into_raw()), None => w!(this, "_anon_{}", id.into_raw()),
}, },
} }

View file

@ -1,4 +1,5 @@
use expect_test::{expect, Expect}; use expect_test::{expect, Expect};
use span::Edition;
use test_fixture::WithFixture; use test_fixture::WithFixture;
use crate::{db::DefDatabase, test_db::TestDB}; use crate::{db::DefDatabase, test_db::TestDB};
@ -6,7 +7,7 @@ use crate::{db::DefDatabase, test_db::TestDB};
fn check(ra_fixture: &str, expect: Expect) { fn check(ra_fixture: &str, expect: Expect) {
let (db, file_id) = TestDB::with_single_file(ra_fixture); let (db, file_id) = TestDB::with_single_file(ra_fixture);
let item_tree = db.file_item_tree(file_id.into()); let item_tree = db.file_item_tree(file_id.into());
let pretty = item_tree.pretty_print(&db); let pretty = item_tree.pretty_print(&db, Edition::CURRENT);
expect.assert_eq(&pretty); expect.assert_eq(&pretty);
} }

View file

@ -328,6 +328,10 @@ impl DefMap {
/// The module id of a crate or block root. /// The module id of a crate or block root.
pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0)); pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
pub fn edition(&self) -> Edition {
self.data.edition
}
pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: CrateId) -> Arc<DefMap> { pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: CrateId) -> Arc<DefMap> {
let crate_graph = db.crate_graph(); let crate_graph = db.crate_graph();
let krate = &crate_graph[crate_id]; let krate = &crate_graph[crate_id];
@ -550,7 +554,7 @@ impl DefMap {
for (name, child) in for (name, child) in
map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
{ {
let path = format!("{path}::{}", name.display(db.upcast())); let path = format!("{path}::{}", name.display(db.upcast(), Edition::LATEST));
buf.push('\n'); buf.push('\n');
go(buf, db, map, &path, *child); go(buf, db, map, &path, *child);
} }

View file

@ -548,7 +548,7 @@ impl DefCollector<'_> {
types => { types => {
tracing::debug!( tracing::debug!(
"could not resolve prelude path `{}` to module (resolved to {:?})", "could not resolve prelude path `{}` to module (resolved to {:?})",
path.display(self.db.upcast()), path.display(self.db.upcast(), Edition::LATEST),
types types
); );
} }
@ -768,7 +768,7 @@ impl DefCollector<'_> {
} }
fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db.upcast())) let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db.upcast(), Edition::LATEST))
.entered(); .entered();
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition); tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
match import.source { match import.source {
@ -2151,7 +2151,7 @@ impl ModCollector<'_, '_> {
} }
tracing::debug!( tracing::debug!(
"non-builtin attribute {}", "non-builtin attribute {}",
attr.path.display(self.def_collector.db.upcast()) attr.path.display(self.def_collector.db.upcast(), Edition::LATEST)
); );
let ast_id = AstIdWithPath::new( let ast_id = AstIdWithPath::new(
@ -2286,8 +2286,8 @@ impl ModCollector<'_, '_> {
stdx::always!( stdx::always!(
name == mac.name, name == mac.name,
"built-in macro {} has #[rustc_builtin_macro] which declares different name {}", "built-in macro {} has #[rustc_builtin_macro] which declares different name {}",
mac.name.display(self.def_collector.db.upcast()), mac.name.display(self.def_collector.db.upcast(), Edition::LATEST),
name.display(self.def_collector.db.upcast()) name.display(self.def_collector.db.upcast(), Edition::LATEST),
); );
helpers_opt = Some(helpers); helpers_opt = Some(helpers);
} }

View file

@ -1,6 +1,7 @@
use expect_test::expect; use expect_test::expect;
use itertools::Itertools; use itertools::Itertools;
use span::Edition;
use super::*; use super::*;
@ -1100,7 +1101,7 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
assert_eq!(def_map.data.exported_derives.len(), 1); assert_eq!(def_map.data.exported_derives.len(), 1);
match def_map.data.exported_derives.values().next() { match def_map.data.exported_derives.values().next() {
Some(helpers) => match &**helpers { Some(helpers) => match &**helpers {
[attr] => assert_eq!(attr.display(&db).to_string(), "helper_attr"), [attr] => assert_eq!(attr.display(&db, Edition::CURRENT).to_string(), "helper_attr"),
_ => unreachable!(), _ => unreachable!(),
}, },
_ => unreachable!(), _ => unreachable!(),
@ -1456,7 +1457,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
let actual = def_map let actual = def_map
.macro_use_prelude .macro_use_prelude
.keys() .keys()
.map(|name| name.display(&db).to_string()) .map(|name| name.display(&db, Edition::CURRENT).to_string())
.sorted() .sorted()
.join("\n"); .join("\n");

View file

@ -144,14 +144,14 @@ pub struct Baz;
crate::r#async crate::r#async
Bar: t v Bar: t v
foo: t
r#async: t r#async: t
foo: t
crate::r#async::foo
Foo: t v
crate::r#async::r#async crate::r#async::r#async
Baz: t v Baz: t v
crate::r#async::foo
Foo: t v
"#]], "#]],
); );
} }

View file

@ -13,7 +13,8 @@ use crate::{
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::Interned; use intern::Interned;
use syntax::{ast, ToSmolStr}; use span::Edition;
use syntax::ast;
pub use hir_expand::mod_path::{path, ModPath, PathKind}; pub use hir_expand::mod_path::{path, ModPath, PathKind};
@ -25,11 +26,21 @@ pub enum ImportAlias {
Alias(Name), Alias(Name),
} }
impl Display for ImportAlias { impl ImportAlias {
pub fn display(&self, edition: Edition) -> impl Display + '_ {
ImportAliasDisplay { value: self, edition }
}
}
struct ImportAliasDisplay<'a> {
value: &'a ImportAlias,
edition: Edition,
}
impl Display for ImportAliasDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self.value {
ImportAlias::Underscore => f.write_str("_"), ImportAlias::Underscore => f.write_str("_"),
ImportAlias::Alias(name) => f.write_str(&name.display_no_db().to_smolstr()), ImportAlias::Alias(name) => Display::fmt(&name.display_no_db(self.edition), f),
} }
} }
} }

View file

@ -5,6 +5,7 @@ use std::fmt::{self, Write};
use hir_expand::mod_path::PathKind; use hir_expand::mod_path::PathKind;
use intern::Interned; use intern::Interned;
use itertools::Itertools; use itertools::Itertools;
use span::Edition;
use crate::{ use crate::{
db::DefDatabase, db::DefDatabase,
@ -13,46 +14,51 @@ use crate::{
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef}, type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
}; };
pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result { pub(crate) fn print_path(
db: &dyn DefDatabase,
path: &Path,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
if let Path::LangItem(it, s) = path { if let Path::LangItem(it, s) = path {
write!(buf, "builtin#lang(")?; write!(buf, "builtin#lang(")?;
match *it { match *it {
LangItemTarget::ImplDef(it) => write!(buf, "{it:?}")?, LangItemTarget::ImplDef(it) => write!(buf, "{it:?}")?,
LangItemTarget::EnumId(it) => { LangItemTarget::EnumId(it) => {
write!(buf, "{}", db.enum_data(it).name.display(db.upcast()))? write!(buf, "{}", db.enum_data(it).name.display(db.upcast(), edition))?
} }
LangItemTarget::Function(it) => { LangItemTarget::Function(it) => {
write!(buf, "{}", db.function_data(it).name.display(db.upcast()))? write!(buf, "{}", db.function_data(it).name.display(db.upcast(), edition))?
} }
LangItemTarget::Static(it) => { LangItemTarget::Static(it) => {
write!(buf, "{}", db.static_data(it).name.display(db.upcast()))? write!(buf, "{}", db.static_data(it).name.display(db.upcast(), edition))?
} }
LangItemTarget::Struct(it) => { LangItemTarget::Struct(it) => {
write!(buf, "{}", db.struct_data(it).name.display(db.upcast()))? write!(buf, "{}", db.struct_data(it).name.display(db.upcast(), edition))?
} }
LangItemTarget::Union(it) => { LangItemTarget::Union(it) => {
write!(buf, "{}", db.union_data(it).name.display(db.upcast()))? write!(buf, "{}", db.union_data(it).name.display(db.upcast(), edition))?
} }
LangItemTarget::TypeAlias(it) => { LangItemTarget::TypeAlias(it) => {
write!(buf, "{}", db.type_alias_data(it).name.display(db.upcast()))? write!(buf, "{}", db.type_alias_data(it).name.display(db.upcast(), edition))?
} }
LangItemTarget::Trait(it) => { LangItemTarget::Trait(it) => {
write!(buf, "{}", db.trait_data(it).name.display(db.upcast()))? write!(buf, "{}", db.trait_data(it).name.display(db.upcast(), edition))?
} }
LangItemTarget::EnumVariant(it) => { LangItemTarget::EnumVariant(it) => {
write!(buf, "{}", db.enum_variant_data(it).name.display(db.upcast()))? write!(buf, "{}", db.enum_variant_data(it).name.display(db.upcast(), edition))?
} }
} }
if let Some(s) = s { if let Some(s) = s {
write!(buf, "::{}", s.display(db.upcast()))?; write!(buf, "::{}", s.display(db.upcast(), edition))?;
} }
return write!(buf, ")"); return write!(buf, ")");
} }
match path.type_anchor() { match path.type_anchor() {
Some(anchor) => { Some(anchor) => {
write!(buf, "<")?; write!(buf, "<")?;
print_type_ref(db, anchor, buf)?; print_type_ref(db, anchor, buf, edition)?;
write!(buf, ">::")?; write!(buf, ">::")?;
} }
None => match path.kind() { None => match path.kind() {
@ -78,10 +84,10 @@ pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write)
write!(buf, "::")?; write!(buf, "::")?;
} }
write!(buf, "{}", segment.name.display(db.upcast()))?; write!(buf, "{}", segment.name.display(db.upcast(), edition))?;
if let Some(generics) = segment.args_and_bindings { if let Some(generics) = segment.args_and_bindings {
write!(buf, "::<")?; write!(buf, "::<")?;
print_generic_args(db, generics, buf)?; print_generic_args(db, generics, buf, edition)?;
write!(buf, ">")?; write!(buf, ">")?;
} }
@ -94,12 +100,13 @@ pub(crate) fn print_generic_args(
db: &dyn DefDatabase, db: &dyn DefDatabase,
generics: &GenericArgs, generics: &GenericArgs,
buf: &mut dyn Write, buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result { ) -> fmt::Result {
let mut first = true; let mut first = true;
let args = if generics.has_self_type { let args = if generics.has_self_type {
let (self_ty, args) = generics.args.split_first().unwrap(); let (self_ty, args) = generics.args.split_first().unwrap();
write!(buf, "Self=")?; write!(buf, "Self=")?;
print_generic_arg(db, self_ty, buf)?; print_generic_arg(db, self_ty, buf, edition)?;
first = false; first = false;
args args
} else { } else {
@ -110,21 +117,21 @@ pub(crate) fn print_generic_args(
write!(buf, ", ")?; write!(buf, ", ")?;
} }
first = false; first = false;
print_generic_arg(db, arg, buf)?; print_generic_arg(db, arg, buf, edition)?;
} }
for binding in generics.bindings.iter() { for binding in generics.bindings.iter() {
if !first { if !first {
write!(buf, ", ")?; write!(buf, ", ")?;
} }
first = false; first = false;
write!(buf, "{}", binding.name.display(db.upcast()))?; write!(buf, "{}", binding.name.display(db.upcast(), edition))?;
if !binding.bounds.is_empty() { if !binding.bounds.is_empty() {
write!(buf, ": ")?; write!(buf, ": ")?;
print_type_bounds(db, &binding.bounds, buf)?; print_type_bounds(db, &binding.bounds, buf, edition)?;
} }
if let Some(ty) = &binding.type_ref { if let Some(ty) = &binding.type_ref {
write!(buf, " = ")?; write!(buf, " = ")?;
print_type_ref(db, ty, buf)?; print_type_ref(db, ty, buf, edition)?;
} }
} }
Ok(()) Ok(())
@ -134,11 +141,12 @@ pub(crate) fn print_generic_arg(
db: &dyn DefDatabase, db: &dyn DefDatabase,
arg: &GenericArg, arg: &GenericArg,
buf: &mut dyn Write, buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result { ) -> fmt::Result {
match arg { match arg {
GenericArg::Type(ty) => print_type_ref(db, ty, buf), GenericArg::Type(ty) => print_type_ref(db, ty, buf, edition),
GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast())), GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast(), edition)),
GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast())), GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition)),
} }
} }
@ -146,6 +154,7 @@ pub(crate) fn print_type_ref(
db: &dyn DefDatabase, db: &dyn DefDatabase,
type_ref: &TypeRef, type_ref: &TypeRef,
buf: &mut dyn Write, buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result { ) -> fmt::Result {
// FIXME: deduplicate with `HirDisplay` impl // FIXME: deduplicate with `HirDisplay` impl
match type_ref { match type_ref {
@ -157,18 +166,18 @@ pub(crate) fn print_type_ref(
if i != 0 { if i != 0 {
write!(buf, ", ")?; write!(buf, ", ")?;
} }
print_type_ref(db, field, buf)?; print_type_ref(db, field, buf, edition)?;
} }
write!(buf, ")")?; write!(buf, ")")?;
} }
TypeRef::Path(path) => print_path(db, path, buf)?, TypeRef::Path(path) => print_path(db, path, buf, edition)?,
TypeRef::RawPtr(pointee, mtbl) => { TypeRef::RawPtr(pointee, mtbl) => {
let mtbl = match mtbl { let mtbl = match mtbl {
Mutability::Shared => "*const", Mutability::Shared => "*const",
Mutability::Mut => "*mut", Mutability::Mut => "*mut",
}; };
write!(buf, "{mtbl} ")?; write!(buf, "{mtbl} ")?;
print_type_ref(db, pointee, buf)?; print_type_ref(db, pointee, buf, edition)?;
} }
TypeRef::Reference(pointee, lt, mtbl) => { TypeRef::Reference(pointee, lt, mtbl) => {
let mtbl = match mtbl { let mtbl = match mtbl {
@ -177,19 +186,19 @@ pub(crate) fn print_type_ref(
}; };
write!(buf, "&")?; write!(buf, "&")?;
if let Some(lt) = lt { if let Some(lt) = lt {
write!(buf, "{} ", lt.name.display(db.upcast()))?; write!(buf, "{} ", lt.name.display(db.upcast(), edition))?;
} }
write!(buf, "{mtbl}")?; write!(buf, "{mtbl}")?;
print_type_ref(db, pointee, buf)?; print_type_ref(db, pointee, buf, edition)?;
} }
TypeRef::Array(elem, len) => { TypeRef::Array(elem, len) => {
write!(buf, "[")?; write!(buf, "[")?;
print_type_ref(db, elem, buf)?; print_type_ref(db, elem, buf, edition)?;
write!(buf, "; {}]", len.display(db.upcast()))?; write!(buf, "; {}]", len.display(db.upcast(), edition))?;
} }
TypeRef::Slice(elem) => { TypeRef::Slice(elem) => {
write!(buf, "[")?; write!(buf, "[")?;
print_type_ref(db, elem, buf)?; print_type_ref(db, elem, buf, edition)?;
write!(buf, "]")?; write!(buf, "]")?;
} }
TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => { TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => {
@ -208,7 +217,7 @@ pub(crate) fn print_type_ref(
if i != 0 { if i != 0 {
write!(buf, ", ")?; write!(buf, ", ")?;
} }
print_type_ref(db, typeref, buf)?; print_type_ref(db, typeref, buf, edition)?;
} }
if *varargs { if *varargs {
if !args.is_empty() { if !args.is_empty() {
@ -217,7 +226,7 @@ pub(crate) fn print_type_ref(
write!(buf, "...")?; write!(buf, "...")?;
} }
write!(buf, ") -> ")?; write!(buf, ") -> ")?;
print_type_ref(db, return_type, buf)?; print_type_ref(db, return_type, buf, edition)?;
} }
TypeRef::Macro(_ast_id) => { TypeRef::Macro(_ast_id) => {
write!(buf, "<macro>")?; write!(buf, "<macro>")?;
@ -225,11 +234,11 @@ pub(crate) fn print_type_ref(
TypeRef::Error => write!(buf, "{{unknown}}")?, TypeRef::Error => write!(buf, "{{unknown}}")?,
TypeRef::ImplTrait(bounds) => { TypeRef::ImplTrait(bounds) => {
write!(buf, "impl ")?; write!(buf, "impl ")?;
print_type_bounds(db, bounds, buf)?; print_type_bounds(db, bounds, buf, edition)?;
} }
TypeRef::DynTrait(bounds) => { TypeRef::DynTrait(bounds) => {
write!(buf, "dyn ")?; write!(buf, "dyn ")?;
print_type_bounds(db, bounds, buf)?; print_type_bounds(db, bounds, buf, edition)?;
} }
} }
@ -240,6 +249,7 @@ pub(crate) fn print_type_bounds(
db: &dyn DefDatabase, db: &dyn DefDatabase,
bounds: &[Interned<TypeBound>], bounds: &[Interned<TypeBound>],
buf: &mut dyn Write, buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result { ) -> fmt::Result {
for (i, bound) in bounds.iter().enumerate() { for (i, bound) in bounds.iter().enumerate() {
if i != 0 { if i != 0 {
@ -252,17 +262,17 @@ pub(crate) fn print_type_bounds(
TraitBoundModifier::None => (), TraitBoundModifier::None => (),
TraitBoundModifier::Maybe => write!(buf, "?")?, TraitBoundModifier::Maybe => write!(buf, "?")?,
} }
print_path(db, path, buf)?; print_path(db, path, buf, edition)?;
} }
TypeBound::ForLifetime(lifetimes, path) => { TypeBound::ForLifetime(lifetimes, path) => {
write!( write!(
buf, buf,
"for<{}> ", "for<{}> ",
lifetimes.iter().map(|it| it.display(db.upcast())).format(", ") lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ")
)?; )?;
print_path(db, path, buf)?; print_path(db, path, buf, edition)?;
} }
TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast()))?, TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
TypeBound::Error => write!(buf, "{{unknown}}")?, TypeBound::Error => write!(buf, "{{unknown}}")?,
} }
} }

View file

@ -176,9 +176,10 @@ fn eager_macro_recur(
Some(path) => match macro_resolver(&path) { Some(path) => match macro_resolver(&path) {
Some(def) => def, Some(def) => def,
None => { None => {
let edition = db.crate_graph()[krate].edition;
error = Some(ExpandError::other( error = Some(ExpandError::other(
span_map.span_at(call.syntax().text_range().start()), span_map.span_at(call.syntax().text_range().start()),
format!("unresolved macro {}", path.display(db)), format!("unresolved macro {}", path.display(db, edition)),
)); ));
offset += call.syntax().text_range().len(); offset += call.syntax().text_range().len();
continue; continue;

View file

@ -14,7 +14,7 @@ use crate::{
use base_db::CrateId; use base_db::CrateId;
use intern::sym; use intern::sym;
use smallvec::SmallVec; use smallvec::SmallVec;
use span::SyntaxContextId; use span::{Edition, SyntaxContextId};
use syntax::{ast, AstNode}; use syntax::{ast, AstNode};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -140,8 +140,12 @@ impl ModPath {
UnescapedModPath(self) UnescapedModPath(self)
} }
pub fn display<'a>(&'a self, db: &'a dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { pub fn display<'a>(
Display { db, path: self } &'a self,
db: &'a dyn crate::db::ExpandDatabase,
edition: Edition,
) -> impl fmt::Display + 'a {
Display { db, path: self, edition }
} }
} }
@ -154,11 +158,12 @@ impl Extend<Name> for ModPath {
struct Display<'a> { struct Display<'a> {
db: &'a dyn ExpandDatabase, db: &'a dyn ExpandDatabase,
path: &'a ModPath, path: &'a ModPath,
edition: Edition,
} }
impl fmt::Display for Display<'_> { impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
display_fmt_path(self.db, self.path, f, true) display_fmt_path(self.db, self.path, f, Escape::IfNeeded(self.edition))
} }
} }
@ -169,7 +174,7 @@ struct UnescapedDisplay<'a> {
impl fmt::Display for UnescapedDisplay<'_> { impl fmt::Display for UnescapedDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
display_fmt_path(self.db, self.path.0, f, false) display_fmt_path(self.db, self.path.0, f, Escape::No)
} }
} }
@ -178,11 +183,17 @@ impl From<Name> for ModPath {
ModPath::from_segments(PathKind::Plain, iter::once(name)) ModPath::from_segments(PathKind::Plain, iter::once(name))
} }
} }
enum Escape {
No,
IfNeeded(Edition),
}
fn display_fmt_path( fn display_fmt_path(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
path: &ModPath, path: &ModPath,
f: &mut fmt::Formatter<'_>, f: &mut fmt::Formatter<'_>,
escaped: bool, escaped: Escape,
) -> fmt::Result { ) -> fmt::Result {
let mut first_segment = true; let mut first_segment = true;
let mut add_segment = |s| -> fmt::Result { let mut add_segment = |s| -> fmt::Result {
@ -210,10 +221,9 @@ fn display_fmt_path(
f.write_str("::")?; f.write_str("::")?;
} }
first_segment = false; first_segment = false;
if escaped { match escaped {
segment.display(db).fmt(f)?; Escape::IfNeeded(edition) => segment.display(db, edition).fmt(f)?,
} else { Escape::No => segment.unescaped().display(db).fmt(f)?,
segment.unescaped().display(db).fmt(f)?;
} }
} }
Ok(()) Ok(())
@ -322,9 +332,11 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::self_ => PathKind::SELF, tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::self_ => PathKind::SELF,
tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::super_ => { tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::super_ => {
let mut deg = 1; let mut deg = 1;
while let Some(tt::Leaf::Ident(tt::Ident { sym: text, span, is_raw })) = leaves.next() { while let Some(tt::Leaf::Ident(tt::Ident { sym: text, span, is_raw: _ })) =
leaves.next()
{
if *text != sym::super_ { if *text != sym::super_ {
segments.push(Name::new_symbol_maybe_raw(text.clone(), *is_raw, span.ctx)); segments.push(Name::new_symbol(text.clone(), span.ctx));
break; break;
} }
deg += 1; deg += 1;
@ -333,19 +345,13 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
} }
tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::crate_ => PathKind::Crate, tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::crate_ => PathKind::Crate,
tt::Leaf::Ident(ident) => { tt::Leaf::Ident(ident) => {
segments.push(Name::new_symbol_maybe_raw( segments.push(Name::new_symbol(ident.sym.clone(), ident.span.ctx));
ident.sym.clone(),
ident.is_raw,
ident.span.ctx,
));
PathKind::Plain PathKind::Plain
} }
_ => return None, _ => return None,
}; };
segments.extend(leaves.filter_map(|leaf| match leaf { segments.extend(leaves.filter_map(|leaf| match leaf {
::tt::Leaf::Ident(ident) => { ::tt::Leaf::Ident(ident) => Some(Name::new_symbol(ident.sym.clone(), ident.span.ctx)),
Some(Name::new_symbol_maybe_raw(ident.sym.clone(), ident.is_raw, ident.span.ctx))
}
_ => None, _ => None,
})); }));
Some(ModPath { kind, segments }) Some(ModPath { kind, segments })

View file

@ -3,22 +3,22 @@
use std::fmt; use std::fmt;
use intern::{sym, Symbol}; use intern::{sym, Symbol};
use span::SyntaxContextId; use span::{Edition, SyntaxContextId};
use syntax::{ast, utils::is_raw_identifier}; use syntax::ast;
use syntax::utils::is_raw_identifier;
/// `Name` is a wrapper around string, which is used in hir for both references /// `Name` is a wrapper around string, which is used in hir for both references
/// and declarations. In theory, names should also carry hygiene info, but we are /// and declarations. In theory, names should also carry hygiene info, but we are
/// not there yet! /// not there yet!
/// ///
/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it /// Note that the rawness (`r#`) of names does not depend on whether they are written raw.
/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the /// This is because we want to show (in completions etc.) names as raw depending on the needs
/// name without "r#". /// of the current crate, for example if it is edition 2021 complete `gen` even if the defining
/// crate is in edition 2024 and wrote `r#gen`, and the opposite holds as well.
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub struct Name { pub struct Name {
symbol: Symbol, symbol: Symbol,
ctx: (), ctx: (),
// FIXME: We should probably encode rawness as a property here instead, once we have hygiene
// in here we've got 4 bytes of padding to fill anyways
} }
impl fmt::Debug for Name { impl fmt::Debug for Name {
@ -42,6 +42,7 @@ impl PartialOrd for Name {
} }
} }
// No need to strip `r#`, all comparisons are done against well-known symbols.
impl PartialEq<Symbol> for Name { impl PartialEq<Symbol> for Name {
fn eq(&self, sym: &Symbol) -> bool { fn eq(&self, sym: &Symbol) -> bool {
self.symbol == *sym self.symbol == *sym
@ -55,16 +56,16 @@ impl PartialEq<Name> for Symbol {
} }
/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier. /// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UnescapedName<'a>(&'a Name); pub struct UnescapedName<'a>(&'a Name);
impl UnescapedName<'_> { impl<'a> UnescapedName<'a> {
pub fn display(&self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + '_ { pub fn display(self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
_ = db; _ = db;
UnescapedDisplay { name: self } UnescapedDisplay { name: self }
} }
#[doc(hidden)] #[doc(hidden)]
pub fn display_no_db(&self) -> impl fmt::Display + '_ { pub fn display_no_db(self) -> impl fmt::Display + 'a {
UnescapedDisplay { name: self } UnescapedDisplay { name: self }
} }
} }
@ -77,16 +78,9 @@ impl Name {
Name { symbol: Symbol::intern(text), ctx: () } Name { symbol: Symbol::intern(text), ctx: () }
} }
pub fn new(text: &str, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Name { pub fn new(text: &str, ctx: SyntaxContextId) -> Name {
_ = ctx; _ = ctx;
Name { Self::new_text(text)
symbol: if raw.yes() {
Symbol::intern(&format!("{}{text}", raw.as_str()))
} else {
Symbol::intern(text)
},
ctx: (),
}
} }
pub fn new_tuple_field(idx: usize) -> Name { pub fn new_tuple_field(idx: usize) -> Name {
@ -97,26 +91,9 @@ impl Name {
Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () } Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () }
} }
/// Shortcut to create a name from a string literal.
fn new_ref(text: &str) -> Name {
Name { symbol: Symbol::intern(text), ctx: () }
}
/// Resolve a name from the text of token. /// Resolve a name from the text of token.
fn resolve(raw_text: &str) -> Name { fn resolve(raw_text: &str) -> Name {
// FIXME: Edition Name::new_text(raw_text.trim_start_matches("r#"))
match raw_text.strip_prefix("r#") {
// When `raw_text` starts with "r#" but the name does not coincide with any
// keyword, we never need the prefix so we strip it.
Some(text) if !is_raw_identifier(text, span::Edition::CURRENT) => Name::new_ref(text),
// Keywords (in the current edition) *can* be used as a name in earlier editions of
// Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their
// escaped form.
None if is_raw_identifier(raw_text, span::Edition::CURRENT) => {
Name::new_text(&format!("r#{}", raw_text))
}
_ => Name::new_text(raw_text),
}
} }
/// A fake name for things missing in the source code. /// A fake name for things missing in the source code.
@ -162,19 +139,23 @@ impl Name {
UnescapedName(self) UnescapedName(self)
} }
pub fn is_escaped(&self) -> bool { pub fn is_escaped(&self, edition: Edition) -> bool {
self.symbol.as_str().starts_with("r#") is_raw_identifier(self.symbol.as_str(), edition)
} }
pub fn display<'a>(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { pub fn display<'a>(
&'a self,
db: &dyn crate::db::ExpandDatabase,
edition: Edition,
) -> impl fmt::Display + 'a {
_ = db; _ = db;
Display { name: self } self.display_no_db(edition)
} }
// FIXME: Remove this // FIXME: Remove this
#[doc(hidden)] #[doc(hidden)]
pub fn display_no_db(&self) -> impl fmt::Display + '_ { pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ {
Display { name: self } Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) }
} }
pub fn symbol(&self) -> &Symbol { pub fn symbol(&self) -> &Symbol {
@ -186,39 +167,39 @@ impl Name {
Self { symbol, ctx: () } Self { symbol, ctx: () }
} }
pub fn new_symbol_maybe_raw(sym: Symbol, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Self {
if raw.no() {
Self { symbol: sym, ctx: () }
} else {
Name::new(sym.as_str(), raw, ctx)
}
}
// FIXME: This needs to go once we have hygiene // FIXME: This needs to go once we have hygiene
pub const fn new_symbol_root(sym: Symbol) -> Self { pub const fn new_symbol_root(sym: Symbol) -> Self {
Self { symbol: sym, ctx: () } Self { symbol: sym, ctx: () }
} }
#[inline]
pub fn eq_ident(&self, ident: &str) -> bool {
self.as_str() == ident.trim_start_matches("r#")
}
} }
struct Display<'a> { struct Display<'a> {
name: &'a Name, name: &'a Name,
needs_escaping: bool,
} }
impl fmt::Display for Display<'_> { impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.needs_escaping {
write!(f, "r#")?;
}
fmt::Display::fmt(self.name.symbol.as_str(), f) fmt::Display::fmt(self.name.symbol.as_str(), f)
} }
} }
struct UnescapedDisplay<'a> { struct UnescapedDisplay<'a> {
name: &'a UnescapedName<'a>, name: UnescapedName<'a>,
} }
impl fmt::Display for UnescapedDisplay<'_> { impl fmt::Display for UnescapedDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let symbol = &self.name.0.symbol.as_str(); let symbol = self.name.0.symbol.as_str();
let text = symbol.strip_prefix("r#").unwrap_or(symbol); fmt::Display::fmt(symbol, f)
fmt::Display::fmt(&text, f)
} }
} }

View file

@ -5,6 +5,7 @@ use std::{iter, ops::ControlFlow, sync::Arc};
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::sym; use intern::sym;
use span::Edition;
use tracing::debug; use tracing::debug;
use chalk_ir::{cast::Caster, fold::shift::Shift, CanonicalVarKinds}; use chalk_ir::{cast::Caster, fold::shift::Shift, CanonicalVarKinds};
@ -424,18 +425,19 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String { fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String {
let id = from_chalk_trait_id(trait_id); let id = from_chalk_trait_id(trait_id);
self.db.trait_data(id).name.display(self.db.upcast()).to_string() self.db.trait_data(id).name.display(self.db.upcast(), self.edition()).to_string()
} }
fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String { fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String {
let edition = self.edition();
match adt_id { match adt_id {
hir_def::AdtId::StructId(id) => { hir_def::AdtId::StructId(id) => {
self.db.struct_data(id).name.display(self.db.upcast()).to_string() self.db.struct_data(id).name.display(self.db.upcast(), edition).to_string()
} }
hir_def::AdtId::EnumId(id) => { hir_def::AdtId::EnumId(id) => {
self.db.enum_data(id).name.display(self.db.upcast()).to_string() self.db.enum_data(id).name.display(self.db.upcast(), edition).to_string()
} }
hir_def::AdtId::UnionId(id) => { hir_def::AdtId::UnionId(id) => {
self.db.union_data(id).name.display(self.db.upcast()).to_string() self.db.union_data(id).name.display(self.db.upcast(), edition).to_string()
} }
} }
} }
@ -445,7 +447,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
} }
fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String { fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String {
let id = self.db.associated_ty_data(assoc_ty_id).name; let id = self.db.associated_ty_data(assoc_ty_id).name;
self.db.type_alias_data(id).name.display(self.db.upcast()).to_string() self.db.type_alias_data(id).name.display(self.db.upcast(), self.edition()).to_string()
} }
fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String { fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String {
format!("Opaque_{}", opaque_ty_id.0) format!("Opaque_{}", opaque_ty_id.0)
@ -519,6 +521,10 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
} }
impl<'a> ChalkContext<'a> { impl<'a> ChalkContext<'a> {
fn edition(&self) -> Edition {
self.db.crate_graph()[self.krate].edition
}
fn for_trait_impls( fn for_trait_impls(
&self, &self,
trait_id: hir_def::TraitId, trait_id: hir_def::TraitId,
@ -843,7 +849,7 @@ fn impl_def_datum(
"impl {:?}: {}{} where {:?}", "impl {:?}: {}{} where {:?}",
chalk_id, chalk_id,
if negative { "!" } else { "" }, if negative { "!" } else { "" },
trait_ref.display(db), trait_ref.display(db, db.crate_graph()[krate].edition),
where_clauses where_clauses
); );

View file

@ -1,3 +1,4 @@
use base_db::SourceDatabase;
use chalk_ir::Substitution; use chalk_ir::Substitution;
use hir_def::db::DefDatabase; use hir_def::db::DefDatabase;
use rustc_apfloat::{ use rustc_apfloat::{
@ -94,9 +95,10 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) {
fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String { fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String {
let mut err = String::new(); let mut err = String::new();
let span_formatter = |file, range| format!("{file:?} {range:?}"); let span_formatter = |file, range| format!("{file:?} {range:?}");
let edition = db.crate_graph()[db.test_crate()].edition;
match e { match e {
ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter), ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter, edition),
ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter), ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter, edition),
} }
.unwrap(); .unwrap();
err err
@ -110,7 +112,9 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result<Const, ConstEvalEr
.declarations() .declarations()
.find_map(|x| match x { .find_map(|x| match x {
hir_def::ModuleDefId::ConstId(x) => { hir_def::ModuleDefId::ConstId(x) => {
if db.const_data(x).name.as_ref()?.display(db).to_string() == "GOAL" { if db.const_data(x).name.as_ref()?.display(db, file_id.edition()).to_string()
== "GOAL"
{
Some(x) Some(x)
} else { } else {
None None

View file

@ -17,17 +17,18 @@ use std::fmt;
use hir_def::{ use hir_def::{
data::adt::VariantData, db::DefDatabase, hir::Pat, src::HasSource, AdtId, AttrDefId, ConstId, data::adt::VariantData, db::DefDatabase, hir::Pat, src::HasSource, AdtId, AttrDefId, ConstId,
EnumId, EnumVariantId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId, StaticId, EnumId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId,
StructId, TraitId, TypeAliasId, StaticId, StructId, TraitId, TypeAliasId,
}; };
use hir_expand::{ use hir_expand::{
name::{AsName, Name}, name::{AsName, Name},
HirFileId, MacroFileIdExt, HirFileId, HirFileIdExt, MacroFileIdExt,
}; };
use intern::sym; use intern::sym;
use stdx::{always, never}; use stdx::{always, never};
use syntax::{ use syntax::{
ast::{self, HasName}, ast::{self, HasName},
utils::is_raw_identifier,
AstNode, AstPtr, ToSmolStr, AstNode, AstPtr, ToSmolStr,
}; };
@ -318,17 +319,21 @@ impl<'a> DeclValidator<'a> {
/// This includes function parameters except for trait implementation associated functions. /// This includes function parameters except for trait implementation associated functions.
fn validate_func_body(&mut self, func: FunctionId) { fn validate_func_body(&mut self, func: FunctionId) {
let body = self.db.body(func.into()); let body = self.db.body(func.into());
let edition = self.edition(func);
let mut pats_replacements = body let mut pats_replacements = body
.pats .pats
.iter() .iter()
.filter_map(|(pat_id, pat)| match pat { .filter_map(|(pat_id, pat)| match pat {
Pat::Bind { id, .. } => { Pat::Bind { id, .. } => {
let bind_name = &body.bindings[*id].name; let bind_name = &body.bindings[*id].name;
let mut suggested_text =
to_lower_snake_case(&bind_name.unescaped().display_no_db().to_smolstr())?;
if is_raw_identifier(&suggested_text, edition) {
suggested_text.insert_str(0, "r#");
}
let replacement = Replacement { let replacement = Replacement {
current_name: bind_name.clone(), current_name: bind_name.clone(),
suggested_text: to_lower_snake_case( suggested_text,
&bind_name.display_no_db().to_smolstr(),
)?,
expected_case: CaseType::LowerSnakeCase, expected_case: CaseType::LowerSnakeCase,
}; };
Some((pat_id, replacement)) Some((pat_id, replacement))
@ -377,6 +382,11 @@ impl<'a> DeclValidator<'a> {
} }
} }
fn edition(&self, id: impl HasModule) -> span::Edition {
let krate = id.krate(self.db.upcast());
self.db.crate_graph()[krate].edition
}
fn validate_struct(&mut self, struct_id: StructId) { fn validate_struct(&mut self, struct_id: StructId) {
// Check the structure name. // Check the structure name.
let non_camel_case_allowed = let non_camel_case_allowed =
@ -405,16 +415,17 @@ impl<'a> DeclValidator<'a> {
let VariantData::Record(fields) = data.variant_data.as_ref() else { let VariantData::Record(fields) = data.variant_data.as_ref() else {
return; return;
}; };
let edition = self.edition(struct_id);
let mut struct_fields_replacements = fields let mut struct_fields_replacements = fields
.iter() .iter()
.filter_map(|(_, field)| { .filter_map(|(_, field)| {
to_lower_snake_case(&field.name.display_no_db().to_smolstr()).map(|new_name| { to_lower_snake_case(&field.name.display_no_db(edition).to_smolstr()).map(
Replacement { |new_name| Replacement {
current_name: field.name.clone(), current_name: field.name.clone(),
suggested_text: new_name, suggested_text: new_name,
expected_case: CaseType::LowerSnakeCase, expected_case: CaseType::LowerSnakeCase,
} },
}) )
}) })
.peekable(); .peekable();
@ -498,14 +509,17 @@ impl<'a> DeclValidator<'a> {
self.validate_enum_variant_fields(*variant_id); self.validate_enum_variant_fields(*variant_id);
} }
let edition = self.edition(enum_id);
let mut enum_variants_replacements = data let mut enum_variants_replacements = data
.variants .variants
.iter() .iter()
.filter_map(|(_, name)| { .filter_map(|(_, name)| {
to_camel_case(&name.display_no_db().to_smolstr()).map(|new_name| Replacement { to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| {
Replacement {
current_name: name.clone(), current_name: name.clone(),
suggested_text: new_name, suggested_text: new_name,
expected_case: CaseType::UpperCamelCase, expected_case: CaseType::UpperCamelCase,
}
}) })
}) })
.peekable(); .peekable();
@ -566,16 +580,17 @@ impl<'a> DeclValidator<'a> {
let VariantData::Record(fields) = variant_data.variant_data.as_ref() else { let VariantData::Record(fields) = variant_data.variant_data.as_ref() else {
return; return;
}; };
let edition = self.edition(variant_id);
let mut variant_field_replacements = fields let mut variant_field_replacements = fields
.iter() .iter()
.filter_map(|(_, field)| { .filter_map(|(_, field)| {
to_lower_snake_case(&field.name.display_no_db().to_smolstr()).map(|new_name| { to_lower_snake_case(&field.name.display_no_db(edition).to_smolstr()).map(
Replacement { |new_name| Replacement {
current_name: field.name.clone(), current_name: field.name.clone(),
suggested_text: new_name, suggested_text: new_name,
expected_case: CaseType::LowerSnakeCase, expected_case: CaseType::LowerSnakeCase,
} },
}) )
}) })
.peekable(); .peekable();
@ -704,18 +719,22 @@ impl<'a> DeclValidator<'a> {
) where ) where
N: AstNode + HasName + fmt::Debug, N: AstNode + HasName + fmt::Debug,
S: HasSource<Value = N>, S: HasSource<Value = N>,
L: Lookup<Data = S, Database<'a> = dyn DefDatabase + 'a>, L: Lookup<Data = S, Database<'a> = dyn DefDatabase + 'a> + HasModule + Copy,
{ {
let to_expected_case_type = match expected_case { let to_expected_case_type = match expected_case {
CaseType::LowerSnakeCase => to_lower_snake_case, CaseType::LowerSnakeCase => to_lower_snake_case,
CaseType::UpperSnakeCase => to_upper_snake_case, CaseType::UpperSnakeCase => to_upper_snake_case,
CaseType::UpperCamelCase => to_camel_case, CaseType::UpperCamelCase => to_camel_case,
}; };
let Some(replacement) = let edition = self.edition(item_id);
to_expected_case_type(&name.display(self.db.upcast()).to_smolstr()).map(|new_name| { let Some(replacement) = to_expected_case_type(
Replacement { current_name: name.clone(), suggested_text: new_name, expected_case } &name.display(self.db.upcast(), edition).to_smolstr(),
}) )
else { .map(|new_name| Replacement {
current_name: name.clone(),
suggested_text: new_name,
expected_case,
}) else {
return; return;
}; };
@ -748,12 +767,13 @@ impl<'a> DeclValidator<'a> {
return; return;
}; };
let edition = file_id.original_file(self.db.upcast()).edition();
let diagnostic = IncorrectCase { let diagnostic = IncorrectCase {
file: file_id, file: file_id,
ident_type, ident_type,
ident: AstPtr::new(&name_ast), ident: AstPtr::new(&name_ast),
expected_case: replacement.expected_case, expected_case: replacement.expected_case,
ident_text: replacement.current_name.display(self.db.upcast()).to_string(), ident_text: replacement.current_name.display(self.db.upcast(), edition).to_string(),
suggested_text: replacement.suggested_text, suggested_text: replacement.suggested_text,
}; };

View file

@ -4,6 +4,7 @@
use std::fmt; use std::fmt;
use base_db::CrateId;
use chalk_solve::rust_ir::AdtKind; use chalk_solve::rust_ir::AdtKind;
use either::Either; use either::Either;
use hir_def::{ use hir_def::{
@ -15,6 +16,7 @@ use intern::sym;
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use rustc_pattern_analysis::constructor::Constructor; use rustc_pattern_analysis::constructor::Constructor;
use span::Edition;
use syntax::{ use syntax::{
ast::{self, UnaryOp}, ast::{self, UnaryOp},
AstNode, AstNode,
@ -258,7 +260,13 @@ impl ExprValidator {
if !witnesses.is_empty() { if !witnesses.is_empty() {
self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms { self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms {
match_expr, match_expr,
uncovered_patterns: missing_match_arms(&cx, scrut_ty, witnesses, m_arms.is_empty()), uncovered_patterns: missing_match_arms(
&cx,
scrut_ty,
witnesses,
m_arms.is_empty(),
self.owner.krate(db.upcast()),
),
}); });
} }
} }
@ -345,7 +353,13 @@ impl ExprValidator {
if !witnesses.is_empty() { if !witnesses.is_empty() {
self.diagnostics.push(BodyValidationDiagnostic::NonExhaustiveLet { self.diagnostics.push(BodyValidationDiagnostic::NonExhaustiveLet {
pat, pat,
uncovered_patterns: missing_match_arms(&cx, ty, witnesses, false), uncovered_patterns: missing_match_arms(
&cx,
ty,
witnesses,
false,
self.owner.krate(db.upcast()),
),
}); });
} }
} }
@ -616,24 +630,26 @@ fn missing_match_arms<'p>(
scrut_ty: &Ty, scrut_ty: &Ty,
witnesses: Vec<WitnessPat<'p>>, witnesses: Vec<WitnessPat<'p>>,
arms_is_empty: bool, arms_is_empty: bool,
krate: CrateId,
) -> String { ) -> String {
struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>); struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, Edition);
impl fmt::Display for DisplayWitness<'_, '_> { impl fmt::Display for DisplayWitness<'_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let DisplayWitness(witness, cx) = *self; let DisplayWitness(witness, cx, edition) = *self;
let pat = cx.hoist_witness_pat(witness); let pat = cx.hoist_witness_pat(witness);
write!(f, "{}", pat.display(cx.db)) write!(f, "{}", pat.display(cx.db, edition))
} }
} }
let edition = cx.db.crate_graph()[krate].edition;
let non_empty_enum = match scrut_ty.as_adt() { let non_empty_enum = match scrut_ty.as_adt() {
Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(), Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(),
_ => false, _ => false,
}; };
if arms_is_empty && !non_empty_enum { if arms_is_empty && !non_empty_enum {
format!("type `{}` is non-empty", scrut_ty.display(cx.db)) format!("type `{}` is non-empty", scrut_ty.display(cx.db, edition))
} else { } else {
let pat_display = |witness| DisplayWitness(witness, cx); let pat_display = |witness| DisplayWitness(witness, cx, edition);
const LIMIT: usize = 3; const LIMIT: usize = 3;
match &*witnesses { match &*witnesses {
[witness] => format!("`{}` not covered", pat_display(witness)), [witness] => format!("`{}` not covered", pat_display(witness)),

View file

@ -14,6 +14,7 @@ use hir_def::{
body::Body, data::adt::VariantData, hir::PatId, AdtId, EnumVariantId, LocalFieldId, VariantId, body::Body, data::adt::VariantData, hir::PatId, AdtId, EnumVariantId, LocalFieldId, VariantId,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use span::Edition;
use stdx::{always, never}; use stdx::{always, never};
use crate::{ use crate::{
@ -151,7 +152,11 @@ impl<'a> PatCtxt<'a> {
match (bm, ty.kind(Interner)) { match (bm, ty.kind(Interner)) {
(BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty, (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty,
(BindingMode::Ref(_), _) => { (BindingMode::Ref(_), _) => {
never!("`ref {}` has wrong type {:?}", name.display(self.db.upcast()), ty); never!(
"`ref {}` has wrong type {:?}",
name.display(self.db.upcast(), Edition::LATEST),
ty
);
self.errors.push(PatternError::UnexpectedType); self.errors.push(PatternError::UnexpectedType);
return Pat { ty: ty.clone(), kind: PatKind::Wild.into() }; return Pat { ty: ty.clone(), kind: PatKind::Wild.into() };
} }
@ -297,7 +302,7 @@ impl HirDisplay for Pat {
PatKind::Wild => write!(f, "_"), PatKind::Wild => write!(f, "_"),
PatKind::Never => write!(f, "!"), PatKind::Never => write!(f, "!"),
PatKind::Binding { name, subpattern } => { PatKind::Binding { name, subpattern } => {
write!(f, "{}", name.display(f.db.upcast()))?; write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
if let Some(subpattern) = subpattern { if let Some(subpattern) = subpattern {
write!(f, " @ ")?; write!(f, " @ ")?;
subpattern.hir_fmt(f)?; subpattern.hir_fmt(f)?;
@ -317,14 +322,22 @@ impl HirDisplay for Pat {
if let Some(variant) = variant { if let Some(variant) = variant {
match variant { match variant {
VariantId::EnumVariantId(v) => { VariantId::EnumVariantId(v) => {
write!(f, "{}", f.db.enum_variant_data(v).name.display(f.db.upcast()))?; write!(
} f,
VariantId::StructId(s) => { "{}",
write!(f, "{}", f.db.struct_data(s).name.display(f.db.upcast()))? f.db.enum_variant_data(v).name.display(f.db.upcast(), f.edition())
} )?;
VariantId::UnionId(u) => {
write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast()))?
} }
VariantId::StructId(s) => write!(
f,
"{}",
f.db.struct_data(s).name.display(f.db.upcast(), f.edition())
)?,
VariantId::UnionId(u) => write!(
f,
"{}",
f.db.union_data(u).name.display(f.db.upcast(), f.edition())
)?,
}; };
let variant_data = variant.variant_data(f.db.upcast()); let variant_data = variant.variant_data(f.db.upcast());
@ -341,7 +354,9 @@ impl HirDisplay for Pat {
write!( write!(
f, f,
"{}: ", "{}: ",
rec_fields[p.field].name.display(f.db.upcast()) rec_fields[p.field]
.name
.display(f.db.upcast(), f.edition())
)?; )?;
p.pattern.hir_fmt(f) p.pattern.hir_fmt(f)
}) })

View file

@ -33,6 +33,7 @@ use rustc_apfloat::{
Float, Float,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
use span::Edition;
use stdx::{never, IsNoneOr}; use stdx::{never, IsNoneOr};
use triomphe::Arc; use triomphe::Arc;
@ -131,7 +132,11 @@ pub trait HirDisplay {
/// Returns a `Display`able type that is human-readable. /// Returns a `Display`able type that is human-readable.
/// Use this for showing types to the user (e.g. diagnostics) /// Use this for showing types to the user (e.g. diagnostics)
fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> fn display<'a>(
&'a self,
db: &'a dyn HirDatabase,
edition: Edition,
) -> HirDisplayWrapper<'a, Self>
where where
Self: Sized, Self: Sized,
{ {
@ -142,7 +147,7 @@ pub trait HirDisplay {
limited_size: None, limited_size: None,
omit_verbose_types: false, omit_verbose_types: false,
closure_style: ClosureStyle::ImplFn, closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Diagnostics, display_target: DisplayTarget::Diagnostics { edition },
show_container_bounds: false, show_container_bounds: false,
} }
} }
@ -153,6 +158,7 @@ pub trait HirDisplay {
&'a self, &'a self,
db: &'a dyn HirDatabase, db: &'a dyn HirDatabase,
max_size: Option<usize>, max_size: Option<usize>,
edition: Edition,
) -> HirDisplayWrapper<'a, Self> ) -> HirDisplayWrapper<'a, Self>
where where
Self: Sized, Self: Sized,
@ -164,7 +170,7 @@ pub trait HirDisplay {
limited_size: None, limited_size: None,
omit_verbose_types: true, omit_verbose_types: true,
closure_style: ClosureStyle::ImplFn, closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Diagnostics, display_target: DisplayTarget::Diagnostics { edition },
show_container_bounds: false, show_container_bounds: false,
} }
} }
@ -175,6 +181,7 @@ pub trait HirDisplay {
&'a self, &'a self,
db: &'a dyn HirDatabase, db: &'a dyn HirDatabase,
limited_size: Option<usize>, limited_size: Option<usize>,
edition: Edition,
) -> HirDisplayWrapper<'a, Self> ) -> HirDisplayWrapper<'a, Self>
where where
Self: Sized, Self: Sized,
@ -186,7 +193,7 @@ pub trait HirDisplay {
limited_size, limited_size,
omit_verbose_types: true, omit_verbose_types: true,
closure_style: ClosureStyle::ImplFn, closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Diagnostics, display_target: DisplayTarget::Diagnostics { edition },
show_container_bounds: false, show_container_bounds: false,
} }
} }
@ -242,6 +249,7 @@ pub trait HirDisplay {
&'a self, &'a self,
db: &'a dyn HirDatabase, db: &'a dyn HirDatabase,
show_container_bounds: bool, show_container_bounds: bool,
edition: Edition,
) -> HirDisplayWrapper<'a, Self> ) -> HirDisplayWrapper<'a, Self>
where where
Self: Sized, Self: Sized,
@ -253,13 +261,23 @@ pub trait HirDisplay {
limited_size: None, limited_size: None,
omit_verbose_types: false, omit_verbose_types: false,
closure_style: ClosureStyle::ImplFn, closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Diagnostics, display_target: DisplayTarget::Diagnostics { edition },
show_container_bounds, show_container_bounds,
} }
} }
} }
impl HirFormatter<'_> { impl HirFormatter<'_> {
pub fn edition(&self) -> Edition {
match self.display_target {
DisplayTarget::Diagnostics { edition } => edition,
DisplayTarget::SourceCode { module_id, .. } => {
self.db.crate_graph()[module_id.krate()].edition
}
DisplayTarget::Test => Edition::CURRENT,
}
}
pub fn write_joined<T: HirDisplay>( pub fn write_joined<T: HirDisplay>(
&mut self, &mut self,
iter: impl IntoIterator<Item = T>, iter: impl IntoIterator<Item = T>,
@ -324,7 +342,7 @@ pub enum DisplayTarget {
/// Display types for inlays, doc popups, autocompletion, etc... /// Display types for inlays, doc popups, autocompletion, etc...
/// Showing `{unknown}` or not qualifying paths is fine here. /// Showing `{unknown}` or not qualifying paths is fine here.
/// There's no reason for this to fail. /// There's no reason for this to fail.
Diagnostics, Diagnostics { edition: Edition },
/// Display types for inserting them in source files. /// Display types for inserting them in source files.
/// The generated code should compile, so paths need to be qualified. /// The generated code should compile, so paths need to be qualified.
SourceCode { module_id: ModuleId, allow_opaque: bool }, SourceCode { module_id: ModuleId, allow_opaque: bool },
@ -460,7 +478,7 @@ impl HirDisplay for ProjectionTy {
">::{}", ">::{}",
f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)) f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id))
.name .name
.display(f.db.upcast()) .display(f.db.upcast(), f.edition())
)?; )?;
let proj_params_count = let proj_params_count =
self.substitution.len(Interner) - trait_ref.substitution.len(Interner); self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
@ -499,7 +517,7 @@ impl HirDisplay for Const {
let id = from_placeholder_idx(f.db, *idx); let id = from_placeholder_idx(f.db, *idx);
let generics = generics(f.db.upcast(), id.parent); let generics = generics(f.db.upcast(), id.parent);
let param_data = &generics[id.local_id]; let param_data = &generics[id.local_id];
write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?; write!(f, "{}", param_data.name().unwrap().display(f.db.upcast(), f.edition()))?;
Ok(()) Ok(())
} }
ConstValue::Concrete(c) => match &c.interned { ConstValue::Concrete(c) => match &c.interned {
@ -633,7 +651,7 @@ fn render_const_scalar(
TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.0 { TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.0 {
hir_def::AdtId::StructId(s) => { hir_def::AdtId::StructId(s) => {
let data = f.db.struct_data(s); let data = f.db.struct_data(s);
write!(f, "&{}", data.name.display(f.db.upcast()))?; write!(f, "&{}", data.name.display(f.db.upcast(), f.edition()))?;
Ok(()) Ok(())
} }
_ => f.write_str("<unsized-enum-or-union>"), _ => f.write_str("<unsized-enum-or-union>"),
@ -691,7 +709,7 @@ fn render_const_scalar(
match adt.0 { match adt.0 {
hir_def::AdtId::StructId(s) => { hir_def::AdtId::StructId(s) => {
let data = f.db.struct_data(s); let data = f.db.struct_data(s);
write!(f, "{}", data.name.display(f.db.upcast()))?; write!(f, "{}", data.name.display(f.db.upcast(), f.edition()))?;
let field_types = f.db.field_types(s.into()); let field_types = f.db.field_types(s.into());
render_variant_after_name( render_variant_after_name(
&data.variant_data, &data.variant_data,
@ -705,7 +723,7 @@ fn render_const_scalar(
) )
} }
hir_def::AdtId::UnionId(u) => { hir_def::AdtId::UnionId(u) => {
write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast())) write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast(), f.edition()))
} }
hir_def::AdtId::EnumId(e) => { hir_def::AdtId::EnumId(e) => {
let Ok(target_data_layout) = f.db.target_data_layout(trait_env.krate) else { let Ok(target_data_layout) = f.db.target_data_layout(trait_env.krate) else {
@ -717,7 +735,7 @@ fn render_const_scalar(
return f.write_str("<failed-to-detect-variant>"); return f.write_str("<failed-to-detect-variant>");
}; };
let data = f.db.enum_variant_data(var_id); let data = f.db.enum_variant_data(var_id);
write!(f, "{}", data.name.display(f.db.upcast()))?; write!(f, "{}", data.name.display(f.db.upcast(), f.edition()))?;
let field_types = f.db.field_types(var_id.into()); let field_types = f.db.field_types(var_id.into());
render_variant_after_name( render_variant_after_name(
&data.variant_data, &data.variant_data,
@ -802,11 +820,11 @@ fn render_variant_after_name(
if matches!(data, VariantData::Record(_)) { if matches!(data, VariantData::Record(_)) {
write!(f, " {{")?; write!(f, " {{")?;
if let Some((id, data)) = it.next() { if let Some((id, data)) = it.next() {
write!(f, " {}: ", data.name.display(f.db.upcast()))?; write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?;
render_field(f, id)?; render_field(f, id)?;
} }
for (id, data) in it { for (id, data) in it {
write!(f, ", {}: ", data.name.display(f.db.upcast()))?; write!(f, ", {}: ", data.name.display(f.db.upcast(), f.edition()))?;
render_field(f, id)?; render_field(f, id)?;
} }
write!(f, " }}")?; write!(f, " }}")?;
@ -1000,15 +1018,23 @@ impl HirDisplay for Ty {
CallableDefId::FunctionId(ff) => { CallableDefId::FunctionId(ff) => {
write!(f, "fn ")?; write!(f, "fn ")?;
f.start_location_link(def.into()); f.start_location_link(def.into());
write!(f, "{}", db.function_data(ff).name.display(f.db.upcast()))? write!(
f,
"{}",
db.function_data(ff).name.display(f.db.upcast(), f.edition())
)?
} }
CallableDefId::StructId(s) => { CallableDefId::StructId(s) => {
f.start_location_link(def.into()); f.start_location_link(def.into());
write!(f, "{}", db.struct_data(s).name.display(f.db.upcast()))? write!(f, "{}", db.struct_data(s).name.display(f.db.upcast(), f.edition()))?
} }
CallableDefId::EnumVariantId(e) => { CallableDefId::EnumVariantId(e) => {
f.start_location_link(def.into()); f.start_location_link(def.into());
write!(f, "{}", db.enum_variant_data(e).name.display(f.db.upcast()))? write!(
f,
"{}",
db.enum_variant_data(e).name.display(f.db.upcast(), f.edition())
)?
} }
}; };
f.end_location_link(); f.end_location_link();
@ -1053,13 +1079,13 @@ impl HirDisplay for Ty {
TyKind::Adt(AdtId(def_id), parameters) => { TyKind::Adt(AdtId(def_id), parameters) => {
f.start_location_link((*def_id).into()); f.start_location_link((*def_id).into());
match f.display_target { match f.display_target {
DisplayTarget::Diagnostics | DisplayTarget::Test => { DisplayTarget::Diagnostics { .. } | DisplayTarget::Test => {
let name = match *def_id { let name = match *def_id {
hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(), hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(),
hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(), hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(),
hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(), hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(),
}; };
write!(f, "{}", name.display(f.db.upcast()))?; write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
} }
DisplayTarget::SourceCode { module_id, allow_opaque: _ } => { DisplayTarget::SourceCode { module_id, allow_opaque: _ } => {
if let Some(path) = find_path::find_path( if let Some(path) = find_path::find_path(
@ -1075,7 +1101,7 @@ impl HirDisplay for Ty {
prefer_absolute: false, prefer_absolute: false,
}, },
) { ) {
write!(f, "{}", path.display(f.db.upcast()))?; write!(f, "{}", path.display(f.db.upcast(), f.edition()))?;
} else { } else {
return Err(HirDisplayError::DisplaySourceCodeError( return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::PathNotFound, DisplaySourceCodeError::PathNotFound,
@ -1101,12 +1127,12 @@ impl HirDisplay for Ty {
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types) // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
if f.display_target.is_test() { if f.display_target.is_test() {
f.start_location_link(trait_.into()); f.start_location_link(trait_.into());
write!(f, "{}", trait_data.name.display(f.db.upcast()))?; write!(f, "{}", trait_data.name.display(f.db.upcast(), f.edition()))?;
f.end_location_link(); f.end_location_link();
write!(f, "::")?; write!(f, "::")?;
f.start_location_link(type_alias.into()); f.start_location_link(type_alias.into());
write!(f, "{}", type_alias_data.name.display(f.db.upcast()))?; write!(f, "{}", type_alias_data.name.display(f.db.upcast(), f.edition()))?;
f.end_location_link(); f.end_location_link();
// Note that the generic args for the associated type come before those for the // Note that the generic args for the associated type come before those for the
// trait (including the self type). // trait (including the self type).
@ -1124,7 +1150,7 @@ impl HirDisplay for Ty {
let alias = from_foreign_def_id(*type_alias); let alias = from_foreign_def_id(*type_alias);
let type_alias = db.type_alias_data(alias); let type_alias = db.type_alias_data(alias);
f.start_location_link(alias.into()); f.start_location_link(alias.into());
write!(f, "{}", type_alias.name.display(f.db.upcast()))?; write!(f, "{}", type_alias.name.display(f.db.upcast(), f.edition()))?;
f.end_location_link(); f.end_location_link();
} }
TyKind::OpaqueType(opaque_ty_id, parameters) => { TyKind::OpaqueType(opaque_ty_id, parameters) => {
@ -1256,7 +1282,10 @@ impl HirDisplay for Ty {
write!( write!(
f, f,
"{}", "{}",
p.name.clone().unwrap_or_else(Name::missing).display(f.db.upcast()) p.name
.clone()
.unwrap_or_else(Name::missing)
.display(f.db.upcast(), f.edition())
)? )?
} }
TypeParamProvenance::ArgumentImplTrait => { TypeParamProvenance::ArgumentImplTrait => {
@ -1289,7 +1318,7 @@ impl HirDisplay for Ty {
} }
}, },
TypeOrConstParamData::ConstParamData(p) => { TypeOrConstParamData::ConstParamData(p) => {
write!(f, "{}", p.name.display(f.db.upcast()))?; write!(f, "{}", p.name.display(f.db.upcast(), f.edition()))?;
} }
} }
} }
@ -1632,7 +1661,7 @@ fn write_bounds_like_dyn_trait(
// existential) here, which is the only thing that's // existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it // possible in actual Rust, and hence don't print it
f.start_location_link(trait_.into()); f.start_location_link(trait_.into());
write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?; write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?;
f.end_location_link(); f.end_location_link();
if is_fn_trait { if is_fn_trait {
if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) { if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) {
@ -1706,7 +1735,7 @@ fn write_bounds_like_dyn_trait(
let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id); let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
let type_alias = f.db.type_alias_data(assoc_ty_id); let type_alias = f.db.type_alias_data(assoc_ty_id);
f.start_location_link(assoc_ty_id.into()); f.start_location_link(assoc_ty_id.into());
write!(f, "{}", type_alias.name.display(f.db.upcast()))?; write!(f, "{}", type_alias.name.display(f.db.upcast(), f.edition()))?;
f.end_location_link(); f.end_location_link();
let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self(); let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
@ -1770,7 +1799,7 @@ fn fmt_trait_ref(
} }
let trait_ = tr.hir_trait_id(); let trait_ = tr.hir_trait_id();
f.start_location_link(trait_.into()); f.start_location_link(trait_.into());
write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?; write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?;
f.end_location_link(); f.end_location_link();
let substs = tr.substitution.as_slice(Interner); let substs = tr.substitution.as_slice(Interner);
hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner)) hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
@ -1796,7 +1825,11 @@ impl HirDisplay for WhereClause {
write!(f, ">::",)?; write!(f, ">::",)?;
let type_alias = from_assoc_type_id(projection_ty.associated_ty_id); let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
f.start_location_link(type_alias.into()); f.start_location_link(type_alias.into());
write!(f, "{}", f.db.type_alias_data(type_alias).name.display(f.db.upcast()),)?; write!(
f,
"{}",
f.db.type_alias_data(type_alias).name.display(f.db.upcast(), f.edition()),
)?;
f.end_location_link(); f.end_location_link();
write!(f, " = ")?; write!(f, " = ")?;
ty.hir_fmt(f)?; ty.hir_fmt(f)?;
@ -1832,7 +1865,7 @@ impl HirDisplay for LifetimeData {
let id = lt_from_placeholder_idx(f.db, *idx); let id = lt_from_placeholder_idx(f.db, *idx);
let generics = generics(f.db.upcast(), id.parent); let generics = generics(f.db.upcast(), id.parent);
let param_data = &generics[id.local_id]; let param_data = &generics[id.local_id];
write!(f, "{}", param_data.name.display(f.db.upcast()))?; write!(f, "{}", param_data.name.display(f.db.upcast(), f.edition()))?;
Ok(()) Ok(())
} }
_ if f.display_target.is_source_code() => write!(f, "'_"), _ if f.display_target.is_source_code() => write!(f, "'_"),
@ -1913,7 +1946,7 @@ impl HirDisplay for TypeRef {
}; };
write!(f, "&")?; write!(f, "&")?;
if let Some(lifetime) = lifetime { if let Some(lifetime) = lifetime {
write!(f, "{} ", lifetime.name.display(f.db.upcast()))?; write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
} }
write!(f, "{mutability}")?; write!(f, "{mutability}")?;
inner.hir_fmt(f)?; inner.hir_fmt(f)?;
@ -1921,7 +1954,7 @@ impl HirDisplay for TypeRef {
TypeRef::Array(inner, len) => { TypeRef::Array(inner, len) => {
write!(f, "[")?; write!(f, "[")?;
inner.hir_fmt(f)?; inner.hir_fmt(f)?;
write!(f, "; {}]", len.display(f.db.upcast()))?; write!(f, "; {}]", len.display(f.db.upcast(), f.edition()))?;
} }
TypeRef::Slice(inner) => { TypeRef::Slice(inner) => {
write!(f, "[")?; write!(f, "[")?;
@ -1942,7 +1975,7 @@ impl HirDisplay for TypeRef {
for index in 0..function_parameters.len() { for index in 0..function_parameters.len() {
let (param_name, param_type) = &function_parameters[index]; let (param_name, param_type) = &function_parameters[index];
if let Some(name) = param_name { if let Some(name) = param_name {
write!(f, "{}: ", name.display(f.db.upcast()))?; write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?;
} }
param_type.hir_fmt(f)?; param_type.hir_fmt(f)?;
@ -2000,12 +2033,15 @@ impl HirDisplay for TypeBound {
} }
path.hir_fmt(f) path.hir_fmt(f)
} }
TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name.display(f.db.upcast())), TypeBound::Lifetime(lifetime) => {
write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
}
TypeBound::ForLifetime(lifetimes, path) => { TypeBound::ForLifetime(lifetimes, path) => {
let edition = f.edition();
write!( write!(
f, f,
"for<{}> ", "for<{}> ",
lifetimes.iter().map(|it| it.display(f.db.upcast())).format(", ") lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ")
)?; )?;
path.hir_fmt(f) path.hir_fmt(f)
} }
@ -2071,7 +2107,7 @@ impl HirDisplay for Path {
if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 { if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
write!(f, "::")?; write!(f, "::")?;
} }
write!(f, "{}", segment.name.display(f.db.upcast()))?; write!(f, "{}", segment.name.display(f.db.upcast(), f.edition()))?;
if let Some(generic_args) = segment.args_and_bindings { if let Some(generic_args) = segment.args_and_bindings {
// We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`. // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
// Do we actually format expressions? // Do we actually format expressions?
@ -2116,7 +2152,7 @@ impl HirDisplay for Path {
} else { } else {
write!(f, ", ")?; write!(f, ", ")?;
} }
write!(f, "{}", binding.name.display(f.db.upcast()))?; write!(f, "{}", binding.name.display(f.db.upcast(), f.edition()))?;
match &binding.type_ref { match &binding.type_ref {
Some(ty) => { Some(ty) => {
write!(f, " = ")?; write!(f, " = ")?;
@ -2150,9 +2186,11 @@ impl HirDisplay for hir_def::path::GenericArg {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
match self { match self {
hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f), hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
hir_def::path::GenericArg::Const(c) => write!(f, "{}", c.display(f.db.upcast())), hir_def::path::GenericArg::Const(c) => {
write!(f, "{}", c.display(f.db.upcast(), f.edition()))
}
hir_def::path::GenericArg::Lifetime(lifetime) => { hir_def::path::GenericArg::Lifetime(lifetime) => {
write!(f, "{}", lifetime.name.display(f.db.upcast())) write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
} }
} }
} }

View file

@ -255,7 +255,9 @@ impl CapturedItem {
pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String {
let body = db.body(owner); let body = db.body(owner);
let mut result = body[self.place.local].name.display(db.upcast()).to_string(); let krate = owner.krate(db.upcast());
let edition = db.crate_graph()[krate].edition;
let mut result = body[self.place.local].name.display(db.upcast(), edition).to_string();
let mut field_need_paren = false; let mut field_need_paren = false;
for proj in &self.place.projections { for proj in &self.place.projections {
match proj { match proj {

View file

@ -42,19 +42,20 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
hir_def::ModuleDefId::AdtId(x) => { hir_def::ModuleDefId::AdtId(x) => {
let name = match x { let name = match x {
hir_def::AdtId::StructId(x) => { hir_def::AdtId::StructId(x) => {
db.struct_data(x).name.display_no_db().to_smolstr() db.struct_data(x).name.display_no_db(file_id.edition()).to_smolstr()
} }
hir_def::AdtId::UnionId(x) => { hir_def::AdtId::UnionId(x) => {
db.union_data(x).name.display_no_db().to_smolstr() db.union_data(x).name.display_no_db(file_id.edition()).to_smolstr()
} }
hir_def::AdtId::EnumId(x) => { hir_def::AdtId::EnumId(x) => {
db.enum_data(x).name.display_no_db().to_smolstr() db.enum_data(x).name.display_no_db(file_id.edition()).to_smolstr()
} }
}; };
(name == "Goal").then_some(Either::Left(x)) (name == "Goal").then_some(Either::Left(x))
} }
hir_def::ModuleDefId::TypeAliasId(x) => { hir_def::ModuleDefId::TypeAliasId(x) => {
let name = db.type_alias_data(x).name.display_no_db().to_smolstr(); let name =
db.type_alias_data(x).name.display_no_db(file_id.edition()).to_smolstr();
(name == "Goal").then_some(Either::Right(x)) (name == "Goal").then_some(Either::Right(x))
} }
_ => None, _ => None,
@ -94,7 +95,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
.declarations() .declarations()
.find_map(|x| match x { .find_map(|x| match x {
hir_def::ModuleDefId::FunctionId(x) => { hir_def::ModuleDefId::FunctionId(x) => {
let name = db.function_data(x).name.display_no_db().to_smolstr(); let name = db.function_data(x).name.display_no_db(file_id.edition()).to_smolstr();
(name == "main").then_some(x) (name == "main").then_some(x)
} }
_ => None, _ => None,
@ -104,7 +105,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
let b = hir_body let b = hir_body
.bindings .bindings
.iter() .iter()
.find(|x| x.1.name.display_no_db().to_smolstr() == "goal") .find(|x| x.1.name.display_no_db(file_id.edition()).to_smolstr() == "goal")
.unwrap() .unwrap()
.0; .0;
let infer = db.infer(function_id.into()); let infer = db.infer(function_id.into());

View file

@ -66,6 +66,7 @@ use intern::{sym, Symbol};
use la_arena::{Arena, Idx}; use la_arena::{Arena, Idx};
use mir::{MirEvalError, VTableMap}; use mir::{MirEvalError, VTableMap};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use span::Edition;
use syntax::ast::{make, ConstArg}; use syntax::ast::{make, ConstArg};
use traits::FnTrait; use traits::FnTrait;
use triomphe::Arc; use triomphe::Arc;
@ -1025,7 +1026,11 @@ where
collector.placeholders.into_iter().collect() collector.placeholders.into_iter().collect()
} }
pub fn known_const_to_ast(konst: &Const, db: &dyn HirDatabase) -> Option<ConstArg> { pub fn known_const_to_ast(
konst: &Const,
db: &dyn HirDatabase,
edition: Edition,
) -> Option<ConstArg> {
if let ConstValue::Concrete(c) = &konst.interned().value { if let ConstValue::Concrete(c) = &konst.interned().value {
match c.interned { match c.interned {
ConstScalar::UnevaluatedConst(GeneralConstId::InTypeConstId(cid), _) => { ConstScalar::UnevaluatedConst(GeneralConstId::InTypeConstId(cid), _) => {
@ -1035,5 +1040,5 @@ pub fn known_const_to_ast(konst: &Const, db: &dyn HirDatabase) -> Option<ConstAr
_ => (), _ => (),
} }
} }
Some(make::expr_const_value(konst.display(db).to_string().as_str())) Some(make::expr_const_value(konst.display(db, edition).to_string().as_str()))
} }

View file

@ -158,7 +158,10 @@ impl<V, T> ProjectionElem<V, T> {
subst.at(Interner, 0).assert_ty_ref(Interner).clone() subst.at(Interner, 0).assert_ty_ref(Interner).clone()
} }
_ => { _ => {
never!("Overloaded deref on type {} is not a projection", base.display(db)); never!(
"Overloaded deref on type {} is not a projection",
base.display(db, db.crate_graph()[krate].edition)
);
TyKind::Error.intern(Interner) TyKind::Error.intern(Interner)
} }
}, },

View file

@ -23,7 +23,7 @@ use rustc_apfloat::{
Float, Float,
}; };
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use span::FileId; use span::{Edition, FileId};
use stdx::never; use stdx::never;
use syntax::{SyntaxNodePtr, TextRange}; use syntax::{SyntaxNodePtr, TextRange};
use triomphe::Arc; use triomphe::Arc;
@ -358,6 +358,7 @@ impl MirEvalError {
f: &mut String, f: &mut String,
db: &dyn HirDatabase, db: &dyn HirDatabase,
span_formatter: impl Fn(FileId, TextRange) -> String, span_formatter: impl Fn(FileId, TextRange) -> String,
edition: Edition,
) -> std::result::Result<(), std::fmt::Error> { ) -> std::result::Result<(), std::fmt::Error> {
writeln!(f, "Mir eval error:")?; writeln!(f, "Mir eval error:")?;
let mut err = self; let mut err = self;
@ -370,7 +371,7 @@ impl MirEvalError {
writeln!( writeln!(
f, f,
"In function {} ({:?})", "In function {} ({:?})",
function_name.name.display(db.upcast()), function_name.name.display(db.upcast(), edition),
func func
)?; )?;
} }
@ -415,7 +416,7 @@ impl MirEvalError {
write!( write!(
f, f,
"Layout for type `{}` is not available due {err:?}", "Layout for type `{}` is not available due {err:?}",
ty.display(db).with_closure_style(ClosureStyle::ClosureWithId) ty.display(db, edition).with_closure_style(ClosureStyle::ClosureWithId)
)?; )?;
} }
MirEvalError::MirLowerError(func, err) => { MirEvalError::MirLowerError(func, err) => {
@ -423,16 +424,17 @@ impl MirEvalError {
writeln!( writeln!(
f, f,
"MIR lowering for function `{}` ({:?}) failed due:", "MIR lowering for function `{}` ({:?}) failed due:",
function_name.name.display(db.upcast()), function_name.name.display(db.upcast(), edition),
func func
)?; )?;
err.pretty_print(f, db, span_formatter)?; err.pretty_print(f, db, span_formatter, edition)?;
} }
MirEvalError::ConstEvalError(name, err) => { MirEvalError::ConstEvalError(name, err) => {
MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print( MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(
f, f,
db, db,
span_formatter, span_formatter,
edition,
)?; )?;
} }
MirEvalError::UndefinedBehavior(_) MirEvalError::UndefinedBehavior(_)
@ -2675,10 +2677,11 @@ impl Evaluator<'_> {
let db = self.db.upcast(); let db = self.db.upcast();
let loc = variant.lookup(db); let loc = variant.lookup(db);
let enum_loc = loc.parent.lookup(db); let enum_loc = loc.parent.lookup(db);
let edition = self.db.crate_graph()[self.crate_id].edition;
let name = format!( let name = format!(
"{}::{}", "{}::{}",
enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition),
loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition),
); );
Err(MirEvalError::ConstEvalError(name, Box::new(e))) Err(MirEvalError::ConstEvalError(name, Box::new(e)))
} }

View file

@ -856,7 +856,11 @@ impl Evaluator<'_> {
Ok(ty_name) => ty_name, Ok(ty_name) => ty_name,
// Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to // Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to
// render full paths. // render full paths.
Err(_) => ty.display(self.db).to_string(), Err(_) => {
let krate = locals.body.owner.krate(self.db.upcast());
let edition = self.db.crate_graph()[krate].edition;
ty.display(self.db, edition).to_string()
}
}; };
let len = ty_name.len(); let len = ty_name.len();
let addr = self.heap_allocate(len, 1)?; let addr = self.heap_allocate(len, 1)?;

View file

@ -1,5 +1,5 @@
use hir_def::db::DefDatabase; use hir_def::db::DefDatabase;
use span::EditionedFileId; use span::{Edition, EditionedFileId};
use syntax::{TextRange, TextSize}; use syntax::{TextRange, TextSize};
use test_fixture::WithFixture; use test_fixture::WithFixture;
@ -15,7 +15,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String),
.declarations() .declarations()
.find_map(|x| match x { .find_map(|x| match x {
hir_def::ModuleDefId::FunctionId(x) => { hir_def::ModuleDefId::FunctionId(x) => {
if db.function_data(x).name.display(db).to_string() == "main" { if db.function_data(x).name.display(db, Edition::CURRENT).to_string() == "main" {
Some(x) Some(x)
} else { } else {
None None
@ -63,7 +63,7 @@ fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr
let span_formatter = |file, range: TextRange| { let span_formatter = |file, range: TextRange| {
format!("{:?} {:?}..{:?}", file, line_index(range.start()), line_index(range.end())) format!("{:?} {:?}..{:?}", file, line_index(range.start()), line_index(range.end()))
}; };
e.pretty_print(&mut err, &db, span_formatter).unwrap(); e.pretty_print(&mut err, &db, span_formatter, Edition::CURRENT).unwrap();
panic!("Error in interpreting: {err}"); panic!("Error in interpreting: {err}");
} }
Ok((stdout, stderr)) => { Ok((stdout, stderr)) => {

View file

@ -21,7 +21,7 @@ use hir_expand::name::Name;
use la_arena::ArenaMap; use la_arena::ArenaMap;
use rustc_apfloat::Float; use rustc_apfloat::Float;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use span::FileId; use span::{Edition, FileId};
use syntax::TextRange; use syntax::TextRange;
use triomphe::Arc; use triomphe::Arc;
@ -157,13 +157,18 @@ impl MirLowerError {
f: &mut String, f: &mut String,
db: &dyn HirDatabase, db: &dyn HirDatabase,
span_formatter: impl Fn(FileId, TextRange) -> String, span_formatter: impl Fn(FileId, TextRange) -> String,
edition: Edition,
) -> std::result::Result<(), std::fmt::Error> { ) -> std::result::Result<(), std::fmt::Error> {
match self { match self {
MirLowerError::ConstEvalError(name, e) => { MirLowerError::ConstEvalError(name, e) => {
writeln!(f, "In evaluating constant {name}")?; writeln!(f, "In evaluating constant {name}")?;
match &**e { match &**e {
ConstEvalError::MirLowerError(e) => e.pretty_print(f, db, span_formatter)?, ConstEvalError::MirLowerError(e) => {
ConstEvalError::MirEvalError(e) => e.pretty_print(f, db, span_formatter)?, e.pretty_print(f, db, span_formatter, edition)?
}
ConstEvalError::MirEvalError(e) => {
e.pretty_print(f, db, span_formatter, edition)?
}
} }
} }
MirLowerError::MissingFunctionDefinition(owner, it) => { MirLowerError::MissingFunctionDefinition(owner, it) => {
@ -171,15 +176,15 @@ impl MirLowerError {
writeln!( writeln!(
f, f,
"Missing function definition for {}", "Missing function definition for {}",
body.pretty_print_expr(db.upcast(), *owner, *it) body.pretty_print_expr(db.upcast(), *owner, *it, edition)
)?; )?;
} }
MirLowerError::TypeMismatch(e) => match e { MirLowerError::TypeMismatch(e) => match e {
Some(e) => writeln!( Some(e) => writeln!(
f, f,
"Type mismatch: Expected {}, found {}", "Type mismatch: Expected {}, found {}",
e.expected.display(db), e.expected.display(db, edition),
e.actual.display(db), e.actual.display(db, edition),
)?, )?,
None => writeln!(f, "Type mismatch: types mismatch with {{unknown}}",)?, None => writeln!(f, "Type mismatch: types mismatch with {{unknown}}",)?,
}, },
@ -189,11 +194,11 @@ impl MirLowerError {
writeln!( writeln!(
f, f,
"Generic arg not provided for {}", "Generic arg not provided for {}",
param.name().unwrap_or(&Name::missing()).display(db.upcast()) param.name().unwrap_or(&Name::missing()).display(db.upcast(), edition)
)?; )?;
writeln!(f, "Provided args: [")?; writeln!(f, "Provided args: [")?;
for g in subst.iter(Interner) { for g in subst.iter(Interner) {
write!(f, " {},", g.display(db))?; write!(f, " {},", g.display(db, edition))?;
} }
writeln!(f, "]")?; writeln!(f, "]")?;
} }
@ -242,8 +247,8 @@ impl From<LayoutError> for MirLowerError {
} }
impl MirLowerError { impl MirLowerError {
fn unresolved_path(db: &dyn HirDatabase, p: &Path) -> Self { fn unresolved_path(db: &dyn HirDatabase, p: &Path, edition: Edition) -> Self {
Self::UnresolvedName(p.display(db).to_string()) Self::UnresolvedName(p.display(db, edition).to_string())
} }
} }
@ -436,7 +441,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
VariantId::UnionId(_) => implementation_error!("Union variant as path"), VariantId::UnionId(_) => implementation_error!("Union variant as path"),
} }
} else { } else {
let unresolved_name = || MirLowerError::unresolved_path(self.db, p); let unresolved_name =
|| MirLowerError::unresolved_path(self.db, p, self.edition());
let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id);
resolver resolver
.resolve_path_in_value_ns_fully(self.db.upcast(), p) .resolve_path_in_value_ns_fully(self.db.upcast(), p)
@ -662,7 +668,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
let (func_id, generic_args) = let (func_id, generic_args) =
self.infer.method_resolution(expr_id).ok_or_else(|| { self.infer.method_resolution(expr_id).ok_or_else(|| {
MirLowerError::UnresolvedMethod( MirLowerError::UnresolvedMethod(
method_name.display(self.db.upcast()).to_string(), method_name.display(self.db.upcast(), self.edition()).to_string(),
) )
})?; })?;
let func = Operand::from_fn(self.db, func_id, generic_args); let func = Operand::from_fn(self.db, func_id, generic_args);
@ -803,7 +809,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
}; };
let variant_id = let variant_id =
self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path { self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path {
Some(p) => MirLowerError::UnresolvedName(p.display(self.db).to_string()), Some(p) => MirLowerError::UnresolvedName(
p.display(self.db, self.edition()).to_string(),
),
None => MirLowerError::RecordLiteralWithoutPath, None => MirLowerError::RecordLiteralWithoutPath,
})?; })?;
let subst = match self.expr_ty_without_adjust(expr_id).kind(Interner) { let subst = match self.expr_ty_without_adjust(expr_id).kind(Interner) {
@ -1378,7 +1386,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
"only `char` and numeric types are allowed in range patterns" "only `char` and numeric types are allowed in range patterns"
), ),
}; };
let unresolved_name = || MirLowerError::unresolved_path(self.db, c.as_ref()); let edition = self.edition();
let unresolved_name =
|| MirLowerError::unresolved_path(self.db, c.as_ref(), edition);
let resolver = self.owner.resolver(self.db.upcast()); let resolver = self.owner.resolver(self.db.upcast());
let pr = resolver let pr = resolver
.resolve_path_in_value_ns(self.db.upcast(), c.as_ref()) .resolve_path_in_value_ns(self.db.upcast(), c.as_ref())
@ -1904,19 +1914,25 @@ impl<'ctx> MirLowerCtx<'ctx> {
match r { match r {
Ok(r) => Ok(r), Ok(r) => Ok(r),
Err(e) => { Err(e) => {
let edition = self.edition();
let db = self.db.upcast(); let db = self.db.upcast();
let loc = variant.lookup(db); let loc = variant.lookup(db);
let enum_loc = loc.parent.lookup(db); let enum_loc = loc.parent.lookup(db);
let name = format!( let name = format!(
"{}::{}", "{}::{}",
enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition),
loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition),
); );
Err(MirLowerError::ConstEvalError(name.into(), Box::new(e))) Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
} }
} }
} }
fn edition(&self) -> Edition {
let krate = self.owner.krate(self.db.upcast());
self.db.crate_graph()[krate].edition
}
fn drop_until_scope( fn drop_until_scope(
&mut self, &mut self,
scope_index: usize, scope_index: usize,
@ -2121,18 +2137,24 @@ pub fn mir_body_for_closure_query(
} }
pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<MirBody>> { pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<MirBody>> {
let krate = def.krate(db.upcast());
let edition = db.crate_graph()[krate].edition;
let detail = match def { let detail = match def {
DefWithBodyId::FunctionId(it) => db.function_data(it).name.display(db.upcast()).to_string(), DefWithBodyId::FunctionId(it) => {
DefWithBodyId::StaticId(it) => db.static_data(it).name.display(db.upcast()).to_string(), db.function_data(it).name.display(db.upcast(), edition).to_string()
}
DefWithBodyId::StaticId(it) => {
db.static_data(it).name.display(db.upcast(), edition).to_string()
}
DefWithBodyId::ConstId(it) => db DefWithBodyId::ConstId(it) => db
.const_data(it) .const_data(it)
.name .name
.clone() .clone()
.unwrap_or_else(Name::missing) .unwrap_or_else(Name::missing)
.display(db.upcast()) .display(db.upcast(), edition)
.to_string(), .to_string(),
DefWithBodyId::VariantId(it) => { DefWithBodyId::VariantId(it) => {
db.enum_variant_data(it).name.display(db.upcast()).to_string() db.enum_variant_data(it).name.display(db.upcast(), edition).to_string()
} }
DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"),
}; };

View file

@ -347,7 +347,8 @@ impl MirLowerCtx<'_> {
// A const don't bind anything. Only needs check. // A const don't bind anything. Only needs check.
return Ok((current, current_else)); return Ok((current, current_else));
} }
let unresolved_name = || MirLowerError::unresolved_path(self.db, p); let unresolved_name =
|| MirLowerError::unresolved_path(self.db, p, self.edition());
let resolver = self.owner.resolver(self.db.upcast()); let resolver = self.owner.resolver(self.db.upcast());
let pr = resolver let pr = resolver
.resolve_path_in_value_ns(self.db.upcast(), p) .resolve_path_in_value_ns(self.db.upcast(), p)

View file

@ -9,6 +9,7 @@ use either::Either;
use hir_def::{body::Body, hir::BindingId}; use hir_def::{body::Body, hir::BindingId};
use hir_expand::{name::Name, Lookup}; use hir_expand::{name::Name, Lookup};
use la_arena::ArenaMap; use la_arena::ArenaMap;
use span::Edition;
use crate::{ use crate::{
db::HirDatabase, db::HirDatabase,
@ -44,18 +45,21 @@ impl MirBody {
ctx.for_body(|this| match ctx.body.owner { ctx.for_body(|this| match ctx.body.owner {
hir_def::DefWithBodyId::FunctionId(id) => { hir_def::DefWithBodyId::FunctionId(id) => {
let data = db.function_data(id); let data = db.function_data(id);
w!(this, "fn {}() ", data.name.display(db.upcast())); w!(this, "fn {}() ", data.name.display(db.upcast(), Edition::LATEST));
} }
hir_def::DefWithBodyId::StaticId(id) => { hir_def::DefWithBodyId::StaticId(id) => {
let data = db.static_data(id); let data = db.static_data(id);
w!(this, "static {}: _ = ", data.name.display(db.upcast())); w!(this, "static {}: _ = ", data.name.display(db.upcast(), Edition::LATEST));
} }
hir_def::DefWithBodyId::ConstId(id) => { hir_def::DefWithBodyId::ConstId(id) => {
let data = db.const_data(id); let data = db.const_data(id);
w!( w!(
this, this,
"const {}: _ = ", "const {}: _ = ",
data.name.as_ref().unwrap_or(&Name::missing()).display(db.upcast()) data.name
.as_ref()
.unwrap_or(&Name::missing())
.display(db.upcast(), Edition::LATEST)
); );
} }
hir_def::DefWithBodyId::VariantId(id) => { hir_def::DefWithBodyId::VariantId(id) => {
@ -64,8 +68,12 @@ impl MirBody {
w!( w!(
this, this,
"enum {}::{} = ", "enum {}::{} = ",
enum_loc.id.item_tree(db.upcast())[enum_loc.id.value].name.display(db.upcast()), enum_loc.id.item_tree(db.upcast())[enum_loc.id.value]
loc.id.item_tree(db.upcast())[loc.id.value].name.display(db.upcast()), .name
.display(db.upcast(), Edition::LATEST),
loc.id.item_tree(db.upcast())[loc.id.value]
.name
.display(db.upcast(), Edition::LATEST),
) )
} }
hir_def::DefWithBodyId::InTypeConstId(id) => { hir_def::DefWithBodyId::InTypeConstId(id) => {
@ -122,7 +130,7 @@ impl HirDisplay for LocalName {
match self { match self {
LocalName::Unknown(l) => write!(f, "_{}", u32::from(l.into_raw())), LocalName::Unknown(l) => write!(f, "_{}", u32::from(l.into_raw())),
LocalName::Binding(n, l) => { LocalName::Binding(n, l) => {
write!(f, "{}_{}", n.display(f.db.upcast()), u32::from(l.into_raw())) write!(f, "{}_{}", n.display(f.db.upcast(), f.edition()), u32::from(l.into_raw()))
} }
} }
} }
@ -200,7 +208,7 @@ impl<'a> MirPrettyCtx<'a> {
wln!( wln!(
self, self,
"let {}: {};", "let {}: {};",
self.local_name(id).display(self.db), self.local_name(id).display_test(self.db),
self.hir_display(&local.ty) self.hir_display(&local.ty)
); );
} }
@ -231,10 +239,18 @@ impl<'a> MirPrettyCtx<'a> {
wln!(this, ";"); wln!(this, ";");
} }
StatementKind::StorageDead(p) => { StatementKind::StorageDead(p) => {
wln!(this, "StorageDead({})", this.local_name(*p).display(self.db)); wln!(
this,
"StorageDead({})",
this.local_name(*p).display_test(self.db)
);
} }
StatementKind::StorageLive(p) => { StatementKind::StorageLive(p) => {
wln!(this, "StorageLive({})", this.local_name(*p).display(self.db)); wln!(
this,
"StorageLive({})",
this.local_name(*p).display_test(self.db)
);
} }
StatementKind::Deinit(p) => { StatementKind::Deinit(p) => {
w!(this, "Deinit("); w!(this, "Deinit(");
@ -297,7 +313,7 @@ impl<'a> MirPrettyCtx<'a> {
fn f(this: &mut MirPrettyCtx<'_>, local: LocalId, projections: &[PlaceElem]) { fn f(this: &mut MirPrettyCtx<'_>, local: LocalId, projections: &[PlaceElem]) {
let Some((last, head)) = projections.split_last() else { let Some((last, head)) = projections.split_last() else {
// no projection // no projection
w!(this, "{}", this.local_name(local).display(this.db)); w!(this, "{}", this.local_name(local).display_test(this.db));
return; return;
}; };
match last { match last {
@ -317,13 +333,13 @@ impl<'a> MirPrettyCtx<'a> {
w!( w!(
this, this,
" as {}).{}", " as {}).{}",
variant_name.display(this.db.upcast()), variant_name.display(this.db.upcast(), Edition::LATEST),
name.display(this.db.upcast()) name.display(this.db.upcast(), Edition::LATEST)
); );
} }
hir_def::VariantId::StructId(_) | hir_def::VariantId::UnionId(_) => { hir_def::VariantId::StructId(_) | hir_def::VariantId::UnionId(_) => {
f(this, local, head); f(this, local, head);
w!(this, ".{}", name.display(this.db.upcast())); w!(this, ".{}", name.display(this.db.upcast(), Edition::LATEST));
} }
} }
} }
@ -337,7 +353,7 @@ impl<'a> MirPrettyCtx<'a> {
} }
ProjectionElem::Index(l) => { ProjectionElem::Index(l) => {
f(this, local, head); f(this, local, head);
w!(this, "[{}]", this.local_name(*l).display(this.db)); w!(this, "[{}]", this.local_name(*l).display_test(this.db));
} }
it => { it => {
f(this, local, head); f(this, local, head);
@ -387,7 +403,7 @@ impl<'a> MirPrettyCtx<'a> {
Rvalue::Repeat(op, len) => { Rvalue::Repeat(op, len) => {
w!(self, "["); w!(self, "[");
self.operand(op); self.operand(op);
w!(self, "; {}]", len.display(self.db)); w!(self, "; {}]", len.display_test(self.db));
} }
Rvalue::Aggregate(AggregateKind::Adt(_, _), it) => { Rvalue::Aggregate(AggregateKind::Adt(_, _), it) => {
w!(self, "Adt("); w!(self, "Adt(");
@ -458,6 +474,6 @@ impl<'a> MirPrettyCtx<'a> {
} }
fn hir_display<T: HirDisplay>(&self, ty: &'a T) -> impl Display + 'a { fn hir_display<T: HirDisplay>(&self, ty: &'a T) -> impl Display + 'a {
ty.display(self.db).with_closure_style(ClosureStyle::ClosureWithSubst) ty.display_test(self.db).with_closure_style(ClosureStyle::ClosureWithSubst)
} }
} }

View file

@ -2,6 +2,7 @@
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use itertools::Itertools; use itertools::Itertools;
use span::Edition;
use crate::{ use crate::{
chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk, chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
@ -24,7 +25,7 @@ impl DebugContext<'_> {
AdtId::UnionId(it) => self.0.union_data(it).name.clone(), AdtId::UnionId(it) => self.0.union_data(it).name.clone(),
AdtId::EnumId(it) => self.0.enum_data(it).name.clone(), AdtId::EnumId(it) => self.0.enum_data(it).name.clone(),
}; };
name.display(self.0.upcast()).fmt(f)?; name.display(self.0.upcast(), Edition::LATEST).fmt(f)?;
Ok(()) Ok(())
} }
@ -35,7 +36,7 @@ impl DebugContext<'_> {
) -> Result<(), fmt::Error> { ) -> Result<(), fmt::Error> {
let trait_: hir_def::TraitId = from_chalk_trait_id(id); let trait_: hir_def::TraitId = from_chalk_trait_id(id);
let trait_data = self.0.trait_data(trait_); let trait_data = self.0.trait_data(trait_);
trait_data.name.display(self.0.upcast()).fmt(f)?; trait_data.name.display(self.0.upcast(), Edition::LATEST).fmt(f)?;
Ok(()) Ok(())
} }
@ -54,8 +55,8 @@ impl DebugContext<'_> {
write!( write!(
fmt, fmt,
"{}::{}", "{}::{}",
trait_data.name.display(self.0.upcast()), trait_data.name.display(self.0.upcast(), Edition::LATEST),
type_alias_data.name.display(self.0.upcast()) type_alias_data.name.display(self.0.upcast(), Edition::LATEST)
)?; )?;
Ok(()) Ok(())
} }
@ -75,7 +76,7 @@ impl DebugContext<'_> {
let trait_ref = projection_ty.trait_ref(self.0); let trait_ref = projection_ty.trait_ref(self.0);
let trait_params = trait_ref.substitution.as_slice(Interner); let trait_params = trait_ref.substitution.as_slice(Interner);
let self_ty = trait_ref.self_type_parameter(Interner); let self_ty = trait_ref.self_type_parameter(Interner);
write!(fmt, "<{self_ty:?} as {}", trait_name.display(self.0.upcast()))?; write!(fmt, "<{self_ty:?} as {}", trait_name.display(self.0.upcast(), Edition::LATEST))?;
if trait_params.len() > 1 { if trait_params.len() > 1 {
write!( write!(
fmt, fmt,
@ -83,7 +84,7 @@ impl DebugContext<'_> {
trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))), trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))),
)?; )?;
} }
write!(fmt, ">::{}", type_alias_data.name.display(self.0.upcast()))?; write!(fmt, ">::{}", type_alias_data.name.display(self.0.upcast(), Edition::LATEST))?;
let proj_params_count = projection_ty.substitution.len(Interner) - trait_params.len(); let proj_params_count = projection_ty.substitution.len(Interner) - trait_params.len();
let proj_params = &projection_ty.substitution.as_slice(Interner)[..proj_params_count]; let proj_params = &projection_ty.substitution.as_slice(Interner)[..proj_params_count];
@ -110,9 +111,11 @@ impl DebugContext<'_> {
CallableDefId::EnumVariantId(e) => self.0.enum_variant_data(e).name.clone(), CallableDefId::EnumVariantId(e) => self.0.enum_variant_data(e).name.clone(),
}; };
match def { match def {
CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name.display(self.0.upcast())), CallableDefId::FunctionId(_) => {
write!(fmt, "{{fn {}}}", name.display(self.0.upcast(), Edition::LATEST))
}
CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => { CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
write!(fmt, "{{ctor {}}}", name.display(self.0.upcast())) write!(fmt, "{{ctor {}}}", name.display(self.0.upcast(), Edition::LATEST))
} }
} }
} }

View file

@ -14,6 +14,7 @@ use hir_def::{
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::sym; use intern::sym;
use span::Edition;
use stdx::{never, panic_context}; use stdx::{never, panic_context};
use triomphe::Arc; use triomphe::Arc;
@ -114,7 +115,7 @@ pub(crate) fn trait_solve_query(
) -> Option<Solution> { ) -> Option<Solution> {
let detail = match &goal.value.goal.data(Interner) { let detail = match &goal.value.goal.data(Interner) {
GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => { GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
db.trait_data(it.hir_trait_id()).name.display(db.upcast()).to_string() db.trait_data(it.hir_trait_id()).name.display(db.upcast(), Edition::LATEST).to_string()
} }
GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(), GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
_ => "??".to_owned(), _ => "??".to_owned(),

View file

@ -328,11 +328,9 @@ fn doc_modpath_from_str(link: &str) -> Option<ModPath> {
}; };
let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() { let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() {
Ok(idx) => Name::new_tuple_field(idx), Ok(idx) => Name::new_tuple_field(idx),
Err(_) => Name::new( Err(_) => {
segment.split_once('<').map_or(segment, |it| it.0), Name::new(segment.split_once('<').map_or(segment, |it| it.0), SyntaxContextId::ROOT)
tt::IdentIsRaw::No, }
SyntaxContextId::ROOT,
),
}); });
Some(ModPath::from_segments(kind, parts)) Some(ModPath::from_segments(kind, parts))
}; };

View file

@ -84,7 +84,7 @@ impl HirDisplay for Function {
if let Some(abi) = &data.abi { if let Some(abi) = &data.abi {
write!(f, "extern \"{}\" ", abi.as_str())?; write!(f, "extern \"{}\" ", abi.as_str())?;
} }
write!(f, "fn {}", data.name.display(f.db.upcast()))?; write!(f, "fn {}", data.name.display(f.db.upcast(), f.edition()))?;
write_generic_params(GenericDefId::FunctionId(self.id), f)?; write_generic_params(GenericDefId::FunctionId(self.id), f)?;
@ -107,7 +107,7 @@ impl HirDisplay for Function {
first = false; first = false;
} }
match local { match local {
Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?, Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?,
None => f.write_str("_: ")?, None => f.write_str("_: ")?,
} }
type_ref.hir_fmt(f)?; type_ref.hir_fmt(f)?;
@ -177,7 +177,7 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi
if let Some(trait_) = impl_.trait_(db) { if let Some(trait_) = impl_.trait_(db) {
let trait_data = db.trait_data(trait_.id); let trait_data = db.trait_data(trait_.id);
write!(f, " {} for", trait_data.name.display(db.upcast()))?; write!(f, " {} for", trait_data.name.display(db.upcast(), f.edition()))?;
} }
f.write_char(' ')?; f.write_char(' ')?;
@ -196,7 +196,7 @@ impl HirDisplay for SelfParam {
{ {
f.write_char('&')?; f.write_char('&')?;
if let Some(lifetime) = lifetime { if let Some(lifetime) = lifetime {
write!(f, "{} ", lifetime.name.display(f.db.upcast()))?; write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
} }
if let hir_def::type_ref::Mutability::Mut = mut_ { if let hir_def::type_ref::Mutability::Mut = mut_ {
f.write_str("mut ")?; f.write_str("mut ")?;
@ -227,7 +227,7 @@ impl HirDisplay for Struct {
// FIXME: Render repr if its set explicitly? // FIXME: Render repr if its set explicitly?
write_visibility(module_id, self.visibility(f.db), f)?; write_visibility(module_id, self.visibility(f.db), f)?;
f.write_str("struct ")?; f.write_str("struct ")?;
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
let def_id = GenericDefId::AdtId(AdtId::StructId(self.id)); let def_id = GenericDefId::AdtId(AdtId::StructId(self.id));
write_generic_params(def_id, f)?; write_generic_params(def_id, f)?;
@ -266,7 +266,7 @@ impl HirDisplay for Enum {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
f.write_str("enum ")?; f.write_str("enum ")?;
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id)); let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
write_generic_params(def_id, f)?; write_generic_params(def_id, f)?;
@ -283,7 +283,7 @@ impl HirDisplay for Union {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
f.write_str("union ")?; f.write_str("union ")?;
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id)); let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
write_generic_params(def_id, f)?; write_generic_params(def_id, f)?;
@ -343,7 +343,7 @@ fn write_variants(
} else { } else {
f.write_str("{\n")?; f.write_str("{\n")?;
for variant in &variants[..count] { for variant in &variants[..count] {
write!(f, " {}", variant.name(f.db).display(f.db.upcast()))?; write!(f, " {}", variant.name(f.db).display(f.db.upcast(), f.edition()))?;
match variant.kind(f.db) { match variant.kind(f.db) {
StructKind::Tuple => { StructKind::Tuple => {
let fields_str = let fields_str =
@ -372,21 +372,21 @@ fn write_variants(
impl HirDisplay for Field { impl HirDisplay for Field {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?; write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
write!(f, "{}: ", self.name(f.db).display(f.db.upcast()))?; write!(f, "{}: ", self.name(f.db).display(f.db.upcast(), f.edition()))?;
self.ty(f.db).hir_fmt(f) self.ty(f.db).hir_fmt(f)
} }
} }
impl HirDisplay for TupleField { impl HirDisplay for TupleField {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write!(f, "pub {}: ", self.name().display(f.db.upcast()))?; write!(f, "pub {}: ", self.name().display(f.db.upcast(), f.edition()))?;
self.ty(f.db).hir_fmt(f) self.ty(f.db).hir_fmt(f)
} }
} }
impl HirDisplay for Variant { impl HirDisplay for Variant {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
let data = self.variant_data(f.db); let data = self.variant_data(f.db);
match &*data { match &*data {
VariantData::Unit => {} VariantData::Unit => {}
@ -424,9 +424,9 @@ impl HirDisplay for ExternCrateDecl {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
f.write_str("extern crate ")?; f.write_str("extern crate ")?;
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
if let Some(alias) = self.alias(f.db) { if let Some(alias) = self.alias(f.db) {
write!(f, " as {alias}",)?; write!(f, " as {}", alias.display(f.edition()))?;
} }
Ok(()) Ok(())
} }
@ -478,7 +478,7 @@ impl HirDisplay for TypeParam {
match param_data { match param_data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeOrConstParamData::TypeParamData(p) => match p.provenance {
TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
write!(f, "{}", p.name.clone().unwrap().display(f.db.upcast()))? write!(f, "{}", p.name.clone().unwrap().display(f.db.upcast(), f.edition()))?
} }
TypeParamProvenance::ArgumentImplTrait => { TypeParamProvenance::ArgumentImplTrait => {
return write_bounds_like_dyn_trait_with_prefix( return write_bounds_like_dyn_trait_with_prefix(
@ -491,7 +491,7 @@ impl HirDisplay for TypeParam {
} }
}, },
TypeOrConstParamData::ConstParamData(p) => { TypeOrConstParamData::ConstParamData(p) => {
write!(f, "{}", p.name.display(f.db.upcast()))?; write!(f, "{}", p.name.display(f.db.upcast(), f.edition()))?;
} }
} }
@ -525,13 +525,13 @@ impl HirDisplay for TypeParam {
impl HirDisplay for LifetimeParam { impl HirDisplay for LifetimeParam {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write!(f, "{}", self.name(f.db).display(f.db.upcast())) write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))
} }
} }
impl HirDisplay for ConstParam { impl HirDisplay for ConstParam {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write!(f, "const {}: ", self.name(f.db).display(f.db.upcast()))?; write!(f, "const {}: ", self.name(f.db).display(f.db.upcast(), f.edition()))?;
self.ty(f.db).hir_fmt(f) self.ty(f.db).hir_fmt(f)
} }
} }
@ -563,7 +563,7 @@ fn write_generic_params(
}; };
for (_, lifetime) in params.iter_lt() { for (_, lifetime) in params.iter_lt() {
delim(f)?; delim(f)?;
write!(f, "{}", lifetime.name.display(f.db.upcast()))?; write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))?;
} }
for (_, ty) in params.iter_type_or_consts() { for (_, ty) in params.iter_type_or_consts() {
if let Some(name) = &ty.name() { if let Some(name) = &ty.name() {
@ -573,7 +573,7 @@ fn write_generic_params(
continue; continue;
} }
delim(f)?; delim(f)?;
write!(f, "{}", name.display(f.db.upcast()))?; write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
if let Some(default) = &ty.default { if let Some(default) = &ty.default {
f.write_str(" = ")?; f.write_str(" = ")?;
default.hir_fmt(f)?; default.hir_fmt(f)?;
@ -581,12 +581,12 @@ fn write_generic_params(
} }
TypeOrConstParamData::ConstParamData(c) => { TypeOrConstParamData::ConstParamData(c) => {
delim(f)?; delim(f)?;
write!(f, "const {}: ", name.display(f.db.upcast()))?; write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?;
c.ty.hir_fmt(f)?; c.ty.hir_fmt(f)?;
if let Some(default) = &c.default { if let Some(default) = &c.default {
f.write_str(" = ")?; f.write_str(" = ")?;
write!(f, "{}", default.display(f.db.upcast()))?; write!(f, "{}", default.display(f.db.upcast(), f.edition()))?;
} }
} }
} }
@ -639,7 +639,7 @@ fn write_where_predicates(
let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target { let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() { WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
Some(name) => write!(f, "{}", name.display(f.db.upcast())), Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())),
None => f.write_str("{unnamed}"), None => f.write_str("{unnamed}"),
}, },
}; };
@ -668,12 +668,13 @@ fn write_where_predicates(
bound.hir_fmt(f)?; bound.hir_fmt(f)?;
} }
Lifetime { target, bound } => { Lifetime { target, bound } => {
let target = target.name.display(f.db.upcast()); let target = target.name.display(f.db.upcast(), f.edition());
let bound = bound.name.display(f.db.upcast()); let bound = bound.name.display(f.db.upcast(), f.edition());
write!(f, "{target}: {bound}")?; write!(f, "{target}: {bound}")?;
} }
ForLifetime { lifetimes, target, bound } => { ForLifetime { lifetimes, target, bound } => {
let lifetimes = lifetimes.iter().map(|it| it.display(f.db.upcast())).join(", "); let lifetimes =
lifetimes.iter().map(|it| it.display(f.db.upcast(), f.edition())).join(", ");
write!(f, "for<{lifetimes}> ")?; write!(f, "for<{lifetimes}> ")?;
write_target(target, f)?; write_target(target, f)?;
f.write_str(": ")?; f.write_str(": ")?;
@ -685,7 +686,9 @@ fn write_where_predicates(
f.write_str(" + ")?; f.write_str(" + ")?;
match nxt { match nxt {
TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?, TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?,
Lifetime { bound, .. } => write!(f, "{}", bound.name.display(f.db.upcast()))?, Lifetime { bound, .. } => {
write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))?
}
} }
} }
f.write_str(",")?; f.write_str(",")?;
@ -707,7 +710,7 @@ impl HirDisplay for Const {
let data = db.const_data(self.id); let data = db.const_data(self.id);
f.write_str("const ")?; f.write_str("const ")?;
match &data.name { match &data.name {
Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?, Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?,
None => f.write_str("_: ")?, None => f.write_str("_: ")?,
} }
data.type_ref.hir_fmt(f)?; data.type_ref.hir_fmt(f)?;
@ -723,7 +726,7 @@ impl HirDisplay for Static {
if data.mutable { if data.mutable {
f.write_str("mut ")?; f.write_str("mut ")?;
} }
write!(f, "{}: ", data.name.display(f.db.upcast()))?; write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?;
data.type_ref.hir_fmt(f)?; data.type_ref.hir_fmt(f)?;
Ok(()) Ok(())
} }
@ -777,7 +780,7 @@ fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), Hi
if data.is_auto { if data.is_auto {
f.write_str("auto ")?; f.write_str("auto ")?;
} }
write!(f, "trait {}", data.name.display(f.db.upcast()))?; write!(f, "trait {}", data.name.display(f.db.upcast(), f.edition()))?;
write_generic_params(GenericDefId::TraitId(trait_.id), f)?; write_generic_params(GenericDefId::TraitId(trait_.id), f)?;
Ok(()) Ok(())
} }
@ -786,7 +789,7 @@ impl HirDisplay for TraitAlias {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
let data = f.db.trait_alias_data(self.id); let data = f.db.trait_alias_data(self.id);
write!(f, "trait {}", data.name.display(f.db.upcast()))?; write!(f, "trait {}", data.name.display(f.db.upcast(), f.edition()))?;
let def_id = GenericDefId::TraitAliasId(self.id); let def_id = GenericDefId::TraitAliasId(self.id);
write_generic_params(def_id, f)?; write_generic_params(def_id, f)?;
f.write_str(" = ")?; f.write_str(" = ")?;
@ -802,7 +805,7 @@ impl HirDisplay for TypeAlias {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
let data = f.db.type_alias_data(self.id); let data = f.db.type_alias_data(self.id);
write!(f, "type {}", data.name.display(f.db.upcast()))?; write!(f, "type {}", data.name.display(f.db.upcast(), f.edition()))?;
let def_id = GenericDefId::TypeAliasId(self.id); let def_id = GenericDefId::TypeAliasId(self.id);
write_generic_params(def_id, f)?; write_generic_params(def_id, f)?;
if !data.bounds.is_empty() { if !data.bounds.is_empty() {
@ -822,7 +825,7 @@ impl HirDisplay for Module {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
// FIXME: Module doesn't have visibility saved in data. // FIXME: Module doesn't have visibility saved in data.
match self.name(f.db) { match self.name(f.db) {
Some(name) => write!(f, "mod {}", name.display(f.db.upcast())), Some(name) => write!(f, "mod {}", name.display(f.db.upcast(), f.edition())),
None if self.is_crate_root() => match self.krate(f.db).display_name(f.db) { None if self.is_crate_root() => match self.krate(f.db).display_name(f.db) {
Some(name) => write!(f, "extern crate {name}"), Some(name) => write!(f, "extern crate {name}"),
None => f.write_str("extern crate {unknown}"), None => f.write_str("extern crate {unknown}"),
@ -839,6 +842,6 @@ impl HirDisplay for Macro {
hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"), hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"),
hir_def::MacroId::ProcMacroId(_) => f.write_str("proc_macro"), hir_def::MacroId::ProcMacroId(_) => f.write_str("proc_macro"),
}?; }?;
write!(f, " {}", self.name(f.db).display(f.db.upcast())) write!(f, " {}", self.name(f.db).display(f.db.upcast(), f.edition()))
} }
} }

View file

@ -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)?]; let mut segments = vec![self.name(db)?];
for m in self.module(db)?.path_to_root(db) { for m in self.module(db)?.path_to_root(db) {
segments.extend(m.name(db)) segments.extend(m.name(db))
} }
segments.reverse(); 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( pub fn canonical_module_path(
@ -556,13 +556,14 @@ impl Module {
style_lints: bool, style_lints: bool,
) { ) {
let _p = tracing::info_span!("Module::diagnostics", name = ?self.name(db)).entered(); 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()); let def_map = self.id.def_map(db.upcast());
for diag in def_map.diagnostics() { for diag in def_map.diagnostics() {
if diag.in_module != self.id.local_id { if diag.in_module != self.id.local_id {
// FIXME: This is accidentally quadratic. // FIXME: This is accidentally quadratic.
continue; continue;
} }
emit_def_diagnostic(db, acc, diag); emit_def_diagnostic(db, acc, diag, edition);
} }
if !self.id.is_block_module() { if !self.id.is_block_module() {
@ -582,7 +583,7 @@ impl Module {
} }
ModuleDef::Trait(t) => { ModuleDef::Trait(t) => {
for diag in db.trait_data_with_diagnostics(t.id).1.iter() { 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) { for item in t.items(db) {
@ -599,19 +600,19 @@ impl Module {
match adt { match adt {
Adt::Struct(s) => { Adt::Struct(s) => {
for diag in db.struct_data_with_diagnostics(s.id).1.iter() { 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) => { Adt::Union(u) => {
for diag in db.union_data_with_diagnostics(u.id).1.iter() { 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) => { Adt::Enum(e) => {
for v in e.variants(db) { for v in e.variants(db) {
acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints)); acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints));
for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { 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); let ast_id_map = db.ast_id_map(file_id);
for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() { 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) { 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); never!("declarative expander for non decl-macro: {:?}", e);
return; return;
}; };
let krate = HasModule::krate(&m.id, db.upcast());
let edition = db.crate_graph()[krate].edition;
emit_def_diagnostic_( emit_def_diagnostic_(
db, db,
acc, acc,
&DefDiagnosticKind::MacroDefError { ast, message: e.to_string() }, &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() },
edition,
); );
} }
} }
} }
fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) { fn emit_def_diagnostic(
emit_def_diagnostic_(db, acc, &diag.kind) db: &dyn HirDatabase,
acc: &mut Vec<AnyDiagnostic>,
diag: &DefDiagnostic,
edition: Edition,
) {
emit_def_diagnostic_(db, acc, &diag.kind, edition)
} }
fn emit_def_diagnostic_( fn emit_def_diagnostic_(
db: &dyn HirDatabase, db: &dyn HirDatabase,
acc: &mut Vec<AnyDiagnostic>, acc: &mut Vec<AnyDiagnostic>,
diag: &DefDiagnosticKind, diag: &DefDiagnosticKind,
edition: Edition,
) { ) {
match diag { match diag {
DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => { DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
@ -910,7 +920,7 @@ fn emit_def_diagnostic_(
MacroError { MacroError {
node: InFile::new(ast.file_id, item.syntax_node_ptr()), node: InFile::new(ast.file_id, item.syntax_node_ptr()),
precise_location: None, precise_location: None,
message: format!("{}: {message}", path.display(db.upcast())), message: format!("{}: {message}", path.display(db.upcast(), edition)),
error, error,
} }
.into(), .into(),
@ -1764,7 +1774,7 @@ impl DefWithBody {
/// A textual representation of the HIR of this def's body for debugging purposes. /// A textual representation of the HIR of this def's body for debugging purposes.
pub fn debug_hir(self, db: &dyn HirDatabase) -> String { pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
let body = db.body(self.id()); 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. /// A textual representation of the MIR of this def's body for debugging purposes.
@ -2259,6 +2269,8 @@ impl Function {
db: &dyn HirDatabase, db: &dyn HirDatabase,
span_formatter: impl Fn(FileId, TextRange) -> String, span_formatter: impl Fn(FileId, TextRange) -> String,
) -> String { ) -> String {
let krate = HasModule::krate(&self.id, db.upcast());
let edition = db.crate_graph()[krate].edition;
let body = match db.monomorphized_mir_body( let body = match db.monomorphized_mir_body(
self.id.into(), self.id.into(),
Substitution::empty(Interner), Substitution::empty(Interner),
@ -2267,7 +2279,7 @@ impl Function {
Ok(body) => body, Ok(body) => body,
Err(e) => { Err(e) => {
let mut r = String::new(); let mut r = String::new();
_ = e.pretty_print(&mut r, db, &span_formatter); _ = e.pretty_print(&mut r, db, &span_formatter, edition);
return r; return r;
} }
}; };
@ -2276,7 +2288,7 @@ impl Function {
Ok(_) => "pass".to_owned(), Ok(_) => "pass".to_owned(),
Err(e) => { Err(e) => {
let mut r = String::new(); let mut r = String::new();
_ = e.pretty_print(&mut r, db, &span_formatter); _ = e.pretty_print(&mut r, db, &span_formatter, edition);
r r
} }
}; };
@ -2510,7 +2522,11 @@ impl Const {
Type::from_value_def(db, self.id) 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 c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?;
let data = &c.data(Interner); let data = &c.data(Interner);
if let TyKind::Scalar(s) = data.ty.kind(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) { if let Ok(s) = mir::render_const_using_debug_impl(db, self.id, &c) {
Ok(s) Ok(s)
} else { } 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)) 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())?; 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) TyKind::Closure(self.id, self.subst).intern(Interner)
} }
pub fn display_with_id(&self, db: &dyn HirDatabase) -> String { pub fn display_with_id(&self, db: &dyn HirDatabase, edition: Edition) -> String {
self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ClosureWithId).to_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 { pub fn display_with_impl(&self, db: &dyn HirDatabase, edition: Edition) -> String {
self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ImplFn).to_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> { pub fn captured_items(&self, db: &dyn HirDatabase) -> Vec<ClosureCapture> {
@ -4704,18 +4728,20 @@ impl Type {
pub fn type_and_const_arguments<'a>( pub fn type_and_const_arguments<'a>(
&'a self, &'a self,
db: &'a dyn HirDatabase, db: &'a dyn HirDatabase,
edition: Edition,
) -> impl Iterator<Item = SmolStr> + 'a { ) -> impl Iterator<Item = SmolStr> + 'a {
self.ty self.ty
.strip_references() .strip_references()
.as_adt() .as_adt()
.into_iter() .into_iter()
.flat_map(|(_, substs)| substs.iter(Interner)) .flat_map(|(_, substs)| substs.iter(Interner))
.filter_map(|arg| { .filter_map(move |arg| {
// arg can be either a `Ty` or `constant` // arg can be either a `Ty` or `constant`
if let Some(ty) = arg.ty(Interner) { if let Some(ty) = arg.ty(Interner) {
Some(format_smolstr!("{}", ty.display(db))) Some(format_smolstr!("{}", ty.display(db, edition)))
} else { } else {
arg.constant(Interner).map(|const_| format_smolstr!("{}", const_.display(db))) arg.constant(Interner)
.map(|const_| format_smolstr!("{}", const_.display(db, edition)))
} }
}) })
} }
@ -4724,13 +4750,17 @@ impl Type {
pub fn generic_parameters<'a>( pub fn generic_parameters<'a>(
&'a self, &'a self,
db: &'a dyn HirDatabase, db: &'a dyn HirDatabase,
edition: Edition,
) -> impl Iterator<Item = SmolStr> + 'a { ) -> impl Iterator<Item = SmolStr> + 'a {
// iterate the lifetime // iterate the lifetime
self.as_adt() 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() .into_iter()
// add the type and const parameters // 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>( pub fn iterate_method_candidates_with_traits<T>(

View file

@ -9,6 +9,7 @@ use hir_def::{
}; };
use hir_expand::HirFileId; use hir_expand::HirFileId;
use hir_ty::{db::HirDatabase, display::HirDisplay}; use hir_ty::{db::HirDatabase, display::HirDisplay};
use span::Edition;
use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr}; use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr};
use crate::{Module, ModuleDef, Semantics}; use crate::{Module, ModuleDef, Semantics};
@ -54,6 +55,7 @@ pub struct SymbolCollector<'a> {
symbols: Vec<FileSymbol>, symbols: Vec<FileSymbol>,
work: Vec<SymbolCollectorWork>, work: Vec<SymbolCollectorWork>,
current_container_name: Option<SmolStr>, current_container_name: Option<SmolStr>,
edition: Edition,
} }
/// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect /// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect
@ -65,10 +67,13 @@ impl<'a> SymbolCollector<'a> {
symbols: Default::default(), symbols: Default::default(),
work: Default::default(), work: Default::default(),
current_container_name: None, current_container_name: None,
edition: Edition::Edition2015,
} }
} }
pub fn collect(&mut self, module: Module) { pub fn collect(&mut self, module: Module) {
self.edition = module.krate().edition(self.db);
// The initial work is the root module we're collecting, additional work will // The initial work is the root module we're collecting, additional work will
// be populated as we traverse the module's definitions. // be populated as we traverse the module's definitions.
self.work.push(SymbolCollectorWork { module_id: module.into(), parent: None }); self.work.push(SymbolCollectorWork { module_id: module.into(), parent: None });
@ -209,7 +214,8 @@ impl<'a> SymbolCollector<'a> {
fn collect_from_impl(&mut self, impl_id: ImplId) { fn collect_from_impl(&mut self, impl_id: ImplId) {
let impl_data = self.db.impl_data(impl_id); let impl_data = self.db.impl_data(impl_id);
let impl_name = Some(SmolStr::new(impl_data.self_ty.display(self.db).to_string())); let impl_name =
Some(SmolStr::new(impl_data.self_ty.display(self.db, self.edition).to_string()));
self.with_container_name(impl_name, |s| { self.with_container_name(impl_name, |s| {
for &assoc_item_id in impl_data.items.iter() { for &assoc_item_id in impl_data.items.iter() {
s.push_assoc_item(assoc_item_id) s.push_assoc_item(assoc_item_id)
@ -239,16 +245,16 @@ impl<'a> SymbolCollector<'a> {
fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option<SmolStr> { fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option<SmolStr> {
match body_id { match body_id {
DefWithBodyId::FunctionId(id) => { DefWithBodyId::FunctionId(id) => {
Some(self.db.function_data(id).name.display_no_db().to_smolstr()) Some(self.db.function_data(id).name.display_no_db(self.edition).to_smolstr())
} }
DefWithBodyId::StaticId(id) => { DefWithBodyId::StaticId(id) => {
Some(self.db.static_data(id).name.display_no_db().to_smolstr()) Some(self.db.static_data(id).name.display_no_db(self.edition).to_smolstr())
} }
DefWithBodyId::ConstId(id) => { DefWithBodyId::ConstId(id) => {
Some(self.db.const_data(id).name.as_ref()?.display_no_db().to_smolstr()) Some(self.db.const_data(id).name.as_ref()?.display_no_db(self.edition).to_smolstr())
} }
DefWithBodyId::VariantId(id) => { DefWithBodyId::VariantId(id) => {
Some(self.db.enum_variant_data(id).name.display_no_db().to_smolstr()) Some(self.db.enum_variant_data(id).name.display_no_db(self.edition).to_smolstr())
} }
DefWithBodyId::InTypeConstId(_) => Some("in type const".into()), DefWithBodyId::InTypeConstId(_) => Some("in type const".into()),
} }

View file

@ -7,6 +7,7 @@ use hir_ty::{
display::{DisplaySourceCodeError, HirDisplay}, display::{DisplaySourceCodeError, HirDisplay},
}; };
use itertools::Itertools; use itertools::Itertools;
use span::Edition;
use crate::{ use crate::{
Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, Local, ModuleDef, Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, Local, ModuleDef,
@ -29,9 +30,10 @@ fn mod_item_path_str(
sema_scope: &SemanticsScope<'_>, sema_scope: &SemanticsScope<'_>,
def: &ModuleDef, def: &ModuleDef,
cfg: ImportPathConfig, cfg: ImportPathConfig,
edition: Edition,
) -> Result<String, DisplaySourceCodeError> { ) -> Result<String, DisplaySourceCodeError> {
let path = mod_item_path(sema_scope, def, cfg); let path = mod_item_path(sema_scope, def, cfg);
path.map(|it| it.display(sema_scope.db.upcast()).to_string()) path.map(|it| it.display(sema_scope.db.upcast(), edition).to_string())
.ok_or(DisplaySourceCodeError::PathNotFound) .ok_or(DisplaySourceCodeError::PathNotFound)
} }
@ -97,37 +99,38 @@ impl Expr {
sema_scope: &SemanticsScope<'_>, sema_scope: &SemanticsScope<'_>,
many_formatter: &mut dyn FnMut(&Type) -> String, many_formatter: &mut dyn FnMut(&Type) -> String,
cfg: ImportPathConfig, cfg: ImportPathConfig,
edition: Edition,
) -> Result<String, DisplaySourceCodeError> { ) -> Result<String, DisplaySourceCodeError> {
let db = sema_scope.db; let db = sema_scope.db;
let mod_item_path_str = |s, def| mod_item_path_str(s, def, cfg); let mod_item_path_str = |s, def| mod_item_path_str(s, def, cfg, edition);
match self { match self {
Expr::Const(it) => match it.as_assoc_item(db).map(|it| it.container(db)) { Expr::Const(it) => match it.as_assoc_item(db).map(|it| it.container(db)) {
Some(container) => { Some(container) => {
let container_name = container_name(container, sema_scope, cfg)?; let container_name = container_name(container, sema_scope, cfg, edition)?;
let const_name = it let const_name = it
.name(db) .name(db)
.map(|c| c.display(db.upcast()).to_string()) .map(|c| c.display(db.upcast(), edition).to_string())
.unwrap_or(String::new()); .unwrap_or(String::new());
Ok(format!("{container_name}::{const_name}")) Ok(format!("{container_name}::{const_name}"))
} }
None => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)), None => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)),
}, },
Expr::Static(it) => mod_item_path_str(sema_scope, &ModuleDef::Static(*it)), Expr::Static(it) => mod_item_path_str(sema_scope, &ModuleDef::Static(*it)),
Expr::Local(it) => Ok(it.name(db).display(db.upcast()).to_string()), Expr::Local(it) => Ok(it.name(db).display(db.upcast(), edition).to_string()),
Expr::ConstParam(it) => Ok(it.name(db).display(db.upcast()).to_string()), Expr::ConstParam(it) => Ok(it.name(db).display(db.upcast(), edition).to_string()),
Expr::FamousType { value, .. } => Ok(value.to_string()), Expr::FamousType { value, .. } => Ok(value.to_string()),
Expr::Function { func, params, .. } => { Expr::Function { func, params, .. } => {
let args = params let args = params
.iter() .iter()
.map(|f| f.gen_source_code(sema_scope, many_formatter, cfg)) .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition))
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()? .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter() .into_iter()
.join(", "); .join(", ");
match func.as_assoc_item(db).map(|it| it.container(db)) { match func.as_assoc_item(db).map(|it| it.container(db)) {
Some(container) => { Some(container) => {
let container_name = container_name(container, sema_scope, cfg)?; let container_name = container_name(container, sema_scope, cfg, edition)?;
let fn_name = func.name(db).display(db.upcast()).to_string(); let fn_name = func.name(db).display(db.upcast(), edition).to_string();
Ok(format!("{container_name}::{fn_name}({args})")) Ok(format!("{container_name}::{fn_name}({args})"))
} }
None => { None => {
@ -141,12 +144,13 @@ impl Expr {
return Ok(many_formatter(&target.ty(db))); return Ok(many_formatter(&target.ty(db)));
} }
let func_name = func.name(db).display(db.upcast()).to_string(); let func_name = func.name(db).display(db.upcast(), edition).to_string();
let self_param = func.self_param(db).unwrap(); let self_param = func.self_param(db).unwrap();
let target_str = target.gen_source_code(sema_scope, many_formatter, cfg)?; let target_str =
target.gen_source_code(sema_scope, many_formatter, cfg, edition)?;
let args = params let args = params
.iter() .iter()
.map(|f| f.gen_source_code(sema_scope, many_formatter, cfg)) .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition))
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()? .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter() .into_iter()
.join(", "); .join(", ");
@ -176,7 +180,7 @@ impl Expr {
StructKind::Tuple => { StructKind::Tuple => {
let args = params let args = params
.iter() .iter()
.map(|f| f.gen_source_code(sema_scope, many_formatter, cfg)) .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition))
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()? .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter() .into_iter()
.join(", "); .join(", ");
@ -190,8 +194,8 @@ impl Expr {
.map(|(a, f)| { .map(|(a, f)| {
let tmp = format!( let tmp = format!(
"{}: {}", "{}: {}",
f.name(db).display(db.upcast()), f.name(db).display(db.upcast(), edition),
a.gen_source_code(sema_scope, many_formatter, cfg)? a.gen_source_code(sema_scope, many_formatter, cfg, edition)?
); );
Ok(tmp) Ok(tmp)
}) })
@ -211,7 +215,7 @@ impl Expr {
StructKind::Tuple => { StructKind::Tuple => {
let args = params let args = params
.iter() .iter()
.map(|a| a.gen_source_code(sema_scope, many_formatter, cfg)) .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg, edition))
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()? .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter() .into_iter()
.join(", "); .join(", ");
@ -225,8 +229,8 @@ impl Expr {
.map(|(a, f)| { .map(|(a, f)| {
let tmp = format!( let tmp = format!(
"{}: {}", "{}: {}",
f.name(db).display(db.upcast()), f.name(db).display(db.upcast(), edition),
a.gen_source_code(sema_scope, many_formatter, cfg)? a.gen_source_code(sema_scope, many_formatter, cfg, edition)?
); );
Ok(tmp) Ok(tmp)
}) })
@ -244,7 +248,7 @@ impl Expr {
Expr::Tuple { params, .. } => { Expr::Tuple { params, .. } => {
let args = params let args = params
.iter() .iter()
.map(|a| a.gen_source_code(sema_scope, many_formatter, cfg)) .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg, edition))
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()? .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter() .into_iter()
.join(", "); .join(", ");
@ -256,8 +260,8 @@ impl Expr {
return Ok(many_formatter(&expr.ty(db))); return Ok(many_formatter(&expr.ty(db)));
} }
let strukt = expr.gen_source_code(sema_scope, many_formatter, cfg)?; let strukt = expr.gen_source_code(sema_scope, many_formatter, cfg, edition)?;
let field = field.name(db).display(db.upcast()).to_string(); let field = field.name(db).display(db.upcast(), edition).to_string();
Ok(format!("{strukt}.{field}")) Ok(format!("{strukt}.{field}"))
} }
Expr::Reference(expr) => { Expr::Reference(expr) => {
@ -265,7 +269,7 @@ impl Expr {
return Ok(many_formatter(&expr.ty(db))); return Ok(many_formatter(&expr.ty(db)));
} }
let inner = expr.gen_source_code(sema_scope, many_formatter, cfg)?; let inner = expr.gen_source_code(sema_scope, many_formatter, cfg, edition)?;
Ok(format!("&{inner}")) Ok(format!("&{inner}"))
} }
Expr::Many(ty) => Ok(many_formatter(ty)), Expr::Many(ty) => Ok(many_formatter(ty)),
@ -353,17 +357,18 @@ fn container_name(
container: AssocItemContainer, container: AssocItemContainer,
sema_scope: &SemanticsScope<'_>, sema_scope: &SemanticsScope<'_>,
cfg: ImportPathConfig, cfg: ImportPathConfig,
edition: Edition,
) -> Result<String, DisplaySourceCodeError> { ) -> Result<String, DisplaySourceCodeError> {
let container_name = match container { let container_name = match container {
crate::AssocItemContainer::Trait(trait_) => { crate::AssocItemContainer::Trait(trait_) => {
mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_), cfg)? mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_), cfg, edition)?
} }
crate::AssocItemContainer::Impl(imp) => { crate::AssocItemContainer::Impl(imp) => {
let self_ty = imp.self_ty(sema_scope.db); let self_ty = imp.self_ty(sema_scope.db);
// Should it be guaranteed that `mod_item_path` always exists? // Should it be guaranteed that `mod_item_path` always exists?
match self_ty.as_adt().and_then(|adt| mod_item_path(sema_scope, &adt.into(), cfg)) { match self_ty.as_adt().and_then(|adt| mod_item_path(sema_scope, &adt.into(), cfg)) {
Some(path) => path.display(sema_scope.db.upcast()).to_string(), Some(path) => path.display(sema_scope.db.upcast(), edition).to_string(),
None => self_ty.display(sema_scope.db).to_string(), None => self_ty.display(sema_scope.db, edition).to_string(),
} }
} }
}; };

View file

@ -1,5 +1,8 @@
use hir::HasSource; use hir::HasSource;
use syntax::ast::{self, make, AstNode}; use syntax::{
ast::{self, make, AstNode},
Edition,
};
use crate::{ use crate::{
assist_context::{AssistContext, Assists}, assist_context::{AssistContext, Assists},
@ -150,14 +153,22 @@ fn add_missing_impl_members_inner(
&missing_items, &missing_items,
trait_, trait_,
&new_impl_def, &new_impl_def,
target_scope, &target_scope,
); );
if let Some(cap) = ctx.config.snippet_cap { if let Some(cap) = ctx.config.snippet_cap {
let mut placeholder = None; let mut placeholder = None;
if let DefaultMethods::No = mode { if let DefaultMethods::No = mode {
if let ast::AssocItem::Fn(func) = &first_new_item { if let ast::AssocItem::Fn(func) = &first_new_item {
if try_gen_trait_body(ctx, func, trait_ref, &impl_def).is_none() { if try_gen_trait_body(
ctx,
func,
trait_ref,
&impl_def,
target_scope.krate().edition(ctx.sema.db),
)
.is_none()
{
if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
{ {
if m.syntax().text() == "todo!()" { if m.syntax().text() == "todo!()" {
@ -182,9 +193,11 @@ fn try_gen_trait_body(
func: &ast::Fn, func: &ast::Fn,
trait_ref: hir::TraitRef, trait_ref: hir::TraitRef,
impl_def: &ast::Impl, impl_def: &ast::Impl,
edition: Edition,
) -> Option<()> { ) -> Option<()> {
let trait_path = let trait_path = make::ext::ident_path(
make::ext::ident_path(&trait_ref.trait_().name(ctx.db()).display(ctx.db()).to_string()); &trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string(),
);
let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?; let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?;
let adt = hir_ty.as_adt()?.source(ctx.db())?; let adt = hir_ty.as_adt()?.source(ctx.db())?;
gen_trait_fn_body(func, &trait_path, &adt.value, Some(trait_ref)) gen_trait_fn_body(func, &trait_path, &adt.value, Some(trait_ref))

View file

@ -445,7 +445,8 @@ fn build_pat(
) -> Option<ast::Pat> { ) -> Option<ast::Pat> {
match var { match var {
ExtendedVariant::Variant(var) => { ExtendedVariant::Variant(var) => {
let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?); let edition = module.krate().edition(db);
let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition);
// FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
Some(match var.source(db)?.value.kind() { Some(match var.source(db)?.value.kind() {
ast::StructKind::Tuple(field_list) => { ast::StructKind::Tuple(field_list) => {

View file

@ -8,7 +8,7 @@ use ide_db::{
insert_use::{insert_use, insert_use_as_alias, ImportScope}, insert_use::{insert_use, insert_use_as_alias, ImportScope},
}, },
}; };
use syntax::{ast, AstNode, NodeOrToken, SyntaxElement}; use syntax::{ast, AstNode, Edition, NodeOrToken, SyntaxElement};
use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
@ -120,13 +120,14 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
// prioritize more relevant imports // prioritize more relevant imports
proposed_imports proposed_imports
.sort_by_key(|import| Reverse(relevance_score(ctx, import, current_module.as_ref()))); .sort_by_key(|import| Reverse(relevance_score(ctx, import, current_module.as_ref())));
let edition = current_module.map(|it| it.krate().edition(ctx.db())).unwrap_or(Edition::CURRENT);
let group_label = group_label(import_assets.import_candidate()); let group_label = group_label(import_assets.import_candidate());
for import in proposed_imports { for import in proposed_imports {
let import_path = import.import_path; let import_path = import.import_path;
let (assist_id, import_name) = let (assist_id, import_name) =
(AssistId("auto_import", AssistKind::QuickFix), import_path.display(ctx.db())); (AssistId("auto_import", AssistKind::QuickFix), import_path.display(ctx.db(), edition));
acc.add_group( acc.add_group(
&group_label, &group_label,
assist_id, assist_id,
@ -138,7 +139,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
}; };
insert_use(&scope, mod_path_to_ast(&import_path), &ctx.config.insert_use); insert_use(&scope, mod_path_to_ast(&import_path, edition), &ctx.config.insert_use);
}, },
); );
@ -165,7 +166,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
}; };
insert_use_as_alias( insert_use_as_alias(
&scope, &scope,
mod_path_to_ast(&import_path), mod_path_to_ast(&import_path, edition),
&ctx.config.insert_use, &ctx.config.insert_use,
); );
}, },

View file

@ -339,6 +339,7 @@ fn augment_references_with_imports(
let cfg = ctx.config.import_path_config(); let cfg = ctx.config.import_path_config();
let edition = target_module.krate().edition(ctx.db());
references references
.into_iter() .into_iter()
.filter_map(|FileReference { range, name, .. }| { .filter_map(|FileReference { range, name, .. }| {
@ -361,7 +362,10 @@ fn augment_references_with_imports(
cfg, cfg,
) )
.map(|mod_path| { .map(|mod_path| {
make::path_concat(mod_path_to_ast(&mod_path), make::path_from_text("Bool")) make::path_concat(
mod_path_to_ast(&mod_path, edition),
make::path_from_text("Bool"),
)
}); });
import_scope.zip(path) import_scope.zip(path)

View file

@ -159,7 +159,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
}; };
// Verify this is `bool::then` that is being called. // Verify this is `bool::then` that is being called.
let func = ctx.sema.resolve_method_call(&mcall)?; let func = ctx.sema.resolve_method_call(&mcall)?;
if func.name(ctx.sema.db).display(ctx.db()).to_string() != "then" { if !func.name(ctx.sema.db).eq_ident("then") {
return None; return None;
} }
let assoc = func.as_assoc_item(ctx.sema.db)?; let assoc = func.as_assoc_item(ctx.sema.db)?;

View file

@ -51,7 +51,10 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
Some(hir::PathResolution::Def(module_def)) => module_def, Some(hir::PathResolution::Def(module_def)) => module_def,
_ => return None, _ => return None,
}; };
mod_path_to_ast(&module.find_path(ctx.db(), src_type_def, cfg)?) mod_path_to_ast(
&module.find_path(ctx.db(), src_type_def, cfg)?,
module.krate().edition(ctx.db()),
)
}; };
let dest_type = match &ast_trait { let dest_type = match &ast_trait {

View file

@ -114,12 +114,16 @@ pub(crate) fn convert_for_loop_with_for_each(
|builder| { |builder| {
let mut buf = String::new(); let mut buf = String::new();
if let Some((expr_behind_ref, method)) = if let Some((expr_behind_ref, method, krate)) =
is_ref_and_impls_iter_method(&ctx.sema, &iterable) is_ref_and_impls_iter_method(&ctx.sema, &iterable)
{ {
// We have either "for x in &col" and col implements a method called iter // We have either "for x in &col" and col implements a method called iter
// or "for x in &mut col" and col implements a method called iter_mut // or "for x in &mut col" and col implements a method called iter_mut
format_to!(buf, "{expr_behind_ref}.{}()", method.display(ctx.db())); format_to!(
buf,
"{expr_behind_ref}.{}()",
method.display(ctx.db(), krate.edition(ctx.db()))
);
} else if let ast::Expr::RangeExpr(..) = iterable { } else if let ast::Expr::RangeExpr(..) = iterable {
// range expressions need to be parenthesized for the syntax to be correct // range expressions need to be parenthesized for the syntax to be correct
format_to!(buf, "({iterable})"); format_to!(buf, "({iterable})");
@ -144,7 +148,7 @@ pub(crate) fn convert_for_loop_with_for_each(
fn is_ref_and_impls_iter_method( fn is_ref_and_impls_iter_method(
sema: &hir::Semantics<'_, ide_db::RootDatabase>, sema: &hir::Semantics<'_, ide_db::RootDatabase>,
iterable: &ast::Expr, iterable: &ast::Expr,
) -> Option<(ast::Expr, hir::Name)> { ) -> Option<(ast::Expr, hir::Name, hir::Crate)> {
let ref_expr = match iterable { let ref_expr = match iterable {
ast::Expr::RefExpr(r) => r, ast::Expr::RefExpr(r) => r,
_ => return None, _ => return None,
@ -172,7 +176,7 @@ fn is_ref_and_impls_iter_method(
return None; return None;
} }
Some((expr_behind_ref, wanted_method)) Some((expr_behind_ref, wanted_method, krate))
} }
/// Whether iterable implements core::Iterator /// Whether iterable implements core::Iterator

View file

@ -211,7 +211,7 @@ fn augment_references_with_imports(
) )
.map(|mod_path| { .map(|mod_path| {
make::path_concat( make::path_concat(
mod_path_to_ast(&mod_path), mod_path_to_ast(&mod_path, target_module.krate().edition(ctx.db())),
make::path_from_text(struct_name), make::path_from_text(struct_name),
) )
}); });

View file

@ -7,7 +7,7 @@ use ide_db::{
FxHashMap, FxHashSet, FxHashMap, FxHashSet,
}; };
use itertools::Itertools; use itertools::Itertools;
use syntax::{ast, ted, AstNode, SmolStr, SyntaxNode, ToSmolStr}; use syntax::{ast, ted, AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr};
use text_edit::TextRange; use text_edit::TextRange;
use crate::{ use crate::{
@ -81,6 +81,7 @@ struct StructEditData {
has_private_members: bool, has_private_members: bool,
is_nested: bool, is_nested: bool,
is_ref: bool, is_ref: bool,
edition: Edition,
} }
fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<StructEditData> { fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<StructEditData> {
@ -145,6 +146,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
names_in_scope, names_in_scope,
is_nested, is_nested,
is_ref, is_ref,
edition: module.krate().edition(ctx.db()),
}) })
} }
@ -180,7 +182,7 @@ fn build_assignment_edit(
) -> AssignmentEdit { ) -> AssignmentEdit {
let ident_pat = builder.make_mut(data.ident_pat.clone()); let ident_pat = builder.make_mut(data.ident_pat.clone());
let struct_path = mod_path_to_ast(&data.struct_def_path); let struct_path = mod_path_to_ast(&data.struct_def_path, data.edition);
let is_ref = ident_pat.ref_token().is_some(); let is_ref = ident_pat.ref_token().is_some();
let is_mut = ident_pat.mut_token().is_some(); let is_mut = ident_pat.mut_token().is_some();
@ -247,7 +249,7 @@ fn generate_field_names(ctx: &AssistContext<'_>, data: &StructEditData) -> Vec<(
.visible_fields .visible_fields
.iter() .iter()
.map(|field| { .map(|field| {
let field_name = field.name(ctx.db()).display_no_db().to_smolstr(); let field_name = field.name(ctx.db()).display_no_db(data.edition).to_smolstr();
let new_name = new_field_name(field_name.clone(), &data.names_in_scope); let new_name = new_field_name(field_name.clone(), &data.names_in_scope);
(field_name, new_name) (field_name, new_name)
}) })

View file

@ -66,7 +66,9 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) ->
let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs); let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs);
let expanded = make::use_tree_list(names_to_import.iter().map(|n| { let expanded = make::use_tree_list(names_to_import.iter().map(|n| {
let path = make::ext::ident_path(&n.display(ctx.db()).to_string()); let path = make::ext::ident_path(
&n.display(ctx.db(), current_module.krate().edition(ctx.db())).to_string(),
);
make::use_tree(path, None, None, false) make::use_tree(path, None, None, false)
})) }))
.clone_for_update(); .clone_for_update();

View file

@ -23,7 +23,7 @@ use syntax::{
self, edit::IndentLevel, edit_in_place::Indent, AstNode, AstToken, HasGenericParams, self, edit::IndentLevel, edit_in_place::Indent, AstNode, AstToken, HasGenericParams,
HasName, HasName,
}, },
match_ast, ted, SyntaxElement, match_ast, ted, Edition, SyntaxElement,
SyntaxKind::{self, COMMENT}, SyntaxKind::{self, COMMENT},
SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
}; };
@ -84,7 +84,6 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
}; };
let body = extraction_target(&node, range)?; let body = extraction_target(&node, range)?;
let (container_info, contains_tail_expr) = body.analyze_container(&ctx.sema)?;
let (locals_used, self_param) = body.analyze(&ctx.sema); let (locals_used, self_param) = body.analyze(&ctx.sema);
@ -92,6 +91,9 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
let insert_after = node_to_insert_after(&body, anchor)?; let insert_after = node_to_insert_after(&body, anchor)?;
let semantics_scope = ctx.sema.scope(&insert_after)?; let semantics_scope = ctx.sema.scope(&insert_after)?;
let module = semantics_scope.module(); let module = semantics_scope.module();
let edition = semantics_scope.krate().edition(ctx.db());
let (container_info, contains_tail_expr) = body.analyze_container(&ctx.sema, edition)?;
let ret_ty = body.return_ty(ctx)?; let ret_ty = body.return_ty(ctx)?;
let control_flow = body.external_control_flow(ctx, &container_info)?; let control_flow = body.external_control_flow(ctx, &container_info)?;
@ -217,7 +219,11 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
); );
if let Some(mod_path) = mod_path { if let Some(mod_path) = mod_path {
insert_use(&scope, mod_path_to_ast(&mod_path), &ctx.config.insert_use); insert_use(
&scope,
mod_path_to_ast(&mod_path, edition),
&ctx.config.insert_use,
);
} }
} }
} }
@ -238,7 +244,13 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
fn make_function_name(semantics_scope: &hir::SemanticsScope<'_>) -> ast::NameRef { fn make_function_name(semantics_scope: &hir::SemanticsScope<'_>) -> ast::NameRef {
let mut names_in_scope = vec![]; let mut names_in_scope = vec![];
semantics_scope.process_all_names(&mut |name, _| { semantics_scope.process_all_names(&mut |name, _| {
names_in_scope.push(name.display(semantics_scope.db.upcast()).to_string()) names_in_scope.push(
name.display(
semantics_scope.db.upcast(),
semantics_scope.krate().edition(semantics_scope.db),
)
.to_string(),
)
}); });
let default_name = "fun_name"; let default_name = "fun_name";
@ -366,6 +378,7 @@ struct ContainerInfo {
ret_type: Option<hir::Type>, ret_type: Option<hir::Type>,
generic_param_lists: Vec<ast::GenericParamList>, generic_param_lists: Vec<ast::GenericParamList>,
where_clauses: Vec<ast::WhereClause>, where_clauses: Vec<ast::WhereClause>,
edition: Edition,
} }
/// Control flow that is exported from extracted function /// Control flow that is exported from extracted function
@ -489,8 +502,8 @@ impl Param {
} }
} }
fn to_arg(&self, ctx: &AssistContext<'_>) -> ast::Expr { fn to_arg(&self, ctx: &AssistContext<'_>, edition: Edition) -> ast::Expr {
let var = path_expr_from_local(ctx, self.var); let var = path_expr_from_local(ctx, self.var, edition);
match self.kind() { match self.kind() {
ParamKind::Value | ParamKind::MutValue => var, ParamKind::Value | ParamKind::MutValue => var,
ParamKind::SharedRef => make::expr_ref(var, false), ParamKind::SharedRef => make::expr_ref(var, false),
@ -498,8 +511,13 @@ impl Param {
} }
} }
fn to_param(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Param { fn to_param(
let var = self.var.name(ctx.db()).display(ctx.db()).to_string(); &self,
ctx: &AssistContext<'_>,
module: hir::Module,
edition: Edition,
) -> ast::Param {
let var = self.var.name(ctx.db()).display(ctx.db(), edition).to_string();
let var_name = make::name(&var); let var_name = make::name(&var);
let pat = match self.kind() { let pat = match self.kind() {
ParamKind::MutValue => make::ident_pat(false, true, var_name), ParamKind::MutValue => make::ident_pat(false, true, var_name),
@ -520,7 +538,7 @@ impl Param {
} }
impl TryKind { impl TryKind {
fn of_ty(ty: hir::Type, ctx: &AssistContext<'_>) -> Option<TryKind> { fn of_ty(ty: hir::Type, ctx: &AssistContext<'_>, edition: Edition) -> Option<TryKind> {
if ty.is_unknown() { if ty.is_unknown() {
// We favour Result for `expr?` // We favour Result for `expr?`
return Some(TryKind::Result { ty }); return Some(TryKind::Result { ty });
@ -529,7 +547,7 @@ impl TryKind {
let name = adt.name(ctx.db()); let name = adt.name(ctx.db());
// FIXME: use lang items to determine if it is std type or user defined // FIXME: use lang items to determine if it is std type or user defined
// E.g. if user happens to define type named `Option`, we would have false positive // E.g. if user happens to define type named `Option`, we would have false positive
let name = &name.display(ctx.db()).to_string(); let name = &name.display(ctx.db(), edition).to_string();
match name.as_str() { match name.as_str() {
"Option" => Some(TryKind::Option), "Option" => Some(TryKind::Option),
"Result" => Some(TryKind::Result { ty }), "Result" => Some(TryKind::Result { ty }),
@ -828,6 +846,7 @@ impl FunctionBody {
fn analyze_container( fn analyze_container(
&self, &self,
sema: &Semantics<'_, RootDatabase>, sema: &Semantics<'_, RootDatabase>,
edition: Edition,
) -> Option<(ContainerInfo, bool)> { ) -> Option<(ContainerInfo, bool)> {
let mut ancestors = self.parent()?.ancestors(); let mut ancestors = self.parent()?.ancestors();
let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted); let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted);
@ -927,6 +946,7 @@ impl FunctionBody {
ret_type: ty, ret_type: ty,
generic_param_lists, generic_param_lists,
where_clauses, where_clauses,
edition,
}, },
contains_tail_expr, contains_tail_expr,
)) ))
@ -1015,7 +1035,7 @@ impl FunctionBody {
let kind = match (try_expr, ret_expr, break_expr, continue_expr) { let kind = match (try_expr, ret_expr, break_expr, continue_expr) {
(Some(_), _, None, None) => { (Some(_), _, None, None) => {
let ret_ty = container_info.ret_type.clone()?; let ret_ty = container_info.ret_type.clone()?;
let kind = TryKind::of_ty(ret_ty, ctx)?; let kind = TryKind::of_ty(ret_ty, ctx, container_info.edition)?;
Some(FlowKind::Try { kind }) Some(FlowKind::Try { kind })
} }
@ -1397,7 +1417,7 @@ fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) {
fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> SyntaxNode { fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> SyntaxNode {
let ret_ty = fun.return_type(ctx); let ret_ty = fun.return_type(ctx);
let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx))); let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx, fun.mods.edition)));
let name = fun.name.clone(); let name = fun.name.clone();
let mut call_expr = if fun.self_param.is_some() { let mut call_expr = if fun.self_param.is_some() {
let self_arg = make::expr_path(make::ext::ident_path("self")); let self_arg = make::expr_path(make::ext::ident_path("self"));
@ -1420,13 +1440,13 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> Sy
[] => None, [] => None,
[var] => { [var] => {
let name = var.local.name(ctx.db()); let name = var.local.name(ctx.db());
let name = make::name(&name.display(ctx.db()).to_string()); let name = make::name(&name.display(ctx.db(), fun.mods.edition).to_string());
Some(ast::Pat::IdentPat(make::ident_pat(false, var.mut_usage_outside_body, name))) Some(ast::Pat::IdentPat(make::ident_pat(false, var.mut_usage_outside_body, name)))
} }
vars => { vars => {
let binding_pats = vars.iter().map(|var| { let binding_pats = vars.iter().map(|var| {
let name = var.local.name(ctx.db()); let name = var.local.name(ctx.db());
let name = make::name(&name.display(ctx.db()).to_string()); let name = make::name(&name.display(ctx.db(), fun.mods.edition).to_string());
make::ident_pat(false, var.mut_usage_outside_body, name).into() make::ident_pat(false, var.mut_usage_outside_body, name).into()
}); });
Some(ast::Pat::TuplePat(make::tuple_pat(binding_pats))) Some(ast::Pat::TuplePat(make::tuple_pat(binding_pats)))
@ -1569,8 +1589,8 @@ impl FlowHandler {
} }
} }
fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local) -> ast::Expr { fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local, edition: Edition) -> ast::Expr {
let name = var.name(ctx.db()).display(ctx.db()).to_string(); let name = var.name(ctx.db()).display(ctx.db(), edition).to_string();
make::expr_path(make::ext::ident_path(&name)) make::expr_path(make::ext::ident_path(&name))
} }
@ -1581,7 +1601,7 @@ fn format_function(
old_indent: IndentLevel, old_indent: IndentLevel,
) -> ast::Fn { ) -> ast::Fn {
let fun_name = make::name(&fun.name.text()); let fun_name = make::name(&fun.name.text());
let params = fun.make_param_list(ctx, module); let params = fun.make_param_list(ctx, module, fun.mods.edition);
let ret_ty = fun.make_ret_ty(ctx, module); let ret_ty = fun.make_ret_ty(ctx, module);
let body = make_body(ctx, old_indent, fun); let body = make_body(ctx, old_indent, fun);
let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun); let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun);
@ -1707,9 +1727,14 @@ impl Function {
type_params_in_descendant_paths.chain(type_params_in_params).collect() type_params_in_descendant_paths.chain(type_params_in_params).collect()
} }
fn make_param_list(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::ParamList { fn make_param_list(
&self,
ctx: &AssistContext<'_>,
module: hir::Module,
edition: Edition,
) -> ast::ParamList {
let self_param = self.self_param.clone(); let self_param = self.self_param.clone();
let params = self.params.iter().map(|param| param.to_param(ctx, module)); let params = self.params.iter().map(|param| param.to_param(ctx, module, edition));
make::param_list(self_param, params) make::param_list(self_param, params)
} }
@ -1842,10 +1867,12 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
None => match fun.outliving_locals.as_slice() { None => match fun.outliving_locals.as_slice() {
[] => {} [] => {}
[var] => { [var] => {
tail_expr = Some(path_expr_from_local(ctx, var.local)); tail_expr = Some(path_expr_from_local(ctx, var.local, fun.mods.edition));
} }
vars => { vars => {
let exprs = vars.iter().map(|var| path_expr_from_local(ctx, var.local)); let exprs = vars
.iter()
.map(|var| path_expr_from_local(ctx, var.local, fun.mods.edition));
let expr = make::expr_tuple(exprs); let expr = make::expr_tuple(exprs);
tail_expr = Some(expr); tail_expr = Some(expr);
} }

View file

@ -1,7 +1,7 @@
use std::iter; use std::iter;
use either::Either; use either::Either;
use hir::{Module, ModuleDef, Name, Variant}; use hir::{HasCrate, Module, ModuleDef, Name, Variant};
use ide_db::{ use ide_db::{
defs::Definition, defs::Definition,
helpers::mod_path_to_ast, helpers::mod_path_to_ast,
@ -16,7 +16,7 @@ use syntax::{
self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams, self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams,
HasName, HasVisibility, HasName, HasVisibility,
}, },
match_ast, ted, SyntaxElement, match_ast, ted, Edition, SyntaxElement,
SyntaxKind::*, SyntaxKind::*,
SyntaxNode, T, SyntaxNode, T,
}; };
@ -58,6 +58,7 @@ pub(crate) fn extract_struct_from_enum_variant(
"Extract struct from enum variant", "Extract struct from enum variant",
target, target,
|builder| { |builder| {
let edition = enum_hir.krate(ctx.db()).edition(ctx.db());
let variant_hir_name = variant_hir.name(ctx.db()); let variant_hir_name = variant_hir.name(ctx.db());
let enum_module_def = ModuleDef::from(enum_hir); let enum_module_def = ModuleDef::from(enum_hir);
let usages = Definition::Variant(variant_hir).usages(&ctx.sema).all(); let usages = Definition::Variant(variant_hir).usages(&ctx.sema).all();
@ -82,7 +83,7 @@ pub(crate) fn extract_struct_from_enum_variant(
references, references,
); );
processed.into_iter().for_each(|(path, node, import)| { processed.into_iter().for_each(|(path, node, import)| {
apply_references(ctx.config.insert_use, path, node, import) apply_references(ctx.config.insert_use, path, node, import, edition)
}); });
} }
builder.edit_file(ctx.file_id()); builder.edit_file(ctx.file_id());
@ -98,7 +99,7 @@ pub(crate) fn extract_struct_from_enum_variant(
references, references,
); );
processed.into_iter().for_each(|(path, node, import)| { processed.into_iter().for_each(|(path, node, import)| {
apply_references(ctx.config.insert_use, path, node, import) apply_references(ctx.config.insert_use, path, node, import, edition)
}); });
} }
@ -169,7 +170,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
), ),
_ => false, _ => false,
}) })
.any(|(name, _)| name.display(db).to_string() == variant_name.to_string()) .any(|(name, _)| name.eq_ident(variant_name.text().as_str()))
} }
fn extract_generic_params( fn extract_generic_params(
@ -359,9 +360,10 @@ fn apply_references(
segment: ast::PathSegment, segment: ast::PathSegment,
node: SyntaxNode, node: SyntaxNode,
import: Option<(ImportScope, hir::ModPath)>, import: Option<(ImportScope, hir::ModPath)>,
edition: Edition,
) { ) {
if let Some((scope, path)) = import { if let Some((scope, path)) = import {
insert_use(&scope, mod_path_to_ast(&path), &insert_use_cfg); insert_use(&scope, mod_path_to_ast(&path, edition), &insert_use_cfg);
} }
// deep clone to prevent cycle // deep clone to prevent cycle
let path = make::path_from_segments(iter::once(segment.clone_subtree()), false); let path = make::path_from_segments(iter::once(segment.clone_subtree()), false);

View file

@ -45,8 +45,9 @@ pub(crate) fn fill_record_pattern_fields(acc: &mut Assists, ctx: &AssistContext<
let new_field_list = let new_field_list =
make::record_pat_field_list(old_field_list.fields(), None).clone_for_update(); make::record_pat_field_list(old_field_list.fields(), None).clone_for_update();
for (f, _) in missing_fields.iter() { for (f, _) in missing_fields.iter() {
let edition = ctx.sema.scope(record_pat.syntax())?.krate().edition(ctx.db());
let field = make::record_pat_field_shorthand(make::name_ref( let field = make::record_pat_field_shorthand(make::name_ref(
&f.name(ctx.sema.db).display_no_db().to_smolstr(), &f.name(ctx.sema.db).display_no_db(edition).to_smolstr(),
)); ));
new_field_list.add_field(field.clone_for_update()); new_field_list.add_field(field.clone_for_update());
} }

View file

@ -4,7 +4,7 @@ use hir::{
use ide_db::FileId; use ide_db::FileId;
use syntax::{ use syntax::{
ast::{self, edit_in_place::HasVisibilityEdit, make, HasVisibility as _}, ast::{self, edit_in_place::HasVisibilityEdit, make, HasVisibility as _},
AstNode, TextRange, ToSmolStr, AstNode, TextRange,
}; };
use crate::{AssistContext, AssistId, AssistKind, Assists}; use crate::{AssistContext, AssistId, AssistKind, Assists};
@ -48,7 +48,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
let (_, def) = module let (_, def) = module
.scope(ctx.db(), None) .scope(ctx.db(), None)
.into_iter() .into_iter()
.find(|(name, _)| name.display_no_db().to_smolstr() == name_ref.text().as_str())?; .find(|(name, _)| name.eq_ident(name_ref.text().as_str()))?;
let ScopeDef::ModuleDef(def) = def else { let ScopeDef::ModuleDef(def) = def else {
return None; return None;
}; };
@ -71,7 +71,10 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
let assist_label = match target_name { let assist_label = match target_name {
None => format!("Change visibility to {missing_visibility}"), None => format!("Change visibility to {missing_visibility}"),
Some(name) => { Some(name) => {
format!("Change visibility of {} to {missing_visibility}", name.display(ctx.db())) format!(
"Change visibility of {} to {missing_visibility}",
name.display(ctx.db(), current_module.krate().edition(ctx.db()))
)
} }
}; };
@ -92,6 +95,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>
let (record_field_def, _, _) = ctx.sema.resolve_record_field(&record_field)?; let (record_field_def, _, _) = ctx.sema.resolve_record_field(&record_field)?;
let current_module = ctx.sema.scope(record_field.syntax())?.module(); let current_module = ctx.sema.scope(record_field.syntax())?.module();
let current_edition = current_module.krate().edition(ctx.db());
let visibility = record_field_def.visibility(ctx.db()); let visibility = record_field_def.visibility(ctx.db());
if visibility.is_visible_from(ctx.db(), current_module.into()) { if visibility.is_visible_from(ctx.db(), current_module.into()) {
return None; return None;
@ -123,8 +127,8 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>
let target_name = record_field_def.name(ctx.db()); let target_name = record_field_def.name(ctx.db());
let assist_label = format!( let assist_label = format!(
"Change visibility of {}.{} to {missing_visibility}", "Change visibility of {}.{} to {missing_visibility}",
parent_name.display(ctx.db()), parent_name.display(ctx.db(), current_edition),
target_name.display(ctx.db()) target_name.display(ctx.db(), current_edition)
); );
acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |edit| { acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |edit| {

View file

@ -51,6 +51,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
let strukt = ctx.find_node_at_offset::<ast::Struct>()?; let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
let strukt_name = strukt.name()?; let strukt_name = strukt.name()?;
let current_module = ctx.sema.scope(strukt.syntax())?.module(); let current_module = ctx.sema.scope(strukt.syntax())?.module();
let current_edition = current_module.krate().edition(ctx.db());
let (field_name, field_ty, target) = match ctx.find_node_at_offset::<ast::RecordField>() { let (field_name, field_ty, target) = match ctx.find_node_at_offset::<ast::RecordField>() {
Some(field) => { Some(field) => {
@ -89,7 +90,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
methods.sort_by(|(a, _), (b, _)| a.cmp(b)); methods.sort_by(|(a, _), (b, _)| a.cmp(b));
for (name, method) in methods { for (name, method) in methods {
let adt = ast::Adt::Struct(strukt.clone()); let adt = ast::Adt::Struct(strukt.clone());
let name = name.display(ctx.db()).to_string(); let name = name.display(ctx.db(), current_edition).to_string();
// if `find_struct_impl` returns None, that means that a function named `name` already exists. // if `find_struct_impl` returns None, that means that a function named `name` already exists.
let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else { let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else {
continue; continue;

View file

@ -22,7 +22,7 @@ use syntax::{
WherePred, WherePred,
}, },
ted::{self, Position}, ted::{self, Position},
AstNode, NodeOrToken, SmolStr, SyntaxKind, ToSmolStr, AstNode, Edition, NodeOrToken, SmolStr, SyntaxKind, ToSmolStr,
}; };
// Assist: generate_delegate_trait // Assist: generate_delegate_trait
@ -109,6 +109,7 @@ struct Field {
ty: ast::Type, ty: ast::Type,
range: syntax::TextRange, range: syntax::TextRange,
impls: Vec<Delegee>, impls: Vec<Delegee>,
edition: Edition,
} }
impl Field { impl Field {
@ -119,6 +120,7 @@ impl Field {
let db = ctx.sema.db; let db = ctx.sema.db;
let module = ctx.sema.file_to_module_def(ctx.file_id())?; let module = ctx.sema.file_to_module_def(ctx.file_id())?;
let edition = module.krate().edition(ctx.db());
let (name, range, ty) = match f { let (name, range, ty) = match f {
Either::Left(f) => { Either::Left(f) => {
@ -147,7 +149,7 @@ impl Field {
} }
} }
Some(Field { name, ty, range, impls }) Some(Field { name, ty, range, impls, edition })
} }
} }
@ -163,18 +165,18 @@ enum Delegee {
} }
impl Delegee { impl Delegee {
fn signature(&self, db: &dyn HirDatabase) -> String { fn signature(&self, db: &dyn HirDatabase, edition: Edition) -> String {
let mut s = String::new(); let mut s = String::new();
let (Delegee::Bound(it) | Delegee::Impls(it, _)) = self; let (Delegee::Bound(it) | Delegee::Impls(it, _)) = self;
for m in it.module(db).path_to_root(db).iter().rev() { for m in it.module(db).path_to_root(db).iter().rev() {
if let Some(name) = m.name(db) { if let Some(name) = m.name(db) {
s.push_str(&format!("{}::", name.display_no_db().to_smolstr())); s.push_str(&format!("{}::", name.display_no_db(edition).to_smolstr()));
} }
} }
s.push_str(&it.name(db).display_no_db().to_smolstr()); s.push_str(&it.name(db).display_no_db(edition).to_smolstr());
s s
} }
} }
@ -212,9 +214,11 @@ impl Struct {
// if self.hir_ty.impls_trait(db, trait_, &[]) { // if self.hir_ty.impls_trait(db, trait_, &[]) {
// continue; // continue;
// } // }
let signature = delegee.signature(db); let signature = delegee.signature(db, field.edition);
let Some(delegate) = generate_impl(ctx, self, &field.ty, &field.name, delegee) else { let Some(delegate) =
generate_impl(ctx, self, &field.ty, &field.name, delegee, field.edition)
else {
continue; continue;
}; };
@ -240,6 +244,7 @@ fn generate_impl(
field_ty: &ast::Type, field_ty: &ast::Type,
field_name: &str, field_name: &str,
delegee: &Delegee, delegee: &Delegee,
edition: Edition,
) -> Option<ast::Impl> { ) -> Option<ast::Impl> {
let delegate: ast::Impl; let delegate: ast::Impl;
let db = ctx.db(); let db = ctx.db();
@ -259,7 +264,7 @@ fn generate_impl(
strukt_params.clone(), strukt_params.clone(),
strukt_params.map(|params| params.to_generic_args()), strukt_params.map(|params| params.to_generic_args()),
delegee.is_auto(db), delegee.is_auto(db),
make::ty(&delegee.name(db).display_no_db().to_smolstr()), make::ty(&delegee.name(db).display_no_db(edition).to_smolstr()),
strukt_ty, strukt_ty,
bound_def.where_clause(), bound_def.where_clause(),
ast_strukt.where_clause(), ast_strukt.where_clause(),
@ -350,7 +355,7 @@ fn generate_impl(
let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args()); let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args());
let path_type = let path_type =
make::ty(&trait_.name(db).display_no_db().to_smolstr()).clone_for_update(); make::ty(&trait_.name(db).display_no_db(edition).to_smolstr()).clone_for_update();
transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type.syntax())?; transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type.syntax())?;
// 3) Generate delegate trait impl // 3) Generate delegate trait impl

View file

@ -4,7 +4,7 @@ use hir::{ModPath, ModuleDef};
use ide_db::{famous_defs::FamousDefs, RootDatabase}; use ide_db::{famous_defs::FamousDefs, RootDatabase};
use syntax::{ use syntax::{
ast::{self, HasName}, ast::{self, HasName},
AstNode, SyntaxNode, AstNode, Edition, SyntaxNode,
}; };
use crate::{ use crate::{
@ -77,6 +77,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
field_name.syntax(), field_name.syntax(),
deref_type_to_generate, deref_type_to_generate,
trait_path, trait_path,
module.krate().edition(ctx.db()),
) )
}, },
) )
@ -117,6 +118,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
field_list_index, field_list_index,
deref_type_to_generate, deref_type_to_generate,
trait_path, trait_path,
module.krate().edition(ctx.db()),
) )
}, },
) )
@ -130,6 +132,7 @@ fn generate_edit(
field_name: impl Display, field_name: impl Display,
deref_type: DerefType, deref_type: DerefType,
trait_path: ModPath, trait_path: ModPath,
edition: Edition,
) { ) {
let start_offset = strukt.syntax().text_range().end(); let start_offset = strukt.syntax().text_range().end();
let impl_code = match deref_type { let impl_code = match deref_type {
@ -147,8 +150,11 @@ fn generate_edit(
), ),
}; };
let strukt_adt = ast::Adt::Struct(strukt); let strukt_adt = ast::Adt::Struct(strukt);
let deref_impl = let deref_impl = generate_trait_impl_text(
generate_trait_impl_text(&strukt_adt, &trait_path.display(db).to_string(), &impl_code); &strukt_adt,
&trait_path.display(db, edition).to_string(),
&impl_code,
);
edit.insert(start_offset, deref_impl); edit.insert(start_offset, deref_impl);
} }

View file

@ -5,7 +5,7 @@ use stdx::{format_to, to_lower_snake_case};
use syntax::{ use syntax::{
algo::skip_whitespace_token, algo::skip_whitespace_token,
ast::{self, edit::IndentLevel, HasDocComments, HasGenericArgs, HasName}, ast::{self, edit::IndentLevel, HasDocComments, HasGenericArgs, HasName},
match_ast, AstNode, AstToken, match_ast, AstNode, AstToken, Edition,
}; };
use crate::assist_context::{AssistContext, Assists}; use crate::assist_context::{AssistContext, Assists};
@ -139,7 +139,8 @@ fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<St
let mut example = String::new(); let mut example = String::new();
let use_path = build_path(ast_func, ctx)?; let edition = ctx.sema.scope(ast_func.syntax())?.krate().edition(ctx.db());
let use_path = build_path(ast_func, ctx, edition)?;
let is_unsafe = ast_func.unsafe_token().is_some(); let is_unsafe = ast_func.unsafe_token().is_some();
let param_list = ast_func.param_list()?; let param_list = ast_func.param_list()?;
let ref_mut_params = ref_mut_params(&param_list); let ref_mut_params = ref_mut_params(&param_list);
@ -472,13 +473,13 @@ fn string_vec_from(string_array: &[&str]) -> Vec<String> {
} }
/// Helper function to build the path of the module in the which is the node /// Helper function to build the path of the module in the which is the node
fn build_path(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> { fn build_path(ast_func: &ast::Fn, ctx: &AssistContext<'_>, edition: Edition) -> Option<String> {
let crate_name = crate_name(ast_func, ctx)?; let crate_name = crate_name(ast_func, ctx)?;
let leaf = self_partial_type(ast_func) let leaf = self_partial_type(ast_func)
.or_else(|| ast_func.name().map(|n| n.to_string())) .or_else(|| ast_func.name().map(|n| n.to_string()))
.unwrap_or_else(|| "*".into()); .unwrap_or_else(|| "*".into());
let module_def: ModuleDef = ctx.sema.to_def(ast_func)?.module(ctx.db()).into(); let module_def: ModuleDef = ctx.sema.to_def(ast_func)?.module(ctx.db()).into();
match module_def.canonical_path(ctx.db()) { match module_def.canonical_path(ctx.db(), edition) {
Some(path) => Some(format!("{crate_name}::{path}::{leaf}")), Some(path) => Some(format!("{crate_name}::{path}::{leaf}")),
None => Some(format!("{crate_name}::{leaf}")), None => Some(format!("{crate_name}::{leaf}")),
} }

View file

@ -17,7 +17,7 @@ use syntax::{
self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, BlockExpr, CallExpr, self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, BlockExpr, CallExpr,
HasArgList, HasGenericParams, HasModuleItem, HasTypeBounds, HasArgList, HasGenericParams, HasModuleItem, HasTypeBounds,
}, },
ted, SyntaxKind, SyntaxNode, TextRange, T, ted, Edition, SyntaxKind, SyntaxNode, TextRange, T,
}; };
use crate::{ use crate::{
@ -175,6 +175,7 @@ fn add_func_to_accumulator(
edit.edit_file(file); edit.edit_file(file);
let target = function_builder.target.clone(); let target = function_builder.target.clone();
let edition = function_builder.target_edition;
let func = function_builder.render(ctx.config.snippet_cap, edit); let func = function_builder.render(ctx.config.snippet_cap, edit);
if let Some(adt) = if let Some(adt) =
@ -183,7 +184,7 @@ fn add_func_to_accumulator(
{ {
let name = make::ty_path(make::ext::ident_path(&format!( let name = make::ty_path(make::ext::ident_path(&format!(
"{}", "{}",
adt.name(ctx.db()).display(ctx.db()) adt.name(ctx.db()).display(ctx.db(), edition)
))); )));
// FIXME: adt may have generic params. // FIXME: adt may have generic params.
@ -222,6 +223,7 @@ struct FunctionBuilder {
should_focus_return_type: bool, should_focus_return_type: bool,
visibility: Visibility, visibility: Visibility,
is_async: bool, is_async: bool,
target_edition: Edition,
} }
impl FunctionBuilder { impl FunctionBuilder {
@ -237,6 +239,7 @@ impl FunctionBuilder {
) -> Option<Self> { ) -> Option<Self> {
let target_module = let target_module =
target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?; target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
let target_edition = target_module.krate().edition(ctx.db());
let current_module = ctx.sema.scope(call.syntax())?.module(); let current_module = ctx.sema.scope(call.syntax())?.module();
let visibility = calculate_necessary_visibility(current_module, target_module, ctx); let visibility = calculate_necessary_visibility(current_module, target_module, ctx);
@ -258,7 +261,9 @@ impl FunctionBuilder {
// If generated function has the name "new" and is an associated function, we generate fn body // If generated function has the name "new" and is an associated function, we generate fn body
// as a constructor and assume a "Self" return type. // as a constructor and assume a "Self" return type.
if let Some(body) = make_fn_body_as_new_function(ctx, &fn_name.text(), adt_info) { if let Some(body) =
make_fn_body_as_new_function(ctx, &fn_name.text(), adt_info, target_edition)
{
ret_type = Some(make::ret_type(make::ty_path(make::ext::ident_path("Self")))); ret_type = Some(make::ret_type(make::ty_path(make::ext::ident_path("Self"))));
should_focus_return_type = false; should_focus_return_type = false;
fn_body = body; fn_body = body;
@ -288,6 +293,7 @@ impl FunctionBuilder {
should_focus_return_type, should_focus_return_type,
visibility, visibility,
is_async, is_async,
target_edition,
}) })
} }
@ -299,6 +305,8 @@ impl FunctionBuilder {
target_module: Module, target_module: Module,
target: GeneratedFunctionTarget, target: GeneratedFunctionTarget,
) -> Option<Self> { ) -> Option<Self> {
let target_edition = target_module.krate().edition(ctx.db());
let current_module = ctx.sema.scope(call.syntax())?.module(); let current_module = ctx.sema.scope(call.syntax())?.module();
let visibility = calculate_necessary_visibility(current_module, target_module, ctx); let visibility = calculate_necessary_visibility(current_module, target_module, ctx);
@ -336,6 +344,7 @@ impl FunctionBuilder {
should_focus_return_type, should_focus_return_type,
visibility, visibility,
is_async, is_async,
target_edition,
}) })
} }
@ -425,6 +434,7 @@ fn make_fn_body_as_new_function(
ctx: &AssistContext<'_>, ctx: &AssistContext<'_>,
fn_name: &str, fn_name: &str,
adt_info: &Option<AdtInfo>, adt_info: &Option<AdtInfo>,
edition: Edition,
) -> Option<ast::BlockExpr> { ) -> Option<ast::BlockExpr> {
if fn_name != "new" { if fn_name != "new" {
return None; return None;
@ -441,7 +451,10 @@ fn make_fn_body_as_new_function(
.iter() .iter()
.map(|field| { .map(|field| {
make::record_expr_field( make::record_expr_field(
make::name_ref(&format!("{}", field.name(ctx.db()).display(ctx.db()))), make::name_ref(&format!(
"{}",
field.name(ctx.db()).display(ctx.db(), edition)
)),
Some(placeholder_expr.clone()), Some(placeholder_expr.clone()),
) )
}) })
@ -1102,8 +1115,9 @@ fn fn_arg_type(
if ty.is_reference() || ty.is_mutable_reference() { if ty.is_reference() || ty.is_mutable_reference() {
let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate()); let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate());
let target_edition = target_module.krate().edition(ctx.db());
convert_reference_type(ty.strip_references(), ctx.db(), famous_defs) convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
.map(|conversion| conversion.convert_type(ctx.db()).to_string()) .map(|conversion| conversion.convert_type(ctx.db(), target_edition).to_string())
.or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok()) .or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok())
} else { } else {
ty.display_source_code(ctx.db(), target_module.into(), true).ok() ty.display_source_code(ctx.db(), target_module.into(), true).ok()

View file

@ -233,7 +233,7 @@ fn generate_getter_from_info(
.map(|conversion| { .map(|conversion| {
cov_mark::hit!(convert_reference_type); cov_mark::hit!(convert_reference_type);
( (
conversion.convert_type(ctx.db()), conversion.convert_type(ctx.db(), krate.edition(ctx.db())),
conversion.getter(record_field_info.field_name.to_string()), conversion.getter(record_field_info.field_name.to_string()),
) )
}) })

View file

@ -64,10 +64,13 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
ctx.config.import_path_config(), ctx.config.import_path_config(),
)?; )?;
let edition = current_module.krate().edition(ctx.db());
let expr = use_trivial_constructor( let expr = use_trivial_constructor(
ctx.sema.db, ctx.sema.db,
ide_db::helpers::mod_path_to_ast(&type_path), ide_db::helpers::mod_path_to_ast(&type_path, edition),
&ty, &ty,
edition,
)?; )?;
Some(make::record_expr_field(make::name_ref(&name.text()), Some(expr))) Some(make::record_expr_field(make::name_ref(&name.text()), Some(expr)))

View file

@ -51,10 +51,13 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>
| ast::Expr::MatchExpr(_) | ast::Expr::MatchExpr(_)
| ast::Expr::MacroExpr(_) | ast::Expr::MacroExpr(_)
| ast::Expr::BinExpr(_) | ast::Expr::BinExpr(_)
| ast::Expr::CallExpr(_) => match konst.render_eval(ctx.sema.db) { | ast::Expr::CallExpr(_) => {
let edition = ctx.sema.scope(variable.syntax())?.krate().edition(ctx.db());
match konst.render_eval(ctx.sema.db, edition) {
Ok(result) => result, Ok(result) => result,
Err(_) => return None, Err(_) => return None,
}, }
}
_ => return None, _ => return None,
}; };

View file

@ -104,9 +104,13 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
}; };
builder.delete(range_to_delete); builder.delete(range_to_delete);
let const_ref = format!("Self::{}", name.display(ctx.db())); let usages = usages.iter().flat_map(|(file_id, usages)| {
for range in usages.file_ranges().map(|it| it.range) { let edition = file_id.edition();
builder.replace(range, const_ref.clone()); usages.iter().map(move |usage| (edition, usage.range))
});
for (edition, range) in usages {
let const_ref = format!("Self::{}", name.display(ctx.db(), edition));
builder.replace(range, const_ref);
} }
// Heuristically inserting the extracted const after the consecutive existing consts // Heuristically inserting the extracted const after the consecutive existing consts

View file

@ -39,7 +39,7 @@ pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
} }
let target = source_file.syntax().text_range(); let target = source_file.syntax().text_range();
let module_name = module.name(ctx.db())?.display(ctx.db()).to_string(); let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string();
let path = format!("../{module_name}.rs"); let path = format!("../{module_name}.rs");
let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path }; let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
acc.add( acc.add(

View file

@ -61,7 +61,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
.string_value_unescape() .string_value_unescape()
.is_none() => .is_none() =>
{ {
format_to!(buf, "{}/", name.display(db)) format_to!(buf, "{}/", name.unescaped().display(db))
} }
_ => (), _ => (),
} }

View file

@ -39,7 +39,7 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
} }
let target = source_file.syntax().text_range(); let target = source_file.syntax().text_range();
let module_name = module.name(ctx.db())?.display(ctx.db()).to_string(); let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string();
let path = format!("./{module_name}/mod.rs"); let path = format!("./{module_name}/mod.rs");
let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path }; let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
acc.add( acc.add(

View file

@ -42,6 +42,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
let resolved_call = ctx.sema.resolve_method_call(&call)?; let resolved_call = ctx.sema.resolve_method_call(&call)?;
let current_module = ctx.sema.scope(call.syntax())?.module(); let current_module = ctx.sema.scope(call.syntax())?.module();
let current_edition = current_module.krate().edition(ctx.db());
let target_module_def = ModuleDef::from(resolved_call); let target_module_def = ModuleDef::from(resolved_call);
let item_in_ns = ItemInNs::from(target_module_def); let item_in_ns = ItemInNs::from(target_module_def);
let receiver_path = current_module.find_path( let receiver_path = current_module.find_path(
@ -61,6 +62,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|replace_with: String| builder.replace(range, replace_with), |replace_with: String| builder.replace(range, replace_with),
&receiver_path, &receiver_path,
item_in_ns, item_in_ns,
current_edition,
) )
}, },
); );

View file

@ -8,6 +8,7 @@ use ide_db::{
imports::import_assets::{ImportCandidate, LocatedImport}, imports::import_assets::{ImportCandidate, LocatedImport},
}; };
use syntax::ast::HasGenericArgs; use syntax::ast::HasGenericArgs;
use syntax::Edition;
use syntax::{ use syntax::{
ast, ast,
ast::{make, HasArgList}, ast::{make, HasArgList},
@ -93,6 +94,8 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
NodeOrToken::Token(t) => t.parent()?, NodeOrToken::Token(t) => t.parent()?,
}) })
.map(|scope| scope.module()); .map(|scope| scope.module());
let current_edition =
current_module.map(|it| it.krate().edition(ctx.db())).unwrap_or(Edition::CURRENT);
// prioritize more relevant imports // prioritize more relevant imports
proposed_imports.sort_by_key(|import| { proposed_imports.sort_by_key(|import| {
Reverse(super::auto_import::relevance_score(ctx, import, current_module.as_ref())) Reverse(super::auto_import::relevance_score(ctx, import, current_module.as_ref()))
@ -103,13 +106,14 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
acc.add_group( acc.add_group(
&group_label, &group_label,
AssistId("qualify_path", AssistKind::QuickFix), AssistId("qualify_path", AssistKind::QuickFix),
label(ctx.db(), candidate, &import), label(ctx.db(), candidate, &import, current_edition),
range, range,
|builder| { |builder| {
qualify_candidate.qualify( qualify_candidate.qualify(
|replace_with: String| builder.replace(range, replace_with), |replace_with: String| builder.replace(range, replace_with),
&import.import_path, &import.import_path,
import.item_to_import, import.item_to_import,
current_edition,
) )
}, },
); );
@ -130,8 +134,9 @@ impl QualifyCandidate<'_> {
mut replacer: impl FnMut(String), mut replacer: impl FnMut(String),
import: &hir::ModPath, import: &hir::ModPath,
item: hir::ItemInNs, item: hir::ItemInNs,
edition: Edition,
) { ) {
let import = mod_path_to_ast(import); let import = mod_path_to_ast(import, edition);
match self { match self {
QualifyCandidate::QualifierStart(segment, generics) => { QualifyCandidate::QualifierStart(segment, generics) => {
let generics = generics.as_ref().map_or_else(String::new, ToString::to_string); let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
@ -203,7 +208,7 @@ fn find_trait_method(
if let Some(hir::AssocItem::Function(method)) = if let Some(hir::AssocItem::Function(method)) =
trait_.items(db).into_iter().find(|item: &hir::AssocItem| { trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
item.name(db) item.name(db)
.map(|name| name.display(db).to_string() == trait_method_name.to_string()) .map(|name| name.eq_ident(trait_method_name.text().as_str()))
.unwrap_or(false) .unwrap_or(false)
}) })
{ {
@ -233,14 +238,19 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel {
GroupLabel(format!("Qualify {name}")) GroupLabel(format!("Qualify {name}"))
} }
fn label(db: &RootDatabase, candidate: &ImportCandidate, import: &LocatedImport) -> String { fn label(
db: &RootDatabase,
candidate: &ImportCandidate,
import: &LocatedImport,
edition: Edition,
) -> String {
let import_path = &import.import_path; let import_path = &import.import_path;
match candidate { match candidate {
ImportCandidate::Path(candidate) if candidate.qualifier.is_none() => { ImportCandidate::Path(candidate) if candidate.qualifier.is_none() => {
format!("Qualify as `{}`", import_path.display(db)) format!("Qualify as `{}`", import_path.display(db, edition))
} }
_ => format!("Qualify with `{}`", import_path.display(db)), _ => format!("Qualify with `{}`", import_path.display(db, edition)),
} }
} }

View file

@ -1,7 +1,7 @@
use either::Either; use either::Either;
use ide_db::FxHashMap; use ide_db::FxHashMap;
use itertools::Itertools; use itertools::Itertools;
use syntax::{ast, ted, AstNode}; use syntax::{ast, ted, AstNode, SmolStr, ToSmolStr};
use crate::{AssistContext, AssistId, AssistKind, Assists}; use crate::{AssistContext, AssistId, AssistKind, Assists};
@ -25,8 +25,9 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
path.syntax().parent().and_then(<Either<ast::RecordExpr, ast::RecordPat>>::cast)?; path.syntax().parent().and_then(<Either<ast::RecordExpr, ast::RecordPat>>::cast)?;
let ranks = compute_fields_ranks(&path, ctx)?; let ranks = compute_fields_ranks(&path, ctx)?;
let get_rank_of_field = let get_rank_of_field = |of: Option<SmolStr>| {
|of: Option<_>| *ranks.get(&of.unwrap_or_default()).unwrap_or(&usize::MAX); *ranks.get(of.unwrap_or_default().trim_start_matches("r#")).unwrap_or(&usize::MAX)
};
let field_list = match &record { let field_list = match &record {
Either::Left(it) => Either::Left(it.record_expr_field_list()?), Either::Left(it) => Either::Left(it.record_expr_field_list()?),
@ -36,7 +37,7 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
Either::Left(it) => Either::Left(( Either::Left(it) => Either::Left((
it.fields() it.fields()
.sorted_unstable_by_key(|field| { .sorted_unstable_by_key(|field| {
get_rank_of_field(field.field_name().map(|it| it.to_string())) get_rank_of_field(field.field_name().map(|it| it.to_smolstr()))
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
it, it,
@ -44,7 +45,7 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
Either::Right(it) => Either::Right(( Either::Right(it) => Either::Right((
it.fields() it.fields()
.sorted_unstable_by_key(|field| { .sorted_unstable_by_key(|field| {
get_rank_of_field(field.field_name().map(|it| it.to_string())) get_rank_of_field(field.field_name().map(|it| it.to_smolstr()))
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
it, it,
@ -97,7 +98,7 @@ fn compute_fields_ranks(
.fields(ctx.db()) .fields(ctx.db())
.into_iter() .into_iter()
.enumerate() .enumerate()
.map(|(idx, field)| (field.name(ctx.db()).display(ctx.db()).to_string(), idx)) .map(|(idx, field)| (field.name(ctx.db()).unescaped().display(ctx.db()).to_string(), idx))
.collect(); .collect();
Some(res) Some(res)

View file

@ -77,7 +77,8 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) ->
ast::AssocItem::MacroCall(_) => None, ast::AssocItem::MacroCall(_) => None,
}; };
name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::MAX) name.and_then(|n| ranks.get(n.text().as_str().trim_start_matches("r#")).copied())
.unwrap_or(usize::MAX)
}) })
.collect(); .collect();
@ -114,7 +115,7 @@ fn compute_item_ranks(
.iter() .iter()
.flat_map(|i| i.name(ctx.db())) .flat_map(|i| i.name(ctx.db()))
.enumerate() .enumerate()
.map(|(idx, name)| (name.display(ctx.db()).to_string(), idx)) .map(|(idx, name)| (name.unescaped().display(ctx.db()).to_string(), idx))
.collect(), .collect(),
) )
} }

View file

@ -70,6 +70,7 @@ pub(crate) fn replace_derive_with_manual_impl(
let current_module = ctx.sema.scope(adt.syntax())?.module(); let current_module = ctx.sema.scope(adt.syntax())?.module();
let current_crate = current_module.krate(); let current_crate = current_module.krate();
let current_edition = current_crate.edition(ctx.db());
let found_traits = items_locator::items_with_name( let found_traits = items_locator::items_with_name(
&ctx.sema, &ctx.sema,
@ -85,7 +86,7 @@ pub(crate) fn replace_derive_with_manual_impl(
current_module current_module
.find_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.import_path_config()) .find_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.import_path_config())
.as_ref() .as_ref()
.map(mod_path_to_ast) .map(|path| mod_path_to_ast(path, current_edition))
.zip(Some(trait_)) .zip(Some(trait_))
}); });
@ -214,7 +215,7 @@ fn impl_def_from_trait(
let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone())); let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone()));
let first_assoc_item = let first_assoc_item =
add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, target_scope); add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, &target_scope);
// Generate a default `impl` function body for the derived trait. // Generate a default `impl` function body for the derived trait.
if let ast::AssocItem::Fn(ref func) = first_assoc_item { if let ast::AssocItem::Fn(ref func) = first_assoc_item {

View file

@ -5,7 +5,7 @@ use ide_db::{
}; };
use syntax::{ use syntax::{
ast::{self, make, HasGenericArgs}, ast::{self, make, HasGenericArgs},
match_ast, ted, AstNode, SyntaxNode, match_ast, ted, AstNode, Edition, SyntaxNode,
}; };
use crate::{AssistContext, AssistId, AssistKind, Assists}; use crate::{AssistContext, AssistId, AssistKind, Assists};
@ -29,32 +29,32 @@ pub(crate) fn replace_qualified_name_with_use(
acc: &mut Assists, acc: &mut Assists,
ctx: &AssistContext<'_>, ctx: &AssistContext<'_>,
) -> Option<()> { ) -> Option<()> {
let path: ast::Path = ctx.find_node_at_offset()?; let original_path: ast::Path = ctx.find_node_at_offset()?;
// We don't want to mess with use statements // We don't want to mess with use statements
if path.syntax().ancestors().find_map(ast::UseTree::cast).is_some() { if original_path.syntax().ancestors().find_map(ast::UseTree::cast).is_some() {
cov_mark::hit!(not_applicable_in_use); cov_mark::hit!(not_applicable_in_use);
return None; return None;
} }
if path.qualifier().is_none() { if original_path.qualifier().is_none() {
cov_mark::hit!(dont_import_trivial_paths); cov_mark::hit!(dont_import_trivial_paths);
return None; return None;
} }
// only offer replacement for non assoc items // only offer replacement for non assoc items
match ctx.sema.resolve_path(&path)? { match ctx.sema.resolve_path(&original_path)? {
hir::PathResolution::Def(def) if def.as_assoc_item(ctx.sema.db).is_none() => (), hir::PathResolution::Def(def) if def.as_assoc_item(ctx.sema.db).is_none() => (),
_ => return None, _ => return None,
} }
// then search for an import for the first path segment of what we want to replace // then search for an import for the first path segment of what we want to replace
// that way it is less likely that we import the item from a different location due re-exports // that way it is less likely that we import the item from a different location due re-exports
let module = match ctx.sema.resolve_path(&path.first_qualifier_or_self())? { let module = match ctx.sema.resolve_path(&original_path.first_qualifier_or_self())? {
hir::PathResolution::Def(module @ hir::ModuleDef::Module(_)) => module, hir::PathResolution::Def(module @ hir::ModuleDef::Module(_)) => module,
_ => return None, _ => return None,
}; };
let starts_with_name_ref = !matches!( let starts_with_name_ref = !matches!(
path.first_segment().and_then(|it| it.kind()), original_path.first_segment().and_then(|it| it.kind()),
Some( Some(
ast::PathSegmentKind::CrateKw ast::PathSegmentKind::CrateKw
| ast::PathSegmentKind::SuperKw | ast::PathSegmentKind::SuperKw
@ -63,7 +63,7 @@ pub(crate) fn replace_qualified_name_with_use(
); );
let path_to_qualifier = starts_with_name_ref let path_to_qualifier = starts_with_name_ref
.then(|| { .then(|| {
ctx.sema.scope(path.syntax())?.module().find_use_path( ctx.sema.scope(original_path.syntax())?.module().find_use_path(
ctx.sema.db, ctx.sema.db,
module, module,
ctx.config.insert_use.prefix_kind, ctx.config.insert_use.prefix_kind,
@ -72,8 +72,8 @@ pub(crate) fn replace_qualified_name_with_use(
}) })
.flatten(); .flatten();
let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?; let scope = ImportScope::find_insert_use_container(original_path.syntax(), &ctx.sema)?;
let target = path.syntax().text_range(); let target = original_path.syntax().text_range();
acc.add( acc.add(
AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite), AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
"Replace qualified path with use", "Replace qualified path with use",
@ -86,10 +86,16 @@ pub(crate) fn replace_qualified_name_with_use(
ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
}; };
shorten_paths(scope.as_syntax_node(), &path); shorten_paths(scope.as_syntax_node(), &original_path);
let path = drop_generic_args(&path); let path = drop_generic_args(&original_path);
let edition = ctx
.sema
.scope(original_path.syntax())
.map(|semantics_scope| semantics_scope.krate().edition(ctx.db()))
.unwrap_or(Edition::CURRENT);
// stick the found import in front of the to be replaced path // stick the found import in front of the to be replaced path
let path = match path_to_qualifier.and_then(|it| mod_path_to_ast(&it).qualifier()) { let path =
match path_to_qualifier.and_then(|it| mod_path_to_ast(&it, edition).qualifier()) {
Some(qualifier) => make::path_concat(qualifier, path), Some(qualifier) => make::path_concat(qualifier, path),
None => path, None => path,
}; };

View file

@ -48,15 +48,17 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
let mut formatter = |_: &hir::Type| String::from("todo!()"); let mut formatter = |_: &hir::Type| String::from("todo!()");
let edition = scope.krate().edition(ctx.db());
let paths = paths let paths = paths
.into_iter() .into_iter()
.filter_map(|path| { .filter_map(|path| {
path.gen_source_code(&scope, &mut formatter, ctx.config.import_path_config()).ok() path.gen_source_code(&scope, &mut formatter, ctx.config.import_path_config(), edition)
.ok()
}) })
.unique(); .unique();
let macro_name = macro_call.name(ctx.sema.db); let macro_name = macro_call.name(ctx.sema.db);
let macro_name = macro_name.display(ctx.sema.db); let macro_name = macro_name.display(ctx.sema.db, edition);
for code in paths { for code in paths {
acc.add_group( acc.add_group(

View file

@ -141,7 +141,8 @@ pub(crate) fn desugar_async_into_impl_future(
ModuleDef::Trait(future_trait), ModuleDef::Trait(future_trait),
ctx.config.import_path_config(), ctx.config.import_path_config(),
)?; )?;
let trait_path = trait_path.display(ctx.db()); let edition = scope.krate().edition(ctx.db());
let trait_path = trait_path.display(ctx.db(), edition);
acc.add( acc.add(
AssistId("desugar_async_into_impl_future", AssistKind::RefactorRewrite), AssistId("desugar_async_into_impl_future", AssistKind::RefactorRewrite),

View file

@ -14,7 +14,7 @@ use syntax::{
edit_in_place::{AttrsOwnerEdit, Indent, Removable}, edit_in_place::{AttrsOwnerEdit, Indent, Removable},
make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace, make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
}, },
ted, AstNode, AstToken, Direction, NodeOrToken, SourceFile, ted, AstNode, AstToken, Direction, Edition, NodeOrToken, SourceFile,
SyntaxKind::*, SyntaxKind::*,
SyntaxNode, SyntaxToken, TextRange, TextSize, T, SyntaxNode, SyntaxToken, TextRange, TextSize, T,
}; };
@ -174,7 +174,7 @@ pub fn add_trait_assoc_items_to_impl(
original_items: &[InFile<ast::AssocItem>], original_items: &[InFile<ast::AssocItem>],
trait_: hir::Trait, trait_: hir::Trait,
impl_: &ast::Impl, impl_: &ast::Impl,
target_scope: hir::SemanticsScope<'_>, target_scope: &hir::SemanticsScope<'_>,
) -> ast::AssocItem { ) -> ast::AssocItem {
let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1;
let items = original_items.iter().map(|InFile { file_id, value: original_item }| { let items = original_items.iter().map(|InFile { file_id, value: original_item }| {
@ -195,7 +195,7 @@ pub fn add_trait_assoc_items_to_impl(
// FIXME: Paths in nested macros are not handled well. See // FIXME: Paths in nested macros are not handled well. See
// `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test. // `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test.
let transform = let transform =
PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone()); PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone());
transform.apply(cloned_item.syntax()); transform.apply(cloned_item.syntax());
} }
cloned_item.remove_attrs_and_docs(); cloned_item.remove_attrs_and_docs();
@ -684,31 +684,31 @@ enum ReferenceConversionType {
} }
impl ReferenceConversion { impl ReferenceConversion {
pub(crate) fn convert_type(&self, db: &dyn HirDatabase) -> ast::Type { pub(crate) fn convert_type(&self, db: &dyn HirDatabase, edition: Edition) -> ast::Type {
let ty = match self.conversion { let ty = match self.conversion {
ReferenceConversionType::Copy => self.ty.display(db).to_string(), ReferenceConversionType::Copy => self.ty.display(db, edition).to_string(),
ReferenceConversionType::AsRefStr => "&str".to_owned(), ReferenceConversionType::AsRefStr => "&str".to_owned(),
ReferenceConversionType::AsRefSlice => { ReferenceConversionType::AsRefSlice => {
let type_argument_name = let type_argument_name =
self.ty.type_arguments().next().unwrap().display(db).to_string(); self.ty.type_arguments().next().unwrap().display(db, edition).to_string();
format!("&[{type_argument_name}]") format!("&[{type_argument_name}]")
} }
ReferenceConversionType::Dereferenced => { ReferenceConversionType::Dereferenced => {
let type_argument_name = let type_argument_name =
self.ty.type_arguments().next().unwrap().display(db).to_string(); self.ty.type_arguments().next().unwrap().display(db, edition).to_string();
format!("&{type_argument_name}") format!("&{type_argument_name}")
} }
ReferenceConversionType::Option => { ReferenceConversionType::Option => {
let type_argument_name = let type_argument_name =
self.ty.type_arguments().next().unwrap().display(db).to_string(); self.ty.type_arguments().next().unwrap().display(db, edition).to_string();
format!("Option<&{type_argument_name}>") format!("Option<&{type_argument_name}>")
} }
ReferenceConversionType::Result => { ReferenceConversionType::Result => {
let mut type_arguments = self.ty.type_arguments(); let mut type_arguments = self.ty.type_arguments();
let first_type_argument_name = let first_type_argument_name =
type_arguments.next().unwrap().display(db).to_string(); type_arguments.next().unwrap().display(db, edition).to_string();
let second_type_argument_name = let second_type_argument_name =
type_arguments.next().unwrap().display(db).to_string(); type_arguments.next().unwrap().display(db, edition).to_string();
format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>") format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>")
} }
}; };

View file

@ -6,7 +6,7 @@ use itertools::Itertools;
use stdx::to_lower_snake_case; use stdx::to_lower_snake_case;
use syntax::{ use syntax::{
ast::{self, HasName}, ast::{self, HasName},
match_ast, AstNode, SmolStr, match_ast, AstNode, Edition, SmolStr,
}; };
/// Trait names, that will be ignored when in `impl Trait` and `dyn Trait` /// Trait names, that will be ignored when in `impl Trait` and `dyn Trait`
@ -271,24 +271,25 @@ fn var_name_from_pat(pat: &ast::Pat) -> Option<ast::Name> {
fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<String> { fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<String> {
let ty = sema.type_of_expr(expr)?.adjusted(); let ty = sema.type_of_expr(expr)?.adjusted();
let ty = ty.remove_ref().unwrap_or(ty); let ty = ty.remove_ref().unwrap_or(ty);
let edition = sema.scope(expr.syntax())?.krate().edition(sema.db);
name_of_type(&ty, sema.db) name_of_type(&ty, sema.db, edition)
} }
fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option<String> { fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<String> {
let name = if let Some(adt) = ty.as_adt() { let name = if let Some(adt) = ty.as_adt() {
let name = adt.name(db).display(db).to_string(); let name = adt.name(db).display(db, edition).to_string();
if WRAPPER_TYPES.contains(&name.as_str()) { if WRAPPER_TYPES.contains(&name.as_str()) {
let inner_ty = ty.type_arguments().next()?; let inner_ty = ty.type_arguments().next()?;
return name_of_type(&inner_ty, db); return name_of_type(&inner_ty, db, edition);
} }
name name
} else if let Some(trait_) = ty.as_dyn_trait() { } else if let Some(trait_) = ty.as_dyn_trait() {
trait_name(&trait_, db)? trait_name(&trait_, db, edition)?
} else if let Some(traits) = ty.as_impl_traits(db) { } else if let Some(traits) = ty.as_impl_traits(db) {
let mut iter = traits.filter_map(|t| trait_name(&t, db)); let mut iter = traits.filter_map(|t| trait_name(&t, db, edition));
let name = iter.next()?; let name = iter.next()?;
if iter.next().is_some() { if iter.next().is_some() {
return None; return None;
@ -300,8 +301,8 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option<String> {
normalize(&name) normalize(&name)
} }
fn trait_name(trait_: &hir::Trait, db: &RootDatabase) -> Option<String> { fn trait_name(trait_: &hir::Trait, db: &RootDatabase, edition: Edition) -> Option<String> {
let name = trait_.name(db).display(db).to_string(); let name = trait_.name(db).display(db, edition).to_string();
if USELESS_TRAITS.contains(&name.as_str()) { if USELESS_TRAITS.contains(&name.as_str()) {
return None; return None;
} }

View file

@ -85,6 +85,7 @@ impl Completions {
CompletionItemKind::Keyword, CompletionItemKind::Keyword,
ctx.source_range(), ctx.source_range(),
SmolStr::new_static(keyword), SmolStr::new_static(keyword),
ctx.edition,
); );
item.add_to(self, ctx.db); item.add_to(self, ctx.db);
} }
@ -124,7 +125,8 @@ impl Completions {
kw: &str, kw: &str,
snippet: &str, snippet: &str,
) { ) {
let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw); let mut item =
CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw, ctx.edition);
match ctx.config.snippet_cap { match ctx.config.snippet_cap {
Some(cap) => { Some(cap) => {
@ -149,7 +151,8 @@ impl Completions {
kw: &str, kw: &str,
snippet: &str, snippet: &str,
) { ) {
let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw); let mut item =
CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw, ctx.edition);
match ctx.config.snippet_cap { match ctx.config.snippet_cap {
Some(cap) => item.insert_snippet(cap, snippet), Some(cap) => item.insert_snippet(cap, snippet),
@ -544,7 +547,8 @@ impl Completions {
CompletionItem::new( CompletionItem::new(
SymbolKind::LifetimeParam, SymbolKind::LifetimeParam,
ctx.source_range(), ctx.source_range(),
name.display_no_db().to_smolstr(), name.display_no_db(ctx.edition).to_smolstr(),
ctx.edition,
) )
.add_to(self, ctx.db) .add_to(self, ctx.db)
} }
@ -553,7 +557,8 @@ impl Completions {
CompletionItem::new( CompletionItem::new(
SymbolKind::Label, SymbolKind::Label,
ctx.source_range(), ctx.source_range(),
name.display_no_db().to_smolstr(), name.display_no_db(ctx.edition).to_smolstr(),
ctx.edition,
) )
.add_to(self, ctx.db) .add_to(self, ctx.db)
} }

View file

@ -49,11 +49,15 @@ pub(crate) fn complete_known_attribute_input(
match path.text().as_str() { match path.text().as_str() {
"repr" => repr::complete_repr(acc, ctx, tt), "repr" => repr::complete_repr(acc, ctx, tt),
"feature" => { "feature" => lint::complete_lint(
lint::complete_lint(acc, ctx, colon_prefix, &parse_tt_as_comma_sep_paths(tt)?, FEATURES) acc,
} ctx,
colon_prefix,
&parse_tt_as_comma_sep_paths(tt, ctx.edition)?,
FEATURES,
),
"allow" | "warn" | "deny" | "forbid" => { "allow" | "warn" | "deny" | "forbid" => {
let existing_lints = parse_tt_as_comma_sep_paths(tt)?; let existing_lints = parse_tt_as_comma_sep_paths(tt, ctx.edition)?;
let lints: Vec<Lint> = CLIPPY_LINT_GROUPS let lints: Vec<Lint> = CLIPPY_LINT_GROUPS
.iter() .iter()
@ -67,9 +71,12 @@ pub(crate) fn complete_known_attribute_input(
lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints); lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints);
} }
"cfg" => cfg::complete_cfg(acc, ctx), "cfg" => cfg::complete_cfg(acc, ctx),
"macro_use" => { "macro_use" => macro_use::complete_macro_use(
macro_use::complete_macro_use(acc, ctx, extern_crate, &parse_tt_as_comma_sep_paths(tt)?) acc,
} ctx,
extern_crate,
&parse_tt_as_comma_sep_paths(tt, ctx.edition)?,
),
_ => (), _ => (),
} }
Some(()) Some(())
@ -131,8 +138,12 @@ pub(crate) fn complete_attribute_path(
}); });
let add_completion = |attr_completion: &AttrCompletion| { let add_completion = |attr_completion: &AttrCompletion| {
let mut item = let mut item = CompletionItem::new(
CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), attr_completion.label); SymbolKind::Attribute,
ctx.source_range(),
attr_completion.label,
ctx.edition,
);
if let Some(lookup) = attr_completion.lookup { if let Some(lookup) = attr_completion.lookup {
item.lookup_by(lookup); item.lookup_by(lookup);

View file

@ -8,7 +8,8 @@ use crate::{completions::Completions, context::CompletionContext, CompletionItem
pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
let add_completion = |item: &str| { let add_completion = |item: &str| {
let mut completion = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item); let mut completion =
CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item, ctx.edition);
completion.insert_text(format!(r#""{item}""#)); completion.insert_text(format!(r#""{item}""#));
acc.add(completion.build(ctx.db)); acc.add(completion.build(ctx.db));
}; };
@ -41,7 +42,12 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| { name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
let s = s.as_str(); let s = s.as_str();
let insert_text = format!(r#""{s}""#); let insert_text = format!(r#""{s}""#);
let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s); let mut item = CompletionItem::new(
SymbolKind::BuiltinAttr,
ctx.source_range(),
s,
ctx.edition,
);
item.insert_text(insert_text); item.insert_text(insert_text);
acc.add(item.build(ctx.db)); acc.add(item.build(ctx.db));
@ -49,7 +55,8 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
}, },
None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| { None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| {
let s = s.as_str(); let s = s.as_str();
let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s); let item =
CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s, ctx.edition);
acc.add(item.build(ctx.db)); acc.add(item.build(ctx.db));
}), }),
} }

View file

@ -62,7 +62,7 @@ pub(crate) fn complete_derive_path(
_ => return acc.add_macro(ctx, path_ctx, mac, name), _ => return acc.add_macro(ctx, path_ctx, mac, name),
}; };
let name_ = name.display_no_db().to_smolstr(); let name_ = name.display_no_db(ctx.edition).to_smolstr();
let find = DEFAULT_DERIVE_DEPENDENCIES let find = DEFAULT_DERIVE_DEPENDENCIES
.iter() .iter()
.find(|derive_completion| derive_completion.label == name_); .find(|derive_completion| derive_completion.label == name_);
@ -72,10 +72,9 @@ pub(crate) fn complete_derive_path(
let mut components = vec![derive_completion.label]; let mut components = vec![derive_completion.label];
components.extend(derive_completion.dependencies.iter().filter( components.extend(derive_completion.dependencies.iter().filter(
|&&dependency| { |&&dependency| {
!existing_derives !existing_derives.iter().map(|it| it.name(ctx.db)).any(|it| {
.iter() it.display_no_db(ctx.edition).to_smolstr() == dependency
.map(|it| it.name(ctx.db)) })
.any(|it| it.display_no_db().to_smolstr() == dependency)
}, },
)); ));
let lookup = components.join(", "); let lookup = components.join(", ");
@ -85,6 +84,7 @@ pub(crate) fn complete_derive_path(
SymbolKind::Derive, SymbolKind::Derive,
ctx.source_range(), ctx.source_range(),
SmolStr::from_iter(label), SmolStr::from_iter(label),
ctx.edition,
); );
if let Some(docs) = mac.docs(ctx.db) { if let Some(docs) = mac.docs(ctx.db) {
item.documentation(docs); item.documentation(docs);

View file

@ -54,7 +54,8 @@ pub(super) fn complete_lint(
Some(qual) if !is_qualified => format!("{qual}::{name}"), Some(qual) if !is_qualified => format!("{qual}::{name}"),
_ => name.to_owned(), _ => name.to_owned(),
}; };
let mut item = CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label); let mut item =
CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label, ctx.edition);
item.documentation(Documentation::new(description.to_owned())); item.documentation(Documentation::new(description.to_owned()));
item.add_to(acc, ctx.db) item.add_to(acc, ctx.db)
} }

View file

@ -28,7 +28,8 @@ pub(super) fn complete_macro_use(
continue; continue;
} }
let item = CompletionItem::new(SymbolKind::Macro, ctx.source_range(), mac_name); let item =
CompletionItem::new(SymbolKind::Macro, ctx.source_range(), mac_name, ctx.edition);
item.add_to(acc, ctx.db); item.add_to(acc, ctx.db);
} }
} }

View file

@ -30,7 +30,12 @@ pub(super) fn complete_repr(
continue; continue;
} }
let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), label); let mut item = CompletionItem::new(
SymbolKind::BuiltinAttr,
ctx.source_range(),
label,
ctx.edition,
);
if let Some(lookup) = lookup { if let Some(lookup) = lookup {
item.lookup_by(lookup); item.lookup_by(lookup);
} }

View file

@ -29,6 +29,7 @@ pub(crate) fn complete_dot(
CompletionItemKind::Keyword, CompletionItemKind::Keyword,
ctx.source_range(), ctx.source_range(),
SmolStr::new_static("await"), SmolStr::new_static("await"),
ctx.edition,
); );
item.detail("expr.await"); item.detail("expr.await");
item.add_to(acc, ctx.db); item.add_to(acc, ctx.db);

View file

@ -56,7 +56,7 @@ pub(crate) fn complete_cargo_env_vars(
let range = original.text_range_between_quotes()?; let range = original.text_range_between_quotes()?;
CARGO_DEFINED_VARS.iter().for_each(|&(var, detail)| { CARGO_DEFINED_VARS.iter().for_each(|&(var, detail)| {
let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var); let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var, ctx.edition);
item.detail(detail); item.detail(detail);
item.add_to(acc, ctx.db); item.add_to(acc, ctx.db);
}); });

View file

@ -52,7 +52,12 @@ pub(crate) fn complete_extern_abi(
let abi_str = expanded; let abi_str = expanded;
let source_range = abi_str.text_range_between_quotes()?; let source_range = abi_str.text_range_between_quotes()?;
for &abi in SUPPORTED_CALLING_CONVENTIONS { for &abi in SUPPORTED_CALLING_CONVENTIONS {
CompletionItem::new(CompletionItemKind::Keyword, source_range, SmolStr::new_static(abi)) CompletionItem::new(
CompletionItemKind::Keyword,
source_range,
SmolStr::new_static(abi),
ctx.edition,
)
.add_to(acc, ctx.db); .add_to(acc, ctx.db);
} }
Some(()) Some(())

View file

@ -19,7 +19,8 @@ pub(crate) fn complete_extern_crate(acc: &mut Completions, ctx: &CompletionConte
let mut item = CompletionItem::new( let mut item = CompletionItem::new(
CompletionItemKind::SymbolKind(SymbolKind::Module), CompletionItemKind::SymbolKind(SymbolKind::Module),
ctx.source_range(), ctx.source_range(),
name.display_no_db().to_smolstr(), name.display_no_db(ctx.edition).to_smolstr(),
ctx.edition,
); );
item.set_documentation(module.docs(ctx.db)); item.set_documentation(module.docs(ctx.db));

View file

@ -411,7 +411,7 @@ fn compute_fuzzy_completion_order_key(
cov_mark::hit!(certain_fuzzy_order_test); cov_mark::hit!(certain_fuzzy_order_test);
let import_name = match proposed_mod_path.segments().last() { let import_name = match proposed_mod_path.segments().last() {
// FIXME: nasty alloc, this is a hot path! // FIXME: nasty alloc, this is a hot path!
Some(name) => name.display_no_db().to_smolstr().to_ascii_lowercase(), Some(name) => name.unescaped().display_no_db().to_smolstr().to_ascii_lowercase(),
None => return usize::MAX, None => return usize::MAX,
}; };
match import_name.match_indices(user_input_lowercased).next() { match import_name.match_indices(user_input_lowercased).next() {

View file

@ -32,7 +32,7 @@ pub(crate) fn complete_fn_param(
let comma_wrapper = comma_wrapper(ctx); let comma_wrapper = comma_wrapper(ctx);
let mut add_new_item_to_acc = |label: &str| { let mut add_new_item_to_acc = |label: &str| {
let mk_item = |label: &str, range: TextRange| { let mk_item = |label: &str, range: TextRange| {
CompletionItem::new(CompletionItemKind::Binding, range, label) CompletionItem::new(CompletionItemKind::Binding, range, label, ctx.edition)
}; };
let item = match &comma_wrapper { let item = match &comma_wrapper {
Some((fmt, range)) => mk_item(&fmt(label), *range), Some((fmt, range)) => mk_item(&fmt(label), *range),
@ -50,7 +50,7 @@ pub(crate) fn complete_fn_param(
ParamKind::Closure(closure) => { ParamKind::Closure(closure) => {
let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?; let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?;
params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { params_from_stmt_list_scope(ctx, stmt_list, |name, ty| {
add_new_item_to_acc(&format!("{}: {ty}", name.display(ctx.db))); add_new_item_to_acc(&format!("{}: {ty}", name.display(ctx.db, ctx.edition)));
}); });
} }
} }
@ -101,8 +101,8 @@ fn fill_fn_params(
if let Some(stmt_list) = function.syntax().parent().and_then(ast::StmtList::cast) { if let Some(stmt_list) = function.syntax().parent().and_then(ast::StmtList::cast) {
params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { params_from_stmt_list_scope(ctx, stmt_list, |name, ty| {
file_params file_params
.entry(format!("{}: {ty}", name.display(ctx.db))) .entry(format!("{}: {ty}", name.display(ctx.db, ctx.edition)))
.or_insert(name.display(ctx.db).to_string()); .or_insert(name.display(ctx.db, ctx.edition).to_string());
}); });
} }
remove_duplicated(&mut file_params, param_list.params()); remove_duplicated(&mut file_params, param_list.params());

View file

@ -35,7 +35,8 @@ pub(crate) fn format_string(
CompletionItem::new( CompletionItem::new(
CompletionItemKind::Binding, CompletionItemKind::Binding,
source_range, source_range,
name.display_no_db().to_smolstr(), name.display_no_db(ctx.edition).to_smolstr(),
ctx.edition,
) )
.add_to(acc, ctx.db); .add_to(acc, ctx.db);
}); });
@ -50,7 +51,8 @@ pub(crate) fn format_string(
CompletionItem::new( CompletionItem::new(
CompletionItemKind::SymbolKind(symbol_kind), CompletionItemKind::SymbolKind(symbol_kind),
source_range, source_range,
name.display_no_db().to_smolstr(), name.display_no_db(ctx.edition).to_smolstr(),
ctx.edition,
) )
.add_to(acc, ctx.db); .add_to(acc, ctx.db);
} }

View file

@ -184,7 +184,7 @@ fn add_function_impl(
let label = format_smolstr!( let label = format_smolstr!(
"{}fn {}({})", "{}fn {}({})",
if is_async { "async " } else { "" }, if is_async { "async " } else { "" },
fn_name.display(ctx.db), fn_name.display(ctx.db, ctx.edition),
if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." } if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." }
); );
@ -194,11 +194,11 @@ fn add_function_impl(
SymbolKind::Function SymbolKind::Function
}); });
let mut item = CompletionItem::new(completion_kind, replacement_range, label); let mut item = CompletionItem::new(completion_kind, replacement_range, label, ctx.edition);
item.lookup_by(format!( item.lookup_by(format!(
"{}fn {}", "{}fn {}",
if is_async { "async " } else { "" }, if is_async { "async " } else { "" },
fn_name.display(ctx.db) fn_name.display(ctx.db, ctx.edition)
)) ))
.set_documentation(func.docs(ctx.db)) .set_documentation(func.docs(ctx.db))
.set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
@ -262,7 +262,8 @@ fn add_type_alias_impl(
let label = format_smolstr!("type {alias_name} ="); let label = format_smolstr!("type {alias_name} =");
let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label); let mut item =
CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label, ctx.edition);
item.lookup_by(format!("type {alias_name}")) item.lookup_by(format!("type {alias_name}"))
.set_documentation(type_alias.docs(ctx.db)) .set_documentation(type_alias.docs(ctx.db))
.set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
@ -320,7 +321,7 @@ fn add_const_impl(
const_: hir::Const, const_: hir::Const,
impl_def: hir::Impl, impl_def: hir::Impl,
) { ) {
let const_name = const_.name(ctx.db).map(|n| n.display_no_db().to_smolstr()); let const_name = const_.name(ctx.db).map(|n| n.display_no_db(ctx.edition).to_smolstr());
if let Some(const_name) = const_name { if let Some(const_name) = const_name {
if let Some(source) = ctx.sema.source(const_) { if let Some(source) = ctx.sema.source(const_) {
@ -334,7 +335,8 @@ fn add_const_impl(
let label = make_const_compl_syntax(&transformed_const, source.file_id.is_macro()); let label = make_const_compl_syntax(&transformed_const, source.file_id.is_macro());
let replacement = format!("{label} "); let replacement = format!("{label} ");
let mut item = CompletionItem::new(SymbolKind::Const, replacement_range, label); let mut item =
CompletionItem::new(SymbolKind::Const, replacement_range, label, ctx.edition);
item.lookup_by(format_smolstr!("const {const_name}")) item.lookup_by(format_smolstr!("const {const_name}"))
.set_documentation(const_.docs(ctx.db)) .set_documentation(const_.docs(ctx.db))
.set_relevance(CompletionRelevance { .set_relevance(CompletionRelevance {

View file

@ -41,7 +41,7 @@ pub(crate) fn complete_lifetime(
if matches!( if matches!(
res, res,
ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))
if param_lifetime != Some(&*name.display_no_db().to_smolstr()) if param_lifetime != Some(&*name.display_no_db(ctx.edition).to_smolstr())
) { ) {
acc.add_lifetime(ctx, name); acc.add_lifetime(ctx, name);
} }

View file

@ -53,7 +53,7 @@ pub(crate) fn complete_mod(
let existing_mod_declarations = current_module let existing_mod_declarations = current_module
.children(ctx.db) .children(ctx.db)
.filter_map(|module| Some(module.name(ctx.db)?.display(ctx.db).to_string())) .filter_map(|module| Some(module.name(ctx.db)?.display(ctx.db, ctx.edition).to_string()))
.filter(|module| module != ctx.original_token.text()) .filter(|module| module != ctx.original_token.text())
.collect::<FxHashSet<_>>(); .collect::<FxHashSet<_>>();
@ -99,7 +99,8 @@ pub(crate) fn complete_mod(
if mod_under_caret.semicolon_token().is_none() { if mod_under_caret.semicolon_token().is_none() {
label.push(';'); label.push(';');
} }
let item = CompletionItem::new(SymbolKind::Module, ctx.source_range(), &label); let item =
CompletionItem::new(SymbolKind::Module, ctx.source_range(), &label, ctx.edition);
item.add_to(acc, ctx.db) item.add_to(acc, ctx.db)
}); });
@ -140,7 +141,9 @@ fn directory_to_look_for_submodules(
module_chain_to_containing_module_file(module, db) module_chain_to_containing_module_file(module, db)
.into_iter() .into_iter()
.filter_map(|module| module.name(db)) .filter_map(|module| module.name(db))
.try_fold(base_directory, |path, name| path.join(&name.display_no_db().to_smolstr())) .try_fold(base_directory, |path, name| {
path.join(&name.unescaped().display_no_db().to_smolstr())
})
} }
fn module_chain_to_containing_module_file( fn module_chain_to_containing_module_file(

View file

@ -72,7 +72,10 @@ pub(crate) fn complete_postfix(
let mut item = postfix_snippet( let mut item = postfix_snippet(
"drop", "drop",
"fn drop(&mut self)", "fn drop(&mut self)",
&format!("{path}($0{receiver_text})", path = path.display(ctx.db)), &format!(
"{path}($0{receiver_text})",
path = path.display(ctx.db, ctx.edition)
),
); );
item.set_documentation(drop_fn.docs(ctx.db)); item.set_documentation(drop_fn.docs(ctx.db));
item.add_to(acc, ctx.db); item.add_to(acc, ctx.db);
@ -335,8 +338,12 @@ fn build_postfix_snippet_builder<'ctx>(
) -> impl Fn(&str, &str, &str) -> Builder + 'ctx { ) -> impl Fn(&str, &str, &str) -> Builder + 'ctx {
move |label, detail, snippet| { move |label, detail, snippet| {
let edit = TextEdit::replace(delete_range, snippet.to_owned()); let edit = TextEdit::replace(delete_range, snippet.to_owned());
let mut item = let mut item = CompletionItem::new(
CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label); CompletionItemKind::Snippet,
ctx.source_range(),
label,
ctx.edition,
);
item.detail(detail).snippet_edit(cap, edit); item.detail(detail).snippet_edit(cap, edit);
let postfix_match = if ctx.original_token.text() == label { let postfix_match = if ctx.original_token.text() == label {
cov_mark::hit!(postfix_exact_match_is_high_priority); cov_mark::hit!(postfix_exact_match_is_high_priority);

View file

@ -73,6 +73,7 @@ pub(crate) fn complete_record_expr_fields(
CompletionItemKind::Snippet, CompletionItemKind::Snippet,
ctx.source_range(), ctx.source_range(),
SmolStr::new_static(".."), SmolStr::new_static(".."),
ctx.edition,
); );
item.insert_text("."); item.insert_text(".");
item.add_to(acc, ctx.db); item.add_to(acc, ctx.db);
@ -101,6 +102,7 @@ pub(crate) fn add_default_update(
SymbolKind::Field, SymbolKind::Field,
ctx.source_range(), ctx.source_range(),
SmolStr::new_static(completion_text), SmolStr::new_static(completion_text),
ctx.edition,
); );
let completion_text = let completion_text =
completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text); completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);

View file

@ -118,7 +118,8 @@ macro_rules! $1 {
} }
fn snippet(ctx: &CompletionContext<'_>, cap: SnippetCap, label: &str, snippet: &str) -> Builder { fn snippet(ctx: &CompletionContext<'_>, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label); let mut item =
CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label, ctx.edition);
item.insert_snippet(cap, snippet); item.insert_snippet(cap, snippet);
item item
} }

View file

@ -107,7 +107,11 @@ pub(crate) fn complete_use_path(
let item = CompletionItem::new( let item = CompletionItem::new(
CompletionItemKind::SymbolKind(SymbolKind::Enum), CompletionItemKind::SymbolKind(SymbolKind::Enum),
ctx.source_range(), ctx.source_range(),
format_smolstr!("{}::", e.name(ctx.db).display(ctx.db)), format_smolstr!(
"{}::",
e.name(ctx.db).display(ctx.db, ctx.edition)
),
ctx.edition,
); );
acc.add(item.build(ctx.db)); acc.add(item.build(ctx.db));
} }

Some files were not shown because too many files have changed in this diff Show more