]>
Commit | Line | Data |
---|---|---|
487cf647 FG |
1 | //! Routines to check for relations between fully inferred types. |
2 | //! | |
3 | //! FIXME: Move this to a more general place. The utility of this extends to | |
4 | //! other areas of the compiler as well. | |
5 | ||
6 | use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; | |
7 | use rustc_infer::traits::ObligationCause; | |
8 | use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; | |
9 | use rustc_trait_selection::traits::ObligationCtxt; | |
10 | ||
11 | /// Returns whether the two types are equal up to subtyping. | |
12 | /// | |
13 | /// This is used in case we don't know the expected subtyping direction | |
14 | /// and still want to check whether anything is broken. | |
15 | pub fn is_equal_up_to_subtyping<'tcx>( | |
16 | tcx: TyCtxt<'tcx>, | |
17 | param_env: ParamEnv<'tcx>, | |
18 | src: Ty<'tcx>, | |
19 | dest: Ty<'tcx>, | |
20 | ) -> bool { | |
21 | // Fast path. | |
22 | if src == dest { | |
23 | return true; | |
24 | } | |
25 | ||
26 | // Check for subtyping in either direction. | |
27 | is_subtype(tcx, param_env, src, dest) || is_subtype(tcx, param_env, dest, src) | |
28 | } | |
29 | ||
30 | /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. | |
31 | /// | |
32 | /// This mostly ignores opaque types as it can be used in constraining contexts | |
33 | /// while still computing the final underlying type. | |
34 | pub fn is_subtype<'tcx>( | |
35 | tcx: TyCtxt<'tcx>, | |
36 | param_env: ParamEnv<'tcx>, | |
37 | src: Ty<'tcx>, | |
38 | dest: Ty<'tcx>, | |
39 | ) -> bool { | |
40 | if src == dest { | |
41 | return true; | |
42 | } | |
43 | ||
44 | let mut builder = | |
45 | tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble); | |
46 | let infcx = builder.build(); | |
47 | let ocx = ObligationCtxt::new(&infcx); | |
48 | let cause = ObligationCause::dummy(); | |
49 | let src = ocx.normalize(&cause, param_env, src); | |
50 | let dest = ocx.normalize(&cause, param_env, dest); | |
51 | match ocx.sub(&cause, param_env, src, dest) { | |
52 | Ok(()) => {} | |
53 | Err(_) => return false, | |
54 | }; | |
55 | let errors = ocx.select_all_or_error(); | |
56 | // With `Reveal::All`, opaque types get normalized away, with `Reveal::UserFacing` | |
57 | // we would get unification errors because we're unable to look into opaque types, | |
58 | // even if they're constrained in our current function. | |
59 | // | |
60 | // It seems very unlikely that this hides any bugs. | |
61 | let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); | |
62 | errors.is_empty() | |
63 | } |