]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/check/autoderef.rs
Auto merge of #43710 - zackmdavis:field_init_shorthand_power_slam, r=Mark-Simulacrum
[rust.git] / src / librustc_typeck / check / autoderef.rs
index f03451c04ed004a19d5d38c0bc0295b2fa84ce49..e0e946a9c63fa7b367a5ef37c80da9ee7de024b0 100644 (file)
 use astconv::AstConv;
 
 use super::{FnCtxt, LvalueOp};
+use super::method::MethodCallee;
 
-use check::coercion::AsCoercionSite;
 use rustc::infer::InferOk;
 use rustc::traits;
 use rustc::ty::{self, Ty, TraitRef};
 use rustc::ty::{ToPredicate, TypeFoldable};
-use rustc::ty::{MethodCall, MethodCallee};
 use rustc::ty::{LvaluePreference, NoPreference};
-use rustc::hir;
+use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
 
 use syntax_pos::Span;
 use syntax::symbol::Symbol;
 
+use std::iter;
+
 #[derive(Copy, Clone, Debug)]
 enum AutoderefKind {
     Builtin,
@@ -117,17 +118,21 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
 
         let mut selcx = traits::SelectionContext::new(self.fcx);
-        let obligation = traits::Obligation::new(cause.clone(), trait_ref.to_predicate());
+        let obligation = traits::Obligation::new(cause.clone(),
+                                                 self.fcx.param_env,
+                                                 trait_ref.to_predicate());
         if !selcx.evaluate_obligation(&obligation) {
             debug!("overloaded_deref_ty: cannot match obligation");
             return None;
         }
 
         let normalized = traits::normalize_projection_type(&mut selcx,
-                                                           ty::ProjectionTy {
-                                                               trait_ref: trait_ref,
-                                                               item_name: Symbol::intern("Target"),
-                                                           },
+                                                           self.fcx.param_env,
+                                                           ty::ProjectionTy::from_ref_and_name(
+                                                               tcx,
+                                                               trait_ref,
+                                                               Symbol::intern("Target"),
+                                                           ),
                                                            cause,
                                                            0);
 
@@ -149,52 +154,59 @@ pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
         self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
     }
 
-    pub fn finalize(self, pref: LvaluePreference, expr: &hir::Expr) {
-        let fcx = self.fcx;
-        fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, &[expr]));
+    pub fn step_count(&self) -> usize {
+        self.steps.len()
+    }
+
+    /// Returns the adjustment steps.
+    pub fn adjust_steps(&self, pref: LvaluePreference)
+                        -> Vec<Adjustment<'tcx>> {
+        self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref))
     }
 
-    pub fn finalize_as_infer_ok<E>(self, pref: LvaluePreference, exprs: &[E])
-                                   -> InferOk<'tcx, ()>
-        where E: AsCoercionSite
-    {
-        let Autoderef { fcx, span, mut obligations, steps, .. } = self;
-        let methods: Vec<_> = steps
-            .iter()
-            .map(|&(ty, kind)| {
-                if let AutoderefKind::Overloaded = kind {
-                    fcx.try_overloaded_deref(span, None, ty, pref)
-                        .map(|InferOk { value, obligations: o }| {
-                            obligations.extend(o);
-                            value
-                        })
-                } else {
-                    None
-                }
-            })
-            .collect();
-
-        debug!("finalize({:?}) - {:?},{:?}",
-               pref,
-               methods,
-               obligations);
-
-        for expr in exprs {
-            let expr = expr.as_coercion_site();
-            debug!("finalize - finalizing #{} - {:?}", expr.id, expr);
-            for (n, method) in methods.iter().enumerate() {
-                if let &Some(method) = method {
-                    let method_call = MethodCall::autoderef(expr.id, n as u32);
-                    fcx.tables.borrow_mut().method_map.insert(method_call, method);
-                }
+    pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference)
+                                    -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
+        let mut obligations = vec![];
+        let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty)
+            .chain(iter::once(self.cur_ty));
+        let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| {
+            if let AutoderefKind::Overloaded = kind {
+                self.fcx.try_overloaded_deref(self.span, source, pref)
+                    .and_then(|InferOk { value: method, obligations: o }| {
+                        obligations.extend(o);
+                        if let ty::TyRef(region, mt) = method.sig.output().sty {
+                            Some(OverloadedDeref {
+                                region,
+                                mutbl: mt.mutbl,
+                            })
+                        } else {
+                            None
+                        }
+                    })
+            } else {
+                None
             }
-        }
+        }).zip(targets).map(|(autoderef, target)| {
+            Adjustment {
+                kind: Adjust::Deref(autoderef),
+                target
+            }
+        }).collect();
 
         InferOk {
-            value: (),
-            obligations
+            obligations,
+            value: steps
         }
     }
+
+    pub fn finalize(self) {
+        let fcx = self.fcx;
+        fcx.register_predicates(self.into_obligations());
+    }
+
+    pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
+        self.obligations
+    }
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
@@ -205,20 +217,15 @@ pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx,
             cur_ty: self.resolve_type_vars_if_possible(&base_ty),
             obligations: vec![],
             at_start: true,
-            span: span,
+            span,
         }
     }
 
     pub fn try_overloaded_deref(&self,
                                 span: Span,
-                                base_expr: Option<&hir::Expr>,
                                 base_ty: Ty<'tcx>,
                                 pref: LvaluePreference)
                                 -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        let rcvr = base_expr.map(|base_expr| super::AdjustedRcvr {
-            rcvr_expr: base_expr, autoderefs: 0, unsize: false
-        });
-
-        self.try_overloaded_lvalue_op(span, rcvr, base_ty, &[], pref, LvalueOp::Deref)
+        self.try_overloaded_lvalue_op(span, base_ty, &[], pref, LvalueOp::Deref)
     }
 }