Skip to content

Commit fb42c72

Browse files
committed
Add closures
1 parent 1781c43 commit fb42c72

File tree

17 files changed

+280
-24
lines changed

17 files changed

+280
-24
lines changed

chalk-integration/src/db.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ use crate::{
77
tls,
88
};
99
use chalk_ir::{
10-
AdtId, AssocTypeId, Canonical, ConstrainedSubst, Environment, FnDefId, GenericArg, Goal,
11-
ImplId, InEnvironment, OpaqueTyId, ProgramClause, ProgramClauses, TraitId, Ty, UCanonical,
10+
AdtId, AssocTypeId, Canonical, ClosureId, ConstrainedSubst, Environment, FnDefId, GenericArg,
11+
Goal, ImplId, InEnvironment, OpaqueTyId, ProgramClause, ProgramClauses, Substitution, TraitId,
12+
Ty, UCanonical,
1213
};
1314
use chalk_solve::rust_ir::{
14-
AdtDatum, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, FnDefDatum, ImplDatum,
15-
OpaqueTyDatum, TraitDatum, WellKnownTrait,
15+
AdtDatum, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, ClosureDatum, FnDefDatum,
16+
ImplDatum, OpaqueTyDatum, TraitDatum, WellKnownTrait,
1617
};
1718
use chalk_solve::{RustIrDatabase, Solution, SolverChoice, SubstitutionResult};
1819
use salsa::Database;
@@ -154,4 +155,22 @@ impl RustIrDatabase<ChalkIr> for ChalkDatabase {
154155
fn is_object_safe(&self, trait_id: TraitId<ChalkIr>) -> bool {
155156
self.program_ir().unwrap().is_object_safe(trait_id)
156157
}
158+
159+
fn closure_datum(
160+
&self,
161+
closure_id: ClosureId<ChalkIr>,
162+
substs: Substitution<ChalkIr>,
163+
) -> Arc<ClosureDatum<ChalkIr>> {
164+
self.program_ir().unwrap().closure_datum(closure_id, substs)
165+
}
166+
167+
fn closure_upvars(
168+
&self,
169+
closure_id: ClosureId<ChalkIr>,
170+
substs: Substitution<ChalkIr>,
171+
) -> Substitution<ChalkIr> {
172+
self.program_ir()
173+
.unwrap()
174+
.closure_upvars(closure_id, substs)
175+
}
157176
}

