Skip to content

Commit

Permalink
Handle type annotations in promoted MIR correctly
Browse files Browse the repository at this point in the history
Type annotations are shared between the MIR of a function and the
promoted constants for that function, so keep them in the type checker
when we check the promoted MIR.
  • Loading branch information
matthewjasper committed Mar 1, 2019
1 parent 848c252 commit 3b93d71
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 15 deletions.
32 changes: 17 additions & 15 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Expand Up @@ -39,7 +39,8 @@ use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::{Subst, SubstsRef, UnpackedKind, UserSubsts};
use rustc::ty::{
self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserType,
CanonicalUserTypeAnnotation, UserTypeAnnotationIndex,
CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
UserTypeAnnotationIndex,
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
Expand Down Expand Up @@ -283,7 +284,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
location.to_locations(),
ConstraintCategory::Boring,
) {
let annotation = &self.mir.user_type_annotations[annotation_index];
let annotation = &self.cx.user_type_annotations[annotation_index];
span_mirbug!(
self,
constant,
Expand Down Expand Up @@ -550,8 +551,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
// checker on the promoted MIR, then transfer the constraints back to
// the main MIR, changing the locations to the provided location.

let main_mir = mem::replace(&mut self.mir, promoted_mir);
self.cx.mir = promoted_mir;
let parent_mir = mem::replace(&mut self.mir, promoted_mir);

let all_facts = &mut None;
let mut constraints = Default::default();
Expand All @@ -573,8 +573,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
self.cx.typeck_mir(promoted_mir);
}

self.mir = main_mir;
self.cx.mir = main_mir;
self.mir = parent_mir;
// Merge the outlives constraints back in, at the given location.
if let Some(ref mut base_bcx) = self.cx.borrowck_context {
mem::swap(base_bcx.all_facts, all_facts);
Expand Down Expand Up @@ -818,7 +817,9 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'gcx>,
last_span: Span,
mir: &'a Mir<'tcx>,
/// User type annotations are shared between the main MIR and the MIR of
/// all of the promoted items.
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
mir_def_id: DefId,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: Option<ty::Region<'tcx>>,
Expand Down Expand Up @@ -973,8 +974,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
let mut checker = Self {
infcx,
last_span: DUMMY_SP,
mir,
mir_def_id,
user_type_annotations: &mir.user_type_annotations,
param_env,
region_bound_pairs,
implicit_region_bound,
Expand All @@ -990,9 +991,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
fn check_user_type_annotations(&mut self) {
debug!(
"check_user_type_annotations: user_type_annotations={:?}",
self.mir.user_type_annotations
self.user_type_annotations
);
for user_annotation in &self.mir.user_type_annotations {
for user_annotation in self.user_type_annotations {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
let (annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
span, user_ty
Expand Down Expand Up @@ -1175,7 +1176,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
a, v, user_ty, locations,
);

let annotated_type = self.mir.user_type_annotations[user_ty.base].inferred_ty;
let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);

let tcx = self.infcx.tcx;
Expand Down Expand Up @@ -1361,7 +1362,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
location.to_locations(),
ConstraintCategory::Boring,
) {
let annotation = &mir.user_type_annotations[annotation_index];
let annotation = &self.user_type_annotations[annotation_index];
span_mirbug!(
self,
stmt,
Expand Down Expand Up @@ -1420,7 +1421,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
Locations::All(stmt.source_info.span),
ConstraintCategory::TypeAnnotation,
) {
let annotation = &mir.user_type_annotations[projection.base];
let annotation = &self.user_type_annotations[projection.base];
span_mirbug!(
self,
stmt,
Expand Down Expand Up @@ -2078,7 +2079,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}

Rvalue::Ref(region, _borrow_kind, borrowed_place) => {
self.add_reborrow_constraint(location, region, borrowed_place);
self.add_reborrow_constraint(mir, location, region, borrowed_place);
}

// FIXME: These other cases have to be implemented in future PRs
Expand Down Expand Up @@ -2177,6 +2178,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
/// - `borrowed_place`: the place `P` being borrowed
fn add_reborrow_constraint(
&mut self,
mir: &Mir<'tcx>,
location: Location,
borrow_region: ty::Region<'tcx>,
borrowed_place: &Place<'tcx>,
Expand Down Expand Up @@ -2226,7 +2228,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
match *elem {
ProjectionElem::Deref => {
let tcx = self.infcx.tcx;
let base_ty = base.ty(self.mir, tcx).to_ty(tcx);
let base_ty = base.ty(mir, tcx).to_ty(tcx);

debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
match base_ty.sty {
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/nll/user-annotations/promoted-annotation.rs
@@ -0,0 +1,12 @@
// Test that type annotations are checked in promoted constants correctly.

#![feature(nll)]

fn foo<'a>() {
let x = 0;
let f = &drop::<&'a i32>;
f(&x);
//~^ ERROR `x` does not live long enough
}

fn main() {}
17 changes: 17 additions & 0 deletions src/test/ui/nll/user-annotations/promoted-annotation.stderr
@@ -0,0 +1,17 @@
error[E0597]: `x` does not live long enough
--> $DIR/promoted-annotation.rs:8:7
|
LL | fn foo<'a>() {
| -- lifetime `'a` defined here
LL | let x = 0;
LL | let f = &drop::<&'a i32>;
| ---------------- assignment requires that `x` is borrowed for `'a`
LL | f(&x);
| ^^ borrowed value does not live long enough
LL | //~^ ERROR `x` does not live long enough
LL | }
| - `x` dropped here while still borrowed

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.

0 comments on commit 3b93d71

Please sign in to comment.