about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-03-11 14:37:32 +0000
committerbors <bors@rust-lang.org>2024-03-11 14:37:32 +0000
commit03d2d9016d171c400f0891c867ea0aca9ec4f972 (patch)
tree47519a012813510e0ad06ca68522b09ace32d1ea
parent8f8bcfc1313d4190ce29d6ea944b2b8ae60dea9d (diff)
parentfdc527f0965a4bf150932976b51f7adc61afe079 (diff)
downloadrust-03d2d9016d171c400f0891c867ea0aca9ec4f972.tar.gz
rust-03d2d9016d171c400f0891c867ea0aca9ec4f972.zip
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
-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 18029adbaf2..be7547f9bae 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 3a97c55a672..a679a114b4b 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 06399e5f003..55e91ceb941 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 {