chalk-integration/src/lowering.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ impl<'k> Env<'k> {
132132
actual: 0,
133133
});
134134
} else {
135-
return Ok(chalk_ir::TyData::Function(chalk_ir::Fn {
136-
num_binders: k.binders.len(interner),
135+
return Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy {
136+
name: chalk_ir::TypeName::FnDef(id.clone()),
137137
substitution: chalk_ir::Substitution::empty(interner),
138138
})
139139
.intern(interner)
@@ -1032,11 +1032,12 @@ impl LowerFnDefn for FnDefn {
10321032
env: &Env,
10331033
) -> LowerResult<rust_ir::FnDefDatum<ChalkIr>> {
10341034
let binders = env.in_binders(self.all_parameters(), |env| {
1035-
let args: LowerResult<_> = self.argument_types.iter().map(|t| t.lower(env)).collect();
10361035
let where_clauses = self.lower_where_clauses(env)?;
1037-
let return_type = self.return_type.lower(env)?;
10381036

1039-
let inputs_and_output = env.in_binders(vec![], |_| {
1037+
let inputs_and_output = env.in_binders(vec![], |env| {
1038+
let args: LowerResult<_> =
1039+
self.argument_types.iter().map(|t| t.lower(env)).collect();
1040+
let return_type = self.return_type.lower(env)?;
10401041
Ok(rust_ir::FnDefInputsAndOutputDatum {
10411042
argument_types: args?,
10421043
return_type,

chalk-integration/src/program.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ use crate::{tls, Identifier, TypeKind};
33
use chalk_ir::could_match::CouldMatch;
44
use chalk_ir::debug::Angle;
55
use chalk_ir::{
6-
debug::SeparatorTraitRef, AdtId, AliasTy, ApplicationTy, AssocTypeId, FnDefId, GenericArg,
7-
Goal, Goals, ImplId, Lifetime, OpaqueTy, OpaqueTyId, ProgramClause, ProgramClauseImplication,
8-
ProgramClauses, ProjectionTy, Substitution, TraitId, Ty,
6+
debug::SeparatorTraitRef, AdtId, AliasTy, ApplicationTy, AssocTypeId, ClosureId, FnDefId,
7+
GenericArg, Goal, Goals, ImplId, Lifetime, OpaqueTy, OpaqueTyId, ProgramClause,
8+
ProgramClauseImplication, ProgramClauses, ProjectionTy, Substitution, TraitId, Ty,
99
};
1010
use chalk_solve::rust_ir::{
11-
AdtDatum, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, FnDefDatum, ImplDatum,
12-
ImplType, OpaqueTyDatum, TraitDatum, WellKnownTrait,
11+
AdtDatum, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, ClosureDatum, FnDefDatum,
12+
ImplDatum, ImplType, OpaqueTyDatum, TraitDatum, WellKnownTrait,
1313
};
1414
use chalk_solve::split::Split;
1515
use chalk_solve::RustIrDatabase;
@@ -412,4 +412,20 @@ impl RustIrDatabase<ChalkIr> for Program {
412412
fn is_object_safe(&self, trait_id: TraitId<ChalkIr>) -> bool {
413413
self.object_safe_traits.contains(&trait_id)
414414
}
415+
416+
fn closure_datum(
417+
&self,
418+
closure_id: ClosureId<ChalkIr>,
419+
substs: Substitution<ChalkIr>,
420+
) -> Arc<ClosureDatum<ChalkIr>> {
421+
todo!()
422+
}
423+
424+
fn closure_upvars(
425+
&self,
426+
closure_id: ClosureId<ChalkIr>,
427+
substs: Substitution<ChalkIr>,
428+
) -> Substitution<ChalkIr> {
429+
todo!()
430+
}
415431
}

chalk-ir/src/debug.rs

+7
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ impl<I: Interner> Debug for FnDefId<I> {
2727
}
2828
}
2929

30+
impl<I: Interner> Debug for ClosureId<I> {
31+
fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result {
32+
I::debug_closure_id(*self, fmt).unwrap_or_else(|| write!(fmt, "ClosureId({:?})", self.0))
33+
}
34+
}
35+
3036
impl<I: Interner> Debug for Ty<I> {
3137
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> {
3238
I::debug_ty(self, fmt).unwrap_or_else(|| write!(fmt, "{:?}", self.interned))
@@ -169,6 +175,7 @@ impl<I: Interner> Debug for TypeName<I> {
169175
TypeName::Ref(mutability) => write!(fmt, "{:?}", mutability),
170176
TypeName::Never => write!(fmt, "Never"),
171177
TypeName::Array => write!(fmt, "{{array}}"),
178+
TypeName::Closure(id) => write!(fmt, "{{closure:{:?}}}", id),
172179
TypeName::Error => write!(fmt, "{{error}}"),
173180
}
174181
}

chalk-ir/src/fold/boring_impls.rs

+1
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ id_fold!(TraitId);
279279
id_fold!(AssocTypeId);
280280
id_fold!(OpaqueTyId);
281281
id_fold!(FnDefId);
282+
id_fold!(ClosureId);
282283

283284
impl<I: Interner, TI: TargetInterner<I>> SuperFold<I, TI> for ProgramClauseData<I> {
284285
fn super_fold_with<'i>(

chalk-ir/src/interner.rs

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::ApplicationTy;
44
use crate::AssocTypeId;
55
use crate::CanonicalVarKind;
66
use crate::CanonicalVarKinds;
7+
use crate::ClosureId;
78
use crate::FnDefId;
89
use crate::GenericArg;
910
use crate::GenericArgData;
@@ -234,6 +235,14 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash {
234235
None
235236
}
236237

238+
#[allow(unused_variables)]
239+
fn debug_closure_id(
240+
fn_def_id: ClosureId<Self>,
241+
fmt: &mut fmt::Formatter<'_>,
242+
) -> Option<fmt::Result> {
243+
None
244+
}
245+
237246
/// Prints the debug representation of an alias. To get good
238247
/// results, this requires inspecting TLS, and is difficult to
239248
/// code without reference to a specific interner (and hence

chalk-ir/src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ pub enum TypeName<I: Interner> {
197197
/// the never type `!`
198198
Never,
199199

200+
/// A closure.
201+
Closure(ClosureId<I>),
202+
200203
/// This can be used to represent an error, e.g. during name resolution of a type.
201204
/// Chalk itself will not produce this, just pass it through when given.
202205
Error,
@@ -290,6 +293,9 @@ pub struct OpaqueTyId<I: Interner>(pub I::DefId);
290293
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
291294
pub struct FnDefId<I: Interner>(pub I::DefId);
292295

296+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
297+
pub struct ClosureId<I: Interner>(pub I::DefId);
298+
293299
impl_debugs!(ImplId, ClauseId);
294300

295301
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)]

chalk-ir/src/visit/boring_impls.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
//! The more interesting impls of `Visit` remain in the `visit` module.
66
77
use crate::{
8-
AdtId, AssocTypeId, ClausePriority, DebruijnIndex, FloatTy, FnDefId, GenericArg, Goals, ImplId,
9-
IntTy, Interner, Mutability, OpaqueTyId, PlaceholderIndex, ProgramClause, ProgramClauseData,
10-
ProgramClauses, QuantifiedWhereClauses, QuantifierKind, Scalar, Substitution, SuperVisit,
11-
TraitId, UintTy, UniverseIndex, Visit, VisitResult, Visitor,
8+
AdtId, AssocTypeId, ClausePriority, ClosureId, DebruijnIndex, FloatTy, FnDefId, GenericArg,
9+
Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, PlaceholderIndex, ProgramClause,
10+
ProgramClauseData, ProgramClauses, QuantifiedWhereClauses, QuantifierKind, Scalar,
11+
Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult, Visitor,
1212
};
1313
use std::{marker::PhantomData, sync::Arc};
1414

@@ -235,6 +235,7 @@ id_visit!(TraitId);
235235
id_visit!(OpaqueTyId);
236236
id_visit!(AssocTypeId);
237237
id_visit!(FnDefId);
238+
id_visit!(ClosureId);
238239

239240
impl<I: Interner> SuperVisit<I> for ProgramClause<I> {
240241
fn super_visit_with<'i, R: VisitResult>(

chalk-solve/src/clauses.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,8 @@ fn match_type_name<I: Interner>(
502502
| TypeName::Raw(_)
503503
| TypeName::Ref(_)
504504
| TypeName::Array
505-
| TypeName::Never => {
505+
| TypeName::Never
506+
| TypeName::Closure(_) => {
506507
builder.push_fact(WellFormed::Ty(application.clone().intern(interner)))
507508
}
508509
}

chalk-solve/src/clauses/builtin_traits.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub fn add_builtin_program_clauses<I: Interner>(
3535
WellKnownTrait::Copy => copy::add_copy_program_clauses(db, builder, &trait_ref, ty),
3636
WellKnownTrait::Clone => clone::add_clone_program_clauses(db, builder, &trait_ref, ty),
3737
WellKnownTrait::FnOnce | WellKnownTrait::FnMut | WellKnownTrait::Fn => {
38-
fn_family::add_fn_trait_program_clauses(db, builder, trait_ref.trait_id, self_ty)?
38+
fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)?
3939
}
4040
WellKnownTrait::Unsize => {
4141
unsize::add_unsize_program_clauses(db, builder, &trait_ref, ty)
@@ -57,8 +57,7 @@ pub fn add_builtin_assoc_program_clauses<I: Interner>(
5757
) -> Result<(), Floundered> {
5858
match well_known {
5959
WellKnownTrait::FnOnce => {
60-
let trait_id = db.well_known_trait_id(well_known).unwrap();
61-
fn_family::add_fn_trait_program_clauses(db, builder, trait_id, self_ty)?;
60+
fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)?;
6261
}
6362
_ => {}
6463
}

chalk-solve/src/clauses/builtin_traits/copy.rs

+18
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,24 @@ pub fn add_copy_program_clauses<I: Interner>(
5454
TypeName::FnDef(_) => {
5555
builder.push_fact(trait_ref.clone());
5656
}
57+
TypeName::Closure(_) => {
58+
let interner = db.interner();
59+
match substitution
60+
.parameters(interner)
61+
.last()
62+
.unwrap()
63+
.assert_ty_ref(interner)
64+
.data(interner)
65+
{
66+
TyData::Apply(ApplicationTy { name, substitution }) => match name {
67+
TypeName::Tuple(arity) => {
68+
push_tuple_copy_conditions(db, builder, trait_ref, *arity, substitution)
69+
}
70+
_ => panic!("Expected tuple for upvars."),
71+
},
72+
_ => panic!("Expected tuple for upvars."),
73+
}
74+
}
5775
_ => return,
5876
},
5977
TyData::Function(_) => builder.push_fact(trait_ref.clone()),

chalk-solve/src/clauses/builtin_traits/fn_family.rs

+108-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::clauses::ClauseBuilder;
22
use crate::infer::instantiate::IntoBindersAndValue;
3-
use crate::rust_ir::WellKnownTrait;
3+
use crate::rust_ir::{ClosureKind, WellKnownTrait};
44
use crate::{Interner, RustIrDatabase, TraitRef};
5+
use chalk_ir::cast::Cast;
56
use chalk_ir::{
67
AliasTy, ApplicationTy, Binders, Floundered, Normalize, ProjectionTy, Substitution, TraitId,
78
Ty, TyData, TypeName, VariableKinds,
@@ -19,11 +20,116 @@ use chalk_ir::{
1920
pub fn add_fn_trait_program_clauses<I: Interner>(
2021
db: &dyn RustIrDatabase<I>,
2122
builder: &mut ClauseBuilder<'_, I>,
22-
trait_id: TraitId<I>,
23+
well_known: WellKnownTrait,
2324
self_ty: Ty<I>,
2425
) -> Result<(), Floundered> {
2526
let interner = db.interner();
27+
let trait_id = db.well_known_trait_id(well_known).unwrap();
2628
match self_ty.data(interner) {
29+
TyData::Apply(apply) => match apply.name {
30+
TypeName::FnDef(fn_def_id) => {
31+
let fn_def_datum = builder.db.fn_def_datum(fn_def_id);
32+
let bound = fn_def_datum
33+
.binders
34+
.substitute(builder.interner(), &apply.substitution);
35+
builder.push_binders(&bound.inputs_and_output, |builder, inputs_and_output| {
36+
let interner = builder.interner();
37+
let ty = ApplicationTy {
38+
name: apply.name,
39+
substitution: builder.substitution_in_scope(),
40+
}
41+
.intern(interner);
42+
43+
let substitution = {
44+
let self_ty = ty.cast(interner);
45+
let arguments = ApplicationTy {
46+
name: TypeName::Tuple(inputs_and_output.argument_types.len()),
47+
substitution: Substitution::from(
48+
interner,
49+
inputs_and_output
50+
.argument_types
51+
.iter()
52+
.cloned()
53+
.map(|ty| ty.cast(interner)),
54+
),
55+
}
56+
.intern(interner)
57+
.cast(interner);
58+
Substitution::from(interner, &[self_ty, arguments])
59+
};
60+
builder.push_fact(TraitRef {
61+
trait_id,
62+
substitution: substitution.clone(),
63+
});
64+
65+
if let WellKnownTrait::FnOnce = well_known {
66+
let trait_datum = db.trait_datum(trait_id);
67+
let output_id = trait_datum.associated_ty_ids[0];
68+
let alias = AliasTy::Projection(ProjectionTy {
69+
associated_ty_id: output_id,
70+
substitution,
71+
});
72+
let return_type = inputs_and_output.return_type;
73+
builder.push_fact(Normalize {
74+
alias,
75+
ty: return_type,
76+
});
77+
}
78+
});
79+
Ok(())
80+
}
81+
TypeName::Closure(closure_id) => {
82+
let closure_datum = db.closure_datum(closure_id, apply.substitution.clone());
83+
let trait_matches = match well_known {
84+
WellKnownTrait::Fn => matches!(closure_datum.kind, ClosureKind::Fn),
85+
WellKnownTrait::FnMut => {
86+
matches!(closure_datum.kind, ClosureKind::FnMut | ClosureKind::Fn)
87+
}
88+
WellKnownTrait::FnOnce => matches!(
89+
closure_datum.kind,
90+
ClosureKind::FnOnce | ClosureKind::FnMut | ClosureKind::Fn
91+
),
92+
_ => false,
93+
};
94+
if trait_matches {
95+
builder.push_binders(
96+
&closure_datum.inputs_and_output,
97+
|builder, inputs_and_output| {
98+
let substitution = Substitution::from(
99+
interner,
100+
Some(self_ty.cast(interner)).into_iter().chain(
101+
inputs_and_output
102+
.argument_types
103+
.iter()
104+
.cloned()
105+
.map(|ty| ty.cast(interner)),
106+
),
107+
);
108+
builder.push_fact(TraitRef {
109+
trait_id,
110+
substitution: substitution.clone(),
111+
});
112+
113+
if let WellKnownTrait::FnOnce = well_known {
114+
let trait_datum = db.trait_datum(trait_id);
115+
let output_id = trait_datum.associated_ty_ids[0];
116+
let alias = AliasTy::Projection(ProjectionTy {
117+
associated_ty_id: output_id,
118+
substitution,
119+
});
120+
let return_type = inputs_and_output.return_type.clone();
121+
builder.push_fact(Normalize {
122+
alias,
123+
ty: return_type,
124+
});
125+
}
126+
},
127+
);
128+
}
129+
Ok(())
130+
}
131+
_ => Ok(()),
132+
},
27133
TyData::Function(fn_val) => {
28134
let (binders, orig_sub) = fn_val.into_binders_and_value(interner);
29135
let bound_ref = Binders::new(VariableKinds::from(interner, binders), orig_sub);

chalk-solve/src/clauses/builtin_traits/sized.rs

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub fn add_sized_program_clauses<I: Interner>(
7676
}
7777
TypeName::Array
7878
| TypeName::Never
79+
| TypeName::Closure(_)
7980
| TypeName::FnDef(_)
8081
| TypeName::Scalar(_)
8182
| TypeName::Raw(_)

0 commit comments

Comments
 (0)