Skip to content

Commit f438d7e

Browse files
authored
Merge pull request #324 from detrumi/impl-trait-alias
Implement Impl Trait
2 parents 28cef6f + d5a8fae commit f438d7e

File tree

27 files changed

+780
-179
lines changed

27 files changed

+780
-179
lines changed

book/src/types/rust_types.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ evaluated. For example, when typing the body of a generic function
5656
like `fn foo<T: Iterator>`, the type `T` would be represented with a
5757
placeholder. Similarly, in that same function, the associated type
5858
`T::Item` might be represented with a placeholder.
59-
59+
6060
Like application types, placeholder *types* are only known to be
6161
equal.
6262

@@ -96,7 +96,7 @@ type. In chalk, these are represented as an existential type where we
9696
store the predicates that are known to be true. So a type like `dyn
9797
Write` would be represented as, effectively, an `exists<T> { T: Write
9898
}` type.
99-
99+
100100
When equating, two `dyn P` and `dyn Q` types are equal if `P = Q` --
101101
i.e., they have the same bounds. Note that -- for this purpose --
102102
ordering of bounds is significant. That means that if you create a
@@ -115,7 +115,7 @@ application types, but with one crucial difference: they also contain
115115
a `forall` binder that for lifetimes whose value is determined when
116116
the function is called. Consider e.g. a type like `fn(&u32)` or --
117117
more explicitly -- `for<'a> fn(&'a u32)`.
118-
118+
119119
Two `Fn` types `A, B` are equal `A = B` if `A <: B` and `B <: A`
120120

121121
Two `Fn` types `A, B` are subtypes `A <: B` if
@@ -124,7 +124,7 @@ Two `Fn` types `A, B` are subtypes `A <: B` if
124124
* You can instantiate the lifetime parameters on `A` existentially...
125125
* And then you find that `P_B <: P_A` for every parameter type `P` on `A` and `B` and
126126
`R_A <: R_B` for the return type `R` of `A` and `B`.
127-
127+
128128
We currently handle type inference with a bit of a hack (same as
129129
rustc); when relating a `Fn` type `F` to an unbounded type
130130
variable `V`, we instantiate `V` with `F`. But in practice
@@ -155,16 +155,14 @@ contained within.
155155

156156
The `Alias` variant wraps an `AliasTy` and is used to represent some form of *type
157157
alias*. These correspond to associated type projections like `<T as Iterator>::Item`
158-
but also `impl Trait` types and named type aliases like `type Foo<X> = Vec<X>`.
158+
but also `impl Trait` types and named type aliases like `type Foo<X> = Vec<X>`.
159159

160160
Each alias has an alias id as well as parameters. Aliases effectively
161161
represent a *type function*.
162162

163163
Aliases are quite special when equating types. In general, an alias
164-
type `A` can also be equal to *any other type* `T` if evaluating the
165-
alias `A` yields `T` (this is currently handled in Chalk via a
166-
`ProjectionEq` goal, but it would be renamed to `AliasEq` under this
167-
proposal).
164+
type `A` can also be equal to *any other type* `T` (`AliasEq`) if evaluating the
165+
alias `A` yields `T`.
168166

169167
However, some alias types can also be instantiated as "alias
170168
placeholders". This occurs when the precise type of the alias is not

chalk-integration/src/db.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use chalk_ir::ConstrainedSubst;
1111
use chalk_ir::Goal;
1212
use chalk_ir::ImplId;
1313
use chalk_ir::InEnvironment;
14+
use chalk_ir::OpaqueTyId;
1415
use chalk_ir::Parameter;
1516
use chalk_ir::ProgramClause;
1617
use chalk_ir::StructId;
@@ -21,6 +22,7 @@ use chalk_rust_ir::AssociatedTyDatum;
2122
use chalk_rust_ir::AssociatedTyValue;
2223
use chalk_rust_ir::AssociatedTyValueId;
2324
use chalk_rust_ir::ImplDatum;
25+
use chalk_rust_ir::OpaqueTyDatum;
2426
use chalk_rust_ir::StructDatum;
2527
use chalk_rust_ir::TraitDatum;
2628
use chalk_rust_ir::WellKnownTrait;
@@ -104,6 +106,10 @@ impl RustIrDatabase<ChalkIr> for ChalkDatabase {
104106
self.program_ir().unwrap().associated_ty_values[&id].clone()
105107
}
106108

