mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 05:38:46 +00:00
4555: VSCode: added patchelf after download for NixOS support r=matklad a=cab404 This adds Nix support, and fixes #4542 4575: Use Chalk's built-in representations for fn items and pointers r=matklad a=flodiebold The `TypeName::FnDef` was just added; the function pointer variant has existed for a while, I just forgot about it because it's special (because fn pointers can be higher-ranked over lifetimes). We *could* also make `FnPtr` a separate `Ty` variant instead of a `TypeCtor` variant, which would make the conversion code a bit less special-casey, but it doesn't seem worth doing right now. Co-authored-by: Vladimir Serov <me@cab404.ru> Co-authored-by: Cabia Rangris <me@cab404.ru> Co-authored-by: Florian Diebold <florian.diebold@freiheit.com>
This commit is contained in:
commit
4cc2ff6e39
8 changed files with 227 additions and 19 deletions
|
@ -76,6 +76,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
||||||
#[salsa::interned]
|
#[salsa::interned]
|
||||||
fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId;
|
fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId;
|
||||||
#[salsa::interned]
|
#[salsa::interned]
|
||||||
|
fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId;
|
||||||
|
#[salsa::interned]
|
||||||
fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
|
fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
|
||||||
#[salsa::interned]
|
#[salsa::interned]
|
||||||
fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId;
|
fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId;
|
||||||
|
@ -94,6 +96,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
||||||
#[salsa::invoke(crate::traits::chalk::impl_datum_query)]
|
#[salsa::invoke(crate::traits::chalk::impl_datum_query)]
|
||||||
fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>;
|
fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>;
|
||||||
|
|
||||||
|
#[salsa::invoke(crate::traits::chalk::fn_def_datum_query)]
|
||||||
|
fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>;
|
||||||
|
|
||||||
#[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
|
#[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
|
||||||
fn associated_ty_value(
|
fn associated_ty_value(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -159,6 +159,12 @@ pub enum TypeCtor {
|
||||||
pub struct TypeCtorId(salsa::InternId);
|
pub struct TypeCtorId(salsa::InternId);
|
||||||
impl_intern_key!(TypeCtorId);
|
impl_intern_key!(TypeCtorId);
|
||||||
|
|
||||||
|
/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
|
||||||
|
/// we have different IDs for struct and enum variant constructors.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||||
|
pub struct CallableDefId(salsa::InternId);
|
||||||
|
impl_intern_key!(CallableDefId);
|
||||||
|
|
||||||
impl TypeCtor {
|
impl TypeCtor {
|
||||||
pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize {
|
pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -2643,6 +2643,80 @@ fn test() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builtin_fn_def_copy() {
|
||||||
|
assert_snapshot!(
|
||||||
|
infer_with_mismatches(r#"
|
||||||
|
#[lang = "copy"]
|
||||||
|
trait Copy {}
|
||||||
|
|
||||||
|
fn foo() {}
|
||||||
|
fn bar<T: Copy>(T) -> T {}
|
||||||
|
struct Struct(usize);
|
||||||
|
enum Enum { Variant(usize) }
|
||||||
|
|
||||||
|
trait Test { fn test(&self) -> bool; }
|
||||||
|
impl<T: Copy> Test for T {}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
foo.test();
|
||||||
|
bar.test();
|
||||||
|
Struct.test();
|
||||||
|
Enum::Variant.test();
|
||||||
|
}
|
||||||
|
"#, true),
|
||||||
|
// wrong result, because the built-in Copy impl for fn defs doesn't exist in Chalk yet
|
||||||
|
@r###"
|
||||||
|
42..44 '{}': ()
|
||||||
|
61..62 'T': {unknown}
|
||||||
|
69..71 '{}': ()
|
||||||
|
69..71: expected T, got ()
|
||||||
|
146..150 'self': &Self
|
||||||
|
202..282 '{ ...t(); }': ()
|
||||||
|
208..211 'foo': fn foo()
|
||||||
|
208..218 'foo.test()': {unknown}
|
||||||
|
224..227 'bar': fn bar<{unknown}>({unknown}) -> {unknown}
|
||||||
|
224..234 'bar.test()': {unknown}
|
||||||
|
240..246 'Struct': Struct(usize) -> Struct
|
||||||
|
240..253 'Struct.test()': {unknown}
|
||||||
|
259..272 'Enum::Variant': Variant(usize) -> Enum
|
||||||
|
259..279 'Enum::...test()': {unknown}
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builtin_fn_ptr_copy() {
|
||||||
|
assert_snapshot!(
|
||||||
|
infer_with_mismatches(r#"
|
||||||
|
#[lang = "copy"]
|
||||||
|
trait Copy {}
|
||||||
|
|
||||||
|
trait Test { fn test(&self) -> bool; }
|
||||||
|
impl<T: Copy> Test for T {}
|
||||||
|
|
||||||
|
fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
|
||||||
|
f1.test();
|
||||||
|
f2.test();
|
||||||
|
f3.test();
|
||||||
|
}
|
||||||
|
"#, true),
|
||||||
|
@r###"
|
||||||
|
55..59 'self': &Self
|
||||||
|
109..111 'f1': fn()
|
||||||
|
119..121 'f2': fn(usize) -> u8
|
||||||
|
140..142 'f3': fn(u8, u8) -> &u8
|
||||||
|
163..211 '{ ...t(); }': ()
|
||||||
|
169..171 'f1': fn()
|
||||||
|
169..178 'f1.test()': bool
|
||||||
|
184..186 'f2': fn(usize) -> u8
|
||||||
|
184..193 'f2.test()': bool
|
||||||
|
199..201 'f3': fn(u8, u8) -> &u8
|
||||||
|
199..208 'f3.test()': bool
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builtin_sized() {
|
fn builtin_sized() {
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
|
|
|
@ -14,7 +14,7 @@ use ra_db::{salsa::InternKey, CrateId};
|
||||||
use super::{builtin, AssocTyValue, ChalkContext, Impl};
|
use super::{builtin, AssocTyValue, ChalkContext, Impl};
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
|
db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
|
||||||
DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor,
|
CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor,
|
||||||
};
|
};
|
||||||
use chalk_rust_ir::WellKnownTrait;
|
use chalk_rust_ir::WellKnownTrait;
|
||||||
use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders};
|
use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders};
|
||||||
|
@ -54,10 +54,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
||||||
|
|
||||||
fn fn_def_datum(
|
fn fn_def_datum(
|
||||||
&self,
|
&self,
|
||||||
_fn_def_id: chalk_ir::FnDefId<Interner>,
|
fn_def_id: chalk_ir::FnDefId<Interner>,
|
||||||
) -> Arc<chalk_rust_ir::FnDefDatum<Interner>> {
|
) -> Arc<chalk_rust_ir::FnDefDatum<Interner>> {
|
||||||
// We don't yet provide any FnDefs to Chalk
|
self.db.fn_def_datum(self.krate, fn_def_id)
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impls_for_trait(
|
fn impls_for_trait(
|
||||||
|
@ -405,6 +404,26 @@ fn type_alias_associated_ty_value(
|
||||||
Arc::new(value)
|
Arc::new(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn fn_def_datum_query(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
_krate: CrateId,
|
||||||
|
fn_def_id: FnDefId,
|
||||||
|
) -> Arc<FnDefDatum> {
|
||||||
|
let callable_def: CallableDef = from_chalk(db, fn_def_id);
|
||||||
|
let generic_params = generics(db.upcast(), callable_def.into());
|
||||||
|
let sig = db.callable_item_signature(callable_def);
|
||||||
|
let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
|
||||||
|
let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
|
||||||
|
let bound = chalk_rust_ir::FnDefDatumBound {
|
||||||
|
// Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
|
||||||
|
argument_types: sig.value.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(),
|
||||||
|
return_type: sig.value.ret().clone().to_chalk(db),
|
||||||
|
where_clauses,
|
||||||
|
};
|
||||||
|
let datum = FnDefDatum { id: fn_def_id, binders: make_binders(bound, sig.num_binders) };
|
||||||
|
Arc::new(datum)
|
||||||
|
}
|
||||||
|
|
||||||
impl From<AdtId> for crate::TypeCtorId {
|
impl From<AdtId> for crate::TypeCtorId {
|
||||||
fn from(struct_id: AdtId) -> Self {
|
fn from(struct_id: AdtId) -> Self {
|
||||||
struct_id.0
|
struct_id.0
|
||||||
|
@ -417,6 +436,18 @@ impl From<crate::TypeCtorId> for AdtId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<FnDefId> for crate::CallableDefId {
|
||||||
|
fn from(fn_def_id: FnDefId) -> Self {
|
||||||
|
InternKey::from_intern_id(fn_def_id.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<crate::CallableDefId> for FnDefId {
|
||||||
|
fn from(callable_def_id: crate::CallableDefId) -> Self {
|
||||||
|
chalk_ir::FnDefId(callable_def_id.as_intern_id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ImplId> for crate::traits::GlobalImplId {
|
impl From<ImplId> for crate::traits::GlobalImplId {
|
||||||
fn from(impl_id: ImplId) -> Self {
|
fn from(impl_id: ImplId) -> Self {
|
||||||
InternKey::from_intern_id(impl_id.0)
|
InternKey::from_intern_id(impl_id.0)
|
||||||
|
|
|
@ -20,6 +20,8 @@ pub type ImplId = chalk_ir::ImplId<Interner>;
|
||||||
pub type ImplDatum = chalk_rust_ir::ImplDatum<Interner>;
|
pub type ImplDatum = chalk_rust_ir::ImplDatum<Interner>;
|
||||||
pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId<Interner>;
|
pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId<Interner>;
|
||||||
pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<Interner>;
|
pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<Interner>;
|
||||||
|
pub type FnDefId = chalk_ir::FnDefId<Interner>;
|
||||||
|
pub type FnDefDatum = chalk_rust_ir::FnDefDatum<Interner>;
|
||||||
|
|
||||||
impl chalk_ir::interner::Interner for Interner {
|
impl chalk_ir::interner::Interner for Interner {
|
||||||
type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc?
|
type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc?
|
||||||
|
|
|
@ -15,8 +15,8 @@ use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
|
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
|
||||||
traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
|
traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
|
||||||
ApplicationTy, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, Substs,
|
ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy,
|
||||||
TraitEnvironment, TraitRef, Ty, TypeCtor,
|
Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::interner::*;
|
use super::interner::*;
|
||||||
|
@ -26,14 +26,19 @@ impl ToChalk for Ty {
|
||||||
type Chalk = chalk_ir::Ty<Interner>;
|
type Chalk = chalk_ir::Ty<Interner>;
|
||||||
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
|
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
|
||||||
match self {
|
match self {
|
||||||
Ty::Apply(apply_ty) => {
|
Ty::Apply(apply_ty) => match apply_ty.ctor {
|
||||||
if let TypeCtor::Ref(m) = apply_ty.ctor {
|
TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
|
||||||
return ref_to_chalk(db, m, apply_ty.parameters);
|
TypeCtor::FnPtr { num_args: _ } => {
|
||||||
|
let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner);
|
||||||
|
chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution })
|
||||||
|
.intern(&Interner)
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
let name = apply_ty.ctor.to_chalk(db);
|
let name = apply_ty.ctor.to_chalk(db);
|
||||||
let substitution = apply_ty.parameters.to_chalk(db);
|
let substitution = apply_ty.parameters.to_chalk(db);
|
||||||
chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
|
chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
Ty::Projection(proj_ty) => {
|
Ty::Projection(proj_ty) => {
|
||||||
let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
|
let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
|
||||||
let substitution = proj_ty.parameters.to_chalk(db);
|
let substitution = proj_ty.parameters.to_chalk(db);
|
||||||
|
@ -93,7 +98,13 @@ impl ToChalk for Ty {
|
||||||
Ty::Projection(ProjectionTy { associated_ty, parameters })
|
Ty::Projection(ProjectionTy { associated_ty, parameters })
|
||||||
}
|
}
|
||||||
chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(),
|
chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(),
|
||||||
chalk_ir::TyData::Function(_) => unimplemented!(),
|
chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => {
|
||||||
|
let parameters: Substs = from_chalk(db, substitution);
|
||||||
|
Ty::Apply(ApplicationTy {
|
||||||
|
ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 },
|
||||||
|
parameters,
|
||||||
|
})
|
||||||
|
}
|
||||||
chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx),
|
chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx),
|
||||||
chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
|
chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
|
||||||
chalk_ir::TyData::Dyn(where_clauses) => {
|
chalk_ir::TyData::Dyn(where_clauses) => {
|
||||||
|
@ -217,11 +228,14 @@ impl ToChalk for TypeCtor {
|
||||||
TypeCtor::Slice => TypeName::Slice,
|
TypeCtor::Slice => TypeName::Slice,
|
||||||
TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)),
|
TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)),
|
||||||
TypeCtor::Str => TypeName::Str,
|
TypeCtor::Str => TypeName::Str,
|
||||||
|
TypeCtor::FnDef(callable_def) => {
|
||||||
|
let id = callable_def.to_chalk(db);
|
||||||
|
TypeName::FnDef(id)
|
||||||
|
}
|
||||||
TypeCtor::Int(Uncertain::Unknown)
|
TypeCtor::Int(Uncertain::Unknown)
|
||||||
| TypeCtor::Float(Uncertain::Unknown)
|
| TypeCtor::Float(Uncertain::Unknown)
|
||||||
| TypeCtor::Adt(_)
|
| TypeCtor::Adt(_)
|
||||||
| TypeCtor::Array
|
| TypeCtor::Array
|
||||||
| TypeCtor::FnDef(_)
|
|
||||||
| TypeCtor::FnPtr { .. }
|
| TypeCtor::FnPtr { .. }
|
||||||
| TypeCtor::Never
|
| TypeCtor::Never
|
||||||
| TypeCtor::Closure { .. } => {
|
| TypeCtor::Closure { .. } => {
|
||||||
|
@ -260,7 +274,10 @@ impl ToChalk for TypeCtor {
|
||||||
TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)),
|
TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)),
|
||||||
TypeName::Str => TypeCtor::Str,
|
TypeName::Str => TypeCtor::Str,
|
||||||
|
|
||||||
TypeName::FnDef(_) => unreachable!(),
|
TypeName::FnDef(fn_def_id) => {
|
||||||
|
let callable_def = from_chalk(db, fn_def_id);
|
||||||
|
TypeCtor::FnDef(callable_def)
|
||||||
|
}
|
||||||
|
|
||||||
TypeName::Error => {
|
TypeName::Error => {
|
||||||
// this should not be reached, since we don't represent TypeName::Error with TypeCtor
|
// this should not be reached, since we don't represent TypeName::Error with TypeCtor
|
||||||
|
@ -347,6 +364,18 @@ impl ToChalk for Impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToChalk for CallableDef {
|
||||||
|
type Chalk = FnDefId;
|
||||||
|
|
||||||
|
fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
|
||||||
|
db.intern_callable_def(self).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDef {
|
||||||
|
db.lookup_intern_callable_def(fn_def_id.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToChalk for TypeAliasId {
|
impl ToChalk for TypeAliasId {
|
||||||
type Chalk = AssocTypeId;
|
type Chalk = AssocTypeId;
|
||||||
|
|
||||||
|
|
|
@ -247,10 +247,24 @@ impl DebugContext<'_> {
|
||||||
|
|
||||||
pub fn debug_fn_def_id(
|
pub fn debug_fn_def_id(
|
||||||
&self,
|
&self,
|
||||||
_fn_def_id: chalk_ir::FnDefId<Interner>,
|
fn_def_id: chalk_ir::FnDefId<Interner>,
|
||||||
fmt: &mut fmt::Formatter<'_>,
|
fmt: &mut fmt::Formatter<'_>,
|
||||||
) -> Result<(), fmt::Error> {
|
) -> Result<(), fmt::Error> {
|
||||||
write!(fmt, "fn")
|
let def: CallableDef = from_chalk(self.0, fn_def_id);
|
||||||
|
let name = match def {
|
||||||
|
CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(),
|
||||||
|
CallableDef::StructId(s) => self.0.struct_data(s).name.clone(),
|
||||||
|
CallableDef::EnumVariantId(e) => {
|
||||||
|
let enum_data = self.0.enum_data(e.parent);
|
||||||
|
enum_data.variants[e.local_id].name.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match def {
|
||||||
|
CallableDef::FunctionId(_) => write!(fmt, "{{fn {}}}", name),
|
||||||
|
CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {
|
||||||
|
write!(fmt, "{{ctor {}}}", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_const(
|
pub fn debug_const(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
import { promises as fs } from "fs";
|
import { promises as fs, PathLike } from "fs";
|
||||||
|
|
||||||
import * as commands from './commands';
|
import * as commands from './commands';
|
||||||
import { activateInlayHints } from './inlay_hints';
|
import { activateInlayHints } from './inlay_hints';
|
||||||
|
@ -12,6 +12,7 @@ import { log, assert, isValidExecutable } from './util';
|
||||||
import { PersistentState } from './persistent_state';
|
import { PersistentState } from './persistent_state';
|
||||||
import { fetchRelease, download } from './net';
|
import { fetchRelease, download } from './net';
|
||||||
import { activateTaskProvider } from './tasks';
|
import { activateTaskProvider } from './tasks';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
|
||||||
let ctx: Ctx | undefined;
|
let ctx: Ctx | undefined;
|
||||||
|
|
||||||
|
@ -188,6 +189,46 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise<
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function patchelf(dest: PathLike): Promise<void> {
|
||||||
|
await vscode.window.withProgress(
|
||||||
|
{
|
||||||
|
location: vscode.ProgressLocation.Notification,
|
||||||
|
title: "Patching rust-analyzer for NixOS"
|
||||||
|
},
|
||||||
|
async (progress, _) => {
|
||||||
|
const expression = `
|
||||||
|
{src, pkgs ? import <nixpkgs> {}}:
|
||||||
|
pkgs.stdenv.mkDerivation {
|
||||||
|
name = "rust-analyzer";
|
||||||
|
inherit src;
|
||||||
|
phases = [ "installPhase" "fixupPhase" ];
|
||||||
|
installPhase = "cp $src $out";
|
||||||
|
fixupPhase = ''
|
||||||
|
chmod 755 $out
|
||||||
|
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
const origFile = dest + "-orig";
|
||||||
|
await fs.rename(dest, origFile);
|
||||||
|
progress.report({ message: "Patching executable", increment: 20 });
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
const handle = exec(`nix-build -E - --arg src '${origFile}' -o ${dest}`,
|
||||||
|
(err, stdout, stderr) => {
|
||||||
|
if (err != null) {
|
||||||
|
reject(Error(stderr));
|
||||||
|
} else {
|
||||||
|
resolve(stdout);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
handle.stdin?.write(expression);
|
||||||
|
handle.stdin?.end();
|
||||||
|
});
|
||||||
|
await fs.unlink(origFile);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async function getServer(config: Config, state: PersistentState): Promise<string | undefined> {
|
async function getServer(config: Config, state: PersistentState): Promise<string | undefined> {
|
||||||
const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath;
|
const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath;
|
||||||
if (explicitPath) {
|
if (explicitPath) {
|
||||||
|
@ -237,6 +278,12 @@ async function getServer(config: Config, state: PersistentState): Promise<string
|
||||||
assert(!!artifact, `Bad release: ${JSON.stringify(release)}`);
|
assert(!!artifact, `Bad release: ${JSON.stringify(release)}`);
|
||||||
|
|
||||||
await download(artifact.browser_download_url, dest, "Downloading rust-analyzer server", { mode: 0o755 });
|
await download(artifact.browser_download_url, dest, "Downloading rust-analyzer server", { mode: 0o755 });
|
||||||
|
|
||||||
|
// Patching executable if that's NixOS.
|
||||||
|
if (await fs.stat("/etc/nixos").then(_ => true).catch(_ => false)) {
|
||||||
|
await patchelf(dest);
|
||||||
|
}
|
||||||
|
|
||||||
await state.updateServerVersion(config.package.version);
|
await state.updateServerVersion(config.package.version);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue