1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use std::ops::Deref;

use rustc_errors::DiagCtxtHandle;
use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::PredicateObligation;
use rustc_macros::extension;
use rustc_middle::bug;
use rustc_middle::ty::{self, Ty};

use crate::error_reporting::infer::sub_relations;

pub mod infer;
pub mod traits;

/// A helper for building type related errors. The `typeck_results`
/// field is only populated during an in-progress typeck.
/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`.
///
/// You must only create this if you intend to actually emit an error (or
/// perhaps a warning, though preferably not.) It provides a lot of utility
/// methods which should not be used during the happy path.
pub struct TypeErrCtxt<'a, 'tcx> {
    pub infcx: &'a InferCtxt<'tcx>,
    pub sub_relations: std::cell::RefCell<sub_relations::SubRelations>,

    pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
    pub fallback_has_occurred: bool,

    pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,

    pub autoderef_steps:
        Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
}

#[extension(pub trait InferCtxtErrorExt<'tcx>)]
impl<'tcx> InferCtxt<'tcx> {
    /// Creates a `TypeErrCtxt` for emitting various inference errors.
    /// During typeck, use `FnCtxt::err_ctxt` instead.
    fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
        TypeErrCtxt {
            infcx: self,
            sub_relations: Default::default(),
            typeck_results: None,
            fallback_has_occurred: false,
            normalize_fn_sig: Box::new(|fn_sig| fn_sig),
            autoderef_steps: Box::new(|ty| {
                debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck");
                vec![(ty, vec![])]
            }),
        }
    }
}

impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
    pub fn dcx(&self) -> DiagCtxtHandle<'a> {
        self.infcx.dcx()
    }

    /// This is just to avoid a potential footgun of accidentally
    /// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
    #[deprecated(note = "you already have a `TypeErrCtxt`")]
    #[allow(unused)]
    pub fn err_ctxt(&self) -> ! {
        bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call");
    }
}

impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> {
    type Target = InferCtxt<'tcx>;
    fn deref(&self) -> &InferCtxt<'tcx> {
        self.infcx
    }
}