From 07201249f09ddf4ade1f02d8208b624b5d927212 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 15 Sep 2018 17:14:18 +0300 Subject: [PATCH 1/7] process nested obligations in autoderef This is a hack-fix to #53843, but I am worried it might break things because it makes the "inference pollution" problem worse. Fixes #53843 (but introduces a bug that someone might notice). --- src/librustc/traits/fulfill.rs | 26 +++++++++++++++--- src/librustc_typeck/check/autoderef.rs | 37 ++++++++++++++++---------- src/test/run-pass/issue-53843.rs | 34 +++++++++++++++++++++++ 3 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 src/test/run-pass/issue-53843.rs diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index bc091a4e7e084..09c7bd679705a 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -61,6 +61,16 @@ pub struct FulfillmentContext<'tcx> { // type-lives-for-region constraints, and because the type // is well-formed, the constraints should hold. register_region_obligations: bool, + // Is it OK to register obligations into this infcx inside + // an infcx snapshot? + // + // The "primary fulfillment" in many cases in typeck lives + // outside of any snapshot, so any use of it inside a snapshot + // will lead to trouble and therefore is checked against, but + // other fulfillment contexts sometimes do live inside of + // a snapshot (they don't *straddle* a snapshot, so there + // is no trouble there). + usable_in_snapshot: bool } #[derive(Clone, Debug)] @@ -74,14 +84,24 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), - register_region_obligations: true + register_region_obligations: true, + usable_in_snapshot: false, + } + } + + pub fn new_in_snapshot() -> FulfillmentContext<'tcx> { + FulfillmentContext { + predicates: ObligationForest::new(), + register_region_obligations: true, + usable_in_snapshot: true, } } pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), - register_region_obligations: false + register_region_obligations: false, + usable_in_snapshot: false } } @@ -195,7 +215,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { debug!("register_predicate_obligation(obligation={:?})", obligation); - assert!(!infcx.is_in_snapshot()); + assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); self.predicates.register_obligation(PendingPredicateObligation { obligation, diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 1b594342c9a71..7a84634d2a3ee 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -15,7 +15,7 @@ use super::method::MethodCallee; use rustc::infer::InferOk; use rustc::session::DiagnosticMessageId; -use rustc::traits; +use rustc::traits::{self, TraitEngine}; use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref}; @@ -128,19 +128,28 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { return None; } - let mut selcx = traits::SelectionContext::new(self.fcx); - let normalized_ty = traits::normalize_projection_type(&mut selcx, - self.fcx.param_env, - ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - Ident::from_str("Target"), - ), - cause, - 0, - &mut self.obligations); - - debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized_ty); + let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); + let normalized_ty = fulfillcx.normalize_projection_type( + &self.fcx, + self.fcx.param_env, + ty::ProjectionTy::from_ref_and_name( + tcx, + trait_ref, + Ident::from_str("Target"), + ), + cause); + if let Err(e) = fulfillcx.select_where_possible(&self.fcx) { + // This shouldn't happen, except for evaluate/fulfill mismatches, + // but that's not a reason for an ICE (`predicate_may_hold` is conservative + // by design). + debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", + e); + return None; + } + let obligations = fulfillcx.pending_obligations(); + debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", + ty, normalized_ty, obligations); + self.obligations.extend(obligations); Some(self.fcx.resolve_type_vars_if_possible(&normalized_ty)) } diff --git a/src/test/run-pass/issue-53843.rs b/src/test/run-pass/issue-53843.rs new file mode 100644 index 0000000000000..4b15ecb3e542b --- /dev/null +++ b/src/test/run-pass/issue-53843.rs @@ -0,0 +1,34 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; + +pub struct Pin

(P); + +impl Deref for Pin

+where + P: Deref, +{ + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } +} + +impl

Pin

{ + fn poll(self) {} +} + +fn main() { + let mut unit = (); + let pin = Pin(&mut unit); + pin.poll(); +} From 832ac110df0f58627ec1134bb9caf60d41f93f3c Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 15 Sep 2018 18:10:10 +0300 Subject: [PATCH 2/7] remove the typeck::autoderef::Autoderef fcx field This allows using it in an fcx-independent context --- src/librustc_typeck/check/autoderef.rs | 49 +++++++++++---------- src/librustc_typeck/check/callee.rs | 10 ++--- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 6 +-- src/librustc_typeck/check/mod.rs | 16 +++---- src/librustc_typeck/check/wfcheck.rs | 2 +- 6 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 7a84634d2a3ee..c13ed1bd9d0e7 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use astconv::AstConv; - use super::{FnCtxt, PlaceOp, Needs}; use super::method::MethodCallee; -use rustc::infer::InferOk; +use rustc::infer::{InferCtxt, InferOk}; use rustc::session::DiagnosticMessageId; use rustc::traits::{self, TraitEngine}; use rustc::ty::{self, Ty, TraitRef}; @@ -21,7 +19,7 @@ use rustc::ty::{ToPredicate, TypeFoldable}; use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref}; use syntax_pos::Span; -use syntax::ast::Ident; +use syntax::ast::{NodeId, Ident}; use std::iter; @@ -32,7 +30,9 @@ enum AutoderefKind { } pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + body_id: NodeId, + param_env: ty::ParamEnv<'tcx>, steps: Vec<(Ty<'tcx>, AutoderefKind)>, cur_ty: Ty<'tcx>, obligations: Vec>, @@ -45,7 +45,7 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { type Item = (Ty<'tcx>, usize); fn next(&mut self) -> Option { - let tcx = self.fcx.tcx; + let tcx = self.infcx.tcx; debug!("autoderef: steps={:?}, cur_ty={:?}", self.steps, @@ -110,7 +110,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option> { debug!("overloaded_deref_ty({:?})", ty); - let tcx = self.fcx.tcx(); + let tcx = self.infcx.tcx; // let trait_ref = TraitRef { @@ -118,27 +118,27 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { substs: tcx.mk_substs_trait(self.cur_ty, &[]), }; - let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); + let cause = traits::ObligationCause::misc(self.span, self.body_id); let obligation = traits::Obligation::new(cause.clone(), - self.fcx.param_env, + self.param_env, trait_ref.to_predicate()); - if !self.fcx.predicate_may_hold(&obligation) { + if !self.infcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); return None; } let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); let normalized_ty = fulfillcx.normalize_projection_type( - &self.fcx, - self.fcx.param_env, + &self.infcx, + self.param_env, ty::ProjectionTy::from_ref_and_name( tcx, trait_ref, Ident::from_str("Target"), ), cause); - if let Err(e) = fulfillcx.select_where_possible(&self.fcx) { + if let Err(e) = fulfillcx.select_where_possible(&self.infcx) { // This shouldn't happen, except for evaluate/fulfill mismatches, // but that's not a reason for an ICE (`predicate_may_hold` is conservative // by design). @@ -151,19 +151,19 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { ty, normalized_ty, obligations); self.obligations.extend(obligations); - Some(self.fcx.resolve_type_vars_if_possible(&normalized_ty)) + Some(self.infcx.resolve_type_vars_if_possible(&normalized_ty)) } /// Returns the final type, generating an error if it is an /// unresolved inference variable. - pub fn unambiguous_final_ty(&self) -> Ty<'tcx> { - self.fcx.structurally_resolved_type(self.span, self.cur_ty) + pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + fcx.structurally_resolved_type(self.span, self.cur_ty) } /// Returns the final type we ended up with, which may well be an /// inference variable (we will resolve it first, if possible). pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> { - self.fcx.resolve_type_vars_if_possible(&self.cur_ty) + self.infcx.resolve_type_vars_if_possible(&self.cur_ty) } pub fn step_count(&self) -> usize { @@ -171,19 +171,19 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } /// Returns the adjustment steps. - pub fn adjust_steps(&self, needs: Needs) + pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, needs: Needs) -> Vec> { - self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(needs)) + fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs)) } - pub fn adjust_steps_as_infer_ok(&self, needs: Needs) + pub fn adjust_steps_as_infer_ok(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, needs: Needs) -> 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, needs) + fcx.try_overloaded_deref(self.span, source, needs) .and_then(|InferOk { value: method, obligations: o }| { obligations.extend(o); if let ty::Ref(region, _, mutbl) = method.sig.output().sty { @@ -220,8 +220,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self } - pub fn finalize(self) { - let fcx = self.fcx; + pub fn finalize(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { fcx.register_predicates(self.into_obligations()); } @@ -233,7 +232,9 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> { Autoderef { - fcx: self, + infcx: &self.infcx, + body_id: self.body_id, + param_env: self.param_env, steps: vec![], cur_ty: self.resolve_type_vars_if_possible(&base_ty), obligations: vec![], diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index e4ce04916ce64..a139310b2076c 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -57,7 +57,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { while result.is_none() && autoderef.next().is_some() { result = self.try_overloaded_call_step(call_expr, callee_expr, &autoderef); } - autoderef.finalize(); + autoderef.finalize(self); let output = match result { None => { @@ -89,7 +89,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { callee_expr: &'gcx hir::Expr, autoderef: &Autoderef<'a, 'gcx, 'tcx>) -> Option> { - let adjusted_ty = autoderef.unambiguous_final_ty(); + let adjusted_ty = autoderef.unambiguous_final_ty(self); debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})", call_expr, adjusted_ty); @@ -97,7 +97,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If the callee is a bare function or a closure, then we're all set. match adjusted_ty.sty { ty::FnDef(..) | ty::FnPtr(_) => { - let adjustments = autoderef.adjust_steps(Needs::None); + let adjustments = autoderef.adjust_steps(self, Needs::None); self.apply_adjustments(callee_expr, adjustments); return Some(CallStep::Builtin(adjusted_ty)); } @@ -115,7 +115,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { infer::FnCall, &closure_ty ).0; - let adjustments = autoderef.adjust_steps(Needs::None); + let adjustments = autoderef.adjust_steps(self, Needs::None); self.record_deferred_call_resolution(def_id, DeferredCallResolution { call_expr, callee_expr, @@ -145,7 +145,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| { - let mut adjustments = autoderef.adjust_steps(Needs::None); + let mut adjustments = autoderef.adjust_steps(self, Needs::None); adjustments.extend(autoref); self.apply_adjustments(callee_expr, adjustments); CallStep::Overloaded(method) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8d844fe3a69e4..d616d88905bbf 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -419,7 +419,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let needs = Needs::maybe_mut_place(mt_b.mutbl); let InferOk { value: mut adjustments, obligations: o } - = autoderef.adjust_steps_as_infer_ok(needs); + = autoderef.adjust_steps_as_infer_ok(self, needs); obligations.extend(o); obligations.extend(autoderef.into_obligations()); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 11fb3889a748d..3902dddd0d476 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -161,9 +161,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let (_, n) = autoderef.nth(pick.autoderefs).unwrap(); assert_eq!(n, pick.autoderefs); - let mut adjustments = autoderef.adjust_steps(Needs::None); + let mut adjustments = autoderef.adjust_steps(self, Needs::None); - let mut target = autoderef.unambiguous_final_ty(); + let mut target = autoderef.unambiguous_final_ty(self); if let Some(mutbl) = pick.autoref { let region = self.next_region_var(infer::Autoref(self.span)); @@ -202,7 +202,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { assert!(pick.unsize.is_none()); } - autoderef.finalize(); + autoderef.finalize(self); // Write out the final adjustments. self.apply_adjustments(self.self_expr, adjustments); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8901f4b6b291b..d4c010b45dfde 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2554,7 +2554,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { while result.is_none() && autoderef.next().is_some() { result = self.try_index_step(expr, base_expr, &autoderef, needs, idx_ty); } - autoderef.finalize(); + autoderef.finalize(self); result } @@ -2571,7 +2571,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { index_ty: Ty<'tcx>) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - let adjusted_ty = autoderef.unambiguous_final_ty(); + let adjusted_ty = autoderef.unambiguous_final_ty(self); debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ index_ty={:?})", expr, @@ -2601,7 +2601,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("try_index_step: success, using overloaded indexing"); let method = self.register_infer_ok_obligations(ok); - let mut adjustments = autoderef.adjust_steps(needs); + let mut adjustments = autoderef.adjust_steps(self, needs); if let ty::Ref(region, _, r_mutbl) = method.sig.inputs()[0].sty { let mutbl = match r_mutbl { hir::MutImmutable => AutoBorrowMutability::Immutable, @@ -3295,9 +3295,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // of error recovery. self.write_field_index(expr.id, index); if field.vis.is_accessible_from(def_scope, self.tcx) { - let adjustments = autoderef.adjust_steps(needs); + let adjustments = autoderef.adjust_steps(self, needs); self.apply_adjustments(base, adjustments); - autoderef.finalize(); + autoderef.finalize(self); self.tcx.check_stability(field.did, Some(expr.id), expr.span); return field_ty; @@ -3310,9 +3310,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Ok(index) = fstr.parse::() { if fstr == index.to_string() { if let Some(field_ty) = tys.get(index) { - let adjustments = autoderef.adjust_steps(needs); + let adjustments = autoderef.adjust_steps(self, needs); self.apply_adjustments(base, adjustments); - autoderef.finalize(); + autoderef.finalize(self); self.write_field_index(expr.id, index); return field_ty; @@ -3323,7 +3323,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } } - autoderef.unambiguous_final_ty(); + autoderef.unambiguous_final_ty(self); if let Some((did, field_ty)) = private_candidate { let struct_path = self.tcx().item_path_str(did); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6471e745aa6fd..e24548cfb239f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -766,7 +766,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, potential_self_ty, self_ty); if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() { - autoderef.finalize(); + autoderef.finalize(fcx); if let Some(mut err) = fcx.demand_eqtype_with_origin( &cause, self_ty, potential_self_ty) { err.emit(); From be2bb4fa1d5788ba1d2df757090daf5fa75df4a2 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 15 Sep 2018 20:23:30 +0300 Subject: [PATCH 3/7] implement "isolated" autoderef using the Canonical mechanism --- .../infer/canonical/query_response.rs | 27 ++ src/librustc_typeck/check/autoderef.rs | 36 ++- src/librustc_typeck/check/method/probe.rs | 266 +++++++++++------- src/librustc_typeck/check/mod.rs | 19 +- src/librustc_typeck/lib.rs | 1 + 5 files changed, 239 insertions(+), 110 deletions(-) diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 8d2b1d74c554b..e225b12366fbd 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -116,6 +116,33 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { Ok(Lrc::new(canonical_result)) } + /// A version of `make_canonicalized_query_response` that does + /// not pack in obligations, for contexts that want to drop + /// pending obligations instead of treating them as an ambiguity (e.g. + /// typeck "probing" contexts). + /// + /// If you DO want to keep track of pending obligations (which + /// include all region obligations, so this includes all cases + /// that care about regions) with this function, you have to + /// do it yourself, by e.g. having them be a part of the answer. + /// + /// TDFX(nikomatsakis): not sure this is the best name. + pub fn make_query_response_with_obligations_pending( + &self, + inference_vars: CanonicalVarValues<'tcx>, + answer: T + ) -> Canonical<'gcx, QueryResponse<'gcx, >::Lifted>> + where + T: Debug + Lift<'gcx> + TypeFoldable<'tcx>, + { + self.canonicalize_response(&QueryResponse { + var_values: inference_vars, + region_constraints: vec![], + certainty: Certainty::Proven, // Ambiguities are OK! + value: answer, + }) + } + /// Helper for `make_canonicalized_query_response` that does /// everything up until the final canonicalization. fn make_query_response( diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index c13ed1bd9d0e7..3fce66a19d865 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -19,7 +19,7 @@ use rustc::ty::{ToPredicate, TypeFoldable}; use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref}; use syntax_pos::Span; -use syntax::ast::{NodeId, Ident}; +use syntax::ast::{self, Ident}; use std::iter; @@ -31,7 +31,7 @@ enum AutoderefKind { pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - body_id: NodeId, + body_id: ast::NodeId, param_env: ty::ParamEnv<'tcx>, steps: Vec<(Ty<'tcx>, AutoderefKind)>, cur_ty: Ty<'tcx>, @@ -107,6 +107,26 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: ast::NodeId, + span: Span, + base_ty: Ty<'tcx>) + -> Autoderef<'a, 'gcx, 'tcx> + { + Autoderef { + infcx, + body_id, + param_env, + steps: vec![], + cur_ty: infcx.resolve_type_vars_if_possible(&base_ty), + obligations: vec![], + at_start: true, + include_raw_pointers: false, + span, + } + } + fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option> { debug!("overloaded_deref_ty({:?})", ty); @@ -231,17 +251,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> { - Autoderef { - infcx: &self.infcx, - body_id: self.body_id, - param_env: self.param_env, - steps: vec![], - cur_ty: self.resolve_type_vars_if_possible(&base_ty), - obligations: vec![], - at_start: true, - include_raw_pointers: false, - span, - } + Autoderef::new(self, self.param_env, self.body_id, span, base_ty) } pub fn try_overloaded_deref(&self, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index dd3c022d53bb3..36aad42e26bad 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -13,20 +13,24 @@ use super::NoMatchData; use super::{CandidateSource, ImplSource, TraitSource}; use super::suggest; +use check::autoderef::Autoderef; use check::FnCtxt; use hir::def_id::DefId; use hir::def::Def; use namespace::Namespace; + use rustc::hir; use rustc::lint; use rustc::session::config::nightly_options; use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, ObligationCause}; -use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable}; +use rustc::ty::{self, ParamEnv, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable}; use rustc::ty::GenericParamDefKind; use rustc::infer::type_variable::TypeVariableOrigin; use rustc::util::nodemap::FxHashSet; use rustc::infer::{self, InferOk}; +use rustc::infer::canonical::{Canonical, QueryResponse}; +use rustc::infer::canonical::{OriginalQueryValues}; use rustc::middle::stability; use syntax::ast; use syntax::util::lev_distance::{lev_distance, find_best_match_for_name}; @@ -51,7 +55,12 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { mode: Mode, method_name: Option, return_type: Option>, - steps: Rc>>, + + /// This is the OriginalQueryValues for the steps queries + /// that are answered in steps. + orig_steps_var_values: OriginalQueryValues<'tcx>, + steps: Rc>>, + inherent_candidates: Vec>, extension_candidates: Vec>, impl_dups: FxHashSet, @@ -82,8 +91,8 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> { } #[derive(Debug)] -struct CandidateStep<'tcx> { - self_ty: Ty<'tcx>, +struct CandidateStep<'gcx> { + self_ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>, autoderefs: usize, // true if the type results from a dereference of a raw pointer. // when assembling candidates, we include these steps, but not when @@ -249,42 +258,86 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> Result> where OP: FnOnce(ProbeContext<'a, 'gcx, 'tcx>) -> Result> { - // FIXME(#18741) -- right now, creating the steps involves evaluating the - // `*` operator, which registers obligations that then escape into - // the global fulfillment context and thus has global - // side-effects. This is a bit of a pain to refactor. So just let - // it ride, although it's really not great, and in fact could I - // think cause spurious errors. Really though this part should - // take place in the `self.probe` below. + let mut orig_values = OriginalQueryValues::default(); + let param_env_and_self_ty = + self.infcx.canonicalize_query(&(self.param_env, self_ty), &mut orig_values); + + // FIXME: consider caching this "whole op" here. let steps = if mode == Mode::MethodCall { - match self.create_steps(span, scope_expr_id, self_ty, is_suggestion) { - Some(steps) => steps, - None => { - return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), - Vec::new(), - Vec::new(), - None, - mode))) - } - } + create_steps_inner(self.tcx.global_tcx(), span, param_env_and_self_ty) } else { - vec![CandidateStep { - self_ty, - autoderefs: 0, - from_unsafe_deref: false, - unsize: false, - }] + self.infcx.probe(|_| { + // Mode::Path - the deref steps is "trivial". This turns + // our CanonicalQuery into a "trivial" QueryResponse. This + // is a bit inefficient, but I don't think that writing + // special handling for this "trivial case" is a good idea. + + let infcx = &self.infcx; + let ((_, self_ty), canonical_inference_vars) = + infcx.instantiate_canonical_with_fresh_inference_vars( + span, ¶m_env_and_self_ty); + debug!("param_env_and_self_ty={:?} self_ty={:?}", param_env_and_self_ty, self_ty); + CreateStepsResult { + steps: vec![CandidateStep { + self_ty: self.make_query_response_with_obligations_pending( + canonical_inference_vars, self_ty), + autoderefs: 0, + from_unsafe_deref: false, + unsize: false, + }], + opt_bad_ty: None + } + }) }; + // If we encountered an `_` type or an error type during autoderef, this is + // ambiguous. + if let Some(CreateStepsBadTy { reached_raw_pointer, ty }) = &steps.opt_bad_ty { + if is_suggestion.0 { + // Ambiguity was encountered during a suggestion. Just keep going. + debug!("ProbeContext: encountered ambiguity in suggestion"); + } else if *reached_raw_pointer && !self.tcx.features().arbitrary_self_types { + // this case used to be allowed by the compiler, + // so we do a future-compat lint here for the 2015 edition + // (see https://github.com/rust-lang/rust/issues/46906) + if self.tcx.sess.rust_2018() { + span_err!(self.tcx.sess, span, E0699, + "the type of this value must be known \ + to call a method on a raw pointer on it"); + } else { + self.tcx.lint_node( + lint::builtin::TYVAR_BEHIND_RAW_POINTER, + scope_expr_id, + span, + "type annotations needed"); + } + } else { + // Encountered a real ambiguity, so abort the lookup. If `ty` is not + // an `Err`, report the right "type annotations needed" error pointing + // to it. + let ty = self.probe_instantiate_query_response(span, &orig_values, ty) + .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); + let t = self.structurally_resolved_type(span, ty.value); + assert_eq!(t, self.tcx.types.err); + return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), + Vec::new(), + Vec::new(), + None, + mode))); + } + } + debug!("ProbeContext: steps for self_ty={:?} are {:?}", self_ty, steps); + // this creates one big transaction so that all type variables etc // that we create during the probe process are removed later self.probe(|_| { let mut probe_cx = ProbeContext::new( - self, span, mode, method_name, return_type, Rc::new(steps), is_suggestion, + self, span, mode, method_name, return_type, orig_values, + Rc::new(steps.steps), is_suggestion, ); probe_cx.assemble_inherent_candidates(); @@ -297,21 +350,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { op(probe_cx) }) } +} + +#[derive(Debug)] +struct CreateStepsResult<'gcx> { + steps: Vec>, + opt_bad_ty: Option> +} - fn create_steps(&self, - span: Span, - scope_expr_id: ast::NodeId, - self_ty: Ty<'tcx>, - is_suggestion: IsSuggestion) - -> Option>> { - // FIXME: we don't need to create the entire steps in one pass +#[derive(Debug)] +struct CreateStepsBadTy<'gcx> { + reached_raw_pointer: bool, + ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>, +} - let mut autoderef = self.autoderef(span, self_ty).include_raw_pointers(); +fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, + span: Span, + pe_and_self_ty: Canonical<'gcx, (ParamEnv<'gcx>, Ty<'gcx>)>) + -> CreateStepsResult<'gcx> +{ + tcx.infer_ctxt().enter(|ref infcx| { + let ((param_env, self_ty), inference_vars) = + infcx.instantiate_canonical_with_fresh_inference_vars(span, &pe_and_self_ty); + let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, span, self_ty) + .include_raw_pointers(); let mut reached_raw_pointer = false; let mut steps: Vec<_> = autoderef.by_ref() .map(|(ty, d)| { let step = CandidateStep { - self_ty: ty, + self_ty: infcx.make_query_response_with_obligations_pending( + inference_vars.clone(), ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, unsize: false, @@ -325,68 +393,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .collect(); let final_ty = autoderef.maybe_ambiguous_final_ty(); - match final_ty.sty { - ty::Infer(ty::TyVar(_)) => { - // Ended in an inference variable. If we are doing - // a real method lookup, this is a hard error because it's - // possible that there will be multiple applicable methods. - if !is_suggestion.0 { - if reached_raw_pointer - && !self.tcx.features().arbitrary_self_types { - // this case used to be allowed by the compiler, - // so we do a future-compat lint here for the 2015 edition - // (see https://github.com/rust-lang/rust/issues/46906) - if self.tcx.sess.rust_2018() { - span_err!(self.tcx.sess, span, E0699, - "the type of this value must be known \ - to call a method on a raw pointer on it"); - } else { - self.tcx.lint_node( - lint::builtin::TYVAR_BEHIND_RAW_POINTER, - scope_expr_id, - span, - "type annotations needed"); - } - } else { - let t = self.structurally_resolved_type(span, final_ty); - assert_eq!(t, self.tcx.types.err); - return None - } - } else { - // If we're just looking for suggestions, - // though, ambiguity is no big thing, we can - // just ignore it. - } + let opt_bad_ty = match final_ty.sty { + ty::Infer(ty::TyVar(_)) | + ty::Error => { + Some(CreateStepsBadTy { + reached_raw_pointer, + ty: infcx.make_query_response_with_obligations_pending( + inference_vars, final_ty) + }) } ty::Array(elem_ty, _) => { let dereferences = steps.len() - 1; steps.push(CandidateStep { - self_ty: self.tcx.mk_slice(elem_ty), + self_ty: infcx.make_query_response_with_obligations_pending( + inference_vars, infcx.tcx.mk_slice(elem_ty)), autoderefs: dereferences, // this could be from an unsafe deref if we had // a *mut/const [T; N] from_unsafe_deref: reached_raw_pointer, unsize: true, }); + + None } - ty::Error => return None, - _ => (), - } + _ => None + }; - debug!("create_steps: steps={:?}", steps); + debug!("create_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty); - Some(steps) - } + CreateStepsResult { steps, opt_bad_ty } + }) } + impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, span: Span, mode: Mode, method_name: Option, return_type: Option>, - steps: Rc>>, + orig_steps_var_values: OriginalQueryValues<'tcx>, + steps: Rc>>, is_suggestion: IsSuggestion) -> ProbeContext<'a, 'gcx, 'tcx> { ProbeContext { @@ -398,7 +446,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { inherent_candidates: Vec::new(), extension_candidates: Vec::new(), impl_dups: FxHashSet::default(), - steps: steps, + orig_steps_var_values, + steps, static_candidates: Vec::new(), allow_similar_names: false, private_candidate: None, @@ -443,18 +492,26 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_inherent_candidates(&mut self) { let steps = self.steps.clone(); for step in steps.iter() { - self.assemble_probe(step.self_ty); + self.assemble_probe(&step.self_ty); } } - fn assemble_probe(&mut self, self_ty: Ty<'tcx>) { + fn assemble_probe(&mut self, self_ty: &Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>) { debug!("assemble_probe: self_ty={:?}", self_ty); let lang_items = self.tcx.lang_items(); - match self_ty.sty { + match self_ty.value.value.sty { ty::Dynamic(ref data, ..) => { let p = data.principal(); - self.assemble_inherent_candidates_from_object(self_ty, p); + self.fcx.probe(|_| { + let InferOk { value: self_ty, obligations: _ } = + self.fcx.probe_instantiate_query_response( + self.span, &self.orig_steps_var_values, self_ty) + .unwrap_or_else(|_| { + span_bug!(self.span, "{:?} was applicable but now isn't?", self_ty) + }); + self.assemble_inherent_candidates_from_object(self_ty); + }); self.assemble_inherent_impl_candidates_for_type(p.def_id()); } ty::Adt(def, _) => { @@ -464,7 +521,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.assemble_inherent_impl_candidates_for_type(did); } ty::Param(p) => { - self.assemble_inherent_candidates_from_param(self_ty, p); + self.assemble_inherent_candidates_from_param(p); } ty::Char => { let lang_def_id = lang_items.char_impl(); @@ -615,11 +672,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn assemble_inherent_candidates_from_object(&mut self, - self_ty: Ty<'tcx>, - principal: ty::PolyExistentialTraitRef<'tcx>) { + self_ty: Ty<'tcx>) { debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty); + let principal = match self_ty.sty { + ty::Dynamic(ref data, ..) => data.principal(), + _ => span_bug!(self.span, "non-object {:?} in assemble_inherent_candidates_from_object", + self_ty) + }; + // It is illegal to invoke a method on a trait instance that // refers to the `Self` type. An error will be reported by // `enforce_object_limitations()` if the method refers to the @@ -642,7 +704,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn assemble_inherent_candidates_from_param(&mut self, - _rcvr_ty: Ty<'tcx>, param_ty: ty::ParamTy) { // FIXME -- Do we want to commit to this behavior for param bounds? @@ -898,14 +959,22 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // a raw pointer !step.self_ty.references_error() && !step.from_unsafe_deref }).flat_map(|step| { - self.pick_by_value_method(step).or_else(|| { - self.pick_autorefd_method(step, hir::MutImmutable).or_else(|| { - self.pick_autorefd_method(step, hir::MutMutable) + let InferOk { value: self_ty, obligations: _ } = + self.fcx.probe_instantiate_query_response( + self.span, &self.orig_steps_var_values, &step.self_ty + ).unwrap_or_else(|_| { + span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty) + }); + self.pick_by_value_method(step, self_ty).or_else(|| { + self.pick_autorefd_method(step, self_ty, hir::MutImmutable).or_else(|| { + self.pick_autorefd_method(step, self_ty, hir::MutMutable) })})}) .next() } - fn pick_by_value_method(&mut self, step: &CandidateStep<'tcx>) -> Option> { + fn pick_by_value_method(&mut self, step: &CandidateStep<'gcx>, self_ty: Ty<'tcx>) + -> Option> + { //! For each type `T` in the step list, this attempts to find a //! method where the (transformed) self type is exactly `T`. We //! do however do one transformation on the adjustment: if we @@ -918,12 +987,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { return None; } - self.pick_method(step.self_ty).map(|r| { + self.pick_method(self_ty).map(|r| { r.map(|mut pick| { pick.autoderefs = step.autoderefs; // Insert a `&*` or `&mut *` if this is a reference type: - if let ty::Ref(_, _, mutbl) = step.self_ty.sty { + if let ty::Ref(_, _, mutbl) = step.self_ty.value.value.sty { pick.autoderefs += 1; pick.autoref = Some(mutbl); } @@ -933,7 +1002,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { }) } - fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>, mutbl: hir::Mutability) + fn pick_autorefd_method(&mut self, + step: &CandidateStep<'gcx>, + self_ty: Ty<'tcx>, + mutbl: hir::Mutability) -> Option> { let tcx = self.tcx; @@ -943,14 +1015,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { - ty: step.self_ty, mutbl + ty: self_ty, mutbl }); self.pick_method(autoref_ty).map(|r| { r.map(|mut pick| { pick.autoderefs = step.autoderefs; pick.autoref = Some(mutbl); pick.unsize = if step.unsize { - Some(step.self_ty) + Some(self_ty) } else { None }; @@ -1288,7 +1360,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let steps = self.steps.clone(); self.probe(|_| { let mut pcx = ProbeContext::new(self.fcx, self.span, self.mode, self.method_name, - self.return_type, steps, IsSuggestion(true)); + self.return_type, + self.orig_steps_var_values.clone(), + steps, IsSuggestion(true)); pcx.allow_similar_names = true; pcx.assemble_inherent_candidates(); pcx.assemble_extension_candidates_for_traits_in_scope(ast::DUMMY_NODE_ID)?; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d4c010b45dfde..7aec741cf4d8e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -102,10 +102,11 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::ItemLikeVisitor; use middle::lang_items; use namespace::Namespace; +use rustc::infer::{self, InferCtxt, InferOk, InferResult, RegionVariableOrigin}; +use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi::Abi; -use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::opaque_types::OpaqueTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; @@ -5349,6 +5350,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; (ctxt, result) } + + /// Instantiate a QueryResponse in a probe context, without a + /// good ObligationCause. + fn probe_instantiate_query_response( + &self, + span: Span, + original_values: &OriginalQueryValues<'tcx>, + query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, + ) -> InferResult<'tcx, Ty<'tcx>> + { + self.instantiate_query_response_and_region_obligations( + &traits::ObligationCause::misc(span, self.body_id), + self.param_env, + original_values, + query_result) + } } pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 8d6fb8b7f3948..fdc81a6ed1a9c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -90,6 +90,7 @@ This API is completely unstable and subject to change. extern crate syntax_pos; extern crate arena; + #[macro_use] extern crate rustc; extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_data_structures; From e25e2e0600e13022ad30c1f6c7ddfdfd58e9efa1 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 2 Dec 2018 00:29:06 +0200 Subject: [PATCH 4/7] make autoderef steps a query --- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/traits/query/method_autoderef.rs | 52 +++++++++++ src/librustc/traits/query/mod.rs | 1 + src/librustc/ty/query/config.rs | 6 ++ src/librustc/ty/query/mod.rs | 5 + src/librustc/ty/query/plumbing.rs | 1 + src/librustc_typeck/check/method/mod.rs | 1 + src/librustc_typeck/check/method/probe.rs | 91 +++++++++---------- 8 files changed, 110 insertions(+), 48 deletions(-) create mode 100644 src/librustc/traits/query/method_autoderef.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index f0c6196412adb..61efdc8204627 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -666,6 +666,7 @@ define_dep_nodes!( <'tcx> [] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>), [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, + [] MethodAutoderefSteps(CanonicalTyGoal<'tcx>), [input] TargetFeaturesWhitelist, diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs new file mode 100644 index 0000000000000..e67497915d7cb --- /dev/null +++ b/src/librustc/traits/query/method_autoderef.rs @@ -0,0 +1,52 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc_data_structures::sync::Lrc; +use infer::canonical::{Canonical, QueryResponse}; +use ty::Ty; + +#[derive(Debug)] +pub struct CandidateStep<'tcx> { + pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, + pub autoderefs: usize, + // true if the type results from a dereference of a raw pointer. + // when assembling candidates, we include these steps, but not when + // picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods + // `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then + // `foo.by_raw_ptr()` will work and `foo.by_ref()` won't. + pub from_unsafe_deref: bool, + pub unsize: bool, +} + +#[derive(Clone, Debug)] +pub struct MethodAutoderefStepsResult<'tcx> { + /// The valid autoderef steps that could be find. + pub steps: Lrc>>, + /// If Some(T), a type autoderef reported an error on. + pub opt_bad_ty: Option>> +} + +#[derive(Debug)] +pub struct MethodAutoderefBadTy<'tcx> { + pub reached_raw_pointer: bool, + pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, +} + +impl_stable_hash_for!(struct MethodAutoderefBadTy<'tcx> { + reached_raw_pointer, ty +}); + +impl_stable_hash_for!(struct MethodAutoderefStepsResult<'tcx> { + steps, opt_bad_ty +}); + +impl_stable_hash_for!(struct CandidateStep<'tcx> { + self_ty, autoderefs, from_unsafe_deref, unsize +}); diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 13683d8544496..b11cb7377645c 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -21,6 +21,7 @@ use ty::{self, Ty}; pub mod dropck_outlives; pub mod evaluate_obligation; +pub mod method_autoderef; pub mod normalize; pub mod normalize_erasing_regions; pub mod outlives_bounds; diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index fd9143be679a4..b320c29dfada5 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -827,6 +827,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::substitute_normalize_and_test_pre } } +impl<'tcx> QueryDescription<'tcx> for queries::method_autoderef_steps<'tcx> { + fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTyGoal<'tcx>) -> Cow<'static, str> { + format!("computing autoderef types for `{:?}`", goal).into() + } +} + impl<'tcx> QueryDescription<'tcx> for queries::target_features_whitelist<'tcx> { fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { "looking up the whitelist of target features".into() diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 5cd06fb8a52c0..0e6810face528 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -40,6 +40,7 @@ use traits::query::{ CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution, }; +use traits::query::method_autoderef::MethodAutoderefStepsResult; use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; use traits::query::outlives_bounds::OutlivesBound; @@ -668,6 +669,10 @@ define_queries! { <'tcx> [] fn substitute_normalize_and_test_predicates: substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, + + [] fn method_autoderef_steps: MethodAutoderefSteps( + CanonicalTyGoal<'tcx> + ) -> MethodAutoderefStepsResult<'tcx>, }, Other { diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 5f33d466c4a19..3fac2db281bb9 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1089,6 +1089,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TypeOpNormalizePolyFnSig | DepKind::TypeOpNormalizeFnSig | DepKind::SubstituteNormalizeAndTestPredicates | + DepKind::MethodAutoderefSteps | DepKind::InstanceDefSizeEstimate | DepKind::ProgramClausesForEnv | diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 858d8c742dfd9..5ecbfcd132cf3 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -39,6 +39,7 @@ use self::probe::{IsSuggestion, ProbeScope}; pub fn provide(providers: &mut ty::query::Providers) { suggest::provide(providers); + probe::provide(providers); } #[derive(Clone, Copy, Debug)] diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 36aad42e26bad..539c33cc14ae9 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -19,12 +19,16 @@ use hir::def_id::DefId; use hir::def::Def; use namespace::Namespace; +use rustc_data_structures::sync::Lrc; use rustc::hir; use rustc::lint; use rustc::session::config::nightly_options; use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, ObligationCause}; -use rustc::ty::{self, ParamEnv, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable}; +use rustc::traits::query::{CanonicalTyGoal}; +use rustc::traits::query::method_autoderef::{CandidateStep, MethodAutoderefStepsResult}; +use rustc::traits::query::method_autoderef::{MethodAutoderefBadTy}; +use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable}; use rustc::ty::GenericParamDefKind; use rustc::infer::type_variable::TypeVariableOrigin; use rustc::util::nodemap::FxHashSet; @@ -34,7 +38,7 @@ use rustc::infer::canonical::{OriginalQueryValues}; use rustc::middle::stability; use syntax::ast; use syntax::util::lev_distance::{lev_distance, find_best_match_for_name}; -use syntax_pos::{Span, symbol::Symbol}; +use syntax_pos::{DUMMY_SP, Span, symbol::Symbol}; use std::iter; use std::mem; use std::ops::Deref; @@ -59,7 +63,7 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { /// This is the OriginalQueryValues for the steps queries /// that are answered in steps. orig_steps_var_values: OriginalQueryValues<'tcx>, - steps: Rc>>, + steps: Lrc>>, inherent_candidates: Vec>, extension_candidates: Vec>, @@ -90,19 +94,6 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> { } } -#[derive(Debug)] -struct CandidateStep<'gcx> { - self_ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>, - autoderefs: usize, - // true if the type results from a dereference of a raw pointer. - // when assembling candidates, we include these steps, but not when - // picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods - // `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then - // `foo.by_raw_ptr()` will work and `foo.by_ref()` won't. - from_unsafe_deref: bool, - unsize: bool, -} - #[derive(Debug)] struct Candidate<'tcx> { xform_self_ty: Ty<'tcx>, @@ -260,11 +251,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { let mut orig_values = OriginalQueryValues::default(); let param_env_and_self_ty = - self.infcx.canonicalize_query(&(self.param_env, self_ty), &mut orig_values); + self.infcx.canonicalize_query( + &ParamEnvAnd { + param_env: self.param_env, + value: self_ty + }, &mut orig_values); - // FIXME: consider caching this "whole op" here. let steps = if mode == Mode::MethodCall { - create_steps_inner(self.tcx.global_tcx(), span, param_env_and_self_ty) + self.tcx.method_autoderef_steps(param_env_and_self_ty) } else { self.infcx.probe(|_| { // Mode::Path - the deref steps is "trivial". This turns @@ -273,18 +267,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // special handling for this "trivial case" is a good idea. let infcx = &self.infcx; - let ((_, self_ty), canonical_inference_vars) = + let (ParamEnvAnd { + param_env: _, + value: self_ty + }, canonical_inference_vars) = infcx.instantiate_canonical_with_fresh_inference_vars( span, ¶m_env_and_self_ty); - debug!("param_env_and_self_ty={:?} self_ty={:?}", param_env_and_self_ty, self_ty); - CreateStepsResult { - steps: vec![CandidateStep { + debug!("probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}", + param_env_and_self_ty, self_ty); + MethodAutoderefStepsResult { + steps: Lrc::new(vec![CandidateStep { self_ty: self.make_query_response_with_obligations_pending( canonical_inference_vars, self_ty), autoderefs: 0, from_unsafe_deref: false, unsize: false, - }], + }]), opt_bad_ty: None } }) @@ -292,11 +290,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If we encountered an `_` type or an error type during autoderef, this is // ambiguous. - if let Some(CreateStepsBadTy { reached_raw_pointer, ty }) = &steps.opt_bad_ty { + if let Some(autoderef_bad_ty) = &steps.opt_bad_ty { + let MethodAutoderefBadTy { reached_raw_pointer, ref ty } = **autoderef_bad_ty; if is_suggestion.0 { // Ambiguity was encountered during a suggestion. Just keep going. debug!("ProbeContext: encountered ambiguity in suggestion"); - } else if *reached_raw_pointer && !self.tcx.features().arbitrary_self_types { + } else if reached_raw_pointer && !self.tcx.features().arbitrary_self_types { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) @@ -337,7 +336,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.probe(|_| { let mut probe_cx = ProbeContext::new( self, span, mode, method_name, return_type, orig_values, - Rc::new(steps.steps), is_suggestion, + steps.steps, is_suggestion, ); probe_cx.assemble_inherent_candidates(); @@ -352,27 +351,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } -#[derive(Debug)] -struct CreateStepsResult<'gcx> { - steps: Vec>, - opt_bad_ty: Option> -} - -#[derive(Debug)] -struct CreateStepsBadTy<'gcx> { - reached_raw_pointer: bool, - ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>, +pub fn provide(providers: &mut ty::query::Providers) { + providers.method_autoderef_steps = method_autoderef_steps; } -fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, - span: Span, - pe_and_self_ty: Canonical<'gcx, (ParamEnv<'gcx>, Ty<'gcx>)>) - -> CreateStepsResult<'gcx> +fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, + goal: CanonicalTyGoal<'tcx>) + -> MethodAutoderefStepsResult<'gcx> { - tcx.infer_ctxt().enter(|ref infcx| { - let ((param_env, self_ty), inference_vars) = - infcx.instantiate_canonical_with_fresh_inference_vars(span, &pe_and_self_ty); - let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, span, self_ty) + debug!("method_autoderef_steps({:?})", goal); + + tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| { + let ParamEnvAnd { param_env, value: self_ty } = goal; + + let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, DUMMY_SP, self_ty) .include_raw_pointers(); let mut reached_raw_pointer = false; let mut steps: Vec<_> = autoderef.by_ref() @@ -396,7 +388,7 @@ fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, let opt_bad_ty = match final_ty.sty { ty::Infer(ty::TyVar(_)) | ty::Error => { - Some(CreateStepsBadTy { + Some(MethodAutoderefBadTy { reached_raw_pointer, ty: infcx.make_query_response_with_obligations_pending( inference_vars, final_ty) @@ -420,9 +412,12 @@ fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, _ => None }; - debug!("create_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty); + debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty); - CreateStepsResult { steps, opt_bad_ty } + MethodAutoderefStepsResult { + steps: Lrc::new(steps), + opt_bad_ty: opt_bad_ty.map(Lrc::new) + } }) } From 12c17f91103c125397d4a95212349f226ddba3bd Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 2 Dec 2018 18:21:41 +0200 Subject: [PATCH 5/7] move overflow error reporting out of the query that allows the error reporting to contain the span. --- src/librustc/traits/query/method_autoderef.rs | 7 ++- src/librustc_typeck/check/autoderef.rs | 58 +++++++++++++------ src/librustc_typeck/check/method/probe.rs | 37 +++++++++--- 3 files changed, 73 insertions(+), 29 deletions(-) diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs index e67497915d7cb..175883eb2a734 100644 --- a/src/librustc/traits/query/method_autoderef.rs +++ b/src/librustc/traits/query/method_autoderef.rs @@ -30,7 +30,10 @@ pub struct MethodAutoderefStepsResult<'tcx> { /// The valid autoderef steps that could be find. pub steps: Lrc>>, /// If Some(T), a type autoderef reported an error on. - pub opt_bad_ty: Option>> + pub opt_bad_ty: Option>>, + /// If `true`, `steps` has been truncated due to reaching the + /// recursion limit. + pub reached_recursion_limit: bool, } #[derive(Debug)] @@ -44,7 +47,7 @@ impl_stable_hash_for!(struct MethodAutoderefBadTy<'tcx> { }); impl_stable_hash_for!(struct MethodAutoderefStepsResult<'tcx> { - steps, opt_bad_ty + reached_recursion_limit, steps, opt_bad_ty }); impl_stable_hash_for!(struct CandidateStep<'tcx> { diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 3fce66a19d865..d240f45c7d9a4 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -14,7 +14,7 @@ use super::method::MethodCallee; use rustc::infer::{InferCtxt, InferOk}; use rustc::session::DiagnosticMessageId; use rustc::traits::{self, TraitEngine}; -use rustc::ty::{self, Ty, TraitRef}; +use rustc::ty::{self, Ty, TyCtxt, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref}; @@ -39,6 +39,8 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> { at_start: bool, include_raw_pointers: bool, span: Span, + silence_errors: bool, + reached_recursion_limit: bool } impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { @@ -57,24 +59,10 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { } if self.steps.len() >= *tcx.sess.recursion_limit.get() { - // We've reached the recursion limit, error gracefully. - let suggested_limit = *tcx.sess.recursion_limit.get() * 2; - let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", - self.cur_ty); - let error_id = (DiagnosticMessageId::ErrorId(55), Some(self.span), msg); - let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); - if fresh { - struct_span_err!(tcx.sess, - self.span, - E0055, - "reached the recursion limit while auto-dereferencing `{:?}`", - self.cur_ty) - .span_label(self.span, "deref recursion limit reached") - .help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit)) - .emit(); + if !self.silence_errors { + report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty); } + self.reached_recursion_limit = true; return None; } @@ -123,6 +111,8 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { obligations: vec![], at_start: true, include_raw_pointers: false, + silence_errors: false, + reached_recursion_limit: false, span, } } @@ -240,6 +230,15 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self } + pub fn silence_errors(mut self) -> Self { + self.silence_errors = true; + self + } + + pub fn reached_recursion_limit(&self) -> bool { + self.reached_recursion_limit + } + pub fn finalize(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { fcx.register_predicates(self.into_obligations()); } @@ -249,6 +248,29 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } } +pub fn report_autoderef_recursion_limit_error<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, span: Span, ty: Ty<'tcx>) +{ + // We've reached the recursion limit, error gracefully. + let suggested_limit = *tcx.sess.recursion_limit.get() * 2; + let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", + ty); + let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg); + let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); + if fresh { + struct_span_err!(tcx.sess, + span, + E0055, + "reached the recursion limit while auto-dereferencing `{:?}`", + ty) + .span_label(span, "deref recursion limit reached") + .help(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)) + .emit(); + } +} + impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> { Autoderef::new(self, self.param_env, self.body_id, span, base_ty) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 539c33cc14ae9..29fd9f5f71e8e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -13,7 +13,7 @@ use super::NoMatchData; use super::{CandidateSource, ImplSource, TraitSource}; use super::suggest; -use check::autoderef::Autoderef; +use check::autoderef::{self, Autoderef}; use check::FnCtxt; use hir::def_id::DefId; use hir::def::Def; @@ -283,19 +283,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { from_unsafe_deref: false, unsize: false, }]), - opt_bad_ty: None + opt_bad_ty: None, + reached_recursion_limit: false } }) }; + // If our autoderef loop had reached the recursion limit, + // report an overflow error, but continue going on with + // the truncated autoderef list. + if steps.reached_recursion_limit { + self.probe(|_| { + let ty = &steps.steps.last().unwrap_or_else(|| { + span_bug!(span, "reached the recursion limit in 0 steps?") + }).self_ty; + let ty = self.probe_instantiate_query_response(span, &orig_values, ty) + .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); + autoderef::report_autoderef_recursion_limit_error(self.tcx, span, + ty.value); + }); + } + + // If we encountered an `_` type or an error type during autoderef, this is // ambiguous. - if let Some(autoderef_bad_ty) = &steps.opt_bad_ty { - let MethodAutoderefBadTy { reached_raw_pointer, ref ty } = **autoderef_bad_ty; + if let Some(bad_ty) = &steps.opt_bad_ty { if is_suggestion.0 { // Ambiguity was encountered during a suggestion. Just keep going. debug!("ProbeContext: encountered ambiguity in suggestion"); - } else if reached_raw_pointer && !self.tcx.features().arbitrary_self_types { + } else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) @@ -314,10 +330,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Encountered a real ambiguity, so abort the lookup. If `ty` is not // an `Err`, report the right "type annotations needed" error pointing // to it. + let ty = &bad_ty.ty; let ty = self.probe_instantiate_query_response(span, &orig_values, ty) .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); - let t = self.structurally_resolved_type(span, ty.value); - assert_eq!(t, self.tcx.types.err); + let ty = self.structurally_resolved_type(span, ty.value); + assert_eq!(ty, self.tcx.types.err); return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(), Vec::new(), @@ -365,7 +382,8 @@ fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, let ParamEnvAnd { param_env, value: self_ty } = goal; let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, DUMMY_SP, self_ty) - .include_raw_pointers(); + .include_raw_pointers() + .silence_errors(); let mut reached_raw_pointer = false; let mut steps: Vec<_> = autoderef.by_ref() .map(|(ty, d)| { @@ -416,7 +434,8 @@ fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, MethodAutoderefStepsResult { steps: Lrc::new(steps), - opt_bad_ty: opt_bad_ty.map(Lrc::new) + opt_bad_ty: opt_bad_ty.map(Lrc::new), + reached_recursion_limit: autoderef.reached_recursion_limit() } }) } From 0152d33bc1aa2e57800cc68c811f843e9aa6676d Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 3 Dec 2018 01:43:00 +0200 Subject: [PATCH 6/7] fix Rc -> Lrc --- src/librustc_typeck/check/method/probe.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 29fd9f5f71e8e..573253c2e1b45 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -42,7 +42,6 @@ use syntax_pos::{DUMMY_SP, Span, symbol::Symbol}; use std::iter; use std::mem; use std::ops::Deref; -use std::rc::Rc; use std::cmp::max; use self::CandidateKind::*; @@ -448,7 +447,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { method_name: Option, return_type: Option>, orig_steps_var_values: OriginalQueryValues<'tcx>, - steps: Rc>>, + steps: Lrc>>, is_suggestion: IsSuggestion) -> ProbeContext<'a, 'gcx, 'tcx> { ProbeContext { From b4db387a6c886d4242a94d997c48967abd63314c Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 15 Dec 2018 01:22:41 +0200 Subject: [PATCH 7/7] address review comments --- src/librustc/infer/canonical/query_response.rs | 4 +--- src/librustc_typeck/check/method/probe.rs | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index e225b12366fbd..ebfc20e30f74e 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -125,9 +125,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// include all region obligations, so this includes all cases /// that care about regions) with this function, you have to /// do it yourself, by e.g. having them be a part of the answer. - /// - /// TDFX(nikomatsakis): not sure this is the best name. - pub fn make_query_response_with_obligations_pending( + pub fn make_query_response_ignoring_pending_obligations( &self, inference_vars: CanonicalVarValues<'tcx>, answer: T diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 573253c2e1b45..190419048b4b5 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -276,7 +276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { param_env_and_self_ty, self_ty); MethodAutoderefStepsResult { steps: Lrc::new(vec![CandidateStep { - self_ty: self.make_query_response_with_obligations_pending( + self_ty: self.make_query_response_ignoring_pending_obligations( canonical_inference_vars, self_ty), autoderefs: 0, from_unsafe_deref: false, @@ -387,7 +387,7 @@ fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, let mut steps: Vec<_> = autoderef.by_ref() .map(|(ty, d)| { let step = CandidateStep { - self_ty: infcx.make_query_response_with_obligations_pending( + self_ty: infcx.make_query_response_ignoring_pending_obligations( inference_vars.clone(), ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, @@ -407,7 +407,7 @@ fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, ty::Error => { Some(MethodAutoderefBadTy { reached_raw_pointer, - ty: infcx.make_query_response_with_obligations_pending( + ty: infcx.make_query_response_ignoring_pending_obligations( inference_vars, final_ty) }) } @@ -415,7 +415,7 @@ fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, let dereferences = steps.len() - 1; steps.push(CandidateStep { - self_ty: infcx.make_query_response_with_obligations_pending( + self_ty: infcx.make_query_response_ignoring_pending_obligations( inference_vars, infcx.tcx.mk_slice(elem_ty)), autoderefs: dereferences, // this could be from an unsafe deref if we had