Skip to content

Commit 4cc2ff6

Browse files
bors[bot]cab404flodiebold
authored
Merge #4555 #4575
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 <[email protected]> Co-authored-by: Cabia Rangris <[email protected]> Co-authored-by: Florian Diebold <[email protected]>
3 parents ca5e459 + b4ef1af + 194dd9e commit 4cc2ff6

File tree

8 files changed

+227
-19
lines changed

8 files changed

+227
-19
lines changed

crates/ra_hir_ty/src/db.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
7676
#[salsa::interned]
7777
fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId;
7878
#[salsa::interned]
79+
fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId;
80+
#[salsa::interned]
7981
fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
8082
#[salsa::interned]
8183
fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId;
@@ -94,6 +96,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
9496
#[salsa::invoke(crate::traits::chalk::impl_datum_query)]
9597
fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>;
9698

99+
#[salsa::invoke(crate::traits::chalk::fn_def_datum_query)]
100+
fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>;
101+
97102
#[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
98103
fn associated_ty_value(
99104
&self,

crates/ra_hir_ty/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ pub enum TypeCtor {
159159
pub struct TypeCtorId(salsa::InternId);
160160
impl_intern_key!(TypeCtorId);
161161

162+
/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
163+
/// we have different IDs for struct and enum variant constructors.
164+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
165+
pub struct CallableDefId(salsa::InternId);
166+
impl_intern_key!(CallableDefId);
167+
162168
impl TypeCtor {
163169
pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize {
164170
match self {

crates/ra_hir_ty/src/tests/traits.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2643,6 +2643,80 @@ fn test() {
26432643
);
26442644
}
26452645

2646+
#[test]
2647+
fn builtin_fn_def_copy() {
2648+
assert_snapshot!(
2649+
infer_with_mismatches(r#"
2650+
#[lang = "copy"]
2651+
trait Copy {}
2652+
2653+
fn foo() {}
2654+
fn bar<T: Copy>(T) -> T {}
2655+
struct Struct(usize);
2656+
enum Enum { Variant(usize) }
2657+
2658+
trait Test { fn test(&self) -> bool; }
2659+
impl<T: Copy> Test for T {}
2660+
2661+
fn test() {
2662+
foo.test();
2663+
bar.test();
2664+
Struct.test();
2665+
Enum::Variant.test();
2666+
}
2667+
"#, true),
2668+
// wrong result, because the built-in Copy impl for fn defs doesn't exist in Chalk yet
2669+
@r###"
2670+
42..44 '{}': ()
2671+
61..62 'T': {unknown}
2672+
69..71 '{}': ()
2673+
69..71: expected T, got ()
2674+
146..150 'self': &Self
2675+
202..282 '{ ...t(); }': ()
2676+
208..211 'foo': fn foo()
2677+
208..218 'foo.test()': {unknown}
2678+
224..227 'bar': fn bar<{unknown}>({unknown}) -> {unknown}
2679+
224..234 'bar.test()': {unknown}
2680+
240..246 'Struct': Struct(usize) -> Struct
2681+
240..253 'Struct.test()': {unknown}
2682+
259..272 'Enum::Variant': Variant(usize) -> Enum
2683+
259..279 'Enum::...test()': {unknown}
2684+
"###
2685+
);
2686+
}
2687+
2688+
#[test]
2689+
fn builtin_fn_ptr_copy() {
2690+
assert_snapshot!(
2691+
infer_with_mismatches(r#"
2692+
#[lang = "copy"]
2693+
trait Copy {}
2694+
2695+
trait Test { fn test(&self) -> bool; }
2696+
impl<T: Copy> Test for T {}
2697+
2698+
fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
2699+
f1.test();
2700+
f2.test();
2701+
f3.test();
2702+
}
2703+
"#, true),
2704+
@r###"
2705+
55..59 'self': &Self
2706+
109..111 'f1': fn()
2707+
119..121 'f2': fn(usize) -> u8
2708+
140..142 'f3': fn(u8, u8) -> &u8
2709+
163..211 '{ ...t(); }': ()
2710+
169..171 'f1': fn()
2711+
169..178 'f1.test()': bool
2712+
184..186 'f2': fn(usize) -> u8
2713+
184..193 'f2.test()': bool
2714+
199..201 'f3': fn(u8, u8) -> &u8
2715+
199..208 'f3.test()': bool
2716+
"###
2717+
);
2718+
}
2719+
26462720
#[test]
26472721
fn builtin_sized() {
26482722
assert_snapshot!(

crates/ra_hir_ty/src/traits/chalk.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use ra_db::{salsa::InternKey, CrateId};
1414
use super::{builtin, AssocTyValue, ChalkContext, Impl};
1515
use crate::{
1616
db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
17-
DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor,
17+
CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor,
1818
};
1919
use chalk_rust_ir::WellKnownTrait;
2020
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> {
5454

5555
fn fn_def_datum(
5656
&self,
57-
_fn_def_id: chalk_ir::FnDefId<Interner>,
57+
fn_def_id: chalk_ir::FnDefId<Interner>,
5858
) -> Arc<chalk_rust_ir::FnDefDatum<Interner>> {
59-
// We don't yet provide any FnDefs to Chalk
60-
unimplemented!()
59+
self.db.fn_def_datum(self.krate, fn_def_id)
6160
}
6261

6362
fn impls_for_trait(
@@ -405,6 +404,26 @@ fn type_alias_associated_ty_value(
405404
Arc::new(value)
406405
}
407406

407+
pub(crate) fn fn_def_datum_query(
408+
db: &dyn HirDatabase,
409+
_krate: CrateId,
410+
fn_def_id: FnDefId,
411+
) -> Arc<FnDefDatum> {
412+
let callable_def: CallableDef = from_chalk(db, fn_def_id);
413+
let generic_params = generics(db.upcast(), callable_def.into());
414+
let sig = db.callable_item_signature(callable_def);
415+
let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
416+
let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
417+
let bound = chalk_rust_ir::FnDefDatumBound {
418+
// Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
419+
argument_types: sig.value.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(),
420+
return_type: sig.value.ret().clone().to_chalk(db),
421+
where_clauses,
422+
};
423+
let datum = FnDefDatum { id: fn_def_id, binders: make_binders(bound, sig.num_binders) };
424+
Arc::new(datum)
425+
}
426+
408427
impl From<AdtId> for crate::TypeCtorId {
409428
fn from(struct_id: AdtId) -> Self {
410429
struct_id.0
@@ -417,6 +436,18 @@ impl From<crate::TypeCtorId> for AdtId {
417436
}
418437
}
419438

439+
impl From<FnDefId> for crate::CallableDefId {
440+
fn from(fn_def_id: FnDefId) -> Self {
441+
InternKey::from_intern_id(fn_def_id.0)
442+
}
443+
}
444+
445+
impl From<crate::CallableDefId> for FnDefId {
446+
fn from(callable_def_id: crate::CallableDefId) -> Self {
447+
chalk_ir::FnDefId(callable_def_id.as_intern_id())
448+
}
449+
}
450+
420451
impl From<ImplId> for crate::traits::GlobalImplId {
421452
fn from(impl_id: ImplId) -> Self {
422453
InternKey::from_intern_id(impl_id.0)

crates/ra_hir_ty/src/traits/chalk/interner.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub type ImplId = chalk_ir::ImplId<Interner>;
2020
pub type ImplDatum = chalk_rust_ir::ImplDatum<Interner>;
2121
pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId<Interner>;
2222
pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<Interner>;
23+
pub type FnDefId = chalk_ir::FnDefId<Interner>;
24+
pub type FnDefDatum = chalk_rust_ir::FnDefDatum<Interner>;
2325

2426
impl chalk_ir::interner::Interner for Interner {
2527
type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc?

crates/ra_hir_ty/src/traits/chalk/mapping.rs

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use crate::{
1515
db::HirDatabase,
1616
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
1717
traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
18-
ApplicationTy, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, Substs,
19-
TraitEnvironment, TraitRef, Ty, TypeCtor,
18+
ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy,
19+
Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
2020
};
2121

2222
use super::interner::*;
@@ -26,14 +26,19 @@ impl ToChalk for Ty {
2626
type Chalk = chalk_ir::Ty<Interner>;
2727
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
2828
match self {
29-
Ty::Apply(apply_ty) => {
30-
if let TypeCtor::Ref(m) = apply_ty.ctor {
31-
return ref_to_chalk(db, m, apply_ty.parameters);
29+
Ty::Apply(apply_ty) => match apply_ty.ctor {
30+
TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
31+
TypeCtor::FnPtr { num_args: _ } => {
32+
let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner);
33+
chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution })
34+
.intern(&Interner)
3235
}
33-
let name = apply_ty.ctor.to_chalk(db);
34-
let substitution = apply_ty.parameters.to_chalk(db);
35-
chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
36-
}
36+
_ => {
37+
let name = apply_ty.ctor.to_chalk(db);
38+
let substitution = apply_ty.parameters.to_chalk(db);
39+
chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
40+
}
41+
},
3742
Ty::Projection(proj_ty) => {
3843
let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
3944
let substitution = proj_ty.parameters.to_chalk(db);
@@ -93,7 +98,13 @@ impl ToChalk for Ty {
9398
Ty::Projection(ProjectionTy { associated_ty, parameters })
9499
}
95100
chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(),
96-
chalk_ir::TyData::Function(_) => unimplemented!(),
101+
chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => {
102+
let parameters: Substs = from_chalk(db, substitution);
103+
Ty::Apply(ApplicationTy {
104+
ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 },
105+
parameters,
106+
})
107+
}
97108
chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx),
98109
chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
99110
chalk_ir::TyData::Dyn(where_clauses) => {
@@ -217,11 +228,14 @@ impl ToChalk for TypeCtor {
217228
TypeCtor::Slice => TypeName::Slice,
218229
TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)),
219230
TypeCtor::Str => TypeName::Str,
231+
TypeCtor::FnDef(callable_def) => {
232+
let id = callable_def.to_chalk(db);
233+
TypeName::FnDef(id)
234+
}
220235
TypeCtor::Int(Uncertain::Unknown)
221236
| TypeCtor::Float(Uncertain::Unknown)
222237
| TypeCtor::Adt(_)
223238
| TypeCtor::Array
224-
| TypeCtor::FnDef(_)
225239
| TypeCtor::FnPtr { .. }
226240
| TypeCtor::Never
227241
| TypeCtor::Closure { .. } => {
@@ -260,7 +274,10 @@ impl ToChalk for TypeCtor {
260274
TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)),
261275
TypeName::Str => TypeCtor::Str,
262276

263-
TypeName::FnDef(_) => unreachable!(),
277+
TypeName::FnDef(fn_def_id) => {
278+
let callable_def = from_chalk(db, fn_def_id);
279+
TypeCtor::FnDef(callable_def)
280+
}
264281

265282
TypeName::Error => {
266283
// this should not be reached, since we don't represent TypeName::Error with TypeCtor
@@ -347,6 +364,18 @@ impl ToChalk for Impl {
347364
}
348365
}
349366

367+
impl ToChalk for CallableDef {
368+
type Chalk = FnDefId;
369+
370+
fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
371+
db.intern_callable_def(self).into()
372+
}
373+
374+
fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDef {
375+
db.lookup_intern_callable_def(fn_def_id.into())
376+
}
377+
}
378+
350379
impl ToChalk for TypeAliasId {
351380
type Chalk = AssocTypeId;
352381

crates/ra_hir_ty/src/traits/chalk/tls.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,24 @@ impl DebugContext<'_> {
247247

248248
pub fn debug_fn_def_id(
249249
&self,
250-
_fn_def_id: chalk_ir::FnDefId<Interner>,
250+
fn_def_id: chalk_ir::FnDefId<Interner>,
251251
fmt: &mut fmt::Formatter<'_>,
252252
) -> Result<(), fmt::Error> {
253-
write!(fmt, "fn")
253+
let def: CallableDef = from_chalk(self.0, fn_def_id);
254+
let name = match def {
255+
CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(),
256+
CallableDef::StructId(s) => self.0.struct_data(s).name.clone(),
257+
CallableDef::EnumVariantId(e) => {
258+
let enum_data = self.0.enum_data(e.parent);
259+
enum_data.variants[e.local_id].name.clone()
260+
}
261+
};
262+
match def {
263+
CallableDef::FunctionId(_) => write!(fmt, "{{fn {}}}", name),
264+
CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {
265+
write!(fmt, "{{ctor {}}}", name)
266+
}
267+
}
254268
}
255269

256270
pub fn debug_const(

editors/code/src/main.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as vscode from 'vscode';
22
import * as path from "path";
33
import * as os from "os";
4-
import { promises as fs } from "fs";
4+
import { promises as fs, PathLike } from "fs";
55

66
import * as commands from './commands';
77
import { activateInlayHints } from './inlay_hints';
@@ -12,6 +12,7 @@ import { log, assert, isValidExecutable } from './util';
1212
import { PersistentState } from './persistent_state';
1313
import { fetchRelease, download } from './net';
1414
import { activateTaskProvider } from './tasks';
15+
import { exec } from 'child_process';
1516

1617
let ctx: Ctx | undefined;
1718

@@ -188,6 +189,46 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise<
188189
return path;
189190
}
190191

192+
async function patchelf(dest: PathLike): Promise<void> {
193+
await vscode.window.withProgress(
194+
{
195+
location: vscode.ProgressLocation.Notification,
196+
title: "Patching rust-analyzer for NixOS"
197+
},
198+
async (progress, _) => {
199+
const expression = `
200+
{src, pkgs ? import <nixpkgs> {}}:
201+
pkgs.stdenv.mkDerivation {
202+
name = "rust-analyzer";
203+
inherit src;
204+
phases = [ "installPhase" "fixupPhase" ];
205+
installPhase = "cp $src $out";
206+
fixupPhase = ''
207+
chmod 755 $out
208+
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
209+
'';
210+
}
211+
`;
212+
const origFile = dest + "-orig";
213+
await fs.rename(dest, origFile);
214+
progress.report({ message: "Patching executable", increment: 20 });
215+
await new Promise((resolve, reject) => {
216+
const handle = exec(`nix-build -E - --arg src '${origFile}' -o ${dest}`,
217+
(err, stdout, stderr) => {
218+
if (err != null) {
219+
reject(Error(stderr));
220+
} else {
221+
resolve(stdout);
222+
}
223+
});
224+
handle.stdin?.write(expression);
225+
handle.stdin?.end();
226+
});
227+
await fs.unlink(origFile);
228+
}
229+
);
230+
}
231+
191232
async function getServer(config: Config, state: PersistentState): Promise<string | undefined> {
192233
const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath;
193234
if (explicitPath) {
@@ -237,6 +278,12 @@ async function getServer(config: Config, state: PersistentState): Promise<string
237278
assert(!!artifact, `Bad release: ${JSON.stringify(release)}`);
238279

239280
await download(artifact.browser_download_url, dest, "Downloading rust-analyzer server", { mode: 0o755 });
281+
282+
// Patching executable if that's NixOS.
283+
if (await fs.stat("/etc/nixos").then(_ => true).catch(_ => false)) {
284+
await patchelf(dest);
285+
}
286+
240287
await state.updateServerVersion(config.package.version);
241288
return dest;
242289
}

0 commit comments

Comments
 (0)