109+
fn opaque_ty_data(&self, id: OpaqueTyId<ChalkIr>) -> Arc<OpaqueTyDatum<ChalkIr>> {
110+
self.program_ir().unwrap().opaque_ty_data(id)
111+
}
112+
107113
fn struct_datum(&self, id: StructId<ChalkIr>) -> Arc<StructDatum<ChalkIr>> {
108114
self.program_ir().unwrap().struct_datum(id)
109115
}

chalk-integration/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use chalk_ir::Binders;
1818
pub enum TypeSort {
1919
Struct,
2020
Trait,
21+
Opaque,
2122
}
2223

2324
#[derive(Clone, Debug, PartialEq, Eq, Hash)]

chalk-integration/src/lowering.rs

Lines changed: 114 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
use chalk_ir::cast::{Cast, Caster};
22
use chalk_ir::interner::ChalkIr;
33
use chalk_ir::{
4-
self, AssocTypeId, BoundVar, ClausePriority, DebruijnIndex, ImplId, QuantifiedWhereClauses,
5-
StructId, Substitution, TraitId,
4+
self, AssocTypeId, BoundVar, ClausePriority, DebruijnIndex, ImplId, OpaqueTyId,
5+
QuantifiedWhereClauses, StructId, Substitution, TraitId,
66
};
77
use chalk_parse::ast::*;
88
use chalk_rust_ir as rust_ir;
9-
use chalk_rust_ir::{Anonymize, AssociatedTyValueId, IntoWhereClauses, ToParameter};
9+
use chalk_rust_ir::{
10+
Anonymize, AssociatedTyValueId, IntoWhereClauses, OpaqueTyDatum, OpaqueTyDatumBound,
11+
ToParameter,
12+
};
1013
use lalrpop_intern::intern;
1114
use std::collections::BTreeMap;
1215
use std::sync::Arc;
@@ -17,6 +20,7 @@ use crate::{Identifier as Ident, RawId, TypeKind, TypeSort};
1720

