1use std::ops::ControlFlow;
2
3use rustc_data_structures::fx::FxHashSet;
4use rustc_data_structures::graph;
5use rustc_data_structures::graph::vec_graph::VecGraph;
6use rustc_data_structures::unord::{UnordMap, UnordSet};
7use rustc_hir::def::{DefKind, Res};
8use rustc_hir::def_id::DefId;
9use rustc_hir::intravisit::{InferKind, Visitor};
10use rustc_hir::{self as hir, CRATE_HIR_ID, HirId};
11use rustc_lint_defs::builtin::{
12 FLOAT_LITERAL_F32_FALLBACK, NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
13};
14use rustc_middle::ty::{self, FloatVid, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
15use rustc_span::def_id::LocalDefId;
16use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
17use rustc_trait_selection::traits::TraitEngine;
18use tracing::debug;
19
20use crate::{FnCtxt, diagnostics};
21
22impl<'tcx> FnCtxt<'_, 'tcx> {
23 pub(super) fn type_inference_fallback(&self) {
26 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs:26",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs"),
::tracing_core::__macro_support::Option::Some(26u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("type-inference-fallback start obligations: {0:#?}",
self.fulfillment_cx.borrow_mut().pending_obligations()) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(
27 "type-inference-fallback start obligations: {:#?}",
28 self.fulfillment_cx.borrow_mut().pending_obligations()
29 );
30
31 self.select_obligations_where_possible(|_| {});
33
34 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs:34",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs"),
::tracing_core::__macro_support::Option::Some(34u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("type-inference-fallback post selection obligations: {0:#?}",
self.fulfillment_cx.borrow_mut().pending_obligations()) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(
35 "type-inference-fallback post selection obligations: {:#?}",
36 self.fulfillment_cx.borrow_mut().pending_obligations()
37 );
38
39 let fallback_occurred = self.fallback_types();
40
41 if fallback_occurred {
42 self.select_obligations_where_possible(|_| {});
44 }
45 }
46
47 fn fallback_types(&self) -> bool {
67 let (unresolved_ty, unresolved_int, unresolved_float) = self.unresolved_root_variables();
68
69 if unresolved_ty.is_empty() && unresolved_int.is_empty() && unresolved_float.is_empty() {
71 return false;
72 }
73
74 if let Some(guar) = self.tainted_by_errors() {
77 self.fallback_types_to_error(guar, unresolved_ty, unresolved_int, unresolved_float);
78 return true;
79 }
80
81 let diverging_fallback = self.calculate_diverging_fallback();
82 let fallback_to_f32 = self.calculate_fallback_to_f32(&unresolved_float);
83
84 let mut fallback_occurred = !unresolved_int.is_empty() || !unresolved_float.is_empty();
87
88 for &vid in unresolved_ty.iter().filter(|&vid| diverging_fallback.contains(vid)) {
89 let span = self.type_var_origin(vid).span;
90 self.demand_eqtype(span, Ty::new_var(self.tcx, vid), self.tcx.types.never);
91
92 self.diverging_fallback_has_occurred.set(true);
93 fallback_occurred = true;
94 }
95
96 for vid in unresolved_int {
97 self.demand_eqtype(DUMMY_SP, Ty::new_int_var(self.tcx, vid), self.tcx.types.i32);
98 }
99
100 for vid in unresolved_float {
101 let fallback = if fallback_to_f32.contains(&vid) {
102 self.tcx.types.f32
103 } else {
104 self.tcx.types.f64
105 };
106 let span = self.float_var_origin(vid).span;
107 self.demand_eqtype(span, Ty::new_float_var(self.tcx, vid), fallback);
108 }
109
110 fallback_occurred
111 }
112
113 fn fallback_types_to_error(
114 &self,
115 guar: ErrorGuaranteed,
116 unresolved_ty: Vec<ty::TyVid>,
117 unresolved_int: Vec<ty::IntVid>,
118 unresolved_float: Vec<ty::FloatVid>,
119 ) {
120 let vars = unresolved_ty
121 .into_iter()
122 .map(|vid| Ty::new_var(self.tcx, vid))
123 .chain(unresolved_int.into_iter().map(|vid| Ty::new_int_var(self.tcx, vid)))
124 .chain(unresolved_float.into_iter().map(|vid| Ty::new_float_var(self.tcx, vid)));
125
126 let error = Ty::new_error(self.tcx, guar);
127
128 for var in vars {
129 self.demand_eqtype(DUMMY_SP, var, error);
130 }
131 }
132
133 fn calculate_fallback_to_f32(
147 &self,
148 unresolved_root_variables: &[ty::FloatVid],
149 ) -> UnordSet<FloatVid> {
150 if unresolved_root_variables.is_empty() {
156 return UnordSet::new();
157 }
158
159 let roots: UnordSet<ty::FloatVid> = self.from_float_for_f32_root_vids();
160 if roots.is_empty() {
161 return UnordSet::new();
164 }
165 let fallback_to_f32 = unresolved_root_variables
169 .iter()
170 .copied()
171 .filter(|&vid| roots.contains(&vid))
172 .inspect(|&vid| {
173 let origin = self.float_var_origin(vid);
174 let mut literal = self.tcx.sess.source_map().span_to_snippet(origin.span).ok();
176 if let Some(ref mut literal) = literal
178 && literal.ends_with('.')
179 {
180 literal.pop();
181 }
182 self.tcx.emit_node_span_lint(
183 FLOAT_LITERAL_F32_FALLBACK,
184 origin.lint_id.unwrap_or(CRATE_HIR_ID),
185 origin.span,
186 diagnostics::FloatLiteralF32Fallback {
187 span: literal.as_ref().map(|_| origin.span),
188 literal: literal.unwrap_or_default(),
189 },
190 );
191 })
192 .collect();
193 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs:193",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs"),
::tracing_core::__macro_support::Option::Some(193u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("calculate_fallback_to_f32: fallback_to_f32={0:?}",
fallback_to_f32) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("calculate_fallback_to_f32: fallback_to_f32={:?}", fallback_to_f32);
194 fallback_to_f32
195 }
196
197 fn calculate_diverging_fallback(&self) -> UnordSet<ty::TyVid> {
198 let diverging_root_vids: Vec<ty::TyVid> = self
204 .diverging_type_vars
205 .borrow()
206 .iter()
207 .filter_map(|&vid| self.infcx.shallow_resolve_ty_var_or_get_root(vid).err())
208 .collect();
209
210 {
211 if !diverging_root_vids.is_empty() {
212 let coercion_graph = self.create_coercion_graph();
215
216 let unsafe_infer_vars = compute_unsafe_infer_vars(self, self.body_def_id);
217
218 for &root_vid in &diverging_root_vids {
219 self.lint_never_type_fallback_flowing_into_unsafe_code(
220 &unsafe_infer_vars,
221 &coercion_graph,
222 root_vid,
223 );
224 }
225 }
226 }
227
228 diverging_root_vids.into_iter().collect::<UnordSet<_>>()
229 }
230
231 fn lint_never_type_fallback_flowing_into_unsafe_code(
232 &self,
233 unsafe_infer_vars: &UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>,
234 coercion_graph: &VecGraph<ty::TyVid, true>,
235 root_vid: ty::TyVid,
236 ) {
237 let affected_unsafe_infer_vars =
238 graph::depth_first_search_as_undirected(&coercion_graph, root_vid)
239 .filter_map(|x| unsafe_infer_vars.get(&x).copied())
240 .collect::<Vec<_>>();
241
242 let sugg = self.try_to_suggest_annotations(&[root_vid], coercion_graph);
243
244 for (hir_id, span, reason) in affected_unsafe_infer_vars {
245 self.tcx.emit_node_span_lint(
246 NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
247 hir_id,
248 span,
249 match reason {
250 UnsafeUseReason::Call => {
251 diagnostics::NeverTypeFallbackFlowingIntoUnsafe::Call { sugg: sugg.clone() }
252 }
253 UnsafeUseReason::Method => {
254 diagnostics::NeverTypeFallbackFlowingIntoUnsafe::Method {
255 sugg: sugg.clone(),
256 }
257 }
258 UnsafeUseReason::Path => {
259 diagnostics::NeverTypeFallbackFlowingIntoUnsafe::Path { sugg: sugg.clone() }
260 }
261 UnsafeUseReason::UnionField => {
262 diagnostics::NeverTypeFallbackFlowingIntoUnsafe::UnionField {
263 sugg: sugg.clone(),
264 }
265 }
266 UnsafeUseReason::Deref => {
267 diagnostics::NeverTypeFallbackFlowingIntoUnsafe::Deref {
268 sugg: sugg.clone(),
269 }
270 }
271 },
272 );
273 }
274 }
275
276 fn create_coercion_graph(&self) -> VecGraph<ty::TyVid, true> {
279 let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations();
280 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs:280",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs"),
::tracing_core::__macro_support::Option::Some(280u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("create_coercion_graph: pending_obligations={0:?}",
pending_obligations) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations);
281 let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations
282 .into_iter()
283 .filter_map(|obligation| {
284 obligation.predicate.kind().no_bound_vars()
287 })
288 .filter_map(|atom| {
289 let (a, b) = match atom {
298 ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => (a, b),
299 ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
300 (a, b)
301 }
302 _ => return None,
303 };
304
305 let a_vid = self.root_vid(a)?;
306 let b_vid = self.root_vid(b)?;
307 Some((a_vid, b_vid))
308 })
309 .collect();
310 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs:310",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs"),
::tracing_core::__macro_support::Option::Some(310u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("create_coercion_graph: coercion_edges={0:?}",
coercion_edges) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges);
311 let num_ty_vars = self.num_ty_vars();
312
313 VecGraph::new(num_ty_vars, coercion_edges)
314 }
315
316 fn root_vid(&self, ty: Ty<'tcx>) -> Option<ty::TyVid> {
318 Some(self.root_var(self.shallow_resolve(ty).ty_vid()?))
319 }
320
321 pub(crate) fn root_float_vid(&self, ty: Ty<'tcx>) -> Option<ty::FloatVid> {
323 Some(self.root_float_var(self.shallow_resolve(ty).float_vid()?))
324 }
325
326 fn try_to_suggest_annotations(
329 &self,
330 diverging_vids: &[ty::TyVid],
331 coercions: &VecGraph<ty::TyVid, true>,
332 ) -> diagnostics::SuggestAnnotations {
333 let body = self.tcx.hir_body_owned_by(self.body_def_id);
334 let suggestions = diverging_vids
338 .iter()
339 .copied()
340 .filter_map(|vid| {
341 let reachable_vids =
342 graph::depth_first_search_as_undirected(coercions, vid).collect();
343 AnnotateUnitFallbackVisitor { reachable_vids, fcx: self }
344 .visit_expr(body.value)
345 .break_value()
346 })
347 .collect();
348 diagnostics::SuggestAnnotations { suggestions }
349 }
350}
351
352struct AnnotateUnitFallbackVisitor<'a, 'tcx> {
355 reachable_vids: FxHashSet<ty::TyVid>,
356 fcx: &'a FnCtxt<'a, 'tcx>,
357}
358impl<'tcx> AnnotateUnitFallbackVisitor<'_, 'tcx> {
359 fn suggest_for_segment(
365 &self,
366 arg_segment: &'tcx hir::PathSegment<'tcx>,
367 def_id: DefId,
368 id: HirId,
369 ) -> ControlFlow<diagnostics::SuggestAnnotation> {
370 if arg_segment.args.is_none()
371 && let Some(all_args) = self.fcx.typeck_results.borrow().node_args_opt(id)
372 && let generics = self.fcx.tcx.generics_of(def_id)
373 && let args = all_args[generics.parent_count..].iter().zip(&generics.own_params)
374 && args.clone().all(|(_, param)| #[allow(non_exhaustive_omitted_patterns)] match param.kind {
ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Lifetime
=> true,
_ => false,
}matches!(param.kind, ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Lifetime))
376 {
377 let non_apit_type_args = args.filter(|(_, param)| {
379 #[allow(non_exhaustive_omitted_patterns)] match param.kind {
ty::GenericParamDefKind::Type { synthetic: false, .. } => true,
_ => false,
}matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: false, .. })
380 });
381 let n_tys = non_apit_type_args.clone().count();
382 for (idx, (arg, _)) in non_apit_type_args.enumerate() {
383 if let Some(ty) = arg.as_type()
384 && let Some(vid) = self.fcx.root_vid(ty)
385 && self.reachable_vids.contains(&vid)
386 {
387 return ControlFlow::Break(diagnostics::SuggestAnnotation::Turbo(
388 arg_segment.ident.span.shrink_to_hi(),
389 n_tys,
390 idx,
391 ));
392 }
393 }
394 }
395 ControlFlow::Continue(())
396 }
397}
398impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
399 type Result = ControlFlow<diagnostics::SuggestAnnotation>;
400
401 fn visit_infer(
402 &mut self,
403 inf_id: HirId,
404 inf_span: Span,
405 _kind: InferKind<'tcx>,
406 ) -> Self::Result {
407 if let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(inf_id)
409 && let Some(vid) = self.fcx.root_vid(ty)
410 && self.reachable_vids.contains(&vid)
411 && inf_span.can_be_used_for_suggestions()
412 {
413 return ControlFlow::Break(diagnostics::SuggestAnnotation::Unit(inf_span));
414 }
415
416 ControlFlow::Continue(())
417 }
418
419 fn visit_qpath(
420 &mut self,
421 qpath: &'tcx rustc_hir::QPath<'tcx>,
422 id: HirId,
423 span: Span,
424 ) -> Self::Result {
425 let arg_segment = match qpath {
426 hir::QPath::Resolved(_, path) => {
427 path.segments.last().expect("paths should have a segment")
428 }
429 hir::QPath::TypeRelative(_, segment) => segment,
430 };
431 if let Some(def_id) = self.fcx.typeck_results.borrow().qpath_res(qpath, id).opt_def_id()
433 && span.can_be_used_for_suggestions()
434 {
435 self.suggest_for_segment(arg_segment, def_id, id)?;
436 }
437 hir::intravisit::walk_qpath(self, qpath, id)
438 }
439
440 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
441 if let hir::ExprKind::Closure(&hir::Closure { body, .. })
442 | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) = expr.kind
443 {
444 self.visit_body(self.fcx.tcx.hir_body(body))?;
445 }
446
447 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
450 && let Res::Def(DefKind::AssocFn, def_id) = path.res
451 && self.fcx.tcx.trait_of_assoc(def_id).is_some()
452 && let Some(args) = self.fcx.typeck_results.borrow().node_args_opt(expr.hir_id)
453 && let self_ty = args.type_at(0)
454 && let Some(vid) = self.fcx.root_vid(self_ty)
455 && self.reachable_vids.contains(&vid)
456 && let [.., trait_segment, _method_segment] = path.segments
457 && expr.span.can_be_used_for_suggestions()
458 {
459 let span = path.span.shrink_to_lo().to(trait_segment.ident.span);
460 return ControlFlow::Break(diagnostics::SuggestAnnotation::Path(span));
461 }
462
463 if let hir::ExprKind::MethodCall(segment, ..) = expr.kind
465 && let Some(def_id) =
466 self.fcx.typeck_results.borrow().type_dependent_def_id(expr.hir_id)
467 && expr.span.can_be_used_for_suggestions()
468 {
469 self.suggest_for_segment(segment, def_id, expr.hir_id)?;
470 }
471
472 hir::intravisit::walk_expr(self, expr)
473 }
474
475 fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) -> Self::Result {
476 if let hir::LocalSource::Normal = local.source
478 && let None = local.ty
479 && let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(local.hir_id)
480 && let Some(vid) = self.fcx.root_vid(ty)
481 && self.reachable_vids.contains(&vid)
482 && local.span.can_be_used_for_suggestions()
483 {
484 return ControlFlow::Break(diagnostics::SuggestAnnotation::Local(
485 local.pat.span.shrink_to_hi(),
486 ));
487 }
488 hir::intravisit::walk_local(self, local)
489 }
490}
491
492#[derive(#[automatically_derived]
impl ::core::fmt::Debug for UnsafeUseReason {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
UnsafeUseReason::Call => "Call",
UnsafeUseReason::Method => "Method",
UnsafeUseReason::Path => "Path",
UnsafeUseReason::UnionField => "UnionField",
UnsafeUseReason::Deref => "Deref",
})
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for UnsafeUseReason { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for UnsafeUseReason { }
#[automatically_derived]
impl ::core::clone::Clone for UnsafeUseReason {
#[inline]
fn clone(&self) -> UnsafeUseReason { *self }
}Clone)]
493pub(crate) enum UnsafeUseReason {
494 Call,
495 Method,
496 Path,
497 UnionField,
498 Deref,
499}
500
501fn compute_unsafe_infer_vars<'a, 'tcx>(
518 fcx: &'a FnCtxt<'a, 'tcx>,
519 body_def_id: LocalDefId,
520) -> UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)> {
521 let body = fcx.tcx.hir_body_owned_by(body_def_id);
522 let mut res = UnordMap::default();
523
524 struct UnsafeInferVarsVisitor<'a, 'tcx> {
525 fcx: &'a FnCtxt<'a, 'tcx>,
526 res: &'a mut UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>,
527 }
528
529 impl Visitor<'_> for UnsafeInferVarsVisitor<'_, '_> {
530 fn visit_expr(&mut self, ex: &'_ hir::Expr<'_>) {
531 let typeck_results = self.fcx.typeck_results.borrow();
532
533 match ex.kind {
534 hir::ExprKind::MethodCall(..) => {
535 if let Some(def_id) = typeck_results.type_dependent_def_id(ex.hir_id)
536 && let method_ty =
537 self.fcx.tcx.type_of(def_id).instantiate_identity().skip_norm_wip()
538 && let sig = method_ty.fn_sig(self.fcx.tcx)
539 && sig.safety().is_unsafe()
540 {
541 let mut collector = InferVarCollector {
542 value: (ex.hir_id, ex.span, UnsafeUseReason::Method),
543 res: self.res,
544 };
545
546 typeck_results
548 .node_args(ex.hir_id)
549 .types()
550 .for_each(|t| t.visit_with(&mut collector));
551 }
552 }
553
554 hir::ExprKind::Call(func, ..) => {
555 let func_ty = typeck_results.expr_ty(func);
556
557 if func_ty.is_fn()
558 && let sig = func_ty.fn_sig(self.fcx.tcx)
559 && sig.safety().is_unsafe()
560 {
561 let mut collector = InferVarCollector {
562 value: (ex.hir_id, ex.span, UnsafeUseReason::Call),
563 res: self.res,
564 };
565
566 typeck_results
571 .node_args(func.hir_id)
572 .types()
573 .for_each(|t| t.visit_with(&mut collector));
574
575 sig.output().visit_with(&mut collector);
577 }
578 }
579
580 hir::ExprKind::Path(_) => {
584 let ty = typeck_results.expr_ty(ex);
585
586 if ty.is_fn()
589 && let sig = ty.fn_sig(self.fcx.tcx)
590 && sig.safety().is_unsafe()
591 {
592 let mut collector = InferVarCollector {
593 value: (ex.hir_id, ex.span, UnsafeUseReason::Path),
594 res: self.res,
595 };
596
597 typeck_results
599 .node_args(ex.hir_id)
600 .types()
601 .for_each(|t| t.visit_with(&mut collector));
602 }
603 }
604
605 hir::ExprKind::Unary(hir::UnOp::Deref, pointer) => {
606 if let ty::RawPtr(pointee, _) = typeck_results.expr_ty(pointer).kind() {
607 pointee.visit_with(&mut InferVarCollector {
608 value: (ex.hir_id, ex.span, UnsafeUseReason::Deref),
609 res: self.res,
610 });
611 }
612 }
613
614 hir::ExprKind::Field(base, _) => {
615 let base_ty = typeck_results.expr_ty(base);
616
617 if base_ty.is_union() {
618 typeck_results.expr_ty(ex).visit_with(&mut InferVarCollector {
619 value: (ex.hir_id, ex.span, UnsafeUseReason::UnionField),
620 res: self.res,
621 });
622 }
623 }
624
625 _ => (),
626 };
627
628 hir::intravisit::walk_expr(self, ex);
629 }
630 }
631
632 struct InferVarCollector<'r, V> {
633 value: V,
634 res: &'r mut UnordMap<ty::TyVid, V>,
635 }
636
637 impl<'tcx, V: Copy> ty::TypeVisitor<TyCtxt<'tcx>> for InferVarCollector<'_, V> {
638 fn visit_ty(&mut self, t: Ty<'tcx>) {
639 if let Some(vid) = t.ty_vid() {
640 _ = self.res.try_insert(vid, self.value);
641 } else {
642 t.super_visit_with(self)
643 }
644 }
645 }
646
647 UnsafeInferVarsVisitor { fcx, res: &mut res }.visit_expr(&body.value);
648
649 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs:649",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_hir_typeck/src/fallback.rs"),
::tracing_core::__macro_support::Option::Some(649u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
::tracing_core::field::FieldSet::new(&["message",
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("res")
}> =
::tracing::__macro_support::FieldName::new("res");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("collected the following unsafe vars for {0:?}",
body_def_id) as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&res)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(?res, "collected the following unsafe vars for {body_def_id:?}");
650
651 res
652}