Skip to content

Commit 9a3d72d

Browse files
committed
Auto merge of #612 - memoryleak47:fix-auto-traits, r=jackh726
Extend push_auto_trait_impl to built-in types cc #604.
2 parents 3ea88b7 + c35689c commit 9a3d72d

File tree

11 files changed

+313
-78
lines changed

11 files changed

+313
-78
lines changed

book/src/clauses/well_known_traits.md

+12-12
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,20 @@ Some common examples of auto traits are `Send` and `Sync`.
3030
# Current state
3131
| Type | Copy | Clone | Sized | Unsize | Drop | FnOnce/FnMut/Fn | Unpin | Generator | auto traits |
3232
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
33-
| tuple types ||||||||| |
33+
| tuple types ||||||||| |
3434
| structs ||||||||||
35-
| scalar types | 📚 | 📚 ||||||| |
36-
| str | 📚 | 📚 ||||||| |
37-
| never type | 📚 | 📚 ||||||| |
35+
| scalar types | 📚 | 📚 ||||||| |
36+
| str | 📚 | 📚 ||||||| |
37+
| never type | 📚 | 📚 ||||||| |
3838
| trait objects ||||||||||
39-
| functions defs ||||||||| |
40-
| functions ptrs ||||||||| |
41-
| raw ptrs | 📚 | 📚 ||||||| |
42-
| immutable refs | 📚 | 📚 ||||||| |
43-
| mutable refs ||||||||| |
44-
| slices ||||||||| |
45-
| arrays ||||||||| |
46-
| closures❌ ||||||||| |
39+
| functions defs ||||||||| |
40+
| functions ptrs ||||||||| |
41+
| raw ptrs | 📚 | 📚 ||||||| |
42+
| immutable refs | 📚 | 📚 ||||||| |
43+
| mutable refs ||||||||| |
44+
| slices ||||||||| |
45+
| arrays ||||||||| |
46+
| closures❌ ||||||||| |
4747
| generators❌ ||||||||||
4848
| gen. witness❌ ||||||||||
4949
| ----------- | | | | | | | | | |

