Skip to content

Commit bf607da

Browse files
Move logic into method
1 parent 3f697b8 commit bf607da

File tree

1 file changed

+140
-116
lines changed

1 file changed

+140
-116
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+140-116
Original file line numberDiff line numberDiff line change
@@ -398,122 +398,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
398398
custom_span_label = true;
399399
}
400400
if static_candidates.len() == 1 {
401-
let mut has_unsuggestable_args = false;
402-
let ty_str = if let Some(CandidateSource::Impl(impl_did)) =
403-
static_candidates.get(0)
404-
{
405-
// When the "method" is resolved through dereferencing, we really want the
406-
// original type that has the associated function for accurate suggestions.
407-
// (#61411)
408-
let ty = tcx.at(span).type_of(*impl_did);
409-
match (&ty.peel_refs().kind(), &rcvr_ty.peel_refs().kind()) {
410-
(ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => {
411-
// If there are any inferred arguments, (`{integer}`), we should replace
412-
// them with underscores to allow the compiler to infer them
413-
let infer_substs: Vec<GenericArg<'_>> = substs
414-
.into_iter()
415-
.map(|arg| {
416-
if !arg.is_suggestable(tcx, true) {
417-
has_unsuggestable_args = true;
418-
match arg.unpack() {
419-
GenericArgKind::Lifetime(_) => self
420-
.next_region_var(RegionVariableOrigin::MiscVariable(
421-
rustc_span::DUMMY_SP,
422-
))
423-
.into(),
424-
GenericArgKind::Type(_) => self
425-
.next_ty_var(TypeVariableOrigin {
426-
span: rustc_span::DUMMY_SP,
427-
kind: TypeVariableOriginKind::MiscVariable,
428-
})
429-
.into(),
430-
GenericArgKind::Const(arg) => self
431-
.next_const_var(
432-
arg.ty(),
433-
ConstVariableOrigin {
434-
span: rustc_span::DUMMY_SP,
435-
kind: ConstVariableOriginKind::MiscVariable,
436-
},
437-
)
438-
.into(),
439-
}
440-
} else {
441-
arg
442-
}
443-
})
444-
.collect::<Vec<_>>();
445-
446-
tcx.value_path_str_with_substs(
447-
def_actual.did(),
448-
tcx.intern_substs(&infer_substs),
449-
)
450-
}
451-
_ => self.ty_to_value_string(ty.peel_refs()),
452-
}
453-
} else {
454-
self.ty_to_value_string(rcvr_ty.peel_refs())
455-
};
456-
if let SelfSource::MethodCall(_) = source {
457-
let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) &&
458-
let Some(assoc) = self.associated_value(*impl_did, item_name) {
459-
let sig = self.tcx.fn_sig(assoc.def_id);
460-
if let Some(first) = sig.inputs().skip_binder().get(0) {
461-
if first.peel_refs() == rcvr_ty.peel_refs() {
462-
None
463-
} else {
464-
Some(if first.is_region_ptr() {
465-
if first.is_mutable_ptr() { "&mut " } else { "&" }
466-
} else {
467-
""
468-
})
469-
}
470-
} else {
471-
None
472-
}
473-
} else {
474-
None
475-
};
476-
let mut applicability = Applicability::MachineApplicable;
477-
let args = if let Some((receiver, args)) = args {
478-
// The first arg is the same kind as the receiver
479-
let explicit_args = if first_arg.is_some() {
480-
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
481-
} else {
482-
// There is no `Self` kind to infer the arguments from
483-
if has_unsuggestable_args {
484-
applicability = Applicability::HasPlaceholders;
485-
}
486-
args.iter().collect()
487-
};
488-
format!(
489-
"({}{})",
490-
first_arg.unwrap_or(""),
491-
explicit_args
492-
.iter()
493-
.map(|arg| tcx
494-
.sess
495-
.source_map()
496-
.span_to_snippet(arg.span)
497-
.unwrap_or_else(|_| {
498-
applicability = Applicability::HasPlaceholders;
499-
"_".to_owned()
500-
}))
501-
.collect::<Vec<_>>()
502-
.join(", "),
503-
)
504-
} else {
505-
applicability = Applicability::HasPlaceholders;
506-
"(...)".to_owned()
507-
};
508-
err.span_suggestion(
509-
sugg_span,
510-
"use associated function syntax instead",
511-
format!("{}::{}{}", ty_str, item_name, args),
512-
applicability,
513-
);
514-
} else {
515-
err.help(&format!("try with `{}::{}`", ty_str, item_name,));
516-
}
401+
self.suggest_associated_call_syntax(
402+
&mut err,
403+
&static_candidates,
404+
rcvr_ty,
405+
source,
406+
item_name,
407+
args,
408+
sugg_span,
409+
);
517410

518411
report_candidates(span, &mut err, &mut static_candidates, sugg_span);
519412
} else if static_candidates.len() > 1 {
@@ -1180,6 +1073,137 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11801073
None
11811074
}
11821075

