]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/borrow_check/nll/type_check/mod.rs
port the relate-types code from NLL type-check into a type-op
[rust.git] / src / librustc_mir / borrow_check / nll / type_check / mod.rs
index 1e79bc272e4c0ba687dc58fe02a83375fcefc63a..bbbe02fda6a84dd145035e0e6331b5117d3b100a 100644 (file)
@@ -23,7 +23,7 @@
 use borrow_check::nll::type_check::free_region_relations::{
     CreateResult, UniversalRegionRelations,
 };
-use borrow_check::nll::universal_regions::UniversalRegions;
+use borrow_check::nll::universal_regions::{DefiningTy, UniversalRegions};
 use borrow_check::nll::ToRegionVid;
 use dataflow::move_paths::MoveData;
 use dataflow::FlowAtLocation;
@@ -42,7 +42,7 @@
 use rustc::traits::query::{Fallible, NoSolution};
 use rustc::traits::{ObligationCause, PredicateObligations};
 use rustc::ty::fold::TypeFoldable;
-use rustc::ty::subst::{Subst, UnpackedKind};
+use rustc::ty::subst::{Subst, Substs, UnpackedKind};
 use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
 use std::rc::Rc;
 use std::{fmt, iter};
@@ -128,7 +128,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
     let mut constraints = MirTypeckRegionConstraints {
         liveness_constraints: LivenessValues::new(elements),
         outlives_constraints: ConstraintSet::default(),
-        closure_bounds_mapping: FxHashMap(),
+        closure_bounds_mapping: Default::default(),
         type_tests: Vec::default(),
     };
     let mut placeholder_indices = PlaceholderIndices::default();
@@ -753,10 +753,8 @@ struct BorrowCheckContext<'a, 'tcx: 'a> {
 
     crate outlives_constraints: ConstraintSet,
 
-    crate closure_bounds_mapping: FxHashMap<
-        Location,
-        FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
-    >,
+    crate closure_bounds_mapping:
+        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
 
     crate type_tests: Vec<TypeTest<'tcx>>,
 }
@@ -847,7 +845,7 @@ fn new(
             region_bound_pairs,
             implicit_region_bound,
             borrowck_context,
-            reported_errors: FxHashSet(),
+            reported_errors: Default::default(),
             universal_region_relations,
         }
     }
@@ -866,7 +864,7 @@ fn fully_perform_op<R>(
         &mut self,
         locations: Locations,
         category: ConstraintCategory,
-        op: impl type_op::TypeOp<'gcx, 'tcx, Output=R>,
+        op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>,
     ) -> Fallible<R> {
         let (r, opt_data) = op.fully_perform(self.infcx)?;
 
@@ -903,23 +901,37 @@ fn push_region_constraints(
         }
     }
 
-    fn sub_types(
+    /// Convenient wrapper around `relate_tys::relate_types` -- see
+    /// that fn for docs.
+    fn relate_types(
         &mut self,
-        sub: Ty<'tcx>,
-        sup: Ty<'tcx>,
+        a: Ty<'tcx>,
+        v: ty::Variance,
+        b: Ty<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        relate_tys::sub_types(
+        relate_tys::relate_types(
             self.infcx,
-            sub,
-            sup,
+            a,
+            v,
+            b,
             locations,
             category,
             self.borrowck_context.as_mut().map(|x| &mut **x),
         )
     }
 
+    fn sub_types(
+        &mut self,
+        sub: Ty<'tcx>,
+        sup: Ty<'tcx>,
+        locations: Locations,
+        category: ConstraintCategory,
+    ) -> Fallible<()> {
+        self.relate_types(sub, ty::Variance::Covariant, sup, locations, category)
+    }
+
     /// Try to relate `sub <: sup`; if this fails, instantiate opaque
     /// variables in `sub` with their inferred definitions and try
     /// again. This is used for opaque types in places (e.g., `let x:
@@ -952,38 +964,51 @@ fn eq_types(
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        relate_tys::eq_types(
-            self.infcx,
-            a,
-            b,
-            locations,
-            category,
-            self.borrowck_context.as_mut().map(|x| &mut **x),
-        )
+        self.relate_types(a, ty::Variance::Invariant, b, locations, category)
     }
 
     fn relate_type_and_user_type(
         &mut self,
         a: Ty<'tcx>,
         v: ty::Variance,
-        b: UserTypeAnnotation<'tcx>,
+        user_ty: UserTypeAnnotation<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        let ty = relate_tys::relate_type_and_user_type(
-            self.infcx,
-            a,
-            v,
-            b,
-            locations,
-            category,
-            self.borrowck_context.as_mut().map(|x| &mut **x),
-        )?;
-        self.prove_predicate(
-            ty::Predicate::WellFormed(ty),
-            locations,
-            category,
+        debug!(
+            "relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})",
+            a, v, user_ty, locations,
         );
+
+        match user_ty {
+            UserTypeAnnotation::Ty(canonical_ty) => {
+                let (ty, _) = self.infcx
+                    .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
+
+                // The `TypeRelating` code assumes that "unresolved inference
+                // variables" appear in the "a" side, so flip `Contravariant`
+                // ambient variance to get the right relationship.
+                let v1 = ty::Contravariant.xform(v);
+
+                self.relate_types(ty, v1, a, locations, category)?;
+            }
+            UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
+                let (
+                    user_substs,
+                    _,
+                ) = self.infcx
+                    .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
+
+                self.fully_perform_op(
+                    locations,
+                    category,
+                    self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
+                        a, v, def_id, user_substs,
+                    )),
+                )?;
+            }
+        }
+
         Ok(())
     }
 
