Skip to content

Commit ba6314a

Browse files
committed
Integrate chalk engine
1 parent ea4187a commit ba6314a

File tree

17 files changed

+412
-75
lines changed

17 files changed

+412
-75
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ define_dep_nodes!( <'tcx>
648648
[] ImpliedOutlivesBounds(CanonicalTyGoal<'tcx>),
649649
[] DropckOutlives(CanonicalTyGoal<'tcx>),
650650
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
651+
[] EvaluateGoal(traits::ChalkCanonicalGoal<'tcx>),
651652
[] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>),
652653
[] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>),
653654
[] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>),

src/librustc/ich/impls_ty.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,3 +1240,10 @@ impl_stable_hash_for!(
12401240
clauses,
12411241
}
12421242
);
1243+
1244+
impl_stable_hash_for!(
1245+
impl<'tcx, G> for struct traits::InEnvironment<'tcx, G> {
1246+
environment,
1247+
goal,
1248+
}
1249+
);

src/librustc/infer/canonical/canonicalizer.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,9 +330,13 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
330330
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
331331
match t.sty {
332332
ty::Infer(ty::TyVar(vid)) => {
333+
debug!("canonical: type var found with vid {:?}", vid);
333334
match self.infcx.unwrap().probe_ty_var(vid) {
334335
// `t` could be a float / int variable: canonicalize that instead
335-
Ok(t) => self.fold_ty(t),
336+
Ok(t) => {
337+
debug!("(resolved to {:?})", t);
338+
self.fold_ty(t)
339+
}
336340

337341
// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
338342
// result
@@ -448,7 +452,12 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
448452

449453
// Fast path: nothing that needs to be canonicalized.
450454
if !value.has_type_flags(needs_canonical_flags) {
451-
let out_value = gcx.lift(value).unwrap();
455+
let out_value = gcx.lift(value).unwrap_or_else(|| {
456+
bug!(
457+
"failed to lift `{:?}` (nothing to canonicalize)",
458+
value
459+
)
460+
});
452461
let canon_value = Canonical {
453462
max_universe: ty::UniverseIndex::ROOT,
454463
variables: List::empty(),

src/librustc/infer/canonical/mod.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,33 @@ BraceStructLiftImpl! {
420420
}
421421

422422
impl<'tcx> CanonicalVarValues<'tcx> {
423-
fn len(&self) -> usize {
423+
pub fn len(&self) -> usize {
424424
self.var_values.len()
425425
}
426+
427+
/// Make an identity substitution from this one: each bound var
428+
/// is matched to the same bound var, preserving the original kinds.
429+
/// For example, if we have:
430+
/// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
431+
/// we'll return a substitution `subst` with:
432+
/// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
433+
pub fn make_identity<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
434+
use ty::subst::UnpackedKind;
435+
436+
CanonicalVarValues {
437+
var_values: self.var_values.iter()
438+
.zip(0..)
439+
.map(|(kind, i)| match kind.unpack() {
440+
UnpackedKind::Type(..) => tcx.mk_ty(
441+
ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())
442+
).into(),
443+
UnpackedKind::Lifetime(..) => tcx.mk_region(
444+
ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))
445+
).into(),
446+
})
447+
.collect()
448+
}
449+
}
426450
}
427451

428452
impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {

src/librustc/traits/chalk_fulfill.rs

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
use traits::{
2+
Environment,
3+
InEnvironment,
4+
TraitEngine,
5+
ObligationCause,
6+
PredicateObligation,
7+
FulfillmentError,
8+
FulfillmentErrorCode,
9+
SelectionError,
10+
};
11+
use traits::query::NoSolution;
12+
use infer::InferCtxt;
13+
use infer::canonical::{Canonical, OriginalQueryValues};
14+
use ty::{self, Ty};
15+
use rustc_data_structures::fx::FxHashSet;
16+
17+
pub type CanonicalGoal<'tcx> = Canonical<'tcx, InEnvironment<'tcx, ty::Predicate<'tcx>>>;
18+
19+
pub struct FulfillmentContext<'tcx> {
20+
obligations: FxHashSet<InEnvironment<'tcx, PredicateObligation<'tcx>>>,
21+
}
22+
23+
impl FulfillmentContext<'tcx> {
24+
crate fn new() -> Self {
25+
FulfillmentContext {
26+
obligations: FxHashSet::default(),
27+
}
28+
}
29+
}
30+
31+
fn in_environment(
32+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
33+
obligation: PredicateObligation<'tcx>
34+
) -> InEnvironment<'tcx, PredicateObligation<'tcx>> {
35+
assert!(!infcx.is_in_snapshot());
36+
let obligation = infcx.resolve_type_vars_if_possible(&obligation);
37+
38+
let environment = match obligation.param_env.def_id {
39+
Some(def_id) => infcx.tcx.environment(def_id),
40+
None if obligation.param_env.caller_bounds.is_empty() => Environment {
41+
clauses: ty::List::empty(),
42+
},
43+
_ => bug!("non-empty `ParamEnv` with no def-id"),
44+
};
45+
46+
InEnvironment {
47+
environment,
48+
goal: obligation,
49+
}
50+
}
51+
52+
impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
53+
fn normalize_projection_type(
54+
&mut self,
55+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
56+
_param_env: ty::ParamEnv<'tcx>,
57+
projection_ty: ty::ProjectionTy<'tcx>,
58+
_cause: ObligationCause<'tcx>,
59+
) -> Ty<'tcx> {
60+
infcx.tcx.mk_ty(ty::Projection(projection_ty))
61+
}
62+
63+
fn register_predicate_obligation(
64+
&mut self,
65+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
66+
obligation: PredicateObligation<'tcx>,
67+
) {
68+
self.obligations.insert(in_environment(infcx, obligation));
69+
}
70+
71+
fn select_all_or_error(
72+
&mut self,
73+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
74+
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
75+
self.select_where_possible(infcx)?;
76+
77+
if self.obligations.is_empty() {
78+
Ok(())
79+
} else {
80+
let errors = self.obligations.iter()
81+
.map(|obligation| FulfillmentError {
82+
obligation: obligation.goal.clone(),
83+
code: FulfillmentErrorCode::CodeAmbiguity,
84+
})
85+
.collect();
86+
Err(errors)
87+
}
88+
}
89+
90+
fn select_where_possible(
91+
&mut self,
92+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
93+
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
94+
let mut errors = Vec::new();
95+
let mut next_round = FxHashSet::default();
96+
let mut making_progress;
97+
98+
loop {
99+
making_progress = false;
100+
101+
// We iterate over all obligations, and record if we are able
102+
// to unambiguously prove at least one obligation.
103+
for obligation in self.obligations.drain() {
104+
let mut orig_values = OriginalQueryValues::default();
105+
let canonical_goal = infcx.canonicalize_query(&InEnvironment {
106+
environment: obligation.environment,
107+
goal: obligation.goal.predicate,
108+
}, &mut orig_values);
109+
110+
match infcx.tcx.global_tcx().evaluate_goal(canonical_goal) {
111+
Ok(response) => {
112+
if response.is_proven() {
113+
making_progress = true;
114+
115+
match infcx.instantiate_query_response_and_region_obligations(
116+
&obligation.goal.cause,
117+
obligation.goal.param_env,
118+
&orig_values,
119+
&response
120+
) {
121+
Ok(infer_ok) => next_round.extend(
122+
infer_ok.obligations
123+
.into_iter()
124+
.map(|obligation| in_environment(infcx, obligation))
125+
),
126+
127+
Err(_err) => errors.push(FulfillmentError {
128+
obligation: obligation.goal,
129+
code: FulfillmentErrorCode::CodeSelectionError(
130+
SelectionError::Unimplemented
131+
),
132+
}),
133+
}
134+
} else {
135+
// Ambiguous: retry at next round.
136+
next_round.insert(obligation);
137+
}
138+
}
139+
140+
Err(NoSolution) => errors.push(FulfillmentError {
141+
obligation: obligation.goal,
142+
code: FulfillmentErrorCode::CodeSelectionError(
143+
SelectionError::Unimplemented
144+
),
145+
})
146+
}
147+
}
148+
next_round = std::mem::replace(&mut self.obligations, next_round);
149+
150+
if !making_progress {
151+
break;
152+
}
153+
}
154+
155+
if errors.is_empty() {
156+
Ok(())
157+
} else {
158+
Err(errors)
159+
}
160+
}
161+
162+
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
163+
self.obligations.iter().map(|obligation| obligation.goal.clone()).collect()
164+
}
165+
}

