Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

process nested obligations in autoderef #54252

Merged
merged 7 commits into from
Dec 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ define_dep_nodes!( <'tcx>
[] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>),

[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
[] MethodAutoderefSteps(CanonicalTyGoal<'tcx>),

[input] TargetFeaturesWhitelist,

Expand Down
25 changes: 25 additions & 0 deletions src/librustc/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,31 @@ 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.
pub fn make_query_response_ignoring_pending_obligations<T>(
&self,
inference_vars: CanonicalVarValues<'tcx>,
answer: T
) -> Canonical<'gcx, QueryResponse<'gcx, <T as Lift<'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<T>(
Expand Down
26 changes: 23 additions & 3 deletions src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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
}
}

Expand Down Expand Up @@ -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,
Expand Down
55 changes: 55 additions & 0 deletions src/librustc/traits/query/method_autoderef.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Vec<CandidateStep<'tcx>>>,
/// If Some(T), a type autoderef reported an error on.
pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
/// If `true`, `steps` has been truncated due to reaching the
/// recursion limit.
pub reached_recursion_limit: bool,
}

#[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> {
reached_recursion_limit, steps, opt_bad_ty
});

impl_stable_hash_for!(struct CandidateStep<'tcx> {
self_ty, autoderefs, from_unsafe_deref, unsize
});
1 change: 1 addition & 0 deletions src/librustc/traits/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/ty/query/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/ty/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ty/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 |

Expand Down
Loading