fix: Fix method resolution snapshotting receiver_ty too early
This commit is contained in:
parent
8f8bcfc131
commit
fdc527f096
@ -438,7 +438,6 @@ pub(crate) fn resolve_with_fallback<T>(
|
|||||||
where
|
where
|
||||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
|
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
|
||||||
{
|
{
|
||||||
// TODO check this vec here
|
|
||||||
self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
|
self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1060,27 +1060,26 @@ fn iterate_method_candidates_by_receiver(
|
|||||||
name: Option<&Name>,
|
name: Option<&Name>,
|
||||||
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
|
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
|
||||||
) -> 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| {
|
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);
|
let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
|
||||||
while let Some((self_ty, _)) = autoderef.next() {
|
while let Some((self_ty, _)) = autoderef.next() {
|
||||||
iterate_trait_method_candidates(
|
iterate_trait_method_candidates(
|
||||||
|
@ -57,27 +57,34 @@ pub(crate) fn unresolved_field(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<Assist>> {
|
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 };
|
let mut fixes = Vec::new();
|
||||||
if let Some(fix) = add_field_fix(ctx, d) {
|
if d.method_with_same_name_exists {
|
||||||
fixes.get_or_insert_with(Vec::new).extend(fix);
|
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
|
// Get the FileRange of the invalid field access
|
||||||
let root = ctx.sema.db.parse_or_expand(d.expr.file_id);
|
let root = ctx.sema.db.parse_or_expand(d.expr.file_id);
|
||||||
let expr = d.expr.value.to_node(&root);
|
let expr = d.expr.value.to_node(&root);
|
||||||
|
|
||||||
let error_range = ctx.sema.original_range_opt(expr.syntax())?;
|
let error_range = ctx.sema.original_range_opt(expr.syntax())?;
|
||||||
|
let field_name = d.name.as_str()?;
|
||||||
// Convert the receiver to an ADT
|
// 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 target_module = adt.module(ctx.sema.db);
|
||||||
|
|
||||||
let suggested_type =
|
let suggested_type =
|
||||||
if let Some(new_field_type) = ctx.sema.type_of_expr(&expr).map(|v| v.adjusted()) {
|
if let Some(new_field_type) = ctx.sema.type_of_expr(&expr).map(|v| v.adjusted()) {
|
||||||
let display =
|
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("()"))
|
make::ty(display.as_deref().unwrap_or("()"))
|
||||||
} else {
|
} else {
|
||||||
make::ty("()")
|
make::ty("()")
|
||||||
@ -87,9 +94,6 @@ fn add_field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Opti
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Add Snippet Support
|
|
||||||
let field_name = d.name.as_str()?;
|
|
||||||
|
|
||||||
match adt {
|
match adt {
|
||||||
Adt::Struct(adt_struct) => {
|
Adt::Struct(adt_struct) => {
|
||||||
add_field_to_struct_fix(ctx, adt_struct, field_name, suggested_type, error_range)
|
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,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_variant_to_union(
|
fn add_variant_to_union(
|
||||||
ctx: &DiagnosticsContext<'_>,
|
ctx: &DiagnosticsContext<'_>,
|
||||||
adt_union: Union,
|
adt_union: Union,
|
||||||
field_name: &str,
|
field_name: &str,
|
||||||
suggested_type: Type,
|
suggested_type: Type,
|
||||||
error_range: FileRange,
|
error_range: FileRange,
|
||||||
) -> Option<Vec<Assist>> {
|
) -> Option<Assist> {
|
||||||
let adt_source = adt_union.source(ctx.sema.db)?;
|
let adt_source = adt_union.source(ctx.sema.db)?;
|
||||||
let adt_syntax = adt_source.syntax();
|
let adt_syntax = adt_source.syntax();
|
||||||
let Some(field_list) = adt_source.value.record_field_list() else {
|
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);
|
let mut src_change_builder = SourceChangeBuilder::new(range.file_id);
|
||||||
src_change_builder.insert(offset, record_field);
|
src_change_builder.insert(offset, record_field);
|
||||||
Some(vec![Assist {
|
Some(Assist {
|
||||||
id: AssistId("add-variant-to-union", AssistKind::QuickFix),
|
id: AssistId("add-variant-to-union", AssistKind::QuickFix),
|
||||||
label: Label::new("Add field to union".to_owned()),
|
label: Label::new("Add field to union".to_owned()),
|
||||||
group: None,
|
group: None,
|
||||||
target: error_range.range,
|
target: error_range.range,
|
||||||
source_change: Some(src_change_builder.finish()),
|
source_change: Some(src_change_builder.finish()),
|
||||||
trigger_signature_help: false,
|
trigger_signature_help: false,
|
||||||
}])
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_field_to_struct_fix(
|
fn add_field_to_struct_fix(
|
||||||
ctx: &DiagnosticsContext<'_>,
|
ctx: &DiagnosticsContext<'_>,
|
||||||
adt_struct: Struct,
|
adt_struct: Struct,
|
||||||
field_name: &str,
|
field_name: &str,
|
||||||
suggested_type: Type,
|
suggested_type: Type,
|
||||||
error_range: FileRange,
|
error_range: FileRange,
|
||||||
) -> Option<Vec<Assist>> {
|
) -> Option<Assist> {
|
||||||
let struct_source = adt_struct.source(ctx.sema.db)?;
|
let struct_source = adt_struct.source(ctx.sema.db)?;
|
||||||
let struct_syntax = struct_source.syntax();
|
let struct_syntax = struct_source.syntax();
|
||||||
let struct_range = struct_syntax.original_file_range(ctx.sema.db);
|
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
|
// FIXME: Allow for choosing a visibility modifier see https://github.com/rust-lang/rust-analyzer/issues/11563
|
||||||
src_change_builder.insert(offset, record_field);
|
src_change_builder.insert(offset, record_field);
|
||||||
Some(vec![Assist {
|
Some(Assist {
|
||||||
id: AssistId("add-field-to-record-struct", AssistKind::QuickFix),
|
id: AssistId("add-field-to-record-struct", AssistKind::QuickFix),
|
||||||
label: Label::new("Add field to Record Struct".to_owned()),
|
label: Label::new("Add field to Record Struct".to_owned()),
|
||||||
group: None,
|
group: None,
|
||||||
target: error_range.range,
|
target: error_range.range,
|
||||||
source_change: Some(src_change_builder.finish()),
|
source_change: Some(src_change_builder.finish()),
|
||||||
trigger_signature_help: false,
|
trigger_signature_help: false,
|
||||||
}])
|
})
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// Add a field list to the Unit Struct
|
// 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());
|
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),
|
id: AssistId("convert-unit-struct-to-record-struct", AssistKind::QuickFix),
|
||||||
label: Label::new("Convert Unit Struct to Record Struct and add field".to_owned()),
|
label: Label::new("Convert Unit Struct to Record Struct and add field".to_owned()),
|
||||||
group: None,
|
group: None,
|
||||||
target: error_range.range,
|
target: error_range.range,
|
||||||
source_change: Some(src_change_builder.finish()),
|
source_change: Some(src_change_builder.finish()),
|
||||||
trigger_signature_help: false,
|
trigger_signature_help: false,
|
||||||
}])
|
})
|
||||||
}
|
}
|
||||||
Some(FieldList::TupleFieldList(_tuple)) => {
|
Some(FieldList::TupleFieldList(_tuple)) => {
|
||||||
// FIXME: Add support for Tuple Structs. Tuple Structs are not sent to this diagnostic
|
// 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.
|
/// Used to determine the layout of the record field in the struct.
|
||||||
fn record_field_layout(
|
fn record_field_layout(
|
||||||
visibility: Option<Visibility>,
|
visibility: Option<Visibility>,
|
||||||
@ -242,15 +249,16 @@ fn record_field_layout(
|
|||||||
|
|
||||||
Some((offset, format!("{comma}{indent}{record_field}{trailing_new_line}")))
|
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
|
// FIXME: We should fill out the call here, move the cursor and trigger signature help
|
||||||
fn method_fix(
|
fn method_fix(
|
||||||
ctx: &DiagnosticsContext<'_>,
|
ctx: &DiagnosticsContext<'_>,
|
||||||
expr_ptr: &InFile<AstPtr<ast::Expr>>,
|
expr_ptr: &InFile<AstPtr<ast::Expr>>,
|
||||||
) -> Option<Vec<Assist>> {
|
) -> Option<Assist> {
|
||||||
let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
|
let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
|
||||||
let expr = expr_ptr.value.to_node(&root);
|
let expr = expr_ptr.value.to_node(&root);
|
||||||
let FileRange { range, file_id } = ctx.sema.original_range_opt(expr.syntax())?;
|
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),
|
id: AssistId("expected-field-found-method-call-fix", AssistKind::QuickFix),
|
||||||
label: Label::new("Use parentheses to call the method".to_owned()),
|
label: Label::new("Use parentheses to call the method".to_owned()),
|
||||||
group: None,
|
group: None,
|
||||||
@ -260,7 +268,7 @@ fn method_fix(
|
|||||||
TextEdit::insert(range.end(), "()".to_owned()),
|
TextEdit::insert(range.end(), "()".to_owned()),
|
||||||
)),
|
)),
|
||||||
trigger_signature_help: false,
|
trigger_signature_help: false,
|
||||||
}])
|
})
|
||||||
}
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
Loading…
Reference in New Issue
Block a user