Skip to content

Commit 38856d0

Browse files
authored
Merge pull request #134 from tmandry/GAT-step3
Finish implementing GATs
2 parents 7b21259 + 4061896 commit 38856d0

File tree

11 files changed

+1074
-189
lines changed

11 files changed

+1074
-189
lines changed

chalk-parse/src/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ pub struct TraitBound {
8787
pub struct ProjectionEqBound {
8888
pub trait_bound: TraitBound,
8989
pub name: Identifier,
90-
pub parameters: Vec<Parameter>,
90+
pub args: Vec<Parameter>,
9191
pub value: Ty,
9292
}
9393

chalk-parse/src/parser.lalrpop

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ ProjectionEqBound: ProjectionEqBound = {
109109
args_no_self: a.unwrap_or(vec![]),
110110
},
111111
name,
112-
parameters: a2,
112+
args: a2,
113113
value: ty,
114114
}
115115
};

src/fold.rs

+13
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ enum_fold!(Constraint[] { LifetimeEq(a, b) });
431431
enum_fold!(Goal[] { Quantified(qkind, subgoal), Implies(wc, subgoal), And(g1, g2), Not(g),
432432
Leaf(wc), CannotProve(a) });
433433
enum_fold!(ProgramClause[] { Implies(a), ForAll(a) });
434+
enum_fold!(InlineBound[] { TraitBound(a), ProjectionEqBound(a) });
434435

