Skip to content

Commit 5c890e7

Browse files
committed
Handle scalars and tuples for the builtin Sized trait
1 parent 036b2bc commit 5c890e7

File tree

4 files changed

+160
-21
lines changed

4 files changed

+160
-21
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+
}
Lines changed: 59 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,65 @@ 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+
// TODO(areredify)
81+
// when #368 lands, extend this to handle everything accordingly
82+
_ => return,
83+
}
4584
}

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+
}

tests/test/tuples.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,53 @@ fn tuple_trait_impl() {
3434
}
3535
}
3636
}
37+
38+
#[test]
39+
fn tuples_are_sized() {
40+
test! {
41+
program {
42+
#[lang(sized)]
43+
trait Sized { }
44+
45+
trait Foo {}
46+
}
47+
48+
goal {
49+
(dyn Foo,): Sized
50+
} yields {
51+
"No possible solution"
52+
}
53+
54+
goal {
55+
(u8, dyn Foo): Sized
56+
} yields {
57+
"No possible solution"
58+
}
59+
60+
// It should not be well-formed because for tuples, only
61+
// the last element is allowed not to be Sized.
62+
goal {
63+
(dyn Foo, u8): Sized
64+
} yields {
65+
"Unique; substitution [], lifetime constraints []"
66+
}
67+
68+
goal {
69+
(): Sized
70+
} yields {
71+
"Unique; substitution [], lifetime constraints []"
72+
}
73+
74+
goal {
75+
(u8,): Sized
76+
} yields {
77+
"Unique; substitution [], lifetime constraints []"
78+
}
79+
80+
goal {
81+
(u8, u8): Sized
82+
} yields {
83+
"Unique; substitution [], lifetime constraints []"
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)