aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/lib.rs4
-rw-r--r--crates/hir/src/semantics.rs5
-rw-r--r--crates/hir_ty/src/lib.rs94
-rw-r--r--crates/ide_completion/src/completions/dot.rs30
-rw-r--r--editors/code/src/config.ts8
-rw-r--r--editors/code/src/main.ts35
-rw-r--r--editors/code/src/persistent_state.ts8
7 files changed, 150 insertions, 34 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 52d72c3c5..800101c91 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2053,7 +2053,7 @@ impl Type {
2053 name: Option<&Name>, 2053 name: Option<&Name>,
2054 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, 2054 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
2055 ) -> Option<T> { 2055 ) -> Option<T> {
2056 let canonical = hir_ty::replace_errors_with_variables(self.ty.clone()); 2056 let canonical = hir_ty::replace_errors_with_variables(&self.ty);
2057 2057
2058 let env = self.env.clone(); 2058 let env = self.env.clone();
2059 let krate = krate.id; 2059 let krate = krate.id;
@@ -2222,7 +2222,7 @@ impl Type {
2222 } 2222 }
2223 2223
2224 pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool { 2224 pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
2225 let tys = hir_ty::replace_errors_with_variables((self.ty.clone(), other.ty.clone())); 2225 let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
2226 could_unify(db, self.env.clone(), &tys) 2226 could_unify(db, self.env.clone(), &tys)
2227 } 2227 }
2228} 2228}
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 38bd376bc..1b5064b5a 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -505,9 +505,10 @@ impl<'db> SemanticsImpl<'db> {
505 } 505 }
506 506
507 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { 507 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
508 // FIXME: this erases Substs 508 // FIXME: this erases Substs, we should instead record the correct
509 // substitution during inference and use that
509 let func = self.resolve_method_call(call)?; 510 let func = self.resolve_method_call(call)?;
510 let (ty, _) = self.db.value_ty(func.into()).into_value_and_skipped_binders(); 511 let ty = hir_ty::TyBuilder::value_ty(self.db, func.into()).fill_with_unknown().build();
511 let resolver = self.analyze(call.syntax()).resolver; 512 let resolver = self.analyze(call.syntax()).resolver;
512 let ty = Type::new_with_resolver(self.db, &resolver, ty)?; 513 let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
513 let mut res = ty.as_callable(self.db)?; 514 let mut res = ty.as_callable(self.db)?;
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 72093d75a..ef021978a 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -43,7 +43,6 @@ use hir_def::{
43 type_ref::{ConstScalar, Rawness}, 43 type_ref::{ConstScalar, Rawness},
44 TypeParamId, 44 TypeParamId,
45}; 45};
46use stdx::always;
47 46
48use crate::{db::HirDatabase, utils::generics}; 47use crate::{db::HirDatabase, utils::generics};
49 48
@@ -329,14 +328,17 @@ pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
329 t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly") 328 t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
330} 329}
331 330
332pub fn replace_errors_with_variables<T>(t: T) -> Canonical<T::Result> 331/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
332/// ensures there are no unbound variables or inference variables anywhere in
333/// the `t`.
334pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T::Result>
333where 335where
334 T: HasInterner<Interner = Interner> + Fold<Interner>, 336 T: HasInterner<Interner = Interner> + Fold<Interner> + Clone,
335 T::Result: HasInterner<Interner = Interner>, 337 T::Result: HasInterner<Interner = Interner>,
336{ 338{
337 use chalk_ir::{ 339 use chalk_ir::{
338 fold::{Folder, SuperFold}, 340 fold::{Folder, SuperFold},
339 Fallible, 341 Fallible, NoSolution,
340 }; 342 };
341 struct ErrorReplacer { 343 struct ErrorReplacer {
342 vars: usize, 344 vars: usize,
@@ -363,18 +365,88 @@ where
363 365
364 fn fold_inference_ty( 366 fn fold_inference_ty(
365 &mut self, 367 &mut self,
366 var: InferenceVar, 368 _var: InferenceVar,
367 kind: TyVariableKind, 369 _kind: TyVariableKind,
370 _outer_binder: DebruijnIndex,
371 ) -> Fallible<Ty> {
372 if cfg!(debug_assertions) {
373 // we don't want to just panic here, because then the error message
374 // won't contain the whole thing, which would not be very helpful
375 Err(NoSolution)
376 } else {
377 Ok(TyKind::Error.intern(&Interner))
378 }
379 }
380
381 fn fold_free_var_ty(
382 &mut self,
383 _bound_var: BoundVar,
368 _outer_binder: DebruijnIndex, 384 _outer_binder: DebruijnIndex,
369 ) -> Fallible<Ty> { 385 ) -> Fallible<Ty> {
370 always!(false); 386 if cfg!(debug_assertions) {
371 Ok(TyKind::InferenceVar(var, kind).intern(&Interner)) 387 // we don't want to just panic here, because then the error message
388 // won't contain the whole thing, which would not be very helpful
389 Err(NoSolution)
390 } else {
391 Ok(TyKind::Error.intern(&Interner))
392 }
393 }
394
395 fn fold_inference_const(
396 &mut self,
397 _ty: Ty,
398 _var: InferenceVar,
399 _outer_binder: DebruijnIndex,
400 ) -> Fallible<Const> {
401 if cfg!(debug_assertions) {
402 Err(NoSolution)
403 } else {
404 Ok(dummy_usize_const())
405 }
406 }
407
408 fn fold_free_var_const(
409 &mut self,
410 _ty: Ty,
411 _bound_var: BoundVar,
412 _outer_binder: DebruijnIndex,
413 ) -> Fallible<Const> {
414 if cfg!(debug_assertions) {
415 Err(NoSolution)
416 } else {
417 Ok(dummy_usize_const())
418 }
419 }
420
421 fn fold_inference_lifetime(
422 &mut self,
423 _var: InferenceVar,
424 _outer_binder: DebruijnIndex,
425 ) -> Fallible<Lifetime> {
426 if cfg!(debug_assertions) {
427 Err(NoSolution)
428 } else {
429 Ok(static_lifetime())
430 }
431 }
432
433 fn fold_free_var_lifetime(
434 &mut self,
435 _bound_var: BoundVar,
436 _outer_binder: DebruijnIndex,
437 ) -> Fallible<Lifetime> {
438 if cfg!(debug_assertions) {
439 Err(NoSolution)
440 } else {
441 Ok(static_lifetime())
442 }
372 } 443 }
373 } 444 }
374 let mut error_replacer = ErrorReplacer { vars: 0 }; 445 let mut error_replacer = ErrorReplacer { vars: 0 };
375 let value = t 446 let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
376 .fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) 447 Ok(t) => t,
377 .expect("fold failed unexpectedly"); 448 Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
449 };
378 let kinds = (0..error_replacer.vars).map(|_| { 450 let kinds = (0..error_replacer.vars).map(|_| {
379 chalk_ir::CanonicalVarKind::new( 451 chalk_ir::CanonicalVarKind::new(
380 chalk_ir::VariableKind::Ty(TyVariableKind::General), 452 chalk_ir::VariableKind::Ty(TyVariableKind::General),
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index 7e4efe589..fd9738743 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -454,4 +454,34 @@ mod foo {
454 "#]], 454 "#]],
455 ); 455 );
456 } 456 }
457
458 #[test]
459 fn issue_8931() {
460 check(
461 r#"
462#[lang = "fn_once"]
463trait FnOnce<Args> {
464 type Output;
465}
466struct S;
467
468struct Foo;
469impl Foo {
470 fn foo(&self) -> &[u8] { loop {} }
471}
472
473impl S {
474 fn indented(&mut self, f: impl FnOnce(&mut Self)) {
475 }
476
477 fn f(&mut self, v: Foo) {
478 self.indented(|this| v.$0)
479 }
480}
481 "#,
482 expect![[r#"
483 me foo() fn(&self) -> &[u8]
484 "#]],
485 );
486 }
457} 487}
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index e858f80bc..fbb7a556a 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -4,7 +4,7 @@ import { log } from "./util";
4 4
5export type UpdatesChannel = "stable" | "nightly"; 5export type UpdatesChannel = "stable" | "nightly";
6 6
7export const NIGHTLY_TAG = "nightly"; 7const NIGHTLY_TAG = "nightly";
8 8
9export type RunnableEnvCfg = undefined | Record<string, string> | { mask?: string; env: Record<string, string> }[]; 9export type RunnableEnvCfg = undefined | Record<string, string> | { mask?: string; env: Record<string, string> }[];
10 10
@@ -34,7 +34,7 @@ export class Config {
34 readonly globalStoragePath: string; 34 readonly globalStoragePath: string;
35 35
36 constructor(ctx: vscode.ExtensionContext) { 36 constructor(ctx: vscode.ExtensionContext) {
37 this.globalStoragePath = ctx.globalStoragePath; 37 this.globalStoragePath = ctx.globalStorageUri.path;
38 vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions); 38 vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions);
39 this.refreshLogging(); 39 this.refreshLogging();
40 } 40 }
@@ -170,4 +170,8 @@ export class Config {
170 gotoTypeDef: this.get<boolean>("hoverActions.gotoTypeDef"), 170 gotoTypeDef: this.get<boolean>("hoverActions.gotoTypeDef"),
171 }; 171 };
172 } 172 }
173
174 get currentExtensionIsNightly() {
175 return this.package.releaseTag === NIGHTLY_TAG;
176 }
173} 177}
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 92c797d47..aaedc2431 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -6,7 +6,7 @@ import { promises as fs, PathLike } from "fs";
6import * as commands from './commands'; 6import * as commands from './commands';
7import { activateInlayHints } from './inlay_hints'; 7import { activateInlayHints } from './inlay_hints';
8import { Ctx } from './ctx'; 8import { Ctx } from './ctx';
9import { Config, NIGHTLY_TAG } from './config'; 9import { Config } from './config';
10import { log, assert, isValidExecutable } from './util'; 10import { log, assert, isValidExecutable } from './util';
11import { PersistentState } from './persistent_state'; 11import { PersistentState } from './persistent_state';
12import { fetchRelease, download } from './net'; 12import { fetchRelease, download } from './net';
@@ -156,16 +156,18 @@ export async function deactivate() {
156async function bootstrap(config: Config, state: PersistentState): Promise<string> { 156async function bootstrap(config: Config, state: PersistentState): Promise<string> {
157 await fs.mkdir(config.globalStoragePath, { recursive: true }); 157 await fs.mkdir(config.globalStoragePath, { recursive: true });
158 158
159 if (!config.currentExtensionIsNightly) {
160 await state.updateNightlyReleaseId(undefined);
161 }
159 await bootstrapExtension(config, state); 162 await bootstrapExtension(config, state);
160 const path = await bootstrapServer(config, state); 163 const path = await bootstrapServer(config, state);
161
162 return path; 164 return path;
163} 165}
164 166
165async function bootstrapExtension(config: Config, state: PersistentState): Promise<void> { 167async function bootstrapExtension(config: Config, state: PersistentState): Promise<void> {
166 if (config.package.releaseTag === null) return; 168 if (config.package.releaseTag === null) return;
167 if (config.channel === "stable") { 169 if (config.channel === "stable") {
168 if (config.package.releaseTag === NIGHTLY_TAG) { 170 if (config.currentExtensionIsNightly) {
169 void vscode.window.showWarningMessage( 171 void vscode.window.showWarningMessage(
170 `You are running a nightly version of rust-analyzer extension. ` + 172 `You are running a nightly version of rust-analyzer extension. ` +
171 `To switch to stable, uninstall the extension and re-install it from the marketplace` 173 `To switch to stable, uninstall the extension and re-install it from the marketplace`
@@ -176,27 +178,34 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
176 if (serverPath(config)) return; 178 if (serverPath(config)) return;
177 179
178 const now = Date.now(); 180 const now = Date.now();
179 if (config.package.releaseTag === NIGHTLY_TAG) { 181 const isInitialNightlyDownload = state.nightlyReleaseId === undefined;
182 if (config.currentExtensionIsNightly) {
180 // Check if we should poll github api for the new nightly version 183 // Check if we should poll github api for the new nightly version
181 // if we haven't done it during the past hour 184 // if we haven't done it during the past hour
182 const lastCheck = state.lastCheck; 185 const lastCheck = state.lastCheck;
183 186
184 const anHour = 60 * 60 * 1000; 187 const anHour = 60 * 60 * 1000;
185 const shouldCheckForNewNightly = state.releaseId === undefined || (now - (lastCheck ?? 0)) > anHour; 188 const shouldCheckForNewNightly = isInitialNightlyDownload || (now - (lastCheck ?? 0)) > anHour;
186 189
187 if (!shouldCheckForNewNightly) return; 190 if (!shouldCheckForNewNightly) return;
188 } 191 }
189 192
190 const release = await downloadWithRetryDialog(state, async () => { 193 const latestNightlyRelease = await downloadWithRetryDialog(state, async () => {
191 return await fetchRelease("nightly", state.githubToken, config.httpProxy); 194 return await fetchRelease("nightly", state.githubToken, config.httpProxy);
192 }).catch(async (e) => { 195 }).catch(async (e) => {
193 log.error(e); 196 log.error(e);
194 if (state.releaseId === undefined) { // Show error only for the initial download 197 if (isInitialNightlyDownload) {
195 await vscode.window.showErrorMessage(`Failed to download rust-analyzer nightly ${e}`); 198 await vscode.window.showErrorMessage(`Failed to download rust-analyzer nightly: ${e}`);
196 } 199 }
197 return undefined; 200 return;
198 }); 201 });
199 if (release === undefined || release.id === state.releaseId) return; 202 if (latestNightlyRelease === undefined) {
203 if (isInitialNightlyDownload) {
204 await vscode.window.showErrorMessage("Failed to download rust-analyzer nightly: empty release contents returned");
205 }
206 return;
207 }
208 if (config.currentExtensionIsNightly && latestNightlyRelease.id === state.nightlyReleaseId) return;
200 209
201 const userResponse = await vscode.window.showInformationMessage( 210 const userResponse = await vscode.window.showInformationMessage(
202 "New version of rust-analyzer (nightly) is available (requires reload).", 211 "New version of rust-analyzer (nightly) is available (requires reload).",
@@ -204,8 +213,8 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
204 ); 213 );
205 if (userResponse !== "Update") return; 214 if (userResponse !== "Update") return;
206 215
207 const artifact = release.assets.find(artifact => artifact.name === "rust-analyzer.vsix"); 216 const artifact = latestNightlyRelease.assets.find(artifact => artifact.name === "rust-analyzer.vsix");
208 assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); 217 assert(!!artifact, `Bad release: ${JSON.stringify(latestNightlyRelease)}`);
209 218
210 const dest = path.join(config.globalStoragePath, "rust-analyzer.vsix"); 219 const dest = path.join(config.globalStoragePath, "rust-analyzer.vsix");
211 220
@@ -221,7 +230,7 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
221 await vscode.commands.executeCommand("workbench.extensions.installExtension", vscode.Uri.file(dest)); 230 await vscode.commands.executeCommand("workbench.extensions.installExtension", vscode.Uri.file(dest));
222 await fs.unlink(dest); 231 await fs.unlink(dest);
223 232
224 await state.updateReleaseId(release.id); 233 await state.updateNightlyReleaseId(latestNightlyRelease.id);
225 await state.updateLastCheck(now); 234 await state.updateLastCheck(now);
226 await vscode.commands.executeCommand("workbench.action.reloadWindow"); 235 await vscode.commands.executeCommand("workbench.action.reloadWindow");
227} 236}
diff --git a/editors/code/src/persistent_state.ts b/editors/code/src/persistent_state.ts
index afb652589..dd2aeecca 100644
--- a/editors/code/src/persistent_state.ts
+++ b/editors/code/src/persistent_state.ts
@@ -3,8 +3,8 @@ import { log } from './util';
3 3
4export class PersistentState { 4export class PersistentState {
5 constructor(private readonly globalState: vscode.Memento) { 5 constructor(private readonly globalState: vscode.Memento) {
6 const { lastCheck, releaseId, serverVersion } = this; 6 const { lastCheck, nightlyReleaseId, serverVersion } = this;
7 log.info("PersistentState:", { lastCheck, releaseId, serverVersion }); 7 log.info("PersistentState:", { lastCheck, nightlyReleaseId, serverVersion });
8 } 8 }
9 9
10 /** 10 /**
@@ -21,10 +21,10 @@ export class PersistentState {
21 * Release id of the *nightly* extension. 21 * Release id of the *nightly* extension.
22 * Used to check if we should update. 22 * Used to check if we should update.
23 */ 23 */
24 get releaseId(): number | undefined { 24 get nightlyReleaseId(): number | undefined {
25 return this.globalState.get("releaseId"); 25 return this.globalState.get("releaseId");
26 } 26 }
27 async updateReleaseId(value: number) { 27 async updateNightlyReleaseId(value: number | undefined) {
28 await this.globalState.update("releaseId", value); 28 await this.globalState.update("releaseId", value);
29 } 29 }
30 30