src/librustc/traits/engine.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use infer::InferCtxt;
2-
use ty::{self, Ty, TyCtxt};
2+
use ty::{self, Ty, TyCtxt, ToPredicate};
3+
use traits::Obligation;
34
use hir::def_id::DefId;
45

5-
use super::{FulfillmentContext, FulfillmentError};
6+
use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError};
67
use super::{ObligationCause, PredicateObligation};
78

89
pub trait TraitEngine<'tcx>: 'tcx {
@@ -14,14 +15,28 @@ pub trait TraitEngine<'tcx>: 'tcx {
1415
cause: ObligationCause<'tcx>,
1516
) -> Ty<'tcx>;
1617

18+
/// Requires that `ty` must implement the trait with `def_id` in
19+
/// the given environment. This trait must not have any type
20+
/// parameters (except for `Self`).
1721
fn register_bound(
1822
&mut self,
1923
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
2024
param_env: ty::ParamEnv<'tcx>,
2125
ty: Ty<'tcx>,
2226
def_id: DefId,
2327
cause: ObligationCause<'tcx>,
24-
);
28+
) {
29+
let trait_ref = ty::TraitRef {
30+
def_id,
31+
substs: infcx.tcx.mk_substs_trait(ty, &[]),
32+
};
33+
self.register_predicate_obligation(infcx, Obligation {
34+
cause,
35+
recursion_depth: 0,
36+
param_env,
37+
predicate: trait_ref.to_predicate()
38+
});
39+
}
2540

