blob: a0ede39df7c773865543a51d0a71a4a3653b8a8a [file] [log] [blame]
use self::builder::ClauseBuilder;
use self::env_elaborator::elaborate_env_clauses;
use self::program_clauses::ToProgramClauses;
use crate::goal_builder::GoalBuilder;
use crate::rust_ir::{Movability, WellKnownTrait};
use crate::split::Split;
use crate::RustIrDatabase;
use chalk_ir::cast::{Cast, Caster};
use chalk_ir::could_match::CouldMatch;
use chalk_ir::interner::Interner;
use chalk_ir::*;
use rustc_hash::FxHashSet;
use std::iter;
use std::marker::PhantomData;
use tracing::{debug, instrument};
pub mod builder;
mod builtin_traits;
mod dyn_ty;
mod env_elaborator;
mod generalize;
pub mod program_clauses;
mod super_traits;
// yields the types "contained" in `app_ty`
fn constituent_types<I: Interner>(db: &dyn RustIrDatabase<I>, ty: &TyKind<I>) -> Vec<Ty<I>> {
let interner = db.interner();
match ty {
// For non-phantom_data adts we collect its variants/fields
TyKind::Adt(adt_id, substitution) if !db.adt_datum(*adt_id).flags.phantom_data => {
let adt_datum = &db.adt_datum(*adt_id);
let adt_datum_bound = adt_datum.binders.clone().substitute(interner, substitution);
adt_datum_bound
.variants
.into_iter()
.flat_map(|variant| variant.fields.into_iter())
.collect()
}
// And for `PhantomData<T>`, we pass `T`.
TyKind::Adt(_, substitution)
| TyKind::Tuple(_, substitution)
| TyKind::FnDef(_, substitution) => substitution
.iter(interner)
.filter_map(|x| x.ty(interner))
.cloned()
.collect(),
TyKind::Array(ty, _) | TyKind::Slice(ty) | TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => {
vec![ty.clone()]
}
TyKind::Str | TyKind::Never | TyKind::Scalar(_) => Vec::new(),
TyKind::Generator(generator_id, substitution) => {
let generator_datum = &db.generator_datum(*generator_id);
let generator_datum_bound = generator_datum
.input_output
.clone()
.substitute(interner, &substitution);
let mut tys = generator_datum_bound.upvars;
tys.push(
TyKind::GeneratorWitness(*generator_id, substitution.clone()).intern(interner),
);
tys
}
TyKind::Closure(_, _) => panic!("this function should not be called for closures"),
TyKind::GeneratorWitness(_, _) => {
panic!("this function should not be called for generator witnesses")
}
TyKind::Function(_) => panic!("this function should not be called for functions"),
TyKind::InferenceVar(_, _) | TyKind::BoundVar(_) => {
panic!("this function should not be called for inference or bound vars")
}
TyKind::Placeholder(_) => panic!("this function should not be called for placeholders"),
TyKind::Dyn(_) => panic!("this function should not be called for dyn types"),
TyKind::Alias(_) => panic!("this function should not be called for alias"),
TyKind::Foreign(_) => panic!("constituent_types of foreign types are unknown!"),
TyKind::Error => Vec::new(),
TyKind::OpaqueType(_, _) => panic!("constituent_types of opaque types are unknown!"),
TyKind::AssociatedType(_, _) => {
panic!("constituent_types of associated types are unknown!")
}
}
}
/// 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.
///
/// So, if you have `impl Send for MyList<Foo>`, then we would
/// generate no rule for `MyList` at all -- similarly if you have
/// `impl !Send for MyList<Foo>`, or `impl<T> Send for MyList<T>`.
///
/// But if you have no rules at all for `Send` / `MyList`, then we
/// generate an impl based on the field types of `MyList`. For example
/// given the following program:
///
/// ```notrust
/// #[auto] trait Send { }
///
/// struct MyList<T> {
/// data: T,
/// next: Box<Option<MyList<T>>>,
/// }
///
/// ```
///
/// we generate:
///
/// ```notrust
/// forall<T> {
/// Implemented(MyList<T>: Send) :-
/// Implemented(T: Send),
/// Implemented(Box<Option<MyList<T>>>: Send).
/// }
/// ```
#[instrument(level = "debug", skip(builder))]
pub fn push_auto_trait_impls<I: Interner>(
builder: &mut ClauseBuilder<'_, I>,
auto_trait_id: TraitId<I>,
ty: &TyKind<I>,
) -> Result<(), Floundered> {
let interner = builder.interner();
// Must be an auto trait.
assert!(builder.db.trait_datum(auto_trait_id).is_auto_trait());
// Auto traits never have generic parameters of their own (apart from `Self`).
assert_eq!(
builder.db.trait_datum(auto_trait_id).binders.len(interner),
1
);
// 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, ty) {
debug!("impl provided");
return Ok(());
}
let mk_ref = |ty: Ty<I>| TraitRef {
trait_id: auto_trait_id,
substitution: Substitution::from1(interner, ty.cast(interner)),
};
let consequence = mk_ref(ty.clone().intern(interner));
match ty {
// function-types implement auto traits unconditionally
TyKind::Function(_) => {
builder.push_fact(consequence);
Ok(())
}
TyKind::InferenceVar(_, _) | TyKind::BoundVar(_) => Err(Floundered),
// auto traits are not implemented for foreign types
TyKind::Foreign(_) => Ok(()),
// closures require binders, while the other types do not
TyKind::Closure(closure_id, substs) => {
let closure_fn_substitution = builder.db.closure_fn_substitution(*closure_id, substs);
let binders = builder.db.closure_upvars(*closure_id, substs);
let upvars = binders.substitute(builder.db.interner(), &closure_fn_substitution);
// in a same behavior as for non-auto traits (reuse the code) we can require that
// every bound type must implement this auto-trait
use crate::clauses::builtin_traits::needs_impl_for_tys;
needs_impl_for_tys(builder.db, builder, consequence, Some(upvars).into_iter());
Ok(())
}
TyKind::Generator(generator_id, _) => {
if Some(auto_trait_id) == builder.db.well_known_trait_id(WellKnownTrait::Unpin) {
match builder.db.generator_datum(*generator_id).movability {
// immovable generators are never `Unpin`
Movability::Static => (),
// movable generators are always `Unpin`
Movability::Movable => builder.push_fact(consequence),
}
} else {
// if trait is not `Unpin`, use regular auto trait clause
let conditions = constituent_types(builder.db, ty).into_iter().map(mk_ref);
builder.push_clause(consequence, conditions);
}
Ok(())
}
TyKind::GeneratorWitness(generator_id, _) => {
push_auto_trait_impls_generator_witness(builder, auto_trait_id, *generator_id);
Ok(())
}
TyKind::OpaqueType(opaque_ty_id, _) => {
push_auto_trait_impls_opaque(builder, auto_trait_id, *opaque_ty_id);
Ok(())
}
// No auto traits
TyKind::AssociatedType(_, _)
| TyKind::Placeholder(_)
| TyKind::Dyn(_)
| TyKind::Alias(_) => Ok(()),
// app_ty implements AutoTrait if all constituents of app_ty implement AutoTrait
_ => {
let conditions = constituent_types(builder.db, ty).into_iter().map(mk_ref);
builder.push_clause(consequence, conditions);
Ok(())
}
}
}
/// Leak auto traits for opaque types, just like `push_auto_trait_impls` does for structs.
///
/// For example, given the following program:
///
/// ```notrust
/// #[auto] trait Send { }
/// trait Trait { }
/// struct Bar { }
/// opaque type Foo: Trait = Bar
/// ```
/// Checking the goal `Foo: Send` would generate the following:
///
/// ```notrust
/// Foo: Send :- Bar: Send
/// ```
#[instrument(level = "debug", skip(builder))]
pub fn push_auto_trait_impls_opaque<I: Interner>(
builder: &mut ClauseBuilder<'_, I>,
auto_trait_id: TraitId<I>,
opaque_id: OpaqueTyId<I>,
) {
let opaque_ty_datum = &builder.db.opaque_ty_data(opaque_id);
let interner = builder.interner();
// Must be an auto trait.
assert!(builder.db.trait_datum(auto_trait_id).is_auto_trait());
// Auto traits never have generic parameters of their own (apart from `Self`).
assert_eq!(
builder.db.trait_datum(auto_trait_id).binders.len(interner),
1
);
let hidden_ty = builder.db.hidden_opaque_type(opaque_id);
let binders = opaque_ty_datum.bound.clone();
builder.push_binders(binders, |builder, _| {
let self_ty =
TyKind::OpaqueType(opaque_id, builder.substitution_in_scope()).intern(interner);
// trait_ref = `OpaqueType<...>: MyAutoTrait`
let auto_trait_ref = TraitRef {
trait_id: auto_trait_id,
substitution: Substitution::from1(interner, self_ty),
};
// OpaqueType<...>: MyAutoTrait :- HiddenType: MyAutoTrait
builder.push_clause(
auto_trait_ref,
std::iter::once(TraitRef {
trait_id: auto_trait_id,
substitution: Substitution::from1(interner, hidden_ty.clone()),
}),
);
});
}
#[instrument(level = "debug", skip(builder))]
pub fn push_auto_trait_impls_generator_witness<I: Interner>(
builder: &mut ClauseBuilder<'_, I>,
auto_trait_id: TraitId<I>,
generator_id: GeneratorId<I>,
) {
let witness_datum = builder.db.generator_witness_datum(generator_id);
let interner = builder.interner();
// Must be an auto trait.
assert!(builder.db.trait_datum(auto_trait_id).is_auto_trait());
// Auto traits never have generic parameters of their own (apart from `Self`).
assert_eq!(
builder.db.trait_datum(auto_trait_id).binders.len(interner),
1
);
// Push binders for the generator generic parameters. These can be used by
// both upvars and witness types
builder.push_binders(witness_datum.inner_types.clone(), |builder, inner_types| {
let witness_ty = TyKind::GeneratorWitness(generator_id, builder.substitution_in_scope())
.intern(interner);
// trait_ref = `GeneratorWitness<...>: MyAutoTrait`
let auto_trait_ref = TraitRef {
trait_id: auto_trait_id,
substitution: Substitution::from1(interner, witness_ty),
};
// Create a goal of the form:
// forall<L0, L1, ..., LN> {
// WitnessType1<L0, L1, ... LN, P0, P1, ..., PN>: MyAutoTrait,
// ...
// WitnessTypeN<L0, L1, ... LN, P0, P1, ..., PN>: MyAutoTrait,
//
// }
//
// where `L0, L1, ...LN` are our existentially bound witness lifetimes,
// and `P0, P1, ..., PN` are the normal generator generics.
//
// We create a 'forall' goal due to the fact that our witness lifetimes
// are *existentially* quantified - the precise reigon is erased during
// type checking, so we just know that the type takes *some* region
// as a parameter. Therefore, we require that the auto trait bound
// hold for *all* regions, which guarantees that the bound will
// hold for the original lifetime (before it was erased).
//
// This does not take into account well-formed information from
// the witness types. For example, if we have the type
// `struct Foo<'a, 'b> { val: &'a &'b u8 }`
// then `'b: 'a` must hold for `Foo<'a, 'b>` to be well-formed.
// If we have `Foo<'a, 'b>` stored as a witness type, we will
// not currently use this information to determine a more precise
// relationship between 'a and 'b. In the future, we will likely
// do this to avoid incorrectly rejecting correct code.
let gb = &mut GoalBuilder::new(builder.db);
let witness_goal = gb.forall(
&inner_types.types,
auto_trait_id,
|gb, _subst, types, auto_trait_id| {
Goal::new(
gb.interner(),
GoalData::All(Goals::from_iter(
gb.interner(),
types.iter().map(|witness_ty| TraitRef {
trait_id: auto_trait_id,
substitution: Substitution::from1(gb.interner(), witness_ty.clone()),
}),
)),
)
},
);
// GeneratorWitnessType: AutoTrait :- forall<...> ...
// where 'forall<...> ...' is the goal described above.
builder.push_clause(auto_trait_ref, std::iter::once(witness_goal));
})
}
/// Given some goal `goal` that must be proven, along with
/// its `environment`, figures out the program clauses that apply
/// to this goal from the Rust program. So for example if the goal
/// is `Implemented(T: Clone)`, then this function might return clauses
/// derived from the trait `Clone` and its impls.
#[instrument(level = "debug", skip(db))]
pub fn program_clauses_for_goal<'db, I: Interner>(
db: &'db dyn RustIrDatabase<I>,
goal: &UCanonical<InEnvironment<DomainGoal<I>>>,
) -> Result<Vec<ProgramClause<I>>, Floundered> {
let interner = db.interner();
let custom_clauses = db.custom_clauses().into_iter();
let clauses_that_could_match =
program_clauses_that_could_match(db, goal).map(|cl| cl.into_iter())?;
let clauses: Vec<ProgramClause<I>> = custom_clauses
.chain(clauses_that_could_match)
.chain(
db.program_clauses_for_env(&goal.canonical.value.environment)
.iter(interner)
.cloned(),
)
.filter(|c| {
c.could_match(
interner,
db.unification_database(),
&goal.canonical.value.goal,
)
})
.collect();
debug!(?clauses);
Ok(clauses)
}
/// Returns a set of program clauses that could possibly match
/// `goal`. This can be any superset of the correct set, but the
/// more precise you can make it, the more efficient solving will
/// be.
#[instrument(level = "debug", skip(db))]
pub fn program_clauses_that_could_match<I: Interner>(
db: &dyn RustIrDatabase<I>,
goal: &UCanonical<InEnvironment<DomainGoal<I>>>,
) -> Result<Vec<ProgramClause<I>>, Floundered> {
let interner = db.interner();
let mut clauses: Vec<ProgramClause<I>> = vec![];
let builder = &mut ClauseBuilder::new(db, &mut clauses);
let UCanonical {
canonical:
Canonical {
value: InEnvironment { environment, goal },
binders,
},
universes: _,
} = goal;
match goal {
DomainGoal::Holds(WhereClause::Implemented(trait_ref)) => {
let self_ty = trait_ref.self_type_parameter(interner);
let trait_id = trait_ref.trait_id;
let trait_datum = db.trait_datum(trait_id);
match self_ty.kind(interner) {
TyKind::InferenceVar(_, _) => {
panic!("Inference vars not allowed when getting program clauses")
}
TyKind::Alias(alias) => {
// An alias could normalize to anything, including `dyn trait`
// or an opaque type, so push a clause that asks for the
// self type to be normalized and return.
push_alias_implemented_clause(builder, trait_ref.clone(), alias.clone());
return Ok(clauses);
}
_ if self_ty.is_general_var(interner, binders) => {
if trait_datum.is_non_enumerable_trait() || trait_datum.is_auto_trait() {
return Err(Floundered);
}
}
TyKind::OpaqueType(opaque_ty_id, _) => {
db.opaque_ty_data(*opaque_ty_id)
.to_program_clauses(builder, environment);
}
TyKind::Dyn(_) => {
// If the self type is a `dyn trait` type, generate program-clauses
// that indicates that it implements its own traits.
// FIXME: This is presently rather wasteful, in that we don't check that the
// these program clauses we are generating are actually relevant to the goal
// `goal` that we are actually *trying* to prove (though there is some later
// code that will screen out irrelevant stuff).
//
// In other words, if we were trying to prove `Implemented(dyn
// Fn(&u8): Clone)`, we would still generate two clauses that are
// totally irrelevant to that goal, because they let us prove other
// things but not `Clone`.
dyn_ty::build_dyn_self_ty_clauses(db, builder, self_ty.clone())
}
// We don't actually do anything here, but we need to record the types when logging
TyKind::Adt(adt_id, _) => {
let _ = db.adt_datum(*adt_id);
}
TyKind::FnDef(fn_def_id, _) => {
let _ = db.fn_def_datum(*fn_def_id);
}
_ => {}
}
// This is needed for the coherence related impls, as well
// as for the `Implemented(Foo) :- FromEnv(Foo)` rule.
trait_datum.to_program_clauses(builder, environment);
for impl_id in db.impls_for_trait(
trait_ref.trait_id,
trait_ref.substitution.as_slice(interner),
binders,
) {
db.impl_datum(impl_id)
.to_program_clauses(builder, environment);
}
// If this is a `Foo: Send` (or any auto-trait), then add
// the automatic impls for `Foo`.
let trait_datum = db.trait_datum(trait_id);
if trait_datum.is_auto_trait() {
let generalized = generalize::Generalize::apply(db.interner(), trait_ref.clone());
builder.push_binders(generalized, |builder, trait_ref| {
let ty = trait_ref.self_type_parameter(interner);
push_auto_trait_impls(builder, trait_id, ty.kind(interner))
})?;
}
if let Some(well_known) = trait_datum.well_known {
builtin_traits::add_builtin_program_clauses(
db,
builder,
well_known,
trait_ref.clone(),
binders,
)?;
}
}
DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => match &alias_eq.alias {
AliasTy::Projection(proj) => {
let trait_self_ty = db
.trait_ref_from_projection(proj)
.self_type_parameter(interner);
match trait_self_ty.kind(interner) {
TyKind::Alias(alias) => {
// An alias could normalize to anything, including an
// opaque type, so push a clause that asks for the self
// type to be normalized and return.
push_alias_alias_eq_clause(
builder,
proj.clone(),
alias_eq.ty.clone(),
alias.clone(),
);
return Ok(clauses);
}
TyKind::OpaqueType(opaque_ty_id, _) => {
db.opaque_ty_data(*opaque_ty_id)
.to_program_clauses(builder, environment);
}
// If the self type is a `dyn trait` type, generate program-clauses
// for any associated type bindings it contains.
// FIXME: see the fixme for the analogous code for Implemented goals.
TyKind::Dyn(_) => {
dyn_ty::build_dyn_self_ty_clauses(db, builder, trait_self_ty.clone())
}
_ => {}
}
db.associated_ty_data(proj.associated_ty_id)
.to_program_clauses(builder, environment)
}
AliasTy::Opaque(opaque_ty) => db
.opaque_ty_data(opaque_ty.opaque_ty_id)
.to_program_clauses(builder, environment),
},
DomainGoal::Holds(WhereClause::LifetimeOutlives(..)) => {
builder.push_bound_lifetime(|builder, a| {
builder.push_bound_lifetime(|builder, b| {
builder.push_fact_with_constraints(
DomainGoal::Holds(WhereClause::LifetimeOutlives(LifetimeOutlives {
a: a.clone(),
b: b.clone(),
})),
Some(InEnvironment::new(
&Environment::new(interner),
Constraint::LifetimeOutlives(a, b),
)),
);
})
});
}
DomainGoal::Holds(WhereClause::TypeOutlives(..)) => {
builder.push_bound_ty(|builder, ty| {
builder.push_bound_lifetime(|builder, lifetime| {
builder.push_fact_with_constraints(
DomainGoal::Holds(WhereClause::TypeOutlives(TypeOutlives {
ty: ty.clone(),
lifetime: lifetime.clone(),
})),
Some(InEnvironment::new(
&Environment::new(interner),
Constraint::TypeOutlives(ty, lifetime),
)),
)
})
});
}
DomainGoal::WellFormed(WellFormed::Trait(trait_ref))
| DomainGoal::LocalImplAllowed(trait_ref) => {
db.trait_datum(trait_ref.trait_id)
.to_program_clauses(builder, environment);
}
DomainGoal::ObjectSafe(trait_id) => {
if builder.db.is_object_safe(*trait_id) {
builder.push_fact(DomainGoal::ObjectSafe(*trait_id));
}
}
DomainGoal::WellFormed(WellFormed::Ty(ty))
| DomainGoal::IsUpstream(ty)
| DomainGoal::DownstreamType(ty)
| DomainGoal::IsFullyVisible(ty)
| DomainGoal::IsLocal(ty) => match_ty(builder, environment, ty)?,
DomainGoal::FromEnv(_) => (), // Computed in the environment
DomainGoal::Normalize(Normalize { alias, ty: _ }) => match alias {
AliasTy::Projection(proj) => {
// Normalize goals derive from `AssociatedTyValue` datums,
// which are found in impls. That is, if we are
// normalizing (e.g.) `<T as Iterator>::Item>`, then
// search for impls of iterator and, within those impls,
// for associated type values:
//
// ```ignore
// impl Iterator for Foo {
// type Item = Bar; // <-- associated type value
// }
// ```
let associated_ty_datum = db.associated_ty_data(proj.associated_ty_id);
let trait_id = associated_ty_datum.trait_id;
let trait_ref = db.trait_ref_from_projection(proj);
let trait_parameters = trait_ref.substitution.as_parameters(interner);
let trait_datum = db.trait_datum(trait_id);
let self_ty = trait_ref.self_type_parameter(interner);
if let TyKind::InferenceVar(_, _) = self_ty.kind(interner) {
panic!("Inference vars not allowed when getting program clauses");
}
// Flounder if the self-type is unknown and the trait is non-enumerable.
//
// e.g., Normalize(<?X as Iterator>::Item = u32)
if (self_ty.is_general_var(interner, binders))
&& trait_datum.is_non_enumerable_trait()
{
return Err(Floundered);
}
if let Some(well_known) = trait_datum.well_known {
builtin_traits::add_builtin_assoc_program_clauses(
db, builder, well_known, self_ty,
)?;
}
push_program_clauses_for_associated_type_values_in_impls_of(
builder,
environment,
trait_id,
trait_parameters,
binders,
);
if environment.has_compatible_clause(interner) {
push_clauses_for_compatible_normalize(
db,
builder,
interner,
trait_id,
proj.associated_ty_id,
);
}
}
AliasTy::Opaque(_) => (),
},
DomainGoal::Compatible | DomainGoal::Reveal => (),
};
Ok(clauses)
}
/// Adds clauses to allow normalizing possible downstream associated type
/// implementations when in the "compatible" mode. Example clauses:
///
/// ```notrust
/// for<type, type, type> Normalize(<^0.0 as Trait<^0.1>>::Item -> ^0.2)
/// :- Compatible, Implemented(^0.0: Trait<^0.1>), DownstreamType(^0.1), CannotProve
/// for<type, type, type> Normalize(<^0.0 as Trait<^0.1>>::Item -> ^0.2)
/// :- Compatible, Implemented(^0.0: Trait<^0.1>), IsFullyVisible(^0.0), DownstreamType(^0.1), CannotProve
/// ```
fn push_clauses_for_compatible_normalize<I: Interner>(
db: &dyn RustIrDatabase<I>,
builder: &mut ClauseBuilder<'_, I>,
interner: I,
trait_id: TraitId<I>,
associated_ty_id: AssocTypeId<I>,
) {
let trait_datum = db.trait_datum(trait_id);
let trait_binders = trait_datum.binders.map_ref(|b| &b.where_clauses).cloned();
builder.push_binders(trait_binders, |builder, where_clauses| {
let projection = ProjectionTy {
associated_ty_id,
substitution: builder.substitution_in_scope(),
};
let trait_ref = TraitRef {
trait_id,
substitution: builder.substitution_in_scope(),
};
let type_parameters: Vec<_> = trait_ref.type_parameters(interner).collect();
builder.push_bound_ty(|builder, target_ty| {
for i in 0..type_parameters.len() {
builder.push_clause(
DomainGoal::Normalize(Normalize {
ty: target_ty.clone(),
alias: AliasTy::Projection(projection.clone()),
}),
where_clauses
.iter()
.cloned()
.casted(interner)
.chain(iter::once(DomainGoal::Compatible.cast(interner)))
.chain(iter::once(
WhereClause::Implemented(trait_ref.clone()).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))),
);
}
});
});
}
/// Generate program clauses from the associated-type values
/// found in impls of the given trait. i.e., if `trait_id` = Iterator,
/// then we would generate program clauses from each `type Item = ...`
/// found in any impls of `Iterator`:
/// which are found in impls. That is, if we are
/// normalizing (e.g.) `<T as Iterator>::Item>`, then
/// search for impls of iterator and, within those impls,
/// for associated type values:
///
/// ```ignore
/// impl Iterator for Foo {
/// type Item = Bar; // <-- associated type value
/// }
/// ```
#[instrument(level = "debug", skip(builder))]
fn push_program_clauses_for_associated_type_values_in_impls_of<I: Interner>(
builder: &mut ClauseBuilder<'_, I>,
environment: &Environment<I>,
trait_id: TraitId<I>,
trait_parameters: &[GenericArg<I>],
binders: &CanonicalVarKinds<I>,
) {
for impl_id in builder
.db
.impls_for_trait(trait_id, trait_parameters, binders)
{
let impl_datum = builder.db.impl_datum(impl_id);
if !impl_datum.is_positive() {
continue;
}
debug!(?impl_id);
for &atv_id in &impl_datum.associated_ty_value_ids {
let atv = builder.db.associated_ty_value(atv_id);
debug!(?atv_id, ?atv);
atv.to_program_clauses(builder, environment);
}
}
}
fn push_alias_implemented_clause<I: Interner>(
builder: &mut ClauseBuilder<'_, I>,
trait_ref: TraitRef<I>,
alias: AliasTy<I>,
) {
let interner = builder.interner();
assert_eq!(
*trait_ref.self_type_parameter(interner).kind(interner),
TyKind::Alias(alias.clone())
);
// TODO: instead generate clauses without reference to the specific type parameters of the goal?
let generalized = generalize::Generalize::apply(interner, (trait_ref, alias));
builder.push_binders(generalized, |builder, (trait_ref, alias)| {
let binders = Binders::with_fresh_type_var(interner, |ty_var| ty_var);
// forall<..., T> {
// <X as Y>::Z: Trait :- T: Trait, <X as Y>::Z == T
// }
builder.push_binders(binders, |builder, bound_var| {
let fresh_self_subst = Substitution::from_iter(
interner,
std::iter::once(bound_var.clone().cast(interner)).chain(
trait_ref.substitution.as_slice(interner)[1..]
.iter()
.cloned(),
),
);
let fresh_self_trait_ref = TraitRef {
trait_id: trait_ref.trait_id,
substitution: fresh_self_subst,
};
builder.push_clause(
DomainGoal::Holds(WhereClause::Implemented(trait_ref.clone())),
&[
DomainGoal::Holds(WhereClause::Implemented(fresh_self_trait_ref)),
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
alias: alias.clone(),
ty: bound_var,
})),
],
);
});
});
}
fn push_alias_alias_eq_clause<I: Interner>(
builder: &mut ClauseBuilder<'_, I>,
projection_ty: ProjectionTy<I>,
ty: Ty<I>,
alias: AliasTy<I>,
) {
let interner = builder.interner();
let self_ty = builder
.db
.trait_ref_from_projection(&projection_ty)
.self_type_parameter(interner);
assert_eq!(*self_ty.kind(interner), TyKind::Alias(alias.clone()));
// TODO: instead generate clauses without reference to the specific type parameters of the goal?
let generalized = generalize::Generalize::apply(interner, (projection_ty, ty, alias));
builder.push_binders(generalized, |builder, (projection_ty, ty, alias)| {
let binders = Binders::with_fresh_type_var(interner, |ty_var| ty_var);
// forall<..., T> {
// <<X as Y>::A as Z>::B == U :- <T as Z>::B == U, <X as Y>::A == T
// }
builder.push_binders(binders, |builder, bound_var| {
let (_, trait_args, assoc_args) = builder.db.split_projection(&projection_ty);
let fresh_self_subst = Substitution::from_iter(
interner,
assoc_args
.iter()
.cloned()
.chain(std::iter::once(bound_var.clone().cast(interner)))
.chain(trait_args[1..].iter().cloned()),
);
let fresh_alias = AliasTy::Projection(ProjectionTy {
associated_ty_id: projection_ty.associated_ty_id,
substitution: fresh_self_subst,
});
builder.push_clause(
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
alias: AliasTy::Projection(projection_ty.clone()),
ty: ty.clone(),
})),
&[
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
alias: fresh_alias,
ty: ty.clone(),
})),
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
alias: alias.clone(),
ty: bound_var,
})),
],
);
});
});
}
/// Examine `T` and push clauses that may be relevant to proving the
/// following sorts of goals (and maybe others):
///
/// * `DomainGoal::WellFormed(T)`
/// * `DomainGoal::IsUpstream(T)`
/// * `DomainGoal::DownstreamType(T)`
/// * `DomainGoal::IsFullyVisible(T)`
/// * `DomainGoal::IsLocal(T)`
///
/// Note that the type `T` must not be an unbound inference variable;
/// earlier parts of the logic should "flounder" in that case.
fn match_ty<I: Interner>(
builder: &mut ClauseBuilder<'_, I>,
environment: &Environment<I>,
ty: &Ty<I>,
) -> Result<(), Floundered> {
let interner = builder.interner();
match ty.kind(interner) {
TyKind::InferenceVar(_, _) => {
panic!("Inference vars not allowed when getting program clauses")
}
TyKind::Adt(adt_id, _) => builder
.db
.adt_datum(*adt_id)
.to_program_clauses(builder, environment),
TyKind::OpaqueType(opaque_ty_id, _) => builder
.db
.opaque_ty_data(*opaque_ty_id)
.to_program_clauses(builder, environment),
TyKind::Error => {}
TyKind::AssociatedType(type_id, _) => builder
.db
.associated_ty_data(*type_id)
.to_program_clauses(builder, environment),
TyKind::FnDef(fn_def_id, _) => builder
.db
.fn_def_datum(*fn_def_id)
.to_program_clauses(builder, environment),
TyKind::Str
| TyKind::Never
| TyKind::Scalar(_)
| TyKind::Foreign(_)
| TyKind::Tuple(0, _) => {
// These have no substitutions, so they are trivially WF
builder.push_fact(WellFormed::Ty(ty.clone()));
}
TyKind::Raw(mutbl, _) => {
// forall<T> WF(*const T) :- WF(T);
builder.push_bound_ty(|builder, ty| {
builder.push_clause(
WellFormed::Ty(TyKind::Raw(*mutbl, ty.clone()).intern(builder.interner())),
Some(WellFormed::Ty(ty)),
);
});
}
TyKind::Ref(mutbl, _, _) => {
// forall<'a, T> WF(&'a T) :- WF(T), T: 'a
builder.push_bound_ty(|builder, ty| {
builder.push_bound_lifetime(|builder, lifetime| {
let ref_ty = TyKind::Ref(*mutbl, lifetime.clone(), ty.clone())
.intern(builder.interner());
builder.push_clause(
WellFormed::Ty(ref_ty),
[
DomainGoal::WellFormed(WellFormed::Ty(ty.clone())),
DomainGoal::Holds(WhereClause::TypeOutlives(TypeOutlives {
ty,
lifetime,
})),
],
);
})
});
}
TyKind::Slice(_) => {
// forall<T> WF([T]) :- T: Sized, WF(T)
builder.push_bound_ty(|builder, ty| {
let sized = builder.db.well_known_trait_id(WellKnownTrait::Sized);
builder.push_clause(
WellFormed::Ty(TyKind::Slice(ty.clone()).intern(builder.interner())),
sized
.map(|id| {
DomainGoal::Holds(WhereClause::Implemented(TraitRef {
trait_id: id,
substitution: Substitution::from1(interner, ty.clone()),
}))
})
.into_iter()
.chain(Some(DomainGoal::WellFormed(WellFormed::Ty(ty)))),
);
});
}
TyKind::Array(..) => {
// forall<T. const N: usize> WF([T, N]) :- T: Sized
let interner = builder.interner();
let binders = Binders::new(
VariableKinds::from_iter(
interner,
[
VariableKind::Ty(TyVariableKind::General),
VariableKind::Const(
TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(interner),
),
],
),
PhantomData::<I>,
);
builder.push_binders(binders, |builder, PhantomData| {
let placeholders_in_scope = builder.placeholders_in_scope();
let placeholder_count = placeholders_in_scope.len();
let ty = placeholders_in_scope[placeholder_count - 2]
.assert_ty_ref(interner)
.clone();
let size = placeholders_in_scope[placeholder_count - 1]
.assert_const_ref(interner)
.clone();
let sized = builder.db.well_known_trait_id(WellKnownTrait::Sized);
let array_ty = TyKind::Array(ty.clone(), size).intern(interner);
builder.push_clause(
WellFormed::Ty(array_ty),
sized
.map(|id| {
DomainGoal::Holds(WhereClause::Implemented(TraitRef {
trait_id: id,
substitution: Substitution::from1(interner, ty.clone()),
}))
})
.into_iter()
.chain(Some(DomainGoal::WellFormed(WellFormed::Ty(ty)))),
);
});
}
TyKind::Tuple(len, _) => {
// WF((T0, ..., Tn, U)) :- T0: Sized, ..., Tn: Sized, WF(T0), ..., WF(Tn), WF(U)
let interner = builder.interner();
let binders = Binders::new(
VariableKinds::from_iter(
interner,
iter::repeat_with(|| VariableKind::Ty(TyVariableKind::General)).take(*len),
),
PhantomData::<I>,
);
builder.push_binders(binders, |builder, PhantomData| {
let placeholders_in_scope = builder.placeholders_in_scope();
let substs = Substitution::from_iter(
builder.interner(),
&placeholders_in_scope[placeholders_in_scope.len() - len..],
);
let tuple_ty = TyKind::Tuple(*len, substs.clone()).intern(interner);
let sized = builder.db.well_known_trait_id(WellKnownTrait::Sized);
builder.push_clause(
WellFormed::Ty(tuple_ty),
substs.as_slice(interner)[..*len - 1]
.iter()
.filter_map(|s| {
let ty_var = s.assert_ty_ref(interner).clone();
sized.map(|id| {
DomainGoal::Holds(WhereClause::Implemented(TraitRef {
trait_id: id,
substitution: Substitution::from1(interner, ty_var),
}))
})
})
.chain(substs.iter(interner).map(|subst| {
DomainGoal::WellFormed(WellFormed::Ty(
subst.assert_ty_ref(interner).clone(),
))
})),
);
});
}
TyKind::Closure(_, _) | TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => {
let ty = generalize::Generalize::apply(builder.db.interner(), ty.clone());
builder.push_binders(ty, |builder, ty| {
builder.push_fact(WellFormed::Ty(ty));
});
}
TyKind::Placeholder(_) => {
builder.push_fact(WellFormed::Ty(ty.clone()));
}
TyKind::Alias(AliasTy::Projection(proj)) => builder
.db
.associated_ty_data(proj.associated_ty_id)
.to_program_clauses(builder, environment),
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => builder
.db
.opaque_ty_data(opaque_ty.opaque_ty_id)
.to_program_clauses(builder, environment),
TyKind::Function(_quantified_ty) => {
let ty = generalize::Generalize::apply(builder.db.interner(), ty.clone());
builder.push_binders(ty, |builder, ty| builder.push_fact(WellFormed::Ty(ty)));
}
TyKind::BoundVar(_) => return Err(Floundered),
TyKind::Dyn(dyn_ty) => {
// FIXME(#203)
// - Object safety? (not needed with RFC 2027)
// - Implied bounds
// - Bounds on the associated types
// - Checking that all associated types are specified, including
// those on supertraits.
// - For trait objects with GATs, if we allow them in the future,
// check that the bounds are fully general (
// `dyn for<'a> StreamingIterator<Item<'a> = &'a ()>` is OK,
// `dyn StreamingIterator<Item<'static> = &'static ()>` is not).
let generalized_ty =
generalize::Generalize::apply(builder.db.interner(), dyn_ty.clone());
builder.push_binders(generalized_ty, |builder, dyn_ty| {
let bounds = dyn_ty
.bounds
.substitute(interner, &[ty.clone().cast::<GenericArg<I>>(interner)]);
let mut wf_goals = Vec::new();
wf_goals.extend(bounds.iter(interner).flat_map(|bound| {
bound.map_ref(|bound| -> Vec<_> {
match bound {
WhereClause::Implemented(trait_ref) => {
vec![DomainGoal::WellFormed(WellFormed::Trait(trait_ref.clone()))]
}
WhereClause::AliasEq(_)
| WhereClause::LifetimeOutlives(_)
| WhereClause::TypeOutlives(_) => vec![],
}
})
}));
builder.push_clause(WellFormed::Ty(ty.clone()), wf_goals);
});
}
}
Ok(())
}
fn match_alias_ty<I: Interner>(
builder: &mut ClauseBuilder<'_, I>,
environment: &Environment<I>,
alias: &AliasTy<I>,
) {
if let AliasTy::Projection(projection_ty) = alias {
builder
.db
.associated_ty_data(projection_ty.associated_ty_id)
.to_program_clauses(builder, environment)
}
}
#[instrument(level = "debug", skip(db))]
pub fn program_clauses_for_env<'db, I: Interner>(
db: &'db dyn RustIrDatabase<I>,
environment: &Environment<I>,
) -> ProgramClauses<I> {
let mut last_round = environment
.clauses
.as_slice(db.interner())
.iter()
.cloned()
.collect::<FxHashSet<_>>();
let mut closure = last_round.clone();
let mut next_round = FxHashSet::default();
while !last_round.is_empty() {
elaborate_env_clauses(
db,
&last_round.drain().collect::<Vec<_>>(),
&mut next_round,
environment,
);
last_round.extend(
next_round
.drain()
.filter(|clause| closure.insert(clause.clone())),
);
}
ProgramClauses::from_iter(db.interner(), closure)
}