From bf51840952b701606fa6aa5e076b4e27fb8d9ee8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 Oct 2018 16:36:31 -0400 Subject: [PATCH] distinguish user-type annotations from other annotations In particular, we don't want to preserve the universes for the `'_` variables that appear in there. And we don't expect to find any placeholders, which justifies this as harmless. (In particular, if you have a query like `Foo(!1, !2, ?3)`, then you care about the universe of `?3`, since it may control whether `?3 = !1` and `?3 = !2` is a valid answer. But without any placeholders, we don't really care: any placeholders that would appear in the output must therefore come from some fresh universe anyway.) --- src/librustc/infer/canonical/canonicalizer.rs | 37 +++++++++++++++++++ src/librustc_typeck/check/mod.rs | 6 +-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 94bb17988c7c2..cc6e4df071033 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -107,6 +107,20 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { ) } + pub fn canonicalize_user_type_annotation(&self, value: &V) -> Canonicalized<'gcx, V> + where + V: TypeFoldable<'tcx> + Lift<'gcx>, + { + let mut query_state = OriginalQueryValues::default(); + Canonicalizer::canonicalize( + value, + Some(self), + self.tcx, + &CanonicalizeUserTypeAnnotation, + &mut query_state, + ) + } + /// A hacky variant of `canonicalize_query` that does not /// canonicalize `'static`. Unfortunately, the existing leak /// check treaks `'static` differently in some cases (see also @@ -197,6 +211,29 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse { } } +struct CanonicalizeUserTypeAnnotation; + +impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation { + fn canonicalize_free_region( + &self, + canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>, + r: ty::Region<'tcx>, + ) -> ty::Region<'tcx> { + match r { + ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReEmpty | ty::ReStatic => r, + ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r), + _ => { + // We only expect region names that the user can type. + bug!("unexpected region in query response: `{:?}`", r) + } + } + } + + fn any(&self) -> bool { + false + } +} + struct CanonicalizeAllFreeRegions; impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7e25694d5598f..8bd4887fa7c20 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -976,7 +976,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { o_ty }; - let c_ty = self.fcx.inh.infcx.canonicalize_response(&revealed_ty); + let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(&revealed_ty); debug!("visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", ty.hir_id, o_ty, revealed_ty, c_ty); self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); @@ -2137,7 +2137,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { method.substs[i] } }); - self.infcx.canonicalize_response(&UserSubsts { + self.infcx.canonicalize_user_type_annotation(&UserSubsts { substs: just_method_substs, user_self_ty: None, // not relevant here }) @@ -2181,7 +2181,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ); if !substs.is_noop() { - let user_substs = self.infcx.canonicalize_response(&UserSubsts { + let user_substs = self.infcx.canonicalize_user_type_annotation(&UserSubsts { substs, user_self_ty, });