Auto merge of #56384 - scalexm:chalk, r=nikomatsakis
Implement the new-style trait solver Final PR of what I believe to be a minimally working implementation of the new-style trait solver. The new trait solver can be used by providing the `-Z chalk` command line flag. It is currently used everywhere in `rustc_typeck`, and for everything relying on `rustc::infer::canonical::query_response::enter_canonical_trait_query`. The trait solver is invoked in rustc by using the `evaluate_goal` canonical query. This is not optimal because each call to `evaluate_goal` creates a new `chalk_engine::Forest`, hence rustc cannot use answers to intermediate goals produced by the root goal. We'll need to change that but I guess that's ok for now. Some next steps, I think, are: * handle region constraints: region constraints are computed but are completely ignored for now, I think we may need additional support from `chalk_engine` (as a side effect, types or trait references with outlive requirements cannot be proved well-formed) * deactivate eager normalization in the presence of `-Z chalk` in order to leverage the lazy normalization strategy of the new-style trait solver * add the remaining built-in impls (only `Sized` is supported currently) * transition the compiler to using generic goals instead of predicates that still refer to named type parameters etc I added a few very simple tests to check that the new solver has the right behavior, they won't be needed anymore once it is mature enough. Additionally it shows off that we get [implied bounds](https://github.com/rust-lang/rust/issues/44491) for free. r? @nikomatsakis
This commit is contained in:
commit
fb86d604bf
48 changed files with 1311 additions and 293 deletions
|
|
@ -273,7 +273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chalk-engine"
|
name = "chalk-engine"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
@ -2067,7 +2067,7 @@ dependencies = [
|
||||||
"backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fmt_macros 0.0.0",
|
"fmt_macros 0.0.0",
|
||||||
"graphviz 0.0.0",
|
"graphviz 0.0.0",
|
||||||
|
|
@ -2640,7 +2640,7 @@ name = "rustc_traits"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"graphviz 0.0.0",
|
"graphviz 0.0.0",
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc 0.0.0",
|
"rustc 0.0.0",
|
||||||
|
|
@ -3403,7 +3403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d8dfe3adeb30f7938e6c1dd5327f29235d8ada3e898aeb08c343005ec2915a2"
|
"checksum cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d8dfe3adeb30f7938e6c1dd5327f29235d8ada3e898aeb08c343005ec2915a2"
|
||||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||||
"checksum chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6749eb72e7d4355d944a99f15fbaea701b978c18c5e184a025fcde942b0c9779"
|
"checksum chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17ec698a6f053a23bfbe646d9f2fde4b02abc19125595270a99e6f44ae0bdd1a"
|
||||||
"checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e"
|
"checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e"
|
||||||
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
||||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ syntax_pos = { path = "../libsyntax_pos" }
|
||||||
backtrace = "0.3.3"
|
backtrace = "0.3.3"
|
||||||
parking_lot = "0.6"
|
parking_lot = "0.6"
|
||||||
byteorder = { version = "1.1", features = ["i128"]}
|
byteorder = { version = "1.1", features = ["i128"]}
|
||||||
chalk-engine = { version = "0.8.0", default-features=false }
|
chalk-engine = { version = "0.9.0", default-features=false }
|
||||||
rustc_fs_util = { path = "../librustc_fs_util" }
|
rustc_fs_util = { path = "../librustc_fs_util" }
|
||||||
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
|
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -648,6 +648,7 @@ define_dep_nodes!( <'tcx>
|
||||||
[] ImpliedOutlivesBounds(CanonicalTyGoal<'tcx>),
|
[] ImpliedOutlivesBounds(CanonicalTyGoal<'tcx>),
|
||||||
[] DropckOutlives(CanonicalTyGoal<'tcx>),
|
[] DropckOutlives(CanonicalTyGoal<'tcx>),
|
||||||
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
|
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
|
||||||
|
[] EvaluateGoal(traits::ChalkCanonicalGoal<'tcx>),
|
||||||
[] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>),
|
[] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>),
|
||||||
[] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>),
|
[] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>),
|
||||||
[] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>),
|
[] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>),
|
||||||
|
|
|
||||||
|
|
@ -885,7 +885,8 @@ for ty::steal::Steal<T>
|
||||||
|
|
||||||
impl_stable_hash_for!(struct ty::ParamEnv<'tcx> {
|
impl_stable_hash_for!(struct ty::ParamEnv<'tcx> {
|
||||||
caller_bounds,
|
caller_bounds,
|
||||||
reveal
|
reveal,
|
||||||
|
def_id
|
||||||
});
|
});
|
||||||
|
|
||||||
impl_stable_hash_for!(enum traits::Reveal {
|
impl_stable_hash_for!(enum traits::Reveal {
|
||||||
|
|
@ -1194,6 +1195,10 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Goal<'tcx> {
|
||||||
quantifier.hash_stable(hcx, hasher);
|
quantifier.hash_stable(hcx, hasher);
|
||||||
goal.hash_stable(hcx, hasher);
|
goal.hash_stable(hcx, hasher);
|
||||||
},
|
},
|
||||||
|
Subtype(a, b) => {
|
||||||
|
a.hash_stable(hcx, hasher);
|
||||||
|
b.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
CannotProve => { },
|
CannotProve => { },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1239,3 +1244,10 @@ impl_stable_hash_for!(
|
||||||
clauses,
|
clauses,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
impl_stable_hash_for!(
|
||||||
|
impl<'tcx, G> for struct traits::InEnvironment<'tcx, G> {
|
||||||
|
environment,
|
||||||
|
goal,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
||||||
|
|
@ -330,9 +330,13 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
|
||||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
match t.sty {
|
match t.sty {
|
||||||
ty::Infer(ty::TyVar(vid)) => {
|
ty::Infer(ty::TyVar(vid)) => {
|
||||||
|
debug!("canonical: type var found with vid {:?}", vid);
|
||||||
match self.infcx.unwrap().probe_ty_var(vid) {
|
match self.infcx.unwrap().probe_ty_var(vid) {
|
||||||
// `t` could be a float / int variable: canonicalize that instead
|
// `t` could be a float / int variable: canonicalize that instead
|
||||||
Ok(t) => self.fold_ty(t),
|
Ok(t) => {
|
||||||
|
debug!("(resolved to {:?})", t);
|
||||||
|
self.fold_ty(t)
|
||||||
|
}
|
||||||
|
|
||||||
// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
|
// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
|
||||||
// result
|
// result
|
||||||
|
|
@ -448,7 +452,12 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// Fast path: nothing that needs to be canonicalized.
|
// Fast path: nothing that needs to be canonicalized.
|
||||||
if !value.has_type_flags(needs_canonical_flags) {
|
if !value.has_type_flags(needs_canonical_flags) {
|
||||||
let out_value = gcx.lift(value).unwrap();
|
let out_value = gcx.lift(value).unwrap_or_else(|| {
|
||||||
|
bug!(
|
||||||
|
"failed to lift `{:?}` (nothing to canonicalize)",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
});
|
||||||
let canon_value = Canonical {
|
let canon_value = Canonical {
|
||||||
max_universe: ty::UniverseIndex::ROOT,
|
max_universe: ty::UniverseIndex::ROOT,
|
||||||
variables: List::empty(),
|
variables: List::empty(),
|
||||||
|
|
|
||||||
|
|
@ -420,9 +420,33 @@ BraceStructLiftImpl! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> CanonicalVarValues<'tcx> {
|
impl<'tcx> CanonicalVarValues<'tcx> {
|
||||||
fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.var_values.len()
|
self.var_values.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Make an identity substitution from this one: each bound var
|
||||||
|
/// is matched to the same bound var, preserving the original kinds.
|
||||||
|
/// For example, if we have:
|
||||||
|
/// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
|
||||||
|
/// we'll return a substitution `subst` with:
|
||||||
|
/// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
|
||||||
|
pub fn make_identity<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
|
||||||
|
use ty::subst::UnpackedKind;
|
||||||
|
|
||||||
|
CanonicalVarValues {
|
||||||
|
var_values: self.var_values.iter()
|
||||||
|
.zip(0..)
|
||||||
|
.map(|(kind, i)| match kind.unpack() {
|
||||||
|
UnpackedKind::Type(..) => tcx.mk_ty(
|
||||||
|
ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())
|
||||||
|
).into(),
|
||||||
|
UnpackedKind::Lifetime(..) => tcx.mk_region(
|
||||||
|
ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))
|
||||||
|
).into(),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
|
impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ use rustc_data_structures::sync::Lrc;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use syntax_pos::DUMMY_SP;
|
use syntax_pos::DUMMY_SP;
|
||||||
use traits::query::{Fallible, NoSolution};
|
use traits::query::{Fallible, NoSolution};
|
||||||
use traits::{FulfillmentContext, TraitEngine};
|
use traits::TraitEngine;
|
||||||
use traits::{Obligation, ObligationCause, PredicateObligation};
|
use traits::{Obligation, ObligationCause, PredicateObligation};
|
||||||
use ty::fold::TypeFoldable;
|
use ty::fold::TypeFoldable;
|
||||||
use ty::subst::{Kind, UnpackedKind};
|
use ty::subst::{Kind, UnpackedKind};
|
||||||
|
|
@ -48,7 +48,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
|
||||||
pub fn enter_canonical_trait_query<K, R>(
|
pub fn enter_canonical_trait_query<K, R>(
|
||||||
&'tcx mut self,
|
&'tcx mut self,
|
||||||
canonical_key: &Canonical<'tcx, K>,
|
canonical_key: &Canonical<'tcx, K>,
|
||||||
operation: impl FnOnce(&InferCtxt<'_, 'gcx, 'tcx>, &mut FulfillmentContext<'tcx>, K)
|
operation: impl FnOnce(&InferCtxt<'_, 'gcx, 'tcx>, &mut dyn TraitEngine<'tcx>, K)
|
||||||
-> Fallible<R>,
|
-> Fallible<R>,
|
||||||
) -> Fallible<CanonicalizedQueryResponse<'gcx, R>>
|
) -> Fallible<CanonicalizedQueryResponse<'gcx, R>>
|
||||||
where
|
where
|
||||||
|
|
@ -59,9 +59,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
|
||||||
DUMMY_SP,
|
DUMMY_SP,
|
||||||
canonical_key,
|
canonical_key,
|
||||||
|ref infcx, key, canonical_inference_vars| {
|
|ref infcx, key, canonical_inference_vars| {
|
||||||
let fulfill_cx = &mut FulfillmentContext::new();
|
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
|
||||||
let value = operation(infcx, fulfill_cx, key)?;
|
let value = operation(infcx, &mut *fulfill_cx, key)?;
|
||||||
infcx.make_canonicalized_query_response(canonical_inference_vars, value, fulfill_cx)
|
infcx.make_canonicalized_query_response(
|
||||||
|
canonical_inference_vars,
|
||||||
|
value,
|
||||||
|
&mut *fulfill_cx
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -91,7 +95,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
inference_vars: CanonicalVarValues<'tcx>,
|
inference_vars: CanonicalVarValues<'tcx>,
|
||||||
answer: T,
|
answer: T,
|
||||||
fulfill_cx: &mut FulfillmentContext<'tcx>,
|
fulfill_cx: &mut dyn TraitEngine<'tcx>,
|
||||||
) -> Fallible<CanonicalizedQueryResponse<'gcx, T>>
|
) -> Fallible<CanonicalizedQueryResponse<'gcx, T>>
|
||||||
where
|
where
|
||||||
T: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
|
T: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
|
||||||
|
|
@ -138,7 +142,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
inference_vars: CanonicalVarValues<'tcx>,
|
inference_vars: CanonicalVarValues<'tcx>,
|
||||||
answer: T,
|
answer: T,
|
||||||
fulfill_cx: &mut FulfillmentContext<'tcx>,
|
fulfill_cx: &mut dyn TraitEngine<'tcx>,
|
||||||
) -> Result<QueryResponse<'tcx, T>, NoSolution>
|
) -> Result<QueryResponse<'tcx, T>, NoSolution>
|
||||||
where
|
where
|
||||||
T: Debug + TypeFoldable<'tcx> + Lift<'gcx>,
|
T: Debug + TypeFoldable<'tcx> + Lift<'gcx>,
|
||||||
|
|
|
||||||
|
|
@ -581,7 +581,7 @@ impl<'tcx, T> InferOk<'tcx, T> {
|
||||||
pub fn into_value_registering_obligations(
|
pub fn into_value_registering_obligations(
|
||||||
self,
|
self,
|
||||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||||
fulfill_cx: &mut impl TraitEngine<'tcx>,
|
fulfill_cx: &mut dyn TraitEngine<'tcx>,
|
||||||
) -> T {
|
) -> T {
|
||||||
let InferOk { value, obligations } = self;
|
let InferOk { value, obligations } = self;
|
||||||
for obligation in obligations {
|
for obligation in obligations {
|
||||||
|
|
|
||||||
|
|
@ -388,12 +388,17 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||||
computed_preds.extend(user_computed_preds.iter().cloned());
|
computed_preds.extend(user_computed_preds.iter().cloned());
|
||||||
let normalized_preds =
|
let normalized_preds =
|
||||||
elaborate_predicates(tcx, computed_preds.clone().into_iter().collect());
|
elaborate_predicates(tcx, computed_preds.clone().into_iter().collect());
|
||||||
new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal);
|
new_env = ty::ParamEnv::new(
|
||||||
|
tcx.mk_predicates(normalized_preds),
|
||||||
|
param_env.reveal,
|
||||||
|
None
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let final_user_env = ty::ParamEnv::new(
|
let final_user_env = ty::ParamEnv::new(
|
||||||
tcx.mk_predicates(user_computed_preds.into_iter()),
|
tcx.mk_predicates(user_computed_preds.into_iter()),
|
||||||
user_env.reveal,
|
user_env.reveal,
|
||||||
|
None
|
||||||
);
|
);
|
||||||
debug!(
|
debug!(
|
||||||
"evaluate_nested_obligations(ty_did={:?}, trait_did={:?}): succeeded with '{:?}' \
|
"evaluate_nested_obligations(ty_did={:?}, trait_did={:?}): succeeded with '{:?}' \
|
||||||
|
|
|
||||||
165
src/librustc/traits/chalk_fulfill.rs
Normal file
165
src/librustc/traits/chalk_fulfill.rs
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
use traits::{
|
||||||
|
Environment,
|
||||||
|
InEnvironment,
|
||||||
|
TraitEngine,
|
||||||
|
ObligationCause,
|
||||||
|
PredicateObligation,
|
||||||
|
FulfillmentError,
|
||||||
|
FulfillmentErrorCode,
|
||||||
|
SelectionError,
|
||||||
|
};
|
||||||
|
use traits::query::NoSolution;
|
||||||
|
use infer::InferCtxt;
|
||||||
|
use infer::canonical::{Canonical, OriginalQueryValues};
|
||||||
|
use ty::{self, Ty};
|
||||||
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
|
||||||
|
pub type CanonicalGoal<'tcx> = Canonical<'tcx, InEnvironment<'tcx, ty::Predicate<'tcx>>>;
|
||||||
|
|
||||||
|
pub struct FulfillmentContext<'tcx> {
|
||||||
|
obligations: FxHashSet<InEnvironment<'tcx, PredicateObligation<'tcx>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FulfillmentContext<'tcx> {
|
||||||
|
crate fn new() -> Self {
|
||||||
|
FulfillmentContext {
|
||||||
|
obligations: FxHashSet::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_environment(
|
||||||
|
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||||
|
obligation: PredicateObligation<'tcx>
|
||||||
|
) -> InEnvironment<'tcx, PredicateObligation<'tcx>> {
|
||||||
|
assert!(!infcx.is_in_snapshot());
|
||||||
|
let obligation = infcx.resolve_type_vars_if_possible(&obligation);
|
||||||
|
|
||||||
|
let environment = match obligation.param_env.def_id {
|
||||||
|
Some(def_id) => infcx.tcx.environment(def_id),
|
||||||
|
None if obligation.param_env.caller_bounds.is_empty() => Environment {
|
||||||
|
clauses: ty::List::empty(),
|
||||||
|
},
|
||||||
|
_ => bug!("non-empty `ParamEnv` with no def-id"),
|
||||||
|
};
|
||||||
|
|
||||||
|
InEnvironment {
|
||||||
|
environment,
|
||||||
|
goal: obligation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||||
|
fn normalize_projection_type(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||||
|
_param_env: ty::ParamEnv<'tcx>,
|
||||||
|
projection_ty: ty::ProjectionTy<'tcx>,
|
||||||
|
_cause: ObligationCause<'tcx>,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
infcx.tcx.mk_ty(ty::Projection(projection_ty))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_predicate_obligation(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||||
|
obligation: PredicateObligation<'tcx>,
|
||||||
|
) {
|
||||||
|
self.obligations.insert(in_environment(infcx, obligation));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_all_or_error(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||||
|
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
|
||||||
|
self.select_where_possible(infcx)?;
|
||||||
|
|
||||||
|
if self.obligations.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
let errors = self.obligations.iter()
|
||||||
|
.map(|obligation| FulfillmentError {
|
||||||
|
obligation: obligation.goal.clone(),
|
||||||
|
code: FulfillmentErrorCode::CodeAmbiguity,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_where_possible(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||||
|
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
let mut next_round = FxHashSet::default();
|
||||||
|
let mut making_progress;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
making_progress = false;
|
||||||
|
|
||||||
|
// We iterate over all obligations, and record if we are able
|
||||||
|
// to unambiguously prove at least one obligation.
|
||||||
|
for obligation in self.obligations.drain() {
|
||||||
|
let mut orig_values = OriginalQueryValues::default();
|
||||||
|
let canonical_goal = infcx.canonicalize_query(&InEnvironment {
|
||||||
|
environment: obligation.environment,
|
||||||
|
goal: obligation.goal.predicate,
|
||||||
|
}, &mut orig_values);
|
||||||
|
|
||||||
|
match infcx.tcx.global_tcx().evaluate_goal(canonical_goal) {
|
||||||
|
Ok(response) => {
|
||||||
|
if response.is_proven() {
|
||||||
|
making_progress = true;
|
||||||
|
|
||||||
|
match infcx.instantiate_query_response_and_region_obligations(
|
||||||
|
&obligation.goal.cause,
|
||||||
|
obligation.goal.param_env,
|
||||||
|
&orig_values,
|
||||||
|
&response
|
||||||
|
) {
|
||||||
|
Ok(infer_ok) => next_round.extend(
|
||||||
|
infer_ok.obligations
|
||||||
|
.into_iter()
|
||||||
|
.map(|obligation| in_environment(infcx, obligation))
|
||||||
|
),
|
||||||
|
|
||||||
|
Err(_err) => errors.push(FulfillmentError {
|
||||||
|
obligation: obligation.goal,
|
||||||
|
code: FulfillmentErrorCode::CodeSelectionError(
|
||||||
|
SelectionError::Unimplemented
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Ambiguous: retry at next round.
|
||||||
|
next_round.insert(obligation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(NoSolution) => errors.push(FulfillmentError {
|
||||||
|
obligation: obligation.goal,
|
||||||
|
code: FulfillmentErrorCode::CodeSelectionError(
|
||||||
|
SelectionError::Unimplemented
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next_round = std::mem::replace(&mut self.obligations, next_round);
|
||||||
|
|
||||||
|
if !making_progress {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
|
||||||
|
self.obligations.iter().map(|obligation| obligation.goal.clone()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
use infer::InferCtxt;
|
use infer::InferCtxt;
|
||||||
use ty::{self, Ty, TyCtxt};
|
use ty::{self, Ty, TyCtxt, ToPredicate};
|
||||||
|
use traits::Obligation;
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
|
|
||||||
use super::{FulfillmentContext, FulfillmentError};
|
use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError};
|
||||||
use super::{ObligationCause, PredicateObligation};
|
use super::{ObligationCause, PredicateObligation};
|
||||||
|
|
||||||
pub trait TraitEngine<'tcx>: 'tcx {
|
pub trait TraitEngine<'tcx>: 'tcx {
|
||||||
|
|
@ -14,6 +15,9 @@ pub trait TraitEngine<'tcx>: 'tcx {
|
||||||
cause: ObligationCause<'tcx>,
|
cause: ObligationCause<'tcx>,
|
||||||
) -> Ty<'tcx>;
|
) -> Ty<'tcx>;
|
||||||
|
|
||||||
|
/// Requires that `ty` must implement the trait with `def_id` in
|
||||||
|
/// the given environment. This trait must not have any type
|
||||||
|
/// parameters (except for `Self`).
|
||||||
fn register_bound(
|
fn register_bound(
|
||||||
&mut self,
|
&mut self,
|
||||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||||
|
|
@ -21,7 +25,18 @@ pub trait TraitEngine<'tcx>: 'tcx {
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
cause: ObligationCause<'tcx>,
|
cause: ObligationCause<'tcx>,
|
||||||
);
|
) {
|
||||||
|
let trait_ref = ty::TraitRef {
|
||||||
|
def_id,
|
||||||
|
substs: infcx.tcx.mk_substs_trait(ty, &[]),
|
||||||
|
};
|
||||||
|
self.register_predicate_obligation(infcx, Obligation {
|
||||||
|
cause,
|
||||||
|
recursion_depth: 0,
|
||||||
|
param_env,
|
||||||
|
predicate: trait_ref.to_predicate()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn register_predicate_obligation(
|
fn register_predicate_obligation(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -63,7 +78,11 @@ impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl dyn TraitEngine<'tcx> {
|
impl dyn TraitEngine<'tcx> {
|
||||||
pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
|
pub fn new(tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
|
||||||
Box::new(FulfillmentContext::new())
|
if tcx.sess.opts.debugging_opts.chalk {
|
||||||
|
Box::new(ChalkFulfillmentContext::new())
|
||||||
|
} else {
|
||||||
|
Box::new(FulfillmentContext::new())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -796,12 +796,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Predicate::WellFormed(ty) => {
|
ty::Predicate::WellFormed(ty) => {
|
||||||
// WF predicates cannot themselves make
|
if !self.tcx.sess.opts.debugging_opts.chalk {
|
||||||
// errors. They can only block due to
|
// WF predicates cannot themselves make
|
||||||
// ambiguity; otherwise, they always
|
// errors. They can only block due to
|
||||||
// degenerate into other obligations
|
// ambiguity; otherwise, they always
|
||||||
// (which may fail).
|
// degenerate into other obligations
|
||||||
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
|
// (which may fail).
|
||||||
|
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
|
||||||
|
} else {
|
||||||
|
// FIXME: we'll need a better message which takes into account
|
||||||
|
// which bounds actually failed to hold.
|
||||||
|
self.tcx.sess.struct_span_err(
|
||||||
|
span,
|
||||||
|
&format!("the type `{}` is not well-formed (chalk)", ty)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Predicate::ConstEvaluatable(..) => {
|
ty::Predicate::ConstEvaluatable(..) => {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,18 @@
|
||||||
use infer::InferCtxt;
|
use infer::InferCtxt;
|
||||||
use mir::interpret::{GlobalId, ErrorHandled};
|
use mir::interpret::{GlobalId, ErrorHandled};
|
||||||
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
|
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef};
|
||||||
use ty::error::ExpectedFound;
|
use ty::error::ExpectedFound;
|
||||||
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
|
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
|
||||||
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
||||||
use rustc_data_structures::obligation_forest::{ProcessResult};
|
use rustc_data_structures::obligation_forest::{ProcessResult};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use hir::def_id::DefId;
|
|
||||||
|
|
||||||
use super::CodeAmbiguity;
|
use super::CodeAmbiguity;
|
||||||
use super::CodeProjectionError;
|
use super::CodeProjectionError;
|
||||||
use super::CodeSelectionError;
|
use super::CodeSelectionError;
|
||||||
use super::engine::{TraitEngine, TraitEngineExt};
|
use super::engine::{TraitEngine, TraitEngineExt};
|
||||||
use super::{FulfillmentError, FulfillmentErrorCode};
|
use super::{FulfillmentError, FulfillmentErrorCode};
|
||||||
use super::{ObligationCause, PredicateObligation, Obligation};
|
use super::{ObligationCause, PredicateObligation};
|
||||||
use super::project;
|
use super::project;
|
||||||
use super::select::SelectionContext;
|
use super::select::SelectionContext;
|
||||||
use super::{Unimplemented, ConstEvalFailure};
|
use super::{Unimplemented, ConstEvalFailure};
|
||||||
|
|
@ -173,28 +172,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||||
normalized_ty
|
normalized_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Requires that `ty` must implement the trait with `def_id` in
|
|
||||||
/// the given environment. This trait must not have any type
|
|
||||||
/// parameters (except for `Self`).
|
|
||||||
fn register_bound<'a, 'gcx>(&mut self,
|
|
||||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
def_id: DefId,
|
|
||||||
cause: ObligationCause<'tcx>)
|
|
||||||
{
|
|
||||||
let trait_ref = ty::TraitRef {
|
|
||||||
def_id,
|
|
||||||
substs: infcx.tcx.mk_substs_trait(ty, &[]),
|
|
||||||
};
|
|
||||||
self.register_predicate_obligation(infcx, Obligation {
|
|
||||||
cause,
|
|
||||||
recursion_depth: 0,
|
|
||||||
param_env,
|
|
||||||
predicate: trait_ref.to_predicate()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_predicate_obligation<'a, 'gcx>(&mut self,
|
fn register_predicate_obligation<'a, 'gcx>(&mut self,
|
||||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
obligation: PredicateObligation<'tcx>)
|
obligation: PredicateObligation<'tcx>)
|
||||||
|
|
@ -213,9 +190,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_all_or_error<'a, 'gcx>(&mut self,
|
fn select_all_or_error<'a, 'gcx>(
|
||||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
|
&mut self,
|
||||||
-> Result<(),Vec<FulfillmentError<'tcx>>>
|
infcx: &InferCtxt<'a, 'gcx, 'tcx>
|
||||||
|
) -> Result<(),Vec<FulfillmentError<'tcx>>>
|
||||||
{
|
{
|
||||||
self.select_where_possible(infcx)?;
|
self.select_where_possible(infcx)?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub mod auto_trait;
|
pub mod auto_trait;
|
||||||
|
mod chalk_fulfill;
|
||||||
mod coherence;
|
mod coherence;
|
||||||
pub mod error_reporting;
|
pub mod error_reporting;
|
||||||
mod engine;
|
mod engine;
|
||||||
|
|
@ -61,6 +62,11 @@ pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_
|
||||||
pub use self::util::{supertraits, supertrait_def_ids, transitive_bounds,
|
pub use self::util::{supertraits, supertrait_def_ids, transitive_bounds,
|
||||||
Supertraits, SupertraitDefIds};
|
Supertraits, SupertraitDefIds};
|
||||||
|
|
||||||
|
pub use self::chalk_fulfill::{
|
||||||
|
CanonicalGoal as ChalkCanonicalGoal,
|
||||||
|
FulfillmentContext as ChalkFulfillmentContext
|
||||||
|
};
|
||||||
|
|
||||||
pub use self::ObligationCauseCode::*;
|
pub use self::ObligationCauseCode::*;
|
||||||
pub use self::FulfillmentErrorCode::*;
|
pub use self::FulfillmentErrorCode::*;
|
||||||
pub use self::SelectionError::*;
|
pub use self::SelectionError::*;
|
||||||
|
|
@ -318,6 +324,7 @@ pub enum GoalKind<'tcx> {
|
||||||
Not(Goal<'tcx>),
|
Not(Goal<'tcx>),
|
||||||
DomainGoal(DomainGoal<'tcx>),
|
DomainGoal(DomainGoal<'tcx>),
|
||||||
Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>),
|
Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>),
|
||||||
|
Subtype(Ty<'tcx>, Ty<'tcx>),
|
||||||
CannotProve,
|
CannotProve,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -340,9 +347,9 @@ impl<'tcx> DomainGoal<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> GoalKind<'tcx> {
|
impl<'tcx> GoalKind<'tcx> {
|
||||||
pub fn from_poly_domain_goal<'a>(
|
pub fn from_poly_domain_goal<'a, 'gcx>(
|
||||||
domain_goal: PolyDomainGoal<'tcx>,
|
domain_goal: PolyDomainGoal<'tcx>,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
) -> GoalKind<'tcx> {
|
) -> GoalKind<'tcx> {
|
||||||
match domain_goal.no_bound_vars() {
|
match domain_goal.no_bound_vars() {
|
||||||
Some(p) => p.into_goal(),
|
Some(p) => p.into_goal(),
|
||||||
|
|
@ -804,8 +811,11 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
|
debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
|
||||||
predicates);
|
predicates);
|
||||||
|
|
||||||
let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
|
let elaborated_env = ty::ParamEnv::new(
|
||||||
unnormalized_env.reveal);
|
tcx.intern_predicates(&predicates),
|
||||||
|
unnormalized_env.reveal,
|
||||||
|
unnormalized_env.def_id
|
||||||
|
);
|
||||||
|
|
||||||
// HACK: we are trying to normalize the param-env inside *itself*. The problem is that
|
// HACK: we are trying to normalize the param-env inside *itself*. The problem is that
|
||||||
// normalization expects its param-env to be already normalized, which means we have
|
// normalization expects its param-env to be already normalized, which means we have
|
||||||
|
|
@ -852,8 +862,11 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
// predicates here anyway. Keeping them here anyway because it seems safer.
|
// predicates here anyway. Keeping them here anyway because it seems safer.
|
||||||
let outlives_env: Vec<_> =
|
let outlives_env: Vec<_> =
|
||||||
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
|
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
|
||||||
let outlives_env = ty::ParamEnv::new(tcx.intern_predicates(&outlives_env),
|
let outlives_env = ty::ParamEnv::new(
|
||||||
unnormalized_env.reveal);
|
tcx.intern_predicates(&outlives_env),
|
||||||
|
unnormalized_env.reveal,
|
||||||
|
None
|
||||||
|
);
|
||||||
let outlives_predicates =
|
let outlives_predicates =
|
||||||
match do_normalize_predicates(tcx, region_context, cause,
|
match do_normalize_predicates(tcx, region_context, cause,
|
||||||
outlives_env, outlives_predicates) {
|
outlives_env, outlives_predicates) {
|
||||||
|
|
@ -869,7 +882,11 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
let mut predicates = non_outlives_predicates;
|
let mut predicates = non_outlives_predicates;
|
||||||
predicates.extend(outlives_predicates);
|
predicates.extend(outlives_predicates);
|
||||||
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
|
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
|
||||||
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal)
|
ty::ParamEnv::new(
|
||||||
|
tcx.intern_predicates(&predicates),
|
||||||
|
unnormalized_env.reveal,
|
||||||
|
unnormalized_env.def_id
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fully_normalize<'a, 'gcx, 'tcx, T>(
|
pub fn fully_normalize<'a, 'gcx, 'tcx, T>(
|
||||||
|
|
@ -1164,14 +1181,26 @@ where
|
||||||
) -> bool;
|
) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ExClauseLift<'tcx>
|
pub trait ChalkContextLift<'tcx>
|
||||||
where
|
where
|
||||||
Self: chalk_engine::context::Context + Clone,
|
Self: chalk_engine::context::Context + Clone,
|
||||||
{
|
{
|
||||||
type LiftedExClause: Debug + 'tcx;
|
type LiftedExClause: Debug + 'tcx;
|
||||||
|
type LiftedDelayedLiteral: Debug + 'tcx;
|
||||||
|
type LiftedLiteral: Debug + 'tcx;
|
||||||
|
|
||||||
fn lift_ex_clause_to_tcx<'a, 'gcx>(
|
fn lift_ex_clause_to_tcx<'a, 'gcx>(
|
||||||
ex_clause: &chalk_engine::ExClause<Self>,
|
ex_clause: &chalk_engine::ExClause<Self>,
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
) -> Option<Self::LiftedExClause>;
|
) -> Option<Self::LiftedExClause>;
|
||||||
|
|
||||||
|
fn lift_delayed_literal_to_tcx<'a, 'gcx>(
|
||||||
|
ex_clause: &chalk_engine::DelayedLiteral<Self>,
|
||||||
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
) -> Option<Self::LiftedDelayedLiteral>;
|
||||||
|
|
||||||
|
fn lift_literal_to_tcx<'a, 'gcx>(
|
||||||
|
ex_clause: &chalk_engine::Literal<Self>,
|
||||||
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
) -> Option<Self::LiftedLiteral>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3243,11 +3243,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
obligations.push(Obligation::new(
|
// FIXME: chalk
|
||||||
obligation.cause.clone(),
|
if !self.tcx().sess.opts.debugging_opts.chalk {
|
||||||
obligation.param_env,
|
obligations.push(Obligation::new(
|
||||||
ty::Predicate::ClosureKind(closure_def_id, substs, kind),
|
obligation.cause.clone(),
|
||||||
));
|
obligation.param_env,
|
||||||
|
ty::Predicate::ClosureKind(closure_def_id, substs, kind),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(VtableClosureData {
|
Ok(VtableClosureData {
|
||||||
closure_def_id,
|
closure_def_id,
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,7 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Subtype(a, b) => write!(fmt, "{} <: {}", a, b),
|
||||||
CannotProve => write!(fmt, "CannotProve"),
|
CannotProve => write!(fmt, "CannotProve"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -668,6 +669,7 @@ EnumLiftImpl! {
|
||||||
(traits::GoalKind::Not)(goal),
|
(traits::GoalKind::Not)(goal),
|
||||||
(traits::GoalKind::DomainGoal)(domain_goal),
|
(traits::GoalKind::DomainGoal)(domain_goal),
|
||||||
(traits::GoalKind::Quantified)(kind, goal),
|
(traits::GoalKind::Quantified)(kind, goal),
|
||||||
|
(traits::GoalKind::Subtype)(a, b),
|
||||||
(traits::GoalKind::CannotProve),
|
(traits::GoalKind::CannotProve),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -700,12 +702,36 @@ impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> {
|
||||||
impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause<C>
|
impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause<C>
|
||||||
where
|
where
|
||||||
C: chalk_engine::context::Context + Clone,
|
C: chalk_engine::context::Context + Clone,
|
||||||
C: traits::ExClauseLift<'tcx>,
|
C: traits::ChalkContextLift<'tcx>,
|
||||||
{
|
{
|
||||||
type Lifted = C::LiftedExClause;
|
type Lifted = C::LiftedExClause;
|
||||||
|
|
||||||
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||||
<C as traits::ExClauseLift>::lift_ex_clause_to_tcx(self, tcx)
|
<C as traits::ChalkContextLift>::lift_ex_clause_to_tcx(self, tcx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, C> Lift<'tcx> for chalk_engine::DelayedLiteral<C>
|
||||||
|
where
|
||||||
|
C: chalk_engine::context::Context + Clone,
|
||||||
|
C: traits::ChalkContextLift<'tcx>,
|
||||||
|
{
|
||||||
|
type Lifted = C::LiftedDelayedLiteral;
|
||||||
|
|
||||||
|
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||||
|
<C as traits::ChalkContextLift>::lift_delayed_literal_to_tcx(self, tcx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, C> Lift<'tcx> for chalk_engine::Literal<C>
|
||||||
|
where
|
||||||
|
C: chalk_engine::context::Context + Clone,
|
||||||
|
C: traits::ChalkContextLift<'tcx>,
|
||||||
|
{
|
||||||
|
type Lifted = C::LiftedLiteral;
|
||||||
|
|
||||||
|
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||||
|
<C as traits::ChalkContextLift>::lift_literal_to_tcx(self, tcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -840,6 +866,7 @@ EnumTypeFoldableImpl! {
|
||||||
(traits::GoalKind::Not)(goal),
|
(traits::GoalKind::Not)(goal),
|
||||||
(traits::GoalKind::DomainGoal)(domain_goal),
|
(traits::GoalKind::DomainGoal)(domain_goal),
|
||||||
(traits::GoalKind::Quantified)(qkind, goal),
|
(traits::GoalKind::Quantified)(qkind, goal),
|
||||||
|
(traits::GoalKind::Subtype)(a, b),
|
||||||
(traits::GoalKind::CannotProve),
|
(traits::GoalKind::CannotProve),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1714,6 +1714,10 @@ impl<'a, 'tcx> Lift<'tcx> for &'a List<Goal<'a>> {
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'b, 'gcx, 'tcx>,
|
tcx: TyCtxt<'b, 'gcx, 'tcx>,
|
||||||
) -> Option<&'tcx List<Goal<'tcx>>> {
|
) -> Option<&'tcx List<Goal<'tcx>>> {
|
||||||
|
if self.is_empty() {
|
||||||
|
return Some(List::empty());
|
||||||
|
}
|
||||||
|
|
||||||
if tcx.interners.arena.in_arena(*self as *const _) {
|
if tcx.interners.arena.in_arena(*self as *const _) {
|
||||||
return Some(unsafe { mem::transmute(*self) });
|
return Some(unsafe { mem::transmute(*self) });
|
||||||
}
|
}
|
||||||
|
|
@ -1732,6 +1736,10 @@ impl<'a, 'tcx> Lift<'tcx> for &'a List<Clause<'a>> {
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'b, 'gcx, 'tcx>,
|
tcx: TyCtxt<'b, 'gcx, 'tcx>,
|
||||||
) -> Option<&'tcx List<Clause<'tcx>>> {
|
) -> Option<&'tcx List<Clause<'tcx>>> {
|
||||||
|
if self.is_empty() {
|
||||||
|
return Some(List::empty());
|
||||||
|
}
|
||||||
|
|
||||||
if tcx.interners.arena.in_arena(*self as *const _) {
|
if tcx.interners.arena.in_arena(*self as *const _) {
|
||||||
return Some(unsafe { mem::transmute(*self) });
|
return Some(unsafe { mem::transmute(*self) });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -533,18 +533,25 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>,
|
G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>,
|
||||||
T: TypeFoldable<'tcx>
|
T: TypeFoldable<'tcx>
|
||||||
{
|
{
|
||||||
let mut map = BTreeMap::new();
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
|
||||||
|
let mut region_map = BTreeMap::new();
|
||||||
|
let mut type_map = FxHashMap::default();
|
||||||
|
|
||||||
if !value.has_escaping_bound_vars() {
|
if !value.has_escaping_bound_vars() {
|
||||||
(value.clone(), map)
|
(value.clone(), region_map)
|
||||||
} else {
|
} else {
|
||||||
let mut real_fld_r = |br| {
|
let mut real_fld_r = |br| {
|
||||||
*map.entry(br).or_insert_with(|| fld_r(br))
|
*region_map.entry(br).or_insert_with(|| fld_r(br))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut replacer = BoundVarReplacer::new(self, &mut real_fld_r, &mut fld_t);
|
let mut real_fld_t = |bound_ty| {
|
||||||
|
*type_map.entry(bound_ty).or_insert_with(|| fld_t(bound_ty))
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut replacer = BoundVarReplacer::new(self, &mut real_fld_r, &mut real_fld_t);
|
||||||
let result = value.fold_with(&mut replacer);
|
let result = value.fold_with(&mut replacer);
|
||||||
(result, map)
|
(result, region_map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1617,6 +1617,11 @@ pub struct ParamEnv<'tcx> {
|
||||||
/// want `Reveal::All` -- note that this is always paired with an
|
/// want `Reveal::All` -- note that this is always paired with an
|
||||||
/// empty environment. To get that, use `ParamEnv::reveal()`.
|
/// empty environment. To get that, use `ParamEnv::reveal()`.
|
||||||
pub reveal: traits::Reveal,
|
pub reveal: traits::Reveal,
|
||||||
|
|
||||||
|
/// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`,
|
||||||
|
/// register that `def_id` (useful for transitioning to the chalk trait
|
||||||
|
/// solver).
|
||||||
|
pub def_id: Option<DefId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ParamEnv<'tcx> {
|
impl<'tcx> ParamEnv<'tcx> {
|
||||||
|
|
@ -1626,7 +1631,7 @@ impl<'tcx> ParamEnv<'tcx> {
|
||||||
/// type-checking.
|
/// type-checking.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::new(List::empty(), Reveal::UserFacing)
|
Self::new(List::empty(), Reveal::UserFacing, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a trait environment with no where clauses in scope
|
/// Construct a trait environment with no where clauses in scope
|
||||||
|
|
@ -1638,15 +1643,17 @@ impl<'tcx> ParamEnv<'tcx> {
|
||||||
/// or invoke `param_env.with_reveal_all()`.
|
/// or invoke `param_env.with_reveal_all()`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reveal_all() -> Self {
|
pub fn reveal_all() -> Self {
|
||||||
Self::new(List::empty(), Reveal::All)
|
Self::new(List::empty(), Reveal::All, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a trait environment with the given set of predicates.
|
/// Construct a trait environment with the given set of predicates.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(caller_bounds: &'tcx List<ty::Predicate<'tcx>>,
|
pub fn new(
|
||||||
reveal: Reveal)
|
caller_bounds: &'tcx List<ty::Predicate<'tcx>>,
|
||||||
-> Self {
|
reveal: Reveal,
|
||||||
ty::ParamEnv { caller_bounds, reveal }
|
def_id: Option<DefId>
|
||||||
|
) -> Self {
|
||||||
|
ty::ParamEnv { caller_bounds, reveal, def_id }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new parameter environment with the same clauses, but
|
/// Returns a new parameter environment with the same clauses, but
|
||||||
|
|
@ -3148,8 +3155,11 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
// are any errors at that point, so after type checking you can be
|
// are any errors at that point, so after type checking you can be
|
||||||
// sure that this will succeed without errors anyway.
|
// sure that this will succeed without errors anyway.
|
||||||
|
|
||||||
let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
|
let unnormalized_env = ty::ParamEnv::new(
|
||||||
traits::Reveal::UserFacing);
|
tcx.intern_predicates(&predicates),
|
||||||
|
traits::Reveal::UserFacing,
|
||||||
|
if tcx.sess.opts.debugging_opts.chalk { Some(def_id) } else { None }
|
||||||
|
);
|
||||||
|
|
||||||
let body_id = tcx.hir().as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| {
|
let body_id = tcx.hir().as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| {
|
||||||
tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.node_id)
|
tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.node_id)
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,15 @@ impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> QueryDescription<'tcx> for queries::evaluate_goal<'tcx> {
|
||||||
|
fn describe(
|
||||||
|
_tcx: TyCtxt<'_, '_, '_>,
|
||||||
|
goal: traits::ChalkCanonicalGoal<'tcx>
|
||||||
|
) -> Cow<'static, str> {
|
||||||
|
format!("evaluating trait selection obligation `{}`", goal.value.goal).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type<'tcx> {
|
impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type<'tcx> {
|
||||||
fn describe(
|
fn describe(
|
||||||
_tcx: TyCtxt<'_, '_, '_>,
|
_tcx: TyCtxt<'_, '_, '_>,
|
||||||
|
|
|
||||||
|
|
@ -593,6 +593,13 @@ define_queries! { <'tcx>
|
||||||
CanonicalPredicateGoal<'tcx>
|
CanonicalPredicateGoal<'tcx>
|
||||||
) -> Result<traits::EvaluationResult, traits::OverflowError>,
|
) -> Result<traits::EvaluationResult, traits::OverflowError>,
|
||||||
|
|
||||||
|
[] fn evaluate_goal: EvaluateGoal(
|
||||||
|
traits::ChalkCanonicalGoal<'tcx>
|
||||||
|
) -> Result<
|
||||||
|
Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>,
|
||||||
|
NoSolution
|
||||||
|
>,
|
||||||
|
|
||||||
/// Do not call this query directly: part of the `Eq` type-op
|
/// Do not call this query directly: part of the `Eq` type-op
|
||||||
[] fn type_op_ascribe_user_type: TypeOpAscribeUserType(
|
[] fn type_op_ascribe_user_type: TypeOpAscribeUserType(
|
||||||
CanonicalTypeOpAscribeUserTypeGoal<'tcx>
|
CanonicalTypeOpAscribeUserTypeGoal<'tcx>
|
||||||
|
|
@ -684,7 +691,7 @@ define_queries! { <'tcx>
|
||||||
) -> Clauses<'tcx>,
|
) -> Clauses<'tcx>,
|
||||||
|
|
||||||
// Get the chalk-style environment of the given item.
|
// Get the chalk-style environment of the given item.
|
||||||
[] fn environment: Environment(DefId) -> ty::Binder<traits::Environment<'tcx>>,
|
[] fn environment: Environment(DefId) -> traits::Environment<'tcx>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Linking {
|
Linking {
|
||||||
|
|
|
||||||
|
|
@ -1103,6 +1103,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
||||||
DepKind::ImpliedOutlivesBounds |
|
DepKind::ImpliedOutlivesBounds |
|
||||||
DepKind::DropckOutlives |
|
DepKind::DropckOutlives |
|
||||||
DepKind::EvaluateObligation |
|
DepKind::EvaluateObligation |
|
||||||
|
DepKind::EvaluateGoal |
|
||||||
DepKind::TypeOpAscribeUserType |
|
DepKind::TypeOpAscribeUserType |
|
||||||
DepKind::TypeOpEq |
|
DepKind::TypeOpEq |
|
||||||
DepKind::TypeOpSubtype |
|
DepKind::TypeOpSubtype |
|
||||||
|
|
|
||||||
|
|
@ -276,6 +276,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
|
||||||
ty::ParamEnv {
|
ty::ParamEnv {
|
||||||
reveal: self.reveal,
|
reveal: self.reveal,
|
||||||
caller_bounds,
|
caller_bounds,
|
||||||
|
def_id: self.def_id,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -589,7 +590,7 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
BraceStructTypeFoldableImpl! {
|
BraceStructTypeFoldableImpl! {
|
||||||
impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> { reveal, caller_bounds }
|
impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> { reveal, caller_bounds, def_id }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
|
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
|
||||||
|
|
|
||||||
|
|
@ -17,5 +17,5 @@ rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
rustc_target = { path = "../librustc_target" }
|
rustc_target = { path = "../librustc_target" }
|
||||||
syntax = { path = "../libsyntax" }
|
syntax = { path = "../libsyntax" }
|
||||||
syntax_pos = { path = "../libsyntax_pos" }
|
syntax_pos = { path = "../libsyntax_pos" }
|
||||||
chalk-engine = { version = "0.8.0", default-features=false }
|
chalk-engine = { version = "0.9.0", default-features=false }
|
||||||
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
|
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,15 @@ mod program_clauses;
|
||||||
mod resolvent_ops;
|
mod resolvent_ops;
|
||||||
mod unify;
|
mod unify;
|
||||||
|
|
||||||
use chalk_engine::fallible::{Fallible, NoSolution};
|
use chalk_engine::fallible::Fallible;
|
||||||
use chalk_engine::{
|
use chalk_engine::{
|
||||||
context,
|
context,
|
||||||
hh::HhGoal,
|
hh::HhGoal,
|
||||||
DelayedLiteral,
|
DelayedLiteral,
|
||||||
Literal,
|
Literal,
|
||||||
ExClause
|
ExClause,
|
||||||
};
|
};
|
||||||
|
use chalk_engine::forest::Forest;
|
||||||
use rustc::infer::{InferCtxt, LateBoundRegionConversionTime};
|
use rustc::infer::{InferCtxt, LateBoundRegionConversionTime};
|
||||||
use rustc::infer::canonical::{
|
use rustc::infer::canonical::{
|
||||||
Canonical,
|
Canonical,
|
||||||
|
|
@ -19,19 +20,23 @@ use rustc::infer::canonical::{
|
||||||
Certainty,
|
Certainty,
|
||||||
};
|
};
|
||||||
use rustc::traits::{
|
use rustc::traits::{
|
||||||
|
self,
|
||||||
DomainGoal,
|
DomainGoal,
|
||||||
ExClauseFold,
|
ExClauseFold,
|
||||||
ExClauseLift,
|
ChalkContextLift,
|
||||||
Goal,
|
Goal,
|
||||||
GoalKind,
|
GoalKind,
|
||||||
Clause,
|
Clause,
|
||||||
QuantifierKind,
|
QuantifierKind,
|
||||||
Environment,
|
Environment,
|
||||||
InEnvironment,
|
InEnvironment,
|
||||||
|
ChalkCanonicalGoal,
|
||||||
};
|
};
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||||
|
use rustc::ty::query::Providers;
|
||||||
use rustc::ty::subst::{Kind, UnpackedKind};
|
use rustc::ty::subst::{Kind, UnpackedKind};
|
||||||
|
use rustc_data_structures::sync::Lrc;
|
||||||
use syntax_pos::DUMMY_SP;
|
use syntax_pos::DUMMY_SP;
|
||||||
|
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
|
|
@ -111,6 +116,8 @@ impl context::Context for ChalkArenas<'tcx> {
|
||||||
|
|
||||||
type UnificationResult = UnificationResult<'tcx>;
|
type UnificationResult = UnificationResult<'tcx>;
|
||||||
|
|
||||||
|
type Variance = ty::Variance;
|
||||||
|
|
||||||
fn goal_in_environment(
|
fn goal_in_environment(
|
||||||
env: &Environment<'tcx>,
|
env: &Environment<'tcx>,
|
||||||
goal: Goal<'tcx>,
|
goal: Goal<'tcx>,
|
||||||
|
|
@ -122,45 +129,77 @@ impl context::Context for ChalkArenas<'tcx> {
|
||||||
impl context::AggregateOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
|
impl context::AggregateOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
|
||||||
fn make_solution(
|
fn make_solution(
|
||||||
&self,
|
&self,
|
||||||
_root_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
|
root_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
|
||||||
mut simplified_answers: impl context::AnswerStream<ChalkArenas<'gcx>>,
|
mut simplified_answers: impl context::AnswerStream<ChalkArenas<'gcx>>,
|
||||||
) -> Option<Canonical<'gcx, QueryResponse<'gcx, ()>>> {
|
) -> Option<Canonical<'gcx, QueryResponse<'gcx, ()>>> {
|
||||||
use chalk_engine::SimplifiedAnswer;
|
use chalk_engine::SimplifiedAnswer;
|
||||||
|
|
||||||
|
debug!("make_solution(root_goal = {:?})", root_goal);
|
||||||
|
|
||||||
if simplified_answers.peek_answer().is_none() {
|
if simplified_answers.peek_answer().is_none() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let SimplifiedAnswer { subst, ambiguous } = simplified_answers
|
let SimplifiedAnswer { subst: constrained_subst, ambiguous } = simplified_answers
|
||||||
.next_answer()
|
.next_answer()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
debug!("make_solution: ambiguous flag = {}", ambiguous);
|
||||||
|
|
||||||
let ambiguous = simplified_answers.peek_answer().is_some() || ambiguous;
|
let ambiguous = simplified_answers.peek_answer().is_some() || ambiguous;
|
||||||
|
|
||||||
Some(subst.unchecked_map(|subst| {
|
let solution = constrained_subst.unchecked_map(|cs| match ambiguous {
|
||||||
QueryResponse {
|
true => QueryResponse {
|
||||||
var_values: subst.subst,
|
var_values: cs.subst.make_identity(self.tcx),
|
||||||
region_constraints: subst.constraints
|
region_constraints: Vec::new(),
|
||||||
.into_iter()
|
certainty: Certainty::Ambiguous,
|
||||||
.map(|c| ty::Binder::bind(c))
|
|
||||||
.collect(),
|
|
||||||
certainty: match ambiguous {
|
|
||||||
true => Certainty::Ambiguous,
|
|
||||||
false => Certainty::Proven,
|
|
||||||
},
|
|
||||||
value: (),
|
value: (),
|
||||||
}
|
},
|
||||||
}))
|
|
||||||
|
false => QueryResponse {
|
||||||
|
var_values: cs.subst,
|
||||||
|
region_constraints: Vec::new(),
|
||||||
|
|
||||||
|
// FIXME: restore this later once we get better at handling regions
|
||||||
|
// region_constraints: cs.constraints
|
||||||
|
// .into_iter()
|
||||||
|
// .map(|c| ty::Binder::bind(c))
|
||||||
|
// .collect(),
|
||||||
|
certainty: Certainty::Proven,
|
||||||
|
value: (),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
debug!("make_solution: solution = {:?}", solution);
|
||||||
|
|
||||||
|
Some(solution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl context::ContextOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
|
impl context::ContextOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
|
||||||
/// True if this is a coinductive goal -- e.g., proving an auto trait.
|
/// True if this is a coinductive goal: basically proving that an auto trait
|
||||||
|
/// is implemented or proving that a trait reference is well-formed.
|
||||||
fn is_coinductive(
|
fn is_coinductive(
|
||||||
&self,
|
&self,
|
||||||
_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>
|
goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>
|
||||||
) -> bool {
|
) -> bool {
|
||||||
unimplemented!()
|
use rustc::traits::{WellFormed, WhereClause};
|
||||||
|
|
||||||
|
let mut goal = goal.value.goal;
|
||||||
|
loop {
|
||||||
|
match goal {
|
||||||
|
GoalKind::DomainGoal(domain_goal) => match domain_goal {
|
||||||
|
DomainGoal::WellFormed(WellFormed::Trait(..)) => return true,
|
||||||
|
DomainGoal::Holds(WhereClause::Implemented(trait_predicate)) => {
|
||||||
|
return self.tcx.trait_is_auto(trait_predicate.def_id());
|
||||||
|
}
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
|
|
||||||
|
GoalKind::Quantified(_, bound_goal) => goal = *bound_goal.skip_binder(),
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an inference table for processing a new goal and instantiate that goal
|
/// Create an inference table for processing a new goal and instantiate that goal
|
||||||
|
|
@ -295,6 +334,11 @@ impl context::InferenceTable<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
|
||||||
GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d),
|
GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d),
|
||||||
GoalKind::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder),
|
GoalKind::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder),
|
||||||
GoalKind::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder),
|
GoalKind::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder),
|
||||||
|
GoalKind::Subtype(a, b) => HhGoal::Unify(
|
||||||
|
ty::Variance::Covariant,
|
||||||
|
a.into(),
|
||||||
|
b.into()
|
||||||
|
),
|
||||||
GoalKind::CannotProve => HhGoal::CannotProve,
|
GoalKind::CannotProve => HhGoal::CannotProve,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -317,16 +361,16 @@ impl context::TruncateOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
|
||||||
{
|
{
|
||||||
fn truncate_goal(
|
fn truncate_goal(
|
||||||
&mut self,
|
&mut self,
|
||||||
subgoal: &InEnvironment<'tcx, Goal<'tcx>>,
|
_subgoal: &InEnvironment<'tcx, Goal<'tcx>>,
|
||||||
) -> Option<InEnvironment<'tcx, Goal<'tcx>>> {
|
) -> Option<InEnvironment<'tcx, Goal<'tcx>>> {
|
||||||
Some(*subgoal) // FIXME we should truncate at some point!
|
None // FIXME we should truncate at some point!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn truncate_answer(
|
fn truncate_answer(
|
||||||
&mut self,
|
&mut self,
|
||||||
subst: &CanonicalVarValues<'tcx>,
|
_subst: &CanonicalVarValues<'tcx>,
|
||||||
) -> Option<CanonicalVarValues<'tcx>> {
|
) -> Option<CanonicalVarValues<'tcx>> {
|
||||||
Some(subst.clone()) // FIXME we should truncate at some point!
|
None // FIXME we should truncate at some point!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -407,11 +451,13 @@ impl context::UnificationOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
|
||||||
fn unify_parameters(
|
fn unify_parameters(
|
||||||
&mut self,
|
&mut self,
|
||||||
environment: &Environment<'tcx>,
|
environment: &Environment<'tcx>,
|
||||||
|
variance: ty::Variance,
|
||||||
a: &Kind<'tcx>,
|
a: &Kind<'tcx>,
|
||||||
b: &Kind<'tcx>,
|
b: &Kind<'tcx>,
|
||||||
) -> Fallible<UnificationResult<'tcx>> {
|
) -> Fallible<UnificationResult<'tcx>> {
|
||||||
self.infcx.commit_if_ok(|_| {
|
self.infcx.commit_if_ok(|_| {
|
||||||
unify(self.infcx, *environment, a, b).map_err(|_| NoSolution)
|
unify(self.infcx, *environment, variance, a, b)
|
||||||
|
.map_err(|_| chalk_engine::fallible::NoSolution)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -424,9 +470,12 @@ impl context::UnificationOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
|
||||||
|
|
||||||
fn lift_delayed_literal(
|
fn lift_delayed_literal(
|
||||||
&self,
|
&self,
|
||||||
_value: DelayedLiteral<ChalkArenas<'tcx>>,
|
value: DelayedLiteral<ChalkArenas<'tcx>>,
|
||||||
) -> DelayedLiteral<ChalkArenas<'gcx>> {
|
) -> DelayedLiteral<ChalkArenas<'gcx>> {
|
||||||
panic!("lift")
|
match self.infcx.tcx.lift_to_global(&value) {
|
||||||
|
Some(literal) => literal,
|
||||||
|
None => bug!("cannot lift {:?}", value),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_ex_clause(
|
fn into_ex_clause(
|
||||||
|
|
@ -442,7 +491,10 @@ crate fn into_ex_clause(result: UnificationResult<'tcx>, ex_clause: &mut ChalkEx
|
||||||
ex_clause.subgoals.extend(
|
ex_clause.subgoals.extend(
|
||||||
result.goals.into_iter().map(Literal::Positive)
|
result.goals.into_iter().map(Literal::Positive)
|
||||||
);
|
);
|
||||||
ex_clause.constraints.extend(result.constraints);
|
|
||||||
|
// FIXME: restore this later once we get better at handling regions
|
||||||
|
let _ = result.constraints.len(); // trick `-D dead-code`
|
||||||
|
// ex_clause.constraints.extend(result.constraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChalkHhGoal<'tcx> = HhGoal<ChalkArenas<'tcx>>;
|
type ChalkHhGoal<'tcx> = HhGoal<ChalkArenas<'tcx>>;
|
||||||
|
|
@ -461,14 +513,45 @@ impl Debug for ChalkInferenceContext<'cx, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExClauseLift<'gcx> for ChalkArenas<'a> {
|
impl ChalkContextLift<'tcx> for ChalkArenas<'a> {
|
||||||
type LiftedExClause = ChalkExClause<'gcx>;
|
type LiftedExClause = ChalkExClause<'tcx>;
|
||||||
|
type LiftedDelayedLiteral = DelayedLiteral<ChalkArenas<'tcx>>;
|
||||||
|
type LiftedLiteral = Literal<ChalkArenas<'tcx>>;
|
||||||
|
|
||||||
fn lift_ex_clause_to_tcx(
|
fn lift_ex_clause_to_tcx(
|
||||||
_ex_clause: &ChalkExClause<'a>,
|
ex_clause: &ChalkExClause<'a>,
|
||||||
_tcx: TyCtxt<'_, '_, 'tcx>,
|
tcx: TyCtxt<'_, 'gcx, 'tcx>
|
||||||
) -> Option<Self::LiftedExClause> {
|
) -> Option<Self::LiftedExClause> {
|
||||||
panic!()
|
Some(ChalkExClause {
|
||||||
|
subst: tcx.lift(&ex_clause.subst)?,
|
||||||
|
delayed_literals: tcx.lift(&ex_clause.delayed_literals)?,
|
||||||
|
constraints: tcx.lift(&ex_clause.constraints)?,
|
||||||
|
subgoals: tcx.lift(&ex_clause.subgoals)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lift_delayed_literal_to_tcx(
|
||||||
|
literal: &DelayedLiteral<ChalkArenas<'a>>,
|
||||||
|
tcx: TyCtxt<'_, 'gcx, 'tcx>
|
||||||
|
) -> Option<Self::LiftedDelayedLiteral> {
|
||||||
|
Some(match literal {
|
||||||
|
DelayedLiteral::CannotProve(()) => DelayedLiteral::CannotProve(()),
|
||||||
|
DelayedLiteral::Negative(index) => DelayedLiteral::Negative(*index),
|
||||||
|
DelayedLiteral::Positive(index, subst) => DelayedLiteral::Positive(
|
||||||
|
*index,
|
||||||
|
tcx.lift(subst)?
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lift_literal_to_tcx(
|
||||||
|
literal: &Literal<ChalkArenas<'a>>,
|
||||||
|
tcx: TyCtxt<'_, 'gcx, 'tcx>,
|
||||||
|
) -> Option<Self::LiftedLiteral> {
|
||||||
|
Some(match literal {
|
||||||
|
Literal::Negative(goal) => Literal::Negative(tcx.lift(goal)?),
|
||||||
|
Literal::Positive(goal) => Literal::Positive(tcx.lift(goal)?),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,9 +579,9 @@ impl ExClauseFold<'tcx> for ChalkArenas<'tcx> {
|
||||||
subgoals,
|
subgoals,
|
||||||
} = ex_clause;
|
} = ex_clause;
|
||||||
subst.visit_with(visitor)
|
subst.visit_with(visitor)
|
||||||
&& delayed_literals.visit_with(visitor)
|
|| delayed_literals.visit_with(visitor)
|
||||||
&& constraints.visit_with(visitor)
|
|| constraints.visit_with(visitor)
|
||||||
&& subgoals.visit_with(visitor)
|
|| subgoals.visit_with(visitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -574,3 +657,59 @@ impl<'tcx, 'gcx: 'tcx, T> Upcast<'tcx, 'gcx> for Canonical<'gcx, T>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate fn provide(p: &mut Providers) {
|
||||||
|
*p = Providers {
|
||||||
|
evaluate_goal,
|
||||||
|
..*p
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn evaluate_goal<'a, 'tcx>(
|
||||||
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
goal: ChalkCanonicalGoal<'tcx>
|
||||||
|
) -> Result<
|
||||||
|
Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>,
|
||||||
|
traits::query::NoSolution
|
||||||
|
> {
|
||||||
|
use crate::lowering::Lower;
|
||||||
|
use rustc::traits::WellFormed;
|
||||||
|
|
||||||
|
let goal = goal.unchecked_map(|goal| InEnvironment {
|
||||||
|
environment: goal.environment,
|
||||||
|
goal: match goal.goal {
|
||||||
|
ty::Predicate::WellFormed(ty) => tcx.mk_goal(
|
||||||
|
GoalKind::DomainGoal(DomainGoal::WellFormed(WellFormed::Ty(ty)))
|
||||||
|
),
|
||||||
|
|
||||||
|
ty::Predicate::Subtype(predicate) => tcx.mk_goal(
|
||||||
|
GoalKind::Quantified(
|
||||||
|
QuantifierKind::Universal,
|
||||||
|
predicate.map_bound(|pred| tcx.mk_goal(GoalKind::Subtype(pred.a, pred.b)))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
other => tcx.mk_goal(
|
||||||
|
GoalKind::from_poly_domain_goal(other.lower(), tcx)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
debug!("evaluate_goal(goal = {:?})", goal);
|
||||||
|
|
||||||
|
let context = ChalkContext {
|
||||||
|
_arenas: ChalkArenas {
|
||||||
|
_phantom: PhantomData,
|
||||||
|
},
|
||||||
|
tcx,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut forest = Forest::new(context);
|
||||||
|
let solution = forest.solve(&goal);
|
||||||
|
|
||||||
|
debug!("evaluate_goal: solution = {:?}", solution);
|
||||||
|
|
||||||
|
solution.map(|ok| Ok(Lrc::new(ok)))
|
||||||
|
.unwrap_or(Err(traits::query::NoSolution))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,13 @@ use rustc::traits::{
|
||||||
Environment,
|
Environment,
|
||||||
};
|
};
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
|
use rustc::ty::subst::{Substs, Subst};
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use super::ChalkInferenceContext;
|
use super::ChalkInferenceContext;
|
||||||
use crate::lowering::Lower;
|
use crate::lowering::Lower;
|
||||||
|
use crate::generic_types;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
fn assemble_clauses_from_impls<'tcx>(
|
fn assemble_clauses_from_impls<'tcx>(
|
||||||
|
|
@ -47,50 +49,152 @@ fn assemble_clauses_from_assoc_ty_values<'tcx>(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program_clauses_for_raw_ptr<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> {
|
fn assemble_builtin_sized_impls<'tcx>(
|
||||||
let ty = ty::Bound(
|
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||||
ty::INNERMOST,
|
sized_def_id: DefId,
|
||||||
ty::BoundVar::from_u32(0).into()
|
ty: ty::Ty<'tcx>,
|
||||||
);
|
clauses: &mut Vec<Clause<'tcx>>
|
||||||
let ty = tcx.mk_ty(ty);
|
) {
|
||||||
|
let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| {
|
||||||
|
let clause = ProgramClause {
|
||||||
|
goal: ty::TraitPredicate {
|
||||||
|
trait_ref: ty::TraitRef {
|
||||||
|
def_id: sized_def_id,
|
||||||
|
substs: tcx.mk_substs_trait(ty, &[]),
|
||||||
|
},
|
||||||
|
}.lower(),
|
||||||
|
hypotheses: tcx.mk_goals(
|
||||||
|
nested.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|nested_ty| ty::TraitRef {
|
||||||
|
def_id: sized_def_id,
|
||||||
|
substs: tcx.mk_substs_trait(nested_ty, &[]),
|
||||||
|
})
|
||||||
|
.map(|trait_ref| ty::TraitPredicate { trait_ref })
|
||||||
|
.map(|pred| GoalKind::DomainGoal(pred.lower()))
|
||||||
|
.map(|goal_kind| tcx.mk_goal(goal_kind))
|
||||||
|
),
|
||||||
|
category: ProgramClauseCategory::Other,
|
||||||
|
};
|
||||||
|
// Bind innermost bound vars that may exist in `ty` and `nested`.
|
||||||
|
clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
|
||||||
|
};
|
||||||
|
|
||||||
let ptr_ty = tcx.mk_ptr(ty::TypeAndMut {
|
match &ty.sty {
|
||||||
ty,
|
// Non parametric primitive types.
|
||||||
mutbl: hir::Mutability::MutImmutable,
|
ty::Bool |
|
||||||
});
|
ty::Char |
|
||||||
|
ty::Int(..) |
|
||||||
|
ty::Uint(..) |
|
||||||
|
ty::Float(..) |
|
||||||
|
ty::Error |
|
||||||
|
ty::Never => push_builtin_impl(ty, &[]),
|
||||||
|
|
||||||
|
// These ones are always `Sized`.
|
||||||
|
&ty::Array(_, length) => {
|
||||||
|
push_builtin_impl(tcx.mk_ty(ty::Array(generic_types::bound(tcx, 0), length)), &[]);
|
||||||
|
}
|
||||||
|
ty::RawPtr(ptr) => {
|
||||||
|
push_builtin_impl(generic_types::raw_ptr(tcx, ptr.mutbl), &[]);
|
||||||
|
}
|
||||||
|
&ty::Ref(_, _, mutbl) => {
|
||||||
|
push_builtin_impl(generic_types::ref_ty(tcx, mutbl), &[]);
|
||||||
|
}
|
||||||
|
ty::FnPtr(fn_ptr) => {
|
||||||
|
let fn_ptr = fn_ptr.skip_binder();
|
||||||
|
let fn_ptr = generic_types::fn_ptr(
|
||||||
|
tcx,
|
||||||
|
fn_ptr.inputs_and_output.len(),
|
||||||
|
fn_ptr.variadic,
|
||||||
|
fn_ptr.unsafety,
|
||||||
|
fn_ptr.abi
|
||||||
|
);
|
||||||
|
push_builtin_impl(fn_ptr, &[]);
|
||||||
|
}
|
||||||
|
&ty::FnDef(def_id, ..) => {
|
||||||
|
push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]);
|
||||||
|
}
|
||||||
|
&ty::Closure(def_id, ..) => {
|
||||||
|
push_builtin_impl(generic_types::closure(tcx, def_id), &[]);
|
||||||
|
}
|
||||||
|
&ty::Generator(def_id, ..) => {
|
||||||
|
push_builtin_impl(generic_types::generator(tcx, def_id), &[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `Sized` if the last type is `Sized` (because else we will get a WF error anyway).
|
||||||
|
&ty::Tuple(type_list) => {
|
||||||
|
let type_list = generic_types::type_list(tcx, type_list.len());
|
||||||
|
push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Struct def
|
||||||
|
ty::Adt(adt_def, _) => {
|
||||||
|
let substs = Substs::bound_vars_for_item(tcx, adt_def.did);
|
||||||
|
let adt = tcx.mk_ty(ty::Adt(adt_def, substs));
|
||||||
|
let sized_constraint = adt_def.sized_constraint(tcx)
|
||||||
|
.iter()
|
||||||
|
.map(|ty| ty.subst(tcx, substs))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
push_builtin_impl(adt, &sized_constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Artificially trigger an ambiguity.
|
||||||
|
ty::Infer(..) => {
|
||||||
|
// Everybody can find at least two types to unify against:
|
||||||
|
// general ty vars, int vars and float vars.
|
||||||
|
push_builtin_impl(tcx.types.i32, &[]);
|
||||||
|
push_builtin_impl(tcx.types.u32, &[]);
|
||||||
|
push_builtin_impl(tcx.types.f32, &[]);
|
||||||
|
push_builtin_impl(tcx.types.f64, &[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Projection(_projection_ty) => {
|
||||||
|
// FIXME: add builtin impls from the associated type values found in
|
||||||
|
// trait impls of `projection_ty.trait_ref(tcx)`.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The `Sized` bound can only come from the environment.
|
||||||
|
ty::Param(..) |
|
||||||
|
ty::Placeholder(..) |
|
||||||
|
ty::UnnormalizedProjection(..) => (),
|
||||||
|
|
||||||
|
// Definitely not `Sized`.
|
||||||
|
ty::Foreign(..) |
|
||||||
|
ty::Str |
|
||||||
|
ty::Slice(..) |
|
||||||
|
ty::Dynamic(..) |
|
||||||
|
ty::Opaque(..) => (),
|
||||||
|
|
||||||
|
ty::Bound(..) |
|
||||||
|
ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wf_clause_for_raw_ptr<'tcx>(
|
||||||
|
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||||
|
mutbl: hir::Mutability
|
||||||
|
) -> Clauses<'tcx> {
|
||||||
|
let ptr_ty = generic_types::raw_ptr(tcx, mutbl);
|
||||||
|
|
||||||
let wf_clause = ProgramClause {
|
let wf_clause = ProgramClause {
|
||||||
goal: DomainGoal::WellFormed(WellFormed::Ty(ptr_ty)),
|
goal: DomainGoal::WellFormed(WellFormed::Ty(ptr_ty)),
|
||||||
hypotheses: ty::List::empty(),
|
hypotheses: ty::List::empty(),
|
||||||
category: ProgramClauseCategory::WellFormed,
|
category: ProgramClauseCategory::WellFormed,
|
||||||
};
|
};
|
||||||
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
let wf_clause = Clause::Implies(wf_clause);
|
||||||
|
|
||||||
// `forall<T> { WellFormed(*const T). }`
|
// `forall<T> { WellFormed(*const T). }`
|
||||||
tcx.mk_clauses(iter::once(wf_clause))
|
tcx.mk_clauses(iter::once(wf_clause))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program_clauses_for_fn_ptr<'tcx>(
|
fn wf_clause_for_fn_ptr<'tcx>(
|
||||||
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||||
arity_and_output: usize,
|
arity_and_output: usize,
|
||||||
variadic: bool,
|
variadic: bool,
|
||||||
unsafety: hir::Unsafety,
|
unsafety: hir::Unsafety,
|
||||||
abi: abi::Abi
|
abi: abi::Abi
|
||||||
) -> Clauses<'tcx> {
|
) -> Clauses<'tcx> {
|
||||||
let inputs_and_output = tcx.mk_type_list(
|
let fn_ptr = generic_types::fn_ptr(tcx, arity_and_output, variadic, unsafety, abi);
|
||||||
(0..arity_and_output).into_iter()
|
|
||||||
.map(|i| ty::BoundVar::from(i))
|
|
||||||
// DebruijnIndex(1) because we are going to inject these in a `PolyFnSig`
|
|
||||||
.map(|var| tcx.mk_ty(ty::Bound(ty::DebruijnIndex::from(1usize), var.into())))
|
|
||||||
);
|
|
||||||
|
|
||||||
let fn_sig = ty::Binder::bind(ty::FnSig {
|
|
||||||
inputs_and_output,
|
|
||||||
variadic,
|
|
||||||
unsafety,
|
|
||||||
abi,
|
|
||||||
});
|
|
||||||
let fn_ptr = tcx.mk_fn_ptr(fn_sig);
|
|
||||||
|
|
||||||
let wf_clause = ProgramClause {
|
let wf_clause = ProgramClause {
|
||||||
goal: DomainGoal::WellFormed(WellFormed::Ty(fn_ptr)),
|
goal: DomainGoal::WellFormed(WellFormed::Ty(fn_ptr)),
|
||||||
|
|
@ -104,13 +208,8 @@ fn program_clauses_for_fn_ptr<'tcx>(
|
||||||
tcx.mk_clauses(iter::once(wf_clause))
|
tcx.mk_clauses(iter::once(wf_clause))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program_clauses_for_slice<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> {
|
fn wf_clause_for_slice<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> {
|
||||||
let ty = ty::Bound(
|
let ty = generic_types::bound(tcx, 0);
|
||||||
ty::INNERMOST,
|
|
||||||
ty::BoundVar::from_u32(0).into()
|
|
||||||
);
|
|
||||||
let ty = tcx.mk_ty(ty);
|
|
||||||
|
|
||||||
let slice_ty = tcx.mk_slice(ty);
|
let slice_ty = tcx.mk_slice(ty);
|
||||||
|
|
||||||
let sized_trait = match tcx.lang_items().sized_trait() {
|
let sized_trait = match tcx.lang_items().sized_trait() {
|
||||||
|
|
@ -138,16 +237,11 @@ fn program_clauses_for_slice<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tc
|
||||||
tcx.mk_clauses(iter::once(wf_clause))
|
tcx.mk_clauses(iter::once(wf_clause))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program_clauses_for_array<'tcx>(
|
fn wf_clause_for_array<'tcx>(
|
||||||
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||||
length: &'tcx ty::Const<'tcx>
|
length: &'tcx ty::Const<'tcx>
|
||||||
) -> Clauses<'tcx> {
|
) -> Clauses<'tcx> {
|
||||||
let ty = ty::Bound(
|
let ty = generic_types::bound(tcx, 0);
|
||||||
ty::INNERMOST,
|
|
||||||
ty::BoundVar::from_u32(0).into()
|
|
||||||
);
|
|
||||||
let ty = tcx.mk_ty(ty);
|
|
||||||
|
|
||||||
let array_ty = tcx.mk_ty(ty::Array(ty, length));
|
let array_ty = tcx.mk_ty(ty::Array(ty, length));
|
||||||
|
|
||||||
let sized_trait = match tcx.lang_items().sized_trait() {
|
let sized_trait = match tcx.lang_items().sized_trait() {
|
||||||
|
|
@ -175,23 +269,21 @@ fn program_clauses_for_array<'tcx>(
|
||||||
tcx.mk_clauses(iter::once(wf_clause))
|
tcx.mk_clauses(iter::once(wf_clause))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program_clauses_for_tuple<'tcx>(
|
fn wf_clause_for_tuple<'tcx>(
|
||||||
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||||
arity: usize
|
arity: usize
|
||||||
) -> Clauses<'tcx> {
|
) -> Clauses<'tcx> {
|
||||||
let type_list = tcx.mk_type_list(
|
let type_list = generic_types::type_list(tcx, arity);
|
||||||
(0..arity).into_iter()
|
|
||||||
.map(|i| ty::BoundVar::from(i))
|
|
||||||
.map(|var| tcx.mk_ty(ty::Bound(ty::INNERMOST, var.into())))
|
|
||||||
);
|
|
||||||
|
|
||||||
let tuple_ty = tcx.mk_ty(ty::Tuple(type_list));
|
let tuple_ty = tcx.mk_ty(ty::Tuple(type_list));
|
||||||
|
|
||||||
let sized_trait = match tcx.lang_items().sized_trait() {
|
let sized_trait = match tcx.lang_items().sized_trait() {
|
||||||
Some(def_id) => def_id,
|
Some(def_id) => def_id,
|
||||||
None => return ty::List::empty(),
|
None => return ty::List::empty(),
|
||||||
};
|
};
|
||||||
let sized_implemented = type_list[0..arity - 1].iter()
|
|
||||||
|
// If `arity == 0` (i.e. the unit type) or `arity == 1`, this list of
|
||||||
|
// hypotheses is actually empty.
|
||||||
|
let sized_implemented = type_list[0 .. std::cmp::max(arity, 1) - 1].iter()
|
||||||
.map(|ty| ty::TraitRef {
|
.map(|ty| ty::TraitRef {
|
||||||
def_id: sized_trait,
|
def_id: sized_trait,
|
||||||
substs: tcx.mk_substs_trait(*ty, ty::List::empty()),
|
substs: tcx.mk_substs_trait(*ty, ty::List::empty()),
|
||||||
|
|
@ -221,26 +313,29 @@ fn program_clauses_for_tuple<'tcx>(
|
||||||
tcx.mk_clauses(iter::once(wf_clause))
|
tcx.mk_clauses(iter::once(wf_clause))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program_clauses_for_ref<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> {
|
fn wf_clause_for_ref<'tcx>(
|
||||||
|
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||||
|
mutbl: hir::Mutability
|
||||||
|
) -> Clauses<'tcx> {
|
||||||
let region = tcx.mk_region(
|
let region = tcx.mk_region(
|
||||||
ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0))
|
ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0))
|
||||||
);
|
);
|
||||||
let ty = tcx.mk_ty(
|
let ty = generic_types::bound(tcx, 1);
|
||||||
ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(1).into())
|
|
||||||
);
|
|
||||||
|
|
||||||
let ref_ty = tcx.mk_ref(region, ty::TypeAndMut {
|
let ref_ty = tcx.mk_ref(region, ty::TypeAndMut {
|
||||||
ty,
|
ty,
|
||||||
mutbl: hir::Mutability::MutImmutable,
|
mutbl,
|
||||||
});
|
});
|
||||||
|
|
||||||
let outlives: DomainGoal = ty::OutlivesPredicate(ty, region).lower();
|
let _outlives: DomainGoal = ty::OutlivesPredicate(ty, region).lower();
|
||||||
let wf_clause = ProgramClause {
|
let wf_clause = ProgramClause {
|
||||||
goal: DomainGoal::WellFormed(WellFormed::Ty(ref_ty)),
|
goal: DomainGoal::WellFormed(WellFormed::Ty(ref_ty)),
|
||||||
hypotheses: tcx.mk_goals(
|
hypotheses: ty::List::empty(),
|
||||||
iter::once(tcx.mk_goal(outlives.into_goal()))
|
|
||||||
),
|
// FIXME: restore this later once we get better at handling regions
|
||||||
category: ProgramClauseCategory::ImpliedBound,
|
// hypotheses: tcx.mk_goals(
|
||||||
|
// iter::once(tcx.mk_goal(outlives.into_goal()))
|
||||||
|
// ),
|
||||||
|
category: ProgramClauseCategory::WellFormed,
|
||||||
};
|
};
|
||||||
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
||||||
|
|
||||||
|
|
@ -248,6 +343,24 @@ fn program_clauses_for_ref<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx>
|
||||||
tcx.mk_clauses(iter::once(wf_clause))
|
tcx.mk_clauses(iter::once(wf_clause))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wf_clause_for_fn_def<'tcx>(
|
||||||
|
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||||
|
def_id: DefId
|
||||||
|
) -> Clauses<'tcx> {
|
||||||
|
let fn_def = generic_types::fn_def(tcx, def_id);
|
||||||
|
|
||||||
|
let wf_clause = ProgramClause {
|
||||||
|
goal: DomainGoal::WellFormed(WellFormed::Ty(fn_def)),
|
||||||
|
hypotheses: ty::List::empty(),
|
||||||
|
category: ProgramClauseCategory::WellFormed,
|
||||||
|
};
|
||||||
|
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
||||||
|
|
||||||
|
// `forall <T1, ..., Tn+1> { WellFormed(fn some_fn(T1, ..., Tn) -> Tn+1). }`
|
||||||
|
// where `def_id` maps to the `some_fn` function definition
|
||||||
|
tcx.mk_clauses(iter::once(wf_clause))
|
||||||
|
}
|
||||||
|
|
||||||
impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
|
impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
|
||||||
pub(super) fn program_clauses_impl(
|
pub(super) fn program_clauses_impl(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -255,6 +368,11 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
|
||||||
goal: &DomainGoal<'tcx>,
|
goal: &DomainGoal<'tcx>,
|
||||||
) -> Vec<Clause<'tcx>> {
|
) -> Vec<Clause<'tcx>> {
|
||||||
use rustc::traits::WhereClause::*;
|
use rustc::traits::WhereClause::*;
|
||||||
|
use rustc::infer::canonical::OriginalQueryValues;
|
||||||
|
|
||||||
|
let goal = self.infcx.resolve_type_vars_if_possible(goal);
|
||||||
|
|
||||||
|
debug!("program_clauses(goal = {:?})", goal);
|
||||||
|
|
||||||
let mut clauses = match goal {
|
let mut clauses = match goal {
|
||||||
DomainGoal::Holds(Implemented(trait_predicate)) => {
|
DomainGoal::Holds(Implemented(trait_predicate)) => {
|
||||||
|
|
@ -263,12 +381,22 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
|
||||||
// * the trait decl (rule `Implemented-From-Env`)
|
// * the trait decl (rule `Implemented-From-Env`)
|
||||||
|
|
||||||
let mut clauses = vec![];
|
let mut clauses = vec![];
|
||||||
|
|
||||||
assemble_clauses_from_impls(
|
assemble_clauses_from_impls(
|
||||||
self.infcx.tcx,
|
self.infcx.tcx,
|
||||||
trait_predicate.def_id(),
|
trait_predicate.def_id(),
|
||||||
&mut clauses
|
&mut clauses
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().sized_trait() {
|
||||||
|
assemble_builtin_sized_impls(
|
||||||
|
self.infcx.tcx,
|
||||||
|
trait_predicate.def_id(),
|
||||||
|
trait_predicate.self_ty(),
|
||||||
|
&mut clauses
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: we need to add special rules for builtin impls:
|
// FIXME: we need to add special rules for builtin impls:
|
||||||
// * `Copy` / `Clone`
|
// * `Copy` / `Clone`
|
||||||
// * `Sized`
|
// * `Sized`
|
||||||
|
|
@ -345,31 +473,34 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
|
||||||
self.infcx.tcx.program_clauses_for(data.item_def_id)
|
self.infcx.tcx.program_clauses_for(data.item_def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// These types are always WF and non-parametric.
|
// These types are always WF.
|
||||||
ty::Bool |
|
ty::Bool |
|
||||||
ty::Char |
|
ty::Char |
|
||||||
ty::Int(..) |
|
ty::Int(..) |
|
||||||
ty::Uint(..) |
|
ty::Uint(..) |
|
||||||
ty::Float(..) |
|
ty::Float(..) |
|
||||||
ty::Str |
|
ty::Str |
|
||||||
|
ty::Param(..) |
|
||||||
|
ty::Placeholder(..) |
|
||||||
|
ty::Error |
|
||||||
ty::Never => {
|
ty::Never => {
|
||||||
let wf_clause = ProgramClause {
|
let wf_clause = ProgramClause {
|
||||||
goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
|
goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
|
||||||
hypotheses: ty::List::empty(),
|
hypotheses: ty::List::empty(),
|
||||||
category: ProgramClauseCategory::WellFormed,
|
category: ProgramClauseCategory::WellFormed,
|
||||||
};
|
};
|
||||||
let wf_clause = Clause::ForAll(ty::Binder::dummy(wf_clause));
|
let wf_clause = Clause::Implies(wf_clause);
|
||||||
|
|
||||||
self.infcx.tcx.mk_clauses(iter::once(wf_clause))
|
self.infcx.tcx.mk_clauses(iter::once(wf_clause))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always WF (recall that we do not check for parameters to be WF).
|
// Always WF (recall that we do not check for parameters to be WF).
|
||||||
ty::RawPtr(..) => program_clauses_for_raw_ptr(self.infcx.tcx),
|
ty::RawPtr(ptr) => wf_clause_for_raw_ptr(self.infcx.tcx, ptr.mutbl),
|
||||||
|
|
||||||
// Always WF (recall that we do not check for parameters to be WF).
|
// Always WF (recall that we do not check for parameters to be WF).
|
||||||
ty::FnPtr(fn_ptr) => {
|
ty::FnPtr(fn_ptr) => {
|
||||||
let fn_ptr = fn_ptr.skip_binder();
|
let fn_ptr = fn_ptr.skip_binder();
|
||||||
program_clauses_for_fn_ptr(
|
wf_clause_for_fn_ptr(
|
||||||
self.infcx.tcx,
|
self.infcx.tcx,
|
||||||
fn_ptr.inputs_and_output.len(),
|
fn_ptr.inputs_and_output.len(),
|
||||||
fn_ptr.variadic,
|
fn_ptr.variadic,
|
||||||
|
|
@ -379,19 +510,21 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WF if inner type is `Sized`.
|
// WF if inner type is `Sized`.
|
||||||
ty::Slice(..) => program_clauses_for_slice(self.infcx.tcx),
|
ty::Slice(..) => wf_clause_for_slice(self.infcx.tcx),
|
||||||
|
|
||||||
// WF if inner type is `Sized`.
|
// WF if inner type is `Sized`.
|
||||||
ty::Array(_, length) => program_clauses_for_array(self.infcx.tcx, length),
|
ty::Array(_, length) => wf_clause_for_array(self.infcx.tcx, length),
|
||||||
|
|
||||||
// WF if all types but the last one are `Sized`.
|
// WF if all types but the last one are `Sized`.
|
||||||
ty::Tuple(types) => program_clauses_for_tuple(
|
ty::Tuple(types) => wf_clause_for_tuple(
|
||||||
self.infcx.tcx,
|
self.infcx.tcx,
|
||||||
types.len()
|
types.len()
|
||||||
),
|
),
|
||||||
|
|
||||||
// WF if `sub_ty` outlives `region`.
|
// WF if `sub_ty` outlives `region`.
|
||||||
ty::Ref(..) => program_clauses_for_ref(self.infcx.tcx),
|
ty::Ref(_, _, mutbl) => wf_clause_for_ref(self.infcx.tcx, mutbl),
|
||||||
|
|
||||||
|
ty::FnDef(def_id, ..) => wf_clause_for_fn_def(self.infcx.tcx, def_id),
|
||||||
|
|
||||||
ty::Dynamic(..) => {
|
ty::Dynamic(..) => {
|
||||||
// FIXME: no rules yet for trait objects
|
// FIXME: no rules yet for trait objects
|
||||||
|
|
@ -402,21 +535,32 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
|
||||||
self.infcx.tcx.program_clauses_for(def.did)
|
self.infcx.tcx.program_clauses_for(def.did)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: these are probably wrong
|
||||||
ty::Foreign(def_id) |
|
ty::Foreign(def_id) |
|
||||||
ty::FnDef(def_id, ..) |
|
|
||||||
ty::Closure(def_id, ..) |
|
ty::Closure(def_id, ..) |
|
||||||
ty::Generator(def_id, ..) |
|
ty::Generator(def_id, ..) |
|
||||||
ty::Opaque(def_id, ..) => {
|
ty::Opaque(def_id, ..) => {
|
||||||
self.infcx.tcx.program_clauses_for(def_id)
|
self.infcx.tcx.program_clauses_for(def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Artificially trigger an ambiguity.
|
||||||
|
ty::Infer(..) => {
|
||||||
|
let tcx = self.infcx.tcx;
|
||||||
|
let types = [tcx.types.i32, tcx.types.u32, tcx.types.f32, tcx.types.f64];
|
||||||
|
let clauses = types.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|ty| ProgramClause {
|
||||||
|
goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
|
||||||
|
hypotheses: ty::List::empty(),
|
||||||
|
category: ProgramClauseCategory::WellFormed,
|
||||||
|
})
|
||||||
|
.map(|clause| Clause::Implies(clause));
|
||||||
|
tcx.mk_clauses(clauses)
|
||||||
|
}
|
||||||
|
|
||||||
ty::GeneratorWitness(..) |
|
ty::GeneratorWitness(..) |
|
||||||
ty::Placeholder(..) |
|
|
||||||
ty::UnnormalizedProjection(..) |
|
ty::UnnormalizedProjection(..) |
|
||||||
ty::Infer(..) |
|
ty::Bound(..) => {
|
||||||
ty::Bound(..) |
|
|
||||||
ty::Param(..) |
|
|
||||||
ty::Error => {
|
|
||||||
bug!("unexpected type {:?}", ty)
|
bug!("unexpected type {:?}", ty)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -458,13 +602,20 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let environment = self.infcx.tcx.lift_to_global(environment)
|
debug!("program_clauses: clauses = {:?}", clauses);
|
||||||
.expect("environment is not global");
|
debug!("program_clauses: adding clauses from environment = {:?}", environment);
|
||||||
clauses.extend(
|
|
||||||
self.infcx.tcx.program_clauses_for_env(environment)
|
let mut _orig_query_values = OriginalQueryValues::default();
|
||||||
.into_iter()
|
let canonical_environment = self.infcx.canonicalize_query(
|
||||||
.cloned()
|
environment,
|
||||||
);
|
&mut _orig_query_values
|
||||||
|
).value;
|
||||||
|
let env_clauses = self.infcx.tcx.program_clauses_for_env(canonical_environment);
|
||||||
|
|
||||||
|
debug!("program_clauses: env_clauses = {:?}", env_clauses);
|
||||||
|
|
||||||
|
clauses.extend(env_clauses.into_iter().cloned());
|
||||||
|
clauses.extend(environment.clauses.iter().cloned());
|
||||||
clauses
|
clauses
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,9 @@ impl context::ResolventOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
|
||||||
) -> Fallible<Canonical<'gcx, ChalkExClause<'gcx>>> {
|
) -> Fallible<Canonical<'gcx, ChalkExClause<'gcx>>> {
|
||||||
use chalk_engine::context::UnificationOps;
|
use chalk_engine::context::UnificationOps;
|
||||||
|
|
||||||
self.infcx.probe(|_| {
|
debug!("resolvent_clause(goal = {:?}, clause = {:?})", goal, clause);
|
||||||
|
|
||||||
|
let result = self.infcx.probe(|_| {
|
||||||
let ProgramClause {
|
let ProgramClause {
|
||||||
goal: consequence,
|
goal: consequence,
|
||||||
hypotheses,
|
hypotheses,
|
||||||
|
|
@ -49,8 +51,13 @@ impl context::ResolventOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
|
||||||
).0,
|
).0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = unify(self.infcx, *environment, goal, &consequence)
|
let result = unify(
|
||||||
.map_err(|_| NoSolution)?;
|
self.infcx,
|
||||||
|
*environment,
|
||||||
|
ty::Variance::Invariant,
|
||||||
|
goal,
|
||||||
|
&consequence
|
||||||
|
).map_err(|_| NoSolution)?;
|
||||||
|
|
||||||
let mut ex_clause = ExClause {
|
let mut ex_clause = ExClause {
|
||||||
subst: subst.clone(),
|
subst: subst.clone(),
|
||||||
|
|
@ -70,7 +77,10 @@ impl context::ResolventOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
|
||||||
|
|
||||||
let canonical_ex_clause = self.canonicalize_ex_clause(&ex_clause);
|
let canonical_ex_clause = self.canonicalize_ex_clause(&ex_clause);
|
||||||
Ok(canonical_ex_clause)
|
Ok(canonical_ex_clause)
|
||||||
})
|
});
|
||||||
|
|
||||||
|
debug!("resolvent_clause: result = {:?}", result);
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_answer_subst(
|
fn apply_answer_subst(
|
||||||
|
|
@ -80,6 +90,12 @@ impl context::ResolventOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
|
||||||
answer_table_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
|
answer_table_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>,
|
||||||
canonical_answer_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>,
|
canonical_answer_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>,
|
||||||
) -> Fallible<ChalkExClause<'tcx>> {
|
) -> Fallible<ChalkExClause<'tcx>> {
|
||||||
|
debug!(
|
||||||
|
"apply_answer_subst(ex_clause = {:?}, selected_goal = {:?})",
|
||||||
|
self.infcx.resolve_type_vars_if_possible(&ex_clause),
|
||||||
|
self.infcx.resolve_type_vars_if_possible(selected_goal)
|
||||||
|
);
|
||||||
|
|
||||||
let (answer_subst, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
|
let (answer_subst, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
|
||||||
DUMMY_SP,
|
DUMMY_SP,
|
||||||
canonical_answer_subst
|
canonical_answer_subst
|
||||||
|
|
@ -96,8 +112,12 @@ impl context::ResolventOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
|
||||||
substitutor.relate(&answer_table_goal.value, &selected_goal)
|
substitutor.relate(&answer_table_goal.value, &selected_goal)
|
||||||
.map_err(|_| NoSolution)?;
|
.map_err(|_| NoSolution)?;
|
||||||
|
|
||||||
let mut ex_clause = substitutor.ex_clause;
|
let ex_clause = substitutor.ex_clause;
|
||||||
ex_clause.constraints.extend(answer_subst.constraints);
|
|
||||||
|
// FIXME: restore this later once we get better at handling regions
|
||||||
|
// ex_clause.constraints.extend(answer_subst.constraints);
|
||||||
|
|
||||||
|
debug!("apply_answer_subst: ex_clause = {:?}", ex_clause);
|
||||||
Ok(ex_clause)
|
Ok(ex_clause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +144,7 @@ impl AnswerSubstitutor<'cx, 'gcx, 'tcx> {
|
||||||
);
|
);
|
||||||
|
|
||||||
super::into_ex_clause(
|
super::into_ex_clause(
|
||||||
unify(self.infcx, self.environment, answer_param, pending)?,
|
unify(self.infcx, self.environment, ty::Variance::Invariant, answer_param, pending)?,
|
||||||
&mut self.ex_clause
|
&mut self.ex_clause
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -172,6 +192,7 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> {
|
||||||
|
|
||||||
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||||
let b = self.infcx.shallow_resolve(b);
|
let b = self.infcx.shallow_resolve(b);
|
||||||
|
debug!("AnswerSubstitutor::tys(a = {:?}, b = {:?})", a, b);
|
||||||
|
|
||||||
if let &ty::Bound(debruijn, bound_ty) = &a.sty {
|
if let &ty::Bound(debruijn, bound_ty) = &a.sty {
|
||||||
// Free bound var
|
// Free bound var
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,16 @@ crate struct UnificationResult<'tcx> {
|
||||||
crate fn unify<'me, 'gcx, 'tcx, T: Relate<'tcx>>(
|
crate fn unify<'me, 'gcx, 'tcx, T: Relate<'tcx>>(
|
||||||
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
|
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
|
||||||
environment: Environment<'tcx>,
|
environment: Environment<'tcx>,
|
||||||
|
variance: ty::Variance,
|
||||||
a: &T,
|
a: &T,
|
||||||
b: &T
|
b: &T
|
||||||
) -> RelateResult<'tcx, UnificationResult<'tcx>> {
|
) -> RelateResult<'tcx, UnificationResult<'tcx>> {
|
||||||
|
debug!("unify(
|
||||||
|
a = {:?},
|
||||||
|
b = {:?},
|
||||||
|
environment = {:?},
|
||||||
|
)", a, b, environment);
|
||||||
|
|
||||||
let mut delegate = ChalkTypeRelatingDelegate::new(
|
let mut delegate = ChalkTypeRelatingDelegate::new(
|
||||||
infcx,
|
infcx,
|
||||||
environment
|
environment
|
||||||
|
|
@ -24,9 +31,11 @@ crate fn unify<'me, 'gcx, 'tcx, T: Relate<'tcx>>(
|
||||||
TypeRelating::new(
|
TypeRelating::new(
|
||||||
infcx,
|
infcx,
|
||||||
&mut delegate,
|
&mut delegate,
|
||||||
ty::Variance::Invariant
|
variance
|
||||||
).relate(a, b)?;
|
).relate(a, b)?;
|
||||||
|
|
||||||
|
debug!("unify: goals = {:?}, constraints = {:?}", delegate.goals, delegate.constraints);
|
||||||
|
|
||||||
Ok(UnificationResult {
|
Ok(UnificationResult {
|
||||||
goals: delegate.goals,
|
goals: delegate.goals,
|
||||||
constraints: delegate.constraints,
|
constraints: delegate.constraints,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::canonical::{Canonical, QueryResponse};
|
use rustc::infer::canonical::{Canonical, QueryResponse};
|
||||||
use rustc::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint};
|
use rustc::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint};
|
||||||
use rustc::traits::query::{CanonicalTyGoal, NoSolution};
|
use rustc::traits::query::{CanonicalTyGoal, NoSolution};
|
||||||
use rustc::traits::{FulfillmentContext, Normalized, ObligationCause, TraitEngineExt};
|
use rustc::traits::{TraitEngine, Normalized, ObligationCause, TraitEngineExt};
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::ty::subst::{Subst, Substs};
|
use rustc::ty::subst::{Subst, Substs};
|
||||||
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||||
|
|
@ -78,7 +78,7 @@ fn dropck_outlives<'tcx>(
|
||||||
// Set used to detect infinite recursion.
|
// Set used to detect infinite recursion.
|
||||||
let mut ty_set = FxHashSet::default();
|
let mut ty_set = FxHashSet::default();
|
||||||
|
|
||||||
let fulfill_cx = &mut FulfillmentContext::new();
|
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
|
||||||
|
|
||||||
let cause = ObligationCause::dummy();
|
let cause = ObligationCause::dummy();
|
||||||
while let Some((ty, depth)) = ty_stack.pop() {
|
while let Some((ty, depth)) = ty_stack.pop() {
|
||||||
|
|
@ -136,7 +136,11 @@ fn dropck_outlives<'tcx>(
|
||||||
|
|
||||||
debug!("dropck_outlives: result = {:#?}", result);
|
debug!("dropck_outlives: result = {:#?}", result);
|
||||||
|
|
||||||
infcx.make_canonicalized_query_response(canonical_inference_vars, result, fulfill_cx)
|
infcx.make_canonicalized_query_response(
|
||||||
|
canonical_inference_vars,
|
||||||
|
result,
|
||||||
|
&mut *fulfill_cx
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
80
src/librustc_traits/generic_types.rs
Normal file
80
src/librustc_traits/generic_types.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
//! Utilities for creating generic types with bound vars in place of parameter values.
|
||||||
|
|
||||||
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
|
use rustc::ty::subst::Substs;
|
||||||
|
use rustc::hir;
|
||||||
|
use rustc::hir::def_id::DefId;
|
||||||
|
use rustc_target::spec::abi;
|
||||||
|
|
||||||
|
crate fn bound(tcx: ty::TyCtxt<'_, '_, 'tcx>, index: u32) -> Ty<'tcx> {
|
||||||
|
let ty = ty::Bound(
|
||||||
|
ty::INNERMOST,
|
||||||
|
ty::BoundVar::from_u32(index).into()
|
||||||
|
);
|
||||||
|
tcx.mk_ty(ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn raw_ptr(tcx: TyCtxt<'_, '_, 'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> {
|
||||||
|
tcx.mk_ptr(ty::TypeAndMut {
|
||||||
|
ty: bound(tcx, 0),
|
||||||
|
mutbl,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn fn_ptr(
|
||||||
|
tcx: ty::TyCtxt<'_, '_, 'tcx>,
|
||||||
|
arity_and_output: usize,
|
||||||
|
variadic: bool,
|
||||||
|
unsafety: hir::Unsafety,
|
||||||
|
abi: abi::Abi
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
let inputs_and_output = tcx.mk_type_list(
|
||||||
|
(0..arity_and_output).into_iter()
|
||||||
|
.map(|i| ty::BoundVar::from(i))
|
||||||
|
// DebruijnIndex(1) because we are going to inject these in a `PolyFnSig`
|
||||||
|
.map(|var| tcx.mk_ty(ty::Bound(ty::DebruijnIndex::from(1usize), var.into())))
|
||||||
|
);
|
||||||
|
|
||||||
|
let fn_sig = ty::Binder::bind(ty::FnSig {
|
||||||
|
inputs_and_output,
|
||||||
|
variadic,
|
||||||
|
unsafety,
|
||||||
|
abi,
|
||||||
|
});
|
||||||
|
tcx.mk_fn_ptr(fn_sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn type_list(tcx: ty::TyCtxt<'_, '_, 'tcx>, arity: usize) -> &'tcx ty::List<Ty<'tcx>> {
|
||||||
|
tcx.mk_type_list(
|
||||||
|
(0..arity).into_iter()
|
||||||
|
.map(|i| ty::BoundVar::from(i))
|
||||||
|
.map(|var| tcx.mk_ty(ty::Bound(ty::INNERMOST, var.into())))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn ref_ty(tcx: ty::TyCtxt<'_, '_, 'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> {
|
||||||
|
let region = tcx.mk_region(
|
||||||
|
ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0))
|
||||||
|
);
|
||||||
|
|
||||||
|
tcx.mk_ref(region, ty::TypeAndMut {
|
||||||
|
ty: bound(tcx, 1),
|
||||||
|
mutbl,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn fn_def(tcx: ty::TyCtxt<'_, '_, 'tcx>, def_id: DefId) -> Ty<'tcx> {
|
||||||
|
tcx.mk_ty(ty::FnDef(def_id, Substs::bound_vars_for_item(tcx, def_id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn closure(tcx: ty::TyCtxt<'_, '_, 'tcx>, def_id: DefId) -> Ty<'tcx> {
|
||||||
|
tcx.mk_closure(def_id, ty::ClosureSubsts {
|
||||||
|
substs: Substs::bound_vars_for_item(tcx, def_id),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn generator(tcx: ty::TyCtxt<'_, '_, 'tcx>, def_id: DefId) -> Ty<'tcx> {
|
||||||
|
tcx.mk_generator(def_id, ty::GeneratorSubsts {
|
||||||
|
substs: Substs::bound_vars_for_item(tcx, def_id),
|
||||||
|
}, hir::GeneratorMovability::Movable)
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,7 @@ mod implied_outlives_bounds;
|
||||||
mod normalize_projection_ty;
|
mod normalize_projection_ty;
|
||||||
mod normalize_erasing_regions;
|
mod normalize_erasing_regions;
|
||||||
pub mod lowering;
|
pub mod lowering;
|
||||||
|
mod generic_types;
|
||||||
mod type_op;
|
mod type_op;
|
||||||
|
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
|
|
@ -34,6 +35,7 @@ pub fn provide(p: &mut Providers) {
|
||||||
evaluate_obligation::provide(p);
|
evaluate_obligation::provide(p);
|
||||||
implied_outlives_bounds::provide(p);
|
implied_outlives_bounds::provide(p);
|
||||||
lowering::provide(p);
|
lowering::provide(p);
|
||||||
|
chalk_context::provide(p);
|
||||||
normalize_projection_ty::provide(p);
|
normalize_projection_ty::provide(p);
|
||||||
normalize_erasing_regions::provide(p);
|
normalize_erasing_regions::provide(p);
|
||||||
type_op::provide(p);
|
type_op::provide(p);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use rustc::ty::{self, TyCtxt, Ty};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use super::Lower;
|
use super::Lower;
|
||||||
|
use crate::generic_types;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
struct ClauseVisitor<'set, 'a, 'tcx: 'a + 'set> {
|
struct ClauseVisitor<'set, 'a, 'tcx: 'a + 'set> {
|
||||||
|
|
@ -38,20 +39,16 @@ impl ClauseVisitor<'set, 'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// forall<'a, T> { `Outlives(T: 'a) :- FromEnv(&'a T)` }
|
// forall<'a, T> { `Outlives(T: 'a) :- FromEnv(&'a T)` }
|
||||||
ty::Ref(..) => {
|
ty::Ref(_, _, mutbl) => {
|
||||||
use rustc::hir;
|
|
||||||
|
|
||||||
let region = self.tcx.mk_region(
|
let region = self.tcx.mk_region(
|
||||||
ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0))
|
ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0))
|
||||||
);
|
);
|
||||||
let ty = self.tcx.mk_ty(
|
let ty = generic_types::bound(self.tcx, 1);
|
||||||
ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(1).into())
|
|
||||||
);
|
|
||||||
|
|
||||||
let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut {
|
let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut {
|
||||||
ty,
|
ty,
|
||||||
mutbl: hir::Mutability::MutImmutable,
|
mutbl,
|
||||||
});
|
});
|
||||||
|
|
||||||
let from_env = DomainGoal::FromEnv(FromEnv::Ty(ref_ty));
|
let from_env = DomainGoal::FromEnv(FromEnv::Ty(ref_ty));
|
||||||
|
|
||||||
let clause = ProgramClause {
|
let clause = ProgramClause {
|
||||||
|
|
@ -105,11 +102,11 @@ impl ClauseVisitor<'set, 'a, 'tcx> {
|
||||||
ty::Never |
|
ty::Never |
|
||||||
ty::Infer(..) |
|
ty::Infer(..) |
|
||||||
ty::Placeholder(..) |
|
ty::Placeholder(..) |
|
||||||
|
ty::Param(..) |
|
||||||
ty::Bound(..) => (),
|
ty::Bound(..) => (),
|
||||||
|
|
||||||
ty::GeneratorWitness(..) |
|
ty::GeneratorWitness(..) |
|
||||||
ty::UnnormalizedProjection(..) |
|
ty::UnnormalizedProjection(..) |
|
||||||
ty::Param(..) |
|
|
||||||
ty::Error => {
|
ty::Error => {
|
||||||
bug!("unexpected type {:?}", ty);
|
bug!("unexpected type {:?}", ty);
|
||||||
}
|
}
|
||||||
|
|
@ -192,25 +189,23 @@ crate fn program_clauses_for_env<'a, 'tcx>(
|
||||||
crate fn environment<'a, 'tcx>(
|
crate fn environment<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
def_id: DefId
|
def_id: DefId
|
||||||
) -> ty::Binder<Environment<'tcx>> {
|
) -> Environment<'tcx> {
|
||||||
use super::{Lower, IntoFromEnvGoal};
|
use super::{Lower, IntoFromEnvGoal};
|
||||||
use rustc::hir::{Node, TraitItemKind, ImplItemKind, ItemKind, ForeignItemKind};
|
use rustc::hir::{Node, TraitItemKind, ImplItemKind, ItemKind, ForeignItemKind};
|
||||||
use rustc::ty::subst::{Subst, Substs};
|
|
||||||
|
debug!("environment(def_id = {:?})", def_id);
|
||||||
|
|
||||||
// The environment of an impl Trait type is its defining function's environment.
|
// The environment of an impl Trait type is its defining function's environment.
|
||||||
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
|
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
|
||||||
return environment(tcx, parent);
|
return environment(tcx, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
let bound_vars = Substs::bound_vars_for_item(tcx, def_id);
|
|
||||||
|
|
||||||
// Compute the bounds on `Self` and the type parameters.
|
// Compute the bounds on `Self` and the type parameters.
|
||||||
let ty::InstantiatedPredicates { predicates } = tcx.predicates_of(def_id)
|
let ty::InstantiatedPredicates { predicates } = tcx.predicates_of(def_id)
|
||||||
.instantiate_identity(tcx);
|
.instantiate_identity(tcx);
|
||||||
|
|
||||||
let clauses = predicates.into_iter()
|
let clauses = predicates.into_iter()
|
||||||
.map(|predicate| predicate.lower())
|
.map(|predicate| predicate.lower())
|
||||||
.map(|predicate| predicate.subst(tcx, bound_vars))
|
|
||||||
.map(|domain_goal| domain_goal.map_bound(|bound| bound.into_from_env_goal()))
|
.map(|domain_goal| domain_goal.map_bound(|bound| bound.into_from_env_goal()))
|
||||||
.map(|domain_goal| domain_goal.map_bound(|bound| bound.into_program_clause()))
|
.map(|domain_goal| domain_goal.map_bound(|bound| bound.into_program_clause()))
|
||||||
|
|
||||||
|
|
@ -221,73 +216,85 @@ crate fn environment<'a, 'tcx>(
|
||||||
let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
|
let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
|
||||||
let node = tcx.hir().get(node_id);
|
let node = tcx.hir().get(node_id);
|
||||||
|
|
||||||
let mut is_fn = false;
|
enum NodeKind {
|
||||||
let mut is_impl = false;
|
TraitImpl,
|
||||||
match node {
|
InherentImpl,
|
||||||
|
Fn,
|
||||||
|
Other,
|
||||||
|
};
|
||||||
|
|
||||||
|
let node_kind = match node {
|
||||||
Node::TraitItem(item) => match item.node {
|
Node::TraitItem(item) => match item.node {
|
||||||
TraitItemKind::Method(..) => is_fn = true,
|
TraitItemKind::Method(..) => NodeKind::Fn,
|
||||||
_ => (),
|
_ => NodeKind::Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::ImplItem(item) => match item.node {
|
Node::ImplItem(item) => match item.node {
|
||||||
ImplItemKind::Method(..) => is_fn = true,
|
ImplItemKind::Method(..) => NodeKind::Fn,
|
||||||
_ => (),
|
_ => NodeKind::Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::Item(item) => match item.node {
|
Node::Item(item) => match item.node {
|
||||||
ItemKind::Impl(..) => is_impl = true,
|
ItemKind::Impl(.., Some(..), _, _) => NodeKind::TraitImpl,
|
||||||
ItemKind::Fn(..) => is_fn = true,
|
ItemKind::Impl(.., None, _, _) => NodeKind::InherentImpl,
|
||||||
_ => (),
|
ItemKind::Fn(..) => NodeKind::Fn,
|
||||||
|
_ => NodeKind::Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::ForeignItem(item) => match item.node {
|
Node::ForeignItem(item) => match item.node {
|
||||||
ForeignItemKind::Fn(..) => is_fn = true,
|
ForeignItemKind::Fn(..) => NodeKind::Fn,
|
||||||
_ => (),
|
_ => NodeKind::Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: closures?
|
// FIXME: closures?
|
||||||
_ => (),
|
_ => NodeKind::Other,
|
||||||
}
|
};
|
||||||
|
|
||||||
let mut input_tys = FxHashSet::default();
|
let mut input_tys = FxHashSet::default();
|
||||||
|
|
||||||
// In an impl, we assume that the header trait ref and all its constituents
|
match node_kind {
|
||||||
// are well-formed.
|
// In a trait impl, we assume that the header trait ref and all its
|
||||||
if is_impl {
|
// constituents are well-formed.
|
||||||
let trait_ref = tcx.impl_trait_ref(def_id)
|
NodeKind::TraitImpl => {
|
||||||
.expect("not an impl")
|
let trait_ref = tcx.impl_trait_ref(def_id)
|
||||||
.subst(tcx, bound_vars);
|
.expect("not an impl");
|
||||||
|
|
||||||
input_tys.extend(
|
input_tys.extend(
|
||||||
trait_ref.substs.types().flat_map(|ty| ty.walk())
|
trait_ref.input_types().flat_map(|ty| ty.walk())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// In an fn, we assume that the arguments and all their constituents are
|
// In an inherent impl, we assume that the receiver type and all its
|
||||||
// well-formed.
|
// constituents are well-formed.
|
||||||
if is_fn {
|
NodeKind::InherentImpl => {
|
||||||
// `skip_binder` because we move region parameters to the root binder,
|
let self_ty = tcx.type_of(def_id);
|
||||||
// restored in the return type of this query
|
input_tys.extend(self_ty.walk());
|
||||||
let fn_sig = tcx.fn_sig(def_id).skip_binder().subst(tcx, bound_vars);
|
}
|
||||||
|
|
||||||
input_tys.extend(
|
// In an fn, we assume that the arguments and all their constituents are
|
||||||
fn_sig.inputs().iter().flat_map(|ty| ty.walk())
|
// well-formed.
|
||||||
);
|
NodeKind::Fn => {
|
||||||
|
let fn_sig = tcx.fn_sig(def_id);
|
||||||
|
let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig);
|
||||||
|
|
||||||
|
input_tys.extend(
|
||||||
|
fn_sig.inputs().iter().flat_map(|ty| ty.walk())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeKind::Other => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let clauses = clauses.chain(
|
let clauses = clauses.chain(
|
||||||
input_tys.into_iter()
|
input_tys.into_iter()
|
||||||
// Filter out type parameters
|
|
||||||
.filter(|ty| match ty.sty {
|
|
||||||
ty::Bound(..) => false,
|
|
||||||
_ => true,
|
|
||||||
})
|
|
||||||
.map(|ty| DomainGoal::FromEnv(FromEnv::Ty(ty)))
|
.map(|ty| DomainGoal::FromEnv(FromEnv::Ty(ty)))
|
||||||
.map(|domain_goal| domain_goal.into_program_clause())
|
.map(|domain_goal| domain_goal.into_program_clause())
|
||||||
.map(Clause::Implies)
|
.map(Clause::Implies)
|
||||||
);
|
);
|
||||||
|
|
||||||
ty::Binder::bind(Environment {
|
debug!("environment: clauses = {:?}", clauses);
|
||||||
|
|
||||||
|
Environment {
|
||||||
clauses: tcx.mk_clauses(clauses),
|
clauses: tcx.mk_clauses(clauses),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,6 @@ fn program_clauses_for_trait<'a, 'tcx>(
|
||||||
let where_clauses = &predicates
|
let where_clauses = &predicates
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(wc, _)| wc.lower())
|
.map(|(wc, _)| wc.lower())
|
||||||
.map(|wc| wc.subst(tcx, bound_vars))
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Rule Implied-Bound-From-Trait
|
// Rule Implied-Bound-From-Trait
|
||||||
|
|
@ -232,14 +231,13 @@ fn program_clauses_for_trait<'a, 'tcx>(
|
||||||
.map(|wc| {
|
.map(|wc| {
|
||||||
// we move binders to the left
|
// we move binders to the left
|
||||||
wc.map_bound(|goal| ProgramClause {
|
wc.map_bound(|goal| ProgramClause {
|
||||||
goal: goal.into_from_env_goal(),
|
// FIXME: As where clauses can only bind lifetimes for now, and that named
|
||||||
|
// bound regions have a def-id, it is safe to just inject `bound_vars` and
|
||||||
// FIXME: As where clauses can only bind lifetimes for now,
|
// `hypotheses` (which contain named vars bound at index `0`) into this
|
||||||
// and that named bound regions have a def-id, it is safe
|
// binding level. This may change if we ever allow where clauses to bind
|
||||||
// to just inject `hypotheses` (which contains named vars bound at index `0`)
|
// types (e.g. for GATs things), because bound types only use a `BoundVar`
|
||||||
// into this binding level. This may change if we ever allow where clauses
|
|
||||||
// to bind types (e.g., for GATs things), because bound types only use a `BoundVar`
|
|
||||||
// index (no def-id).
|
// index (no def-id).
|
||||||
|
goal: goal.subst(tcx, bound_vars).into_from_env_goal(),
|
||||||
hypotheses,
|
hypotheses,
|
||||||
|
|
||||||
category: ProgramClauseCategory::ImpliedBound,
|
category: ProgramClauseCategory::ImpliedBound,
|
||||||
|
|
@ -346,7 +344,6 @@ pub fn program_clauses_for_type_def<'a, 'tcx>(
|
||||||
let where_clauses = tcx.predicates_of(def_id).predicates
|
let where_clauses = tcx.predicates_of(def_id).predicates
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(wc, _)| wc.lower())
|
.map(|(wc, _)| wc.lower())
|
||||||
.map(|wc| wc.subst(tcx, bound_vars))
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// `WellFormed(Ty<...>) :- WC1, ..., WCm`
|
// `WellFormed(Ty<...>) :- WC1, ..., WCm`
|
||||||
|
|
@ -355,7 +352,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>(
|
||||||
hypotheses: tcx.mk_goals(
|
hypotheses: tcx.mk_goals(
|
||||||
where_clauses
|
where_clauses
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.map(|wc| wc.subst(tcx, bound_vars))
|
||||||
.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
|
.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
|
||||||
),
|
),
|
||||||
category: ProgramClauseCategory::WellFormed,
|
category: ProgramClauseCategory::WellFormed,
|
||||||
|
|
@ -383,11 +380,10 @@ pub fn program_clauses_for_type_def<'a, 'tcx>(
|
||||||
.map(|wc| {
|
.map(|wc| {
|
||||||
// move the binders to the left
|
// move the binders to the left
|
||||||
wc.map_bound(|goal| ProgramClause {
|
wc.map_bound(|goal| ProgramClause {
|
||||||
goal: goal.into_from_env_goal(),
|
// FIXME: we inject `bound_vars` and `hypotheses` into this binding
|
||||||
|
// level, which may be incorrect in the future: see the FIXME in
|
||||||
// FIXME: we inject `hypotheses` into this binding level,
|
// `program_clauses_for_trait`.
|
||||||
// which may be incorrect in the future: see the FIXME in
|
goal: goal.subst(tcx, bound_vars).into_from_env_goal(),
|
||||||
// `program_clauses_for_trait`
|
|
||||||
hypotheses,
|
hypotheses,
|
||||||
|
|
||||||
category: ProgramClauseCategory::ImpliedBound,
|
category: ProgramClauseCategory::ImpliedBound,
|
||||||
|
|
@ -626,7 +622,7 @@ impl<'a, 'tcx> ClauseDumper<'a, 'tcx> {
|
||||||
|
|
||||||
if attr.check_name("rustc_dump_env_program_clauses") {
|
if attr.check_name("rustc_dump_env_program_clauses") {
|
||||||
let environment = self.tcx.environment(def_id);
|
let environment = self.tcx.environment(def_id);
|
||||||
clauses = Some(self.tcx.program_clauses_for_env(*environment.skip_binder()));
|
clauses = Some(self.tcx.program_clauses_for_env(environment));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(clauses) = clauses {
|
if let Some(clauses) = clauses {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use rustc::traits::query::type_op::prove_predicate::ProvePredicate;
|
||||||
use rustc::traits::query::type_op::subtype::Subtype;
|
use rustc::traits::query::type_op::subtype::Subtype;
|
||||||
use rustc::traits::query::{Fallible, NoSolution};
|
use rustc::traits::query::{Fallible, NoSolution};
|
||||||
use rustc::traits::{
|
use rustc::traits::{
|
||||||
FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt,
|
Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt,
|
||||||
};
|
};
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::ty::subst::{Kind, Subst, UserSelfTy, UserSubsts};
|
use rustc::ty::subst::{Kind, Subst, UserSelfTy, UserSubsts};
|
||||||
|
|
@ -75,7 +75,7 @@ fn type_op_ascribe_user_type<'tcx>(
|
||||||
struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> {
|
struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> {
|
||||||
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
|
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
|
||||||
param_env: ParamEnv<'tcx>,
|
param_env: ParamEnv<'tcx>,
|
||||||
fulfill_cx: &'me mut FulfillmentContext<'tcx>,
|
fulfill_cx: &'me mut dyn TraitEngine<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
|
impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
|
||||||
|
|
@ -231,7 +231,7 @@ fn type_op_eq<'tcx>(
|
||||||
|
|
||||||
fn type_op_normalize<T>(
|
fn type_op_normalize<T>(
|
||||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||||
fulfill_cx: &mut FulfillmentContext<'tcx>,
|
fulfill_cx: &mut dyn TraitEngine<'tcx>,
|
||||||
key: ParamEnvAnd<'tcx, Normalize<T>>,
|
key: ParamEnvAnd<'tcx, Normalize<T>>,
|
||||||
) -> Fallible<T>
|
) -> Fallible<T>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -206,8 +206,11 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
// The key step here is to update the caller_bounds's predicates to be
|
// The key step here is to update the caller_bounds's predicates to be
|
||||||
// the new hybrid bounds we computed.
|
// the new hybrid bounds we computed.
|
||||||
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id);
|
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id);
|
||||||
let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates),
|
let param_env = ty::ParamEnv::new(
|
||||||
Reveal::UserFacing);
|
tcx.intern_predicates(&hybrid_preds.predicates),
|
||||||
|
Reveal::UserFacing,
|
||||||
|
None
|
||||||
|
);
|
||||||
let param_env = traits::normalize_param_env_or_error(tcx,
|
let param_env = traits::normalize_param_env_or_error(tcx,
|
||||||
impl_m.def_id,
|
impl_m.def_id,
|
||||||
param_env,
|
param_env,
|
||||||
|
|
|
||||||
16
src/test/compile-fail/chalkify/chalk_initial_program.rs
Normal file
16
src/test/compile-fail/chalkify/chalk_initial_program.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
// compile-flags: -Z chalk
|
||||||
|
|
||||||
|
trait Foo { }
|
||||||
|
|
||||||
|
impl Foo for i32 { }
|
||||||
|
|
||||||
|
impl Foo for u32 { }
|
||||||
|
|
||||||
|
fn gimme<F: Foo>() { }
|
||||||
|
|
||||||
|
// Note: this also tests that `std::process::Termination` is implemented for `()`.
|
||||||
|
fn main() {
|
||||||
|
gimme::<i32>();
|
||||||
|
gimme::<u32>();
|
||||||
|
gimme::<f32>(); //~ERROR the trait bound `f32: Foo` is not satisfied
|
||||||
|
}
|
||||||
18
src/test/compile-fail/chalkify/generic_impls.rs
Normal file
18
src/test/compile-fail/chalkify/generic_impls.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
// compile-flags: -Z chalk
|
||||||
|
|
||||||
|
trait Foo { }
|
||||||
|
|
||||||
|
impl<T> Foo for (T, u32) { }
|
||||||
|
|
||||||
|
fn gimme<F: Foo>() { }
|
||||||
|
|
||||||
|
fn foo<T>() {
|
||||||
|
gimme::<(T, u32)>();
|
||||||
|
gimme::<(Option<T>, u32)>();
|
||||||
|
gimme::<(Option<T>, f32)>(); //~ ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
gimme::<(i32, u32)>();
|
||||||
|
gimme::<(i32, f32)>(); //~ ERROR
|
||||||
|
}
|
||||||
38
src/test/compile-fail/chalkify/impl_wf.rs
Normal file
38
src/test/compile-fail/chalkify/impl_wf.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
// compile-flags: -Z chalk
|
||||||
|
|
||||||
|
trait Foo: Sized { }
|
||||||
|
|
||||||
|
trait Bar {
|
||||||
|
type Item: Foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for i32 { }
|
||||||
|
|
||||||
|
impl Foo for str { }
|
||||||
|
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||||
|
|
||||||
|
// Implicit `T: Sized` bound.
|
||||||
|
impl<T> Foo for Option<T> { }
|
||||||
|
|
||||||
|
impl Bar for () {
|
||||||
|
type Item = i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Bar for Option<T> {
|
||||||
|
type Item = Option<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bar for f32 {
|
||||||
|
//~^ ERROR the trait bound `f32: Foo` is not satisfied
|
||||||
|
type Item = f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Baz<U: ?Sized> where U: Foo { }
|
||||||
|
|
||||||
|
impl Baz<i32> for i32 { }
|
||||||
|
|
||||||
|
impl Baz<f32> for f32 { }
|
||||||
|
//~^ ERROR the trait bound `f32: Foo` is not satisfied
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
24
src/test/compile-fail/chalkify/type_wf.rs
Normal file
24
src/test/compile-fail/chalkify/type_wf.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
// compile-flags: -Z chalk
|
||||||
|
|
||||||
|
trait Foo { }
|
||||||
|
|
||||||
|
struct S<T: Foo> {
|
||||||
|
x: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for i32 { }
|
||||||
|
impl<T> Foo for Option<T> { }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = S {
|
||||||
|
x: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
let s = S { //~ ERROR the trait bound `{float}: Foo` is not satisfied
|
||||||
|
x: 5.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let s = S {
|
||||||
|
x: Some(5.0),
|
||||||
|
};
|
||||||
|
}
|
||||||
41
src/test/run-pass/chalkify/inherent_impl.rs
Normal file
41
src/test/run-pass/chalkify/inherent_impl.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
// compile-flags: -Z chalk
|
||||||
|
|
||||||
|
trait Foo { }
|
||||||
|
|
||||||
|
impl Foo for i32 { }
|
||||||
|
|
||||||
|
struct S<T: Foo> {
|
||||||
|
x: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn only_foo<T: Foo>(_x: &T) { }
|
||||||
|
|
||||||
|
impl<T> S<T> {
|
||||||
|
// Test that we have the correct environment inside an inherent method.
|
||||||
|
fn dummy_foo(&self) {
|
||||||
|
only_foo(&self.x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Bar { }
|
||||||
|
impl Bar for u32 { }
|
||||||
|
|
||||||
|
fn only_bar<T: Bar>() { }
|
||||||
|
|
||||||
|
impl<T> S<T> {
|
||||||
|
// Test that the environment of `dummy_bar` adds up with the environment
|
||||||
|
// of the inherent impl.
|
||||||
|
fn dummy_bar<U: Bar>(&self) {
|
||||||
|
only_foo(&self.x);
|
||||||
|
only_bar::<U>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = S {
|
||||||
|
x: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
s.dummy_foo();
|
||||||
|
s.dummy_bar::<u32>();
|
||||||
|
}
|
||||||
24
src/test/run-pass/chalkify/projection.rs
Normal file
24
src/test/run-pass/chalkify/projection.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
// compile-flags: -Z chalk
|
||||||
|
|
||||||
|
trait Foo { }
|
||||||
|
|
||||||
|
trait Bar {
|
||||||
|
type Item: Foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for i32 { }
|
||||||
|
impl Bar for i32 {
|
||||||
|
type Item = i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn only_foo<T: Foo>() { }
|
||||||
|
|
||||||
|
fn only_bar<T: Bar>() {
|
||||||
|
// `T` implements `Bar` hence `<T as Bar>::Item` must also implement `Bar`
|
||||||
|
only_foo::<T::Item>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
only_bar::<i32>();
|
||||||
|
only_foo::<<i32 as Bar>::Item>();
|
||||||
|
}
|
||||||
18
src/test/run-pass/chalkify/super_trait.rs
Normal file
18
src/test/run-pass/chalkify/super_trait.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
// compile-flags: -Z chalk
|
||||||
|
|
||||||
|
trait Foo { }
|
||||||
|
trait Bar: Foo { }
|
||||||
|
|
||||||
|
impl Foo for i32 { }
|
||||||
|
impl Bar for i32 { }
|
||||||
|
|
||||||
|
fn only_foo<T: Foo>() { }
|
||||||
|
|
||||||
|
fn only_bar<T: Bar>() {
|
||||||
|
// `T` implements `Bar` hence `T` must also implement `Foo`
|
||||||
|
only_foo::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
only_bar::<i32>()
|
||||||
|
}
|
||||||
17
src/test/run-pass/chalkify/trait_implied_bound.rs
Normal file
17
src/test/run-pass/chalkify/trait_implied_bound.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
// compile-flags: -Z chalk
|
||||||
|
|
||||||
|
trait Foo { }
|
||||||
|
trait Bar<U> where U: Foo { }
|
||||||
|
|
||||||
|
impl Foo for i32 { }
|
||||||
|
impl Bar<i32> for i32 { }
|
||||||
|
|
||||||
|
fn only_foo<T: Foo>() { }
|
||||||
|
|
||||||
|
fn only_bar<U, T: Bar<U>>() {
|
||||||
|
only_foo::<U>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
only_bar::<i32, i32>()
|
||||||
|
}
|
||||||
28
src/test/run-pass/chalkify/type_implied_bound.rs
Normal file
28
src/test/run-pass/chalkify/type_implied_bound.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
// compile-flags: -Z chalk
|
||||||
|
|
||||||
|
trait Eq { }
|
||||||
|
trait Hash: Eq { }
|
||||||
|
|
||||||
|
impl Eq for i32 { }
|
||||||
|
impl Hash for i32 { }
|
||||||
|
|
||||||
|
struct Set<T: Hash> {
|
||||||
|
_x: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn only_eq<T: Eq>() { }
|
||||||
|
|
||||||
|
fn take_a_set<T>(_: &Set<T>) {
|
||||||
|
// `Set<T>` is an input type of `take_a_set`, hence we know that
|
||||||
|
// `T` must implement `Hash`, and we know in turn that `T` must
|
||||||
|
// implement `Eq`.
|
||||||
|
only_eq::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let set = Set {
|
||||||
|
_x: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
take_a_set(&set);
|
||||||
|
}
|
||||||
26
src/test/ui/chalkify/type_inference.rs
Normal file
26
src/test/ui/chalkify/type_inference.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
// compile-flags: -Z chalk
|
||||||
|
|
||||||
|
trait Foo { }
|
||||||
|
impl Foo for i32 { }
|
||||||
|
|
||||||
|
trait Bar { }
|
||||||
|
impl Bar for i32 { }
|
||||||
|
impl Bar for u32 { }
|
||||||
|
|
||||||
|
fn only_foo<T: Foo>(_x: T) { }
|
||||||
|
|
||||||
|
fn only_bar<T: Bar>(_x: T) { }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = 5.0;
|
||||||
|
|
||||||
|
// The only type which implements `Foo` is `i32`, so the chalk trait solver
|
||||||
|
// is expecting a variable of type `i32`. This behavior differs from the
|
||||||
|
// old-style trait solver. I guess this will change, that's why I'm
|
||||||
|
// adding that test.
|
||||||
|
only_foo(x); //~ ERROR mismatched types
|
||||||
|
|
||||||
|
// Here we have two solutions so we get back the behavior of the old-style
|
||||||
|
// trait solver.
|
||||||
|
only_bar(x); //~ ERROR the trait bound `{float}: Bar` is not satisfied
|
||||||
|
}
|
||||||
28
src/test/ui/chalkify/type_inference.stderr
Normal file
28
src/test/ui/chalkify/type_inference.stderr
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/type_inference.rs:21:14
|
||||||
|
|
|
||||||
|
LL | only_foo(x); //~ ERROR mismatched types
|
||||||
|
| ^ expected i32, found floating-point variable
|
||||||
|
|
|
||||||
|
= note: expected type `i32`
|
||||||
|
found type `{float}`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `{float}: Bar` is not satisfied
|
||||||
|
--> $DIR/type_inference.rs:25:5
|
||||||
|
|
|
||||||
|
LL | only_bar(x); //~ ERROR the trait bound `{float}: Bar` is not satisfied
|
||||||
|
| ^^^^^^^^ the trait `Bar` is not implemented for `{float}`
|
||||||
|
|
|
||||||
|
= help: the following implementations were found:
|
||||||
|
<i32 as Bar>
|
||||||
|
<u32 as Bar>
|
||||||
|
note: required by `only_bar`
|
||||||
|
--> $DIR/type_inference.rs:12:1
|
||||||
|
|
|
||||||
|
LL | fn only_bar<T: Bar>(_x: T) { }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors occurred: E0277, E0308.
|
||||||
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
|
@ -10,7 +10,7 @@ note: ...which requires const-evaluating `Foo::bytes::{{constant}}`...
|
||||||
LL | intrinsics::size_of::<T>()
|
LL | intrinsics::size_of::<T>()
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
note: ...which requires computing layout of `Foo`...
|
note: ...which requires computing layout of `Foo`...
|
||||||
note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All }, value: [u8; _] }`...
|
note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
|
||||||
note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}`...
|
note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}`...
|
||||||
--> $DIR/const-size_of-cycle.rs:6:17
|
--> $DIR/const-size_of-cycle.rs:6:17
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ note: ...which requires const-evaluating `Foo::bytes::{{constant}}`...
|
||||||
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
note: ...which requires computing layout of `Foo`...
|
note: ...which requires computing layout of `Foo`...
|
||||||
note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All }, value: [u8; _] }`...
|
note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
|
||||||
note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}`...
|
note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}`...
|
||||||
--> $DIR/issue-44415.rs:6:17
|
--> $DIR/issue-44415.rs:6:17
|
||||||
|
|
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue