Skip to content

Opaque Type Generics #464

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions chalk-integration/src/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type OpaqueTyIds = BTreeMap<Ident, chalk_ir::OpaqueTyId<ChalkIr>>;
type AdtKinds = BTreeMap<chalk_ir::AdtId<ChalkIr>, TypeKind>;
type FnDefKinds = BTreeMap<chalk_ir::FnDefId<ChalkIr>, TypeKind>;
type TraitKinds = BTreeMap<chalk_ir::TraitId<ChalkIr>, TypeKind>;
type OpaqueTyKinds = BTreeMap<chalk_ir::OpaqueTyId<ChalkIr>, TypeKind>;
type AssociatedTyLookups = BTreeMap<(chalk_ir::TraitId<ChalkIr>, Ident), AssociatedTyLookup>;
type AssociatedTyValueIds =
BTreeMap<(chalk_ir::ImplId<ChalkIr>, Ident), AssociatedTyValueId<ChalkIr>>;
Expand All @@ -42,6 +43,7 @@ struct Env<'k> {
trait_ids: &'k TraitIds,
trait_kinds: &'k TraitKinds,
opaque_ty_ids: &'k OpaqueTyIds,
opaque_ty_kinds: &'k OpaqueTyKinds,
associated_ty_lookups: &'k AssociatedTyLookups,
/// GenericArg identifiers are used as keys, therefore
/// all identifiers in an environment must be unique (no shadowing).
Expand Down Expand Up @@ -76,6 +78,7 @@ struct AssociatedTyLookup {
enum ApplyTypeLookup {
Adt(AdtId<ChalkIr>),
FnDef(FnDefId<ChalkIr>),
Opaque(OpaqueTyId<ChalkIr>),
}

const SELF: &str = "Self";
Expand Down Expand Up @@ -158,10 +161,6 @@ impl<'k> Env<'k> {
return Err(RustIrError::CannotApplyTypeParameter(name.clone()));
}

if let Some(_) = self.opaque_ty_ids.get(&name.str) {
return Err(RustIrError::CannotApplyTypeParameter(name.clone()));
}

if let Some(id) = self.adt_ids.get(&name.str) {
return Ok(ApplyTypeLookup::Adt(*id));
}
Expand All @@ -170,6 +169,10 @@ impl<'k> Env<'k> {
return Ok(ApplyTypeLookup::FnDef(*id));
}

if let Some(id) = self.opaque_ty_ids.get(&name.str) {
return Ok(ApplyTypeLookup::Opaque(*id));
}

Err(RustIrError::NotStruct(name.clone()))
}

Expand Down Expand Up @@ -201,6 +204,10 @@ impl<'k> Env<'k> {
&self.fn_def_kinds[&id]
}

fn opaque_kind(&self, id: chalk_ir::OpaqueTyId<ChalkIr>) -> &TypeKind {
&self.opaque_ty_kinds[&id]
}

/// Introduces new parameters, shifting the indices of existing
/// parameters to accommodate them. The indices of the new binders
/// will be assigned in order as they are iterated.
Expand Down Expand Up @@ -369,6 +376,7 @@ impl LowerProgram for Program {
trait_ids: &trait_ids,
trait_kinds: &trait_kinds,
opaque_ty_ids: &opaque_ty_ids,
opaque_ty_kinds: &opaque_ty_kinds,
associated_ty_lookups: &associated_ty_lookups,
parameter_map: BTreeMap::new(),
};
Expand Down Expand Up @@ -1311,6 +1319,9 @@ impl LowerTy for Ty {
ApplyTypeLookup::FnDef(id) => {
(chalk_ir::TypeName::FnDef(id), env.fn_def_kind(id))
}
ApplyTypeLookup::Opaque(id) => {
(chalk_ir::TypeName::OpaqueType(id), env.opaque_kind(id))
}
};

