Merge pull request #19644 from ChayimFriedman2/const-syms
internal: Make predefined symbols `const` instead of `static`
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index e7784f3..5431ec9 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -345,6 +345,7 @@
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
+ UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None;
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs
index 389ef6d..4c5cae1 100644
--- a/crates/hir-def/src/signatures.rs
+++ b/crates/hir-def/src/signatures.rs
@@ -62,6 +62,8 @@
const IS_MANUALLY_DROP = 1 << 5;
/// Indicates whether this struct is `UnsafeCell`.
const IS_UNSAFE_CELL = 1 << 6;
+ /// Indicates whether this struct is `UnsafePinned`.
+ const IS_UNSAFE_PINNED = 1 << 7;
}
}
@@ -84,6 +86,7 @@
LangItem::OwnedBox => flags |= StructFlags::IS_BOX,
LangItem::ManuallyDrop => flags |= StructFlags::IS_MANUALLY_DROP,
LangItem::UnsafeCell => flags |= StructFlags::IS_UNSAFE_CELL,
+ LangItem::UnsafePinned => flags |= StructFlags::IS_UNSAFE_PINNED,
_ => (),
}
}
diff --git a/crates/hir-ty/src/lang_items.rs b/crates/hir-ty/src/lang_items.rs
index 9b46847..3ef7f50 100644
--- a/crates/hir-ty/src/lang_items.rs
+++ b/crates/hir-ty/src/lang_items.rs
@@ -11,12 +11,6 @@
db.struct_signature(id).flags.contains(StructFlags::IS_BOX)
}
-pub fn is_unsafe_cell(db: &dyn HirDatabase, adt: AdtId) -> bool {
- let AdtId::StructId(id) = adt else { return false };
-
- db.struct_signature(id).flags.contains(StructFlags::IS_UNSAFE_CELL)
-}
-
pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> {
use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering};
Some(match op {
diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs
index 331fb3c..73dba30 100644
--- a/crates/hir-ty/src/layout/adt.rs
+++ b/crates/hir-ty/src/layout/adt.rs
@@ -5,7 +5,7 @@
use hir_def::{
AdtId, VariantId,
layout::{Integer, ReprOptions, TargetDataLayout},
- signatures::VariantFields,
+ signatures::{StructFlags, VariantFields},
};
use intern::sym;
use rustc_index::IndexVec;
@@ -16,7 +16,6 @@
use crate::{
Substitution, TraitEnvironment,
db::HirDatabase,
- lang_items::is_unsafe_cell,
layout::{Layout, LayoutError, field_ty},
};
@@ -40,18 +39,22 @@
.map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), trait_env.clone()))
.collect::<Result<Vec<_>, _>>()
};
- let (variants, repr) = match def {
+ let (variants, repr, is_special_no_niche) = match def {
AdtId::StructId(s) => {
- let data = db.struct_signature(s);
+ let sig = db.struct_signature(s);
let mut r = SmallVec::<[_; 1]>::new();
r.push(handle_variant(s.into(), &db.variant_fields(s.into()))?);
- (r, data.repr.unwrap_or_default())
+ (
+ r,
+ sig.repr.unwrap_or_default(),
+ sig.flags.intersects(StructFlags::IS_UNSAFE_CELL | StructFlags::IS_UNSAFE_PINNED),
+ )
}
AdtId::UnionId(id) => {
let data = db.union_signature(id);
let mut r = SmallVec::new();
r.push(handle_variant(id.into(), &db.variant_fields(id.into()))?);
- (r, data.repr.unwrap_or_default())
+ (r, data.repr.unwrap_or_default(), false)
}
AdtId::EnumId(e) => {
let variants = db.enum_variants(e);
@@ -60,7 +63,7 @@
.iter()
.map(|&(v, _)| handle_variant(v.into(), &db.variant_fields(v.into())))
.collect::<Result<SmallVec<_>, _>>()?;
- (r, db.enum_signature(e).repr.unwrap_or_default())
+ (r, db.enum_signature(e).repr.unwrap_or_default(), false)
}
};
let variants = variants
@@ -75,7 +78,7 @@
&repr,
&variants,
matches!(def, AdtId::EnumId(..)),
- is_unsafe_cell(db, def),
+ is_special_no_niche,
layout_scalar_valid_range(db, def),
|min, max| repr_discr(dl, &repr, min, max).unwrap_or((Integer::I8, false)),
variants.iter_enumerated().filter_map(|(id, _)| {
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs
index 58e7f58..893997c 100644
--- a/crates/ide-completion/src/completions/item_list.rs
+++ b/crates/ide-completion/src/completions/item_list.rs
@@ -142,7 +142,7 @@
add_keyword("struct", "struct $0");
add_keyword("trait", "trait $1 {\n $0\n}");
add_keyword("union", "union $1 {\n $0\n}");
- add_keyword("use", "use $0");
+ add_keyword("use", "use $0;");
if no_vis_qualifiers {
add_keyword("impl", "impl $1 {\n $0\n}");
add_keyword("impl for", "impl $1 for $2 {\n $0\n}");
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 7bb8800..69b83f3 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -909,9 +909,9 @@
let mut needs_impl_header = true;
for (trait_, assoc_types) in notable_traits {
desc.push_str(if mem::take(&mut needs_impl_header) {
- "Implements notable traits: "
+ "Implements notable traits: `"
} else {
- ", "
+ "`, `"
});
format_to!(desc, "{}", trait_.name(db).display(db, edition));
if !assoc_types.is_empty() {
@@ -931,7 +931,12 @@
desc.push('>');
}
}
- desc.is_empty().not().then_some(desc)
+ if desc.is_empty() {
+ None
+ } else {
+ desc.push('`');
+ Some(desc)
+ }
}
fn type_info(
@@ -958,37 +963,12 @@
res.markup = if let Some(adjusted_ty) = adjusted {
walk_and_push_ty(db, &adjusted_ty, &mut push_new_def);
- let notable = {
- let mut desc = String::new();
- let mut needs_impl_header = true;
- for (trait_, assoc_types) in notable_traits(db, &original) {
- desc.push_str(if mem::take(&mut needs_impl_header) {
- "Implements Notable Traits: "
- } else {
- ", "
- });
- format_to!(desc, "{}", trait_.name(db).display(db, edition));
- if !assoc_types.is_empty() {
- desc.push('<');
- format_to!(
- desc,
- "{}",
- assoc_types.into_iter().format_with(", ", |(ty, name), f| {
- f(&name.display(db, edition))?;
- f(&" = ")?;
- match ty {
- Some(ty) => f(&ty.display(db, display_target)),
- None => f(&"?"),
- }
- })
- );
- desc.push('>');
- }
- }
- if !desc.is_empty() {
- desc.push('\n');
- }
- desc
+ let notable = if let Some(notable) =
+ render_notable_trait(db, ¬able_traits(db, &original), edition, display_target)
+ {
+ format!("{notable}\n")
+ } else {
+ String::new()
};
let original = original.display(db, display_target).to_string();
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index e08a956..293efa0 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -8929,7 +8929,7 @@
---
- Implements notable traits: Notable\<Assoc = &str, Assoc2 = char>
+ Implements notable traits: `Notable<Assoc = &str, Assoc2 = char>`
---
@@ -9054,7 +9054,7 @@
S
```
___
- Implements notable traits: Future<Output = u32>, Iterator<Item = S>, Notable"#]],
+ Implements notable traits: `Future<Output = u32>`, `Iterator<Item = S>`, `Notable`"#]],
);
}
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index a4fffc2..3effc66 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -495,6 +495,7 @@
unreachable_2021,
unreachable,
unsafe_cell,
+ unsafe_pinned,
unsize,
unstable,
usize,
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs
index c50e63d..3e52dba 100644
--- a/crates/load-cargo/src/lib.rs
+++ b/crates/load-cargo/src/lib.rs
@@ -66,7 +66,7 @@
pub fn load_workspace(
ws: ProjectWorkspace,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
load_config: &LoadCargoConfig,
) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option<ProcMacroClient>)> {
let (sender, receiver) = unbounded();
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 5b0085f..34dcf2a 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -58,7 +58,7 @@
// }
attributes::outer_attrs(p);
- if p.at(T![let]) {
+ if p.at(T![let]) || (p.at(T![super]) && p.nth_at(1, T![let])) {
let_stmt(p, semicolon);
m.complete(p, LET_STMT);
return;
@@ -113,8 +113,9 @@
}
// test let_stmt
-// fn f() { let x: i32 = 92; }
+// fn f() { let x: i32 = 92; super let y; super::foo; }
pub(super) fn let_stmt(p: &mut Parser<'_>, with_semi: Semicolon) {
+ p.eat(T![super]);
p.bump(T![let]);
patterns::pattern(p);
if p.at(T![:]) {
diff --git a/crates/parser/src/grammar/items/consts.rs b/crates/parser/src/grammar/items/consts.rs
index 9549ec9..8e25598 100644
--- a/crates/parser/src/grammar/items/consts.rs
+++ b/crates/parser/src/grammar/items/consts.rs
@@ -24,6 +24,18 @@
name(p);
}
+ // FIXME: Recover on statics with generic params/where clause.
+ if is_const {
+ // test generic_const
+ // const C<i32>: u32 = 0;
+ // impl Foo {
+ // const C<'a>: &'a () = &();
+ // }
+ generic_params::opt_generic_param_list(p);
+ }
+ // test_err generic_static
+ // static C<i32>: u32 = 0;
+
if p.at(T![:]) {
types::ascription(p);
} else {
@@ -32,6 +44,20 @@
if p.eat(T![=]) {
expressions::expr(p);
}
+
+ if is_const {
+ // test const_where_clause
+ // const C<i32>: u32 = 0
+ // where i32: Copy;
+ // trait Foo {
+ // const C: i32 where i32: Copy;
+ // }
+ generic_params::opt_where_clause(p);
+ }
+ // test_err static_where_clause
+ // static C: u32 = 0
+ // where i32: Copy;
+
p.expect(T![;]);
m.complete(p, if is_const { CONST } else { STATIC });
}
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index 2ea2934..87ffc99 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -139,6 +139,10 @@
run_and_expect_no_errors("test_data/parser/inline/ok/const_trait_bound.rs");
}
#[test]
+ fn const_where_clause() {
+ run_and_expect_no_errors("test_data/parser/inline/ok/const_where_clause.rs");
+ }
+ #[test]
fn continue_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/continue_expr.rs"); }
#[test]
fn crate_path() { run_and_expect_no_errors("test_data/parser/inline/ok/crate_path.rs"); }
@@ -278,6 +282,8 @@
run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg_bounds.rs");
}
#[test]
+ fn generic_const() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_const.rs"); }
+ #[test]
fn generic_param_attribute() {
run_and_expect_no_errors("test_data/parser/inline/ok/generic_param_attribute.rs");
}
@@ -764,6 +770,8 @@
run_and_expect_errors("test_data/parser/inline/err/generic_param_list_recover.rs");
}
#[test]
+ fn generic_static() { run_and_expect_errors("test_data/parser/inline/err/generic_static.rs"); }
+ #[test]
fn impl_type() { run_and_expect_errors("test_data/parser/inline/err/impl_type.rs"); }
#[test]
fn let_else_right_curly_brace() {
@@ -836,6 +844,10 @@
run_and_expect_errors("test_data/parser/inline/err/recover_from_missing_const_default.rs");
}
#[test]
+ fn static_where_clause() {
+ run_and_expect_errors("test_data/parser/inline/err/static_where_clause.rs");
+ }
+ #[test]
fn struct_field_recover() {
run_and_expect_errors("test_data/parser/inline/err/struct_field_recover.rs");
}
diff --git a/crates/parser/test_data/parser/inline/err/generic_static.rast b/crates/parser/test_data/parser/inline/err/generic_static.rast
new file mode 100644
index 0000000..485ad11
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/generic_static.rast
@@ -0,0 +1,42 @@
+SOURCE_FILE
+ STATIC
+ STATIC_KW "static"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ ERROR
+ L_ANGLE "<"
+ ERROR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ ERROR
+ R_ANGLE ">"
+ ERROR
+ COLON ":"
+ WHITESPACE " "
+ ERROR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE " "
+ ERROR
+ EQ "="
+ WHITESPACE " "
+ ERROR
+ INT_NUMBER "0"
+ ERROR
+ SEMICOLON ";"
+ WHITESPACE "\n"
+error 8: missing type for `const` or `static`
+error 8: expected SEMICOLON
+error 8: expected an item
+error 12: expected an item
+error 12: expected an item
+error 13: expected an item
+error 18: expected an item
+error 19: expected an item
+error 21: expected an item
+error 22: expected an item
diff --git a/crates/parser/test_data/parser/inline/err/generic_static.rs b/crates/parser/test_data/parser/inline/err/generic_static.rs
new file mode 100644
index 0000000..d76aa7a
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/generic_static.rs
@@ -0,0 +1 @@
+static C<i32>: u32 = 0;
diff --git a/crates/parser/test_data/parser/inline/err/static_where_clause.rast b/crates/parser/test_data/parser/inline/err/static_where_clause.rast
new file mode 100644
index 0000000..cde3e47
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/static_where_clause.rast
@@ -0,0 +1,44 @@
+SOURCE_FILE
+ STATIC
+ STATIC_KW "static"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ WHITESPACE "\n"
+ ERROR
+ WHERE_KW "where"
+ WHITESPACE " "
+ ERROR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ ERROR
+ COLON ":"
+ WHITESPACE " "
+ ERROR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ ERROR
+ SEMICOLON ";"
+ WHITESPACE "\n"
+error 17: expected SEMICOLON
+error 18: expected an item
+error 27: expected an item
+error 27: expected an item
+error 33: expected an item
+error 33: expected an item
diff --git a/crates/parser/test_data/parser/inline/err/static_where_clause.rs b/crates/parser/test_data/parser/inline/err/static_where_clause.rs
new file mode 100644
index 0000000..c330f35
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/static_where_clause.rs
@@ -0,0 +1,2 @@
+static C: u32 = 0
+where i32: Copy;
diff --git a/crates/parser/test_data/parser/inline/ok/const_where_clause.rast b/crates/parser/test_data/parser/inline/ok/const_where_clause.rast
new file mode 100644
index 0000000..12148f6
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/const_where_clause.rast
@@ -0,0 +1,89 @@
+SOURCE_FILE
+ CONST
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "i32"
+ R_ANGLE ">"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ CONST
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/const_where_clause.rs b/crates/parser/test_data/parser/inline/ok/const_where_clause.rs
new file mode 100644
index 0000000..5ad4b2f
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/const_where_clause.rs
@@ -0,0 +1,5 @@
+const C<i32>: u32 = 0
+where i32: Copy;
+trait Foo {
+ const C: i32 where i32: Copy;
+}
diff --git a/crates/parser/test_data/parser/inline/ok/generic_const.rast b/crates/parser/test_data/parser/inline/ok/generic_const.rast
new file mode 100644
index 0000000..bf432b9
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/generic_const.rast
@@ -0,0 +1,71 @@
+SOURCE_FILE
+ CONST
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "i32"
+ R_ANGLE ">"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ CONST
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ COLON ":"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/generic_const.rs b/crates/parser/test_data/parser/inline/ok/generic_const.rs
new file mode 100644
index 0000000..ce718a4
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/generic_const.rs
@@ -0,0 +1,4 @@
+const C<i32>: u32 = 0;
+impl Foo {
+ const C<'a>: &'a () = &();
+}
diff --git a/crates/parser/test_data/parser/inline/ok/let_stmt.rast b/crates/parser/test_data/parser/inline/ok/let_stmt.rast
index de9d0fc..d99dad4 100644
--- a/crates/parser/test_data/parser/inline/ok/let_stmt.rast
+++ b/crates/parser/test_data/parser/inline/ok/let_stmt.rast
@@ -32,5 +32,28 @@
INT_NUMBER "92"
SEMICOLON ";"
WHITESPACE " "
+ LET_STMT
+ SUPER_KW "super"
+ WHITESPACE " "
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "y"
+ SEMICOLON ";"
+ WHITESPACE " "
+ EXPR_STMT
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SUPER_KW "super"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ SEMICOLON ";"
+ WHITESPACE " "
R_CURLY "}"
WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/let_stmt.rs b/crates/parser/test_data/parser/inline/ok/let_stmt.rs
index 8003999..d4cc1be 100644
--- a/crates/parser/test_data/parser/inline/ok/let_stmt.rs
+++ b/crates/parser/test_data/parser/inline/ok/let_stmt.rs
@@ -1 +1 @@
-fn f() { let x: i32 = 92; }
+fn f() { let x: i32 = 92; super let y; super::foo; }
diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs
index d67d605..25c30b6 100644
--- a/crates/proc-macro-api/src/lib.rs
+++ b/crates/proc-macro-api/src/lib.rs
@@ -105,10 +105,11 @@
impl ProcMacroClient {
/// Spawns an external process as the proc macro server and returns a client connected to it.
- pub fn spawn(
+ pub fn spawn<'a>(
process_path: &AbsPath,
- env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>
- + Clone,
+ env: impl IntoIterator<
+ Item = (impl AsRef<std::ffi::OsStr>, &'a Option<impl 'a + AsRef<std::ffi::OsStr>>),
+ > + Clone,
) -> io::Result<ProcMacroClient> {
let process = ProcMacroServerProcess::run(process_path, env)?;
Ok(ProcMacroClient { process: Arc::new(process), path: process_path.to_owned() })
diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs
index 27bf751..fcea75e 100644
--- a/crates/proc-macro-api/src/process.rs
+++ b/crates/proc-macro-api/src/process.rs
@@ -43,10 +43,11 @@
impl ProcMacroServerProcess {
/// Starts the proc-macro server and performs a version check
- pub(crate) fn run(
+ pub(crate) fn run<'a>(
process_path: &AbsPath,
- env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>
- + Clone,
+ env: impl IntoIterator<
+ Item = (impl AsRef<std::ffi::OsStr>, &'a Option<impl 'a + AsRef<std::ffi::OsStr>>),
+ > + Clone,
) -> io::Result<ProcMacroServerProcess> {
let create_srv = || {
let mut process = Process::run(process_path, env.clone())?;
@@ -193,9 +194,11 @@
impl Process {
/// Runs a new proc-macro server process with the specified environment variables.
- fn run(
+ fn run<'a>(
path: &AbsPath,
- env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>,
+ env: impl IntoIterator<
+ Item = (impl AsRef<std::ffi::OsStr>, &'a Option<impl 'a + AsRef<std::ffi::OsStr>>),
+ >,
) -> io::Result<Process> {
let child = JodChild(mk_child(path, env)?);
Ok(Process { child })
@@ -212,14 +215,21 @@
}
/// Creates and configures a new child process for the proc-macro server.
-fn mk_child(
+fn mk_child<'a>(
path: &AbsPath,
- env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>,
+ extra_env: impl IntoIterator<
+ Item = (impl AsRef<std::ffi::OsStr>, &'a Option<impl 'a + AsRef<std::ffi::OsStr>>),
+ >,
) -> io::Result<Child> {
#[allow(clippy::disallowed_methods)]
let mut cmd = Command::new(path);
- cmd.envs(env)
- .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
+ for env in extra_env {
+ match env {
+ (key, Some(val)) => cmd.env(key, val),
+ (key, None) => cmd.env_remove(key),
+ };
+ }
+ cmd.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit());
diff --git a/crates/project-model/src/build_dependencies.rs b/crates/project-model/src/build_dependencies.rs
index b26d19e..e0c38cc 100644
--- a/crates/project-model/src/build_dependencies.rs
+++ b/crates/project-model/src/build_dependencies.rs
@@ -163,7 +163,7 @@
pub(crate) fn rustc_crates(
rustc: &CargoWorkspace,
current_dir: &AbsPath,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
sysroot: &Sysroot,
) -> Self {
let mut bs = WorkspaceBuildScripts::default();
@@ -172,16 +172,14 @@
}
let res = (|| {
let target_libdir = (|| {
- let mut cargo_config = sysroot.tool(Tool::Cargo, current_dir);
- cargo_config.envs(extra_env);
+ let mut cargo_config = sysroot.tool(Tool::Cargo, current_dir, extra_env);
cargo_config
.args(["rustc", "-Z", "unstable-options", "--print", "target-libdir"])
.env("RUSTC_BOOTSTRAP", "1");
if let Ok(it) = utf8_stdout(&mut cargo_config) {
return Ok(it);
}
- let mut cmd = sysroot.tool(Tool::Rustc, current_dir);
- cmd.envs(extra_env);
+ let mut cmd = sysroot.tool(Tool::Rustc, current_dir, extra_env);
cmd.args(["--print", "target-libdir"]);
utf8_stdout(&mut cmd)
})()?;
@@ -390,12 +388,12 @@
) -> io::Result<Command> {
let mut cmd = match config.run_build_script_command.as_deref() {
Some([program, args @ ..]) => {
- let mut cmd = toolchain::command(program, current_dir);
+ let mut cmd = toolchain::command(program, current_dir, &config.extra_env);
cmd.args(args);
cmd
}
_ => {
- let mut cmd = sysroot.tool(Tool::Cargo, current_dir);
+ let mut cmd = sysroot.tool(Tool::Cargo, current_dir, &config.extra_env);
cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]);
cmd.args(&config.extra_args);
@@ -448,7 +446,6 @@
}
};
- cmd.envs(&config.extra_env);
if config.wrap_rustc_in_build_scripts {
// Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
// that to compile only proc macros and build scripts during the initial
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index d304c97..6e730b1 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -104,7 +104,7 @@
/// Extra args to pass to the cargo command.
pub extra_args: Vec<String>,
/// Extra env vars to set when invoking the cargo command
- pub extra_env: FxHashMap<String, String>,
+ pub extra_env: FxHashMap<String, Option<String>>,
pub invocation_strategy: InvocationStrategy,
/// Optional path to use instead of `target` when building
pub target_dir: Option<Utf8PathBuf>,
@@ -289,7 +289,7 @@
/// Extra args to pass to the cargo command.
pub extra_args: Vec<String>,
/// Extra env vars to set when invoking the cargo command
- pub extra_env: FxHashMap<String, String>,
+ pub extra_env: FxHashMap<String, Option<String>>,
}
// Deserialize helper for the cargo metadata
@@ -343,11 +343,10 @@
locked: bool,
progress: &dyn Fn(String),
) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
- let cargo = sysroot.tool(Tool::Cargo, current_dir);
+ let cargo = sysroot.tool(Tool::Cargo, current_dir, &config.extra_env);
let mut meta = MetadataCommand::new();
meta.cargo_path(cargo.get_program());
cargo.get_envs().for_each(|(var, val)| _ = meta.env(var, val.unwrap_or_default()));
- config.extra_env.iter().for_each(|(var, val)| _ = meta.env(var, val));
meta.manifest_path(cargo_toml.to_path_buf());
match &config.features {
CargoFeatures::All => {
diff --git a/crates/project-model/src/env.rs b/crates/project-model/src/env.rs
index 08d51c0..f2e5df1 100644
--- a/crates/project-model/src/env.rs
+++ b/crates/project-model/src/env.rs
@@ -62,11 +62,10 @@
pub(crate) fn cargo_config_env(
manifest: &ManifestPath,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
sysroot: &Sysroot,
) -> Env {
- let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent());
- cargo_config.envs(extra_env);
+ let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env);
cargo_config
.args(["-Z", "unstable-options", "config", "get", "env"])
.env("RUSTC_BOOTSTRAP", "1");
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index 6ed030a..c7c1b04 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -86,7 +86,7 @@
impl Sysroot {
/// Attempts to discover the toolchain's sysroot from the given `dir`.
- pub fn discover(dir: &AbsPath, extra_env: &FxHashMap<String, String>) -> Sysroot {
+ pub fn discover(dir: &AbsPath, extra_env: &FxHashMap<String, Option<String>>) -> Sysroot {
let sysroot_dir = discover_sysroot_dir(dir, extra_env);
let rust_lib_src_dir = sysroot_dir.as_ref().ok().map(|sysroot_dir| {
discover_rust_lib_src_dir_or_add_component(sysroot_dir, dir, extra_env)
@@ -96,7 +96,7 @@
pub fn discover_with_src_override(
current_dir: &AbsPath,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
rust_lib_src_dir: AbsPathBuf,
) -> Sysroot {
let sysroot_dir = discover_sysroot_dir(current_dir, extra_env);
@@ -118,7 +118,12 @@
}
/// Returns a command to run a tool preferring the cargo proxies if the sysroot exists.
- pub fn tool(&self, tool: Tool, current_dir: impl AsRef<Path>) -> Command {
+ pub fn tool(
+ &self,
+ tool: Tool,
+ current_dir: impl AsRef<Path>,
+ envs: &FxHashMap<String, Option<String>>,
+ ) -> Command {
match self.root() {
Some(root) => {
// special case rustc, we can look that up directly in the sysroot's bin folder
@@ -127,15 +132,15 @@
if let Some(path) =
probe_for_binary(root.join("bin").join(Tool::Rustc.name()).into())
{
- return toolchain::command(path, current_dir);
+ return toolchain::command(path, current_dir, envs);
}
}
- let mut cmd = toolchain::command(tool.prefer_proxy(), current_dir);
+ let mut cmd = toolchain::command(tool.prefer_proxy(), current_dir, envs);
cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(root));
cmd
}
- _ => toolchain::command(tool.path(), current_dir),
+ _ => toolchain::command(tool.path(), current_dir, envs),
}
}
@@ -292,7 +297,7 @@
// the sysroot uses `public-dependency`, so we make cargo think it's a nightly
cargo_config.extra_env.insert(
"__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS".to_owned(),
- "nightly".to_owned(),
+ Some("nightly".to_owned()),
);
let (mut res, _) = match CargoWorkspace::fetch_metadata(
@@ -368,10 +373,9 @@
fn discover_sysroot_dir(
current_dir: &AbsPath,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
) -> Result<AbsPathBuf> {
- let mut rustc = toolchain::command(Tool::Rustc.path(), current_dir);
- rustc.envs(extra_env);
+ let mut rustc = toolchain::command(Tool::Rustc.path(), current_dir, extra_env);
rustc.current_dir(current_dir).args(["--print", "sysroot"]);
tracing::debug!("Discovering sysroot by {:?}", rustc);
let stdout = utf8_stdout(&mut rustc)?;
@@ -398,12 +402,11 @@
fn discover_rust_lib_src_dir_or_add_component(
sysroot_path: &AbsPathBuf,
current_dir: &AbsPath,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
) -> Result<AbsPathBuf> {
discover_rust_lib_src_dir(sysroot_path)
.or_else(|| {
- let mut rustup = toolchain::command(Tool::Rustup.prefer_proxy(), current_dir);
- rustup.envs(extra_env);
+ let mut rustup = toolchain::command(Tool::Rustup.prefer_proxy(), current_dir, extra_env);
rustup.args(["component", "add", "rust-src"]);
tracing::info!("adding rust-src component by {:?}", rustup);
utf8_stdout(&mut rustup).ok()?;
diff --git a/crates/project-model/src/toolchain_info/rustc_cfg.rs b/crates/project-model/src/toolchain_info/rustc_cfg.rs
index e472da0..a77f767 100644
--- a/crates/project-model/src/toolchain_info/rustc_cfg.rs
+++ b/crates/project-model/src/toolchain_info/rustc_cfg.rs
@@ -11,7 +11,7 @@
pub fn get(
config: QueryConfig<'_>,
target: Option<&str>,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
) -> Vec<CfgAtom> {
let _p = tracing::info_span!("rustc_cfg::get").entered();
@@ -58,14 +58,13 @@
fn rustc_print_cfg(
target: Option<&str>,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
config: QueryConfig<'_>,
) -> anyhow::Result<String> {
const RUSTC_ARGS: [&str; 2] = ["--print", "cfg"];
let (sysroot, current_dir) = match config {
QueryConfig::Cargo(sysroot, cargo_toml) => {
- let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent());
- cmd.envs(extra_env);
+ let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env);
cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS);
if let Some(target) = target {
cmd.args(["--target", target]);
@@ -86,8 +85,7 @@
QueryConfig::Rustc(sysroot, current_dir) => (sysroot, current_dir),
};
- let mut cmd = sysroot.tool(Tool::Rustc, current_dir);
- cmd.envs(extra_env);
+ let mut cmd = sysroot.tool(Tool::Rustc, current_dir, extra_env);
cmd.args(RUSTC_ARGS);
cmd.arg("-O");
if let Some(target) = target {
diff --git a/crates/project-model/src/toolchain_info/target_data_layout.rs b/crates/project-model/src/toolchain_info/target_data_layout.rs
index 5d96c37..a4d0ec6 100644
--- a/crates/project-model/src/toolchain_info/target_data_layout.rs
+++ b/crates/project-model/src/toolchain_info/target_data_layout.rs
@@ -10,7 +10,7 @@
pub fn get(
config: QueryConfig<'_>,
target: Option<&str>,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
) -> anyhow::Result<String> {
const RUSTC_ARGS: [&str; 2] = ["--print", "target-spec-json"];
let process = |output: String| {
@@ -21,8 +21,7 @@
};
let (sysroot, current_dir) = match config {
QueryConfig::Cargo(sysroot, cargo_toml) => {
- let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent());
- cmd.envs(extra_env);
+ let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env);
cmd.env("RUSTC_BOOTSTRAP", "1");
cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS).args([
"--",
@@ -43,11 +42,8 @@
QueryConfig::Rustc(sysroot, current_dir) => (sysroot, current_dir),
};
- let mut cmd = Sysroot::tool(sysroot, Tool::Rustc, current_dir);
- cmd.envs(extra_env)
- .env("RUSTC_BOOTSTRAP", "1")
- .args(["-Z", "unstable-options"])
- .args(RUSTC_ARGS);
+ let mut cmd = Sysroot::tool(sysroot, Tool::Rustc, current_dir, extra_env);
+ cmd.env("RUSTC_BOOTSTRAP", "1").args(["-Z", "unstable-options"]).args(RUSTC_ARGS);
if let Some(target) = target {
cmd.args(["--target", target]);
}
diff --git a/crates/project-model/src/toolchain_info/target_tuple.rs b/crates/project-model/src/toolchain_info/target_tuple.rs
index 3917efb..f6ab853 100644
--- a/crates/project-model/src/toolchain_info/target_tuple.rs
+++ b/crates/project-model/src/toolchain_info/target_tuple.rs
@@ -12,7 +12,7 @@
pub fn get(
config: QueryConfig<'_>,
target: Option<&str>,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
) -> anyhow::Result<Vec<String>> {
let _p = tracing::info_span!("target_tuple::get").entered();
if let Some(target) = target {
@@ -32,12 +32,11 @@
}
fn rustc_discover_host_tuple(
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
sysroot: &Sysroot,
current_dir: &Path,
) -> anyhow::Result<String> {
- let mut cmd = sysroot.tool(Tool::Rustc, current_dir);
- cmd.envs(extra_env);
+ let mut cmd = sysroot.tool(Tool::Rustc, current_dir, extra_env);
cmd.arg("-vV");
let stdout = utf8_stdout(&mut cmd)
.with_context(|| format!("unable to discover host platform via `{cmd:?}`"))?;
@@ -53,11 +52,10 @@
fn cargo_config_build_target(
cargo_toml: &ManifestPath,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
sysroot: &Sysroot,
) -> Option<Vec<String>> {
- let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent());
- cmd.envs(extra_env);
+ let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env);
cmd.current_dir(cargo_toml.parent()).env("RUSTC_BOOTSTRAP", "1");
cmd.args(["-Z", "unstable-options", "config", "get", "build.target"]);
// if successful we receive `build.target = "target-tuple"`
diff --git a/crates/project-model/src/toolchain_info/version.rs b/crates/project-model/src/toolchain_info/version.rs
index e795fdf..91ba859 100644
--- a/crates/project-model/src/toolchain_info/version.rs
+++ b/crates/project-model/src/toolchain_info/version.rs
@@ -9,17 +9,16 @@
pub(crate) fn get(
config: QueryConfig<'_>,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
) -> Result<Option<Version>, anyhow::Error> {
let (mut cmd, prefix) = match config {
QueryConfig::Cargo(sysroot, cargo_toml) => {
- (sysroot.tool(Tool::Cargo, cargo_toml.parent()), "cargo ")
+ (sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env), "cargo ")
}
QueryConfig::Rustc(sysroot, current_dir) => {
- (sysroot.tool(Tool::Rustc, current_dir), "rustc ")
+ (sysroot.tool(Tool::Rustc, current_dir, extra_env), "rustc ")
}
};
- cmd.envs(extra_env);
cmd.arg("--version");
let out = utf8_stdout(&mut cmd).with_context(|| format!("Failed to query rust toolchain version via `{cmd:?}`, is your toolchain setup correctly?"))?;
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index c1e68af..c6e0cf3 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -856,7 +856,7 @@
pub fn to_crate_graph(
&self,
load: FileLoader<'_>,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
) -> (CrateGraphBuilder, ProcMacroPaths) {
let _p = tracing::info_span!("ProjectWorkspace::to_crate_graph").entered();
@@ -974,7 +974,7 @@
load: FileLoader<'_>,
project: &ProjectJson,
sysroot: &Sysroot,
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
override_cfg: &CfgOverrides,
set_test: bool,
is_sysroot: bool,
@@ -1804,7 +1804,7 @@
}
fn sysroot_metadata_config(
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
targets: &[String],
) -> CargoMetadataConfig {
CargoMetadataConfig {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index a9bde18..dd82794 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -602,7 +602,7 @@
cargo_extraArgs: Vec<String> = vec![],
/// Extra environment variables that will be set when running cargo, rustc
/// or other commands within the workspace. Useful for setting RUSTFLAGS.
- cargo_extraEnv: FxHashMap<String, String> = FxHashMap::default(),
+ cargo_extraEnv: FxHashMap<String, Option<String>> = FxHashMap::default(),
/// List of features to activate.
///
/// Set this to `"all"` to pass `--all-features` to cargo.
@@ -652,7 +652,7 @@
check_extraArgs | checkOnSave_extraArgs: Vec<String> = vec![],
/// Extra environment variables that will be set when running `cargo check`.
/// Extends `#rust-analyzer.cargo.extraEnv#`.
- check_extraEnv | checkOnSave_extraEnv: FxHashMap<String, String> = FxHashMap::default(),
+ check_extraEnv | checkOnSave_extraEnv: FxHashMap<String, Option<String>> = FxHashMap::default(),
/// List of features to activate. Defaults to
/// `#rust-analyzer.cargo.features#`.
///
@@ -921,10 +921,9 @@
tracing::info!("updating config from JSON: {:#}", json);
if !(json.is_null() || json.as_object().is_some_and(|it| it.is_empty())) {
- let mut json_errors = vec![];
let detached_files = get_field_json::<Vec<Utf8PathBuf>>(
&mut json,
- &mut json_errors,
+ &mut Vec::new(),
"detachedFiles",
None,
)
@@ -936,17 +935,19 @@
patch_old_style::patch_json_for_outdated_configs(&mut json);
let mut json_errors = vec![];
- let snips = get_field_json::<FxIndexMap<String, SnippetDef>>(
- &mut json,
- &mut json_errors,
- "completion_snippets_custom",
- None,
- )
- .unwrap_or(self.completion_snippets_custom().to_owned());
+
+ let input = FullConfigInput::from_json(json, &mut json_errors);
// IMPORTANT : This holds as long as ` completion_snippets_custom` is declared `client`.
config.snippets.clear();
+ let snips = input
+ .global
+ .completion_snippets_custom
+ .as_ref()
+ .unwrap_or(&self.default_config.global.completion_snippets_custom);
+ #[allow(dead_code)]
+ let _ = Self::completion_snippets_custom;
for (name, def) in snips.iter() {
if def.prefix.is_empty() && def.postfix.is_empty() {
continue;
@@ -973,8 +974,9 @@
)),
}
}
+
config.client_config = (
- FullConfigInput::from_json(json, &mut json_errors),
+ input,
ConfigErrors(
json_errors
.into_iter()
@@ -1882,7 +1884,10 @@
self.cargo_extraArgs(source_root)
}
- pub fn extra_env(&self, source_root: Option<SourceRootId>) -> &FxHashMap<String, String> {
+ pub fn extra_env(
+ &self,
+ source_root: Option<SourceRootId>,
+ ) -> &FxHashMap<String, Option<String>> {
self.cargo_extraEnv(source_root)
}
@@ -1892,7 +1897,10 @@
extra_args
}
- pub fn check_extra_env(&self, source_root: Option<SourceRootId>) -> FxHashMap<String, String> {
+ pub fn check_extra_env(
+ &self,
+ source_root: Option<SourceRootId>,
+ ) -> FxHashMap<String, Option<String>> {
let mut extra_env = self.cargo_extraEnv(source_root).clone();
extra_env.extend(self.check_extraEnv(source_root).clone());
extra_env
@@ -2728,10 +2736,6 @@
}
macro_rules! _default_val {
- (@verbatim: $s:literal, $ty:ty) => {{
- let default_: $ty = serde_json::from_str(&$s).unwrap();
- default_
- }};
($default:expr, $ty:ty) => {{
let default_: $ty = $default;
default_
@@ -2740,9 +2744,6 @@
use _default_val as default_val;
macro_rules! _default_str {
- (@verbatim: $s:literal, $_ty:ty) => {
- $s.to_owned()
- };
($default:expr, $ty:ty) => {{
let val = default_val!($default, $ty);
serde_json::to_string_pretty(&val).unwrap()
@@ -2883,7 +2884,7 @@
($(#[doc=$dox:literal])* $modname:ident: struct $name:ident <- $input:ident -> {
$(
$(#[doc=$doc:literal])*
- $vis:vis $field:ident $(| $alias:ident)*: $ty:ty = $(@$marker:ident: )? $default:expr,
+ $vis:vis $field:ident $(| $alias:ident)*: $ty:ty = $default:expr,
)*
}) => {
/// Default config values for this grouping.
@@ -2920,7 +2921,7 @@
impl Default for $name {
fn default() -> Self {
$name {$(
- $field: default_val!($(@$marker:)? $default, $ty),
+ $field: default_val!($default, $ty),
)*}
}
}
@@ -2956,7 +2957,7 @@
$({
let field = stringify!($field);
let ty = stringify!($ty);
- let default = default_str!($(@$marker:)? $default, $ty);
+ let default = default_str!($default, $ty);
(field, ty, &[$($doc),*], default)
},)*
diff --git a/crates/rust-analyzer/src/discover.rs b/crates/rust-analyzer/src/discover.rs
index 09de309..6b87505 100644
--- a/crates/rust-analyzer/src/discover.rs
+++ b/crates/rust-analyzer/src/discover.rs
@@ -3,6 +3,7 @@
use std::{io, path::Path};
use crossbeam_channel::Sender;
+use ide_db::FxHashMap;
use paths::{AbsPathBuf, Utf8Path, Utf8PathBuf};
use project_model::ProjectJsonData;
use serde::{Deserialize, Serialize};
@@ -62,7 +63,8 @@
})
.collect();
- let mut cmd = toolchain::command(command, current_dir);
+ // TODO: are we sure the extra env should be empty?
+ let mut cmd = toolchain::command(command, current_dir, &FxHashMap::default());
cmd.args(args);
Ok(DiscoverHandle {
diff --git a/crates/rust-analyzer/src/flycheck.rs b/crates/rust-analyzer/src/flycheck.rs
index 126d065..2778b31 100644
--- a/crates/rust-analyzer/src/flycheck.rs
+++ b/crates/rust-analyzer/src/flycheck.rs
@@ -35,7 +35,7 @@
pub(crate) features: Vec<String>,
pub(crate) extra_args: Vec<String>,
pub(crate) extra_test_bin_args: Vec<String>,
- pub(crate) extra_env: FxHashMap<String, String>,
+ pub(crate) extra_env: FxHashMap<String, Option<String>>,
pub(crate) target_dir: Option<Utf8PathBuf>,
}
@@ -69,7 +69,6 @@
if let Some(target_dir) = &self.target_dir {
cmd.arg("--target-dir").arg(target_dir);
}
- cmd.envs(&self.extra_env);
}
}
@@ -83,7 +82,7 @@
CustomCommand {
command: String,
args: Vec<String>,
- extra_env: FxHashMap<String, String>,
+ extra_env: FxHashMap<String, Option<String>>,
invocation_strategy: InvocationStrategy,
},
}
@@ -468,7 +467,8 @@
) -> Option<Command> {
match &self.config {
FlycheckConfig::CargoCommand { command, options, ansi_color_output } => {
- let mut cmd = toolchain::command(Tool::Cargo.path(), &*self.root);
+ let mut cmd =
+ toolchain::command(Tool::Cargo.path(), &*self.root, &options.extra_env);
if let Some(sysroot_root) = &self.sysroot_root {
cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(sysroot_root));
}
@@ -516,8 +516,7 @@
&*self.root
}
};
- let mut cmd = toolchain::command(command, root);
- cmd.envs(extra_env);
+ let mut cmd = toolchain::command(command, root, extra_env);
// If the custom command has a $saved_file placeholder, and
// we're saving a file, replace the placeholder in the arguments.
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index dd41991..e08dd80 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -2315,8 +2315,11 @@
let mut command = match snap.config.rustfmt(source_root_id) {
RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
// FIXME: Set RUSTUP_TOOLCHAIN
- let mut cmd = toolchain::command(toolchain::Tool::Rustfmt.path(), current_dir);
- cmd.envs(snap.config.extra_env(source_root_id));
+ let mut cmd = toolchain::command(
+ toolchain::Tool::Rustfmt.path(),
+ current_dir,
+ snap.config.extra_env(source_root_id),
+ );
cmd.args(extra_args);
if let Some(edition) = edition {
@@ -2358,6 +2361,7 @@
RustfmtConfig::CustomCommand { command, args } => {
let cmd = Utf8PathBuf::from(&command);
let target_spec = TargetSpec::for_file(snap, file_id)?;
+ let extra_env = snap.config.extra_env(source_root_id);
let mut cmd = match target_spec {
Some(TargetSpec::Cargo(_)) => {
// approach: if the command name contains a path separator, join it with the project root.
@@ -2370,12 +2374,11 @@
} else {
cmd
};
- toolchain::command(cmd_path, current_dir)
+ toolchain::command(cmd_path, current_dir, extra_env)
}
- _ => toolchain::command(cmd, current_dir),
+ _ => toolchain::command(cmd, current_dir, extra_env),
};
- cmd.envs(snap.config.extra_env(source_root_id));
cmd.args(args);
cmd
}
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 5702042..55ed192 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -652,12 +652,14 @@
| ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, ..)), .. } => cargo
.env()
.into_iter()
- .chain(self.config.extra_env(None))
- .map(|(a, b)| (a.clone(), b.clone()))
+ .map(|(k, v)| (k.clone(), Some(v.clone())))
+ .chain(
+ self.config.extra_env(None).iter().map(|(k, v)| (k.clone(), v.clone())),
+ )
.chain(
ws.sysroot
.root()
- .map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), it.to_string())),
+ .map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), Some(it.to_string()))),
)
.collect(),
@@ -893,7 +895,7 @@
// FIXME: Move this into load-cargo?
pub fn ws_to_crate_graph(
workspaces: &[ProjectWorkspace],
- extra_env: &FxHashMap<String, String>,
+ extra_env: &FxHashMap<String, Option<String>>,
mut load: impl FnMut(&AbsPath) -> Option<vfs::FileId>,
) -> (CrateGraphBuilder, Vec<ProcMacroPaths>) {
let mut crate_graph = CrateGraphBuilder::default();
diff --git a/crates/rust-analyzer/src/test_runner.rs b/crates/rust-analyzer/src/test_runner.rs
index f245c6a..9c0bc33 100644
--- a/crates/rust-analyzer/src/test_runner.rs
+++ b/crates/rust-analyzer/src/test_runner.rs
@@ -101,7 +101,7 @@
test_target: TestTarget,
sender: Sender<CargoTestMessage>,
) -> std::io::Result<Self> {
- let mut cmd = toolchain::command(Tool::Cargo.path(), root);
+ let mut cmd = toolchain::command(Tool::Cargo.path(), root, &options.extra_env);
cmd.env("RUSTC_BOOTSTRAP", "1");
cmd.arg("test");
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index 673334b..a0ae0d6 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -287,8 +287,9 @@
Const =
Attr* Visibility?
'default'?
- 'const' (Name | '_') ':' Type
- ('=' body:Expr)? ';'
+ 'const' (Name | '_') GenericParamList? ':' Type
+ ('=' body:Expr)?
+ WhereClause? ';'
Static =
Attr* Visibility?
@@ -348,7 +349,7 @@
| LetStmt
LetStmt =
- Attr* 'let' Pat (':' Type)?
+ Attr* 'super'? 'let' Pat (':' Type)?
'=' initializer:Expr
LetElse?
';'
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index fd23cdc..1243f64 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -405,6 +405,7 @@
}
impl ast::HasAttrs for Const {}
impl ast::HasDocComments for Const {}
+impl ast::HasGenericParams for Const {}
impl ast::HasName for Const {}
impl ast::HasVisibility for Const {}
impl Const {
@@ -823,6 +824,8 @@
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
#[inline]
pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
+ #[inline]
+ pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) }
}
pub struct Lifetime {
pub(crate) syntax: SyntaxNode,
@@ -9421,7 +9424,7 @@
impl AstNode for AnyHasGenericParams {
#[inline]
fn can_cast(kind: SyntaxKind) -> bool {
- matches!(kind, ENUM | FN | IMPL | STRUCT | TRAIT | TRAIT_ALIAS | TYPE_ALIAS | UNION)
+ matches!(kind, CONST | ENUM | FN | IMPL | STRUCT | TRAIT | TRAIT_ALIAS | TYPE_ALIAS | UNION)
}
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -9445,6 +9448,10 @@
f.debug_struct("AnyHasGenericParams").field("syntax", &self.syntax).finish()
}
}
+impl From<Const> for AnyHasGenericParams {
+ #[inline]
+ fn from(node: Const) -> AnyHasGenericParams { AnyHasGenericParams { syntax: node.syntax } }
+}
impl From<Enum> for AnyHasGenericParams {
#[inline]
fn from(node: Enum) -> AnyHasGenericParams { AnyHasGenericParams { syntax: node.syntax } }
diff --git a/crates/toolchain/src/lib.rs b/crates/toolchain/src/lib.rs
index e3b30ff..8b7bf1a 100644
--- a/crates/toolchain/src/lib.rs
+++ b/crates/toolchain/src/lib.rs
@@ -71,11 +71,22 @@
}
}
-pub fn command(cmd: impl AsRef<OsStr>, working_directory: impl AsRef<Path>) -> Command {
+#[allow(clippy::disallowed_types)] /* generic parameter allows for FxHashMap */
+pub fn command<H>(
+ cmd: impl AsRef<OsStr>,
+ working_directory: impl AsRef<Path>,
+ extra_env: &std::collections::HashMap<String, Option<String>, H>,
+) -> Command {
// we are `toolchain::command``
#[allow(clippy::disallowed_methods)]
let mut cmd = Command::new(cmd);
cmd.current_dir(working_directory);
+ for env in extra_env {
+ match env {
+ (key, Some(val)) => cmd.env(key, val),
+ (key, None) => cmd.env_remove(key),
+ };
+ }
cmd
}
diff --git a/editors/code/package.json b/editors/code/package.json
index b05be45..a282eea 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -543,7 +543,8 @@
"additionalProperties": {
"type": [
"string",
- "number"
+ "number",
+ "null"
]
},
"default": null,
diff --git a/editors/code/src/bootstrap.ts b/editors/code/src/bootstrap.ts
index c63c6f2..bddf195 100644
--- a/editors/code/src/bootstrap.ts
+++ b/editors/code/src/bootstrap.ts
@@ -187,8 +187,16 @@
export async function isValidExecutable(path: string, extraEnv: Env): Promise<boolean> {
log.debug("Checking availability of a binary at", path);
+ const newEnv = { ...process.env };
+ for (const [k, v] of Object.entries(extraEnv)) {
+ if (v) {
+ newEnv[k] = v;
+ } else if (k in newEnv) {
+ delete newEnv[k];
+ }
+ }
const res = await spawnAsync(path, ["--version"], {
- env: { ...process.env, ...extraEnv },
+ env: newEnv,
});
if (res.error) {
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index ba1c3b0..f36e18a 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -213,12 +213,13 @@
get serverExtraEnv(): Env {
const extraEnv =
- this.get<{ [key: string]: string | number } | null>("server.extraEnv") ?? {};
+ this.get<{ [key: string]: { toString(): string } | null } | null>("server.extraEnv") ??
+ {};
return substituteVariablesInEnv(
Object.fromEntries(
Object.entries(extraEnv).map(([k, v]) => [
k,
- typeof v !== "string" ? v.toString() : v,
+ typeof v === "string" ? v : v?.toString(),
]),
),
);
@@ -398,6 +399,7 @@
// FIXME: Merge this with `substituteVSCodeVariables` above
export function substituteVariablesInEnv(env: Env): Env {
+ const depRe = new RegExp(/\${(?<depName>.+?)}/g);
const missingDeps = new Set<string>();
// vscode uses `env:ENV_NAME` for env vars resolution, and it's easier
// to follow the same convention for our dependency tracking
@@ -405,15 +407,16 @@
const envWithDeps = Object.fromEntries(
Object.entries(env).map(([key, value]) => {
const deps = new Set<string>();
- const depRe = new RegExp(/\${(?<depName>.+?)}/g);
- let match = undefined;
- while ((match = depRe.exec(value))) {
- const depName = unwrapUndefinable(match.groups?.["depName"]);
- deps.add(depName);
- // `depName` at this point can have a form of `expression` or
- // `prefix:expression`
- if (!definedEnvKeys.has(depName)) {
- missingDeps.add(depName);
+ if (value) {
+ let match = undefined;
+ while ((match = depRe.exec(value))) {
+ const depName = unwrapUndefinable(match.groups?.["depName"]);
+ deps.add(depName);
+ // `depName` at this point can have a form of `expression` or
+ // `prefix:expression`
+ if (!definedEnvKeys.has(depName)) {
+ missingDeps.add(depName);
+ }
}
}
return [`env:${key}`, { deps: [...deps], value }];
@@ -454,11 +457,10 @@
do {
leftToResolveSize = toResolve.size;
for (const key of toResolve) {
- const item = unwrapUndefinable(envWithDeps[key]);
- if (item.deps.every((dep) => resolved.has(dep))) {
- item.value = item.value.replace(/\${(?<depName>.+?)}/g, (_wholeMatch, depName) => {
- const item = unwrapUndefinable(envWithDeps[depName]);
- return item.value;
+ const item = envWithDeps[key];
+ if (item && item.deps.every((dep) => resolved.has(dep))) {
+ item.value = item.value?.replace(/\${(?<depName>.+?)}/g, (_wholeMatch, depName) => {
+ return envWithDeps[depName]?.value ?? "";
});
resolved.add(key);
toResolve.delete(key);
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index 1149523..e55754f 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -213,7 +213,14 @@
this.refreshServerStatus();
},
);
- const newEnv = Object.assign({}, process.env, this.config.serverExtraEnv);
+ const newEnv = { ...process.env };
+ for (const [k, v] of Object.entries(this.config.serverExtraEnv)) {
+ if (v) {
+ newEnv[k] = v;
+ } else if (k in newEnv) {
+ delete newEnv[k];
+ }
+ }
const run: lc.Executable = {
command: this._serverPath,
options: { env: newEnv },
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index 83b8abe..410b055 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -14,7 +14,7 @@
}
export type Env = {
- [name: string]: string;
+ [name: string]: string | undefined;
};
class Log {