summaryrefslogtreecommitdiffstats
path: root/vendor/chalk-solve-0.87.0/src/wf.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/chalk-solve-0.87.0/src/wf.rs')
-rw-r--r--vendor/chalk-solve-0.87.0/src/wf.rs1202
1 files changed, 0 insertions, 1202 deletions
diff --git a/vendor/chalk-solve-0.87.0/src/wf.rs b/vendor/chalk-solve-0.87.0/src/wf.rs
deleted file mode 100644
index d552cdde7..000000000
--- a/vendor/chalk-solve-0.87.0/src/wf.rs
+++ /dev/null
@@ -1,1202 +0,0 @@
-use std::ops::ControlFlow;
-use std::{fmt, iter};
-
-use crate::{
- ext::*, goal_builder::GoalBuilder, rust_ir::*, solve::Solver, split::Split, RustIrDatabase,
-};
-use chalk_ir::{
- cast::*,
- fold::shift::Shift,
- interner::Interner,
- visit::{TypeVisitable, TypeVisitor},
- *,
-};
-use tracing::debug;
-
-#[derive(Debug)]
-pub enum WfError<I: Interner> {
- IllFormedTypeDecl(chalk_ir::AdtId<I>),
- IllFormedOpaqueTypeDecl(chalk_ir::OpaqueTyId<I>),
- IllFormedTraitImpl(chalk_ir::TraitId<I>),
-}
-
-impl<I: Interner> fmt::Display for WfError<I> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- WfError::IllFormedTypeDecl(id) => write!(
- f,
- "type declaration `{:?}` does not meet well-formedness requirements",
- id
- ),
- WfError::IllFormedOpaqueTypeDecl(id) => write!(
- f,
- "opaque type declaration `{:?}` does not meet well-formedness requirements",
- id
- ),
- WfError::IllFormedTraitImpl(id) => write!(
- f,
- "trait impl for `{:?}` does not meet well-formedness requirements",
- id
- ),
- }
- }
-}
-
-impl<I: Interner> std::error::Error for WfError<I> {}
-
-pub struct WfSolver<'a, I: Interner> {
- db: &'a dyn RustIrDatabase<I>,
- solver_builder: &'a dyn Fn() -> Box<dyn Solver<I>>,
-}
-
-struct InputTypeCollector<I: Interner> {
- types: Vec<Ty<I>>,
- interner: I,
-}
-
-impl<I: Interner> InputTypeCollector<I> {
- fn new(interner: I) -> Self {
- Self {
- types: Vec::new(),
- interner,
- }
- }
-
- fn types_in(interner: I, value: impl TypeVisitable<I>) -> Vec<Ty<I>> {
- let mut collector = Self::new(interner);
- value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
- collector.types
- }
-}
-
-impl<I: Interner> TypeVisitor<I> for InputTypeCollector<I> {
- type BreakTy = ();
- fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> {
- self
- }
-
- fn interner(&self) -> I {
- self.interner
- }
-
- fn visit_where_clause(
- &mut self,
- where_clause: &WhereClause<I>,
- outer_binder: DebruijnIndex,
- ) -> ControlFlow<()> {
- match where_clause {
- WhereClause::AliasEq(alias_eq) => alias_eq
- .alias
- .clone()
- .intern(self.interner)
- .visit_with(self, outer_binder),
- WhereClause::Implemented(trait_ref) => trait_ref.visit_with(self, outer_binder),
- WhereClause::TypeOutlives(TypeOutlives { ty, .. }) => ty.visit_with(self, outer_binder),
- WhereClause::LifetimeOutlives(..) => ControlFlow::Continue(()),
- }
- }
-
- fn visit_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> ControlFlow<()> {
- let interner = self.interner();
-
- let mut push_ty = || {
- self.types
- .push(ty.clone().shifted_out_to(interner, outer_binder).unwrap())
- };
- match ty.kind(interner) {
- TyKind::Adt(id, substitution) => {
- push_ty();
- id.visit_with(self, outer_binder);
- substitution.visit_with(self, outer_binder)
- }
- TyKind::AssociatedType(assoc_ty, substitution) => {
- push_ty();
- assoc_ty.visit_with(self, outer_binder);
- substitution.visit_with(self, outer_binder)
- }
- TyKind::Scalar(scalar) => {
- push_ty();
- scalar.visit_with(self, outer_binder)
- }
- TyKind::Str => {
- push_ty();
- ControlFlow::Continue(())
- }
- TyKind::Tuple(arity, substitution) => {
- push_ty();
- arity.visit_with(self, outer_binder);
- substitution.visit_with(self, outer_binder)
- }
- TyKind::OpaqueType(opaque_ty, substitution) => {
- push_ty();
- opaque_ty.visit_with(self, outer_binder);
- substitution.visit_with(self, outer_binder)
- }
- TyKind::Slice(substitution) => {
- push_ty();
- substitution.visit_with(self, outer_binder)
- }
- TyKind::FnDef(fn_def, substitution) => {
- push_ty();
- fn_def.visit_with(self, outer_binder);
- substitution.visit_with(self, outer_binder)
- }
- TyKind::Ref(mutability, lifetime, ty) => {
- push_ty();
- mutability.visit_with(self, outer_binder);
- lifetime.visit_with(self, outer_binder);
- ty.visit_with(self, outer_binder)
- }
- TyKind::Raw(mutability, substitution) => {
- push_ty();
- mutability.visit_with(self, outer_binder);
- substitution.visit_with(self, outer_binder)
- }
- TyKind::Never => {
- push_ty();
- ControlFlow::Continue(())
- }
- TyKind::Array(ty, const_) => {
- push_ty();
- ty.visit_with(self, outer_binder);
- const_.visit_with(self, outer_binder)
- }
- TyKind::Closure(_id, substitution) => {
- push_ty();
- substitution.visit_with(self, outer_binder)
- }
- TyKind::Generator(_generator, substitution) => {
- push_ty();
- substitution.visit_with(self, outer_binder)
- }
- TyKind::GeneratorWitness(_witness, substitution) => {
- push_ty();
- substitution.visit_with(self, outer_binder)
- }
- TyKind::Foreign(_foreign_ty) => {
- push_ty();
- ControlFlow::Continue(())
- }
- TyKind::Error => {
- push_ty();
- ControlFlow::Continue(())
- }
-
- TyKind::Dyn(clauses) => {
- push_ty();
- clauses.visit_with(self, outer_binder)
- }
-
- TyKind::Alias(AliasTy::Projection(proj)) => {
- push_ty();
- proj.visit_with(self, outer_binder)
- }
-
- TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
- push_ty();
- opaque_ty.visit_with(self, outer_binder)
- }
-
- TyKind::Placeholder(_) => {
- push_ty();
- ControlFlow::Continue(())
- }
-
- // Type parameters do not carry any input types (so we can sort of assume they are
- // always WF).
- TyKind::BoundVar(..) => ControlFlow::Continue(()),
-
- // Higher-kinded types such as `for<'a> fn(&'a u32)` introduce their own implied
- // bounds, and these bounds will be enforced upon calling such a function. In some
- // sense, well-formedness requirements for the input types of an HKT will be enforced
- // lazily, so no need to include them here.
- TyKind::Function(..) => ControlFlow::Continue(()),
-
- TyKind::InferenceVar(..) => {
- panic!("unexpected inference variable in wf rules: {:?}", ty)
- }
- }
- }
-}
-
-impl<'a, I> WfSolver<'a, I>
-where
- I: Interner,
-{
- /// Constructs a new `WfSolver`.
- pub fn new(
- db: &'a dyn RustIrDatabase<I>,
- solver_builder: &'a dyn Fn() -> Box<dyn Solver<I>>,
- ) -> Self {
- Self { db, solver_builder }
- }
-
- pub fn verify_adt_decl(&self, adt_id: AdtId<I>) -> Result<(), WfError<I>> {
- let interner = self.db.interner();
-
- // Given a struct like
- //
- // ```rust
- // struct Foo<T> where T: Eq {
- // data: Vec<T>
- // }
- // ```
- let adt_datum = self.db.adt_datum(adt_id);
- let is_enum = adt_datum.kind == AdtKind::Enum;
-
- let mut gb = GoalBuilder::new(self.db);
- let adt_data = adt_datum
- .binders
- .map_ref(|b| (&b.variants, &b.where_clauses));
-
- // We make a goal like...
- //
- // forall<T> { ... }
- let wg_goal = gb.forall(
- &adt_data,
- is_enum,
- |gb, _, (variants, where_clauses), is_enum| {
- let interner = gb.interner();
-
- // (FromEnv(T: Eq) => ...)
- gb.implies(
- where_clauses
- .iter()
- .cloned()
- .map(|wc| wc.into_from_env_goal(interner)),
- |gb| {
- let sub_goals: Vec<_> = variants
- .iter()
- .flat_map(|variant| {
- let fields = &variant.fields;
-
- // When checking if Enum is well-formed, we require that all fields of
- // each variant are sized. For `structs`, we relax this requirement to
- // all but the last field.
- let sized_constraint_goal =
- WfWellKnownConstraints::struct_sized_constraint(
- gb.db(),
- fields,
- is_enum,
- );
-
- // WellFormed(Vec<T>), for each field type `Vec<T>` or type that appears in the where clauses
- let types = InputTypeCollector::types_in(
- gb.interner(),
- (&fields, &where_clauses),
- );
-
- types
- .into_iter()
- .map(|ty| ty.well_formed().cast(interner))
- .chain(sized_constraint_goal.into_iter())
- })
- .collect();
-
- gb.all(sub_goals)
- },
- )
- },
- );
-
- let wg_goal = wg_goal.into_closed_goal(interner);
- let mut fresh_solver = (self.solver_builder)();
- let is_legal = fresh_solver.has_unique_solution(self.db, &wg_goal);
-
- if !is_legal {
- Err(WfError::IllFormedTypeDecl(adt_id))
- } else {
- Ok(())
- }
- }
-
- pub fn verify_trait_impl(&self, impl_id: ImplId<I>) -> Result<(), WfError<I>> {
- let interner = self.db.interner();
-
- let impl_datum = self.db.impl_datum(impl_id);
- let trait_id = impl_datum.trait_id();
-
- let impl_goal = Goal::all(
- interner,
- impl_header_wf_goal(self.db, impl_id).into_iter().chain(
- impl_datum
- .associated_ty_value_ids
- .iter()
- .filter_map(|&id| compute_assoc_ty_goal(self.db, id)),
- ),
- );
-
- if let Some(well_known) = self.db.trait_datum(trait_id).well_known {
- self.verify_well_known_impl(impl_id, well_known)?
- }
-
- debug!("WF trait goal: {:?}", impl_goal);
-
- let mut fresh_solver = (self.solver_builder)();
- let is_legal =
- fresh_solver.has_unique_solution(self.db, &impl_goal.into_closed_goal(interner));
-
- if is_legal {
- Ok(())
- } else {
- Err(WfError::IllFormedTraitImpl(trait_id))
- }
- }
-
- pub fn verify_opaque_ty_decl(&self, opaque_ty_id: OpaqueTyId<I>) -> Result<(), WfError<I>> {
- // Given an opaque type like
- // ```notrust
- // opaque type Foo<T>: Clone where T: Bar = Baz;
- // ```
- let interner = self.db.interner();
-
- let mut gb = GoalBuilder::new(self.db);
-
- let datum = self.db.opaque_ty_data(opaque_ty_id);
- let bound = &datum.bound;
-
- // We make a goal like
- //
- // forall<T>
- let goal = gb.forall(bound, opaque_ty_id, |gb, _, bound, opaque_ty_id| {
- let interner = gb.interner();
-
- let subst = Substitution::from1(interner, gb.db().hidden_opaque_type(opaque_ty_id));
-
- let bounds = bound.bounds.clone().substitute(interner, &subst);
- let where_clauses = bound.where_clauses.clone().substitute(interner, &subst);
-
- let clauses = where_clauses
- .iter()
- .cloned()
- .map(|wc| wc.into_from_env_goal(interner));
-
- // if (WellFormed(T: Bar))
- gb.implies(clauses, |gb| {
- let interner = gb.interner();
-
- // all(WellFormed(Baz: Clone))
- gb.all(
- bounds
- .iter()
- .cloned()
- .map(|b| b.into_well_formed_goal(interner)),
- )
- })
- });
-
- debug!("WF opaque type goal: {:#?}", goal);
-
- let mut new_solver = (self.solver_builder)();
- let is_legal = new_solver.has_unique_solution(self.db, &goal.into_closed_goal(interner));
-
- if is_legal {
- Ok(())
- } else {
- Err(WfError::IllFormedOpaqueTypeDecl(opaque_ty_id))
- }
- }
-
- /// Verify builtin rules for well-known traits
- pub fn verify_well_known_impl(
- &self,
- impl_id: ImplId<I>,
- well_known: WellKnownTrait,
- ) -> Result<(), WfError<I>> {
- let mut solver = (self.solver_builder)();
- let impl_datum = self.db.impl_datum(impl_id);
-
- let is_legal = match well_known {
- WellKnownTrait::Copy => {
- WfWellKnownConstraints::copy_impl_constraint(&mut *solver, self.db, &impl_datum)
- }
- WellKnownTrait::Drop => {
- WfWellKnownConstraints::drop_impl_constraint(&mut *solver, self.db, &impl_datum)
- }
- WellKnownTrait::CoerceUnsized => {
- WfWellKnownConstraints::coerce_unsized_impl_constraint(
- &mut *solver,
- self.db,
- &impl_datum,
- )
- }
- WellKnownTrait::DispatchFromDyn => {
- WfWellKnownConstraints::dispatch_from_dyn_constraint(
- &mut *solver,
- self.db,
- &impl_datum,
- )
- }
- WellKnownTrait::Clone | WellKnownTrait::Unpin => true,
- // You can't add a manual implementation for the following traits:
- WellKnownTrait::Fn
- | WellKnownTrait::FnOnce
- | WellKnownTrait::FnMut
- | WellKnownTrait::Unsize
- | WellKnownTrait::Sized
- | WellKnownTrait::DiscriminantKind
- | WellKnownTrait::Generator
- | WellKnownTrait::Tuple => false,
- };
-
- if is_legal {
- Ok(())
- } else {
- Err(WfError::IllFormedTraitImpl(impl_datum.trait_id()))
- }
- }
-}
-
-fn impl_header_wf_goal<I: Interner>(
- db: &dyn RustIrDatabase<I>,
- impl_id: ImplId<I>,
-) -> Option<Goal<I>> {
- let impl_datum = db.impl_datum(impl_id);
-
- if !impl_datum.is_positive() {
- return None;
- }
-
- let impl_fields = impl_datum
- .binders
- .map_ref(|v| (&v.trait_ref, &v.where_clauses));
-
- let mut gb = GoalBuilder::new(db);
- // forall<P0...Pn> {...}
- let well_formed_goal = gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| {
- let interner = gb.interner();
-
- // if (WC && input types are well formed) { ... }
- gb.implies(
- impl_wf_environment(interner, where_clauses, trait_ref),
- |gb| {
- // We retrieve all the input types of the where clauses appearing on the trait impl,
- // e.g. in:
- // ```
- // impl<T, K> Foo for (T, K) where T: Iterator<Item = (HashSet<K>, Vec<Box<T>>)> { ... }
- // ```
- // we would retrieve `HashSet<K>`, `Box<T>`, `Vec<Box<T>>`, `(HashSet<K>, Vec<Box<T>>)`.
- // We will have to prove that these types are well-formed (e.g. an additional `K: Hash`
- // bound would be needed here).
- let types = InputTypeCollector::types_in(gb.interner(), &where_clauses);
-
- // Things to prove well-formed: input types of the where-clauses, projection types
- // appearing in the header, associated type values, and of course the trait ref.
- debug!(input_types=?types);
- let goals = types
- .into_iter()
- .map(|ty| ty.well_formed().cast(interner))
- .chain(Some((*trait_ref).clone().well_formed().cast(interner)));
-
- gb.all::<_, Goal<I>>(goals)
- },
- )
- });
-
- Some(well_formed_goal)
-}
-
-/// Creates the conditions that an impl (and its contents of an impl)
-/// can assume to be true when proving that it is well-formed.
-fn impl_wf_environment<'i, I: Interner>(
- interner: I,
- where_clauses: &'i [QuantifiedWhereClause<I>],
- trait_ref: &'i TraitRef<I>,
-) -> impl Iterator<Item = ProgramClause<I>> + 'i {
- // if (WC) { ... }
- let wc = where_clauses
- .iter()
- .cloned()
- .map(move |qwc| qwc.into_from_env_goal(interner).cast(interner));
-
- // We retrieve all the input types of the type on which we implement the trait: we will
- // *assume* that these types are well-formed, e.g. we will be able to derive that
- // `K: Hash` holds without writing any where clause.
- //
- // Example:
- // ```
- // struct HashSet<K> where K: Hash { ... }
- //
- // impl<K> Foo for HashSet<K> {
- // // Inside here, we can rely on the fact that `K: Hash` holds
- // }
- // ```
- let types = InputTypeCollector::types_in(interner, trait_ref);
-
- let types_wf = types
- .into_iter()
- .map(move |ty| ty.into_from_env_goal(interner).cast(interner));
-
- wc.chain(types_wf)
-}
-
-/// Associated type values are special because they can be parametric (independently of
-/// the impl), so we issue a special goal which is quantified using the binders of the
-/// associated type value, for example in:
-///
-/// ```ignore
-/// trait Foo {
-/// type Item<'a>: Clone where Self: 'a
-/// }
-///
-/// impl<T> Foo for Box<T> {
-/// type Item<'a> = Box<&'a T>;
-/// }
-/// ```
-///
-/// we would issue the following subgoal: `forall<'a> { WellFormed(Box<&'a T>) }`.
-///
-/// Note that there is no binder for `T` in the above: the goal we
-/// generate is expected to be exected in the context of the
-/// larger WF goal for the impl, which already has such a
-/// binder. So the entire goal for the impl might be:
-///
-/// ```ignore
-/// forall<T> {
-/// WellFormed(Box<T>) /* this comes from the impl, not this routine */,
-/// forall<'a> { WellFormed(Box<&'a T>) },
-/// }
-/// ```
-fn compute_assoc_ty_goal<I: Interner>(
- db: &dyn RustIrDatabase<I>,
- assoc_ty_id: AssociatedTyValueId<I>,
-) -> Option<Goal<I>> {
- let mut gb = GoalBuilder::new(db);
- let assoc_ty = &db.associated_ty_value(assoc_ty_id);
-
- // Create `forall<T, 'a> { .. }`
- Some(gb.forall(
- &assoc_ty.value.map_ref(|v| &v.ty),
- assoc_ty_id,
- |gb, assoc_ty_substitution, value_ty, assoc_ty_id| {
- let interner = gb.interner();
- let db = gb.db();
-
- // Hmm, because `Arc<AssociatedTyValue>` does not implement `TypeFoldable`, we can't pass this value through,
- // just the id, so we have to fetch `assoc_ty` from the database again.
- // Implementing `TypeFoldable` for `AssociatedTyValue` doesn't *quite* seem right though, as that
- // would result in a deep clone, and the value is inert. We could do some more refatoring
- // (move the `Arc` behind a newtype, for example) to fix this, but for now doesn't
- // seem worth it.
- let assoc_ty = &db.associated_ty_value(assoc_ty_id);
-
- let (impl_parameters, projection) = db
- .impl_parameters_and_projection_from_associated_ty_value(
- assoc_ty_substitution.as_slice(interner),
- assoc_ty,
- );
-
- // If (/* impl WF environment */) { ... }
- let impl_id = assoc_ty.impl_id;
- let impl_datum = &db.impl_datum(impl_id);
- let ImplDatumBound {
- trait_ref: impl_trait_ref,
- where_clauses: impl_where_clauses,
- } = impl_datum
- .binders
- .clone()
- .substitute(interner, impl_parameters);
- let impl_wf_clauses =
- impl_wf_environment(interner, &impl_where_clauses, &impl_trait_ref);
- gb.implies(impl_wf_clauses, |gb| {
- // Get the bounds and where clauses from the trait
- // declaration, substituted appropriately.
- //
- // From our example:
- //
- // * bounds
- // * original in trait, `Clone`
- // * after substituting impl parameters, `Clone`
- // * note that the self-type is not yet supplied for bounds,
- // we will do that later
- // * where clauses
- // * original in trait, `Self: 'a`
- // * after substituting impl parameters, `Box<!T>: '!a`
- let assoc_ty_datum = db.associated_ty_data(projection.associated_ty_id);
- let AssociatedTyDatumBound {
- bounds: defn_bounds,
- where_clauses: defn_where_clauses,
- } = assoc_ty_datum
- .binders
- .clone()
- .substitute(interner, &projection.substitution);
-
- // Create `if (/* where clauses on associated type value */) { .. }`
- gb.implies(
- defn_where_clauses
- .iter()
- .cloned()
- .map(|qwc| qwc.into_from_env_goal(interner)),
- |gb| {
- let types = InputTypeCollector::types_in(gb.interner(), value_ty);
-
- // We require that `WellFormed(T)` for each type that appears in the value
- let wf_goals = types
- .into_iter()
- .map(|ty| ty.well_formed())
- .casted(interner);
-
- // Check that the `value_ty` meets the bounds from the trait.
- // Here we take the substituted bounds (`defn_bounds`) and we
- // supply the self-type `value_ty` to yield the final result.
- //
- // In our example, the bound was `Clone`, so the combined
- // result is `Box<!T>: Clone`. This is then converted to a
- // well-formed goal like `WellFormed(Box<!T>: Clone)`.
- let bound_goals = defn_bounds
- .iter()
- .cloned()
- .flat_map(|qb| qb.into_where_clauses(interner, (*value_ty).clone()))
- .map(|qwc| qwc.into_well_formed_goal(interner))
- .casted(interner);
-
- // Concatenate the WF goals of inner types + the requirements from trait
- gb.all::<_, Goal<I>>(wf_goals.chain(bound_goals))
- },
- )
- })
- },
- ))
-}
-
-/// Defines methods to compute well-formedness goals for well-known
-/// traits (e.g. a goal for all fields of struct in a Copy impl to be Copy)
-struct WfWellKnownConstraints;
-
-impl WfWellKnownConstraints {
- /// Computes a goal to prove Sized constraints on a struct definition.
- /// Struct is considered well-formed (in terms of Sized) when it either
- /// has no fields or all of it's fields except the last are proven to be Sized.
- pub fn struct_sized_constraint<I: Interner>(
- db: &dyn RustIrDatabase<I>,
- fields: &[Ty<I>],
- size_all: bool,
- ) -> Option<Goal<I>> {
- let excluded = if size_all { 0 } else { 1 };
-
- if fields.len() <= excluded {
- return None;
- }
-
- let interner = db.interner();
-
- let sized_trait = db.well_known_trait_id(WellKnownTrait::Sized)?;
-
- Some(Goal::all(
- interner,
- fields[..fields.len() - excluded].iter().map(|ty| {
- TraitRef {
- trait_id: sized_trait,
- substitution: Substitution::from1(interner, ty.clone()),
- }
- .cast(interner)
- }),
- ))
- }
-
- /// Verify constraints on a Copy implementation.
- /// Copy impl is considered well-formed for
- /// a) certain builtin types (scalar values, shared ref, etc..)
- /// b) adts which
- /// 1) have all Copy fields
- /// 2) don't have a Drop impl
- fn copy_impl_constraint<I: Interner>(
- solver: &mut dyn Solver<I>,
- db: &dyn RustIrDatabase<I>,
- impl_datum: &ImplDatum<I>,
- ) -> bool {
- let interner = db.interner();
-
- let mut gb = GoalBuilder::new(db);
-
- let impl_fields = impl_datum
- .binders
- .map_ref(|v| (&v.trait_ref, &v.where_clauses));
-
- // Implementations for scalars, pointer types and never type are provided by libcore.
- // User implementations on types other than ADTs are forbidden.
- match impl_datum
- .binders
- .skip_binders()
- .trait_ref
- .self_type_parameter(interner)
- .kind(interner)
- {
- TyKind::Scalar(_)
- | TyKind::Raw(_, _)
- | TyKind::Ref(Mutability::Not, _, _)
- | TyKind::Never => return true,
-
- TyKind::Adt(_, _) => (),
-
- _ => return false,
- };
-
- // Well fomedness goal for ADTs
- let well_formed_goal =
- gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| {
- let interner = gb.interner();
-
- let ty = trait_ref.self_type_parameter(interner);
-
- let (adt_id, substitution) = match ty.kind(interner) {
- TyKind::Adt(adt_id, substitution) => (*adt_id, substitution),
-
- _ => unreachable!(),
- };
-
- // if (WC) { ... }
- gb.implies(
- impl_wf_environment(interner, where_clauses, trait_ref),
- |gb| -> Goal<I> {
- let db = gb.db();
-
- // not { Implemented(ImplSelfTy: Drop) }
- let neg_drop_goal =
- db.well_known_trait_id(WellKnownTrait::Drop)
- .map(|drop_trait_id| {
- TraitRef {
- trait_id: drop_trait_id,
- substitution: Substitution::from1(interner, ty.clone()),
- }
- .cast::<Goal<I>>(interner)
- .negate(interner)
- });
-
- let adt_datum = db.adt_datum(adt_id);
-
- let goals = adt_datum
- .binders
- .map_ref(|b| &b.variants)
- .cloned()
- .substitute(interner, substitution)
- .into_iter()
- .flat_map(|v| {
- v.fields.into_iter().map(|f| {
- // Implemented(FieldTy: Copy)
- TraitRef {
- trait_id: trait_ref.trait_id,
- substitution: Substitution::from1(interner, f),
- }
- .cast(interner)
- })
- })
- .chain(neg_drop_goal.into_iter());
- gb.all(goals)
- },
- )
- });
-
- solver.has_unique_solution(db, &well_formed_goal.into_closed_goal(interner))
- }
-
- /// Verifies constraints on a Drop implementation
- /// Drop implementation is considered well-formed if:
- /// a) it's implemented on an ADT
- /// b) The generic parameters of the impl's type must all be parameters
- /// of the Drop impl itself (i.e., no specialization like
- /// `impl Drop for S<Foo> {...}` is allowed).
- /// c) Any bounds on the genereic parameters of the impl must be
- /// deductible from the bounds imposed by the struct definition
- /// (i.e. the implementation must be exactly as generic as the ADT definition).
- ///
- /// ```rust,ignore
- /// struct S<T1, T2> { }
- /// struct Foo<T> { }
- ///
- /// impl<U1: Copy, U2: Sized> Drop for S<U2, Foo<U1>> { }
- /// ```
- ///
- /// generates the following:
- /// goal derived from c):
- ///
- /// ```notrust
- /// forall<U1, U2> {
- /// Implemented(U1: Copy), Implemented(U2: Sized) :- FromEnv(S<U2, Foo<U1>>)
- /// }
- /// ```
- ///
- /// goal derived from b):
- /// ```notrust
- /// forall <T1, T2> {
- /// exists<U1, U2> {
- /// S<T1, T2> = S<U2, Foo<U1>>
- /// }
- /// }
- /// ```
- fn drop_impl_constraint<I: Interner>(
- solver: &mut dyn Solver<I>,
- db: &dyn RustIrDatabase<I>,
- impl_datum: &ImplDatum<I>,
- ) -> bool {
- let interner = db.interner();
-
- let adt_id = match impl_datum.self_type_adt_id(interner) {
- Some(id) => id,
- // Drop can only be implemented on a nominal type
- None => return false,
- };
-
- let mut gb = GoalBuilder::new(db);
-
- let adt_datum = db.adt_datum(adt_id);
-
- let impl_fields = impl_datum
- .binders
- .map_ref(|v| (&v.trait_ref, &v.where_clauses));
-
- // forall<ImplP1...ImplPn> { .. }
- let implied_by_adt_def_goal =
- gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| {
- let interner = gb.interner();
-
- // FromEnv(ImplSelfType) => ...
- gb.implies(
- iter::once(
- FromEnv::Ty(trait_ref.self_type_parameter(interner))
- .cast::<DomainGoal<I>>(interner),
- ),
- |gb| {
- // All(ImplWhereClauses)
- gb.all(
- where_clauses
- .iter()
- .map(|wc| wc.clone().into_well_formed_goal(interner)),
- )
- },
- )
- });
-
- let impl_self_ty = impl_datum
- .binders
- .map_ref(|b| b.trait_ref.self_type_parameter(interner));
-
- // forall<StructP1..StructPN> {...}
- let eq_goal = gb.forall(
- &adt_datum.binders,
- (adt_id, impl_self_ty),
- |gb, substitution, _, (adt_id, impl_self_ty)| {
- let interner = gb.interner();
-
- let def_adt = TyKind::Adt(adt_id, substitution).intern(interner);
-
- // exists<ImplP1...ImplPn> { .. }
- gb.exists(&impl_self_ty, def_adt, |gb, _, impl_adt, def_adt| {
- let interner = gb.interner();
-
- // StructName<StructP1..StructPn> = ImplSelfType
- GoalData::EqGoal(EqGoal {
- a: GenericArgData::Ty(def_adt).intern(interner),
- b: GenericArgData::Ty(impl_adt.clone()).intern(interner),
- })
- .intern(interner)
- })
- },
- );
-
- let well_formed_goal = gb.all([implied_by_adt_def_goal, eq_goal].iter());
-
- solver.has_unique_solution(db, &well_formed_goal.into_closed_goal(interner))
- }
-
- /// Verify constraints a CoerceUnsized impl.
- /// Rules for CoerceUnsized impl to be considered well-formed:
- /// 1) pointer conversions: `&[mut] T -> &[mut] U`, `&[mut] T -> *[mut] U`,
- /// `*[mut] T -> *[mut] U` are considered valid if
- /// 1) `T: Unsize<U>`
- /// 2) mutability is respected, i.e. immutable -> immutable, mutable -> immutable,
- /// mutable -> mutable conversions are allowed, immutable -> mutable is not.
- /// 2) struct conversions of structures with the same definition, `S<P0...Pn>` -> `S<Q0...Qn>`.
- /// To check if this impl is legal, we would walk down the fields of `S`
- /// and consider their types with both substitutes. We are looking to find
- /// exactly one (non-phantom) field that has changed its type (from `T` to `U`), and
- /// expect `T` to be unsizeable to `U`, i.e. `T: CoerceUnsized<U>`.
- ///
- /// As an example, consider a struct
- /// ```rust
- /// struct Foo<T, U> {
- /// extra: T,
- /// ptr: *mut U,
- /// }
- /// ```
- ///
- /// We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
- /// to `Foo<T, [i32]>`. That impl would look like:
- /// ```rust,ignore
- /// impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
- /// ```
- /// In this case:
- ///
- /// - `extra` has type `T` before and type `T` after
- /// - `ptr` has type `*mut U` before and type `*mut V` after
- ///
- /// Since just one field changed, we would then check that `*mut U: CoerceUnsized<*mut V>`
- /// is implemented. This will work out because `U: Unsize<V>`, and we have a libcore rule
- /// that `*mut U` can be coerced to `*mut V` if `U: Unsize<V>`.
- fn coerce_unsized_impl_constraint<I: Interner>(
- solver: &mut dyn Solver<I>,
- db: &dyn RustIrDatabase<I>,
- impl_datum: &ImplDatum<I>,
- ) -> bool {
- let interner = db.interner();
- let mut gb = GoalBuilder::new(db);
-
- let (binders, impl_datum) = impl_datum.binders.as_ref().into();
-
- let trait_ref: &TraitRef<I> = &impl_datum.trait_ref;
-
- let source = trait_ref.self_type_parameter(interner);
- let target = trait_ref
- .substitution
- .at(interner, 1)
- .assert_ty_ref(interner)
- .clone();
-
- let mut place_in_environment = |goal| -> Goal<I> {
- gb.forall(
- &Binders::new(
- binders.clone(),
- (goal, trait_ref, &impl_datum.where_clauses),
- ),
- (),
- |gb, _, (goal, trait_ref, where_clauses), ()| {
- let interner = gb.interner();
- gb.implies(
- impl_wf_environment(interner, where_clauses, trait_ref),
- |_| goal,
- )
- },
- )
- };
-
- match (source.kind(interner), target.kind(interner)) {
- (TyKind::Ref(s_m, _, source), TyKind::Ref(t_m, _, target))
- | (TyKind::Ref(s_m, _, source), TyKind::Raw(t_m, target))
- | (TyKind::Raw(s_m, source), TyKind::Raw(t_m, target)) => {
- if (*s_m, *t_m) == (Mutability::Not, Mutability::Mut) {
- return false;
- }
-
- let unsize_trait_id =
- if let Some(id) = db.well_known_trait_id(WellKnownTrait::Unsize) {
- id
- } else {
- return false;
- };
-
- // Source: Unsize<Target>
- let unsize_goal: Goal<I> = TraitRef {
- trait_id: unsize_trait_id,
- substitution: Substitution::from_iter(
- interner,
- [source.clone(), target.clone()].iter().cloned(),
- ),
- }
- .cast(interner);
-
- // ImplEnv -> Source: Unsize<Target>
- let unsize_goal = place_in_environment(unsize_goal);
-
- solver.has_unique_solution(db, &unsize_goal.into_closed_goal(interner))
- }
- (TyKind::Adt(source_id, subst_a), TyKind::Adt(target_id, subst_b)) => {
- let adt_datum = db.adt_datum(*source_id);
-
- if source_id != target_id || adt_datum.kind != AdtKind::Struct {
- return false;
- }
-
- let fields = adt_datum
- .binders
- .map_ref(|bound| &bound.variants.last().unwrap().fields)
- .cloned();
-
- let (source_fields, target_fields) = (
- fields.clone().substitute(interner, subst_a),
- fields.substitute(interner, subst_b),
- );
-
- // collect fields with unequal ids
- let uneq_field_ids: Vec<usize> = (0..source_fields.len())
- .filter(|&i| {
- // ignore phantom data fields
- if let Some(adt_id) = source_fields[i].adt_id(interner) {
- if db.adt_datum(adt_id).flags.phantom_data {
- return false;
- }
- }
-
- let eq_goal: Goal<I> = EqGoal {
- a: source_fields[i].clone().cast(interner),
- b: target_fields[i].clone().cast(interner),
- }
- .cast(interner);
-
- // ImplEnv -> Source.fields[i] = Target.fields[i]
- let eq_goal = place_in_environment(eq_goal);
-
- // We are interested in !UNEQUAL! fields
- !solver.has_unique_solution(db, &eq_goal.into_closed_goal(interner))
- })
- .collect();
-
- if uneq_field_ids.len() != 1 {
- return false;
- }
-
- let field_id = uneq_field_ids[0];
-
- // Source.fields[i]: CoerceUnsized<TargetFields[i]>
- let coerce_unsized_goal: Goal<I> = TraitRef {
- trait_id: trait_ref.trait_id,
- substitution: Substitution::from_iter(
- interner,
- [
- source_fields[field_id].clone(),
- target_fields[field_id].clone(),
- ]
- .iter()
- .cloned(),
- ),
- }
- .cast(interner);
-
- // ImplEnv -> Source.fields[i]: CoerceUnsized<TargetFields[i]>
- let coerce_unsized_goal = place_in_environment(coerce_unsized_goal);
-
- solver.has_unique_solution(db, &coerce_unsized_goal.into_closed_goal(interner))
- }
- _ => false,
- }
- }
-
- /// Verify constraints of a DispatchFromDyn impl.
- ///
- /// Rules for DispatchFromDyn impl to be considered well-formed:
- ///
- /// * Self and the type parameter must both be references or raw pointers with the same mutabilty
- /// * OR all the following hold:
- /// - Self and the type parameter must be structs
- /// - Self and the type parameter must have the same definitions
- /// - Self must not be `#[repr(packed)]` or `#[repr(C)]`
- /// - Self must have exactly one field which is not a 1-ZST (there may be any number of 1-ZST
- /// fields), and that field must have a different type in the type parameter (i.e., it is
- /// the field being coerced)
- /// - `DispatchFromDyn` is implemented for the type of the field being coerced.
- fn dispatch_from_dyn_constraint<I: Interner>(
- solver: &mut dyn Solver<I>,
- db: &dyn RustIrDatabase<I>,
- impl_datum: &ImplDatum<I>,
- ) -> bool {
- let interner = db.interner();
- let mut gb = GoalBuilder::new(db);
-
- let (binders, impl_datum) = impl_datum.binders.as_ref().into();
-
- let trait_ref: &TraitRef<I> = &impl_datum.trait_ref;
-
- // DispatchFromDyn specifies that Self (source) can be coerced to T (target; its single type parameter).
- let source = trait_ref.self_type_parameter(interner);
- let target = trait_ref
- .substitution
- .at(interner, 1)
- .assert_ty_ref(interner)
- .clone();
-
- let mut place_in_environment = |goal| -> Goal<I> {
- gb.forall(
- &Binders::new(
- binders.clone(),
- (goal, trait_ref, &impl_datum.where_clauses),
- ),
- (),
- |gb, _, (goal, trait_ref, where_clauses), ()| {
- let interner = gb.interner();
- gb.implies(
- impl_wf_environment(interner, &where_clauses, &trait_ref),
- |_| goal,
- )
- },
- )
- };
-
- match (source.kind(interner), target.kind(interner)) {
- (TyKind::Ref(s_m, _, _), TyKind::Ref(t_m, _, _))
- | (TyKind::Raw(s_m, _), TyKind::Raw(t_m, _))
- if s_m == t_m =>
- {
- true
- }
- (TyKind::Adt(source_id, subst_a), TyKind::Adt(target_id, subst_b)) => {
- let adt_datum = db.adt_datum(*source_id);
-
- // Definitions are equal and are structs.
- if source_id != target_id || adt_datum.kind != AdtKind::Struct {
- return false;
- }
-
- // Not repr(C) or repr(packed).
- let repr = db.adt_repr(*source_id);
- if repr.c || repr.packed {
- return false;
- }
-
- // Collect non 1-ZST fields; there must be exactly one.
- let fields = adt_datum
- .binders
- .map_ref(|bound| &bound.variants.last().unwrap().fields)
- .cloned();
-
- let (source_fields, target_fields) = (
- fields.clone().substitute(interner, subst_a),
- fields.substitute(interner, subst_b),
- );
-
- let mut non_zst_fields: Vec<_> = source_fields
- .iter()
- .zip(target_fields.iter())
- .filter(|(sf, _)| match sf.adt_id(interner) {
- Some(adt) => !db.adt_size_align(adt).one_zst(),
- None => true,
- })
- .collect();
-
- if non_zst_fields.len() != 1 {
- return false;
- }
-
- // The field being coerced (the interesting field).
- let (field_src, field_tgt) = non_zst_fields.pop().unwrap();
-
- // The interesting field is different in the source and target types.
- let eq_goal: Goal<I> = EqGoal {
- a: field_src.clone().cast(interner),
- b: field_tgt.clone().cast(interner),
- }
- .cast(interner);
- let eq_goal = place_in_environment(eq_goal);
- if solver.has_unique_solution(db, &eq_goal.into_closed_goal(interner)) {
- return false;
- }
-
- // Type(field_src): DispatchFromDyn<Type(field_tgt)>
- let field_dispatch_goal: Goal<I> = TraitRef {
- trait_id: trait_ref.trait_id,
- substitution: Substitution::from_iter(
- interner,
- [field_src.clone(), field_tgt.clone()].iter().cloned(),
- ),
- }
- .cast(interner);
- let field_dispatch_goal = place_in_environment(field_dispatch_goal);
- if !solver.has_unique_solution(db, &field_dispatch_goal.into_closed_goal(interner))
- {
- return false;
- }
-
- true
- }
- _ => false,
- }
- }
-}