Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #16811 - Veykril:snapshot, r=Veykril
fix: Fix method resolution snapshotting receiver_ty too early Accidental change in https://github.com/rust-lang/rust-analyzer/pull/16749 presumably caused some type mismatches in webrender
bors 2024-03-11
parent 8f8bcfc · parent fdc527f · commit 03d2d90
-rw-r--r--crates/hir-ty/src/infer/unify.rs1
-rw-r--r--crates/hir-ty/src/method_resolution.rs39
-rw-r--r--crates/ide-diagnostics/src/handlers/unresolved_field.rs50
3 files changed, 48 insertions, 42 deletions
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 18029adbaf..be7547f9ba 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -438,7 +438,6 @@ impl<'a> InferenceTable<'a> {
where
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
{
- // TODO check this vec here
self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
}
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 3a97c55a67..a679a114b4 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -1060,27 +1060,26 @@ fn iterate_method_candidates_by_receiver(
name: Option<&Name>,
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
+ let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
+ // We're looking for methods with *receiver* type receiver_ty. These could
+ // be found in any of the derefs of receiver_ty, so we have to go through
+ // that, including raw derefs.
+ table.run_in_snapshot(|table| {
+ let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
+ while let Some((self_ty, _)) = autoderef.next() {
+ iterate_inherent_methods(
+ &self_ty,
+ autoderef.table,
+ name,
+ Some(&receiver_ty),
+ Some(receiver_adjustments.clone()),
+ visible_from_module,
+ &mut callback,
+ )?
+ }
+ ControlFlow::Continue(())
+ })?;
table.run_in_snapshot(|table| {
- let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
- // We're looking for methods with *receiver* type receiver_ty. These could
- // be found in any of the derefs of receiver_ty, so we have to go through
- // that, including raw derefs.
- table.run_in_snapshot(|table| {
- let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
- while let Some((self_ty, _)) = autoderef.next() {
- iterate_inherent_methods(
- &self_ty,
- autoderef.table,
- name,
- Some(&receiver_ty),
- Some(receiver_adjustments.clone()),
- visible_from_module,
- &mut callback,
- )?
- }
- ControlFlow::Continue(())
- })?;
-
let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
while let Some((self_ty, _)) = autoderef.next() {
iterate_trait_method_candidates(
diff --git a/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 06399e5f00..55e91ceb94 100644
--- a/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -57,27 +57,34 @@ pub(crate) fn unresolved_field(
}
fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<Assist>> {
- let mut fixes = if d.method_with_same_name_exists { method_fix(ctx, &d.expr) } else { None };
- if let Some(fix) = add_field_fix(ctx, d) {
- fixes.get_or_insert_with(Vec::new).extend(fix);
+ let mut fixes = Vec::new();
+ if d.method_with_same_name_exists {
+ fixes.extend(method_fix(ctx, &d.expr));
+ }
+ fixes.extend(field_fix(ctx, d));
+ if fixes.is_empty() {
+ None
+ } else {
+ Some(fixes)
}
- fixes
}
-fn add_field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<Assist>> {
+// FIXME: Add Snippet Support
+fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Assist> {
// Get the FileRange of the invalid field access
let root = ctx.sema.db.parse_or_expand(d.expr.file_id);
let expr = d.expr.value.to_node(&root);
let error_range = ctx.sema.original_range_opt(expr.syntax())?;
+ let field_name = d.name.as_str()?;
// Convert the receiver to an ADT
- let adt = d.receiver.as_adt()?;
+ let adt = d.receiver.strip_references().as_adt()?;
let target_module = adt.module(ctx.sema.db);
let suggested_type =
if let Some(new_field_type) = ctx.sema.type_of_expr(&expr).map(|v| v.adjusted()) {
let display =
- new_field_type.display_source_code(ctx.sema.db, target_module.into(), true).ok();
+ new_field_type.display_source_code(ctx.sema.db, target_module.into(), false).ok();
make::ty(display.as_deref().unwrap_or("()"))
} else {
make::ty("()")
@@ -87,9 +94,6 @@ fn add_field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Opti
return None;
}
- // FIXME: Add Snippet Support
- let field_name = d.name.as_str()?;
-
match adt {
Adt::Struct(adt_struct) => {
add_field_to_struct_fix(ctx, adt_struct, field_name, suggested_type, error_range)
@@ -100,13 +104,14 @@ fn add_field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Opti
_ => None,
}
}
+
fn add_variant_to_union(
ctx: &DiagnosticsContext<'_>,
adt_union: Union,
field_name: &str,
suggested_type: Type,
error_range: FileRange,
-) -> Option<Vec<Assist>> {
+) -> Option<Assist> {
let adt_source = adt_union.source(ctx.sema.db)?;
let adt_syntax = adt_source.syntax();
let Some(field_list) = adt_source.value.record_field_list() else {
@@ -120,22 +125,23 @@ fn add_variant_to_union(
let mut src_change_builder = SourceChangeBuilder::new(range.file_id);
src_change_builder.insert(offset, record_field);
- Some(vec![Assist {
+ Some(Assist {
id: AssistId("add-variant-to-union", AssistKind::QuickFix),
label: Label::new("Add field to union".to_owned()),
group: None,
target: error_range.range,
source_change: Some(src_change_builder.finish()),
trigger_signature_help: false,
- }])
+ })
}
+
fn add_field_to_struct_fix(
ctx: &DiagnosticsContext<'_>,
adt_struct: Struct,
field_name: &str,
suggested_type: Type,
error_range: FileRange,
-) -> Option<Vec<Assist>> {
+) -> Option<Assist> {
let struct_source = adt_struct.source(ctx.sema.db)?;
let struct_syntax = struct_source.syntax();
let struct_range = struct_syntax.original_file_range(ctx.sema.db);
@@ -162,14 +168,14 @@ fn add_field_to_struct_fix(
// FIXME: Allow for choosing a visibility modifier see https://github.com/rust-lang/rust-analyzer/issues/11563
src_change_builder.insert(offset, record_field);
- Some(vec![Assist {
+ Some(Assist {
id: AssistId("add-field-to-record-struct", AssistKind::QuickFix),
label: Label::new("Add field to Record Struct".to_owned()),
group: None,
target: error_range.range,
source_change: Some(src_change_builder.finish()),
trigger_signature_help: false,
- }])
+ })
}
None => {
// Add a field list to the Unit Struct
@@ -193,14 +199,14 @@ fn add_field_to_struct_fix(
}
src_change_builder.replace(semi_colon.text_range(), record_field_list.to_string());
- Some(vec![Assist {
+ Some(Assist {
id: AssistId("convert-unit-struct-to-record-struct", AssistKind::QuickFix),
label: Label::new("Convert Unit Struct to Record Struct and add field".to_owned()),
group: None,
target: error_range.range,
source_change: Some(src_change_builder.finish()),
trigger_signature_help: false,
- }])
+ })
}
Some(FieldList::TupleFieldList(_tuple)) => {
// FIXME: Add support for Tuple Structs. Tuple Structs are not sent to this diagnostic
@@ -208,6 +214,7 @@ fn add_field_to_struct_fix(
}
}
}
+
/// Used to determine the layout of the record field in the struct.
fn record_field_layout(
visibility: Option<Visibility>,
@@ -242,15 +249,16 @@ fn record_field_layout(
Some((offset, format!("{comma}{indent}{record_field}{trailing_new_line}")))
}
+
// FIXME: We should fill out the call here, move the cursor and trigger signature help
fn method_fix(
ctx: &DiagnosticsContext<'_>,
expr_ptr: &InFile<AstPtr<ast::Expr>>,
-) -> Option<Vec<Assist>> {
+) -> Option<Assist> {
let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
let expr = expr_ptr.value.to_node(&root);
let FileRange { range, file_id } = ctx.sema.original_range_opt(expr.syntax())?;
- Some(vec![Assist {
+ Some(Assist {
id: AssistId("expected-field-found-method-call-fix", AssistKind::QuickFix),
label: Label::new("Use parentheses to call the method".to_owned()),
group: None,
@@ -260,7 +268,7 @@ fn method_fix(
TextEdit::insert(range.end(), "()".to_owned()),
)),
trigger_signature_help: false,
- }])
+ })
}
#[cfg(test)]
mod tests {