if k.binders.len(interner) != args.len() {
Expand Down Expand Up @@ -1658,6 +1669,7 @@ impl LowerGoal<LoweredProgram> for Goal {
adt_kinds: &program.adt_kinds,
fn_def_kinds: &program.fn_def_kinds,
trait_kinds: &program.trait_kinds,
opaque_ty_kinds: &program.opaque_ty_kinds,
associated_ty_lookups: &associated_ty_lookups,
parameter_map: BTreeMap::new(),
};
Expand Down
19 changes: 16 additions & 3 deletions chalk-solve/src/clauses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,22 @@ fn program_clauses_that_could_match<I: Interner>(
}
}
DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => match &alias_eq.alias {
AliasTy::Projection(proj) => db
.associated_ty_data(proj.associated_ty_id)
.to_program_clauses(builder),
AliasTy::Projection(proj) => {
let trait_self_ty = db
.trait_ref_from_projection(proj)
.self_type_parameter(interner);

if let TyData::Apply(ApplicationTy {
name: TypeName::OpaqueType(opaque_ty_id),
..
}) = trait_self_ty.data(interner)
{
db.opaque_ty_data(*opaque_ty_id).to_program_clauses(builder)
}

db.associated_ty_data(proj.associated_ty_id)
.to_program_clauses(builder)
}
AliasTy::Opaque(opaque_ty) => db
.opaque_ty_data(opaque_ty.opaque_ty_id)
.to_program_clauses(builder),
Expand Down
46 changes: 0 additions & 46 deletions tests/test/existential_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,6 @@

use super::*;

#[test]
fn opaque_bounds() {
test! {
program {
struct Ty { }

trait Clone { }
opaque type T: Clone = Ty;
}

goal {
T: Clone
} yields {
"Unique; substitution []"
}
}
}

#[test]
fn opaque_reveal() {
test! {
program {
struct Ty { }
trait Trait { }
impl Trait for Ty { }

trait Clone { }
opaque type T: Clone = Ty;
}

goal {
if (Reveal) {
T: Trait
}
} yields {
"Unique; substitution []"
}

goal {
T: Trait
} yields {
"No possible solution"
}
}
}

#[test]
fn dyn_Clone_is_Clone() {
test! {
Expand Down
1 change: 1 addition & 0 deletions tests/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ mod impls;
mod misc;
mod negation;
mod object_safe;
mod opaque_types;
mod projection;
mod refs;
mod scalars;
Expand Down
100 changes: 100 additions & 0 deletions tests/test/opaque_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use super::*;

#[test]
fn opaque_bounds() {
test! {
program {
struct Ty { }

trait Clone { }
opaque type T: Clone = Ty;
}

goal {
T: Clone
} yields {
"Unique; substitution []"
}
}
}

#[test]
fn opaque_reveal() {
test! {
program {
struct Ty { }
trait Trait { }
impl Trait for Ty { }

trait Clone { }
opaque type T: Clone = Ty;
}

goal {
if (Reveal) {
T: Trait
}
} yields {
"Unique; substitution []"
}

goal {
T: Trait
} yields {
"No possible solution"
}
}
}

#[test]
fn opaque_generics_simple() {
test! {
program {
trait Iterator { type Item; }

struct Vec<T> { }
struct Bar { }
impl<T> Iterator for Vec<T> {
type Item = u32;
}

opaque type Foo<X>: Iterator = Vec<X>;
}

goal {
Foo<Bar>: Iterator
} yields {
"Unique; substitution []"
}

}
}

#[test]
fn opaque_generics() {
test! {
program {
trait Iterator { type Item; }

struct Vec<T> { }
struct Bar { }

opaque type Foo<X>: Iterator<Item = X> = Vec<X>;
}

goal {
Foo<Bar>: Iterator<Item = Bar>
} yields {
"Unique; substitution []"
}

goal {
forall<T> {
Foo<T>: Iterator<Item = T>
}
} yields {
"Unique; substitution []"
}

}
}