2641
fn register_predicate_obligation(
2742
&mut self,
@@ -63,7 +78,11 @@ impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
6378
}
6479

6580
impl dyn TraitEngine<'tcx> {
66-
pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
67-
Box::new(FulfillmentContext::new())
81+
pub fn new(tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
82+
if tcx.sess.opts.debugging_opts.chalk {
83+
Box::new(ChalkFulfillmentContext::new())
84+
} else {
85+
Box::new(FulfillmentContext::new())
86+
}
6887
}
6988
}

src/librustc/traits/error_reporting.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -796,12 +796,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
796796
}
797797

798798
ty::Predicate::WellFormed(ty) => {
799-
// WF predicates cannot themselves make
800-
// errors. They can only block due to
801-
// ambiguity; otherwise, they always
802-
// degenerate into other obligations
803-
// (which may fail).
804-
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
799+
if !self.tcx.sess.opts.debugging_opts.chalk {
800+
// WF predicates cannot themselves make
801+
// errors. They can only block due to
802+
// ambiguity; otherwise, they always
803+
// degenerate into other obligations
804+
// (which may fail).
805+
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
806+
} else {
807+
// FIXME: we'll need a better message which takes into account
808+
// which bounds actually failed to hold.
809+
self.tcx.sess.struct_span_err(
810+
span,
811+
&format!("the type `{}` is not well-formed (chalk)", ty)
812+
)
813+
}
805814
}
806815

807816
ty::Predicate::ConstEvaluatable(..) => {

src/librustc/traits/fulfill.rs

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
use infer::InferCtxt;
22
use mir::interpret::{GlobalId, ErrorHandled};
3-
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
3+
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef};
44
use ty::error::ExpectedFound;
55
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
66
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
77
use rustc_data_structures::obligation_forest::{ProcessResult};
88
use std::marker::PhantomData;
9-
use hir::def_id::DefId;
109

1110
use super::CodeAmbiguity;
1211
use super::CodeProjectionError;
1312
use super::CodeSelectionError;
1413
use super::engine::{TraitEngine, TraitEngineExt};
1514
use super::{FulfillmentError, FulfillmentErrorCode};
16-
use super::{ObligationCause, PredicateObligation, Obligation};
15+
use super::{ObligationCause, PredicateObligation};
1716
use super::project;
1817
use super::select::SelectionContext;
1918
use super::{Unimplemented, ConstEvalFailure};
@@ -173,28 +172,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
173172
normalized_ty
174173
}
175174

176-
/// Requires that `ty` must implement the trait with `def_id` in
177-
/// the given environment. This trait must not have any type
178-
/// parameters (except for `Self`).
179-
fn register_bound<'a, 'gcx>(&mut self,
180-
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
181-
param_env: ty::ParamEnv<'tcx>,
182-
ty: Ty<'tcx>,
183-
def_id: DefId,
184-
cause: ObligationCause<'tcx>)
185-
{
186-
let trait_ref = ty::TraitRef {
187-
def_id,
188-
substs: infcx.tcx.mk_substs_trait(ty, &[]),
189-
};
190-
self.register_predicate_obligation(infcx, Obligation {
191-
cause,
192-
recursion_depth: 0,
193-
param_env,
194-
predicate: trait_ref.to_predicate()
195-
});
196-
}
197-
198175
fn register_predicate_obligation<'a, 'gcx>(&mut self,
199176
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
200177
obligation: PredicateObligation<'tcx>)
@@ -213,9 +190,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
213190
});
214191
}
215192

216-
fn select_all_or_error<'a, 'gcx>(&mut self,
217-
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
218-
-> Result<(),Vec<FulfillmentError<'tcx>>>
193+
fn select_all_or_error<'a, 'gcx>(
194+
&mut self,
195+
infcx: &InferCtxt<'a, 'gcx, 'tcx>
196+
) -> Result<(),Vec<FulfillmentError<'tcx>>>
219197
{
220198
self.select_where_possible(infcx)?;
221199

0 commit comments

Comments
 (0)