Skip to content

Commit 186da37

Browse files
authored
Merge pull request #226 from KiChjang/dyn-and-impl-trait
Add basic support for dyn and impl Trait
2 parents d33f297 + ee13458 commit 186da37

File tree

13 files changed

+212
-13
lines changed

13 files changed

+212
-13
lines changed

chalk-ir/src/debug.rs

+2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ impl Debug for Ty {
8585
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
8686
match self {
8787
Ty::BoundVar(depth) => write!(fmt, "^{}", depth),
88+
Ty::Dyn(clauses) => write!(fmt, "{:?}", clauses),
89+
Ty::Opaque(clauses) => write!(fmt, "{:?}", clauses),
8890
Ty::InferenceVar(var) => write!(fmt, "{:?}", var),
8991
Ty::Apply(apply) => write!(fmt, "{:?}", apply),
9092
Ty::Projection(proj) => write!(fmt, "{:?}", proj),

chalk-ir/src/fold.rs

+2
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ pub fn super_fold_ty(folder: &mut dyn Folder, ty: &Ty, binders: usize) -> Fallib
341341
Ok(Ty::BoundVar(depth))
342342
}
343343
}
344+
Ty::Dyn(ref clauses) => Ok(Ty::Dyn(clauses.fold_with(folder, binders)?)),
345+
Ty::Opaque(ref clauses) => Ok(Ty::Opaque(clauses.fold_with(folder, binders)?)),
344346
Ty::InferenceVar(var) => folder.fold_inference_ty(var, binders),
345347
Ty::Apply(ref apply) => {
346348
let ApplicationTy {

chalk-ir/src/lib.rs

+50-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ macro_rules! impl_debugs {
2525
use crate::cast::Cast;
2626
use crate::fold::shift::Shift;
2727
use crate::fold::{
28-
DefaultInferenceFolder, DefaultPlaceholderFolder, DefaultTypeFolder, Fold, FreeVarFolder,
28+
DefaultInferenceFolder, DefaultPlaceholderFolder, DefaultTypeFolder, Fold, FreeVarFolder, Subst,
2929
};
3030
use chalk_engine::fallible::*;
3131
use lalrpop_intern::InternedString;
@@ -235,6 +235,41 @@ pub enum Ty {
235235
/// an empty list).
236236
Apply(ApplicationTy),
237237

238+
/// A "dyn" type is a trait object type created via the "dyn Trait" syntax.
239+
/// In the chalk parser, the traits that the object represents is parsed as
240+
/// a QuantifiedInlineBound, and is then changed to a list of where clauses
241+
/// during lowering.
242+
///
243+
/// See the `Opaque` variant for a discussion about the use of
244+
/// binders here.
245+
Dyn(Binders<Vec<QuantifiedWhereClause>>),
246+
247+
/// An "opaque" type is one that is created via the "impl Trait" syntax.
248+
/// They are named so because the concrete type implementing the trait
249+
/// is unknown, and hence the type is opaque to us. The only information
250+
/// that we know of is that this type implements the traits listed by the
251+
/// user.
252+
///
253+
/// The "binder" here represents the unknown self type. So, a type like
254+
/// `impl for<'a> Fn(&'a u32)` would be represented with two-levels of
255+
/// binder, as "depicted" here:
256+
///
257+
/// ```notrust
258+
/// exists<type> {
259+
/// vec![
260+
/// // A QuantifiedWhereClause:
261+
/// forall<region> { ^1: Fn(&^0 u32) }
262+
/// ]
263+
/// }
264+
/// ```
265+
///
266+
/// The outer `exists<type>` binder indicates that there exists
267+
/// some type that meets the criteria within, but that type is not
268+
/// known. It is referenced within the type using `^1`, indicating
269+
/// a bound type with debruijn index 1 (i.e., skipping through one
270+
/// level of binder).
271+
Opaque(Binders<Vec<QuantifiedWhereClause>>),
272+
238273
/// A "projection" type corresponds to an (unnormalized)
239274
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
240275
/// trait and all its parameters are fully known.
@@ -788,6 +823,20 @@ impl<T> Binders<T> {
788823
}
789824
}
790825

826+
impl<T> Binders<T>
827+
where
828+
T: Fold,
829+
{
830+
/// Substitute `parameters` for the variables introduced by these
831+
/// binders. So if the binders represent (e.g.) `<X, Y> { T }` and
832+
/// parameters is the slice `[A, B]`, then returns `[X => A, Y =>
833+
/// B] T`.
834+
pub fn substitute(&self, parameters: &[Parameter]) -> T::Result {
835+
assert_eq!(self.binders.len(), parameters.len());
836+
Subst::apply(parameters, &self.value)
837+
}
838+
}
839+
791840
/// Allows iterating over a Binders<Vec<T>>, for instance.
792841
/// Each element will include the same set of parameter bounds.
793842
impl<V: IntoIterator> IntoIterator for Binders<V> {

chalk-parse/src/ast.rs

+6
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ pub enum Ty {
154154
Id {
155155
name: Identifier,
156156
},
157+
Dyn {
158+
bounds: Vec<QuantifiedInlineBound>,
159+
},
160+
Opaque {
161+
bounds: Vec<QuantifiedInlineBound>,
162+
},
157163
Apply {
158164
name: Identifier,
159165
args: Vec<Parameter>,

chalk-parse/src/parser.lalrpop

+6
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ pub Ty: Ty = {
172172

173173
TyWithoutFor: Ty = {
174174
<n:Id> => Ty::Id { name: n},
175+
"dyn" <b:Plus<QuantifiedInlineBound>> => Ty::Dyn {
176+
bounds: b,
177+
},
178+
"impl" <b:Plus<QuantifiedInlineBound>> => Ty::Opaque {
179+
bounds: b,
180+
},
175181
<n:Id> "<" <a:Comma<Parameter>> ">" => Ty::Apply { name: n, args: a },
176182
<p:ProjectionTy> => Ty::Projection { proj: p },
177183
"(" <Ty> ")",

chalk-solve/src/clauses.rs

+34-2
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,28 @@ fn program_clauses_that_could_match(
167167
}
168168
}
169169

170+
// If the self type is `dyn Foo` (or `impl Foo`), then we generate clauses like:
171+
//
172+
// ```notrust
173+
// Implemented(dyn Foo: Foo)
174+
// ```
175+
//
176+
// FIXME. This is presently rather wasteful, in that we
177+
// don't check that the `dyn Foo: Foo` trait is relevant
178+
// to the goal `goal` that we are actually *trying* to
179+
// prove (though there is some later code that will screen
180+
// out irrelevant stuff). In other words, we might be
181+
// trying to prove `dyn Foo: Bar`, in which case the clause
182+
// for `dyn Foo: Foo` is not particularly relevant.
183+
match trait_ref.self_type_parameter() {
184+
Some(Ty::Opaque(qwc)) | Some(Ty::Dyn(qwc)) => {
185+
let self_ty = trait_ref.self_type_parameter().unwrap(); // This cannot be None
186+
let wc = qwc.substitute(&[self_ty.cast()]);
187+
clauses.extend(wc.into_iter().casted());
188+
}
189+
_ => {}
190+
}
191+
170192
// TODO sized, unsize_trait, builtin impls?
171193
}
172194
DomainGoal::Holds(WhereClause::ProjectionEq(projection_predicate)) => {
@@ -246,8 +268,17 @@ fn push_program_clauses_for_associated_type_values_in_impls_of(
246268
}
247269
}
248270

249-
/// Given the "self-type" of a domain goal, push potentially relevant program
250-
/// clauses.
271+
/// Examine `T` and push clauses that may be relevant to proving the
272+
/// following sorts of goals (and maybe others):
273+
///
274+
/// * `DomainGoal::WellFormed(T)`
275+
/// * `DomainGoal::IsUpstream(T)`
276+
/// * `DomainGoal::DownstreamType(T)`
277+
/// * `DomainGoal::IsFullyVisible(T)`
278+
/// * `DomainGoal::IsLocal(T)`
279+
///
280+
/// Note that the type `T` must not be an unbound inference variable;
281+
/// earlier parts of the logic should "flounder" in that case.
251282
fn match_ty(
252283
db: &dyn RustIrDatabase,
253284
environment: &Arc<Environment>,
@@ -268,6 +299,7 @@ fn match_ty(
268299
Ty::ForAll(quantified_ty) => match_ty(db, environment, &quantified_ty.ty, clauses),
269300
Ty::BoundVar(_) => {}
270301
Ty::InferenceVar(_) => panic!("should have floundered"),
302+
Ty::Dyn(_) | Ty::Opaque(_) => {}
271303
}
272304
}
273305

chalk-solve/src/clauses/env_elaborator.rs

+5
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ impl<'db, 'set> EnvElaborator<'db, 'set> {
6161
Ty::Projection(projection_ty) => {
6262
self.visit_projection_ty(projection_ty);
6363
}
64+
65+
// FIXME(#203) -- We haven't fully figured out the implied
66+
// bounds story around object and impl trait types.
67+
Ty::Dyn(_) | Ty::Opaque(_) => (),
68+
6469
Ty::ForAll(_) | Ty::BoundVar(_) | Ty::InferenceVar(_) => (),
6570
}
6671
self.round.extend(clauses);

chalk-solve/src/infer/unify.rs

+59-5
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ impl<'t> Unifier<'t> {
105105
);
106106

107107
match (a, b) {
108+
// Unifying two inference variables: unify them in the underlying
109+
// ena table.
108110
(&Ty::InferenceVar(var1), &Ty::InferenceVar(var2)) => {
109111
debug!("unify_ty_ty: unify_var_var({:?}, {:?})", var1, var2);
110112
let var1 = EnaVariable::from(var1);
@@ -116,35 +118,71 @@ impl<'t> Unifier<'t> {
116118
.expect("unification of two unbound variables cannot fail"))
117119
}
118120

121+
// Unifying an inference variables with a non-inference variable.
119122
(&Ty::InferenceVar(var), ty @ &Ty::Apply(_))
120123
| (ty @ &Ty::Apply(_), &Ty::InferenceVar(var))
124+
| (&Ty::InferenceVar(var), ty @ &Ty::Opaque(_))
125+
| (ty @ Ty::Opaque(_), &Ty::InferenceVar(var))
126+
| (&Ty::InferenceVar(var), ty @ &Ty::Dyn(_))
127+
| (ty @ &Ty::Dyn(_), &Ty::InferenceVar(var))
121128
| (&Ty::InferenceVar(var), ty @ &Ty::ForAll(_))
122129
| (ty @ &Ty::ForAll(_), &Ty::InferenceVar(var)) => self.unify_var_ty(var, ty),
123130

131+
// Unifying `forall<X> { T }` with some other forall type `forall<X> { U }`
124132
(&Ty::ForAll(ref quantified_ty1), &Ty::ForAll(ref quantified_ty2)) => {
125133
self.unify_forall_tys(quantified_ty1, quantified_ty2)
126134
}
127135

128-
(&Ty::ForAll(ref quantified_ty), apply_ty @ &Ty::Apply(_))
129-
| (apply_ty @ &Ty::Apply(_), &Ty::ForAll(ref quantified_ty)) => {
130-
self.unify_forall_apply(quantified_ty, apply_ty)
136+
// Unifying `forall<X> { T }` with some other type `U`
137+
(&Ty::ForAll(ref quantified_ty), other_ty @ &Ty::Apply(_))
138+
| (&Ty::ForAll(ref quantified_ty), other_ty @ &Ty::Dyn(_))
139+
| (&Ty::ForAll(ref quantified_ty), other_ty @ &Ty::Opaque(_))
140+
| (other_ty @ &Ty::Apply(_), &Ty::ForAll(ref quantified_ty))
141+
| (other_ty @ &Ty::Dyn(_), &Ty::ForAll(ref quantified_ty))
142+
| (other_ty @ &Ty::Opaque(_), &Ty::ForAll(ref quantified_ty)) => {
143+
self.unify_forall_other(quantified_ty, other_ty)
131144
}
132145

133146
(&Ty::Apply(ref apply1), &Ty::Apply(ref apply2)) => {
147+
// Cannot unify (e.g.) some struct type `Foo` and some struct type `Bar`
134148
if apply1.name != apply2.name {
135149
return Err(NoSolution);
136150
}
137151

138152
Zip::zip_with(self, &apply1.parameters, &apply2.parameters)
139153
}
140154

155+
// Cannot unify (e.g.) some struct type `Foo` and an `impl Trait` type
156+
(&Ty::Apply(_), &Ty::Opaque(_)) | (&Ty::Opaque(_), &Ty::Apply(_)) => {
157+
return Err(NoSolution);
158+
}
159+
160+
// Cannot unify (e.g.) some struct type `Foo` and a `dyn Trait` type
161+
(&Ty::Apply(_), &Ty::Dyn(_)) | (&Ty::Dyn(_), &Ty::Apply(_)) => {
162+
return Err(NoSolution);
163+
}
164+
165+
// Cannot unify (e.g.) some `dyn Trait` and some `impl Trait` type
166+
(&Ty::Dyn(..), &Ty::Opaque(..)) | (&Ty::Opaque(..), &Ty::Dyn(..)) => {
167+
return Err(NoSolution);
168+
}
169+
170+
(&Ty::Opaque(ref qwc1), &Ty::Opaque(ref qwc2))
171+
| (&Ty::Dyn(ref qwc1), &Ty::Dyn(ref qwc2)) => Zip::zip_with(self, qwc1, qwc2),
172+
173+
// Unifying an associated type projection `<T as
174+
// Trait>::Item` with some other type `U`.
141175
(ty @ &Ty::Apply(_), &Ty::Projection(ref proj))
142176
| (ty @ &Ty::ForAll(_), &Ty::Projection(ref proj))
143177
| (ty @ &Ty::InferenceVar(_), &Ty::Projection(ref proj))
178+
| (ty @ &Ty::Dyn(_), &Ty::Projection(ref proj))
179+
| (ty @ &Ty::Opaque(_), &Ty::Projection(ref proj))
144180
| (&Ty::Projection(ref proj), ty @ &Ty::Projection(_))
145181
| (&Ty::Projection(ref proj), ty @ &Ty::Apply(_))
146182
| (&Ty::Projection(ref proj), ty @ &Ty::ForAll(_))
147-
| (&Ty::Projection(ref proj), ty @ &Ty::InferenceVar(_)) => {
183+
| (&Ty::Projection(ref proj), ty @ &Ty::InferenceVar(_))
184+
| (&Ty::Projection(ref proj), ty @ &Ty::Dyn(_))
185+
| (&Ty::Projection(ref proj), ty @ &Ty::Opaque(_)) => {
148186
self.unify_projection_ty(proj, ty)
149187
}
150188

@@ -186,6 +224,12 @@ impl<'t> Unifier<'t> {
186224
self.sub_unify(ty1, ty2)
187225
}
188226

227+
/// Unify an associated type projection `proj` like `<T as Trait>::Item` with some other
228+
/// type `ty` (which might also be a projection). Creates a goal like
229+
///
230+
/// ```notrust
231+
/// ProjectionEq(<T as Trait>::Item = U)
232+
/// ```
189233
fn unify_projection_ty(&mut self, proj: &ProjectionTy, ty: &Ty) -> Fallible<()> {
190234
Ok(self.goals.push(InEnvironment::new(
191235
self.environment,
@@ -197,7 +241,11 @@ impl<'t> Unifier<'t> {
197241
)))
198242
}
199243

200-
fn unify_forall_apply(&mut self, ty1: &QuantifiedTy, ty2: &Ty) -> Fallible<()> {
244+
/// Unifying `forall<X> { T }` with some other type `U` --
245+
/// to do so, we create a fresh placeholder `P` for `X` and
246+
/// see if `[X/Px] T` can be unified with `U`. This should
247+
/// almost never be true, actually, unless `X` is unused.
248+
fn unify_forall_other(&mut self, ty1: &QuantifiedTy, ty2: &Ty) -> Fallible<()> {
201249
let ui = self.table.new_universe();
202250
let lifetimes1: Vec<_> = (0..ty1.num_binders)
203251
.map(|idx| Lifetime::Placeholder(PlaceholderIndex { ui, idx }).cast())
@@ -209,6 +257,12 @@ impl<'t> Unifier<'t> {
209257
self.sub_unify(ty1, ty2)
210258
}
211259

260+
/// Unify an inference variable `var` with some non-inference
261+
/// variable `ty`, just bind `var` to `ty`. But we must enforce two conditions:
262+
///
263+
/// - `var` does not appear inside of `ty` (the standard `OccursCheck`)
264+
/// - `ty` does not reference anything in a lifetime that could not be named in `var`
265+
/// (the extended `OccursCheck` created to handle universes)
212266
fn unify_var_ty(&mut self, var: InferenceVar, ty: &Ty) -> Fallible<()> {
213267
debug!("unify_var_ty(var={:?}, ty={:?})", var, ty);
214268

chalk-solve/src/solve/slg.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,11 @@ impl MayInvalidate {
447447
}
448448

449449
// For everything else, be conservative here and just say we may invalidate.
450-
(Ty::ForAll(_), _) | (Ty::Apply(_), _) | (Ty::Projection(_), _) => true,
450+
(Ty::ForAll(_), _)
451+
| (Ty::Dyn(_), _)
452+
| (Ty::Opaque(_), _)
453+
| (Ty::Apply(_), _)
454+
| (Ty::Projection(_), _) => true,
451455
}
452456
}
453457

chalk-solve/src/solve/slg/aggregate.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,12 @@ impl<'infer> AntiUnifier<'infer> {
178178

179179
// Ugh. Aggregating two types like `for<'a> fn(&'a u32,
180180
// &'a u32)` and `for<'a, 'b> fn(&'a u32, &'b u32)` seems
181-
// kinda' hard. Don't try to be smart for now, just plop a
181+
// kinda hard. Don't try to be smart for now, just plop a
182182
// variable in there and be done with it.
183-
(Ty::BoundVar(_), Ty::BoundVar(_)) | (Ty::ForAll(_), Ty::ForAll(_)) => {
184-
self.new_variable()
185-
}
183+
(Ty::BoundVar(_), Ty::BoundVar(_))
184+
| (Ty::ForAll(_), Ty::ForAll(_))
185+
| (Ty::Dyn(_), Ty::Dyn(_))
186+
| (Ty::Opaque(_), Ty::Opaque(_)) => self.new_variable(),
186187

187188
(Ty::Apply(apply1), Ty::Apply(apply2)) => {
188189
self.aggregate_application_tys(apply1, apply2)
@@ -195,6 +196,8 @@ impl<'infer> AntiUnifier<'infer> {
195196
// Mismatched base kinds.
196197
(Ty::InferenceVar(_), _)
197198
| (Ty::BoundVar(_), _)
199+
| (Ty::Dyn(_), _)
200+
| (Ty::Opaque(_), _)
198201
| (Ty::ForAll(_), _)
199202
| (Ty::Apply(_), _)
200203
| (Ty::Projection(_), _) => self.new_variable(),

chalk-solve/src/solve/slg/resolvent.rs

+6
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,10 @@ impl<'t> Zipper for AnswerSubstitutor<'t> {
346346

347347
(Ty::Apply(answer), Ty::Apply(pending)) => Zip::zip_with(self, answer, pending),
348348

349+
(Ty::Dyn(answer), Ty::Dyn(pending)) | (Ty::Opaque(answer), Ty::Opaque(pending)) => {
350+
Zip::zip_with(self, answer, pending)
351+
}
352+
349353
(Ty::Projection(answer), Ty::Projection(pending)) => {
350354
Zip::zip_with(self, answer, pending)
351355
}
@@ -366,6 +370,8 @@ impl<'t> Zipper for AnswerSubstitutor<'t> {
366370

367371
(Ty::BoundVar(_), _)
368372
| (Ty::Apply(_), _)
373+
| (Ty::Dyn(_), _)
374+
| (Ty::Opaque(_), _)
369375
| (Ty::Projection(_), _)
370376
| (Ty::ForAll(_), _) => panic!(
371377
"structural mismatch between answer `{:?}` and pending goal `{:?}`",

chalk-solve/src/wf.rs

+4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ impl FoldInputTypes for Ty {
6868
accumulator.push(self.clone());
6969
app.parameters.fold(accumulator);
7070
}
71+
Ty::Dyn(qwc) | Ty::Opaque(qwc) => {
72+
accumulator.push(self.clone());
73+
qwc.fold(accumulator);
74+
}
7175
Ty::Projection(proj) => {
7276
accumulator.push(self.clone());
7377
proj.parameters.fold(accumulator);

0 commit comments

Comments
 (0)