Skip to content

Commit eeaa60c

Browse files
authored
Merge pull request #413 from marmeladema/sized-for-scalar-and-tuple
Handle functions, scalars and tuples for the builtin `Sized` trait
2 parents 036b2bc + c18b6c4 commit eeaa60c

File tree

7 files changed

+320
-22
lines changed

7 files changed

+320
-22
lines changed

chalk-solve/src/clauses/builtin_traits.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::builder::ClauseBuilder;
22
use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait};
3-
use chalk_ir::TyData;
3+
use chalk_ir::{Substitution, Ty, TyData};
44

55
mod clone;
66
mod copy;
@@ -30,3 +30,27 @@ pub fn add_builtin_program_clauses<I: Interner>(
3030
WellKnownTrait::DropTrait => (),
3131
}
3232
}
33+
34+
/// Given a trait ref `T0: Trait` and a list of types `U0..Un`, pushes a clause of the form
35+
/// `Implemented(T0: Trait) :- Implemented(U0: Trait) .. Implemented(Un: Trait)`
36+
pub fn needs_impl_for_tys<I: Interner>(
37+
db: &dyn RustIrDatabase<I>,
38+
builder: &mut ClauseBuilder<'_, I>,
39+
trait_ref: &TraitRef<I>,
40+
tys: impl Iterator<Item = Ty<I>>,
41+
) {
42+
// The trait must take one parameter (a type)
43+
debug_assert_eq!(
44+
db.trait_datum(trait_ref.trait_id)
45+
.binders
46+
.len(db.interner()),
47+
1,
48+
);
49+
builder.push_clause(
50+
trait_ref.clone(),
51+
tys.map(|ty| TraitRef {
52+
trait_id: trait_ref.trait_id,
53+
substitution: Substitution::from1(db.interner(), ty),
54+
}),
55+
);
56+
}

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,32 @@
1+
use crate::clauses::builtin_traits::needs_impl_for_tys;
12
use crate::clauses::ClauseBuilder;
23
use crate::{Interner, RustIrDatabase, TraitRef};
3-
use chalk_ir::TyData;
4+
use chalk_ir::{ApplicationTy, Substitution, TyData, TypeName};
5+
6+
fn push_tuple_copy_conditions<I: Interner>(
7+
db: &dyn RustIrDatabase<I>,
8+
builder: &mut ClauseBuilder<'_, I>,
9+
trait_ref: &TraitRef<I>,
10+
arity: usize,
11+
substitution: &Substitution<I>,
12+
) {
13+
// Empty tuples are always Copy
14+
if arity == 0 {
15+
builder.push_fact(trait_ref.clone());
16+
return;
17+
}
18+
19+
let interner = db.interner();
20+
21+
needs_impl_for_tys(
22+
db,
23+
builder,
24+
trait_ref,
25+
substitution
26+
.iter(interner)
27+
.map(|param| param.ty(interner).unwrap().clone()),
28+
);
29+
}
430

