From 218caa410aa38c29984be31a5229b9fa717560ee Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:13 +0200 Subject: Merging upstream version 1.68.2+dfsg1. Signed-off-by: Daniel Baumann --- .../src/clauses/program_clauses.rs | 921 +++++++++++++++++++++ 1 file changed, 921 insertions(+) create mode 100644 vendor/chalk-solve-0.87.0/src/clauses/program_clauses.rs (limited to 'vendor/chalk-solve-0.87.0/src/clauses/program_clauses.rs') diff --git a/vendor/chalk-solve-0.87.0/src/clauses/program_clauses.rs b/vendor/chalk-solve-0.87.0/src/clauses/program_clauses.rs new file mode 100644 index 000000000..19811ff8b --- /dev/null +++ b/vendor/chalk-solve-0.87.0/src/clauses/program_clauses.rs @@ -0,0 +1,921 @@ +use crate::clauses::builder::ClauseBuilder; +use crate::rust_ir::*; +use crate::split::Split; +use chalk_ir::cast::{Cast, Caster}; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use std::iter; +use tracing::instrument; + +/// Trait for lowering a given piece of rust-ir source (e.g., an impl +/// or struct definition) into its associated "program clauses" -- +/// that is, into the lowered, logical rules that it defines. +pub trait ToProgramClauses { + fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>, environment: &Environment); +} + +impl ToProgramClauses for ImplDatum { + /// Given `impl Clone for Vec { ... }`, generate: + /// + /// ```notrust + /// -- Rule Implemented-From-Impl + /// forall { + /// Implemented(Vec: Clone) :- Implemented(T: Clone). + /// } + /// ``` + /// + /// For a negative impl like `impl... !Clone for ...`, however, we + /// generate nothing -- this is just a way to *opt out* from the + /// default auto trait impls, it doesn't have any positive effect + /// on its own. + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { + if self.is_positive() { + let binders = self.binders.clone(); + builder.push_binders( + binders, + |builder, + ImplDatumBound { + trait_ref, + where_clauses, + }| { + builder.push_clause(trait_ref, where_clauses); + }, + ); + } + } +} + +impl ToProgramClauses for AssociatedTyValue { + /// Given the following trait: + /// + /// ```notrust + /// trait Iterable { + /// type IntoIter<'a>: 'a; + /// } + /// ``` + /// + /// Then for the following impl: + /// ```notrust + /// impl Iterable for Vec where T: Clone { + /// type IntoIter<'a> = Iter<'a, T>; + /// } + /// ``` + /// + /// we generate: + /// + /// ```notrust + /// -- Rule Normalize-From-Impl + /// forall<'a, T> { + /// Normalize( as Iterable>::IntoIter<'a> -> Iter<'a, T>>) :- + /// Implemented(T: Clone), // (1) + /// Implemented(Iter<'a, T>: 'a). // (2) + /// } + /// ``` + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { + let impl_datum = builder.db.impl_datum(self.impl_id); + let associated_ty = builder.db.associated_ty_data(self.associated_ty_id); + + builder.push_binders(self.value.clone(), |builder, assoc_ty_value| { + let all_parameters = builder.placeholders_in_scope().to_vec(); + + // Get the projection for this associated type: + // + // * `impl_params`: `[!T]` + // * `projection`: ` as Iterable>::Iter<'!a>` + let (impl_params, projection) = builder + .db + .impl_parameters_and_projection_from_associated_ty_value(&all_parameters, self); + + // Assemble the full list of conditions for projection to be valid. + // This comes in two parts, marked as (1) and (2) in doc above: + // + // 1. require that the where clauses from the impl apply + let interner = builder.db.interner(); + let impl_where_clauses = impl_datum + .binders + .map_ref(|b| &b.where_clauses) + .into_iter() + .map(|wc| wc.cloned().substitute(interner, impl_params)); + + // 2. any where-clauses from the `type` declaration in the trait: the + // parameters must be substituted with those of the impl + let assoc_ty_where_clauses = associated_ty + .binders + .map_ref(|b| &b.where_clauses) + .into_iter() + .map(|wc| wc.cloned().substitute(interner, &projection.substitution)); + + // Create the final program clause: + // + // ```notrust + // -- Rule Normalize-From-Impl + // forall<'a, T> { + // Normalize( as Iterable>::IntoIter<'a> -> Iter<'a, T>>) :- + // Implemented(T: Clone), // (1) + // Implemented(Iter<'a, T>: 'a). // (2) + // } + // ``` + builder.push_clause( + Normalize { + alias: AliasTy::Projection(projection.clone()), + ty: assoc_ty_value.ty, + }, + impl_where_clauses.chain(assoc_ty_where_clauses), + ); + }); + } +} + +impl ToProgramClauses for OpaqueTyDatum { + /// Given `opaque type T: A + B = HiddenTy where U: C;`, we generate: + /// + /// ```notrust + /// AliasEq(T = HiddenTy) :- Reveal. + /// AliasEq(T = !T). + /// WF(T) :- WF(U: C). + /// Implemented(!T: A). + /// Implemented(!T: B). + /// ``` + /// where `!T<..>` is the placeholder for the unnormalized type `T<..>`. + #[instrument(level = "debug", skip(builder))] + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { + builder.push_binders(self.bound.clone(), |builder, opaque_ty_bound| { + let interner = builder.interner(); + let substitution = builder.substitution_in_scope(); + let alias = AliasTy::Opaque(OpaqueTy { + opaque_ty_id: self.opaque_ty_id, + substitution: substitution.clone(), + }); + + let alias_placeholder_ty = + TyKind::OpaqueType(self.opaque_ty_id, substitution).intern(interner); + + // AliasEq(T<..> = HiddenTy) :- Reveal. + builder.push_clause( + DomainGoal::Holds( + AliasEq { + alias: alias.clone(), + ty: builder.db.hidden_opaque_type(self.opaque_ty_id), + } + .cast(interner), + ), + iter::once(DomainGoal::Reveal), + ); + + // AliasEq(T<..> = !T<..>). + builder.push_fact(DomainGoal::Holds( + AliasEq { + alias, + ty: alias_placeholder_ty.clone(), + } + .cast(interner), + )); + + // WF(!T<..>) :- WF(WC). + builder.push_binders(opaque_ty_bound.where_clauses, |builder, where_clauses| { + builder.push_clause( + WellFormed::Ty(alias_placeholder_ty.clone()), + where_clauses + .into_iter() + .map(|wc| wc.into_well_formed_goal(interner)), + ); + }); + + let substitution = Substitution::from1(interner, alias_placeholder_ty); + for bound in opaque_ty_bound.bounds { + let bound_with_placeholder_ty = bound.substitute(interner, &substitution); + builder.push_binders(bound_with_placeholder_ty, |builder, bound| match &bound { + // For the implemented traits, we need to elaborate super traits and add where clauses from the trait + WhereClause::Implemented(trait_ref) => { + super::super_traits::push_trait_super_clauses( + builder.db, + builder, + trait_ref.clone(), + ) + } + // FIXME: Associated item bindings are just taken as facts (?) + WhereClause::AliasEq(_) => builder.push_fact(bound), + WhereClause::LifetimeOutlives(..) => {} + WhereClause::TypeOutlives(..) => {} + }); + } + }); + } +} + +/// Generates the "well-formed" program clauses for an applicative type +/// with the name `type_name`. For example, given a struct definition: +/// +/// ```ignore +/// struct Foo { } +/// ``` +/// +/// we would generate the clause: +/// +/// ```notrust +/// forall { +/// WF(Foo) :- WF(T: Eq). +/// } +/// ``` +/// +/// # Parameters +/// - builder -- the clause builder. We assume all the generic types from `Foo` are in scope +/// - type_name -- in our example above, the name `Foo` +/// - where_clauses -- the list of where clauses declared on the type (`T: Eq`, in our example) +fn well_formed_program_clauses<'a, I, Wc>( + builder: &'a mut ClauseBuilder<'_, I>, + ty: Ty, + where_clauses: Wc, +) where + I: Interner, + Wc: Iterator>, +{ + let interner = builder.interner(); + builder.push_clause( + WellFormed::Ty(ty), + where_clauses + .cloned() + .map(|qwc| qwc.into_well_formed_goal(interner)), + ); +} + +/// Generates the "fully visible" program clauses for an applicative type +/// with the name `type_name`. For example, given a struct definition: +/// +/// ```ignore +/// struct Foo { } +/// ``` +/// +/// we would generate the clause: +/// +/// ```notrust +/// forall { +/// IsFullyVisible(Foo) :- IsFullyVisible(T). +/// } +/// ``` +/// +/// # Parameters +/// +/// - builder -- the clause builder. We assume all the generic types from `Foo` are in scope +/// - type_name -- in our example above, the name `Foo` +fn fully_visible_program_clauses( + builder: &mut ClauseBuilder<'_, I>, + ty: Ty, + subst: &Substitution, +) where + I: Interner, +{ + let interner = builder.interner(); + builder.push_clause( + DomainGoal::IsFullyVisible(ty), + subst + .type_parameters(interner) + .map(|typ| DomainGoal::IsFullyVisible(typ).cast::>(interner)), + ); +} + +/// Generates the "implied bounds" clauses for an applicative +/// type with the name `type_name`. For example, if `type_name` +/// represents a struct `S` that is declared like: +/// +/// ```ignore +/// struct S where T: Eq { } +/// ``` +/// +/// then we would generate the rule: +/// +/// ```notrust +/// FromEnv(T: Eq) :- FromEnv(S) +/// ``` +/// +/// # Parameters +/// +/// - builder -- the clause builder. We assume all the generic types from `S` are in scope. +/// - type_name -- in our example above, the name `S` +/// - where_clauses -- the list of where clauses declared on the type (`T: Eq`, in our example). +fn implied_bounds_program_clauses<'a, I, Wc>( + builder: &'a mut ClauseBuilder<'_, I>, + ty: &Ty, + where_clauses: Wc, +) where + I: Interner, + Wc: Iterator>, +{ + let interner = builder.interner(); + + for qwc in where_clauses { + builder.push_binders(qwc.clone(), |builder, wc| { + builder.push_clause(wc.into_from_env_goal(interner), Some(ty.clone().from_env())); + }); + } +} + +impl ToProgramClauses for AdtDatum { + /// Given the following type definition: `struct Foo { }`, generate: + /// + /// ```notrust + /// -- Rule WellFormed-Type + /// forall { + /// WF(Foo) :- WF(T: Eq). + /// } + /// + /// -- Rule Implied-Bound-From-Type + /// forall { + /// FromEnv(T: Eq) :- FromEnv(Foo). + /// } + /// + /// forall { + /// IsFullyVisible(Foo) :- IsFullyVisible(T). + /// } + /// ``` + /// + /// If the type `Foo` is marked `#[upstream]`, we also generate: + /// + /// ```notrust + /// forall { IsUpstream(Foo). } + /// ``` + /// + /// Otherwise, if the type `Foo` is not marked `#[upstream]`, we generate: + /// ```notrust + /// forall { IsLocal(Foo). } + /// ``` + /// + /// Given an `#[upstream]` type that is also fundamental: + /// + /// ```notrust + /// #[upstream] + /// #[fundamental] + /// struct Box {} + /// ``` + /// + /// We generate the following clauses: + /// + /// ```notrust + /// forall { IsLocal(Box) :- IsLocal(T). } + /// forall { IsLocal(Box) :- IsLocal(U). } + /// + /// forall { IsUpstream(Box) :- IsUpstream(T), IsUpstream(U). } + /// + /// // Generated for both upstream and local fundamental types + /// forall { DownstreamType(Box) :- DownstreamType(T). } + /// forall { DownstreamType(Box) :- DownstreamType(U). } + /// ``` + /// + #[instrument(level = "debug", skip(builder))] + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { + let interner = builder.interner(); + let binders = self.binders.map_ref(|b| &b.where_clauses).cloned(); + + builder.push_binders(binders, |builder, where_clauses| { + let self_ty = TyKind::Adt(self.id, builder.substitution_in_scope()).intern(interner); + + well_formed_program_clauses(builder, self_ty.clone(), where_clauses.iter()); + + implied_bounds_program_clauses(builder, &self_ty, where_clauses.iter()); + + fully_visible_program_clauses( + builder, + self_ty.clone(), + &builder.substitution_in_scope(), + ); + + // Types that are not marked `#[upstream]` satisfy IsLocal(Ty) + if !self.flags.upstream { + // `IsLocalTy(Ty)` depends *only* on whether the type + // is marked #[upstream] and nothing else + builder.push_fact(DomainGoal::IsLocal(self_ty.clone())); + } else if self.flags.fundamental { + // If a type is `#[upstream]`, but is also + // `#[fundamental]`, it satisfies IsLocal if and only + // if its parameters satisfy IsLocal + for type_param in builder.substitution_in_scope().type_parameters(interner) { + builder.push_clause( + DomainGoal::IsLocal(self_ty.clone()), + Some(DomainGoal::IsLocal(type_param)), + ); + } + builder.push_clause( + DomainGoal::IsUpstream(self_ty.clone()), + builder + .substitution_in_scope() + .type_parameters(interner) + .map(|type_param| DomainGoal::IsUpstream(type_param)), + ); + } else { + // The type is just upstream and not fundamental + builder.push_fact(DomainGoal::IsUpstream(self_ty.clone())); + } + + if self.flags.fundamental { + assert!( + builder + .substitution_in_scope() + .type_parameters(interner) + .count() + >= 1, + "Only fundamental types with type parameters are supported" + ); + for type_param in builder.substitution_in_scope().type_parameters(interner) { + builder.push_clause( + DomainGoal::DownstreamType(self_ty.clone()), + Some(DomainGoal::DownstreamType(type_param)), + ); + } + } + }); + } +} + +impl ToProgramClauses for FnDefDatum { + /// Given the following function definition: `fn bar() where T: Eq`, generate: + /// + /// ```notrust + /// -- Rule WellFormed-Type + /// forall { + /// WF(bar) :- WF(T: Eq) + /// } + /// + /// -- Rule Implied-Bound-From-Type + /// forall { + /// FromEnv(T: Eq) :- FromEnv(bar). + /// } + /// + /// forall { + /// IsFullyVisible(bar) :- IsFullyVisible(T). + /// } + /// ``` + #[instrument(level = "debug", skip(builder))] + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { + let interner = builder.interner(); + let binders = self.binders.map_ref(|b| &b.where_clauses).cloned(); + + builder.push_binders(binders, |builder, where_clauses| { + let ty = TyKind::FnDef(self.id, builder.substitution_in_scope()).intern(interner); + + well_formed_program_clauses(builder, ty.clone(), where_clauses.iter()); + + implied_bounds_program_clauses(builder, &ty, where_clauses.iter()); + + fully_visible_program_clauses(builder, ty, &builder.substitution_in_scope()); + }); + } +} + +impl ToProgramClauses for TraitDatum { + /// Given the following trait declaration: `trait Ord where Self: Eq { ... }`, generate: + /// + /// ```notrust + /// -- Rule WellFormed-TraitRef + /// forall { + /// WF(Self: Ord) :- Implemented(Self: Ord), WF(Self: Eq). + /// } + /// ``` + /// + /// and the reverse rules: + /// + /// ```notrust + /// -- Rule Implemented-From-Env + /// forall { + /// (Self: Ord) :- FromEnv(Self: Ord). + /// } + /// + /// -- Rule Implied-Bound-From-Trait + /// forall { + /// FromEnv(Self: Eq) :- FromEnv(Self: Ord). + /// } + /// ``` + /// + /// As specified in the orphan rules, if a trait is not marked `#[upstream]`, the current crate + /// can implement it for any type. To represent that, we generate: + /// + /// ```notrust + /// // `Ord` would not be `#[upstream]` when compiling `std` + /// forall { LocalImplAllowed(Self: Ord). } + /// ``` + /// + /// For traits that are `#[upstream]` (i.e. not in the current crate), the orphan rules dictate + /// that impls are allowed as long as at least one type parameter is local and each type + /// prior to that is fully visible. That means that each type prior to the first local + /// type cannot contain any of the type parameters of the impl. + /// + /// This rule is fairly complex, so we expand it and generate a program clause for each + /// possible case. This is represented as follows: + /// + /// ```notrust + /// // for `#[upstream] trait Foo where Self: Eq { ... }` + /// forall { + /// LocalImplAllowed(Self: Foo) :- IsLocal(Self). + /// } + /// + /// forall { + /// LocalImplAllowed(Self: Foo) :- + /// IsFullyVisible(Self), + /// IsLocal(T). + /// } + /// + /// forall { + /// LocalImplAllowed(Self: Foo) :- + /// IsFullyVisible(Self), + /// IsFullyVisible(T), + /// IsLocal(U). + /// } + /// + /// forall { + /// LocalImplAllowed(Self: Foo) :- + /// IsFullyVisible(Self), + /// IsFullyVisible(T), + /// IsFullyVisible(U), + /// IsLocal(V). + /// } + /// ``` + /// + /// The overlap check uses compatible { ... } mode to ensure that it accounts for impls that + /// may exist in some other *compatible* world. For every upstream trait, we add a rule to + /// account for the fact that upstream crates are able to compatibly add impls of upstream + /// traits for upstream types. + /// + /// ```notrust + /// // For `#[upstream] trait Foo where Self: Eq { ... }` + /// forall { + /// Implemented(Self: Foo) :- + /// Implemented(Self: Eq), // where clauses + /// Compatible, // compatible modality + /// IsUpstream(Self), + /// IsUpstream(T), + /// IsUpstream(U), + /// IsUpstream(V), + /// CannotProve. // returns ambiguous + /// } + /// ``` + /// + /// In certain situations, this is too restrictive. Consider the following code: + /// + /// ```notrust + /// /* In crate std */ + /// trait Sized { } + /// struct str { } + /// + /// /* In crate bar (depends on std) */ + /// trait Bar { } + /// impl Bar for str { } + /// impl Bar for T where T: Sized { } + /// ``` + /// + /// Here, because of the rules we've defined, these two impls overlap. The std crate is + /// upstream to bar, and thus it is allowed to compatibly implement Sized for str. If str + /// can implement Sized in a compatible future, these two impls definitely overlap since the + /// second impl covers all types that implement Sized. + /// + /// The solution we've got right now is to mark Sized as "fundamental" when it is defined. + /// This signals to the Rust compiler that it can rely on the fact that str does not + /// implement Sized in all contexts. A consequence of this is that we can no longer add an + /// implementation of Sized compatibly for str. This is the trade off you make when defining + /// a fundamental trait. + /// + /// To implement fundamental traits, we simply just do not add the rule above that allows + /// upstream types to implement upstream traits. Fundamental traits are not allowed to + /// compatibly do that. + fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>, environment: &Environment) { + let interner = builder.interner(); + let binders = self.binders.map_ref(|b| &b.where_clauses).cloned(); + builder.push_binders(binders, |builder, where_clauses| { + let trait_ref = chalk_ir::TraitRef { + trait_id: self.id, + substitution: builder.substitution_in_scope(), + }; + + builder.push_clause( + trait_ref.clone().well_formed(), + where_clauses + .iter() + .cloned() + .map(|qwc| qwc.into_well_formed_goal(interner)) + .casted::>(interner) + .chain(Some(trait_ref.clone().cast(interner))), + ); + + // The number of parameters will always be at least 1 + // because of the Self parameter that is automatically + // added to every trait. This is important because + // otherwise the added program clauses would not have any + // conditions. + let type_parameters: Vec<_> = trait_ref.type_parameters(interner).collect(); + + if environment.has_compatible_clause(interner) { + // Note: even though we do check for a `Compatible` clause here, + // we also keep it as a condition for the clauses below, purely + // for logical consistency. But really, it's not needed and could be + // removed. + + // Drop trait can't have downstream implementation because it can only + // be implemented with the same genericity as the struct definition, + // i.e. Drop implementation for `struct S {}` is forced to be + // `impl Drop for S { ... }`. That means that orphan rules + // prevent Drop from being implemented in downstream crates. + if self.well_known != Some(WellKnownTrait::Drop) { + // Add all cases for potential downstream impls that could exist + for i in 0..type_parameters.len() { + builder.push_clause( + trait_ref.clone(), + where_clauses + .iter() + .cloned() + .casted(interner) + .chain(iter::once(DomainGoal::Compatible.cast(interner))) + .chain((0..i).map(|j| { + DomainGoal::IsFullyVisible(type_parameters[j].clone()) + .cast(interner) + })) + .chain(iter::once( + DomainGoal::DownstreamType(type_parameters[i].clone()) + .cast(interner), + )) + .chain(iter::once(GoalData::CannotProve.intern(interner))), + ); + } + } + + // Fundamental traits can be reasoned about negatively without any ambiguity, so no + // need for this rule if the trait is fundamental. + if !self.flags.fundamental { + builder.push_clause( + trait_ref.clone(), + where_clauses + .iter() + .cloned() + .casted(interner) + .chain(iter::once(DomainGoal::Compatible.cast(interner))) + .chain( + trait_ref + .type_parameters(interner) + .map(|ty| DomainGoal::IsUpstream(ty).cast(interner)), + ) + .chain(iter::once(GoalData::CannotProve.intern(interner))), + ); + } + } + + // Orphan rules: + if !self.flags.upstream { + // Impls for traits declared locally always pass the impl rules + builder.push_fact(DomainGoal::LocalImplAllowed(trait_ref.clone())); + } else { + // Impls for remote traits must have a local type in the right place + for i in 0..type_parameters.len() { + builder.push_clause( + DomainGoal::LocalImplAllowed(trait_ref.clone()), + (0..i) + .map(|j| DomainGoal::IsFullyVisible(type_parameters[j].clone())) + .chain(Some(DomainGoal::IsLocal(type_parameters[i].clone()))), + ); + } + } + + // Reverse implied bound rules: given (e.g.) `trait Foo: Bar + Baz`, + // we create rules like: + // + // ``` + // FromEnv(T: Bar) :- FromEnv(T: Foo) + // ``` + // + // and + // + // ``` + // FromEnv(T: Baz) :- FromEnv(T: Foo) + // ``` + for qwc in where_clauses { + builder.push_binders(qwc, |builder, wc| { + builder.push_clause( + wc.into_from_env_goal(interner), + Some(trait_ref.clone().from_env()), + ); + }); + } + + // Finally, for every trait `Foo` we make a rule + // + // ``` + // Implemented(T: Foo) :- FromEnv(T: Foo) + // ``` + builder.push_clause(trait_ref.clone(), Some(trait_ref.from_env())); + }); + } +} + +impl ToProgramClauses for AssociatedTyDatum { + /// For each associated type, we define the "projection + /// equality" rules. There are always two; one for a successful normalization, + /// and one for the "fallback" notion of equality. + /// + /// Given: (here, `'a` and `T` represent zero or more parameters) + /// + /// ```notrust + /// trait Foo { + /// type Assoc<'a, T>: Bounds where WC; + /// } + /// ``` + /// + /// we generate the 'fallback' rule: + /// + /// ```notrust + /// -- Rule AliasEq-Placeholder + /// forall { + /// AliasEq(::Assoc<'a, T> = (Foo::Assoc<'a, T>)). + /// } + /// ``` + /// + /// and + /// + /// ```notrust + /// -- Rule AliasEq-Normalize + /// forall { + /// AliasEq(::Assoc<'a, T> = U) :- + /// Normalize(::Assoc -> U). + /// } + /// ``` + /// + /// We used to generate an "elaboration" rule like this: + /// + /// ```notrust + /// forall { + /// T: Foo :- exists { AliasEq(::Assoc = U) }. + /// } + /// ``` + /// + /// but this caused problems with the recursive solver. In + /// particular, whenever normalization is possible, we cannot + /// solve that projection uniquely, since we can now elaborate + /// `AliasEq` to fallback *or* normalize it. So instead we + /// handle this kind of reasoning through the `FromEnv` predicate. + /// + /// We also generate rules specific to WF requirements and implied bounds: + /// + /// ```notrust + /// -- Rule WellFormed-AssocTy + /// forall { + /// WellFormed((Foo::Assoc)) :- WellFormed(Self: Foo), WellFormed(WC). + /// } + /// + /// -- Rule Implied-WC-From-AssocTy + /// forall { + /// FromEnv(WC) :- FromEnv((Foo::Assoc)). + /// } + /// + /// -- Rule Implied-Bound-From-AssocTy + /// forall { + /// FromEnv(::Assoc<'a,T>: Bounds) :- FromEnv(Self: Foo), WC. + /// } + /// + /// -- Rule Implied-Trait-From-AssocTy + /// forall { + /// FromEnv(Self: Foo) :- FromEnv((Foo::Assoc)). + /// } + /// ``` + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { + let interner = builder.interner(); + let binders = self.binders.clone(); + builder.push_binders( + binders, + |builder, + AssociatedTyDatumBound { + where_clauses, + bounds, + }| { + let substitution = builder.substitution_in_scope(); + + let projection = ProjectionTy { + associated_ty_id: self.id, + substitution: substitution.clone(), + }; + let projection_ty = AliasTy::Projection(projection.clone()).intern(interner); + + // Retrieve the trait ref embedding the associated type + let trait_ref = builder.db.trait_ref_from_projection(&projection); + + // Construct an application from the projection. So if we have `::Item`, + // we would produce `(Iterator::Item)`. + let ty = TyKind::AssociatedType(self.id, substitution).intern(interner); + + let projection_eq = AliasEq { + alias: AliasTy::Projection(projection.clone()), + ty: ty.clone(), + }; + + // Fallback rule. The solver uses this to move between the projection + // and placeholder type. + // + // forall { + // AliasEq(::Assoc = (Foo::Assoc)). + // } + builder.push_fact_with_priority(projection_eq, None, ClausePriority::Low); + + // Well-formedness of projection type. + // + // forall { + // WellFormed((Foo::Assoc)) :- WellFormed(Self: Foo), WellFormed(WC). + // } + builder.push_clause( + WellFormed::Ty(ty.clone()), + iter::once(WellFormed::Trait(trait_ref.clone()).cast::>(interner)) + .chain( + where_clauses + .iter() + .cloned() + .map(|qwc| qwc.into_well_formed_goal(interner)) + .casted(interner), + ), + ); + + // Assuming well-formedness of projection type means we can assume + // the trait ref as well. Mostly used in function bodies. + // + // forall { + // FromEnv(Self: Foo) :- FromEnv((Foo::Assoc)). + // } + builder.push_clause(FromEnv::Trait(trait_ref.clone()), Some(ty.from_env())); + + // Reverse rule for where clauses. + // + // forall { + // FromEnv(WC) :- FromEnv((Foo::Assoc)). + // } + // + // This is really a family of clauses, one for each where clause. + for qwc in &where_clauses { + builder.push_binders(qwc.clone(), |builder, wc| { + builder.push_clause( + wc.into_from_env_goal(interner), + Some(FromEnv::Ty(ty.clone())), + ); + }); + } + + // Reverse rule for implied bounds. + // + // forall { + // FromEnv(::Assoc: Bounds) :- FromEnv(Self: Foo), WC + // } + for quantified_bound in bounds { + builder.push_binders(quantified_bound, |builder, bound| { + for wc in bound.into_where_clauses(interner, projection_ty.clone()) { + builder.push_clause( + wc.into_from_env_goal(interner), + iter::once( + FromEnv::Trait(trait_ref.clone()).cast::>(interner), + ) + .chain(where_clauses.iter().cloned().casted(interner)), + ); + } + }); + } + + // add new type parameter U + builder.push_bound_ty(|builder, ty| { + // `Normalize(::Assoc -> U)` + let normalize = Normalize { + alias: AliasTy::Projection(projection.clone()), + ty: ty.clone(), + }; + + // `AliasEq(::Assoc = U)` + let projection_eq = AliasEq { + alias: AliasTy::Projection(projection), + ty, + }; + + // Projection equality rule from above. + // + // forall { + // AliasEq(::Assoc = U) :- + // Normalize(::Assoc -> U). + // } + builder.push_clause(projection_eq, Some(normalize)); + }); + }, + ); + } +} -- cgit v1.2.3