chalk-integration/src/db.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ use crate::{
77
tls, SolverChoice,
88
};
99
use chalk_ir::{
10-
AdtId, AssocTypeId, Binders, Canonical, CanonicalVarKinds, ClosureId, ConstrainedSubst,
11-
Environment, FnDefId, GenericArg, Goal, ImplId, InEnvironment, OpaqueTyId, ProgramClause,
12-
ProgramClauses, Substitution, TraitId, Ty, UCanonical,
10+
AdtId, ApplicationTy, AssocTypeId, Binders, Canonical, CanonicalVarKinds, ClosureId,
11+
ConstrainedSubst, Environment, FnDefId, GenericArg, Goal, ImplId, InEnvironment, OpaqueTyId,
12+
ProgramClause, ProgramClauses, Substitution, TraitId, Ty, UCanonical,
1313
};
1414
use chalk_solve::rust_ir::{
1515
AdtDatum, AdtRepr, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, ClosureKind,
@@ -131,10 +131,14 @@ impl RustIrDatabase<ChalkIr> for ChalkDatabase {
131131
.local_impls_to_coherence_check(trait_id)
132132
}
133133

134-
fn impl_provided_for(&self, auto_trait_id: TraitId<ChalkIr>, adt_id: AdtId<ChalkIr>) -> bool {
134+
fn impl_provided_for(
135+
&self,
136+
auto_trait_id: TraitId<ChalkIr>,
137+
app_ty: &ApplicationTy<ChalkIr>,
138+
) -> bool {
135139
self.program_ir()
136140
.unwrap()
137-
.impl_provided_for(auto_trait_id, adt_id)
141+
.impl_provided_for(auto_trait_id, app_ty)
138142
}
139143

140144
fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option<TraitId<ChalkIr>> {

chalk-integration/src/program.rs

+30-8
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use chalk_ir::{
66
debug::SeparatorTraitRef, AdtId, AliasTy, ApplicationTy, AssocTypeId, Binders,
77
CanonicalVarKinds, ClosureId, FnDefId, ForeignDefId, GenericArg, Goal, Goals, ImplId, Lifetime,
88
OpaqueTy, OpaqueTyId, ProgramClause, ProgramClauseImplication, ProgramClauses, ProjectionTy,
9-
Substitution, TraitId, Ty,
9+
Substitution, TraitId, Ty, TyData,
1010
};
1111
use chalk_solve::rust_ir::{
1212
AdtDatum, AdtRepr, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, ClosureKind,
@@ -422,14 +422,36 @@ impl RustIrDatabase<ChalkIr> for Program {
422422
.collect()
423423
}
424424

425-
fn impl_provided_for(&self, auto_trait_id: TraitId<ChalkIr>, adt_id: AdtId<ChalkIr>) -> bool {
425+
fn impl_provided_for(
426+
&self,
427+
auto_trait_id: TraitId<ChalkIr>,
428+
app_ty: &ApplicationTy<ChalkIr>,
429+
) -> bool {
426430
let interner = self.interner();
427-
// Look for an impl like `impl Send for Foo` where `Foo` is
428-
// the ADT. See `push_auto_trait_impls` for more.
429-
self.impl_data.values().any(|impl_datum| {
430-
impl_datum.trait_id() == auto_trait_id
431-
&& impl_datum.self_type_adt_id(interner) == Some(adt_id)
432-
})
431+
432+
// an iterator containing the `ApplicationTy`s which have an impl for the trait `auto_trait_id`.
433+
let mut impl_app_tys = self.impl_data.values().filter_map(|impl_datum| {
434+
if impl_datum.trait_id() != auto_trait_id {
435+
return None;
436+
}
437+
438+
let ty = impl_datum
439+
.binders
440+
.skip_binders()
441+
.trait_ref
442+
.self_type_parameter(interner);
443+
match ty.data(interner) {
444+
TyData::Apply(app) => Some(app.clone()),
445+
_ => None,
446+
}
447+
});
448+
449+
// we only compare the `TypeName`s as
450+
// - given a `struct S<T>`; an implementation for `S<A>` should suppress an auto impl for `S<B>`, and
451+
// - an implementation for `[A]` should suppress an auto impl for `[B]`, and
452+
// - an implementation for `(A, B, C)` should suppress an auto impl for `(D, E, F)`
453+
// this may change later
454+
impl_app_tys.any(|x| x.name == app_ty.name)
433455
}
434456

435457
fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option<TraitId<ChalkIr>> {

chalk-integration/src/query.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::program::Program;
88
use crate::program_environment::ProgramEnvironment;
99
use crate::tls;
1010
use crate::SolverChoice;
11-
use chalk_ir::TraitId;
11+
use chalk_ir::{ApplicationTy, Substitution, TraitId, TypeName};
1212
use chalk_solve::clauses::builder::ClauseBuilder;
1313
use chalk_solve::clauses::program_clauses::ToProgramClauses;
1414
use chalk_solve::coherence::orphan;
@@ -225,7 +225,11 @@ fn environment(db: &dyn LoweringDatabase) -> Result<Arc<ProgramEnvironment>, Cha
225225
.filter(|(_, auto_trait)| auto_trait.is_auto_trait())
226226
{
227227
for &adt_id in program.adt_data.keys() {
228-
chalk_solve::clauses::push_auto_trait_impls(builder, auto_trait_id, adt_id);
228+
let app_ty = ApplicationTy {
229+
name: TypeName::Adt(adt_id),
230+
substitution: Substitution::empty(builder.interner()),
231+
};
232+
chalk_solve::clauses::push_auto_trait_impls(builder, auto_trait_id, &app_ty);
229233
}
230234
}
231235

chalk-solve/src/clauses.rs

+90-37
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,49 @@ mod env_elaborator;
1818
mod generalize;
1919
pub mod program_clauses;
2020

21+
// yields the types "contained" in `app_ty`
22+
fn constituent_types<I: Interner>(
23+
db: &dyn RustIrDatabase<I>,
24+
app_ty: &ApplicationTy<I>,
25+
) -> Vec<Ty<I>> {
26+
let interner = db.interner();
27+
28+
match app_ty.name {
29+
// For non-phantom_data adts we collect its variants/fields
30+
TypeName::Adt(adt_id) if !db.adt_datum(adt_id).flags.phantom_data => {
31+
let adt_datum = &db.adt_datum(adt_id);
32+
let adt_datum_bound = adt_datum.binders.substitute(interner, &app_ty.substitution);
33+
adt_datum_bound
34+
.variants
35+
.into_iter()
36+
.flat_map(|variant| variant.fields.into_iter())
37+
.collect()
38+
}
39+
// And for `PhantomData<T>`, we pass `T`.
40+
TypeName::Adt(_)
41+
| TypeName::Array
42+
| TypeName::Tuple(_)
43+
| TypeName::Slice
44+
| TypeName::Raw(_)
45+
| TypeName::Ref(_)
46+
| TypeName::Scalar(_)
47+
| TypeName::Str
48+
| TypeName::Never
49+
| TypeName::FnDef(_) => app_ty
50+
.substitution
51+
.iter(interner)
52+
.filter_map(|x| x.ty(interner))
53+
.cloned()
54+
.collect(),
55+
56+
TypeName::Closure(_) => panic!("this function should not be called for closures"),
57+
TypeName::Foreign(_) => panic!("constituent_types of foreign types are unknown!"),
58+
TypeName::Error => Vec::new(),
59+
TypeName::OpaqueType(_) => unimplemented!(),
60+
TypeName::AssociatedType(_) => unimplemented!(),
61+
}
62+
}
63+
2164
/// FIXME(#505) update comments for ADTs
2265
/// For auto-traits, we generate a default rule for every struct,
2366
/// unless there is a manual impl for that struct given explicitly.
@@ -53,9 +96,8 @@ pub mod program_clauses;
5396
pub fn push_auto_trait_impls<I: Interner>(
5497
builder: &mut ClauseBuilder<'_, I>,
5598
auto_trait_id: TraitId<I>,
56-
adt_id: AdtId<I>,
99+
app_ty: &ApplicationTy<I>,
57100
) {
58-
let adt_datum = &builder.db.adt_datum(adt_id);
59101
let interner = builder.interner();
60102

61103
// Must be an auto trait.
@@ -67,44 +109,48 @@ pub fn push_auto_trait_impls<I: Interner>(
67109
1
68110
);
69111

112+
// we assume that the builder has no binders so far.
113+
assert!(builder.placeholders_in_scope().is_empty());
114+
70115
// If there is a `impl AutoTrait for Foo<..>` or `impl !AutoTrait
71116
// for Foo<..>`, where `Foo` is the adt we're looking at, then
72117
// we don't generate our own rules.
73-
if builder.db.impl_provided_for(auto_trait_id, adt_id) {
118+
if builder.db.impl_provided_for(auto_trait_id, app_ty) {
74119
debug!("impl provided");
75120
return;
76121
}
77122

78-
let binders = adt_datum.binders.map_ref(|b| &b.variants);
79-
builder.push_binders(&binders, |builder, variants| {
80-
let self_ty: Ty<_> = ApplicationTy {
81-
name: adt_id.cast(interner),
82-
substitution: builder.substitution_in_scope(),
123+
let mk_ref = |ty: Ty<I>| TraitRef {
124+
trait_id: auto_trait_id,
125+
substitution: Substitution::from1(interner, ty.cast(interner)),
126+
};
127+
128+
let consequence = mk_ref(app_ty.clone().intern(interner));
129+
130+
match app_ty.name {
131+
// auto traits are not implemented for foreign types
132+
TypeName::Foreign(_) => return,
133+
134+
// closures require binders, while the other types do not
135+
TypeName::Closure(closure_id) => {
136+
let binders = builder
137+
.db
138+
.closure_upvars(closure_id, &Substitution::empty(interner));
139+
builder.push_binders(&binders, |builder, upvar_ty| {
140+
let conditions = iter::once(mk_ref(upvar_ty));
141+
builder.push_clause(consequence, conditions);
142+
});
83143
}
84-
.intern(interner);
85144

86-
// trait_ref = `MyStruct<...>: MyAutoTrait`
87-
let auto_trait_ref = TraitRef {
88-
trait_id: auto_trait_id,
89-
substitution: Substitution::from1(interner, self_ty),
90-
};
145+
// app_ty implements AutoTrait if all constituents of app_ty implement AutoTrait
146+
_ => {
147+
let conditions = constituent_types(builder.db, app_ty)
148+
.into_iter()
149+
.map(mk_ref);
91150

92-
// forall<P0..Pn> { // generic parameters from struct
93-
// MyStruct<...>: MyAutoTrait :-
94-
// Field0: MyAutoTrait,
95-
// ...
96-
// FieldN: MyAutoTrait
97-
// }
98-
builder.push_clause(
99-
auto_trait_ref,
100-
variants.iter().flat_map(|variant| {
101-
variant.fields.iter().map(|field_ty| TraitRef {
102-
trait_id: auto_trait_id,
103-
substitution: Substitution::from1(interner, field_ty.clone()),
104-
})
105-
}),
106-
);
107-
});
151+
builder.push_clause(consequence, conditions);
152+
}
153+
}
108154
}
109155

110156
/// Leak auto traits for opaque types, just like `push_auto_trait_impls` does for structs.
@@ -253,13 +299,20 @@ fn program_clauses_that_could_match<I: Interner>(
253299
// the automatic impls for `Foo`.
254300
let trait_datum = db.trait_datum(trait_id);
255301
if trait_datum.is_auto_trait() {
256-
match trait_ref.self_type_parameter(interner).data(interner) {
257-
TyData::Apply(apply) => match &apply.name {
258-
TypeName::Adt(adt_id) => {
259-
push_auto_trait_impls(builder, trait_id, *adt_id);
260-
}
261-
_ => {}
262-
},
302+
let ty = trait_ref.self_type_parameter(interner);
303+
match ty.data(interner) {
304+
TyData::Apply(apply) => {
305+
push_auto_trait_impls(builder, trait_id, apply);
306+
}
307+
// function-types implement auto traits unconditionally
308+
TyData::Function(_) => {
309+
let auto_trait_ref = TraitRef {
310+
trait_id,
311+
substitution: Substitution::from1(interner, ty.cast(interner)),
312+
};
313+
314+
builder.push_fact(auto_trait_ref);
315+
}
263316
TyData::InferenceVar(_, _) | TyData::BoundVar(_) => {
264317
return Err(Floundered);
265318
}

chalk-solve/src/display/stub.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl<I: Interner, DB: RustIrDatabase<I>> RustIrDatabase<I> for StubWrapper<'_, D
156156
fn impl_provided_for(
157157
&self,
158158
_auto_trait_id: chalk_ir::TraitId<I>,
159-
_adt_id: chalk_ir::AdtId<I>,
159+
_app_ty: &chalk_ir::ApplicationTy<I>,
160160
) -> bool {
161161
// We panic here because the returned ids may not be collected,
162162
// resulting in unresolvable names.

chalk-solve/src/lib.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,11 @@ pub trait RustIrDatabase<I: Interner>: Debug {
101101
fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>>;
102102

103103
/// Returns true if there is an explicit impl of the auto trait
104-
/// `auto_trait_id` for the ADT `adt_id`. This is part of
104+
/// `auto_trait_id` for the type `app_ty`. This is part of
105105
/// the auto trait handling -- if there is no explicit impl given
106-
/// by the user for the struct, then we provide default impls
107-
/// based on the field types (otherwise, we rely on the impls the
108-
/// user gave).
109-
fn impl_provided_for(&self, auto_trait_id: TraitId<I>, adt_id: AdtId<I>) -> bool;
106+
/// by the user for `app_ty`, then we provide default impls
107+
/// (otherwise, we rely on the impls the user gave).
108+
fn impl_provided_for(&self, auto_trait_id: TraitId<I>, app_ty: &ApplicationTy<I>) -> bool;
110109

111110
/// Returns id of a trait lang item, if found
112111
fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option<TraitId<I>>;

chalk-solve/src/logging_db.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,12 @@ where
166166
self.ws.db().local_impls_to_coherence_check(trait_id)
167167
}
168168

169-
fn impl_provided_for(&self, auto_trait_id: TraitId<I>, adt_id: AdtId<I>) -> bool {
169+
fn impl_provided_for(&self, auto_trait_id: TraitId<I>, app_ty: &ApplicationTy<I>) -> bool {
170170
self.record(auto_trait_id);
171-
self.record(adt_id);
172-
self.ws.db().impl_provided_for(auto_trait_id, adt_id)
171+
if let TypeName::Adt(adt_id) = app_ty.name {
172+
self.record(adt_id);
173+
}
174+
self.ws.db().impl_provided_for(auto_trait_id, app_ty)
173175
}
174176

175177
fn well_known_trait_id(
@@ -379,8 +381,8 @@ where
379381
self.db.local_impls_to_coherence_check(trait_id)
380382
}
381383

382-
fn impl_provided_for(&self, auto_trait_id: TraitId<I>, adt_id: AdtId<I>) -> bool {
383-
self.db.impl_provided_for(auto_trait_id, adt_id)
384+
fn impl_provided_for(&self, auto_trait_id: TraitId<I>, app_ty: &ApplicationTy<I>) -> bool {
385+
self.db.impl_provided_for(auto_trait_id, app_ty)
384386
}
385387

386388
fn well_known_trait_id(

tests/display/unique_names.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@ where
122122
fn impl_provided_for(
123123
&self,
124124
auto_trait_id: chalk_ir::TraitId<I>,
125-
adt_id: chalk_ir::AdtId<I>,
125+
app_ty: &chalk_ir::ApplicationTy<I>,
126126
) -> bool {
127-
self.db.impl_provided_for(auto_trait_id, adt_id)
127+
self.db.impl_provided_for(auto_trait_id, app_ty)
128128
}
129129
fn well_known_trait_id(
130130
&self,

tests/integration/panic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl RustIrDatabase<ChalkIr> for MockDatabase {
176176
fn impl_provided_for(
177177
&self,
178178
auto_trait_id: TraitId<ChalkIr>,
179-
struct_id: AdtId<ChalkIr>,
179+
app_ty: &ApplicationTy<ChalkIr>,
180180
) -> bool {
181181
unimplemented!()
182182
}

0 commit comments

Comments
 (0)