X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustc_typeck%2Fcheck%2Fautoderef.rs;h=e0e946a9c63fa7b367a5ef37c80da9ee7de024b0;hb=6f4ab9458a7ad06c8ce630604f533c8c0c0acef4;hp=c9584f1d9e1e0968a057f4c6875058788a6ebb75;hpb=b091d6ed428a5edb67ad24850374e75e7f615c93;p=rust.git diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index c9584f1d9e1..e0e946a9c63 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -11,19 +11,20 @@ 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, @@ -62,7 +63,7 @@ fn next(&mut self) -> Option { E0055, "reached the recursion limit while auto-dereferencing {:?}", self.cur_ty) - .span_label(self.span, &format!("deref recursion limit reached")) + .span_label(self.span, "deref recursion limit reached") .help(&format!( "consider adding a `#[recursion_limit=\"{}\"]` attribute to your crate", suggested_limit)) @@ -117,17 +118,21 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option> { 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> { + self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref)) } - pub fn finalize_as_infer_ok(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>> { + 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> { + 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>> { - 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) } }