1821
type StructIds = BTreeMap<Ident, chalk_ir::StructId<ChalkIr>>;
1922
type TraitIds = BTreeMap<Ident, chalk_ir::TraitId<ChalkIr>>;
23+
type OpaqueTyIds = BTreeMap<Ident, chalk_ir::OpaqueTyId<ChalkIr>>;
2024
type StructKinds = BTreeMap<chalk_ir::StructId<ChalkIr>, TypeKind>;
2125
type TraitKinds = BTreeMap<chalk_ir::TraitId<ChalkIr>, TypeKind>;
2226
type AssociatedTyLookups = BTreeMap<(chalk_ir::TraitId<ChalkIr>, Ident), AssociatedTyLookup>;
@@ -32,6 +36,7 @@ struct Env<'k> {
3236
struct_kinds: &'k StructKinds,
3337
trait_ids: &'k TraitIds,
3438
trait_kinds: &'k TraitKinds,
39+
opaque_ty_ids: &'k OpaqueTyIds,
3540
associated_ty_lookups: &'k AssociatedTyLookups,
3641
/// Parameter identifiers are used as keys, therefore
3742
/// all identifiers in an environment must be unique (no shadowing).
@@ -66,6 +71,7 @@ struct AssociatedTyLookup {
6671
enum TypeLookup {
6772
Struct(chalk_ir::StructId<ChalkIr>),
6873
Parameter(BoundVar),
74+
Opaque(chalk_ir::OpaqueTyId<ChalkIr>),
6975
}
7076

7177
enum LifetimeLookup {
@@ -88,6 +94,9 @@ impl<'k> Env<'k> {
8894
return Ok(TypeLookup::Struct(*id));
8995
}
9096

97+
if let Some(id) = self.opaque_ty_ids.get(&name.str) {
98+
return Ok(TypeLookup::Opaque(*id));
99+
}
91100
if let Some(_) = self.trait_ids.get(&name.str) {
92101
return Err(RustIrError::NotStruct(name));
93102
}
@@ -223,8 +232,10 @@ impl LowerProgram for Program {
223232

224233
let mut struct_ids = BTreeMap::new();
225234
let mut trait_ids = BTreeMap::new();
235+
let mut opaque_ty_ids = BTreeMap::new();
226236
let mut struct_kinds = BTreeMap::new();
227237
let mut trait_kinds = BTreeMap::new();
238+
let mut opaque_ty_kinds = BTreeMap::new();
228239
for (item, &raw_id) in self.items.iter().zip(&raw_ids) {
229240
match item {
230241
Item::StructDefn(defn) => {
@@ -239,6 +250,12 @@ impl LowerProgram for Program {
239250
trait_ids.insert(type_kind.name, id);
240251
trait_kinds.insert(id, type_kind);
241252
}
253+
Item::OpaqueTyDefn(defn) => {
254+
let type_kind = defn.lower_type_kind()?;
255+
let id = OpaqueTyId(raw_id);
256+
opaque_ty_ids.insert(defn.identifier.str, id);
257+
opaque_ty_kinds.insert(id, type_kind);
258+
}
242259
Item::Impl(_) => continue,
243260
Item::Clause(_) => continue,
244261
};
@@ -250,13 +267,15 @@ impl LowerProgram for Program {
250267
let mut impl_data = BTreeMap::new();
251268
let mut associated_ty_data = BTreeMap::new();
252269
let mut associated_ty_values = BTreeMap::new();
270+
let mut opaque_ty_data = BTreeMap::new();
253271
let mut custom_clauses = Vec::new();
254272
for (item, &raw_id) in self.items.iter().zip(&raw_ids) {
255273
let empty_env = Env {
256274
struct_ids: &struct_ids,
257275
struct_kinds: &struct_kinds,
258276
trait_ids: &trait_ids,
259277
trait_kinds: &trait_kinds,
278+
opaque_ty_ids: &opaque_ty_ids,
260279
associated_ty_lookups: &associated_ty_lookups,
261280
parameter_map: BTreeMap::new(),
262281
};
@@ -361,6 +380,57 @@ impl LowerProgram for Program {
361380
Item::Clause(ref clause) => {
362381
custom_clauses.extend(clause.lower_clause(&empty_env)?);
363382
}
383+
Item::OpaqueTyDefn(ref opaque_ty) => {
384+
if let Some(&opaque_ty_id) = opaque_ty_ids.get(&opaque_ty.identifier.str) {
385+
let parameter_kinds = opaque_ty
386+
.parameter_kinds
387+
.iter()
388+
.map(|k| k.lower())
389+
.collect::<Vec<_>>();
390+
391+
// Introduce the parameters declared on the opaque type definition.
392+
// So if we have `type Foo<P1..Pn> = impl Trait<T1..Tn>`, this would introduce `P1..Pn`
393+
let binders = empty_env.in_binders(parameter_kinds, |env| {
394+
let hidden_ty = opaque_ty.ty.lower(&env)?;
395+
396+
// Introduce a variable to represent the hidden "self type". This will be used in the bounds.
397+
// So the `impl Trait<T1..Tn>` will be lowered to `exists<Self> { Self: Trait<T1..Tn> }`.
398+
let bounds: chalk_ir::Binders<Vec<chalk_ir::Binders<_>>> = env
399+
.in_binders(
400+
Some(chalk_ir::ParameterKind::Ty(intern(FIXME_SELF))),
401+
|env1| {
402+
let interner = env1.interner();
403+
Ok(opaque_ty
404+
.bounds
405+
.lower(&env1)?
406+
.iter()
407+
.flat_map(|qil| {
408+
// Instantiate the bounds with the innermost bound variable, which represents Self, as the self type.
409+
qil.into_where_clauses(
410+
interner,
411+
chalk_ir::TyData::BoundVar(BoundVar::new(
412+
DebruijnIndex::INNERMOST,
413+
0,
414+
))
415+
.intern(interner),
416+
)
417+
})
418+
.collect())
419+
},
420+
)?;
421+
422+
Ok(OpaqueTyDatumBound { hidden_ty, bounds })
423+
})?;
424+
425+
opaque_ty_data.insert(
426+
opaque_ty_id,
427+
Arc::new(OpaqueTyDatum {
428+
opaque_ty_id,
429+
bound: binders,
430+
}),
431+
);
432+
}
433+
}
364434
}
365435
}
366436

@@ -375,6 +445,8 @@ impl LowerProgram for Program {
375445
impl_data,
376446
associated_ty_values,
377447
associated_ty_data,
448+
opaque_ty_ids,
449+
opaque_ty_data,
378450
custom_clauses,
379451
};
380452

@@ -551,6 +623,17 @@ impl LowerTypeKind for TraitDefn {
551623
}
552624
}
553625

626+
impl LowerTypeKind for OpaqueTyDefn {
627+
fn lower_type_kind(&self) -> LowerResult<TypeKind> {
628+
let binders: Vec<_> = self.parameter_kinds.iter().map(|p| p.lower()).collect();
629+
Ok(TypeKind {
630+
sort: TypeSort::Opaque,
631+
name: self.identifier.str,
632+
binders: chalk_ir::Binders::new(binders.anonymize(), ()),
633+
})
634+
}
635+
}
636+
554637
impl LowerWhereClauses for TraitDefn {
555638
fn where_clauses(&self) -> &[QuantifiedWhereClause] {
556639
&self.where_clauses
@@ -582,7 +665,7 @@ trait LowerWhereClause<T> {
582665
/// Lower from an AST `where` clause to an internal IR.
583666
/// Some AST `where` clauses can lower to multiple ones, this is why we return a `Vec`.
584667
/// As for now, this is the only the case for `where T: Foo<Item = U>` which lowers to
585-
/// `Implemented(T: Foo)` and `AliasEq(<T as Foo>::Item = U)`.
668+
/// `Implemented(T: Foo)` and `ProjectionEq(<T as Foo>::Item = U)`.
586669
fn lower(&self, env: &Env) -> LowerResult<Vec<T>>;
587670
}
588671

@@ -592,12 +675,12 @@ impl LowerWhereClause<chalk_ir::WhereClause<ChalkIr>> for WhereClause {
592675
WhereClause::Implemented { trait_ref } => {
593676
vec![chalk_ir::WhereClause::Implemented(trait_ref.lower(env)?)]
594677
}
595-
WhereClause::AliasEq { alias, ty } => vec![
678+
WhereClause::ProjectionEq { projection, ty } => vec![
596679
chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq {
597-
alias: alias.lower(env)?,
680+
alias: chalk_ir::AliasTy::Projection(projection.lower(env)?),
598681
ty: ty.lower(env)?,
599682
}),
600-
chalk_ir::WhereClause::Implemented(alias.trait_ref.lower(env)?),
683+
chalk_ir::WhereClause::Implemented(projection.trait_ref.lower(env)?),
601684
],
602685
};
603686
Ok(where_clauses)
@@ -624,9 +707,9 @@ impl LowerDomainGoal for DomainGoal {
624707
.into_iter()
625708
.casted(interner)
626709
.collect(),
627-
DomainGoal::Normalize { alias, ty } => {
710+
DomainGoal::Normalize { projection, ty } => {
628711
vec![chalk_ir::DomainGoal::Normalize(chalk_ir::Normalize {
629-
alias: alias.lower(env)?,
712+
alias: chalk_ir::AliasTy::Projection(projection.lower(env)?),
630713
ty: ty.lower(env)?,
631714
})]
632715
}
@@ -656,6 +739,7 @@ impl LowerDomainGoal for DomainGoal {
656739
DomainGoal::DownstreamType { ty } => {
657740
vec![chalk_ir::DomainGoal::DownstreamType(ty.lower(env)?)]
658741
}
742+
DomainGoal::Reveal => vec![chalk_ir::DomainGoal::Reveal(())],
659743
};
660744
Ok(goals)
661745
}
@@ -915,13 +999,13 @@ impl LowerTraitFlags for TraitFlags {
915999
}
9161000
}
9171001

918-
trait LowerAliasTy {
919-
fn lower(&self, env: &Env) -> LowerResult<chalk_ir::AliasTy<ChalkIr>>;
1002+
trait LowerProjectionTy {
1003+
fn lower(&self, env: &Env) -> LowerResult<chalk_ir::ProjectionTy<ChalkIr>>;
9201004
}
9211005

922-
impl LowerAliasTy for AliasTy {
923-
fn lower(&self, env: &Env) -> LowerResult<chalk_ir::AliasTy<ChalkIr>> {
924-
let AliasTy {
1006+
impl LowerProjectionTy for ProjectionTy {
1007+
fn lower(&self, env: &Env) -> LowerResult<chalk_ir::ProjectionTy<ChalkIr>> {
1008+
let ProjectionTy {
9251009
ref trait_ref,
9261010
ref name,
9271011
ref args,
@@ -960,7 +1044,7 @@ impl LowerAliasTy for AliasTy {
9601044

9611045
args.extend(trait_substitution.iter(interner).cloned());
9621046

963-
Ok(chalk_ir::AliasTy {
1047+
Ok(chalk_ir::ProjectionTy {
9641048
associated_ty_id: lookup.id,
9651049
substitution: chalk_ir::Substitution::from(interner, args),
9661050
})
@@ -993,6 +1077,13 @@ impl LowerTy for Ty {
9931077
}
9941078
}
9951079
TypeLookup::Parameter(d) => Ok(chalk_ir::TyData::BoundVar(d).intern(interner)),
1080+
TypeLookup::Opaque(id) => Ok(chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(
1081+
chalk_ir::OpaqueTy {
1082+
opaque_ty_id: id,
1083+
substitution: chalk_ir::Substitution::empty(interner),
1084+
},
1085+
))
1086+
.intern(interner)),
9961087
},
9971088

9981089
Ty::Dyn { ref bounds } => Ok(chalk_ir::TyData::Dyn(chalk_ir::DynTy {
@@ -1021,7 +1112,9 @@ impl LowerTy for Ty {
10211112
Ty::Apply { name, ref args } => {
10221113
let id = match env.lookup_type(name)? {
10231114
TypeLookup::Struct(id) => id,
1024-
TypeLookup::Parameter(_) => Err(RustIrError::CannotApplyTypeParameter(name))?,
1115+
TypeLookup::Parameter(_) | TypeLookup::Opaque(_) => {
1116+
Err(RustIrError::CannotApplyTypeParameter(name))?
1117+
}
10251118
};
10261119

10271120
let k = env.struct_kind(id);
@@ -1055,9 +1148,10 @@ impl LowerTy for Ty {
10551148
.intern(interner))
10561149
}
10571150

1058-
Ty::Alias { ref alias } => {
1059-
Ok(chalk_ir::TyData::Alias(alias.lower(env)?).intern(interner))
1060-
}
1151+
Ty::Projection { ref proj } => Ok(chalk_ir::TyData::Alias(
1152+
chalk_ir::AliasTy::Projection(proj.lower(env)?),
1153+
)
1154+
.intern(interner)),
10611155

10621156
Ty::ForAll {
10631157
ref lifetime_names,
@@ -1287,6 +1381,7 @@ impl LowerGoal<LoweredProgram> for Goal {
12871381
let env = Env {
12881382
struct_ids: &program.struct_ids,
12891383
trait_ids: &program.trait_ids,
1384+
opaque_ty_ids: &program.opaque_ty_ids,
12901385
struct_kinds: &program.struct_kinds,
12911386
trait_kinds: &program.trait_kinds,
12921387
associated_ty_lookups: &associated_ty_lookups,

0 commit comments

Comments
 (0)