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