1076+
/// Suggest calling `Ty::method` if `.method()` isn't found because the method
1077+
/// doesn't take a `self` receiver.
1078+
fn suggest_associated_call_syntax(
1079+
&self,
1080+
err: &mut Diagnostic,
1081+
static_candidates: &Vec<CandidateSource>,
1082+
rcvr_ty: Ty<'tcx>,
1083+
source: SelfSource<'tcx>,
1084+
item_name: Ident,
1085+
args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>,
1086+
sugg_span: Span,
1087+
) {
1088+
let mut has_unsuggestable_args = false;
1089+
let ty_str = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) {
1090+
// When the "method" is resolved through dereferencing, we really want the
1091+
// original type that has the associated function for accurate suggestions.
1092+
// (#61411)
1093+
let ty = self.tcx.type_of(*impl_did);
1094+
match (&ty.peel_refs().kind(), &rcvr_ty.peel_refs().kind()) {
1095+
(ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => {
1096+
// If there are any inferred arguments, (`{integer}`), we should replace
1097+
// them with underscores to allow the compiler to infer them
1098+
let infer_substs: Vec<GenericArg<'_>> = substs
1099+
.into_iter()
1100+
.map(|arg| {
1101+
if !arg.is_suggestable(self.tcx, true) {
1102+
has_unsuggestable_args = true;
1103+
match arg.unpack() {
1104+
GenericArgKind::Lifetime(_) => self
1105+
.next_region_var(RegionVariableOrigin::MiscVariable(
1106+
rustc_span::DUMMY_SP,
1107+
))
1108+
.into(),
1109+
GenericArgKind::Type(_) => self
1110+
.next_ty_var(TypeVariableOrigin {
1111+
span: rustc_span::DUMMY_SP,
1112+
kind: TypeVariableOriginKind::MiscVariable,
1113+
})
1114+
.into(),
1115+
GenericArgKind::Const(arg) => self
1116+
.next_const_var(
1117+
arg.ty(),
1118+
ConstVariableOrigin {
1119+
span: rustc_span::DUMMY_SP,
1120+
kind: ConstVariableOriginKind::MiscVariable,
1121+
},
1122+
)
1123+
.into(),
1124+
}
1125+
} else {
1126+
arg
1127+
}
1128+
})
1129+
.collect::<Vec<_>>();
1130+
1131+
self.tcx.value_path_str_with_substs(
1132+
def_actual.did(),
1133+
self.tcx.intern_substs(&infer_substs),
1134+
)
1135+
}
1136+
_ => self.ty_to_value_string(ty.peel_refs()),
1137+
}
1138+
} else {
1139+
self.ty_to_value_string(rcvr_ty.peel_refs())
1140+
};
1141+
if let SelfSource::MethodCall(_) = source {
1142+
let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0)
1143+
&& let Some(assoc) = self.associated_value(*impl_did, item_name)
1144+
&& assoc.kind == ty::AssocKind::Fn
1145+
{
1146+
let sig = self.tcx.fn_sig(assoc.def_id);
1147+
if let Some(first) = sig.inputs().skip_binder().get(0) {
1148+
if first.peel_refs() == rcvr_ty.peel_refs() {
1149+
None
1150+
} else {
1151+
Some(if first.is_region_ptr() {
1152+
if first.is_mutable_ptr() { "&mut " } else { "&" }
1153+
} else {
1154+
""
1155+
})
1156+
}
1157+
} else {
1158+
None
1159+
}
1160+
} else {
1161+
None
1162+
};
1163+
let mut applicability = Applicability::MachineApplicable;
1164+
let args = if let Some((receiver, args)) = args {
1165+
// The first arg is the same kind as the receiver
1166+
let explicit_args = if first_arg.is_some() {
1167+
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
1168+
} else {
1169+
// There is no `Self` kind to infer the arguments from
1170+
if has_unsuggestable_args {
1171+
applicability = Applicability::HasPlaceholders;
1172+
}
1173+
args.iter().collect()
1174+
};
1175+
format!(
1176+
"({}{})",
1177+
first_arg.unwrap_or(""),
1178+
explicit_args
1179+
.iter()
1180+
.map(|arg| self
1181+
.tcx
1182+
.sess
1183+
.source_map()
1184+
.span_to_snippet(arg.span)
1185+
.unwrap_or_else(|_| {
1186+
applicability = Applicability::HasPlaceholders;
1187+
"_".to_owned()
1188+
}))
1189+
.collect::<Vec<_>>()
1190+
.join(", "),
1191+
)
1192+
} else {
1193+
applicability = Applicability::HasPlaceholders;
1194+
"(...)".to_owned()
1195+
};
1196+
err.span_suggestion(
1197+
sugg_span,
1198+
"use associated function syntax instead",
1199+
format!("{}::{}{}", ty_str, item_name, args),
1200+
applicability,
1201+
);
1202+
} else {
1203+
err.help(&format!("try with `{}::{}`", ty_str, item_name,));
1204+
}
1205+
}
1206+
11831207
/// Suggest calling a field with a type that implements the `Fn*` traits instead of a method with
11841208
/// the same name as the field i.e. `(a.my_fn_ptr)(10)` instead of `a.my_fn_ptr(10)`.
11851209
fn suggest_calling_field_as_fn(

0 commit comments

Comments
 (0)