]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/borrow_check/nll/type_check/mod.rs
Check for uninhabitedness instead of never
[rust.git] / src / librustc_mir / borrow_check / nll / type_check / mod.rs
index 734ddbc3ab9a72af39babca2f7080aac3e3577c9..39019b35beb184517e8bacddcfa6990746587853 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 //! This pass type-checks the MIR to ensure it is not broken.
+
 #![allow(unreachable_code)]
 
 use borrow_check::borrow_set::BorrowSet;
@@ -47,7 +48,8 @@
 use rustc::ty::subst::{Subst, Substs, UnpackedKind};
 use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc::ty::layout::VariantIdx;
 use std::rc::Rc;
 use std::{fmt, iter};
 use syntax_pos::{Span, DUMMY_SP};
@@ -111,7 +113,7 @@ macro_rules! span_mirbug_and_err {
 /// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
 ///   constraints for the regions in the types of variables
 /// - `flow_inits` -- results of a maybe-init dataflow analysis
-/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysiss
+/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
 pub(crate) fn type_check<'gcx, 'tcx>(
     infcx: &InferCtxt<'_, 'gcx, 'tcx>,
     param_env: ty::ParamEnv<'gcx>,
@@ -574,7 +576,7 @@ fn sanitize_projection(
             },
             ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty {
                 ty::Adt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => {
-                    if index >= adt_def.variants.len() {
+                    if index.as_usize() >= adt_def.variants.len() {
                         PlaceTy::Ty {
                             ty: span_mirbug_and_err!(
                                 self,
@@ -654,7 +656,8 @@ fn field_ty(
                 variant_index,
             } => (&adt_def.variants[variant_index], substs),
             PlaceTy::Ty { ty } => match ty.sty {
-                ty::Adt(adt_def, substs) if !adt_def.is_enum() => (&adt_def.variants[0], substs),
+                ty::Adt(adt_def, substs) if !adt_def.is_enum() =>
+                    (&adt_def.variants[VariantIdx::new(0)], substs),
                 ty::Closure(def_id, substs) => {
                     return match substs.upvar_tys(def_id, tcx).nth(field.index()) {
                         Some(ty) => Ok(ty),
@@ -775,7 +778,7 @@ impl MirTypeckRegionConstraints<'tcx> {
     fn placeholder_region(
         &mut self,
         infcx: &InferCtxt<'_, '_, 'tcx>,
-        placeholder: ty::Placeholder,
+        placeholder: ty::PlaceholderRegion,
     ) -> ty::Region<'tcx> {
         let placeholder_index = self.placeholder_indices.insert(placeholder);
         match self.placeholder_index_to_region.get(placeholder_index) {
@@ -1021,20 +1024,39 @@ fn relate_type_and_user_type(
                 let v1 = ty::Contravariant.xform(v);
 
                 let tcx = self.infcx.tcx;
-                let mut projected_ty = PlaceTy::from_ty(ty);
+                let ty = self.normalize(ty, locations);
+
+                // We need to follow any provided projetions into the type.
+                //
+                // if we hit a ty var as we descend, then just skip the
+                // attempt to relate the mir local with any type.
+                #[derive(Debug)] struct HitTyVar;
+                let mut curr_projected_ty: Result<PlaceTy, HitTyVar>;
+
+                curr_projected_ty = Ok(PlaceTy::from_ty(ty));
                 for proj in &user_ty.projs {
-                    projected_ty = projected_ty.projection_ty_core(
+                    let projected_ty = if let Ok(projected_ty) = curr_projected_ty {
+                        projected_ty
+                    } else {
+                        break;
+                    };
+                    curr_projected_ty = projected_ty.projection_ty_core(
                         tcx, proj, |this, field, &()| {
-                            let ty = this.field_ty(tcx, field);
-                            self.normalize(ty, locations)
+                            if this.to_ty(tcx).is_ty_var() {
+                                Err(HitTyVar)
+                            } else {
+                                let ty = this.field_ty(tcx, field);
+                                Ok(self.normalize(ty, locations))
+                            }
                         });
                 }
                 debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
-                       user_ty.base, ty, user_ty.projs, projected_ty);
+                       user_ty.base, ty, user_ty.projs, curr_projected_ty);
 
-                let ty = projected_ty.to_ty(tcx);
-
-                self.relate_types(ty, v1, a, locations, category)?;
+                if let Ok(projected_ty) = curr_projected_ty {
+                    let ty = projected_ty.to_ty(tcx);
+                    self.relate_types(ty, v1, a, locations, category)?;
+                }
             }
             UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
                 let (
@@ -1261,7 +1283,7 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca
                         );
                     }
                 };
-                if variant_index >= adt.variants.len() {
+                if variant_index.as_usize() >= adt.variants.len() {
                     span_bug!(
                         stmt.source_info.span,
                         "bad set discriminant ({:?} = {:?}): value of of range",
@@ -1290,11 +1312,11 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca
                 }
             }
             StatementKind::FakeRead(..)
-            | StatementKind::StorageLive(_)
-            | StatementKind::StorageDead(_)
+            | StatementKind::StorageLive(..)
+            | StatementKind::StorageDead(..)
             | StatementKind::InlineAsm { .. }
-            | StatementKind::EndRegion(_)
             | StatementKind::Retag { .. }
+            | StatementKind::EscapeToRaw { .. }
             | StatementKind::Nop => {}
         }
     }
@@ -1385,7 +1407,7 @@ fn check_terminator(
                         return;
                     }
                 };
-                let (sig, map) = self.infcx.replace_late_bound_regions_with_fresh_var(
+                let (sig, map) = self.infcx.replace_bound_vars_with_fresh_vars(
                     term.source_info.span,
                     LateBoundRegionConversionTime::FnCall,
                     &sig,
@@ -1446,7 +1468,7 @@ fn check_terminator(
                             value_ty,
                             ty,
                             term_location.to_locations(),
-                            ConstraintCategory::Return,
+                            ConstraintCategory::Yield,
                         ) {
                             span_mirbug!(
                                 self,
@@ -1524,8 +1546,7 @@ fn check_call_dest(
                 }
             }
             None => {
-                // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                if !sig.output().is_never() {
+                if !sig.output().conservative_is_uninhabited() {
                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
                 }
             }