531
pub fn add_copy_program_clauses<I: Interner>(
632
db: &dyn RustIrDatabase<I>,
@@ -11,6 +37,12 @@ pub fn add_copy_program_clauses<I: Interner>(
1137
let _interner = db.interner();
1238

1339
match ty {
40+
TyData::Apply(ApplicationTy { name, substitution }) => match name {
41+
TypeName::Tuple(arity) => {
42+
push_tuple_copy_conditions(db, builder, trait_ref, *arity, substitution)
43+
}
44+
_ => return,
45+
},
1446
TyData::Function(_) => builder.push_fact(trait_ref.clone()),
1547
// TODO(areredify)
1648
// when #368 lands, extend this to handle everything accordingly
Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,17 @@
11
use std::iter;
22

3+
use crate::clauses::builtin_traits::needs_impl_for_tys;
34
use crate::clauses::ClauseBuilder;
45
use crate::{Interner, RustIrDatabase, TraitRef};
5-
use chalk_ir::{ApplicationTy, Substitution, TyData, TypeName};
6+
use chalk_ir::{ApplicationTy, StructId, Substitution, TyData, TypeName};
67

7-
pub fn add_sized_program_clauses<I: Interner>(
8+
fn push_struct_sized_conditions<I: Interner>(
89
db: &dyn RustIrDatabase<I>,
910
builder: &mut ClauseBuilder<'_, I>,
1011
trait_ref: &TraitRef<I>,
11-
ty: &TyData<I>,
12+
struct_id: StructId<I>,
13+
substitution: &Substitution<I>,
1214
) {
13-
let interner = db.interner();
14-
15-
let (struct_id, substitution) = match ty {
16-
TyData::Apply(ApplicationTy {
17-
name: TypeName::Struct(struct_id),
18-
substitution,
19-
}) => (*struct_id, substitution),
20-
// TODO(areredify)
21-
// when #368 lands, extend this to handle everything accordingly
22-
_ => return,
23-
};
24-
2515
let struct_datum = db.struct_datum(struct_id);
2616

2717
// Structs with no fields are always Sized
@@ -30,16 +20,66 @@ pub fn add_sized_program_clauses<I: Interner>(
3020
return;
3121
}
3222

23+
let interner = db.interner();
24+
3325
// To check if a struct type S<..> is Sized, we only have to look at its last field.
3426
// This is because the WF checks for structs require that all the other fields must be Sized.
3527
let last_field_ty = struct_datum
3628
.binders
3729
.map_ref(|b| b.fields.last().unwrap())
3830
.substitute(interner, substitution);
3931

40-
let last_field_sized_goal = TraitRef {
41-
trait_id: trait_ref.trait_id,
42-
substitution: Substitution::from1(interner, last_field_ty),
43-
};
44-
builder.push_clause(trait_ref.clone(), iter::once(last_field_sized_goal));
32+
needs_impl_for_tys(db, builder, trait_ref, iter::once(last_field_ty));
33+
}
34+
35+
fn push_tuple_sized_conditions<I: Interner>(
36+
db: &dyn RustIrDatabase<I>,
37+
builder: &mut ClauseBuilder<'_, I>,
38+
trait_ref: &TraitRef<I>,
39+
arity: usize,
40+
substitution: &Substitution<I>,
41+
) {
42+
// Empty tuples are always Sized
43+
if arity == 0 {
44+
builder.push_fact(trait_ref.clone());
45+
return;
46+
}
47+
48+
let interner = db.interner();
49+
50+
// To check if a tuple is Sized, we only have to look at its last element.
51+
// This is because the WF checks for tuples require that all the other elements must be Sized.
52+
let last_elem_ty = substitution
53+
.iter(interner)
54+
.last()
55+
.unwrap()
56+
.ty(interner)
57+
.unwrap()
58+
.clone();
59+
60+
needs_impl_for_tys(db, builder, trait_ref, iter::once(last_elem_ty));
61+
}
62+
63+
pub fn add_sized_program_clauses<I: Interner>(
64+
db: &dyn RustIrDatabase<I>,
65+
builder: &mut ClauseBuilder<'_, I>,
66+
trait_ref: &TraitRef<I>,
67+
ty: &TyData<I>,
68+
) {
69+
match ty {
70+
TyData::Apply(ApplicationTy { name, substitution }) => match name {
71+
TypeName::Struct(struct_id) => {
72+
push_struct_sized_conditions(db, builder, trait_ref, *struct_id, substitution)
73+
}
74+
TypeName::Scalar(_) => builder.push_fact(trait_ref.clone()),
75+
TypeName::Tuple(arity) => {
76+
push_tuple_sized_conditions(db, builder, trait_ref, *arity, substitution)
77+
}
78+
_ => return,
79+
},
80+
TyData::Function(_) => builder.push_fact(trait_ref.clone()),
81+
// TODO(areredify)
82+
// when #368 lands, extend this to handle everything accordingly
83+
_ => return,
84+
}
4585
}

tests/test/functions.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use super::*;
2+
3+
#[test]
4+
fn functions_are_sized() {
5+
test! {
6+
program {
7+
#[lang(sized)]
8+
trait Sized { }
9+
10+
trait Copy {}
11+
}
12+
13+
goal {
14+
fn(()): Sized
15+
} yields {
16+
"Unique; substitution [], lifetime constraints []"
17+
}
18+
19+
goal {
20+
fn(dyn Copy): Sized
21+
} yields {
22+
"Unique; substitution [], lifetime constraints []"
23+
}
24+
}
25+
}

tests/test/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ mod coherence_goals;
309309
mod coinduction;
310310
mod cycle;
311311
mod existential_types;
312+
mod functions;
312313
mod implied_bounds;
313314
mod impls;
314315
mod misc;

tests/test/scalars.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,29 @@ fn scalars_are_well_formed() {
136136
goal { WellFormed(char) } yields { "Unique" }
137137
}
138138
}
139+
140+
#[test]
141+
fn scalars_are_sized() {
142+
test! {
143+
program {
144+
#[lang(sized)] trait Sized { }
145+
}
146+
147+
goal { i8: Sized } yields { "Unique" }
148+
goal { i16: Sized } yields { "Unique" }
149+
goal { i32: Sized } yields { "Unique" }
150+
goal { i64: Sized } yields { "Unique" }
151+
goal { i128: Sized } yields { "Unique" }
152+
goal { isize: Sized } yields { "Unique" }
153+
goal { u8: Sized } yields { "Unique" }
154+
goal { u16: Sized } yields { "Unique" }
155+
goal { u32: Sized } yields { "Unique" }
156+
goal { u64: Sized } yields { "Unique" }
157+
goal { u128: Sized } yields { "Unique" }
158+
goal { usize: Sized } yields { "Unique" }
159+
goal { f32: Sized } yields { "Unique" }
160+
goal { f64: Sized } yields { "Unique" }
161+
goal { bool: Sized } yields { "Unique" }
162+
goal { char: Sized } yields { "Unique" }
163+
}
164+
}

0 commit comments

Comments
 (0)