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::attrs::DivergingFallbackBehavior;
8use rustc_hir::def::{DefKind, Res};
9use rustc_hir::def_id::DefId;
10use rustc_hir::intravisit::{InferKind, Visitor};
11use rustc_hir::{self as hir, CRATE_HIR_ID, HirId};
12use rustc_lint::builtin::FLOAT_LITERAL_F32_FALLBACK;
13use rustc_middle::ty::{self, FloatVid, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
14use rustc_session::lint;
15use rustc_span::def_id::LocalDefId;
16use rustc_span::{DUMMY_SP, Span};
17use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt, 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 compiler/rustc_hir_typeck/src/fallback.rs:26",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("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 compiler/rustc_hir_typeck/src/fallback.rs:34",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("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 let (diverging_fallback, diverging_fallback_ty) = self.calculate_diverging_fallback();
75 let fallback_to_f32 = self.calculate_fallback_to_f32(&unresolved_float);
76
77 let mut fallback_occurred = false;
81
82 for vid in unresolved_ty {
83 fallback_occurred |= self.fallback_if_possible(
84 vid,
85 || {
86 diverging_fallback.contains(&vid).then(|| {
87 self.diverging_fallback_has_occurred.set(true);
88 diverging_fallback_ty
89 })
90 },
91 |vid| (Ty::new_var(self.tcx, vid), self.type_var_origin(vid).span),
92 );
93 }
94
95 for vid in unresolved_int {
96 fallback_occurred |= self.fallback_if_possible(
97 vid,
98 || Some(self.tcx.types.i32),
99 |vid| (Ty::new_int_var(self.tcx, vid), DUMMY_SP),
101 );
102 }
103
104 for vid in unresolved_float {
105 fallback_occurred |= self.fallback_if_possible(
106 vid,
107 || {
108 Some(if fallback_to_f32.contains(&vid) {
109 self.tcx.types.f32
110 } else {
111 self.tcx.types.f64
112 })
113 },
114 |vid| (Ty::new_float_var(self.tcx, vid), self.float_var_origin(vid).span),
115 );
116 }
117
118 fallback_occurred
119 }
120
121 fn fallback_if_possible<V>(
129 &self,
130 vid: V,
131 fallback: impl FnOnce() -> Option<Ty<'tcx>>,
132 vid_to_ty_and_span: impl FnOnce(V) -> (Ty<'tcx>, Span),
133 ) -> bool {
134 let fallback = if let Some(e) = self.tainted_by_errors() {
135 Ty::new_error(self.tcx, e)
136 } else if let Some(fallback) = fallback() {
137 fallback
138 } else {
139 return false;
140 };
141
142 let (ty, span) = vid_to_ty_and_span(vid);
143 self.demand_eqtype(span, ty, fallback);
144 true
145 }
146
147 fn calculate_fallback_to_f32(
161 &self,
162 unresolved_root_variables: &[ty::FloatVid],
163 ) -> UnordSet<FloatVid> {
164 if unresolved_root_variables.is_empty() {
170 return UnordSet::new();
171 }
172
173 let roots: UnordSet<ty::FloatVid> = self.from_float_for_f32_root_vids();
174 if roots.is_empty() {
175 return UnordSet::new();
178 }
179 let fallback_to_f32 = unresolved_root_variables
183 .iter()
184 .copied()
185 .filter(|&vid| roots.contains(&vid))
186 .inspect(|&vid| {
187 let origin = self.float_var_origin(vid);
188 let mut literal = self.tcx.sess.source_map().span_to_snippet(origin.span).ok();
190 if let Some(ref mut literal) = literal
192 && literal.ends_with('.')
193 {
194 literal.pop();
195 }
196 self.tcx.emit_node_span_lint(
197 FLOAT_LITERAL_F32_FALLBACK,
198 origin.lint_id.unwrap_or(CRATE_HIR_ID),
199 origin.span,
200 diagnostics::FloatLiteralF32Fallback {
201 span: literal.as_ref().map(|_| origin.span),
202 literal: literal.unwrap_or_default(),
203 },
204 );
205 })
206 .collect();
207 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fallback.rs:207",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
::tracing_core::__macro_support::Option::Some(207u32),
::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);
208 fallback_to_f32
209 }
210
211 fn calculate_diverging_fallback(&self) -> (UnordSet<ty::TyVid>, Ty<'tcx>) {
212 let diverging_fallback_ty = match self.diverging_fallback_behavior {
213 DivergingFallbackBehavior::ToUnit => self.tcx.types.unit,
214 DivergingFallbackBehavior::ToNever => self.tcx.types.never,
215 DivergingFallbackBehavior::NoFallback => {
216 return (UnordSet::new(), self.tcx.types.unit);
218 }
219 };
220
221 let diverging_root_vids: Vec<ty::TyVid> = self
228 .diverging_type_vars
229 .borrow()
230 .iter()
231 .filter_map(|&vid| self.infcx.shallow_resolve_ty_var_or_get_root(vid).err())
232 .collect();
233 {
234 let coercion_graph = self.create_coercion_graph();
237
238 self.lint_obligations_broken_by_never_type_fallback_change(
239 &diverging_root_vids,
240 &coercion_graph,
241 );
242
243 if !diverging_root_vids.is_empty() {
244 let unsafe_infer_vars = compute_unsafe_infer_vars(self, self.body_def_id);
245
246 for &root_vid in &diverging_root_vids {
247 self.lint_never_type_fallback_flowing_into_unsafe_code(
248 &unsafe_infer_vars,
249 &coercion_graph,
250 root_vid,
251 );
252 }
253 }
254 }
255
256 let diverging_fallback = diverging_root_vids.into_iter().collect::<UnordSet<_>>();
257
258 (diverging_fallback, diverging_fallback_ty)
259 }
260
261 fn lint_never_type_fallback_flowing_into_unsafe_code(
262 &self,
263 unsafe_infer_vars: &UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>,
264 coercion_graph: &VecGraph<ty::TyVid, true>,
265 root_vid: ty::TyVid,
266 ) {
267 let affected_unsafe_infer_vars =
268 graph::depth_first_search_as_undirected(&coercion_graph, root_vid)
269 .filter_map(|x| unsafe_infer_vars.get(&x).copied())
270 .collect::<Vec<_>>();
271
272 let sugg = self.try_to_suggest_annotations(&[root_vid], coercion_graph);
273
274 for (hir_id, span, reason) in affected_unsafe_infer_vars {
275 self.tcx.emit_node_span_lint(
276 lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
277 hir_id,
278 span,
279 match reason {
280 UnsafeUseReason::Call => {
281 diagnostics::NeverTypeFallbackFlowingIntoUnsafe::Call { sugg: sugg.clone() }
282 }
283 UnsafeUseReason::Method => {
284 diagnostics::NeverTypeFallbackFlowingIntoUnsafe::Method {
285 sugg: sugg.clone(),
286 }
287 }
288 UnsafeUseReason::Path => {
289 diagnostics::NeverTypeFallbackFlowingIntoUnsafe::Path { sugg: sugg.clone() }
290 }
291 UnsafeUseReason::UnionField => {
292 diagnostics::NeverTypeFallbackFlowingIntoUnsafe::UnionField {
293 sugg: sugg.clone(),
294 }
295 }
296 UnsafeUseReason::Deref => {
297 diagnostics::NeverTypeFallbackFlowingIntoUnsafe::Deref {
298 sugg: sugg.clone(),
299 }
300 }
301 },
302 );
303 }
304 }
305
306 fn lint_obligations_broken_by_never_type_fallback_change(
307 &self,
308 diverging_vids: &[ty::TyVid],
309 coercions: &VecGraph<ty::TyVid, true>,
310 ) {
311 let DivergingFallbackBehavior::ToUnit = self.diverging_fallback_behavior else { return };
312
313 if diverging_vids.is_empty() {
315 return;
316 }
317
318 let remaining_errors_if_fallback_to = |fallback| {
320 self.probe(|_| {
321 let obligations = self.fulfillment_cx.borrow().pending_obligations();
322 let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx);
323 ocx.register_obligations(obligations.iter().cloned());
324
325 for &diverging_vid in diverging_vids {
326 let diverging_ty = Ty::new_var(self.tcx, diverging_vid);
327
328 ocx.eq(&ObligationCause::dummy(), self.param_env, diverging_ty, fallback)
329 .expect("expected diverging var to be unconstrained");
330 }
331
332 ocx.try_evaluate_obligations()
333 })
334 };
335
336 let unit_errors = remaining_errors_if_fallback_to(self.tcx.types.unit);
339 if unit_errors.no_errors()
340 && let mut never_errors = remaining_errors_if_fallback_to(self.tcx.types.never)
341 && let [never_error, ..] = never_errors.as_mut_slice()
342 {
343 self.adjust_fulfillment_error_for_expr_obligation(never_error);
344 let sugg = self.try_to_suggest_annotations(diverging_vids, coercions);
345 self.tcx.emit_node_span_lint(
346 lint::builtin::DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK,
347 self.tcx.local_def_id_to_hir_id(self.body_def_id),
348 self.tcx.def_span(self.body_def_id),
349 diagnostics::DependencyOnUnitNeverTypeFallback {
350 obligation_span: never_error.obligation.cause.span,
351 obligation: never_error.obligation.predicate,
352 sugg,
353 },
354 )
355 }
356 }
357
358 fn create_coercion_graph(&self) -> VecGraph<ty::TyVid, true> {
361 let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations();
362 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fallback.rs:362",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
::tracing_core::__macro_support::Option::Some(362u32),
::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);
363 let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations
364 .into_iter()
365 .filter_map(|obligation| {
366 obligation.predicate.kind().no_bound_vars()
369 })
370 .filter_map(|atom| {
371 let (a, b) = match atom {
380 ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => (a, b),
381 ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
382 (a, b)
383 }
384 _ => return None,
385 };
386
387 let a_vid = self.root_vid(a)?;
388 let b_vid = self.root_vid(b)?;
389 Some((a_vid, b_vid))
390 })
391 .collect();
392 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fallback.rs:392",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
::tracing_core::__macro_support::Option::Some(392u32),
::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);
393 let num_ty_vars = self.num_ty_vars();
394
395 VecGraph::new(num_ty_vars, coercion_edges)
396 }
397
398 fn root_vid(&self, ty: Ty<'tcx>) -> Option<ty::TyVid> {
400 Some(self.root_var(self.shallow_resolve(ty).ty_vid()?))
401 }
402
403 pub(crate) fn root_float_vid(&self, ty: Ty<'tcx>) -> Option<ty::FloatVid> {
405 Some(self.root_float_var(self.shallow_resolve(ty).float_vid()?))
406 }
407
408 fn try_to_suggest_annotations(
411 &self,
412 diverging_vids: &[ty::TyVid],
413 coercions: &VecGraph<ty::TyVid, true>,
414 ) -> diagnostics::SuggestAnnotations {
415 let body = self.tcx.hir_body_owned_by(self.body_def_id);
416 let suggestions = diverging_vids
420 .iter()
421 .copied()
422 .filter_map(|vid| {
423 let reachable_vids =
424 graph::depth_first_search_as_undirected(coercions, vid).collect();
425 AnnotateUnitFallbackVisitor { reachable_vids, fcx: self }
426 .visit_expr(body.value)
427 .break_value()
428 })
429 .collect();
430 diagnostics::SuggestAnnotations { suggestions }
431 }
432}
433
434struct AnnotateUnitFallbackVisitor<'a, 'tcx> {
437 reachable_vids: FxHashSet<ty::TyVid>,
438 fcx: &'a FnCtxt<'a, 'tcx>,
439}
440impl<'tcx> AnnotateUnitFallbackVisitor<'_, 'tcx> {
441 fn suggest_for_segment(
447 &self,
448 arg_segment: &'tcx hir::PathSegment<'tcx>,
449 def_id: DefId,
450 id: HirId,
451 ) -> ControlFlow<diagnostics::SuggestAnnotation> {
452 if arg_segment.args.is_none()
453 && let Some(all_args) = self.fcx.typeck_results.borrow().node_args_opt(id)
454 && let generics = self.fcx.tcx.generics_of(def_id)
455 && let args = all_args[generics.parent_count..].iter().zip(&generics.own_params)
456 && 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))
458 {
459 let non_apit_type_args = args.filter(|(_, param)| {
461 #[allow(non_exhaustive_omitted_patterns)] match param.kind {
ty::GenericParamDefKind::Type { synthetic: false, .. } => true,
_ => false,
}matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: false, .. })
462 });
463 let n_tys = non_apit_type_args.clone().count();
464 for (idx, (arg, _)) in non_apit_type_args.enumerate() {
465 if let Some(ty) = arg.as_type()
466 && let Some(vid) = self.fcx.root_vid(ty)
467 && self.reachable_vids.contains(&vid)
468 {
469 return ControlFlow::Break(diagnostics::SuggestAnnotation::Turbo(
470 arg_segment.ident.span.shrink_to_hi(),
471 n_tys,
472 idx,
473 ));
474 }
475 }
476 }
477 ControlFlow::Continue(())
478 }
479}
480impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
481 type Result = ControlFlow<diagnostics::SuggestAnnotation>;
482
483 fn visit_infer(
484 &mut self,
485 inf_id: HirId,
486 inf_span: Span,
487 _kind: InferKind<'tcx>,
488 ) -> Self::Result {
489 if let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(inf_id)
491 && let Some(vid) = self.fcx.root_vid(ty)
492 && self.reachable_vids.contains(&vid)
493 && inf_span.can_be_used_for_suggestions()
494 {
495 return ControlFlow::Break(diagnostics::SuggestAnnotation::Unit(inf_span));
496 }
497
498 ControlFlow::Continue(())
499 }
500
501 fn visit_qpath(
502 &mut self,
503 qpath: &'tcx rustc_hir::QPath<'tcx>,
504 id: HirId,
505 span: Span,
506 ) -> Self::Result {
507 let arg_segment = match qpath {
508 hir::QPath::Resolved(_, path) => {
509 path.segments.last().expect("paths should have a segment")
510 }
511 hir::QPath::TypeRelative(_, segment) => segment,
512 };
513 if let Some(def_id) = self.fcx.typeck_results.borrow().qpath_res(qpath, id).opt_def_id()
515 && span.can_be_used_for_suggestions()
516 {
517 self.suggest_for_segment(arg_segment, def_id, id)?;
518 }
519 hir::intravisit::walk_qpath(self, qpath, id)
520 }
521
522 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
523 if let hir::ExprKind::Closure(&hir::Closure { body, .. })
524 | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) = expr.kind
525 {
526 self.visit_body(self.fcx.tcx.hir_body(body))?;
527 }
528
529 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
532 && let Res::Def(DefKind::AssocFn, def_id) = path.res
533 && self.fcx.tcx.trait_of_assoc(def_id).is_some()
534 && let Some(args) = self.fcx.typeck_results.borrow().node_args_opt(expr.hir_id)
535 && let self_ty = args.type_at(0)
536 && let Some(vid) = self.fcx.root_vid(self_ty)
537 && self.reachable_vids.contains(&vid)
538 && let [.., trait_segment, _method_segment] = path.segments
539 && expr.span.can_be_used_for_suggestions()
540 {
541 let span = path.span.shrink_to_lo().to(trait_segment.ident.span);
542 return ControlFlow::Break(diagnostics::SuggestAnnotation::Path(span));
543 }
544
545 if let hir::ExprKind::MethodCall(segment, ..) = expr.kind
547 && let Some(def_id) =
548 self.fcx.typeck_results.borrow().type_dependent_def_id(expr.hir_id)
549 && expr.span.can_be_used_for_suggestions()
550 {
551 self.suggest_for_segment(segment, def_id, expr.hir_id)?;
552 }
553
554 hir::intravisit::walk_expr(self, expr)
555 }
556
557 fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) -> Self::Result {
558 if let hir::LocalSource::Normal = local.source
560 && let None = local.ty
561 && let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(local.hir_id)
562 && let Some(vid) = self.fcx.root_vid(ty)
563 && self.reachable_vids.contains(&vid)
564 && local.span.can_be_used_for_suggestions()
565 {
566 return ControlFlow::Break(diagnostics::SuggestAnnotation::Local(
567 local.pat.span.shrink_to_hi(),
568 ));
569 }
570 hir::intravisit::walk_local(self, local)
571 }
572}
573
574#[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]
impl ::core::clone::Clone for UnsafeUseReason {
#[inline]
fn clone(&self) -> UnsafeUseReason { *self }
}Clone)]
575pub(crate) enum UnsafeUseReason {
576 Call,
577 Method,
578 Path,
579 UnionField,
580 Deref,
581}
582
583fn compute_unsafe_infer_vars<'a, 'tcx>(
600 fcx: &'a FnCtxt<'a, 'tcx>,
601 body_def_id: LocalDefId,
602) -> UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)> {
603 let body = fcx.tcx.hir_body_owned_by(body_def_id);
604 let mut res = UnordMap::default();
605
606 struct UnsafeInferVarsVisitor<'a, 'tcx> {
607 fcx: &'a FnCtxt<'a, 'tcx>,
608 res: &'a mut UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>,
609 }
610
611 impl Visitor<'_> for UnsafeInferVarsVisitor<'_, '_> {
612 fn visit_expr(&mut self, ex: &'_ hir::Expr<'_>) {
613 let typeck_results = self.fcx.typeck_results.borrow();
614
615 match ex.kind {
616 hir::ExprKind::MethodCall(..) => {
617 if let Some(def_id) = typeck_results.type_dependent_def_id(ex.hir_id)
618 && let method_ty =
619 self.fcx.tcx.type_of(def_id).instantiate_identity().skip_norm_wip()
620 && let sig = method_ty.fn_sig(self.fcx.tcx)
621 && sig.safety().is_unsafe()
622 {
623 let mut collector = InferVarCollector {
624 value: (ex.hir_id, ex.span, UnsafeUseReason::Method),
625 res: self.res,
626 };
627
628 typeck_results
630 .node_args(ex.hir_id)
631 .types()
632 .for_each(|t| t.visit_with(&mut collector));
633 }
634 }
635
636 hir::ExprKind::Call(func, ..) => {
637 let func_ty = typeck_results.expr_ty(func);
638
639 if func_ty.is_fn()
640 && let sig = func_ty.fn_sig(self.fcx.tcx)
641 && sig.safety().is_unsafe()
642 {
643 let mut collector = InferVarCollector {
644 value: (ex.hir_id, ex.span, UnsafeUseReason::Call),
645 res: self.res,
646 };
647
648 typeck_results
653 .node_args(func.hir_id)
654 .types()
655 .for_each(|t| t.visit_with(&mut collector));
656
657 sig.output().visit_with(&mut collector);
659 }
660 }
661
662 hir::ExprKind::Path(_) => {
666 let ty = typeck_results.expr_ty(ex);
667
668 if ty.is_fn()
671 && let sig = ty.fn_sig(self.fcx.tcx)
672 && sig.safety().is_unsafe()
673 {
674 let mut collector = InferVarCollector {
675 value: (ex.hir_id, ex.span, UnsafeUseReason::Path),
676 res: self.res,
677 };
678
679 typeck_results
681 .node_args(ex.hir_id)
682 .types()
683 .for_each(|t| t.visit_with(&mut collector));
684 }
685 }
686
687 hir::ExprKind::Unary(hir::UnOp::Deref, pointer) => {
688 if let ty::RawPtr(pointee, _) = typeck_results.expr_ty(pointer).kind() {
689 pointee.visit_with(&mut InferVarCollector {
690 value: (ex.hir_id, ex.span, UnsafeUseReason::Deref),
691 res: self.res,
692 });
693 }
694 }
695
696 hir::ExprKind::Field(base, _) => {
697 let base_ty = typeck_results.expr_ty(base);
698
699 if base_ty.is_union() {
700 typeck_results.expr_ty(ex).visit_with(&mut InferVarCollector {
701 value: (ex.hir_id, ex.span, UnsafeUseReason::UnionField),
702 res: self.res,
703 });
704 }
705 }
706
707 _ => (),
708 };
709
710 hir::intravisit::walk_expr(self, ex);
711 }
712 }
713
714 struct InferVarCollector<'r, V> {
715 value: V,
716 res: &'r mut UnordMap<ty::TyVid, V>,
717 }
718
719 impl<'tcx, V: Copy> ty::TypeVisitor<TyCtxt<'tcx>> for InferVarCollector<'_, V> {
720 fn visit_ty(&mut self, t: Ty<'tcx>) {
721 if let Some(vid) = t.ty_vid() {
722 _ = self.res.try_insert(vid, self.value);
723 } else {
724 t.super_visit_with(self)
725 }
726 }
727 }
728
729 UnsafeInferVarsVisitor { fcx, res: &mut res }.visit_expr(&body.value);
730
731 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fallback.rs:731",
"rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
::tracing_core::__macro_support::Option::Some(731u32),
::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:?}");
732
733 res
734}