| 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<I: Interner> { |
| fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>, environment: &Environment<I>); |
| } |
| |
| impl<I: Interner> ToProgramClauses<I> for ImplDatum<I> { |
| /// Given `impl<T: Clone> Clone for Vec<T> { ... }`, generate: |
| /// |
| /// ```notrust |
| /// -- Rule Implemented-From-Impl |
| /// forall<T> { |
| /// Implemented(Vec<T>: 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<I>, |
| ) { |
| 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<I: Interner> ToProgramClauses<I> for AssociatedTyValue<I> { |
| /// Given the following trait: |
| /// |
| /// ```notrust |
| /// trait Iterable { |
| /// type IntoIter<'a>: 'a; |
| /// } |
| /// ``` |
| /// |
| /// Then for the following impl: |
| /// ```notrust |
| /// impl<T> Iterable for Vec<T> where T: Clone { |
| /// type IntoIter<'a> = Iter<'a, T>; |
| /// } |
| /// ``` |
| /// |
| /// we generate: |
| /// |
| /// ```notrust |
| /// -- Rule Normalize-From-Impl |
| /// forall<'a, T> { |
| /// Normalize(<Vec<T> 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<I>, |
| ) { |
| 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`: `<Vec<!T> 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(<Vec<T> 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<I: Interner> ToProgramClauses<I> for OpaqueTyDatum<I> { |
| /// Given `opaque type T<U>: A + B = HiddenTy where U: C;`, we generate: |
| /// |
| /// ```notrust |
| /// AliasEq(T<U> = HiddenTy) :- Reveal. |
| /// AliasEq(T<U> = !T<U>). |
| /// WF(T<U>) :- WF(U: C). |
| /// Implemented(!T<U>: A). |
| /// Implemented(!T<U>: 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<I>, |
| ) { |
| 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<T: Eq> { } |
| /// ``` |
| /// |
| /// we would generate the clause: |
| /// |
| /// ```notrust |
| /// forall<T> { |
| /// WF(Foo<T>) :- 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<I>, |
| where_clauses: Wc, |
| ) where |
| I: Interner, |
| Wc: Iterator<Item = &'a QuantifiedWhereClause<I>>, |
| { |
| 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<T: Eq> { } |
| /// ``` |
| /// |
| /// we would generate the clause: |
| /// |
| /// ```notrust |
| /// forall<T> { |
| /// IsFullyVisible(Foo<T>) :- 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<I>( |
| builder: &mut ClauseBuilder<'_, I>, |
| ty: Ty<I>, |
| subst: &Substitution<I>, |
| ) where |
| I: Interner, |
| { |
| let interner = builder.interner(); |
| builder.push_clause( |
| DomainGoal::IsFullyVisible(ty), |
| subst |
| .type_parameters(interner) |
| .map(|typ| DomainGoal::IsFullyVisible(typ).cast::<Goal<_>>(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<T> where T: Eq { } |
| /// ``` |
| /// |
| /// then we would generate the rule: |
| /// |
| /// ```notrust |
| /// FromEnv(T: Eq) :- FromEnv(S<T>) |
| /// ``` |
| /// |
| /// # 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<I>, |
| where_clauses: Wc, |
| ) where |
| I: Interner, |
| Wc: Iterator<Item = &'a QuantifiedWhereClause<I>>, |
| { |
| 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<I: Interner> ToProgramClauses<I> for AdtDatum<I> { |
| /// Given the following type definition: `struct Foo<T: Eq> { }`, generate: |
| /// |
| /// ```notrust |
| /// -- Rule WellFormed-Type |
| /// forall<T> { |
| /// WF(Foo<T>) :- WF(T: Eq). |
| /// } |
| /// |
| /// -- Rule Implied-Bound-From-Type |
| /// forall<T> { |
| /// FromEnv(T: Eq) :- FromEnv(Foo<T>). |
| /// } |
| /// |
| /// forall<T> { |
| /// IsFullyVisible(Foo<T>) :- IsFullyVisible(T). |
| /// } |
| /// ``` |
| /// |
| /// If the type `Foo` is marked `#[upstream]`, we also generate: |
| /// |
| /// ```notrust |
| /// forall<T> { IsUpstream(Foo<T>). } |
| /// ``` |
| /// |
| /// Otherwise, if the type `Foo` is not marked `#[upstream]`, we generate: |
| /// ```notrust |
| /// forall<T> { IsLocal(Foo<T>). } |
| /// ``` |
| /// |
| /// Given an `#[upstream]` type that is also fundamental: |
| /// |
| /// ```notrust |
| /// #[upstream] |
| /// #[fundamental] |
| /// struct Box<T, U> {} |
| /// ``` |
| /// |
| /// We generate the following clauses: |
| /// |
| /// ```notrust |
| /// forall<T, U> { IsLocal(Box<T, U>) :- IsLocal(T). } |
| /// forall<T, U> { IsLocal(Box<T, U>) :- IsLocal(U). } |
| /// |
| /// forall<T, U> { IsUpstream(Box<T, U>) :- IsUpstream(T), IsUpstream(U). } |
| /// |
| /// // Generated for both upstream and local fundamental types |
| /// forall<T, U> { DownstreamType(Box<T, U>) :- DownstreamType(T). } |
| /// forall<T, U> { DownstreamType(Box<T, U>) :- DownstreamType(U). } |
| /// ``` |
| /// |
| #[instrument(level = "debug", skip(builder))] |
| fn to_program_clauses( |
| &self, |
| builder: &mut ClauseBuilder<'_, I>, |
| _environment: &Environment<I>, |
| ) { |
| 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<I: Interner> ToProgramClauses<I> for FnDefDatum<I> { |
| /// Given the following function definition: `fn bar<T>() where T: Eq`, generate: |
| /// |
| /// ```notrust |
| /// -- Rule WellFormed-Type |
| /// forall<T> { |
| /// WF(bar<T>) :- WF(T: Eq) |
| /// } |
| /// |
| /// -- Rule Implied-Bound-From-Type |
| /// forall<T> { |
| /// FromEnv(T: Eq) :- FromEnv(bar<T>). |
| /// } |
| /// |
| /// forall<T> { |
| /// IsFullyVisible(bar<T>) :- IsFullyVisible(T). |
| /// } |
| /// ``` |
| #[instrument(level = "debug", skip(builder))] |
| fn to_program_clauses( |
| &self, |
| builder: &mut ClauseBuilder<'_, I>, |
| _environment: &Environment<I>, |
| ) { |
| 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<I: Interner> ToProgramClauses<I> for TraitDatum<I> { |
| /// Given the following trait declaration: `trait Ord<T> where Self: Eq<T> { ... }`, generate: |
| /// |
| /// ```notrust |
| /// -- Rule WellFormed-TraitRef |
| /// forall<Self, T> { |
| /// WF(Self: Ord<T>) :- Implemented(Self: Ord<T>), WF(Self: Eq<T>). |
| /// } |
| /// ``` |
| /// |
| /// and the reverse rules: |
| /// |
| /// ```notrust |
| /// -- Rule Implemented-From-Env |
| /// forall<Self, T> { |
| /// (Self: Ord<T>) :- FromEnv(Self: Ord<T>). |
| /// } |
| /// |
| /// -- Rule Implied-Bound-From-Trait |
| /// forall<Self, T> { |
| /// FromEnv(Self: Eq<T>) :- FromEnv(Self: Ord<T>). |
| /// } |
| /// ``` |
| /// |
| /// 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<T>` would not be `#[upstream]` when compiling `std` |
| /// forall<Self, T> { LocalImplAllowed(Self: Ord<T>). } |
| /// ``` |
| /// |
| /// 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<T, U, V> where Self: Eq<T> { ... }` |
| /// forall<Self, T, U, V> { |
| /// LocalImplAllowed(Self: Foo<T, U, V>) :- IsLocal(Self). |
| /// } |
| /// |
| /// forall<Self, T, U, V> { |
| /// LocalImplAllowed(Self: Foo<T, U, V>) :- |
| /// IsFullyVisible(Self), |
| /// IsLocal(T). |
| /// } |
| /// |
| /// forall<Self, T, U, V> { |
| /// LocalImplAllowed(Self: Foo<T, U, V>) :- |
| /// IsFullyVisible(Self), |
| /// IsFullyVisible(T), |
| /// IsLocal(U). |
| /// } |
| /// |
| /// forall<Self, T, U, V> { |
| /// LocalImplAllowed(Self: Foo<T, U, V>) :- |
| /// 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<T, U, V> where Self: Eq<T> { ... }` |
| /// forall<Self, T, U, V> { |
| /// Implemented(Self: Foo<T, U, V>) :- |
| /// Implemented(Self: Eq<T>), // 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<T> 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<I>) { |
| 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::<Goal<_>>(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<T: Eq> {}` is forced to be |
| // `impl Drop<T: Eq> for S<T> { ... }`. 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<I: Interner> ToProgramClauses<I> for AssociatedTyDatum<I> { |
| /// 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<Self, 'a, T> { |
| /// AliasEq(<Self as Foo>::Assoc<'a, T> = (Foo::Assoc<'a, T>)<Self>). |
| /// } |
| /// ``` |
| /// |
| /// and |
| /// |
| /// ```notrust |
| /// -- Rule AliasEq-Normalize |
| /// forall<Self, 'a, T, U> { |
| /// AliasEq(<T as Foo>::Assoc<'a, T> = U) :- |
| /// Normalize(<T as Foo>::Assoc -> U). |
| /// } |
| /// ``` |
| /// |
| /// We used to generate an "elaboration" rule like this: |
| /// |
| /// ```notrust |
| /// forall<T> { |
| /// T: Foo :- exists<U> { AliasEq(<T as Foo>::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. |
| /// |
| /// Another set of clauses we generate for each associated type is about placeholder associated |
| /// types (i.e. `TyKind::AssociatedType`). Given |
| /// |
| /// ```notrust |
| /// trait Foo { |
| /// type Assoc<'a, T>: Bar<U = Ty> where WC; |
| /// } |
| /// ``` |
| /// |
| /// we generate |
| /// |
| /// ```notrust |
| /// forall<Self, 'a, T> { |
| /// Implemented((Foo::Assoc<'a, T>)<Self>: Bar) :- WC. |
| /// AliasEq(<<(Foo::Assoc<'a, T>)<Self>> as Bar>::U = Ty) :- WC. |
| /// } |
| /// ``` |
| /// |
| /// We also generate rules specific to WF requirements and implied bounds: |
| /// |
| /// ```notrust |
| /// -- Rule WellFormed-AssocTy |
| /// forall<Self, 'a, T> { |
| /// WellFormed((Foo::Assoc)<Self, 'a, T>) :- WellFormed(Self: Foo), WellFormed(WC). |
| /// } |
| /// |
| /// -- Rule Implied-WC-From-AssocTy |
| /// forall<Self, 'a, T> { |
| /// FromEnv(WC) :- FromEnv((Foo::Assoc)<Self, 'a, T>). |
| /// } |
| /// |
| /// -- Rule Implied-Bound-From-AssocTy |
| /// forall<Self, 'a, T> { |
| /// FromEnv(<Self as Foo>::Assoc<'a,T>: Bounds) :- FromEnv(Self: Foo), WC. |
| /// } |
| /// |
| /// -- Rule Implied-Trait-From-AssocTy |
| /// forall<Self,'a, T> { |
| /// FromEnv(Self: Foo) :- FromEnv((Foo::Assoc)<Self, 'a,T>). |
| /// } |
| /// ``` |
| fn to_program_clauses( |
| &self, |
| builder: &mut ClauseBuilder<'_, I>, |
| _environment: &Environment<I>, |
| ) { |
| 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 `<T as Iterator>::Item`, |
| // we would produce `(Iterator::Item)<T>`. |
| let placeholder_ty = TyKind::AssociatedType(self.id, substitution).intern(interner); |
| |
| let projection_eq = AliasEq { |
| alias: AliasTy::Projection(projection.clone()), |
| ty: placeholder_ty.clone(), |
| }; |
| |
| // Fallback rule. The solver uses this to move between the projection |
| // and placeholder type. |
| // |
| // forall<Self> { |
| // AliasEq(<Self as Foo>::Assoc = (Foo::Assoc)<Self>). |
| // } |
| builder.push_fact_with_priority(projection_eq, None, ClausePriority::Low); |
| |
| // Well-formedness of projection type. |
| // |
| // forall<Self> { |
| // WellFormed((Foo::Assoc)<Self>) :- WellFormed(Self: Foo), WellFormed(WC). |
| // } |
| builder.push_clause( |
| WellFormed::Ty(placeholder_ty.clone()), |
| iter::once(WellFormed::Trait(trait_ref.clone()).cast::<Goal<_>>(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<Self> { |
| // FromEnv(Self: Foo) :- FromEnv((Foo::Assoc)<Self>). |
| // } |
| builder.push_clause( |
| FromEnv::Trait(trait_ref.clone()), |
| Some(placeholder_ty.from_env()), |
| ); |
| |
| // Reverse rule for where clauses. |
| // |
| // forall<Self> { |
| // FromEnv(WC) :- FromEnv((Foo::Assoc)<Self>). |
| // } |
| // |
| // 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(placeholder_ty.clone())), |
| ); |
| }); |
| } |
| |
| for quantified_bound in bounds { |
| builder.push_binders(quantified_bound, |builder, bound| { |
| // Reverse rule for implied bounds. |
| // |
| // forall<Self> { |
| // FromEnv(<Self as Foo>::Assoc: Bounds) :- FromEnv(Self: Foo), WC |
| // } |
| 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::<Goal<_>>(interner), |
| ) |
| .chain(where_clauses.iter().cloned().casted(interner)), |
| ); |
| } |
| |
| // Rules for the corresponding placeholder type. |
| // |
| // When `Foo::Assoc` has a bound `type Assoc: Trait<T = Ty>`, we generate: |
| // |
| // forall<Self> { |
| // Implemented((Foo::Assoc)<Self>: Trait) :- WC |
| // AliasEq(<(Foo::Assoc)<Self> as Trait>::T = Ty) :- WC |
| // } |
| for wc in bound.into_where_clauses(interner, placeholder_ty.clone()) { |
| builder.push_clause(wc, where_clauses.iter().cloned()); |
| } |
| }); |
| } |
| |
| // add new type parameter U |
| builder.push_bound_ty(|builder, ty| { |
| // `Normalize(<T as Foo>::Assoc -> U)` |
| let normalize = Normalize { |
| alias: AliasTy::Projection(projection.clone()), |
| ty: ty.clone(), |
| }; |
| |
| // `AliasEq(<T as Foo>::Assoc = U)` |
| let projection_eq = AliasEq { |
| alias: AliasTy::Projection(projection), |
| ty, |
| }; |
| |
| // Projection equality rule from above. |
| // |
| // forall<T, U> { |
| // AliasEq(<T as Foo>::Assoc = U) :- |
| // Normalize(<T as Foo>::Assoc -> U). |
| // } |
| builder.push_clause(projection_eq, Some(normalize)); |
| }); |
| }, |
| ); |
| } |
| } |