input_output.rs 8.5 KB
Newer Older
1 2 3
//! This module contains code to equate the input/output types appearing
//! in the MIR with the expected input/output types from the function
//! signature. This requires a bit of processing, as the expected types
V
varkor 已提交
4
//! are supplied to us before normalization and may contain opaque
5 6
//! `impl Trait` instances. In contrast, the input/output types found in
//! the MIR (specifically, in the special local variables for the
7
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
8 9
//! contain revealed `impl Trait` values).

10
use rustc_index::vec::Idx;
11
use rustc_infer::infer::LateBoundRegionConversionTime;
M
Mazdak Farrokhzad 已提交
12
use rustc_middle::mir::*;
13 14
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, Ty};
15
use rustc_span::Span;
16
use rustc_trait_selection::traits::query::normalize::AtExt;
17

18
use crate::universal_regions::UniversalRegions;
M
Mark Mansi 已提交
19

20
use super::{Locations, TypeChecker};
21

22
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
23 24
    pub(super) fn equate_inputs_and_outputs(
        &mut self,
25
        body: &Body<'tcx>,
26
        universal_regions: &UniversalRegions<'tcx>,
27
        normalized_inputs_and_output: &[Ty<'tcx>],
28
    ) {
29 30
        let (&normalized_output_ty, normalized_input_tys) =
            normalized_inputs_and_output.split_last().unwrap();
31

32 33
        let mir_def_id = body.source.def_id().expect_local();

N
Niko Matsakis 已提交
34 35 36
        // If the user explicitly annotated the input types, extract
        // those.
        //
37
        // e.g., `|x: FxHashMap<_, &'static u32>| ...`
N
Niko Matsakis 已提交
38
        let user_provided_sig;
39
        if !self.tcx().is_closure(mir_def_id.to_def_id()) {
N
Niko Matsakis 已提交
40 41
            user_provided_sig = None;
        } else {
42
            let typeck_results = self.tcx().typeck(mir_def_id);
43 44
            user_provided_sig = typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()).map(
                |user_provided_poly_sig| {
45 46 47
                    // Instantiate the canonicalized variables from
                    // user-provided signature (e.g., the `_` in the code
                    // above) with fresh variables.
48
                    let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
49 50 51 52 53 54 55
                        body.span,
                        &user_provided_poly_sig,
                    );

                    // Replace the bound items in the fn sig with fresh
                    // variables, so that they represent the view from
                    // "inside" the closure.
56 57 58 59 60 61 62 63 64 65
                    self.infcx
                        .replace_bound_vars_with_fresh_vars(
                            body.span,
                            LateBoundRegionConversionTime::FnCall,
                            poly_sig,
                        )
                        .0
                },
            );
        }
N
Niko Matsakis 已提交
66

67 68 69 70 71
        debug!(
            "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}",
            normalized_input_tys, body.local_decls
        );

72
        // Equate expected input tys with those in the MIR.
D
Dániel Buga 已提交
73
        for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
74 75 76 77 78 79
            if argument_index + 1 >= body.local_decls.len() {
                self.tcx()
                    .sess
                    .delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
                break;
            }
N
Niko Matsakis 已提交
80 81 82
            // In MIR, argument N is stored in local N+1.
            let local = Local::new(argument_index + 1);

83 84
            let mir_input_ty = body.local_decls[local].ty;
            let mir_input_span = body.local_decls[local].source_info.span;
85 86 87 88 89
            self.equate_normalized_input_or_output(
                normalized_input_ty,
                mir_input_ty,
                mir_input_span,
            );
90 91
        }

N
Niko Matsakis 已提交
92
        if let Some(user_provided_sig) = user_provided_sig {
D
Dániel Buga 已提交
93 94
            for (argument_index, &user_provided_input_ty) in
                user_provided_sig.inputs().iter().enumerate()
N
Niko Matsakis 已提交
95 96 97 98
            {
                // In MIR, closures begin an implicit `self`, so
                // argument N is stored in local N+2.
                let local = Local::new(argument_index + 2);
99 100
                let mir_input_ty = body.local_decls[local].ty;
                let mir_input_span = body.local_decls[local].source_info.span;
N
Niko Matsakis 已提交
101 102 103 104 105 106 107 108 109 110 111 112

                // If the user explicitly annotated the input types, enforce those.
                let user_provided_input_ty =
                    self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
                self.equate_normalized_input_or_output(
                    user_provided_input_ty,
                    mir_input_ty,
                    mir_input_span,
                );
            }
        }

D
Dániel Buga 已提交
113 114
        assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some());
        if let Some(mir_yield_ty) = body.yield_ty() {
115
            let ur_yield_ty = universal_regions.yield_ty.unwrap();
116
            let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
117
            self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
118 119
        }

V
varkor 已提交
120
        // Return types are a bit more complex. They may contain opaque `impl Trait` types.
121 122
        let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
        let output_span = body.local_decls[RETURN_PLACE].source_info.span;
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
        if let Err(terr) = self.eq_opaque_type_and_type(
            mir_output_ty,
            normalized_output_ty,
            Locations::All(output_span),
            ConstraintCategory::BoringNoLocation,
        ) {
            span_mirbug!(
                self,
                Location::START,
                "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                normalized_output_ty,
                mir_output_ty,
                terr
            );
        };
N
Niko Matsakis 已提交
138 139

        // If the user explicitly annotated the output types, enforce those.
140
        // Note that this only happens for closures.
N
Niko Matsakis 已提交
141 142 143 144
        if let Some(user_provided_sig) = user_provided_sig {
            let user_provided_output_ty = user_provided_sig.output();
            let user_provided_output_ty =
                self.normalize(user_provided_output_ty, Locations::All(output_span));
145
            if let Err(err) = self.eq_opaque_type_and_type(
N
Niko Matsakis 已提交
146
                mir_output_ty,
147 148
                user_provided_output_ty,
                Locations::All(output_span),
M
Mark Rousskov 已提交
149
                ConstraintCategory::BoringNoLocation,
150 151 152 153 154 155 156 157 158 159
            ) {
                span_mirbug!(
                    self,
                    Location::START,
                    "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                    mir_output_ty,
                    user_provided_output_ty,
                    err
                );
            }
N
Niko Matsakis 已提交
160
        }
161 162
    }

163
    fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
164 165
        debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);

J
jackh726 已提交
166
        if let Err(_) =
M
Mark Rousskov 已提交
167 168
            self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
        {
J
jackh726 已提交
169 170
            // FIXME(jackh726): This is a hack. It's somewhat like
            // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
J
jackh726 已提交
171 172
            // like to normalize *before* inserting into `local_decls`, but
            // doing so ends up causing some other trouble.
J
jackh726 已提交
173 174 175 176 177 178 179 180 181 182 183
            let b = match self
                .infcx
                .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
                .normalize(b)
            {
                Ok(n) => {
                    debug!("equate_inputs_and_outputs: {:?}", n);
                    if n.obligations.iter().all(|o| {
                        matches!(
                            o.predicate.kind().skip_binder(),
                            ty::PredicateKind::RegionOutlives(_)
J
jackh726 已提交
184
                                | ty::PredicateKind::TypeOutlives(_)
J
jackh726 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
                        )
                    }) {
                        n.value
                    } else {
                        b
                    }
                }
                Err(_) => {
                    debug!("equate_inputs_and_outputs: NoSolution");
                    b
                }
            };
            if let Err(terr) =
                self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
            {
                span_mirbug!(
                    self,
                    Location::START,
                    "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
                    a,
                    b,
                    terr
                );
            }
209 210 211
        }
    }
}