@@ -1105,7 +1130,23 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca
                 // of lowering. Assignments to other sorts of places *are* interesting
                 // though.
                 let category = match *place {
-                    Place::Local(RETURN_PLACE) => ConstraintCategory::Return,
+                    Place::Local(RETURN_PLACE) => if let Some(BorrowCheckContext {
+                        universal_regions:
+                            UniversalRegions {
+                                defining_ty: DefiningTy::Const(def_id, _),
+                                ..
+                            },
+                        ..
+                    }) = self.borrowck_context
+                    {
+                        if tcx.is_static(*def_id).is_some() {
+                            ConstraintCategory::UseAsStatic
+                        } else {
+                            ConstraintCategory::UseAsConst
+                        }
+                    } else {
+                        ConstraintCategory::Return
+                    },
                     Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => {
                         ConstraintCategory::Boring
                     }
@@ -1115,9 +1156,9 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca
                 let place_ty = place.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = rv.ty(mir, tcx);
                 if let Err(terr) =
-                self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
-                    {
-                        span_mirbug!(
+                    self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
+                {
+                    span_mirbug!(
                         self,
                         stmt,
                         "bad assignment ({:?} = {:?}): {:?}",
@@ -1125,7 +1166,7 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca
                         rv_ty,
                         terr
                     );
-                    }
+                }
 
                 if let Some(user_ty) = self.rvalue_user_ty(rv) {
                     if let Err(terr) = self.relate_type_and_user_type(
@@ -1245,9 +1286,9 @@ fn check_terminator(
 
                 let locations = term_location.to_locations();
                 if let Err(terr) =
-                self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
-                    {
-                        span_mirbug!(
+                    self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
+                {
+                    span_mirbug!(
                         self,
                         term,
                         "bad DropAndReplace ({:?} = {:?}): {:?}",
@@ -1255,7 +1296,7 @@ fn check_terminator(
                         rv_ty,
                         terr
                     );
-                    }
+                }
             }
             TerminatorKind::SwitchInt {
                 ref discr,
@@ -1287,6 +1328,7 @@ fn check_terminator(
                 ref func,
                 ref args,
                 ref destination,
+                from_hir_call,
                 ..
             } => {
                 let func_ty = func.ty(mir, tcx);
@@ -1331,7 +1373,7 @@ fn check_terminator(
                     }
                 }
 
-                self.check_call_inputs(mir, term, &sig, args, term_location);
+                self.check_call_inputs(mir, term, &sig, args, term_location, from_hir_call);
             }
             TerminatorKind::Assert {
                 ref cond, ref msg, ..
@@ -1389,7 +1431,25 @@ fn check_call_dest(
             Some((ref dest, _target_block)) => {
                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
                 let category = match *dest {
-                    Place::Local(RETURN_PLACE) => ConstraintCategory::Return,
+                    Place::Local(RETURN_PLACE) => {
+                        if let Some(BorrowCheckContext {
+                            universal_regions:
+                                UniversalRegions {
+                                    defining_ty: DefiningTy::Const(def_id, _),
+                                    ..
+                                },
+                            ..
+                        }) = self.borrowck_context
+                        {
+                            if tcx.is_static(*def_id).is_some() {
+                                ConstraintCategory::UseAsStatic
+                            } else {
+                                ConstraintCategory::UseAsConst
+                            }
+                        } else {
+                            ConstraintCategory::Return
+                        }
+                    }
                     Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => {
                         ConstraintCategory::Boring
                     }
@@ -1399,9 +1459,9 @@ fn check_call_dest(
                 let locations = term_location.to_locations();
 
                 if let Err(terr) =
-                self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
-                    {
-                        span_mirbug!(
+                    self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
+                {
+                    span_mirbug!(
                         self,
                         term,
                         "call dest mismatch ({:?} <- {:?}): {:?}",
@@ -1409,7 +1469,7 @@ fn check_call_dest(
                         sig.output(),
                         terr
                     );
-                    }
+                }
 
                 // When `#![feature(unsized_locals)]` is not enabled,
                 // this check is done at `check_local`.
@@ -1434,6 +1494,7 @@ fn check_call_inputs(
         sig: &ty::FnSig<'tcx>,
         args: &[Operand<'tcx>],
         term_location: Location,
+        from_hir_call: bool,
     ) {
         debug!("check_call_inputs({:?}, {:?})", sig, args);
         if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.variadic) {
@@ -1441,12 +1502,14 @@ fn check_call_inputs(
         }
         for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
             let op_arg_ty = op_arg.ty(mir, self.tcx());
-            if let Err(terr) = self.sub_types(
-                op_arg_ty,
-                fn_arg,
-                term_location.to_locations(),
-                ConstraintCategory::CallArgument,
-            ) {
+            let category = if from_hir_call {
+                ConstraintCategory::CallArgument
+            } else {
+                ConstraintCategory::Boring
+            };
+            if let Err(terr) =
+                self.sub_types(op_arg_ty, fn_arg, term_location.to_locations(), category)
+            {
                 span_mirbug!(
                     self,
                     term,
@@ -2050,7 +2113,7 @@ fn prove_aggregate_predicates(
             aggregate_kind, location
         );
 
-        let instantiated_predicates = match aggregate_kind  {
+        let instantiated_predicates = match aggregate_kind {
             AggregateKind::Adt(def, _, substs, _, _) => {
                 tcx.predicates_of(def.did).instantiate(tcx, substs)
             }
@@ -2075,12 +2138,9 @@ fn prove_aggregate_predicates(
             // desugaring. A closure gets desugared to a struct, and
             // these extra requirements are basically like where
             // clauses on the struct.
-            AggregateKind::Closure(def_id, substs) => {
-                self.prove_closure_bounds(tcx, *def_id, *substs, location)
-            }
-
-            AggregateKind::Generator(def_id, substs, _) => {
-                tcx.predicates_of(*def_id).instantiate(tcx, substs.substs)
+            AggregateKind::Closure(def_id, ty::ClosureSubsts { substs })
+            | AggregateKind::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
+                self.prove_closure_bounds(tcx, *def_id, substs, location)
             }
 
             AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
@@ -2096,18 +2156,12 @@ fn prove_closure_bounds(
         &mut self,
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
         def_id: DefId,
-        substs: ty::ClosureSubsts<'tcx>,
+        substs: &'tcx Substs<'tcx>,
         location: Location,
     ) -> ty::InstantiatedPredicates<'tcx> {
-        if let Some(closure_region_requirements) =
-            tcx.mir_borrowck(def_id).closure_requirements
-        {
-            let closure_constraints = closure_region_requirements.apply_requirements(
-                tcx,
-                location,
-                def_id,
-                substs,
-            );
+        if let Some(closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements {
+            let closure_constraints =
+                closure_region_requirements.apply_requirements(tcx, location, def_id, substs);
 
             if let Some(ref mut borrowck_context) = self.borrowck_context {
                 let bounds_mapping = closure_constraints
@@ -2116,10 +2170,7 @@ fn prove_closure_bounds(
                     .filter_map(|(idx, constraint)| {
                         let ty::OutlivesPredicate(k1, r2) =
                             constraint.no_late_bound_regions().unwrap_or_else(|| {
-                                bug!(
-                                    "query_constraint {:?} contained bound regions",
-                                    constraint,
-                                );
+                                bug!("query_constraint {:?} contained bound regions", constraint,);
                             });
 
                         match k1.unpack() {
@@ -2127,8 +2178,8 @@ fn prove_closure_bounds(
                                 // constraint is r1: r2
                                 let r1_vid = borrowck_context.universal_regions.to_region_vid(r1);
                                 let r2_vid = borrowck_context.universal_regions.to_region_vid(r2);
-                                let outlives_requirements = &closure_region_requirements
-                                    .outlives_requirements[idx];
+                                let outlives_requirements =
+                                    &closure_region_requirements.outlives_requirements[idx];
                                 Some((
                                     (r1_vid, r2_vid),
                                     (
@@ -2142,10 +2193,14 @@ fn prove_closure_bounds(
                     })
                     .collect();
 
-                let existing = borrowck_context.constraints
+                let existing = borrowck_context
+                    .constraints
                     .closure_bounds_mapping
                     .insert(location, bounds_mapping);
-                assert!(existing.is_none(), "Multiple closures at the same location.");
+                assert!(
+                    existing.is_none(),
+                    "Multiple closures at the same location."
+                );
             }
 
             self.push_region_constraints(
@@ -2155,7 +2210,7 @@ fn prove_closure_bounds(
             );
         }
 
-        tcx.predicates_of(def_id).instantiate(tcx, substs.substs)
+        tcx.predicates_of(def_id).instantiate(tcx, substs)
     }
 
     fn prove_trait_ref(