From 2a96aa300242da76faf49a89ee1974628961c88d Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Fri, 18 Sep 2020 18:52:40 +0200 Subject: [PATCH 01/14] Extend push_auto_trait_impl to a few built-in types --- chalk-integration/src/db.rs | 14 ++- chalk-integration/src/program.rs | 38 +++++-- chalk-integration/src/query.rs | 8 +- chalk-solve/src/clauses.rs | 172 ++++++++++++++++++++++++------- chalk-solve/src/display/stub.rs | 2 +- chalk-solve/src/lib.rs | 9 +- chalk-solve/src/logging_db.rs | 10 +- 7 files changed, 192 insertions(+), 61 deletions(-) diff --git a/chalk-integration/src/db.rs b/chalk-integration/src/db.rs index 3d1f05a6026..89175b389fe 100644 --- a/chalk-integration/src/db.rs +++ b/chalk-integration/src/db.rs @@ -7,9 +7,9 @@ use crate::{ tls, SolverChoice, }; use chalk_ir::{ - AdtId, AssocTypeId, Binders, Canonical, CanonicalVarKinds, ClosureId, ConstrainedSubst, - Environment, FnDefId, GenericArg, Goal, ImplId, InEnvironment, OpaqueTyId, ProgramClause, - ProgramClauses, Substitution, TraitId, Ty, UCanonical, + AdtId, ApplicationTy, AssocTypeId, Binders, Canonical, CanonicalVarKinds, ClosureId, + ConstrainedSubst, Environment, FnDefId, GenericArg, Goal, ImplId, InEnvironment, OpaqueTyId, + ProgramClause, ProgramClauses, Substitution, TraitId, Ty, UCanonical, }; use chalk_solve::rust_ir::{ AdtDatum, AdtRepr, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, ClosureKind, @@ -131,10 +131,14 @@ impl RustIrDatabase for ChalkDatabase { .local_impls_to_coherence_check(trait_id) } - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { + fn impl_provided_for( + &self, + auto_trait_id: TraitId, + app_ty: &ApplicationTy, + ) -> bool { self.program_ir() .unwrap() - .impl_provided_for(auto_trait_id, adt_id) + .impl_provided_for(auto_trait_id, app_ty) } fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option> { diff --git a/chalk-integration/src/program.rs b/chalk-integration/src/program.rs index de12b0875bc..76a3017754e 100644 --- a/chalk-integration/src/program.rs +++ b/chalk-integration/src/program.rs @@ -6,7 +6,7 @@ use chalk_ir::{ debug::SeparatorTraitRef, AdtId, AliasTy, ApplicationTy, AssocTypeId, Binders, CanonicalVarKinds, ClosureId, FnDefId, ForeignDefId, GenericArg, Goal, Goals, ImplId, Lifetime, OpaqueTy, OpaqueTyId, ProgramClause, ProgramClauseImplication, ProgramClauses, ProjectionTy, - Substitution, TraitId, Ty, + Substitution, TraitId, Ty, TyData, }; use chalk_solve::rust_ir::{ AdtDatum, AdtRepr, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, ClosureKind, @@ -422,14 +422,36 @@ impl RustIrDatabase for Program { .collect() } - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { + fn impl_provided_for( + &self, + auto_trait_id: TraitId, + app_ty: &ApplicationTy, + ) -> bool { let interner = self.interner(); - // Look for an impl like `impl Send for Foo` where `Foo` is - // the ADT. See `push_auto_trait_impls` for more. - self.impl_data.values().any(|impl_datum| { - impl_datum.trait_id() == auto_trait_id - && impl_datum.self_type_adt_id(interner) == Some(adt_id) - }) + + // an iterator containing the `ApplicationTy`s which have an impl for the trait `auto_trait_id`. + let mut impl_app_tys = self.impl_data.values().filter_map(|impl_datum| { + if impl_datum.trait_id() != auto_trait_id { + return None; + } + + let ty = impl_datum + .binders + .skip_binders() + .trait_ref + .self_type_parameter(interner); + match ty.data(interner) { + TyData::Apply(app) => Some(app.clone()), + _ => None, + } + }); + + // we only compare the `TypeName`s as + // - given a `struct S`; an implementation for `S` should suppress an auto impl for `S`, and + // - an implementation for `[A]` should suppress an auto impl for `[B]`, and + // - an implementation for `(A, B, C)` should suppress an auto impl for `(D, E, F)` + // this may change later + impl_app_tys.any(|x| x.name == app_ty.name) } fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option> { diff --git a/chalk-integration/src/query.rs b/chalk-integration/src/query.rs index d35120da445..704dea5ead5 100644 --- a/chalk-integration/src/query.rs +++ b/chalk-integration/src/query.rs @@ -8,7 +8,7 @@ use crate::program::Program; use crate::program_environment::ProgramEnvironment; use crate::tls; use crate::SolverChoice; -use chalk_ir::TraitId; +use chalk_ir::{ApplicationTy, Substitution, TraitId, TypeName}; use chalk_solve::clauses::builder::ClauseBuilder; use chalk_solve::clauses::program_clauses::ToProgramClauses; use chalk_solve::coherence::orphan; @@ -225,7 +225,11 @@ fn environment(db: &dyn LoweringDatabase) -> Result, Cha .filter(|(_, auto_trait)| auto_trait.is_auto_trait()) { for &adt_id in program.adt_data.keys() { - chalk_solve::clauses::push_auto_trait_impls(builder, auto_trait_id, adt_id); + let app_ty = ApplicationTy { + name: TypeName::Adt(adt_id), + substitution: Substitution::empty(builder.interner()), + }; + chalk_solve::clauses::push_auto_trait_impls(builder, auto_trait_id, &app_ty); } } diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index afb6a256bef..4c18c694517 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -53,9 +53,8 @@ pub mod program_clauses; pub fn push_auto_trait_impls( builder: &mut ClauseBuilder<'_, I>, auto_trait_id: TraitId, - adt_id: AdtId, + app_ty: &ApplicationTy, ) { - let adt_datum = &builder.db.adt_datum(adt_id); let interner = builder.interner(); // Must be an auto trait. @@ -70,41 +69,147 @@ pub fn push_auto_trait_impls( // If there is a `impl AutoTrait for Foo<..>` or `impl !AutoTrait // for Foo<..>`, where `Foo` is the adt we're looking at, then // we don't generate our own rules. - if builder.db.impl_provided_for(auto_trait_id, adt_id) { + if builder.db.impl_provided_for(auto_trait_id, app_ty) { debug!("impl provided"); return; } - let binders = adt_datum.binders.map_ref(|b| &b.variants); - builder.push_binders(&binders, |builder, variants| { - let self_ty: Ty<_> = ApplicationTy { - name: adt_id.cast(interner), - substitution: builder.substitution_in_scope(), + // we assume that the builder has no binders so far. + assert!(builder.placeholders_in_scope().is_empty()); + + match app_ty.name { + TypeName::Adt(adt_id) => { + let adt_datum = &builder.db.adt_datum(adt_id); + + let binders = adt_datum.binders.map_ref(|b| &b.variants); + builder.push_binders(&binders, |builder, variants| { + let self_ty: Ty<_> = ApplicationTy { + name: adt_id.cast(interner), + substitution: builder.substitution_in_scope(), + } + .intern(interner); + + // trait_ref = `MyStruct<...>: MyAutoTrait` + let auto_trait_ref = TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, self_ty), + }; + + // forall { // generic parameters from struct + // MyStruct<...>: MyAutoTrait :- + // Field0: MyAutoTrait, + // ... + // FieldN: MyAutoTrait + // } + builder.push_clause( + auto_trait_ref, + variants.iter().flat_map(|variant| { + variant.fields.iter().map(|field_ty| TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, field_ty.clone()), + }) + }), + ); + }); } - .intern(interner); + TypeName::Array => { + let len_type: Ty<_> = ApplicationTy { + name: TypeName::Scalar(Scalar::Uint(UintTy::U32)), + substitution: Substitution::empty(interner), + } + .intern(interner); + let varkinds_iter = iter::once(VariableKind::Ty(TyKind::General)) + .chain(iter::once(VariableKind::Const(len_type))); + let binders = Binders::new( + VariableKinds::from_iter(interner, varkinds_iter), + std::marker::PhantomData::, + ); + + builder.push_binders(&binders, |builder, _| { + let sub = builder.substitution_in_scope(); + let arg: GenericArg<_> = sub.at(interner, 0).clone(); + + // self_ty = [P; n] + let self_ty: GenericArg<_> = ApplicationTy { + name: TypeName::Array, + substitution: sub, + } + .intern(interner) + .cast(interner); - // trait_ref = `MyStruct<...>: MyAutoTrait` - let auto_trait_ref = TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, self_ty), - }; + // consequence = `[P; n]: MyAutoTrait` + let consequence = TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, self_ty), + }; - // forall { // generic parameters from struct - // MyStruct<...>: MyAutoTrait :- - // Field0: MyAutoTrait, - // ... - // FieldN: MyAutoTrait - // } - builder.push_clause( - auto_trait_ref, - variants.iter().flat_map(|variant| { - variant.fields.iter().map(|field_ty| TraitRef { + // condition = `P: MyAutoTrait` + let condition = TraitRef { trait_id: auto_trait_id, - substitution: Substitution::from1(interner, field_ty.clone()), - }) - }), - ); - }); + substitution: Substitution::from1(interner, arg), + }; + + // forall { + // [P; n]: MyAutoTrait :- P: MyAutoTrait + // } + builder.push_clause(consequence, iter::once(condition)); + }); + } + // non-atomic TypeName-variants which implement AutoTrait if and only if all types from `app_ty.substitution` implement AutoTrait + tn @ TypeName::Tuple(_) | tn @ TypeName::Slice | tn @ TypeName::Raw(_) => { + let n = app_ty.substitution.len(interner); + let binders = Binders::new( + VariableKinds::from_iter( + interner, + iter::repeat(VariableKind::Ty(TyKind::General)).take(n), + ), + std::marker::PhantomData::, + ); + builder.push_binders(&binders, |builder, _| { + let sub = builder.substitution_in_scope(); + + let self_ty: GenericArg<_> = ApplicationTy { + name: tn, + substitution: sub.clone(), + } + .intern(interner) + .cast(interner); + + let consequence = TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, self_ty), + }; + + let conditions = sub.iter(interner).map(|x| TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, x.clone()), + }); + + // forall { (P0, ..., Pn): MyAutoTrait :- P0: MyAutoTrait, ..., Pn: MyAutoTrait } + // forall

{ [P]: MyAutoTrait :- P: MyAutoTrait } + // forall

{ *const P: MyAutoTrait :- P: MyAutoTrait } + builder.push_clause(consequence, conditions); + }); + } + // atomic TypeName-variants + TypeName::Scalar(_) | TypeName::Str | TypeName::Never | TypeName::FnDef(_) => { + let self_ty: GenericArg<_> = app_ty.clone().intern(interner).cast(interner); + let auto_trait_ref = TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, self_ty), + }; + + builder.push_fact(auto_trait_ref); + } + TypeName::Ref(_) => { + unimplemented!(); + } + TypeName::AssociatedType(_) => unimplemented!(), + TypeName::Closure(_) => unimplemented!(), + TypeName::OpaqueType(_) => unimplemented!(), + TypeName::Foreign(_) => unimplemented!(), + TypeName::Error => {} + } } /// Leak auto traits for opaque types, just like `push_auto_trait_impls` does for structs. @@ -254,12 +359,9 @@ fn program_clauses_that_could_match( let trait_datum = db.trait_datum(trait_id); if trait_datum.is_auto_trait() { match trait_ref.self_type_parameter(interner).data(interner) { - TyData::Apply(apply) => match &apply.name { - TypeName::Adt(adt_id) => { - push_auto_trait_impls(builder, trait_id, *adt_id); - } - _ => {} - }, + TyData::Apply(apply) => { + push_auto_trait_impls(builder, trait_id, apply); + } TyData::InferenceVar(_, _) | TyData::BoundVar(_) => { return Err(Floundered); } diff --git a/chalk-solve/src/display/stub.rs b/chalk-solve/src/display/stub.rs index 2c433578c22..2ad5791d499 100644 --- a/chalk-solve/src/display/stub.rs +++ b/chalk-solve/src/display/stub.rs @@ -156,7 +156,7 @@ impl> RustIrDatabase for StubWrapper<'_, D fn impl_provided_for( &self, _auto_trait_id: chalk_ir::TraitId, - _adt_id: chalk_ir::AdtId, + _app_ty: &chalk_ir::ApplicationTy, ) -> bool { // We panic here because the returned ids may not be collected, // resulting in unresolvable names. diff --git a/chalk-solve/src/lib.rs b/chalk-solve/src/lib.rs index 0c6d300959e..583595e11c7 100644 --- a/chalk-solve/src/lib.rs +++ b/chalk-solve/src/lib.rs @@ -101,12 +101,11 @@ pub trait RustIrDatabase: Debug { fn local_impls_to_coherence_check(&self, trait_id: TraitId) -> Vec>; /// Returns true if there is an explicit impl of the auto trait - /// `auto_trait_id` for the ADT `adt_id`. This is part of + /// `auto_trait_id` for the type `app_ty`. This is part of /// the auto trait handling -- if there is no explicit impl given - /// by the user for the struct, then we provide default impls - /// based on the field types (otherwise, we rely on the impls the - /// user gave). - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool; + /// by the user for `app_ty`, then we provide default impls + /// (otherwise, we rely on the impls the user gave). + fn impl_provided_for(&self, auto_trait_id: TraitId, app_ty: &ApplicationTy) -> bool; /// Returns id of a trait lang item, if found fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option>; diff --git a/chalk-solve/src/logging_db.rs b/chalk-solve/src/logging_db.rs index 52279110dbe..78f36cdb5ce 100644 --- a/chalk-solve/src/logging_db.rs +++ b/chalk-solve/src/logging_db.rs @@ -166,10 +166,10 @@ where self.ws.db().local_impls_to_coherence_check(trait_id) } - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { + fn impl_provided_for(&self, auto_trait_id: TraitId, app_ty: &ApplicationTy) -> bool { self.record(auto_trait_id); - self.record(adt_id); - self.ws.db().impl_provided_for(auto_trait_id, adt_id) + // TODO record app_ty + self.ws.db().impl_provided_for(auto_trait_id, app_ty) } fn well_known_trait_id( @@ -379,8 +379,8 @@ where self.db.local_impls_to_coherence_check(trait_id) } - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { - self.db.impl_provided_for(auto_trait_id, adt_id) + fn impl_provided_for(&self, auto_trait_id: TraitId, app_ty: &ApplicationTy) -> bool { + self.db.impl_provided_for(auto_trait_id, app_ty) } fn well_known_trait_id( From e87aa6d9e83788c49eebb330512f5f1e5d33da68 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Fri, 18 Sep 2020 18:57:56 +0200 Subject: [PATCH 02/14] Fix test --- tests/display/unique_names.rs | 4 ++-- tests/integration/panic.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/display/unique_names.rs b/tests/display/unique_names.rs index 60a8ccdb6df..a645ffd18a0 100644 --- a/tests/display/unique_names.rs +++ b/tests/display/unique_names.rs @@ -122,9 +122,9 @@ where fn impl_provided_for( &self, auto_trait_id: chalk_ir::TraitId, - adt_id: chalk_ir::AdtId, + app_ty: &chalk_ir::ApplicationTy, ) -> bool { - self.db.impl_provided_for(auto_trait_id, adt_id) + self.db.impl_provided_for(auto_trait_id, app_ty) } fn well_known_trait_id( &self, diff --git a/tests/integration/panic.rs b/tests/integration/panic.rs index c02dcf881ef..70bb366f56f 100644 --- a/tests/integration/panic.rs +++ b/tests/integration/panic.rs @@ -176,7 +176,7 @@ impl RustIrDatabase for MockDatabase { fn impl_provided_for( &self, auto_trait_id: TraitId, - struct_id: AdtId, + app_ty: &ApplicationTy, ) -> bool { unimplemented!() } From 6bd2da5b435a01e3d2d489ccbf1747f6269594aa Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Fri, 18 Sep 2020 22:07:58 +0200 Subject: [PATCH 03/14] Add `consistuent_types` --- chalk-solve/src/clauses.rs | 179 ++++++++++--------------------------- 1 file changed, 48 insertions(+), 131 deletions(-) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index 4c18c694517..02fdc3773d3 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -18,6 +18,45 @@ mod env_elaborator; mod generalize; pub mod program_clauses; +// yields the types "contained" in `app_ty` +fn consistuent_types( + db: &dyn RustIrDatabase, + app_ty: &ApplicationTy, +) -> Vec> { + let interner = db.interner(); + match app_ty.name { + TypeName::Adt(adt_id) => { + let adt_datum = &db.adt_datum(adt_id); + let adt_datum_bound = adt_datum.binders.substitute(interner, &app_ty.substitution); + adt_datum_bound + .variants + .into_iter() + .map(|variant| variant.fields.into_iter()) + .flatten() + .collect() + } + TypeName::Array + | TypeName::Tuple(_) + | TypeName::Slice + | TypeName::Raw(_) + | TypeName::Ref(_) + | TypeName::Scalar(_) + | TypeName::Str + | TypeName::Never + | TypeName::FnDef(_) => app_ty + .substitution + .iter(interner) + .filter_map(|x| x.ty(interner)) + .cloned() + .collect(), + TypeName::AssociatedType(_) => unimplemented!(), + TypeName::Closure(_) => unimplemented!(), + TypeName::OpaqueType(_) => unimplemented!(), + TypeName::Foreign(_) => unimplemented!(), + TypeName::Error => Vec::new(), + } +} + /// FIXME(#505) update comments for ADTs /// For auto-traits, we generate a default rule for every struct, /// unless there is a manual impl for that struct given explicitly. @@ -77,139 +116,17 @@ pub fn push_auto_trait_impls( // we assume that the builder has no binders so far. assert!(builder.placeholders_in_scope().is_empty()); - match app_ty.name { - TypeName::Adt(adt_id) => { - let adt_datum = &builder.db.adt_datum(adt_id); + let mk_ref = |ty: Ty| TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, ty.cast(interner)), + }; + let consequence = mk_ref(app_ty.clone().intern(interner)); - let binders = adt_datum.binders.map_ref(|b| &b.variants); - builder.push_binders(&binders, |builder, variants| { - let self_ty: Ty<_> = ApplicationTy { - name: adt_id.cast(interner), - substitution: builder.substitution_in_scope(), - } - .intern(interner); - - // trait_ref = `MyStruct<...>: MyAutoTrait` - let auto_trait_ref = TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, self_ty), - }; - - // forall { // generic parameters from struct - // MyStruct<...>: MyAutoTrait :- - // Field0: MyAutoTrait, - // ... - // FieldN: MyAutoTrait - // } - builder.push_clause( - auto_trait_ref, - variants.iter().flat_map(|variant| { - variant.fields.iter().map(|field_ty| TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, field_ty.clone()), - }) - }), - ); - }); - } - TypeName::Array => { - let len_type: Ty<_> = ApplicationTy { - name: TypeName::Scalar(Scalar::Uint(UintTy::U32)), - substitution: Substitution::empty(interner), - } - .intern(interner); - let varkinds_iter = iter::once(VariableKind::Ty(TyKind::General)) - .chain(iter::once(VariableKind::Const(len_type))); - let binders = Binders::new( - VariableKinds::from_iter(interner, varkinds_iter), - std::marker::PhantomData::, - ); - - builder.push_binders(&binders, |builder, _| { - let sub = builder.substitution_in_scope(); - let arg: GenericArg<_> = sub.at(interner, 0).clone(); - - // self_ty = [P; n] - let self_ty: GenericArg<_> = ApplicationTy { - name: TypeName::Array, - substitution: sub, - } - .intern(interner) - .cast(interner); - - // consequence = `[P; n]: MyAutoTrait` - let consequence = TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, self_ty), - }; - - // condition = `P: MyAutoTrait` - let condition = TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, arg), - }; - - // forall { - // [P; n]: MyAutoTrait :- P: MyAutoTrait - // } - builder.push_clause(consequence, iter::once(condition)); - }); - } - // non-atomic TypeName-variants which implement AutoTrait if and only if all types from `app_ty.substitution` implement AutoTrait - tn @ TypeName::Tuple(_) | tn @ TypeName::Slice | tn @ TypeName::Raw(_) => { - let n = app_ty.substitution.len(interner); - let binders = Binders::new( - VariableKinds::from_iter( - interner, - iter::repeat(VariableKind::Ty(TyKind::General)).take(n), - ), - std::marker::PhantomData::, - ); - builder.push_binders(&binders, |builder, _| { - let sub = builder.substitution_in_scope(); - - let self_ty: GenericArg<_> = ApplicationTy { - name: tn, - substitution: sub.clone(), - } - .intern(interner) - .cast(interner); - - let consequence = TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, self_ty), - }; - - let conditions = sub.iter(interner).map(|x| TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, x.clone()), - }); - - // forall { (P0, ..., Pn): MyAutoTrait :- P0: MyAutoTrait, ..., Pn: MyAutoTrait } - // forall

{ [P]: MyAutoTrait :- P: MyAutoTrait } - // forall

{ *const P: MyAutoTrait :- P: MyAutoTrait } - builder.push_clause(consequence, conditions); - }); - } - // atomic TypeName-variants - TypeName::Scalar(_) | TypeName::Str | TypeName::Never | TypeName::FnDef(_) => { - let self_ty: GenericArg<_> = app_ty.clone().intern(interner).cast(interner); - let auto_trait_ref = TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, self_ty), - }; + let conditions = consistuent_types(builder.db, app_ty) + .into_iter() + .map(mk_ref); - builder.push_fact(auto_trait_ref); - } - TypeName::Ref(_) => { - unimplemented!(); - } - TypeName::AssociatedType(_) => unimplemented!(), - TypeName::Closure(_) => unimplemented!(), - TypeName::OpaqueType(_) => unimplemented!(), - TypeName::Foreign(_) => unimplemented!(), - TypeName::Error => {} - } + builder.push_clause(consequence, conditions); } /// Leak auto traits for opaque types, just like `push_auto_trait_impls` does for structs. From 85f93c97e78f9cde94cc06f8c47bfb2a032215b4 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Fri, 18 Sep 2020 22:26:53 +0200 Subject: [PATCH 04/14] Use flat_map(...) instead of map(...).flatten() --- chalk-solve/src/clauses.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index 02fdc3773d3..6d162125fcb 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -31,8 +31,7 @@ fn consistuent_types( adt_datum_bound .variants .into_iter() - .map(|variant| variant.fields.into_iter()) - .flatten() + .flat_map(|variant| variant.fields.into_iter()) .collect() } TypeName::Array From ef0b55bfd18a63e131d0922c870b79cbbcdcc929 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Fri, 18 Sep 2020 22:37:43 +0200 Subject: [PATCH 05/14] Typo --- chalk-solve/src/clauses.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index 6d162125fcb..fdd311639c8 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -19,7 +19,7 @@ mod generalize; pub mod program_clauses; // yields the types "contained" in `app_ty` -fn consistuent_types( +fn constituent_types( db: &dyn RustIrDatabase, app_ty: &ApplicationTy, ) -> Vec> { @@ -121,7 +121,7 @@ pub fn push_auto_trait_impls( }; let consequence = mk_ref(app_ty.clone().intern(interner)); - let conditions = consistuent_types(builder.db, app_ty) + let conditions = constituent_types(builder.db, app_ty) .into_iter() .map(mk_ref); From 4aa64303d1653f049de55d4e7a269c762a7e22d1 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Sat, 19 Sep 2020 11:59:52 +0200 Subject: [PATCH 06/14] Auto traits are not implemented for foreign types --- chalk-solve/src/clauses.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index fdd311639c8..fb47c505fb6 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -48,11 +48,11 @@ fn constituent_types( .filter_map(|x| x.ty(interner)) .cloned() .collect(), - TypeName::AssociatedType(_) => unimplemented!(), TypeName::Closure(_) => unimplemented!(), - TypeName::OpaqueType(_) => unimplemented!(), - TypeName::Foreign(_) => unimplemented!(), + TypeName::Foreign(_) => panic!("constituent_types of foreign types are unknown!"), TypeName::Error => Vec::new(), + TypeName::OpaqueType(_) => unimplemented!(), + TypeName::AssociatedType(_) => unimplemented!(), } } @@ -104,6 +104,14 @@ pub fn push_auto_trait_impls( 1 ); + // we assume that the builder has no binders so far. + assert!(builder.placeholders_in_scope().is_empty()); + + // auto traits are not implemented for foreign types + if let TypeName::Foreign(_) = app_ty.name { + return; + } + // If there is a `impl AutoTrait for Foo<..>` or `impl !AutoTrait // for Foo<..>`, where `Foo` is the adt we're looking at, then // we don't generate our own rules. @@ -112,9 +120,6 @@ pub fn push_auto_trait_impls( return; } - // we assume that the builder has no binders so far. - assert!(builder.placeholders_in_scope().is_empty()); - let mk_ref = |ty: Ty| TraitRef { trait_id: auto_trait_id, substitution: Substitution::from1(interner, ty.cast(interner)), From ee8fa77d94f480dd2a280fa334a12303fac17f69 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Sat, 19 Sep 2020 12:21:22 +0200 Subject: [PATCH 07/14] Function types implement auto traits unconditionally --- chalk-solve/src/clauses.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index fb47c505fb6..bebee734ab8 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -279,10 +279,20 @@ fn program_clauses_that_could_match( // the automatic impls for `Foo`. let trait_datum = db.trait_datum(trait_id); if trait_datum.is_auto_trait() { - match trait_ref.self_type_parameter(interner).data(interner) { + let ty = trait_ref.self_type_parameter(interner); + match ty.data(interner) { TyData::Apply(apply) => { push_auto_trait_impls(builder, trait_id, apply); } + // function-types implement auto traits unconditionally + TyData::Function(_) => { + let auto_trait_ref = TraitRef { + trait_id, + substitution: Substitution::from1(interner, ty.cast(interner)), + }; + + builder.push_fact(auto_trait_ref); + } TyData::InferenceVar(_, _) | TyData::BoundVar(_) => { return Err(Floundered); } From 40d4edc1fb8d6cd8f7e06d668d3eda1f6e6c0e76 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Sat, 19 Sep 2020 13:09:57 +0200 Subject: [PATCH 08/14] Implement auto trait handling of closures --- chalk-solve/src/clauses.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index bebee734ab8..c18851a4986 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -24,6 +24,7 @@ fn constituent_types( app_ty: &ApplicationTy, ) -> Vec> { let interner = db.interner(); + match app_ty.name { TypeName::Adt(adt_id) => { let adt_datum = &db.adt_datum(adt_id); @@ -48,7 +49,7 @@ fn constituent_types( .filter_map(|x| x.ty(interner)) .cloned() .collect(), - TypeName::Closure(_) => unimplemented!(), + TypeName::Closure(_) => panic!("this function should not be called for closures"), TypeName::Foreign(_) => panic!("constituent_types of foreign types are unknown!"), TypeName::Error => Vec::new(), TypeName::OpaqueType(_) => unimplemented!(), @@ -124,13 +125,25 @@ pub fn push_auto_trait_impls( trait_id: auto_trait_id, substitution: Substitution::from1(interner, ty.cast(interner)), }; + let consequence = mk_ref(app_ty.clone().intern(interner)); - let conditions = constituent_types(builder.db, app_ty) - .into_iter() - .map(mk_ref); + // closures require binders, while the other types do not + if let TypeName::Closure(closure_id) = app_ty.name { + let binders = builder + .db + .closure_upvars(closure_id, &Substitution::empty(interner)); + builder.push_binders(&binders, |builder, upvar_ty| { + let conditions = iter::once(mk_ref(upvar_ty)); + builder.push_clause(consequence, conditions); + }); + } else { + let conditions = constituent_types(builder.db, app_ty) + .into_iter() + .map(mk_ref); - builder.push_clause(consequence, conditions); + builder.push_clause(consequence, conditions); + } } /// Leak auto traits for opaque types, just like `push_auto_trait_impls` does for structs. From 0604b12145cc49d5df9152d3c7a327bd21accd56 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Sat, 19 Sep 2020 13:53:23 +0200 Subject: [PATCH 09/14] Update book --- book/src/clauses/well_known_traits.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/book/src/clauses/well_known_traits.md b/book/src/clauses/well_known_traits.md index d32b2d2434d..b5cdb76d154 100644 --- a/book/src/clauses/well_known_traits.md +++ b/book/src/clauses/well_known_traits.md @@ -30,20 +30,20 @@ Some common examples of auto traits are `Send` and `Sync`. # Current state | Type | Copy | Clone | Sized | Unsize | Drop | FnOnce/FnMut/Fn | Unpin | Generator | auto traits | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| tuple types | ✅ | ✅ | ✅ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | +| tuple types | ✅ | ✅ | ✅ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | | structs | ⚬ | ⚬ | ✅ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | -| scalar types | 📚 | 📚 | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | -| str | 📚 | 📚 | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | -| never type | 📚 | 📚 | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | +| scalar types | 📚 | 📚 | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | +| str | 📚 | 📚 | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | +| never type | 📚 | 📚 | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | | trait objects | ⚬ | ⚬ | ⚬ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | -| functions defs | ✅ | ✅ | ✅ | ⚬ | ⚬ | ❌ | ⚬ | ⚬ | ❌ | -| functions ptrs | ✅ | ✅ | ✅ | ⚬ | ⚬ | ✅ | ⚬ | ⚬ | ❌ | -| raw ptrs | 📚 | 📚 | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | -| immutable refs | 📚 | 📚 | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | -| mutable refs | ⚬ | ⚬ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | -| slices | ⚬ | ⚬ | ⚬ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | -| arrays | ✅ | ✅ | ✅ | ❌ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | -| closures❌ | ❌ | ❌ | ❌ | ⚬ | ⚬ | ❌ | ⚬ | ⚬ | ❌ | +| functions defs | ✅ | ✅ | ✅ | ⚬ | ⚬ | ❌ | ⚬ | ⚬ | ✅ | +| functions ptrs | ✅ | ✅ | ✅ | ⚬ | ⚬ | ✅ | ⚬ | ⚬ | ✅ | +| raw ptrs | 📚 | 📚 | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | +| immutable refs | 📚 | 📚 | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | +| mutable refs | ⚬ | ⚬ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | +| slices | ⚬ | ⚬ | ⚬ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | +| arrays | ✅ | ✅ | ✅ | ❌ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | +| closures❌ | ❌ | ❌ | ❌ | ⚬ | ⚬ | ❌ | ⚬ | ⚬ | ✅ | | generators❌ | ⚬ | ⚬ | ❌ | ⚬ | ⚬ | ⚬ | ❌ | ❌ | ❌ | | gen. witness❌ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | | ----------- | | | | | | | | | | From fdfce1d871c38fcf8b9084382bde871feaf2c6d8 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Sat, 19 Sep 2020 13:54:49 +0200 Subject: [PATCH 10/14] Add auto trait tests --- tests/test/auto_traits.rs | 109 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/tests/test/auto_traits.rs b/tests/test/auto_traits.rs index 37721676b74..b4d08d8d823 100644 --- a/tests/test/auto_traits.rs +++ b/tests/test/auto_traits.rs @@ -217,3 +217,112 @@ fn enum_auto_trait() { } } } + +#[test] +fn builtin_auto_trait() { + test! { + program { + #[auto] trait AutoTrait {} + struct Struct {} + enum Enum { Var1, Var2 } + fn func(); + + struct Marker {} + impl !AutoTrait for Marker {} + + closure good_closure(self, arg: Marker) -> Marker { i32 } + closure bad_closure(self, arg: i32) -> i32 { Marker } + + extern type Ext; + enum ExtEnum { GoodVariant, BadVariant(Ext) } + } + + goal { + (Struct, Marker): AutoTrait + } + yields { + "No possible solution" + } + + goal { + forall<'a> { (fn(), [(); 1], [()], u32, *const (), str, !, Struct, Enum, func, good_closure, &'a ()): AutoTrait } + } + yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + good_closure: AutoTrait + } + yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + bad_closure: AutoTrait + } + yields { + "No possible solution" + } + + goal { + ExtEnum: AutoTrait + } + yields { + "No possible solution" + } + } +} + +#[test] +fn adt_auto_trait() { + test! { + program { + #[auto] trait AutoTrait {} + struct Yes {} + struct No {} + impl !AutoTrait for No {} + + struct WrapperNo { t: T } + struct WrapperYes { t: T } + + struct X {} + impl !AutoTrait for WrapperNo {} + } + + goal { + Yes: AutoTrait + } + yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + No: AutoTrait + } + yields { + "No possible solution" + } + + goal { + X: AutoTrait + } + yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + WrapperNo: AutoTrait + } + yields { + "No possible solution" + } + + goal { + WrapperYes: AutoTrait + } + yields { + "No possible solution" + } + } +} From c613abdb21a9cf2b388f5c46a7aae2ef0d4f45a5 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Sat, 19 Sep 2020 17:07:53 +0200 Subject: [PATCH 11/14] Fix logging --- chalk-solve/src/logging_db.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chalk-solve/src/logging_db.rs b/chalk-solve/src/logging_db.rs index 78f36cdb5ce..3681e8c2807 100644 --- a/chalk-solve/src/logging_db.rs +++ b/chalk-solve/src/logging_db.rs @@ -168,7 +168,9 @@ where fn impl_provided_for(&self, auto_trait_id: TraitId, app_ty: &ApplicationTy) -> bool { self.record(auto_trait_id); - // TODO record app_ty + if let TypeName::Adt(adt_id) = app_ty.name { + self.record(adt_id); + } self.ws.db().impl_provided_for(auto_trait_id, app_ty) } From d8fe6bc5c411af80cb8206fb57bd515e2932a64b Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Sat, 19 Sep 2020 17:38:22 +0200 Subject: [PATCH 12/14] Cover PhantomData for auto traits --- chalk-solve/src/clauses.rs | 8 ++++++-- tests/test/auto_traits.rs | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index c18851a4986..b8355d7944a 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -26,7 +26,8 @@ fn constituent_types( let interner = db.interner(); match app_ty.name { - TypeName::Adt(adt_id) => { + // For non-phantom_data adts we collect its variants/fields + TypeName::Adt(adt_id) if !db.adt_datum(adt_id).flags.phantom_data => { let adt_datum = &db.adt_datum(adt_id); let adt_datum_bound = adt_datum.binders.substitute(interner, &app_ty.substitution); adt_datum_bound @@ -35,7 +36,9 @@ fn constituent_types( .flat_map(|variant| variant.fields.into_iter()) .collect() } - TypeName::Array + // And for `PhantomData`, we pass `T`. + TypeName::Adt(_) + | TypeName::Array | TypeName::Tuple(_) | TypeName::Slice | TypeName::Raw(_) @@ -49,6 +52,7 @@ fn constituent_types( .filter_map(|x| x.ty(interner)) .cloned() .collect(), + TypeName::Closure(_) => panic!("this function should not be called for closures"), TypeName::Foreign(_) => panic!("constituent_types of foreign types are unknown!"), TypeName::Error => Vec::new(), diff --git a/tests/test/auto_traits.rs b/tests/test/auto_traits.rs index b4d08d8d823..d54a82fa425 100644 --- a/tests/test/auto_traits.rs +++ b/tests/test/auto_traits.rs @@ -326,3 +326,22 @@ fn adt_auto_trait() { } } } + +#[test] +fn phantom_auto_trait() { + test! { + program { + #[auto] trait AutoTrait {} + #[phantom_data] struct PhantomData {} + struct Bad {} + impl !AutoTrait for Bad {} + } + + goal { + PhantomData: AutoTrait + } + yields { + "No possible solution" + } + } +} From 17eb26e790e38629f7289d2fa25462930e2e2fa1 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Sat, 19 Sep 2020 17:58:57 +0200 Subject: [PATCH 13/14] Improve auto trait tests --- tests/test/auto_traits.rs | 83 +++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/tests/test/auto_traits.rs b/tests/test/auto_traits.rs index d54a82fa425..d2901360d77 100644 --- a/tests/test/auto_traits.rs +++ b/tests/test/auto_traits.rs @@ -237,40 +237,63 @@ fn builtin_auto_trait() { enum ExtEnum { GoodVariant, BadVariant(Ext) } } - goal { - (Struct, Marker): AutoTrait - } - yields { - "No possible solution" - } + // The following types only contain AutoTrait-types, and thus implement AutoTrait themselves. + goal { (i32, f32): AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } - goal { - forall<'a> { (fn(), [(); 1], [()], u32, *const (), str, !, Struct, Enum, func, good_closure, &'a ()): AutoTrait } - } - yields { - "Unique; substitution [], lifetime constraints []" - } + goal { [(); 1]: AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } - goal { - good_closure: AutoTrait - } - yields { - "Unique; substitution [], lifetime constraints []" - } + goal { [()]: AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } - goal { - bad_closure: AutoTrait - } - yields { - "No possible solution" - } + goal { u32: AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } - goal { - ExtEnum: AutoTrait - } - yields { - "No possible solution" - } + goal { *const (): AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } + + goal { *mut (): AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } + + goal { forall<'a> { &'a (): AutoTrait } } + yields { "Unique; substitution [], lifetime constraints []" } + + goal { forall<'a> { &'a mut (): AutoTrait } } + yields { "Unique; substitution [], lifetime constraints []" } + + goal { str: AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } + + goal { !: AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } + + goal { Enum: AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } + + goal { func: AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } + + goal { good_closure: AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } + + goal { fn(Marker) -> Marker: AutoTrait } + yields { "Unique; substitution [], lifetime constraints []" } + + + // foreign types do not implement AutoTraits automatically + goal { Ext: AutoTrait } + yields { "No possible solution" } + + // The following types do contain non-AutoTrait types, and thus do not implement AutoTrait. + goal { bad_closure: AutoTrait } + yields { "No possible solution" } + + goal { ExtEnum: AutoTrait } + yields { "No possible solution" } + + goal { (Struct, Marker): AutoTrait } + yields { "No possible solution" } } } From c35689cbe28812e35f03d90478f9fffcd3c9ca67 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Sat, 19 Sep 2020 18:54:21 +0200 Subject: [PATCH 14/14] Simplify edge-case handling --- chalk-solve/src/clauses.rs | 41 ++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index b8355d7944a..ebea5efaf1f 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -112,11 +112,6 @@ pub fn push_auto_trait_impls( // we assume that the builder has no binders so far. assert!(builder.placeholders_in_scope().is_empty()); - // auto traits are not implemented for foreign types - if let TypeName::Foreign(_) = app_ty.name { - return; - } - // If there is a `impl AutoTrait for Foo<..>` or `impl !AutoTrait // for Foo<..>`, where `Foo` is the adt we're looking at, then // we don't generate our own rules. @@ -132,21 +127,29 @@ pub fn push_auto_trait_impls( let consequence = mk_ref(app_ty.clone().intern(interner)); - // closures require binders, while the other types do not - if let TypeName::Closure(closure_id) = app_ty.name { - let binders = builder - .db - .closure_upvars(closure_id, &Substitution::empty(interner)); - builder.push_binders(&binders, |builder, upvar_ty| { - let conditions = iter::once(mk_ref(upvar_ty)); - builder.push_clause(consequence, conditions); - }); - } else { - let conditions = constituent_types(builder.db, app_ty) - .into_iter() - .map(mk_ref); + match app_ty.name { + // auto traits are not implemented for foreign types + TypeName::Foreign(_) => return, + + // closures require binders, while the other types do not + TypeName::Closure(closure_id) => { + let binders = builder + .db + .closure_upvars(closure_id, &Substitution::empty(interner)); + builder.push_binders(&binders, |builder, upvar_ty| { + let conditions = iter::once(mk_ref(upvar_ty)); + builder.push_clause(consequence, conditions); + }); + } + + // app_ty implements AutoTrait if all constituents of app_ty implement AutoTrait + _ => { + let conditions = constituent_types(builder.db, app_ty) + .into_iter() + .map(mk_ref); - builder.push_clause(consequence, conditions); + builder.push_clause(consequence, conditions); + } } }