435436
macro_rules! struct_fold {
436437
($s:ident $([$($tt_args:tt)*])? { $($name:ident),* $(,)* } $($w:tt)*) => {
@@ -582,4 +583,16 @@ struct_fold!(ConstrainedSubst {
582583
constraints,
583584
});
584585

586+
struct_fold!(TraitBound {
587+
trait_id,
588+
args_no_self,
589+
});
590+
591+
struct_fold!(ProjectionEqBound {
592+
trait_bound,
593+
associated_ty_id,
594+
parameters,
595+
value,
596+
});
597+
585598
// struct_fold!(ApplicationTy { name, parameters }); -- intentionally omitted, folded through Ty

src/ir.rs

+105-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use fold::shift::Shift;
55
use lalrpop_intern::InternedString;
66
use std::collections::{BTreeMap, BTreeSet};
77
use std::sync::Arc;
8+
use std::iter;
89

910
#[macro_use]
1011
mod macros;
@@ -259,6 +260,80 @@ pub struct TraitFlags {
259260
pub deref: bool,
260261
}
261262

263+
/// An inline bound, e.g. `: Foo<K>` in `impl<K, T: Foo<K>> SomeType<T>`.
264+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
265+
pub enum InlineBound {
266+
TraitBound(TraitBound),
267+
ProjectionEqBound(ProjectionEqBound),
268+
}
269+
270+
impl InlineBound {
271+
/// Applies the `InlineBound` to `self_ty` and lowers to a [`DomainGoal`].
272+
///
273+
/// Because an `InlineBound` does not know anything about what it's binding,
274+
/// you must provide that type as `self_ty`.
275+
crate fn lower_with_self(&self, self_ty: Ty) -> Vec<DomainGoal> {
276+
match self {
277+
InlineBound::TraitBound(b) => b.lower_with_self(self_ty),
278+
InlineBound::ProjectionEqBound(b) => b.lower_with_self(self_ty),
279+
}
280+
}
281+
}
282+
283+
/// Represents a trait bound on e.g. a type or type parameter.
284+
/// Does not know anything about what it's binding.
285+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
286+
pub struct TraitBound {
287+
crate trait_id: ItemId,
288+
crate args_no_self: Vec<Parameter>,
289+
}
290+
291+
impl TraitBound {
292+
crate fn lower_with_self(&self, self_ty: Ty) -> Vec<DomainGoal> {
293+
let trait_ref = self.as_trait_ref(self_ty);
294+
vec![DomainGoal::Holds(WhereClauseAtom::Implemented(trait_ref))]
295+
}
296+
297+
fn as_trait_ref(&self, self_ty: Ty) -> TraitRef {
298+
let self_ty = ParameterKind::Ty(self_ty);
299+
TraitRef {
300+
trait_id: self.trait_id,
301+
parameters: iter::once(self_ty).chain(self.args_no_self.iter().cloned()).collect(),
302+
}
303+
}
304+
}
305+
306+
/// Represents a projection equality bound on e.g. a type or type parameter.
307+
/// Does not know anything about what it's binding.
308+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
309+
pub struct ProjectionEqBound {
310+
crate trait_bound: TraitBound,
311+
crate associated_ty_id: ItemId,
312+
/// Does not include trait parameters.
313+
crate parameters: Vec<Parameter>,
314+
crate value: Ty,
315+
}
316+
317+
impl ProjectionEqBound {
318+
crate fn lower_with_self(&self, self_ty: Ty) -> Vec<DomainGoal> {
319+
let trait_ref = self.trait_bound.as_trait_ref(self_ty);
320+
321+
let mut parameters = self.parameters.clone();
322+
parameters.extend(trait_ref.parameters.clone());
323+
324+
vec![
325+
DomainGoal::Holds(WhereClauseAtom::Implemented(trait_ref)),
326+
DomainGoal::Holds(WhereClauseAtom::ProjectionEq(ProjectionEq {
327+
projection: ProjectionTy {
328+
associated_ty_id: self.associated_ty_id,
329+
parameters: parameters,
330+
},
331+
ty: self.value.clone(),
332+
}))
333+
]
334+
}
335+
}
336+
262337
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
263338
pub struct AssociatedTyDatum {
264339
/// The trait this associated type is defined in.
@@ -274,12 +349,37 @@ pub struct AssociatedTyDatum {
274349
/// but possibly including more.
275350
crate parameter_kinds: Vec<ParameterKind<Identifier>>,
276351

277-
// FIXME: inline bounds on the associated ty need to be implemented
352+
/// Bounds on the associated type itself.
353+
///
354+
/// These must be proven by the implementer, for all possible parameters that
355+
/// would result in a well-formed projection.
356+
crate bounds: Vec<InlineBound>,
278357

279-
/// Where clauses that must hold for the projection be well-formed.
358+
/// Where clauses that must hold for the projection to be well-formed.
280359
crate where_clauses: Vec<QuantifiedDomainGoal>,
281360
}
282361

362+
impl AssociatedTyDatum {
363+
/// Returns the associated ty's bounds applied to the projection type, e.g.:
364+
///
365+
/// ```notrust
366+
/// Implemented(<?0 as Foo>::Item<?1>: Sized)
367+
/// ```
368+
crate fn bounds_on_self(&self) -> Vec<DomainGoal> {
369+
let parameters = self.parameter_kinds
370+
.anonymize()
371+
.iter()
372+
.zip(0..)
373+
.map(|p| p.to_parameter())
374+
.collect();
375+
let self_ty = Ty::Projection(ProjectionTy {
376+
associated_ty_id: self.id,
377+
parameters
378+
});
379+
self.bounds.iter().flat_map(|b| b.lower_with_self(self_ty.clone())).collect()
380+
}
381+
}
382+
283383
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
284384
pub struct AssociatedTyValue {
285385
crate associated_ty_id: ItemId,
@@ -612,7 +712,9 @@ impl DomainGoal {
612712
/// Same as `into_well_formed_goal` but with the `FromEnv` predicate instead of `WellFormed`.
613713
crate fn into_from_env_goal(self) -> DomainGoal {
614714
match self {
615-
DomainGoal::Holds(wca) => DomainGoal::FromEnv(wca),
715+
DomainGoal::Holds(wca @ WhereClauseAtom::Implemented(..)) => {
716+
DomainGoal::FromEnv(wca)
717+
}
616718
goal => goal,
617719
}
618720
}

src/ir/lowering.rs

+127-20
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ impl LowerProgram for Program {
191191
id: info.id,
192192
name: defn.name.str,
193193
parameter_kinds: parameter_kinds,
194+
bounds: defn.bounds.lower(&env)?,
194195
where_clauses: defn.where_clauses.lower(&env)?,
195196
},
196197
);
@@ -441,32 +442,37 @@ trait LowerWhereClause<T> {
441442
/// type in Rust and well-formedness checks.
442443
impl LowerWhereClause<ir::DomainGoal> for WhereClause {
443444
fn lower(&self, env: &Env) -> Result<Vec<ir::DomainGoal>> {
444-
let goal = match self {
445+
let goals = match self {
445446
WhereClause::Implemented { trait_ref } => {
446-
ir::DomainGoal::Holds(ir::WhereClauseAtom::Implemented(trait_ref.lower(env)?))
447+
vec![ir::DomainGoal::Holds(ir::WhereClauseAtom::Implemented(trait_ref.lower(env)?))]
447448
}
448449
WhereClause::ProjectionEq {
449450
projection,
450451
ty,
451-
} => ir::DomainGoal::Holds(ir::WhereClauseAtom::ProjectionEq(ir::ProjectionEq {
452-
projection: projection.lower(env)?,
453-
ty: ty.lower(env)?,
454-
})),
452+
} => vec![
453+
ir::DomainGoal::Holds(ir::WhereClauseAtom::ProjectionEq(ir::ProjectionEq {
454+
projection: projection.lower(env)?,
455+
ty: ty.lower(env)?,
456+
})),
457+
ir::DomainGoal::Holds(ir::WhereClauseAtom::Implemented(
458+
projection.trait_ref.lower(env)?
459+
)),
460+
],
455461
WhereClause::Normalize {
456462
projection,
457463
ty,
458-
} => ir::DomainGoal::Normalize(ir::Normalize {
464+
} => vec![ir::DomainGoal::Normalize(ir::Normalize {
459465
projection: projection.lower(env)?,
460466
ty: ty.lower(env)?,
461-
}),
462-
WhereClause::TyWellFormed { ty } => ir::DomainGoal::WellFormedTy(ty.lower(env)?),
463-
WhereClause::TraitRefWellFormed { trait_ref } => {
467+
})],
468+
WhereClause::TyWellFormed { ty } => vec![ir::DomainGoal::WellFormedTy(ty.lower(env)?)],
469+
WhereClause::TraitRefWellFormed { trait_ref } => vec![
464470
ir::DomainGoal::WellFormed(ir::WhereClauseAtom::Implemented(trait_ref.lower(env)?))
465-
}
466-
WhereClause::TyFromEnv { ty } => ir::DomainGoal::FromEnvTy(ty.lower(env)?),
467-
WhereClause::TraitRefFromEnv { trait_ref } => {
471+
],
472+
WhereClause::TyFromEnv { ty } => vec![ir::DomainGoal::FromEnvTy(ty.lower(env)?)],
473+
WhereClause::TraitRefFromEnv { trait_ref } => vec![
468474
ir::DomainGoal::FromEnv(ir::WhereClauseAtom::Implemented(trait_ref.lower(env)?))
469-
}
475+
],
470476
WhereClause::UnifyTys { .. } | WhereClause::UnifyLifetimes { .. } => {
471477
bail!("this form of where-clause not allowed here")
472478
}
@@ -480,19 +486,19 @@ impl LowerWhereClause<ir::DomainGoal> for WhereClause {
480486
bail!(ErrorKind::NotTrait(trait_name));
481487
}
482488

483-
ir::DomainGoal::InScope(id)
489+
vec![ir::DomainGoal::InScope(id)]
484490
}
485-
WhereClause::Derefs { source, target } => {
491+
WhereClause::Derefs { source, target } => vec![
486492
ir::DomainGoal::Derefs(ir::Derefs {
487493
source: source.lower(env)?,
488494
target: target.lower(env)?
489495
})
490-
}
491-
WhereClause::TyIsLocal { ty } => {
496+
],
497+
WhereClause::TyIsLocal { ty } => vec![
492498
ir::DomainGoal::IsLocalTy(ty.lower(env)?)
493-
}
499+
],
494500
};
495-
Ok(vec![goal])
501+
Ok(goals)
496502
}
497503
}
498504

@@ -638,6 +644,107 @@ impl LowerTraitRef for TraitRef {
638644
}
639645
}
640646

647+
trait LowerTraitBound {
648+
fn lower_trait_bound(&self, env: &Env) -> Result<ir::TraitBound>;
649+
}
650+
651+
impl LowerTraitBound for TraitBound {
652+
fn lower_trait_bound(&self, env: &Env) -> Result<ir::TraitBound> {
653+
let id = match env.lookup(self.trait_name)? {
654+
NameLookup::Type(id) => id,
655+
NameLookup::Parameter(_) => bail!(ErrorKind::NotTrait(self.trait_name)),
656+
};
657+
658+
let k = env.type_kind(id);
659+
if k.sort != ir::TypeSort::Trait {
660+
bail!(ErrorKind::NotTrait(self.trait_name));
661+
}
662+
663+
let parameters = self.args_no_self
664+
.iter()
665+
.map(|a| Ok(a.lower(env)?))
666+
.collect::<Result<Vec<_>>>()?;
667+
668+
if parameters.len() != k.binders.len() {
669+
bail!(
670+
"wrong number of parameters, expected `{:?}`, got `{:?}`",
671+
k.binders.len(),
672+
parameters.len()
673+
)
674+
}
675+
676+
for (binder, param) in k.binders.binders.iter().zip(parameters.iter()) {
677+
check_type_kinds("incorrect kind for trait parameter", binder, param)?;
678+
}
679+
680+
Ok(ir::TraitBound {
681+
trait_id: id,
682+
args_no_self: parameters,
683+
})
684+
}
685+
}
686+
687+
trait LowerInlineBound {
688+
fn lower(&self, env: &Env) -> Result<ir::InlineBound>;
689+
}
690+
691+
impl LowerInlineBound for TraitBound {
692+
fn lower(&self, env: &Env) -> Result<ir::InlineBound> {
693+
Ok(ir::InlineBound::TraitBound(self.lower_trait_bound(&env)?))
694+
}
695+
}
696+
697+
impl LowerInlineBound for ProjectionEqBound {
698+
fn lower(&self, env: &Env) -> Result<ir::InlineBound> {
699+
let trait_bound = self.trait_bound.lower_trait_bound(env)?;
700+
let info = match env.associated_ty_infos.get(&(trait_bound.trait_id, self.name.str)) {
701+
Some(info) => info,
702+
None => bail!("no associated type `{}` defined in trait", self.name.str),
703+
};
704+
let args: Vec<_> = try!(self.args.iter().map(|a| a.lower(env)).collect());
705+
706+
if args.len() != info.addl_parameter_kinds.len() {
707+
bail!(
708+
"wrong number of parameters for associated type (expected {}, got {})",
709+
info.addl_parameter_kinds.len(),
710+
args.len()
711+
)
712+
}
713+
714+
for (param, arg) in info.addl_parameter_kinds.iter().zip(args.iter()) {
715+
check_type_kinds("incorrect kind for associated type parameter", param, arg)?;
716+
}
717+
718+
Ok(ir::InlineBound::ProjectionEqBound(ir::ProjectionEqBound {
719+
trait_bound,
720+
associated_ty_id: info.id,
721+
parameters: args,
722+
value: self.value.lower(env)?,
723+
}))
724+
}
725+
}
726+
727+
impl LowerInlineBound for InlineBound {
728+
fn lower(&self, env: &Env) -> Result<ir::InlineBound> {
729+
match self {
730+
InlineBound::TraitBound(b) => b.lower(&env),
731+
InlineBound::ProjectionEqBound(b) => b.lower(&env),
732+
}
733+
}
734+
}
735+
736+
trait LowerInlineBounds {
737+
fn lower(&self, env: &Env) -> Result<Vec<ir::InlineBound>>;
738+
}
739+
740+
impl LowerInlineBounds for Vec<InlineBound> {
741+
fn lower(&self, env: &Env) -> Result<Vec<ir::InlineBound>> {
742+
self.iter()
743+
.map(|b| b.lower(env))
744+
.collect()
745+
}
746+
}
747+
641748
trait LowerPolarizedTraitRef {
642749
fn lower(&self, env: &Env) -> Result<ir::PolarizedTraitRef>;
643750
}

0 commit comments

Comments
 (0)