diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:21 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:21 +0000 |
commit | 4e8199b572f2035b7749cba276ece3a26630d23e (patch) | |
tree | f09feeed6a0fe39d027b1908aa63ea6b35e4b631 /vendor/chalk-solve | |
parent | Adding upstream version 1.66.0+dfsg1. (diff) | |
download | rustc-4e8199b572f2035b7749cba276ece3a26630d23e.tar.xz rustc-4e8199b572f2035b7749cba276ece3a26630d23e.zip |
Adding upstream version 1.67.1+dfsg1.upstream/1.67.1+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/chalk-solve')
52 files changed, 13457 insertions, 0 deletions
diff --git a/vendor/chalk-solve/.cargo-checksum.json b/vendor/chalk-solve/.cargo-checksum.json new file mode 100644 index 000000000..f93fb555d --- /dev/null +++ b/vendor/chalk-solve/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"0af41724ea071b728ceab0fbee7e1783208b880ad7b4686c0c7cd9bc18f56492","README.md":"2de2da988dbbaa8feb78b0a771b7bee942f34705ab057c824b1183300c535c74","src/clauses.rs":"ebb72db87c40e17b2607f582626345286f3def126b5ca5d07e30d2de8ecc70ac","src/clauses/builder.rs":"b8bda05d9e0fca83b6b96b72fae56ea57e2d21c3c2dbb8e72ba0d8b8faeefcbe","src/clauses/builtin_traits.rs":"74839e05dc0be11790a097a01caae15cc085403ccc45b3d853f80c96745d456f","src/clauses/builtin_traits/clone.rs":"36c4603367cfa285043dfd8153121b53df0ee4e4619f7777b4a90d754d6a7942","src/clauses/builtin_traits/copy.rs":"e46a76240b6af043db19ec7fb73d82b9287c5f556075b758bc36aa0d2f574098","src/clauses/builtin_traits/discriminant_kind.rs":"4c987b4c4547586c0180e40cffa1073569a2a3fb50ac56738f962eba6b50f536","src/clauses/builtin_traits/fn_family.rs":"c3eb3594481066bc21593e7663e7e98e110d696854878fbcb43c03ae4971a1f4","src/clauses/builtin_traits/generator.rs":"a8663274c02f4e8b76e6d46c297723d9293b533dd6f45f0c267de177bc809b90","src/clauses/builtin_traits/sized.rs":"2be4e91ce170756dd6a01d334a037a39464e41a5e7fe6f088de55a7332752092","src/clauses/builtin_traits/tuple.rs":"64625a0f2d9c4bcde0c3b68574e517d928429bad29f80d838ad76062694c2124","src/clauses/builtin_traits/unsize.rs":"ba05d22f757e86fa1d901048a29ca94e725eae4f6abbdfe4940404d299bc2e20","src/clauses/dyn_ty.rs":"1d13771582d92c7de96a96bdd2ff7b3ebd26dc1a4d773ee55c5456e3920308b4","src/clauses/env_elaborator.rs":"ad4cd93294f75c1c49fe17aea1cfd41ae4894f10893628a313179ae199fff988","src/clauses/generalize.rs":"68a60005ba8056e9b6a2a5282d17ff6699f1990b0eb6d8bf19b2cd958d8c6b24","src/clauses/program_clauses.rs":"74ace617cf3cf04e00c8905a110f3f04267b7ad1a503309475e232fad5789e9d","src/clauses/super_traits.rs":"e2452a7abb7b8eb8d8ac59cd3032aee8fbc4c52d37954dd8675d3760b80894ba","src/coherence.rs":"452dedfba4db073dc40c3ec25017be6214fed28838f25ec916024664f31ced7d","src/coherence/orphan.rs":"621a839058309f1977e9eea972afa1622a372e06889d8d20aff64788cfba1829","src/coherence/solve.rs":"6677fd4ee28154f72e6d7c34ad3a637323f5169efe54f96e7f7f1b5577f3fa00","src/coinductive_goal.rs":"7a2179fb2d61435cf55c5c87301db6c15edb3cb46750bea381451649b2f1051d","src/display.rs":"ffdb5a8f3523073a3360a48c8be9eaa85f431bff5dc9642d4a929be85ee2984a","src/display/bounds.rs":"7a57ee1dddc199afe933dd76fb5b27f5dbe84ec1a9405c3d4bfb61c3add911dc","src/display/identifiers.rs":"22937fc099812dd9282c20c77ad3797cfa13a8838a0c68638bc4fc32178afbc8","src/display/items.rs":"1464006f0b2684c8092e063fb28ea1e7d0fb77241b76d050b560ac11eb25a8c1","src/display/render_trait.rs":"ccdcbe8e5a1771630dd61eb24b8e384fc30147c285bd40865f9ccc87ab4931b7","src/display/state.rs":"290160db2dd813493f49041b7d21f14f0006bd60a96fb87dd79b5ce44713953a","src/display/stub.rs":"d991613e060871ea638c479e3cdeba67c533a3d4ca68fb0820f3807159c89356","src/display/ty.rs":"5b1a9e8d75c0644df16613cf2f53c8187adc21f1a8db4641b475674b84b07f4f","src/display/utils.rs":"98b0da45184c3934c5707245fdb501e72aa9c916d840907b3b71ca03da51166b","src/ext.rs":"f09806bce122cd3439cfa184435c264cf410eb03c7a6894d428393b745159841","src/goal_builder.rs":"ae59a6f0f3e96eddd197e8887693e6a56506ed848c4698d0a10a9817bd4ff02b","src/infer.rs":"773fe717cccf8e5544d211a10dbece0114fa99f00b587fdb84316c0adc50171b","src/infer/canonicalize.rs":"4d1e7607f779b8806a1a5ecbe6c91101083bf776467b00e7fae5e40e91ad4149","src/infer/instantiate.rs":"ae9a0c3b6d9c898c9429f189c22ff07d00e6784d54520a0b96a6b986d100bb4b","src/infer/invert.rs":"0f016e422ebf94b6b6fad175c6fb7f485ec5b51de4ba0810c782485a2454838d","src/infer/test.rs":"f2285b18331872f2ae639861d318c275b41bd7cbc52a42faa268f339c3313f3e","src/infer/ucanonicalize.rs":"2d94c4fa04026a03ea99ecfd6ec626a4b6f9e834bafd5278f3540e4373519b1e","src/infer/unify.rs":"2b7b3e7aedff0d21c96666e8bdf01b10c125f6057917d6bffb99a8b5f0c95d8f","src/infer/var.rs":"8d657864a789914d1699ca9bc4eb254af381a58c849533d1f4870c5ccad2eaf9","src/lib.rs":"042452f221434c425df391376e07451077d02a2b53358ee416f92b56c3149c20","src/logging.rs":"74445ce59542b977ddb47061294c6772e1d3978b0cdf99e6440ea0dcb698aaba","src/logging_db.rs":"ef66043e71e95796ab24321ecc0b15325b65e3bcfd3fc234acde435972f6ef29","src/logging_db/id_collector.rs":"1286b8fd9ee9b28673907dfc568b2fb6ae072c529f8c517c46861ca3b96e94f8","src/rust_ir.rs":"2182dcaa7015184f46e9d97f6930e352617ec75f5daab4baf87d3c2e452f7108","src/solve.rs":"b91a974ec50ab8c8e37cd2eb8845df0b046910a53df205eb5b07d2793b491f66","src/solve/test/bench.rs":"8da8bb948bdf598ed7f225fd695b12c9e8626cd7a14d4b7d8650de0fae73d655","src/solve/truncate.rs":"d9890902006dccb5e6b4b6347435043be10132ace9b78692a8ebe13b0410901a","src/split.rs":"63d6f033be45da36248188993f747038c6dcd8b4a728427fc79b6ced26368e0d","src/wf.rs":"9934b840a0e7f6225fc3586b8979b200f74b75cf3ef71faaada11344ef33edbd"},"package":"61213deefc36ba265ad01c4d997e18bcddf7922862a4594a47ca4575afb3dab4"}
\ No newline at end of file diff --git a/vendor/chalk-solve/Cargo.toml b/vendor/chalk-solve/Cargo.toml new file mode 100644 index 000000000..b57214aa8 --- /dev/null +++ b/vendor/chalk-solve/Cargo.toml @@ -0,0 +1,70 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "chalk-solve" +version = "0.87.0" +authors = [ + "Rust Compiler Team", + "Chalk developers", +] +description = "Combines the chalk-engine with chalk-ir" +readme = "README.md" +keywords = [ + "compiler", + "traits", + "prolog", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/chalk" + +[dependencies.chalk-derive] +version = "=0.87.0" + +[dependencies.chalk-ir] +version = "=0.87.0" + +[dependencies.ena] +version = "0.14.0" + +[dependencies.indexmap] +version = "1.8.0" + +[dependencies.itertools] +version = "0.10.0" + +[dependencies.petgraph] +version = "0.5.1" + +[dependencies.rustc-hash] +version = "1.1.0" + +[dependencies.tracing] +version = "0.1" + +[dependencies.tracing-subscriber] +version = "0.3" +features = ["env-filter"] +optional = true + +[dependencies.tracing-tree] +version = "0.2" +optional = true + +[dev-dependencies] + +[features] +default = ["tracing-full"] +tracing-full = [ + "tracing-subscriber", + "tracing-tree", +] diff --git a/vendor/chalk-solve/README.md b/vendor/chalk-solve/README.md new file mode 100644 index 000000000..bed41761d --- /dev/null +++ b/vendor/chalk-solve/README.md @@ -0,0 +1,3 @@ +A library that defines the rules that translates Rust IR to logical predicates. + +See [Github](https://github.com/rust-lang/chalk) for up-to-date information. diff --git a/vendor/chalk-solve/src/clauses.rs b/vendor/chalk-solve/src/clauses.rs new file mode 100644 index 000000000..e3fdd351b --- /dev/null +++ b/vendor/chalk-solve/src/clauses.rs @@ -0,0 +1,1132 @@ +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 fresh_self_subst = Substitution::from_iter( + interner, + std::iter::once(bound_var.clone().cast(interner)).chain( + projection_ty.substitution.as_slice(interner)[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) +} diff --git a/vendor/chalk-solve/src/clauses/builder.rs b/vendor/chalk-solve/src/clauses/builder.rs new file mode 100644 index 000000000..bbe7c2fd2 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/builder.rs @@ -0,0 +1,207 @@ +use std::marker::PhantomData; + +use crate::cast::{Cast, CastTo}; +use crate::RustIrDatabase; +use chalk_ir::fold::{Shift, TypeFoldable}; +use chalk_ir::interner::{HasInterner, Interner}; +use chalk_ir::*; +use tracing::{debug, instrument}; + +/// The "clause builder" is a useful tool for building up sets of +/// program clauses. It takes ownership of the output vector while it +/// lasts, and offers methods like `push_clause` and so forth to +/// append to it. +pub struct ClauseBuilder<'me, I: Interner> { + pub db: &'me dyn RustIrDatabase<I>, + clauses: &'me mut Vec<ProgramClause<I>>, + binders: Vec<VariableKind<I>>, + parameters: Vec<GenericArg<I>>, +} + +impl<'me, I: Interner> ClauseBuilder<'me, I> { + pub fn new(db: &'me dyn RustIrDatabase<I>, clauses: &'me mut Vec<ProgramClause<I>>) -> Self { + Self { + db, + clauses, + binders: vec![], + parameters: vec![], + } + } + + /// Pushes a "fact" `forall<..> { consequence }` into the set of + /// program clauses, meaning something that we can assume to be + /// true unconditionally. The `forall<..>` binders will be + /// whichever binders have been pushed (see `push_binders`). + pub fn push_fact(&mut self, consequence: impl CastTo<DomainGoal<I>>) { + self.push_clause(consequence, None::<Goal<_>>); + } + + /// Pushes a "fact" `forall<..> { consequence }` into the set of + /// program clauses, meaning something that we can assume to be + /// true unconditionally. The `forall<..>` binders will be + /// whichever binders have been pushed (see `push_binders`). + pub fn push_fact_with_priority( + &mut self, + consequence: impl CastTo<DomainGoal<I>>, + constraints: impl IntoIterator<Item = InEnvironment<Constraint<I>>>, + priority: ClausePriority, + ) { + self.push_clause_with_priority(consequence, None::<Goal<_>>, constraints, priority); + } + + /// Pushes a clause `forall<..> { consequence :- conditions }` + /// into the set of program clauses, meaning that `consequence` + /// can be proven if `conditions` are all true. The `forall<..>` + /// binders will be whichever binders have been pushed (see `push_binders`). + pub fn push_clause( + &mut self, + consequence: impl CastTo<DomainGoal<I>>, + conditions: impl IntoIterator<Item = impl CastTo<Goal<I>>>, + ) { + self.push_clause_with_priority(consequence, conditions, None, ClausePriority::High) + } + + pub fn push_fact_with_constraints( + &mut self, + consequence: impl CastTo<DomainGoal<I>>, + constraints: impl IntoIterator<Item = InEnvironment<Constraint<I>>>, + ) { + self.push_fact_with_priority(consequence, constraints, ClausePriority::High) + } + + /// Pushes a clause `forall<..> { consequence :- conditions ; constraints }` + /// into the set of program clauses, meaning that `consequence` + /// can be proven if `conditions` are all true and `constraints` + /// are proven to hold. The `forall<..>` binders will be whichever binders + /// have been pushed (see `push_binders`). + pub fn push_clause_with_priority( + &mut self, + consequence: impl CastTo<DomainGoal<I>>, + conditions: impl IntoIterator<Item = impl CastTo<Goal<I>>>, + constraints: impl IntoIterator<Item = InEnvironment<Constraint<I>>>, + priority: ClausePriority, + ) { + let interner = self.db.interner(); + let clause = ProgramClauseImplication { + consequence: consequence.cast(interner), + conditions: Goals::from_iter(interner, conditions), + constraints: Constraints::from_iter(interner, constraints), + priority, + }; + + let clause = if self.binders.is_empty() { + // Compensate for the added empty binder + clause.shifted_in(interner) + } else { + clause + }; + + self.clauses.push( + ProgramClauseData(Binders::new( + VariableKinds::from_iter(interner, self.binders.clone()), + clause, + )) + .intern(interner), + ); + + debug!("pushed clause {:?}", self.clauses.last()); + } + + /// Accesses the placeholders for the current list of parameters in scope. + pub fn placeholders_in_scope(&self) -> &[GenericArg<I>] { + &self.parameters + } + + /// Accesses the placeholders for the current list of parameters in scope, + /// in the form of a `Substitution`. + pub fn substitution_in_scope(&self) -> Substitution<I> { + Substitution::from_iter( + self.db.interner(), + self.placeholders_in_scope().iter().cloned(), + ) + } + + /// Executes `op` with the `binders` in-scope; `op` is invoked + /// with the bound value `v` as a parameter. After `op` finishes, + /// the binders are popped from scope. + /// + /// The new binders are always pushed onto the end of the internal + /// list of binders; this means that any extant values where were + /// created referencing the *old* list of binders are still valid. + #[instrument(level = "debug", skip(self, op))] + pub fn push_binders<R, V>( + &mut self, + binders: Binders<V>, + op: impl FnOnce(&mut Self, V) -> R, + ) -> R + where + V: TypeFoldable<I> + HasInterner<Interner = I>, + V: std::fmt::Debug, + { + let old_len = self.binders.len(); + let interner = self.interner(); + self.binders.extend(binders.binders.iter(interner).cloned()); + self.parameters.extend( + binders + .binders + .iter(interner) + .zip(old_len..) + .map(|(pk, i)| (i, pk).to_generic_arg(interner)), + ); + let value = binders.substitute(self.interner(), &self.parameters[old_len..]); + debug!(?value); + let res = op(self, value); + + self.binders.truncate(old_len); + self.parameters.truncate(old_len); + res + } + + /// Push a single binder, for a type, at the end of the binder + /// list. The indices of previously bound variables are + /// unaffected and hence the context remains usable. Invokes `op`, + /// passing a type representing this new type variable in as an + /// argument. + pub fn push_bound_ty(&mut self, op: impl FnOnce(&mut Self, Ty<I>)) { + let interner = self.interner(); + let binders = Binders::new( + VariableKinds::from1(interner, VariableKind::Ty(TyVariableKind::General)), + PhantomData::<I>, + ); + self.push_binders(binders, |this, PhantomData| { + let ty = this + .placeholders_in_scope() + .last() + .unwrap() + .assert_ty_ref(interner) + .clone(); + op(this, ty) + }); + } + + /// Push a single binder, for a lifetime, at the end of the binder + /// list. The indices of previously bound variables are + /// unaffected and hence the context remains usable. Invokes `op`, + /// passing a lifetime representing this new lifetime variable in as an + /// argument. + pub fn push_bound_lifetime(&mut self, op: impl FnOnce(&mut Self, Lifetime<I>)) { + let interner = self.interner(); + let binders = Binders::new( + VariableKinds::from1(interner, VariableKind::Lifetime), + PhantomData::<I>, + ); + self.push_binders(binders, |this, PhantomData| { + let lifetime = this + .placeholders_in_scope() + .last() + .unwrap() + .assert_lifetime_ref(interner) + .clone(); + op(this, lifetime) + }); + } + + pub fn interner(&self) -> I { + self.db.interner() + } +} diff --git a/vendor/chalk-solve/src/clauses/builtin_traits.rs b/vendor/chalk-solve/src/clauses/builtin_traits.rs new file mode 100644 index 000000000..b5a1c7d57 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/builtin_traits.rs @@ -0,0 +1,119 @@ +use super::{builder::ClauseBuilder, generalize}; +use crate::{CanonicalVarKinds, Interner, RustIrDatabase, TraitRef, WellKnownTrait}; +use chalk_ir::{Floundered, Substitution, Ty}; + +mod clone; +mod copy; +mod discriminant_kind; +mod fn_family; +mod generator; +mod sized; +mod tuple; +mod unsize; + +/// For well known traits we have special hard-coded impls, either as an +/// optimization or to enforce special rules for correctness. +pub fn add_builtin_program_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + well_known: WellKnownTrait, + trait_ref: TraitRef<I>, + binders: &CanonicalVarKinds<I>, +) -> Result<(), Floundered> { + // If `trait_ref` contains bound vars, we want to universally quantify them. + // `Generalize` collects them for us. + let generalized = generalize::Generalize::apply(db.interner(), trait_ref); + + builder.push_binders(generalized, |builder, trait_ref| { + let self_ty = trait_ref.self_type_parameter(db.interner()); + let ty = self_ty.kind(db.interner()).clone(); + + match well_known { + // Built-in traits are non-enumerable. + _ if self_ty.is_general_var(db.interner(), binders) => return Err(Floundered), + WellKnownTrait::Sized => { + sized::add_sized_program_clauses(db, builder, trait_ref, ty, binders)?; + } + WellKnownTrait::Copy => { + copy::add_copy_program_clauses(db, builder, trait_ref, ty, binders)?; + } + WellKnownTrait::Clone => { + clone::add_clone_program_clauses(db, builder, trait_ref, ty, binders)?; + } + WellKnownTrait::FnOnce | WellKnownTrait::FnMut | WellKnownTrait::Fn => { + fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty); + } + WellKnownTrait::Unsize => { + unsize::add_unsize_program_clauses(db, builder, trait_ref, ty) + } + // DiscriminantKind is automatically implemented for all types + WellKnownTrait::DiscriminantKind => builder.push_fact(trait_ref), + WellKnownTrait::Generator => { + generator::add_generator_program_clauses(db, builder, self_ty)?; + } + WellKnownTrait::Tuple => { + tuple::add_tuple_program_clauses(db, builder, self_ty)?; + } + // There are no builtin impls provided for the following traits: + WellKnownTrait::Unpin + | WellKnownTrait::Drop + | WellKnownTrait::CoerceUnsized + | WellKnownTrait::DispatchFromDyn => (), + } + Ok(()) + }) +} + +/// Like `add_builtin_program_clauses`, but for `DomainGoal::Normalize` involving +/// a projection (e.g. `<fn(u8) as FnOnce<(u8,)>>::Output`) +pub fn add_builtin_assoc_program_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + well_known: WellKnownTrait, + self_ty: Ty<I>, +) -> Result<(), Floundered> { + match well_known { + WellKnownTrait::FnOnce => { + // If `self_ty` contains bound vars, we want to universally quantify them. + // `Generalize` collects them for us. + let generalized = generalize::Generalize::apply(db.interner(), self_ty); + + builder.push_binders(generalized, |builder, self_ty| { + fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty); + Ok(()) + }) + } + WellKnownTrait::DiscriminantKind => { + discriminant_kind::add_discriminant_clauses(db, builder, self_ty) + } + WellKnownTrait::Generator => { + let generalized = generalize::Generalize::apply(db.interner(), self_ty); + + builder.push_binders(generalized, |builder, self_ty| { + generator::add_generator_program_clauses(db, builder, self_ty) + }) + } + _ => Ok(()), + } +} + +/// Given a trait ref `T0: Trait` and a list of types `U0..Un`, pushes a clause of the form +/// `Implemented(T0: Trait) :- Implemented(U0: Trait) .. Implemented(Un: Trait)` +pub fn needs_impl_for_tys<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + trait_ref: TraitRef<I>, + tys: impl Iterator<Item = Ty<I>>, +) { + let trait_id = trait_ref.trait_id; + + // The trait must take one parameter (a type) + debug_assert_eq!(db.trait_datum(trait_id).binders.len(db.interner()), 1,); + builder.push_clause( + trait_ref, + tys.map(|ty| TraitRef { + trait_id, + substitution: Substitution::from1(db.interner(), ty), + }), + ); +} diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/clone.rs b/vendor/chalk-solve/src/clauses/builtin_traits/clone.rs new file mode 100644 index 000000000..6d6b3a362 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/builtin_traits/clone.rs @@ -0,0 +1,16 @@ +use crate::clauses::ClauseBuilder; +use crate::{Interner, RustIrDatabase, TraitRef}; +use chalk_ir::{CanonicalVarKinds, Floundered, TyKind}; + +use super::copy::add_copy_program_clauses; + +pub fn add_clone_program_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + trait_ref: TraitRef<I>, + ty: TyKind<I>, + binders: &CanonicalVarKinds<I>, +) -> Result<(), Floundered> { + // Implement Clone for types that automaticly implement Copy + add_copy_program_clauses(db, builder, trait_ref, ty, binders) +} diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs b/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs new file mode 100644 index 000000000..c0174b21e --- /dev/null +++ b/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs @@ -0,0 +1,99 @@ +use crate::clauses::builtin_traits::needs_impl_for_tys; +use crate::clauses::ClauseBuilder; +use crate::{Interner, RustIrDatabase, TraitRef}; +use chalk_ir::{CanonicalVarKinds, Floundered, Substitution, TyKind, TyVariableKind, VariableKind}; +use std::iter; +use tracing::instrument; + +fn push_tuple_copy_conditions<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + trait_ref: TraitRef<I>, + arity: usize, + substitution: &Substitution<I>, +) { + // Empty tuples are always Copy + if arity == 0 { + builder.push_fact(trait_ref); + return; + } + + let interner = db.interner(); + + needs_impl_for_tys( + db, + builder, + trait_ref, + substitution + .iter(interner) + .map(|param| param.assert_ty_ref(interner).clone()), + ); +} + +#[instrument(skip(db, builder))] +pub fn add_copy_program_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + trait_ref: TraitRef<I>, + ty: TyKind<I>, + binders: &CanonicalVarKinds<I>, +) -> Result<(), Floundered> { + match ty { + TyKind::Tuple(arity, ref substitution) => { + push_tuple_copy_conditions(db, builder, trait_ref, arity, substitution) + } + TyKind::Array(ty, _) => { + needs_impl_for_tys(db, builder, trait_ref, iter::once(ty)); + } + TyKind::FnDef(_, _) => { + builder.push_fact(trait_ref); + } + TyKind::Closure(closure_id, ref substitution) => { + let closure_fn_substitution = db.closure_fn_substitution(closure_id, substitution); + let upvars = db.closure_upvars(closure_id, substitution); + let upvars = upvars.substitute(db.interner(), &closure_fn_substitution); + needs_impl_for_tys(db, builder, trait_ref, Some(upvars).into_iter()); + } + + // these impls are in libcore + TyKind::Ref(_, _, _) + | TyKind::Raw(_, _) + | TyKind::Scalar(_) + | TyKind::Never + | TyKind::Str => {} + + TyKind::Adt(_, _) + | TyKind::AssociatedType(_, _) + | TyKind::Slice(_) + | TyKind::OpaqueType(_, _) + | TyKind::Foreign(_) + | TyKind::Generator(_, _) + | TyKind::GeneratorWitness(_, _) + | TyKind::Error => {} + + TyKind::Function(_) => builder.push_fact(trait_ref), + + TyKind::InferenceVar(_, TyVariableKind::Float) + | TyKind::InferenceVar(_, TyVariableKind::Integer) => builder.push_fact(trait_ref), + + TyKind::BoundVar(bound_var) => { + let var_kind = &binders.at(db.interner(), bound_var.index).kind; + match var_kind { + VariableKind::Ty(TyVariableKind::Integer) + | VariableKind::Ty(TyVariableKind::Float) => builder.push_fact(trait_ref), + + // Don't know enough + VariableKind::Ty(TyVariableKind::General) => return Err(Floundered), + + VariableKind::Const(_) | VariableKind::Lifetime => {} + } + } + + // Don't know enough + TyKind::InferenceVar(_, TyVariableKind::General) => return Err(Floundered), + + // These should be handled elsewhere + TyKind::Alias(_) | TyKind::Dyn(_) | TyKind::Placeholder(_) => {} + }; + Ok(()) +} diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/discriminant_kind.rs b/vendor/chalk-solve/src/clauses/builtin_traits/discriminant_kind.rs new file mode 100644 index 000000000..27d49df75 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/builtin_traits/discriminant_kind.rs @@ -0,0 +1,73 @@ +use crate::clauses::ClauseBuilder; +use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait}; +use chalk_ir::{ + AliasTy, Floundered, Normalize, ProjectionTy, Substitution, Ty, TyKind, TyVariableKind, +}; + +pub fn add_discriminant_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + self_ty: Ty<I>, +) -> Result<(), Floundered> { + let interner = db.interner(); + + let can_determine_discriminant = match self_ty.data(interner).kind { + TyKind::Adt(..) + | TyKind::Array(..) + | TyKind::Tuple(..) + | TyKind::Slice(..) + | TyKind::Raw(..) + | TyKind::Ref(..) + | TyKind::Scalar(_) + | TyKind::Str + | TyKind::Never + | TyKind::FnDef(..) + | TyKind::Generator(..) + | TyKind::Closure(..) + | TyKind::GeneratorWitness(..) + | TyKind::Foreign(_) + | TyKind::Dyn(_) + | TyKind::Function(..) + | TyKind::InferenceVar(_, TyVariableKind::Integer) + | TyKind::InferenceVar(_, TyVariableKind::Float) => true, + TyKind::OpaqueType(..) + | TyKind::Alias(_) + | TyKind::BoundVar(_) + | TyKind::Placeholder(_) + | TyKind::AssociatedType(..) + | TyKind::Error + | TyKind::InferenceVar(..) => false, + }; + + if !can_determine_discriminant { + return Err(Floundered); + } + + let disc_ty = db.discriminant_type(self_ty.clone()); + + let trait_id = db + .well_known_trait_id(WellKnownTrait::DiscriminantKind) + .unwrap(); + let trait_datum = db.trait_datum(trait_id); + + let associated_ty_id = trait_datum.associated_ty_ids[0]; + let substitution = Substitution::from1(interner, self_ty); + + let trait_ref = TraitRef { + trait_id, + substitution: substitution.clone(), + }; + + let normalize = Normalize { + alias: AliasTy::Projection(ProjectionTy { + associated_ty_id, + substitution, + }), + ty: disc_ty, + }; + + builder.push_fact(trait_ref); + builder.push_fact(normalize); + + Ok(()) +} diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs b/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs new file mode 100644 index 000000000..f2358bc73 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs @@ -0,0 +1,155 @@ +use crate::clauses::ClauseBuilder; +use crate::rust_ir::{ClosureKind, FnDefInputsAndOutputDatum, WellKnownTrait}; +use crate::{Interner, RustIrDatabase, TraitRef}; +use chalk_ir::cast::Cast; +use chalk_ir::{ + AliasTy, Binders, Normalize, ProjectionTy, Safety, Substitution, TraitId, Ty, TyKind, +}; + +fn push_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + well_known: WellKnownTrait, + trait_id: TraitId<I>, + self_ty: Ty<I>, + arg_sub: Substitution<I>, + return_type: Ty<I>, +) { + let interner = db.interner(); + let tupled = TyKind::Tuple(arg_sub.len(interner), arg_sub).intern(interner); + let substitution = + Substitution::from_iter(interner, &[self_ty.cast(interner), tupled.cast(interner)]); + builder.push_fact(TraitRef { + trait_id, + substitution: substitution.clone(), + }); + + // The `Output` type is defined on the `FnOnce` + if let WellKnownTrait::FnOnce = well_known { + let trait_datum = db.trait_datum(trait_id); + assert_eq!( + trait_datum.associated_ty_ids.len(), + 1, + "FnOnce trait should have exactly one associated type, found {:?}", + trait_datum.associated_ty_ids + ); + // Constructs the alias. For `Fn`, for example, this would look like + // `Normalize(<fn(A) -> B as FnOnce<(A,)>>::Output -> B)` + let output_id = trait_datum.associated_ty_ids[0]; + let alias = AliasTy::Projection(ProjectionTy { + associated_ty_id: output_id, + substitution, + }); + builder.push_fact(Normalize { + alias, + ty: return_type, + }); + } +} + +fn push_clauses_for_apply<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + well_known: WellKnownTrait, + trait_id: TraitId<I>, + self_ty: Ty<I>, + inputs_and_output: Binders<FnDefInputsAndOutputDatum<I>>, +) { + let interner = db.interner(); + builder.push_binders(inputs_and_output, |builder, inputs_and_output| { + let arg_sub = inputs_and_output + .argument_types + .iter() + .cloned() + .map(|ty| ty.cast(interner)); + let arg_sub = Substitution::from_iter(interner, arg_sub); + let output_ty = inputs_and_output.return_type; + + push_clauses( + db, builder, well_known, trait_id, self_ty, arg_sub, output_ty, + ); + }); +} + +/// Handles clauses for FnOnce/FnMut/Fn. +/// If `self_ty` is a function, we push a clause of the form +/// `fn(A1, A2, ..., AN) -> O: FnTrait<(A1, A2, ..., AN)>`, where `FnTrait` +/// is the trait corresponding to `trait_id` (FnOnce/FnMut/Fn) +/// +/// If `trait_id` is `FnOnce`, we also push a clause for the output type of the form: +/// `Normalize(<fn(A) -> B as FnOnce<(A,)>>::Output -> B)` +/// We do not add the usual `Implemented(fn(A) -> b as FnOnce<(A,)>` clause +/// as a condition, since we already called `push_fact` with it +pub fn add_fn_trait_program_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + well_known: WellKnownTrait, + self_ty: Ty<I>, +) { + let interner = db.interner(); + let trait_id = db.well_known_trait_id(well_known).unwrap(); + + match self_ty.kind(interner) { + TyKind::FnDef(fn_def_id, substitution) => { + let fn_def_datum = builder.db.fn_def_datum(*fn_def_id); + if fn_def_datum.sig.safety == Safety::Safe && !fn_def_datum.sig.variadic { + let bound = fn_def_datum + .binders + .clone() + .substitute(builder.interner(), &substitution); + push_clauses_for_apply( + db, + builder, + well_known, + trait_id, + self_ty, + bound.inputs_and_output, + ); + } + } + TyKind::Closure(closure_id, substitution) => { + let closure_kind = db.closure_kind(*closure_id, substitution); + let trait_matches = matches!( + (well_known, closure_kind), + (WellKnownTrait::Fn, ClosureKind::Fn) + | (WellKnownTrait::FnMut, ClosureKind::FnMut | ClosureKind::Fn) + | (WellKnownTrait::FnOnce, _) + ); + if !trait_matches { + return; + } + let closure_inputs_and_output = db.closure_inputs_and_output(*closure_id, substitution); + push_clauses_for_apply( + db, + builder, + well_known, + trait_id, + self_ty, + closure_inputs_and_output, + ); + } + TyKind::Function(fn_val) if fn_val.sig.safety == Safety::Safe && !fn_val.sig.variadic => { + let bound_ref = fn_val.clone().into_binders(interner); + builder.push_binders(bound_ref, |builder, orig_sub| { + // The last parameter represents the function return type + let (arg_sub, fn_output_ty) = orig_sub + .0 + .as_slice(interner) + .split_at(orig_sub.0.len(interner) - 1); + let arg_sub = Substitution::from_iter(interner, arg_sub); + let output_ty = fn_output_ty[0].assert_ty_ref(interner).clone(); + + push_clauses( + db, + builder, + well_known, + trait_id, + self_ty.clone(), + arg_sub, + output_ty, + ); + }); + } + _ => {} + } +} diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/generator.rs b/vendor/chalk-solve/src/clauses/builtin_traits/generator.rs new file mode 100644 index 000000000..67415bfd7 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/builtin_traits/generator.rs @@ -0,0 +1,76 @@ +use crate::clauses::ClauseBuilder; +use crate::rust_ir::WellKnownTrait; +use crate::{Interner, RustIrDatabase, TraitRef}; +use chalk_ir::cast::Cast; +use chalk_ir::{AliasTy, Floundered, Normalize, ProjectionTy, Substitution, Ty, TyKind}; + +/// Add implicit impls of the generator trait, i.e., add a clause that all generators implement +/// `Generator` and clauses for `Generator`'s associated types. +pub fn add_generator_program_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + self_ty: Ty<I>, +) -> Result<(), Floundered> { + let interner = db.interner(); + + match self_ty.kind(interner) { + TyKind::Generator(id, substitution) => { + let generator_datum = db.generator_datum(*id); + let generator_io_datum = generator_datum + .input_output + .clone() + .substitute(interner, &substitution); + + let trait_id = db.well_known_trait_id(WellKnownTrait::Generator).unwrap(); + let trait_datum = db.trait_datum(trait_id); + assert_eq!( + trait_datum.associated_ty_ids.len(), + 2, + "Generator trait should have exactly two associated types, found {:?}", + trait_datum.associated_ty_ids + ); + + let substitution = Substitution::from_iter( + interner, + &[ + self_ty.cast(interner), + generator_io_datum.resume_type.cast(interner), + ], + ); + + // generator: Generator<resume_type> + builder.push_fact(TraitRef { + trait_id, + substitution: substitution.clone(), + }); + + // `Generator::Yield` + let yield_id = trait_datum.associated_ty_ids[0]; + let yield_alias = AliasTy::Projection(ProjectionTy { + associated_ty_id: yield_id, + substitution: substitution.clone(), + }); + builder.push_fact(Normalize { + alias: yield_alias, + ty: generator_io_datum.yield_type, + }); + + // `Generator::Return` + let return_id = trait_datum.associated_ty_ids[1]; + let return_alias = AliasTy::Projection(ProjectionTy { + associated_ty_id: return_id, + substitution, + }); + builder.push_fact(Normalize { + alias: return_alias, + ty: generator_io_datum.return_type, + }); + + Ok(()) + } + + // Generator trait is non-enumerable + TyKind::InferenceVar(..) | TyKind::BoundVar(_) | TyKind::Alias(..) => Err(Floundered), + _ => Ok(()), + } +} diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs b/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs new file mode 100644 index 000000000..3ed46d425 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs @@ -0,0 +1,124 @@ +use std::iter; + +use crate::clauses::builtin_traits::needs_impl_for_tys; +use crate::clauses::ClauseBuilder; +use crate::rust_ir::AdtKind; +use crate::{Interner, RustIrDatabase, TraitRef}; +use chalk_ir::{ + AdtId, CanonicalVarKinds, Floundered, Substitution, TyKind, TyVariableKind, VariableKind, +}; + +fn push_adt_sized_conditions<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + trait_ref: TraitRef<I>, + adt_id: AdtId<I>, + substitution: &Substitution<I>, +) { + let adt_datum = db.adt_datum(adt_id); + + // WF ensures that all enums are Sized, so we only have to consider structs. + if adt_datum.kind != AdtKind::Struct { + builder.push_fact(trait_ref); + return; + } + + let interner = db.interner(); + + // To check if a struct S<..> is Sized, we only have to look at its last field. + // This is because the WF checks for ADTs require that all the other fields must be Sized. + let last_field_ty = adt_datum + .binders + .map_ref(|b| b.variants.clone()) + .substitute(interner, substitution) + .into_iter() + .take(1) // We have a struct so we're guaranteed one variant + .flat_map(|mut v| v.fields.pop()); + + needs_impl_for_tys(db, builder, trait_ref, last_field_ty); +} + +fn push_tuple_sized_conditions<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + trait_ref: TraitRef<I>, + arity: usize, + substitution: &Substitution<I>, +) { + // Empty tuples are always Sized + if arity == 0 { + builder.push_fact(trait_ref); + return; + } + + let interner = db.interner(); + + // To check if a tuple is Sized, we only have to look at its last element. + // This is because the WF checks for tuples require that all the other elements must be Sized. + let last_elem_ty = substitution + .iter(interner) + .last() + .unwrap() + .ty(interner) + .unwrap() + .clone(); + + needs_impl_for_tys(db, builder, trait_ref, iter::once(last_elem_ty)); +} + +pub fn add_sized_program_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + trait_ref: TraitRef<I>, + ty: TyKind<I>, + binders: &CanonicalVarKinds<I>, +) -> Result<(), Floundered> { + match ty { + TyKind::Adt(adt_id, ref substitution) => { + push_adt_sized_conditions(db, builder, trait_ref, adt_id, substitution) + } + TyKind::Tuple(arity, ref substitution) => { + push_tuple_sized_conditions(db, builder, trait_ref, arity, substitution) + } + TyKind::Array(_, _) + | TyKind::Never + | TyKind::Closure(_, _) + | TyKind::FnDef(_, _) + | TyKind::Scalar(_) + | TyKind::Raw(_, _) + | TyKind::Generator(_, _) + | TyKind::GeneratorWitness(_, _) + | TyKind::Ref(_, _, _) => builder.push_fact(trait_ref), + + TyKind::AssociatedType(_, _) + | TyKind::Slice(_) + | TyKind::OpaqueType(_, _) + | TyKind::Str + | TyKind::Foreign(_) + | TyKind::Error => {} + + TyKind::Function(_) + | TyKind::InferenceVar(_, TyVariableKind::Float) + | TyKind::InferenceVar(_, TyVariableKind::Integer) => builder.push_fact(trait_ref), + + TyKind::BoundVar(bound_var) => { + let var_kind = &binders.at(db.interner(), bound_var.index).kind; + match var_kind { + VariableKind::Ty(TyVariableKind::Integer) + | VariableKind::Ty(TyVariableKind::Float) => builder.push_fact(trait_ref), + + // Don't know enough + VariableKind::Ty(TyVariableKind::General) => return Err(Floundered), + + VariableKind::Const(_) | VariableKind::Lifetime => {} + } + } + + // We don't know enough here + TyKind::InferenceVar(_, TyVariableKind::General) => return Err(Floundered), + + // These would be handled elsewhere + TyKind::Placeholder(_) | TyKind::Dyn(_) | TyKind::Alias(_) => {} + } + Ok(()) +} diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/tuple.rs b/vendor/chalk-solve/src/clauses/builtin_traits/tuple.rs new file mode 100644 index 000000000..a62447827 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/builtin_traits/tuple.rs @@ -0,0 +1,30 @@ +use crate::clauses::ClauseBuilder; +use crate::rust_ir::WellKnownTrait; +use crate::{Interner, RustIrDatabase, TraitRef}; +use chalk_ir::{Floundered, Substitution, Ty, TyKind}; + +/// Add implicit impl for the `Tuple` trait for all tuples +pub fn add_tuple_program_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + self_ty: Ty<I>, +) -> Result<(), Floundered> { + let interner = db.interner(); + + match self_ty.kind(interner) { + TyKind::Tuple(..) => { + let trait_id = db.well_known_trait_id(WellKnownTrait::Tuple).unwrap(); + + builder.push_fact(TraitRef { + trait_id, + substitution: Substitution::from1(interner, self_ty), + }); + + Ok(()) + } + + // Tuple trait is non-enumerable + TyKind::InferenceVar(..) | TyKind::BoundVar(_) | TyKind::Alias(..) => Err(Floundered), + _ => Ok(()), + } +} diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/unsize.rs b/vendor/chalk-solve/src/clauses/builtin_traits/unsize.rs new file mode 100644 index 000000000..6682735b6 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/builtin_traits/unsize.rs @@ -0,0 +1,479 @@ +use std::collections::HashSet; +use std::iter; +use std::ops::ControlFlow; + +use crate::clauses::ClauseBuilder; +use crate::rust_ir::AdtKind; +use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait}; +use chalk_ir::{ + cast::Cast, + interner::HasInterner, + visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, + Binders, Const, ConstValue, DebruijnIndex, DomainGoal, DynTy, EqGoal, Goal, LifetimeOutlives, + QuantifiedWhereClauses, Substitution, TraitId, Ty, TyKind, TypeOutlives, WhereClause, +}; + +struct UnsizeParameterCollector<I: Interner> { + interner: I, + // FIXME should probably use a bitset instead + parameters: HashSet<usize>, +} + +impl<I: Interner> TypeVisitor<I> for UnsizeParameterCollector<I> { + type BreakTy = (); + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> { + self + } + + fn visit_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> ControlFlow<()> { + let interner = self.interner; + + match ty.kind(interner) { + TyKind::BoundVar(bound_var) => { + // check if bound var refers to the outermost binder + if bound_var.debruijn.shifted_in() == outer_binder { + self.parameters.insert(bound_var.index); + } + ControlFlow::Continue(()) + } + _ => ty.super_visit_with(self, outer_binder), + } + } + + fn visit_const(&mut self, constant: &Const<I>, outer_binder: DebruijnIndex) -> ControlFlow<()> { + let interner = self.interner; + + if let ConstValue::BoundVar(bound_var) = constant.data(interner).value { + // check if bound var refers to the outermost binder + if bound_var.debruijn.shifted_in() == outer_binder { + self.parameters.insert(bound_var.index); + } + } + ControlFlow::Continue(()) + } + + fn interner(&self) -> I { + self.interner + } +} + +fn outer_binder_parameters_used<I: Interner>( + interner: I, + v: &Binders<impl TypeVisitable<I> + HasInterner>, +) -> HashSet<usize> { + let mut visitor = UnsizeParameterCollector { + interner, + parameters: HashSet::new(), + }; + v.visit_with(&mut visitor, DebruijnIndex::INNERMOST); + visitor.parameters +} + +// has nothing to do with occurs check +struct ParameterOccurenceCheck<'p, I: Interner> { + interner: I, + parameters: &'p HashSet<usize>, +} + +impl<'p, I: Interner> TypeVisitor<I> for ParameterOccurenceCheck<'p, I> { + type BreakTy = (); + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> { + self + } + + fn visit_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> ControlFlow<()> { + let interner = self.interner; + + match ty.kind(interner) { + TyKind::BoundVar(bound_var) => { + if bound_var.debruijn.shifted_in() == outer_binder + && self.parameters.contains(&bound_var.index) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + } + _ => ty.super_visit_with(self, outer_binder), + } + } + + fn visit_const(&mut self, constant: &Const<I>, outer_binder: DebruijnIndex) -> ControlFlow<()> { + let interner = self.interner; + + match constant.data(interner).value { + ConstValue::BoundVar(bound_var) => { + if bound_var.debruijn.shifted_in() == outer_binder + && self.parameters.contains(&bound_var.index) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + } + _ => ControlFlow::Continue(()), + } + } + + fn interner(&self) -> I { + self.interner + } +} + +fn uses_outer_binder_params<I: Interner>( + interner: I, + v: &Binders<impl TypeVisitable<I> + HasInterner>, + parameters: &HashSet<usize>, +) -> bool { + let mut visitor = ParameterOccurenceCheck { + interner, + parameters, + }; + + let flow = v.visit_with(&mut visitor, DebruijnIndex::INNERMOST); + matches!(flow, ControlFlow::Break(_)) +} + +fn principal_id<I: Interner>( + db: &dyn RustIrDatabase<I>, + bounds: &Binders<QuantifiedWhereClauses<I>>, +) -> Option<TraitId<I>> { + let interner = db.interner(); + + bounds + .skip_binders() + .iter(interner) + .filter_map(|b| b.trait_id()) + .find(|&id| !db.trait_datum(id).is_auto_trait()) +} + +fn auto_trait_ids<'a, I: Interner>( + db: &'a dyn RustIrDatabase<I>, + bounds: &'a Binders<QuantifiedWhereClauses<I>>, +) -> impl Iterator<Item = TraitId<I>> + 'a { + let interner = db.interner(); + + bounds + .skip_binders() + .iter(interner) + .filter_map(|clause| clause.trait_id()) + .filter(move |&id| db.trait_datum(id).is_auto_trait()) +} + +pub fn add_unsize_program_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + trait_ref: TraitRef<I>, + _ty: TyKind<I>, +) { + let interner = db.interner(); + + let source_ty = trait_ref.self_type_parameter(interner); + let target_ty = trait_ref + .substitution + .at(interner, 1) + .assert_ty_ref(interner) + .clone(); + + let unsize_trait_id = trait_ref.trait_id; + + // N.B. here rustc asserts that `TraitRef` is not a higher-ranked bound + // i.e. `for<'a> &'a T: Unsize<dyn Trait+'a>` is never provable. + // + // In chalk it would be awkward to implement and I am not sure + // there is a need for it, the original comment states that this restriction + // could be lifted. + // + // for more info visit `fn assemble_candidates_for_unsizing` and + // `fn confirm_builtin_unisize_candidate` in rustc. + + match (source_ty.kind(interner), target_ty.kind(interner)) { + // dyn Trait + AutoX + 'a -> dyn Trait + AutoY + 'b + ( + TyKind::Dyn(DynTy { + bounds: bounds_a, + lifetime: lifetime_a, + }), + TyKind::Dyn(DynTy { + bounds: bounds_b, + lifetime: lifetime_b, + }), + ) => { + let principal_a = principal_id(db, bounds_a); + let principal_b = principal_id(db, bounds_b); + + let auto_trait_ids_a: Vec<_> = auto_trait_ids(db, bounds_a).collect(); + let auto_trait_ids_b: Vec<_> = auto_trait_ids(db, bounds_b).collect(); + + let may_apply = principal_a == principal_b + && auto_trait_ids_b + .iter() + .all(|id_b| auto_trait_ids_a.iter().any(|id_a| id_a == id_b)); + + if !may_apply { + return; + } + + // COMMENT FROM RUSTC: + // ------------------ + // Require that the traits involved in this upcast are **equal**; + // only the **lifetime bound** is changed. + // + // This condition is arguably too strong -- it would + // suffice for the source trait to be a *subtype* of the target + // trait. In particular, changing from something like + // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be + // permitted. + // <...> + // I've modified this to `.eq` because I want to continue rejecting + // that [`old-lub-glb-object.rs`] test (as we have + // done for quite some time) before we are firmly comfortable + // with what our behavior should be there. -nikomatsakis + // ------------------ + + // Construct a new trait object type by taking the source ty, + // filtering out auto traits of source that are not present in target + // and changing source lifetime to target lifetime. + // + // In order for the coercion to be valid, this new type + // should be equal to target type. + let new_source_ty = TyKind::Dyn(DynTy { + bounds: bounds_a.map_ref(|bounds| { + QuantifiedWhereClauses::from_iter( + interner, + bounds.iter(interner).filter(|bound| { + let trait_id = match bound.trait_id() { + Some(id) => id, + None => return true, + }; + + if auto_trait_ids_a.iter().all(|&id_a| id_a != trait_id) { + return true; + } + auto_trait_ids_b.iter().any(|&id_b| id_b == trait_id) + }), + ) + }), + lifetime: lifetime_b.clone(), + }) + .intern(interner); + + // Check that new source is equal to target + let eq_goal = EqGoal { + a: new_source_ty.cast(interner), + b: target_ty.clone().cast(interner), + } + .cast(interner); + + // Check that source lifetime outlives target lifetime + let lifetime_outlives_goal: Goal<I> = WhereClause::LifetimeOutlives(LifetimeOutlives { + a: lifetime_a.clone(), + b: lifetime_b.clone(), + }) + .cast(interner); + + builder.push_clause(trait_ref, [eq_goal, lifetime_outlives_goal].iter()); + } + + // T -> dyn Trait + 'a + (_, TyKind::Dyn(DynTy { bounds, lifetime })) => { + // Check if all traits in trait object are object safe + let object_safe_goals = bounds + .skip_binders() + .iter(interner) + .filter_map(|bound| bound.trait_id()) + .map(|id| DomainGoal::ObjectSafe(id).cast(interner)); + + // Check that T implements all traits of the trait object + let source_ty_bounds = bounds + .clone() + .substitute(interner, &Substitution::from1(interner, source_ty.clone())); + + // Check that T is sized because we can only make + // a trait object from a sized type + let self_sized_goal: WhereClause<_> = TraitRef { + trait_id: db + .well_known_trait_id(WellKnownTrait::Sized) + .expect("Expected Sized to be defined when proving Unsize"), + substitution: Substitution::from1(interner, source_ty.clone()), + } + .cast(interner); + + // Check that `source_ty` outlives `'a` + let source_ty_outlives: Goal<_> = WhereClause::TypeOutlives(TypeOutlives { + ty: source_ty, + lifetime: lifetime.clone(), + }) + .cast(interner); + + builder.push_clause( + trait_ref, + source_ty_bounds + .iter(interner) + .map(|bound| bound.clone().cast::<Goal<I>>(interner)) + .chain(object_safe_goals) + .chain(iter::once(self_sized_goal.cast(interner))) + .chain(iter::once(source_ty_outlives)), + ); + } + + (TyKind::Array(array_ty, _array_const), TyKind::Slice(slice_ty)) => { + let eq_goal = EqGoal { + a: array_ty.clone().cast(interner), + b: slice_ty.clone().cast(interner), + }; + + builder.push_clause(trait_ref, iter::once(eq_goal)); + } + + // Adt<T> -> Adt<U> + (TyKind::Adt(adt_id_a, substitution_a), TyKind::Adt(adt_id_b, substitution_b)) => { + if adt_id_a != adt_id_b { + return; + } + + let adt_id = *adt_id_a; + let adt_datum = db.adt_datum(adt_id); + + // Unsizing of enums is not allowed + if adt_datum.kind == AdtKind::Enum { + return; + } + + // We have a `struct` so we're guaranteed a single variant + let fields_len = adt_datum + .binders + .skip_binders() + .variants + .last() + .unwrap() + .fields + .len(); + + if fields_len == 0 { + return; + } + + let adt_tail_field = adt_datum + .binders + .map_ref(|bound| bound.variants.last().unwrap().fields.last().unwrap()) + .cloned(); + + // Collect unsize parameters that last field contains and + // ensure there at least one of them. + let unsize_parameter_candidates = + outer_binder_parameters_used(interner, &adt_tail_field); + + if unsize_parameter_candidates.is_empty() { + return; + } + // Ensure none of the other fields mention the parameters used + // in unsizing. + // We specifically want variables specified by the outermost binder + // i.e. the struct generic arguments binder. + if uses_outer_binder_params( + interner, + &adt_datum + .binders + .map_ref(|bound| &bound.variants.last().unwrap().fields[..fields_len - 1]), + &unsize_parameter_candidates, + ) { + return; + } + + let parameters_a = substitution_a.as_slice(interner); + let parameters_b = substitution_b.as_slice(interner); + // Check that the source adt with the target's + // unsizing parameters is equal to the target. + // We construct a new substitution where if a parameter is used in the + // coercion (i.e. it's a non-lifetime struct parameter used by it's last field), + // then we take that parameter from target substitution, otherwise we take + // it from the source substitution. + // + // In order for the coercion to be valid, target struct and + // struct with this newly constructed substitution applied to it should be equal. + let substitution = Substitution::from_iter( + interner, + parameters_a.iter().enumerate().map(|(i, p)| { + if unsize_parameter_candidates.contains(&i) { + ¶meters_b[i] + } else { + p + } + }), + ); + + let eq_goal = EqGoal { + a: TyKind::Adt(adt_id, substitution) + .intern(interner) + .cast(interner), + b: target_ty.clone().cast(interner), + } + .cast(interner); + + // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`. + let source_tail_field = adt_tail_field.clone().substitute(interner, substitution_a); + let target_tail_field = adt_tail_field.substitute(interner, substitution_b); + + // Check that `TailField<T>: Unsize<TailField<U>>` + let last_field_unsizing_goal: Goal<I> = TraitRef { + trait_id: unsize_trait_id, + substitution: Substitution::from_iter( + interner, + [source_tail_field, target_tail_field].iter().cloned(), + ), + } + .cast(interner); + + builder.push_clause(trait_ref, [eq_goal, last_field_unsizing_goal].iter()); + } + + // (.., T) -> (.., U) + (TyKind::Tuple(arity_a, substitution_a), TyKind::Tuple(arity_b, substitution_b)) => { + if arity_a != arity_b || *arity_a == 0 { + return; + } + let arity = arity_a; + + let tail_ty_a = substitution_a.iter(interner).last().unwrap(); + let tail_ty_b = substitution_b.iter(interner).last().unwrap(); + + // Check that the source tuple with the target's + // last element is equal to the target. + let new_tuple = TyKind::Tuple( + *arity, + Substitution::from_iter( + interner, + substitution_a + .iter(interner) + .take(arity - 1) + .chain(iter::once(tail_ty_b)), + ), + ) + .cast(interner) + .intern(interner); + + let eq_goal: Goal<I> = EqGoal { + a: new_tuple.cast(interner), + b: target_ty.clone().cast(interner), + } + .cast(interner); + + // Check that `T: Unsize<U>` + let last_field_unsizing_goal: Goal<I> = TraitRef { + trait_id: unsize_trait_id, + substitution: Substitution::from_iter( + interner, + [tail_ty_a, tail_ty_b].iter().cloned(), + ), + } + .cast(interner); + + builder.push_clause(trait_ref, [eq_goal, last_field_unsizing_goal].iter()); + } + + _ => (), + } +} diff --git a/vendor/chalk-solve/src/clauses/dyn_ty.rs b/vendor/chalk-solve/src/clauses/dyn_ty.rs new file mode 100644 index 000000000..505da43f9 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/dyn_ty.rs @@ -0,0 +1,81 @@ +use super::{builder::ClauseBuilder, generalize}; +use crate::RustIrDatabase; +use chalk_ir::{cast::Cast, interner::Interner, Ty, TyKind, WhereClause}; + +/// If the self type `S` of an `Implemented` goal is a `dyn trait` type, we wish +/// to generate program-clauses that indicates that it implements its own +/// traits. For example, a `dyn Write` type implements `Write` and so on. +/// +/// To see how this works, consider as an example the type `dyn Fn(&u8)`. This +/// is really shorthand for `dyn for<'a> Fn<(&'a u8), Output = ()>`, and we +/// represent that type as something like this: +/// +/// ```ignore +/// dyn(exists<T> { +/// forall<'a> { Implemented(T: Fn<'a>) }, +/// forall<'a> { AliasEq(<T as Fn<'a>>::Output, ()) }, +/// }) +/// ``` +/// +/// so what we will do is to generate one program clause for each of the +/// conditions. Thus we get two program clauses: +/// +/// ```ignore +/// forall<'a> { Implemented(dyn Fn(&u8): Fn<(&'a u8)>) } +/// ``` +/// +/// and +/// +/// ```ignore +/// forall<'a> { AliasEq(<dyn Fn(&u8) as Fn<'a>>::Output, ()) }, +/// ``` +pub(super) fn build_dyn_self_ty_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + self_ty: Ty<I>, +) { + let interner = db.interner(); + let dyn_ty = match self_ty.kind(interner) { + TyKind::Dyn(dyn_ty) => dyn_ty.clone(), + _ => return, + }; + let generalized_dyn_ty = generalize::Generalize::apply(db.interner(), dyn_ty); + + // Here, `self_ty` is the `dyn Fn(&u8)`, and `dyn_ty` is the `exists<T> { .. + // }` clauses shown above. + + // Turn free BoundVars in the type into new existentials. E.g. + // we might get some `dyn Foo<?X>`, and we don't want to return + // a clause with a free variable. We can instead return a + // slightly more general clause by basically turning this into + // `exists<A> dyn Foo<A>`. + + builder.push_binders(generalized_dyn_ty, |builder, dyn_ty| { + for exists_qwc in dyn_ty.bounds.map_ref(|r| r.iter(interner)) { + // Replace the `T` from `exists<T> { .. }` with `self_ty`, + // yielding clases like + // + // ``` + // forall<'a> { Implemented(dyn Fn(&u8): Fn<(&'a u8)>) } + // ``` + let qwc = exists_qwc + .cloned() + .substitute(interner, &[self_ty.clone().cast(interner)]); + + builder.push_binders(qwc, |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(..) => {} + }); + } + }); +} diff --git a/vendor/chalk-solve/src/clauses/env_elaborator.rs b/vendor/chalk-solve/src/clauses/env_elaborator.rs new file mode 100644 index 000000000..29032a7ad --- /dev/null +++ b/vendor/chalk-solve/src/clauses/env_elaborator.rs @@ -0,0 +1,107 @@ +use super::program_clauses::ToProgramClauses; +use crate::clauses::builder::ClauseBuilder; +use crate::clauses::{match_alias_ty, match_ty}; +use crate::DomainGoal; +use crate::FromEnv; +use crate::ProgramClause; +use crate::RustIrDatabase; +use crate::Ty; +use crate::{debug_span, TyKind}; +use chalk_ir::interner::Interner; +use chalk_ir::visit::{TypeVisitable, TypeVisitor}; +use chalk_ir::{DebruijnIndex, Environment}; +use rustc_hash::FxHashSet; +use std::ops::ControlFlow; +use tracing::instrument; + +/// When proving a `FromEnv` goal, we elaborate all `FromEnv` goals +/// found in the environment. +/// +/// For example, when `T: Clone` is in the environment, we can prove +/// `T: Copy` by adding the clauses from `trait Clone`, which includes +/// the rule `FromEnv(T: Copy) :- FromEnv(T: Clone) +pub(super) fn elaborate_env_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + in_clauses: &[ProgramClause<I>], + out: &mut FxHashSet<ProgramClause<I>>, + environment: &Environment<I>, +) { + let mut this_round = vec![]; + let builder = &mut ClauseBuilder::new(db, &mut this_round); + let mut elaborater = EnvElaborator { + db, + builder, + environment, + }; + in_clauses.visit_with(&mut elaborater, DebruijnIndex::INNERMOST); + out.extend(this_round); +} + +struct EnvElaborator<'me, 'builder, I: Interner> { + db: &'me dyn RustIrDatabase<I>, + builder: &'builder mut ClauseBuilder<'me, I>, + environment: &'me Environment<I>, +} + +impl<'me, 'builder, I: Interner> TypeVisitor<I> for EnvElaborator<'me, 'builder, I> { + type BreakTy = (); + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> { + self + } + + fn interner(&self) -> I { + self.db.interner() + } + #[instrument(level = "debug", skip(self, _outer_binder))] + fn visit_ty(&mut self, ty: &Ty<I>, _outer_binder: DebruijnIndex) -> ControlFlow<()> { + match ty.kind(self.interner()) { + TyKind::Alias(alias_ty) => match_alias_ty(self.builder, self.environment, alias_ty), + TyKind::Placeholder(_) => {} + + // FIXME(#203) -- We haven't fully figured out the implied + // bounds story around `dyn Trait` types. + TyKind::Dyn(_) => (), + + TyKind::Function(_) | TyKind::BoundVar(_) | TyKind::InferenceVar(_, _) => (), + + _ => { + // This shouldn't fail because of the above clauses + match_ty(self.builder, self.environment, ty) + .map_err(|_| ()) + .unwrap() + } + } + ControlFlow::Continue(()) + } + + fn visit_domain_goal( + &mut self, + domain_goal: &DomainGoal<I>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<()> { + if let DomainGoal::FromEnv(from_env) = domain_goal { + debug_span!("visit_domain_goal", ?from_env); + match from_env { + FromEnv::Trait(trait_ref) => { + let trait_datum = self.db.trait_datum(trait_ref.trait_id); + + trait_datum.to_program_clauses(self.builder, self.environment); + + // If we know that `T: Iterator`, then we also know + // things about `<T as Iterator>::Item`, so push those + // implied bounds too: + for &associated_ty_id in &trait_datum.associated_ty_ids { + self.db + .associated_ty_data(associated_ty_id) + .to_program_clauses(self.builder, self.environment); + } + ControlFlow::Continue(()) + } + FromEnv::Ty(ty) => ty.visit_with(self, outer_binder), + } + } else { + ControlFlow::Continue(()) + } + } +} diff --git a/vendor/chalk-solve/src/clauses/generalize.rs b/vendor/chalk-solve/src/clauses/generalize.rs new file mode 100644 index 000000000..bff05b369 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/generalize.rs @@ -0,0 +1,99 @@ +//! This gets rid of free variables in a type by replacing them by fresh bound +//! ones. We use this when building clauses that contain types passed to +//! `program_clauses`; these may contain variables, and just copying those +//! variables verbatim leads to problems. Instead, we return a slightly more +//! general program clause, with new variables in those places. This can only +//! happen with `dyn Trait` currently; that's the only case where we use the +//! types passed to `program_clauses` in the clauses we generate. + +use chalk_derive::FallibleTypeFolder; +use chalk_ir::{ + fold::{TypeFoldable, TypeFolder}, + interner::{HasInterner, Interner}, + Binders, BoundVar, Const, ConstData, ConstValue, DebruijnIndex, Lifetime, LifetimeData, Ty, + TyKind, TyVariableKind, VariableKind, VariableKinds, +}; +use rustc_hash::FxHashMap; + +#[derive(FallibleTypeFolder)] +pub struct Generalize<I: Interner> { + binders: Vec<VariableKind<I>>, + mapping: FxHashMap<BoundVar, usize>, + interner: I, +} + +impl<I: Interner> Generalize<I> { + pub fn apply<T>(interner: I, value: T) -> Binders<T> + where + T: HasInterner<Interner = I> + TypeFoldable<I>, + { + let mut generalize = Generalize { + binders: Vec::new(), + mapping: FxHashMap::default(), + interner, + }; + let value = value + .try_fold_with(&mut generalize, DebruijnIndex::INNERMOST) + .unwrap(); + Binders::new( + VariableKinds::from_iter(interner, generalize.binders), + value, + ) + } +} + +impl<I: Interner> TypeFolder<I> for Generalize<I> { + fn as_dyn(&mut self) -> &mut dyn TypeFolder<I> { + self + } + + fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty<I> { + let binder_vec = &mut self.binders; + let new_index = self.mapping.entry(bound_var).or_insert_with(|| { + let i = binder_vec.len(); + binder_vec.push(VariableKind::Ty(TyVariableKind::General)); + i + }); + let new_var = BoundVar::new(outer_binder, *new_index); + TyKind::BoundVar(new_var).intern(TypeFolder::interner(self)) + } + + fn fold_free_var_const( + &mut self, + ty: Ty<I>, + bound_var: BoundVar, + outer_binder: DebruijnIndex, + ) -> Const<I> { + let binder_vec = &mut self.binders; + let new_index = self.mapping.entry(bound_var).or_insert_with(|| { + let i = binder_vec.len(); + binder_vec.push(VariableKind::Const(ty.clone())); + i + }); + let new_var = BoundVar::new(outer_binder, *new_index); + ConstData { + ty, + value: ConstValue::BoundVar(new_var), + } + .intern(TypeFolder::interner(self)) + } + + fn fold_free_var_lifetime( + &mut self, + bound_var: BoundVar, + outer_binder: DebruijnIndex, + ) -> Lifetime<I> { + let binder_vec = &mut self.binders; + let new_index = self.mapping.entry(bound_var).or_insert_with(|| { + let i = binder_vec.len(); + binder_vec.push(VariableKind::Lifetime); + i + }); + let new_var = BoundVar::new(outer_binder, *new_index); + LifetimeData::BoundVar(new_var).intern(TypeFolder::interner(self)) + } + + fn interner(&self) -> I { + self.interner + } +} diff --git a/vendor/chalk-solve/src/clauses/program_clauses.rs b/vendor/chalk-solve/src/clauses/program_clauses.rs new file mode 100644 index 000000000..19811ff8b --- /dev/null +++ b/vendor/chalk-solve/src/clauses/program_clauses.rs @@ -0,0 +1,921 @@ +use crate::clauses::builder::ClauseBuilder; +use crate::rust_ir::*; +use crate::split::Split; +use chalk_ir::cast::{Cast, Caster}; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use std::iter; +use tracing::instrument; + +/// Trait for lowering a given piece of rust-ir source (e.g., an impl +/// or struct definition) into its associated "program clauses" -- +/// that is, into the lowered, logical rules that it defines. +pub trait ToProgramClauses<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. + /// + /// 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 ty = TyKind::AssociatedType(self.id, substitution).intern(interner); + + let projection_eq = AliasEq { + alias: AliasTy::Projection(projection.clone()), + ty: ty.clone(), + }; + + // Fallback rule. The solver uses this to move between the projection + // and placeholder type. + // + // forall<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(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(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(ty.clone())), + ); + }); + } + + // Reverse rule for implied bounds. + // + // forall<Self> { + // FromEnv(<Self as Foo>::Assoc: Bounds) :- FromEnv(Self: Foo), WC + // } + for quantified_bound in bounds { + builder.push_binders(quantified_bound, |builder, bound| { + for wc in bound.into_where_clauses(interner, projection_ty.clone()) { + builder.push_clause( + wc.into_from_env_goal(interner), + iter::once( + FromEnv::Trait(trait_ref.clone()).cast::<Goal<_>>(interner), + ) + .chain(where_clauses.iter().cloned().casted(interner)), + ); + } + }); + } + + // 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)); + }); + }, + ); + } +} diff --git a/vendor/chalk-solve/src/clauses/super_traits.rs b/vendor/chalk-solve/src/clauses/super_traits.rs new file mode 100644 index 000000000..3110b03e8 --- /dev/null +++ b/vendor/chalk-solve/src/clauses/super_traits.rs @@ -0,0 +1,118 @@ +use rustc_hash::FxHashSet; + +use super::builder::ClauseBuilder; +use crate::RustIrDatabase; +use chalk_ir::{ + fold::shift::Shift, interner::Interner, Binders, BoundVar, DebruijnIndex, TraitId, TraitRef, + WhereClause, +}; + +/// Generate `Implemented` clauses for `dyn Trait` and opaque types. We need to generate +/// `Implemented` clauses for all super traits, and for each trait we require +/// its where clauses. (See #203.) +pub(super) fn push_trait_super_clauses<I: Interner>( + db: &dyn RustIrDatabase<I>, + builder: &mut ClauseBuilder<'_, I>, + trait_ref: TraitRef<I>, +) { + let interner = db.interner(); + // Given`trait SuperTrait: WC`, which is a super trait + // of `Trait` (including actually just being the same trait); + // then we want to push + // - for `dyn Trait`: + // `Implemented(dyn Trait: SuperTrait) :- WC`. + // - for placeholder `!T` of `opaque type T: Trait = HiddenTy`: + // `Implemented(!T: SuperTrait) :- WC` + + let super_trait_refs = + super_traits(db, trait_ref.trait_id).substitute(interner, &trait_ref.substitution); + + for q_super_trait_ref in super_trait_refs { + builder.push_binders(q_super_trait_ref.clone(), |builder, super_trait_ref| { + let trait_datum = db.trait_datum(super_trait_ref.trait_id); + let wc = trait_datum + .where_clauses() + .cloned() + .substitute(interner, &super_trait_ref.substitution); + builder.push_clause(super_trait_ref, wc); + }); + } +} + +pub fn super_traits<I: Interner>( + db: &dyn RustIrDatabase<I>, + trait_id: TraitId<I>, +) -> Binders<Vec<Binders<TraitRef<I>>>> { + let interner = db.interner(); + let mut seen_traits = FxHashSet::default(); + let trait_datum = db.trait_datum(trait_id); + let trait_ref = Binders::empty( + db.interner(), + TraitRef { + trait_id, + substitution: trait_datum + .binders + .identity_substitution(interner) + .shifted_in(interner), + }, + ); + let mut trait_refs = Vec::new(); + go(db, trait_ref, &mut seen_traits, &mut trait_refs); + + fn go<I: Interner>( + db: &dyn RustIrDatabase<I>, + trait_ref: Binders<TraitRef<I>>, + seen_traits: &mut FxHashSet<TraitId<I>>, + trait_refs: &mut Vec<Binders<TraitRef<I>>>, + ) { + let interner = db.interner(); + let trait_id = trait_ref.skip_binders().trait_id; + // Avoid cycles + if !seen_traits.insert(trait_id) { + return; + } + trait_refs.push(trait_ref.clone()); + let trait_datum = db.trait_datum(trait_id); + let super_trait_refs = trait_datum + .binders + .map_ref(|td| { + td.where_clauses + .iter() + .filter_map(|qwc| { + qwc.as_ref().filter_map(|wc| match wc { + WhereClause::Implemented(tr) => { + let self_ty = tr.self_type_parameter(db.interner()); + + // We're looking for where clauses + // of the form `Self: Trait`. That's + // ^1.0 because we're one binder in. + if self_ty.bound_var(db.interner()) + != Some(BoundVar::new(DebruijnIndex::ONE, 0)) + { + return None; + } + Some(tr.clone()) + } + WhereClause::AliasEq(_) => None, + WhereClause::LifetimeOutlives(..) => None, + WhereClause::TypeOutlives(..) => None, + }) + }) + .collect::<Vec<_>>() + }) + // we skip binders on the trait_ref here and add them to the binders + // on the trait ref in the loop below. We could probably avoid this if + // we could turn the `Binders<Vec<>>` into a `Vec<Binders<>>` easily. + .substitute(db.interner(), &trait_ref.skip_binders().substitution); + for q_super_trait_ref in super_trait_refs { + // So now we need to combine the binders of trait_ref with the + // binders of super_trait_ref. + let actual_binders = Binders::new(trait_ref.binders.clone(), q_super_trait_ref); + let q_super_trait_ref = actual_binders.fuse_binders(interner); + go(db, q_super_trait_ref, seen_traits, trait_refs); + } + seen_traits.remove(&trait_id); + } + + Binders::new(trait_datum.binders.binders.clone(), trait_refs) +} diff --git a/vendor/chalk-solve/src/coherence.rs b/vendor/chalk-solve/src/coherence.rs new file mode 100644 index 000000000..5528b9a21 --- /dev/null +++ b/vendor/chalk-solve/src/coherence.rs @@ -0,0 +1,149 @@ +use indexmap::IndexMap; +use petgraph::prelude::*; +use rustc_hash::FxHashMap; + +use crate::solve::Solver; +use crate::RustIrDatabase; +use chalk_ir::interner::Interner; +use chalk_ir::{self, ImplId, TraitId}; +use std::fmt; +use std::sync::Arc; + +pub mod orphan; +mod solve; + +pub struct CoherenceSolver<'a, I: Interner> { + db: &'a dyn RustIrDatabase<I>, + solver_builder: &'a dyn Fn() -> Box<dyn Solver<I>>, + trait_id: TraitId<I>, +} + +#[derive(Debug)] +pub enum CoherenceError<I: Interner> { + OverlappingImpls(TraitId<I>), + FailedOrphanCheck(TraitId<I>), +} + +impl<I: Interner> fmt::Display for CoherenceError<I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CoherenceError::OverlappingImpls(id) => { + write!(f, "overlapping impls of trait `{:?}`", id) + } + CoherenceError::FailedOrphanCheck(id) => { + write!(f, "impl for trait `{:?}` violates the orphan rules", id) + } + } + } +} + +impl<I: Interner> std::error::Error for CoherenceError<I> {} + +/// Stores the specialization priorities for a set of impls. +/// This basically encodes which impls specialize one another. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct SpecializationPriorities<I: Interner> { + map: IndexMap<ImplId<I>, SpecializationPriority>, +} + +impl<I: Interner> SpecializationPriorities<I> { + pub fn new() -> Self { + Self { + map: IndexMap::new(), + } + } + + /// Lookup the priority of an impl in the set (panics if impl is not in set). + pub fn priority(&self, impl_id: ImplId<I>) -> SpecializationPriority { + self.map[&impl_id] + } + + /// Store the priority of an impl (used during construction). + /// Panics if we have already stored the priority for this impl. + fn insert(&mut self, impl_id: ImplId<I>, p: SpecializationPriority) { + let old_value = self.map.insert(impl_id, p); + assert!(old_value.is_none()); + } +} + +/// Impls with higher priority take precedence over impls with lower +/// priority (if both apply to the same types). Impls with equal +/// priority should never apply to the same set of input types. +#[derive(Copy, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug)] +pub struct SpecializationPriority(usize); + +impl<'a, I> CoherenceSolver<'a, I> +where + I: Interner, +{ + /// Constructs a new `CoherenceSolver`. + pub fn new( + db: &'a dyn RustIrDatabase<I>, + solver_builder: &'a dyn Fn() -> Box<dyn Solver<I>>, + trait_id: TraitId<I>, + ) -> Self { + Self { + db, + solver_builder, + trait_id, + } + } + + pub fn specialization_priorities( + &self, + ) -> Result<Arc<SpecializationPriorities<I>>, CoherenceError<I>> { + let mut result = SpecializationPriorities::<I>::new(); + + let forest = self.build_specialization_forest()?; + + // TypeVisitable every root in the forest & set specialization + // priority for the tree that is the root of. + for root_idx in forest.externals(Direction::Incoming) { + self.set_priorities(root_idx, &forest, 0, &mut result); + } + + Ok(Arc::new(result)) + } + + // Build the forest of specialization relationships. + fn build_specialization_forest(&self) -> Result<Graph<ImplId<I>, ()>, CoherenceError<I>> { + let mut forest = DiGraph::new(); + let mut node_map = FxHashMap::default(); + + // Find all specializations. Record them in the forest + // by adding an edge from the less special to the more special. + self.visit_specializations_of_trait(|less_special, more_special| { + let less_special_node = *node_map + .entry(less_special) + .or_insert_with(|| forest.add_node(less_special)); + let more_special_node = *node_map + .entry(more_special) + .or_insert_with(|| forest.add_node(more_special)); + forest.update_edge(less_special_node, more_special_node, ()); + })?; + + Ok(forest) + } + + // Recursively set priorities for those node and all of its children. + fn set_priorities( + &self, + idx: NodeIndex, + forest: &Graph<ImplId<I>, ()>, + p: usize, + map: &mut SpecializationPriorities<I>, + ) { + // Get the impl datum recorded at this node and reset its priority + { + let impl_id = forest + .node_weight(idx) + .expect("index should be a valid index into graph"); + map.insert(*impl_id, SpecializationPriority(p)); + } + + // TypeVisitable all children of this node, setting their priority to this + 1 + for child_idx in forest.neighbors(idx) { + self.set_priorities(child_idx, forest, p + 1, map); + } + } +} diff --git a/vendor/chalk-solve/src/coherence/orphan.rs b/vendor/chalk-solve/src/coherence/orphan.rs new file mode 100644 index 000000000..f8e06b901 --- /dev/null +++ b/vendor/chalk-solve/src/coherence/orphan.rs @@ -0,0 +1,44 @@ +use crate::coherence::CoherenceError; +use crate::ext::GoalExt; +use crate::solve::Solver; +use crate::RustIrDatabase; +use chalk_ir::cast::*; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use tracing::{debug, instrument}; + +// Test if a local impl violates the orphan rules. +// +// For `impl<T> Trait for MyType<T>` we generate: +// +// forall<T> { LocalImplAllowed(MyType<T>: Trait) } +// +// This must be provable in order to pass the orphan check. +#[instrument(level = "debug", skip(db, solver))] +pub fn perform_orphan_check<I: Interner>( + db: &dyn RustIrDatabase<I>, + solver: &mut dyn Solver<I>, + impl_id: ImplId<I>, +) -> Result<(), CoherenceError<I>> { + let impl_datum = db.impl_datum(impl_id); + debug!(?impl_datum); + + let impl_allowed: Goal<I> = impl_datum + .binders + .map_ref(|bound_impl| { + // Ignoring the polarization of the impl's polarized trait ref + DomainGoal::LocalImplAllowed(bound_impl.trait_ref.clone()) + }) + .cast(db.interner()); + + let canonical_goal = &impl_allowed.into_closed_goal(db.interner()); + let is_allowed = solver.solve(db, canonical_goal).is_some(); + debug!("overlaps = {:?}", is_allowed); + + if !is_allowed { + let trait_id = impl_datum.trait_id(); + return Err(CoherenceError::FailedOrphanCheck(trait_id)); + } + + Ok(()) +} diff --git a/vendor/chalk-solve/src/coherence/solve.rs b/vendor/chalk-solve/src/coherence/solve.rs new file mode 100644 index 000000000..57dd81061 --- /dev/null +++ b/vendor/chalk-solve/src/coherence/solve.rs @@ -0,0 +1,260 @@ +use crate::coherence::{CoherenceError, CoherenceSolver}; +use crate::debug_span; +use crate::ext::*; +use crate::rust_ir::*; +use crate::{goal_builder::GoalBuilder, Solution}; +use chalk_ir::cast::*; +use chalk_ir::fold::shift::Shift; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use itertools::Itertools; +use tracing::{debug, instrument}; + +impl<I: Interner> CoherenceSolver<'_, I> { + pub(super) fn visit_specializations_of_trait( + &self, + mut record_specialization: impl FnMut(ImplId<I>, ImplId<I>), + ) -> Result<(), CoherenceError<I>> { + // Ignore impls for marker traits as they are allowed to overlap. + let trait_datum = self.db.trait_datum(self.trait_id); + if trait_datum.flags.marker { + return Ok(()); + } + + // Iterate over every pair of impls for the same trait. + let impls = self.db.local_impls_to_coherence_check(self.trait_id); + for (l_id, r_id) in impls.into_iter().tuple_combinations() { + let lhs = &self.db.impl_datum(l_id); + let rhs = &self.db.impl_datum(r_id); + + // Two negative impls never overlap. + if !lhs.is_positive() && !rhs.is_positive() { + continue; + } + + // Check if the impls overlap, then if they do, check if one specializes + // the other. Note that specialization can only run one way - if both + // specialization checks return *either* true or false, that's an error. + if !self.disjoint(lhs, rhs) { + match (self.specializes(l_id, r_id), self.specializes(r_id, l_id)) { + (true, false) => record_specialization(l_id, r_id), + (false, true) => record_specialization(r_id, l_id), + (_, _) => { + return Err(CoherenceError::OverlappingImpls(self.trait_id)); + } + } + } + } + + Ok(()) + } + + // Test if the set of types that these two impls apply to overlap. If the test succeeds, these + // two impls are disjoint. + // + // We combine the binders of the two impls & treat them as existential quantifiers. Then we + // attempt to unify the input types to the trait provided by each impl, as well as prove that + // the where clauses from both impls all hold. At the end, we apply the `compatible` modality + // and negate the query. Negating the query means that we are asking chalk to prove that no + // such overlapping impl exists. By applying `compatible { G }`, chalk attempts to prove that + // "there exists a compatible world where G is provable." When we negate compatible, it turns + // into the statement "for all compatible worlds, G is not provable." This is exactly what we + // want since we want to ensure that there is no overlap in *all* compatible worlds, not just + // that there is no overlap in *some* compatible world. + // + // Examples: + // + // Impls: + // impl<T> Foo for T { } // rhs + // impl Foo for i32 { } // lhs + // Generates: + // not { compatible { exists<T> { exists<> { T = i32 } } } } + // + // Impls: + // impl<T1, U> Foo<T1> for Vec<U> { } // rhs + // impl<T2> Foo<T2> for Vec<i32> { } // lhs + // Generates: + // not { compatible { exists<T1, U> { exists<T2> { Vec<U> = Vec<i32>, T1 = T2 } } } } + // + // Impls: + // impl<T> Foo for Vec<T> where T: Bar { } + // impl<U> Foo for Vec<U> where U: Baz { } + // Generates: + // not { compatible { exists<T> { exists<U> { Vec<T> = Vec<U>, T: Bar, U: Baz } } } } + // + #[instrument(level = "debug", skip(self))] + fn disjoint(&self, lhs: &ImplDatum<I>, rhs: &ImplDatum<I>) -> bool { + let interner = self.db.interner(); + + let (lhs_binders, lhs_bound) = lhs.binders.as_ref().into(); + let (rhs_binders, rhs_bound) = rhs.binders.as_ref().into(); + + // Upshift the rhs variables in params to account for the joined binders + let lhs_params = lhs_bound + .trait_ref + .substitution + .as_slice(interner) + .iter() + .cloned(); + let rhs_params = rhs_bound + .trait_ref + .substitution + .as_slice(interner) + .iter() + .map(|param| param.clone().shifted_in(interner)); + + // Create an equality goal for every input type the trait, attempting + // to unify the inputs to both impls with one another + let params_goals = lhs_params + .zip(rhs_params) + .map(|(a, b)| GoalData::EqGoal(EqGoal { a, b }).intern(interner)); + + // Upshift the rhs variables in where clauses + let lhs_where_clauses = lhs_bound.where_clauses.iter().cloned(); + let rhs_where_clauses = rhs_bound + .where_clauses + .iter() + .map(|wc| wc.clone().shifted_in(interner)); + + // Create a goal for each clause in both where clauses + let wc_goals = lhs_where_clauses + .chain(rhs_where_clauses) + .map(|wc| wc.cast(interner)); + + // Join all the goals we've created together with And, then quantify them + // over the joined binders. This is our query. + let goal = Box::new(Goal::all(interner, params_goals.chain(wc_goals))) + .quantify(interner, QuantifierKind::Exists, lhs_binders) + .quantify(interner, QuantifierKind::Exists, rhs_binders) + .compatible(interner) + .negate(interner); + + let canonical_goal = &goal.into_closed_goal(interner); + let mut fresh_solver = (self.solver_builder)(); + let solution = fresh_solver.solve(self.db, canonical_goal); + let result = match solution { + // Goal was proven with a unique solution, so no impl was found that causes these two + // to overlap + Some(Solution::Unique(_)) => true, + // Goal was ambiguous, so there *may* be overlap + Some(Solution::Ambig(_)) | + // Goal cannot be proven, so there is some impl that causes overlap + None => false, + }; + debug!("overlaps: result = {:?}", result); + result + } + + // Creates a goal which, if provable, means "more special" impl specializes the "less special" one. + // + // # General rule + // + // Given the more special impl: + // + // ```ignore + // impl<P0..Pn> SomeTrait<T1..Tm> for T0 where WC_more + // ``` + // + // and less special impl + // + // ```ignore + // impl<Q0..Qo> SomeTrait<U1..Um> for U0 where WC_less + // ``` + // + // create the goal: + // + // ```ignore + // forall<P0..Pn> { + // if (WC_more) {} + // exists<Q0..Qo> { + // T0 = U0, ..., Tm = Um, + // WC_less + // } + // } + // } + // ``` + // + // # Example + // + // Given: + // + // * more: `impl<T: Clone> Foo for Vec<T>` + // * less: `impl<U: Clone> Foo for U` + // + // Resulting goal: + // + // ```ignore + // forall<T> { + // if (T: Clone) { + // exists<U> { + // Vec<T> = U, U: Clone + // } + // } + // } + // ``` + #[instrument(level = "debug", skip(self))] + fn specializes(&self, less_special_id: ImplId<I>, more_special_id: ImplId<I>) -> bool { + let more_special = &self.db.impl_datum(more_special_id); + let less_special = &self.db.impl_datum(less_special_id); + debug_span!("specializes", ?less_special, ?more_special); + + let interner = self.db.interner(); + + let gb = &mut GoalBuilder::new(self.db); + + // forall<P0..Pn> { ... } + let goal = gb.forall( + &more_special.binders, + less_special_id, + |gb, _, more_special_impl, less_special_id| { + // if (WC_more) { ... } + gb.implies(more_special_impl.where_clauses.iter().cloned(), |gb| { + let less_special = &gb.db().impl_datum(less_special_id); + + // exists<Q0..Qn> { ... } + gb.exists( + &less_special.binders, + more_special_impl.trait_ref.clone(), + |gb, _, less_special_impl, more_special_trait_ref| { + let interner = gb.interner(); + + // T0 = U0, ..., Tm = Um + let params_goals = more_special_trait_ref + .substitution + .as_slice(interner) + .iter() + .cloned() + .zip( + less_special_impl + .trait_ref + .substitution + .as_slice(interner) + .iter() + .cloned(), + ) + .map(|(a, b)| GoalData::EqGoal(EqGoal { a, b }).intern(interner)); + + // <less_special_wc_goals> = where clauses from the less special impl + let less_special_wc_goals = less_special_impl + .where_clauses + .iter() + .cloned() + .casted(interner); + + // <equality_goals> && WC_less + gb.all(params_goals.chain(less_special_wc_goals)) + }, + ) + }) + }, + ); + + let canonical_goal = &goal.into_closed_goal(interner); + let mut fresh_solver = (self.solver_builder)(); + let result = fresh_solver.has_unique_solution(self.db, canonical_goal); + + debug!("specializes: result = {:?}", result); + + result + } +} diff --git a/vendor/chalk-solve/src/coinductive_goal.rs b/vendor/chalk-solve/src/coinductive_goal.rs new file mode 100644 index 000000000..cdb5cca10 --- /dev/null +++ b/vendor/chalk-solve/src/coinductive_goal.rs @@ -0,0 +1,43 @@ +use crate::RustIrDatabase; +use chalk_ir::interner::Interner; +use chalk_ir::*; + +pub trait IsCoinductive<I: Interner> { + /// A goal G has coinductive semantics if proving G is allowed to + /// assume G is true (very roughly speaking). In the case of + /// chalk-ir, this is true for goals of the form `T: AutoTrait`, + /// or if it is of the form `WellFormed(T: Trait)` where `Trait` + /// is any trait. The latter is needed for dealing with WF + /// requirements and cyclic traits, which generates cycles in the + /// proof tree which must not be rejected but instead must be + /// treated as a success. + fn is_coinductive(&self, db: &dyn RustIrDatabase<I>) -> bool; +} + +impl<I: Interner> IsCoinductive<I> for Goal<I> { + fn is_coinductive(&self, db: &dyn RustIrDatabase<I>) -> bool { + let interner = db.interner(); + match self.data(interner) { + GoalData::DomainGoal(DomainGoal::Holds(wca)) => match wca { + WhereClause::Implemented(tr) => { + db.trait_datum(tr.trait_id).is_auto_trait() + || db.trait_datum(tr.trait_id).is_coinductive_trait() + } + WhereClause::AliasEq(..) => false, + WhereClause::LifetimeOutlives(..) => false, + WhereClause::TypeOutlives(..) => false, + }, + GoalData::DomainGoal(DomainGoal::WellFormed(WellFormed::Trait(..))) => true, + GoalData::Quantified(QuantifierKind::ForAll, goal) => { + goal.skip_binders().is_coinductive(db) + } + _ => false, + } + } +} + +impl<I: Interner> IsCoinductive<I> for UCanonical<InEnvironment<Goal<I>>> { + fn is_coinductive(&self, db: &dyn RustIrDatabase<I>) -> bool { + self.canonical.value.goal.is_coinductive(db) + } +} diff --git a/vendor/chalk-solve/src/display.rs b/vendor/chalk-solve/src/display.rs new file mode 100644 index 000000000..bb1f7a3c5 --- /dev/null +++ b/vendor/chalk-solve/src/display.rs @@ -0,0 +1,224 @@ +use std::{ + borrow::Borrow, + fmt::{Display, Result}, + sync::Arc, +}; + +use crate::rust_ir::*; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +use crate::{logging_db::RecordedItemId, split::Split, RustIrDatabase}; + +#[macro_use] +mod utils; + +mod bounds; +mod identifiers; +mod items; +mod render_trait; +mod state; +mod stub; +mod ty; + +use self::render_trait::*; +pub use self::state::*; +pub use self::utils::sanitize_debug_name; + +use self::utils::as_display; + +fn write_item<F, I, T>(f: &mut F, ws: &InternalWriterState<'_, I>, v: &T) -> Result +where + F: std::fmt::Write + ?Sized, + I: Interner, + T: RenderAsRust<I>, +{ + writeln!(f, "{}", v.display(ws)) +} + +/// Writes stubs for items which were referenced by name, but for which we +/// didn't directly access. For instance, traits mentioned in where bounds which +/// are only usually checked during well-formedness, when we weren't recording +/// well-formedness. +/// +/// The "stub" nature of this means it writes output with the right names and +/// the right number of generics, but nothing else. Where clauses, bounds, and +/// fields are skipped. Associated types are ???? skipped. +/// +/// `RecordedItemId::Impl` is not supported. +pub fn write_stub_items<F, I, DB, P, T>(f: &mut F, ws: &WriterState<I, DB, P>, ids: T) -> Result +where + F: std::fmt::Write + ?Sized, + I: Interner, + DB: RustIrDatabase<I>, + P: Borrow<DB>, + T: IntoIterator<Item = RecordedItemId<I>>, +{ + let wrapped_db = &ws.wrap_db_ref(|db| stub::StubWrapper::new(db.borrow())); + + write_items(f, wrapped_db, ids) +} + +/// Writes out each item recorded by a [`LoggingRustIrDatabase`]. +/// +/// [`LoggingRustIrDatabase`]: crate::logging_db::LoggingRustIrDatabase +pub fn write_items<F, I, DB, P, T>(f: &mut F, ws: &WriterState<I, DB, P>, ids: T) -> Result +where + F: std::fmt::Write + ?Sized, + I: Interner, + DB: RustIrDatabase<I>, + P: Borrow<DB>, + T: IntoIterator<Item = RecordedItemId<I>>, +{ + for id in ids { + match id { + RecordedItemId::Impl(id) => { + let v = ws.db().impl_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::Adt(id) => { + let v = ws.db().adt_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::Trait(id) => { + let v = ws.db().trait_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::OpaqueTy(id) => { + let v = ws.db().opaque_ty_data(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::FnDef(id) => { + let v = ws.db().fn_def_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::Generator(id) => { + let generator = ws.db().generator_datum(id); + let witness = ws.db().generator_witness_datum(id); + write_item(f, &InternalWriterState::new(ws), &(&*generator, &*witness))?; + } + } + } + Ok(()) +} + +/// Displays a set of bounds, all targeting `Self`, as just the trait names, +/// separated by `+`. +/// +/// For example, a list of quantified where clauses which would normally be +/// displayed as: +/// +/// ```notrust +/// Self: A, Self: B, Self: C +/// ``` +/// +/// Is instead displayed by this function as: +/// +/// ```notrust +/// A + B + C +/// ``` +/// +/// Shared between the `Trait` in `dyn Trait` and [`OpaqueTyDatum`] bounds. +fn display_self_where_clauses_as_bounds<'a, I: Interner>( + s: &'a InternalWriterState<'a, I>, + bounds: &'a [QuantifiedWhereClause<I>], +) -> impl Display + 'a { + as_display(move |f| { + let interner = s.db().interner(); + write!( + f, + "{}", + bounds + .iter() + .map(|bound| { + as_display(|f| { + // each individual trait can have a forall + let s = &s.add_debrujin_index(None); + if !bound.binders.is_empty(interner) { + write!( + f, + "forall<{}> ", + s.binder_var_display(&bound.binders) + .collect::<Vec<_>>() + .join(", ") + )?; + } + match &bound.skip_binders() { + WhereClause::Implemented(trait_ref) => display_type_with_generics( + s, + trait_ref.trait_id, + &trait_ref.substitution.as_slice(interner)[1..], + ) + .fmt(f), + WhereClause::AliasEq(alias_eq) => match &alias_eq.alias { + AliasTy::Projection(projection_ty) => { + let (assoc_ty_datum, trait_params, assoc_type_params) = + s.db().split_projection(projection_ty); + display_trait_with_assoc_ty_value( + s, + assoc_ty_datum, + &trait_params[1..], + assoc_type_params, + &alias_eq.ty, + ) + .fmt(f) + } + AliasTy::Opaque(opaque) => opaque.display(s).fmt(f), + }, + WhereClause::LifetimeOutlives(lifetime) => lifetime.display(s).fmt(f), + WhereClause::TypeOutlives(ty) => ty.display(s).fmt(f), + } + }) + .to_string() + }) + .format(" + ") + ) + }) +} + +/// Displays a type with its parameters - something like `AsRef<T>`, +/// OpaqueTyName<U>, or `AdtName<Value>`. +/// +/// This is shared between where bounds, OpaqueTy, & dyn Trait. +fn display_type_with_generics<'a, I: Interner>( + s: &'a InternalWriterState<'a, I>, + trait_name: impl RenderAsRust<I> + 'a, + trait_params: impl IntoIterator<Item = &'a GenericArg<I>> + 'a, +) -> impl Display + 'a { + use std::fmt::Write; + let trait_params = trait_params.into_iter().map(|param| param.display(s)); + let mut trait_params_str = String::new(); + write_joined_non_empty_list!(trait_params_str, "<{}>", trait_params, ", ").unwrap(); + as_display(move |f| write!(f, "{}{}", trait_name.display(s), trait_params_str)) +} + +/// Displays a trait with its parameters and a single associated type - +/// something like `IntoIterator<Item=T>`. +/// +/// This is shared between where bounds & dyn Trait. +fn display_trait_with_assoc_ty_value<'a, I: Interner>( + s: &'a InternalWriterState<'a, I>, + assoc_ty_datum: Arc<AssociatedTyDatum<I>>, + trait_params: &'a [GenericArg<I>], + assoc_ty_params: &'a [GenericArg<I>], + assoc_ty_value: &'a Ty<I>, +) -> impl Display + 'a { + as_display(move |f| { + write!(f, "{}<", assoc_ty_datum.trait_id.display(s))?; + write_joined_non_empty_list!( + f, + "{}, ", + trait_params.iter().map(|param| param.display(s)), + ", " + )?; + write!(f, "{}", assoc_ty_datum.id.display(s))?; + write_joined_non_empty_list!( + f, + "<{}>", + assoc_ty_params.iter().map(|param| param.display(s)), + ", " + )?; + write!(f, "={}>", assoc_ty_value.display(s))?; + Ok(()) + }) +} diff --git a/vendor/chalk-solve/src/display/bounds.rs b/vendor/chalk-solve/src/display/bounds.rs new file mode 100644 index 000000000..3c6bfde14 --- /dev/null +++ b/vendor/chalk-solve/src/display/bounds.rs @@ -0,0 +1,168 @@ +//! Writer logic for `where` clauses and other bounds. +//! +//! Contains logic for writing the various forms of `Foo: Bar`. +use std::fmt::{Display, Formatter, Result}; + +use crate::rust_ir::*; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +use super::{ + display_trait_with_assoc_ty_value, display_type_with_generics, render_trait::RenderAsRust, + state::InternalWriterState, +}; +use crate::split::Split; + +impl<I: Interner> RenderAsRust<I> for InlineBound<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + // Foo: Vec<T> + InlineBound::TraitBound(trait_bound) => trait_bound.fmt(s, f), + // Foo: Iterator<Item=Foo> + InlineBound::AliasEqBound(eq_bound) => eq_bound.fmt(s, f), + } + } +} + +impl<I: Interner> RenderAsRust<I> for TraitBound<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + display_type_with_generics(s, self.trait_id, &self.args_no_self).fmt(f) + } +} + +impl<I: Interner> RenderAsRust<I> for AliasEqBound<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + display_trait_with_assoc_ty_value( + s, + s.db().associated_ty_data(self.associated_ty_id), + &self.trait_bound.args_no_self, + &self.parameters, + &self.value, + ) + .fmt(f) + } +} + +impl<I: Interner> RenderAsRust<I> for QuantifiedWhereClause<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + let s = &s.add_debrujin_index(None); + if !self.binders.is_empty(interner) { + write!( + f, + "forall<{}> ", + s.binder_var_display(&self.binders).format(", ") + )?; + } + self.skip_binders().fmt(s, f) + } +} + +impl<I: Interner> RenderAsRust<I> for QuantifiedInlineBound<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + let s = &s.add_debrujin_index(None); + if !self.binders.is_empty(interner) { + write!( + f, + "forall<{}> ", + s.binder_var_display(&self.binders).format(", ") + )?; + } + self.skip_binders().fmt(s, f) + } +} + +impl<I: Interner> RenderAsRust<I> for Vec<QuantifiedWhereClause<I>> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + write!( + f, + "{}", + self.iter() + .map(|where_clause| { format!("{}{}", s.indent(), where_clause.display(s)) }) + .format(",\n") + )?; + Ok(()) + } +} + +impl<I: Interner> RenderAsRust<I> for WhereClause<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + WhereClause::Implemented(trait_ref) => trait_ref.fmt(s, f), + WhereClause::AliasEq(alias_eq) => alias_eq.fmt(s, f), + WhereClause::LifetimeOutlives(lifetime) => lifetime.display(s).fmt(f), + WhereClause::TypeOutlives(ty) => ty.display(s).fmt(f), + } + } +} + +/// This renders `TraitRef` as a clause in a where clause, as opposed to its +/// usage in other places. +impl<I: Interner> RenderAsRust<I> for TraitRef<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + write!( + f, + "{}: {}", + self.self_type_parameter(interner).display(s), + display_type_with_generics( + s, + self.trait_id, + &self.substitution.as_slice(interner)[1..] + ) + ) + } +} + +/// This renders `AliasEq` as a clause in a where clause, as opposed to its +/// usage in other places. +impl<I: Interner> RenderAsRust<I> for AliasEq<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // we have: X: Y<A1, A2, A3, Z<B1, B2, B3>=D> + // B1, B2, B3, X, A1, A2, A3 are put into alias_eq.alias.substitution + // D is alias_eq.ty + // Z is alias_eq.alias.associated_ty_id + // Y is also packed into alias_eq.alias.associated_ty_id + // Now, we split out A*, Y/Z and B*: + // trait_params is X, A1, A2, A3, + // assoc_type_params is B1, B2, B3, + // assoc_ty_datum stores info about Y and Z. + match &self.alias { + AliasTy::Projection(projection_ty) => { + let (assoc_ty_datum, trait_params, assoc_type_params) = + s.db().split_projection(projection_ty); + // An alternate form might be `<{} as {}<{}>>::{}<{}> = {}` (with same + // parameter ordering). This alternate form would require type equality + // constraints (https://github.com/rust-lang/rust/issues/20041). + write!( + f, + "{}: {}", + trait_params[0].display(s), + display_trait_with_assoc_ty_value( + s, + assoc_ty_datum, + &trait_params[1..], + assoc_type_params, + &self.ty + ), + ) + } + AliasTy::Opaque(opaque) => write!(f, "{}", opaque.display(s)), + } + } +} + +impl<I: Interner> RenderAsRust<I> for LifetimeOutlives<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + // a': 'b + write!(f, "{}: {}", self.a.display(s), self.b.display(s)) + } +} + +impl<I: Interner> RenderAsRust<I> for TypeOutlives<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + // T: 'a + write!(f, "{}: {}", self.ty.display(s), self.lifetime.display(s)) + } +} diff --git a/vendor/chalk-solve/src/display/identifiers.rs b/vendor/chalk-solve/src/display/identifiers.rs new file mode 100644 index 000000000..81a08d71b --- /dev/null +++ b/vendor/chalk-solve/src/display/identifiers.rs @@ -0,0 +1,54 @@ +//! Writer logic for simple IDs +//! +//! `RenderAsRust` impls for identifiers which are either too small or too +//! shared to belong anywhere else belong here. +use std::fmt::{Formatter, Result}; + +use chalk_ir::interner::Interner; +use chalk_ir::*; + +use super::{render_trait::RenderAsRust, state::InternalWriterState}; + +impl<I: Interner> RenderAsRust<I> for AdtId<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_adt_id_name(self.0, s.db().adt_name(*self)) + ) + } +} + +impl<I: Interner> RenderAsRust<I> for TraitId<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_id_name(self.0, s.db().trait_name(*self)) + ) + } +} + +impl<I: Interner> RenderAsRust<I> for AssocTypeId<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_id_name(self.0, s.db().assoc_type_name(*self)) + ) + } +} + +impl<I: Interner> RenderAsRust<I> for OpaqueTyId<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_id_name(self.0, s.db().opaque_type_name(*self)) + ) + } +} diff --git a/vendor/chalk-solve/src/display/items.rs b/vendor/chalk-solve/src/display/items.rs new file mode 100644 index 000000000..00387a07b --- /dev/null +++ b/vendor/chalk-solve/src/display/items.rs @@ -0,0 +1,503 @@ +//! Writer logic for top level items. +//! +//! Contains code specific to top-level items and other structures specific to a +//! single top-level item. + +use std::fmt::{Formatter, Result}; + +use crate::rust_ir::*; +use crate::split::Split; +use chalk_ir::interner::Interner; +use itertools::Itertools; + +use super::{ + display_self_where_clauses_as_bounds, display_type_with_generics, render_trait::RenderAsRust, + state::InternalWriterState, +}; + +/// Used in `AdtDatum` and `TraitDatum` to write n flags from a flags struct +/// to a writer. Each flag field turns into an if expression + write!, so we can +/// just list the names and not repeat this pattern over and over. +/// +/// This macro will error if unknown flags are specified. This will also error +/// if any flags are missing. +/// +/// # Usage +/// +/// ```rust,ignore +/// write_flags!(f, self.flags, XFlags { red, green }) +/// ``` +/// +/// Turns into +/// +/// ```rust,ignore +/// match self.flags { +/// XFlags { red, green } => { +/// if red { +/// write!(f, "#[red]")?; +/// } +/// if green { +/// write!(f, "#[green]")?; +/// } +/// } +/// } +/// ``` +macro_rules! write_flags { + ($writer:ident, $val:expr, $struct_name:ident { $($n:ident $(: $extra_arg:tt)?),* }) => { + match $val { + // if any fields are missing, the destructuring will error + $struct_name { + $($n,)* + } => { + $(if $n { + write!($writer, "#[{}]\n", write_flags!(@default $n $(: $extra_arg)*))?; + })* + } + } + }; + (@default $n:ident : $name:literal) => { + $name + }; + (@default $n:ident ) => { + stringify!($n) + }; +} + +impl<'a, I: Interner> RenderAsRust<I> for (&'a GeneratorDatum<I>, &'a GeneratorWitnessDatum<I>) { + fn fmt(&self, _s: &InternalWriterState<'_, I>, _f: &'_ mut Formatter<'_>) -> Result { + unimplemented!() + } +} + +impl<I: Interner> RenderAsRust<I> for AdtDatum<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // When support for Self in structs is added, self_binding should be + // changed to Some(0) + let s = &s.add_debrujin_index(None); + let value = self.binders.skip_binders(); + + // flags + write_flags!( + f, + self.flags, + AdtFlags { + // Ordering matters + upstream, + fundamental, + phantom_data + } + ); + + // repr + let repr = s.db().adt_repr(self.id); + + if repr.c { + write!(f, "#[repr(C)]")?; + } + if repr.packed { + write!(f, "#[repr(packed)]")?; + } + if let Some(t) = &repr.int { + write!(f, "#[repr({})]", t.display(s))?; + } + + // name + match self.kind { + AdtKind::Struct => write!(f, "struct {}", self.id.display(s),)?, + AdtKind::Enum => write!(f, "enum {}", self.id.display(s),)?, + AdtKind::Union => write!(f, "union {}", self.id.display(s),)?, + } + write_joined_non_empty_list!(f, "<{}>", s.binder_var_display(&self.binders.binders), ", ")?; + + // where clauses + if !value.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; + } else { + write!(f, " ")?; + } + + // body + write!(f, "{{")?; + let s = &s.add_indent(); + match self.kind { + AdtKind::Struct | AdtKind::Union => { + write_joined_non_empty_list!( + f, + "\n{}\n", + value.variants[0] + .fields + .iter() + .enumerate() + .map(|(idx, field)| { + format!("{}field_{}: {}", s.indent(), idx, field.display(s)) + }), + ",\n" + )?; + } + AdtKind::Enum => { + for (variant_idx, variant) in value.variants.iter().enumerate() { + write!(f, "\n{}variant_{} {{", s.indent(), variant_idx)?; + let s = &s.add_indent(); + write_joined_non_empty_list!( + f, + "\n{}\n", + variant.fields.iter().enumerate().map(|(idx, field)| { + format!("{}field_{}: {}", s.indent(), idx, field.display(s)) + }), + ",\n" + )?; + write!(f, "{}}},", s.indent())?; + } + } + } + write!(f, "}}")?; + Ok(()) + } +} + +impl<I: Interner> RenderAsRust<I> for Polarity { + fn fmt(&self, _s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + if !self.is_positive() { + write!(f, "!")?; + } + Ok(()) + } +} + +impl<I: Interner> RenderAsRust<I> for TraitDatum<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let s = &s.add_debrujin_index(Some(0)); + let value = self.binders.skip_binders(); + + // flags + write_flags!( + f, + self.flags, + TraitFlags { + auto, + marker, + upstream, + fundamental, + non_enumerable, + coinductive + } + ); + + // object safe + if s.db().is_object_safe(self.id) { + writeln!(f, "#[object_safe]")?; + } + + // well-known + if let Some(well_known) = self.well_known { + let name = match well_known { + WellKnownTrait::Sized => "sized", + WellKnownTrait::Copy => "copy", + WellKnownTrait::Clone => "clone", + WellKnownTrait::Drop => "drop", + WellKnownTrait::FnOnce => "fn_once", + WellKnownTrait::FnMut => "fn_mut", + WellKnownTrait::Fn => "fn", + WellKnownTrait::Unsize => "unsize", + WellKnownTrait::Unpin => "unpin", + WellKnownTrait::CoerceUnsized => "coerce_unsized", + WellKnownTrait::DiscriminantKind => "discriminant_kind", + WellKnownTrait::Generator => "generator", + WellKnownTrait::DispatchFromDyn => "dispatch_from_dyn", + WellKnownTrait::Tuple => "tuple_trait", + }; + writeln!(f, "#[lang({})]", name)?; + } + + // trait declaration + let binders = s.binder_var_display(&self.binders.binders).skip(1); + write!(f, "trait {}", self.id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", binders, ", ")?; + + // where clauses + if !value.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; + } else { + write!(f, " ")?; + } + + // body + write!(f, "{{")?; + let s = &s.add_indent(); + write_joined_non_empty_list!( + f, + "\n{}\n", + self.associated_ty_ids.iter().map(|assoc_ty_id| { + let assoc_ty_data = s.db().associated_ty_data(*assoc_ty_id); + format!("{}{}", s.indent(), (*assoc_ty_data).display(s)) + }), + "\n" + )?; + write!(f, "}}")?; + Ok(()) + } +} + +impl<I: Interner> RenderAsRust<I> for ImplDatum<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + + let s = &s.add_debrujin_index(None); + let binders = s.binder_var_display(&self.binders.binders); + let value = self.binders.skip_binders(); + + // annotations + // #[upstream] + // ^^^^^^^^^^^ + // impl<T> Foo<T> for Bar<T> where T: Baz { } + if self.impl_type == ImplType::External { + writeln!(f, "#[upstream]")?; + } + + // impl keyword + // impl<T> Foo<T> for Bar<T> where T: Baz { } + // ^^^^ + write!(f, "impl")?; + let trait_ref = &value.trait_ref; + + // generic binders + // impl<T> Foo<T> for Bar<T> where T: Baz + // ^^^ + write_joined_non_empty_list!(f, "<{}>", binders, ", ")?; + + // trait, type and parameters + // impl<T> Foo<T> for Bar<T> where T: Baz { } + // ^^^^^^^^^^^^^^^^^ + let full_trait_name = display_type_with_generics( + s, + trait_ref.trait_id, + // Ignore automatically added Self parameter by skipping first parameter + &trait_ref.substitution.as_slice(interner)[1..], + ); + write!( + f, + " {}{} for {}", + self.polarity.display(s), + full_trait_name, + trait_ref.self_type_parameter(interner).display(s) + )?; + + // where clauses + // impl<T> Foo<T> for Bar<T> where T: Baz { } + // ^^^^^^^^^^^^ + if !value.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; + } else { + write!(f, " ")?; + } + + // body + // impl<T> Foo<T> for Bar<T> where T: Baz { } + // ^^^ + write!(f, "{{")?; + { + let s = &s.add_indent(); + let assoc_ty_values = self.associated_ty_value_ids.iter().map(|assoc_ty_value| { + s.db() + .associated_ty_value(*assoc_ty_value) + .display(s) + .to_string() + }); + write_joined_non_empty_list!(f, "\n{}\n", assoc_ty_values, "\n")?; + } + write!(f, "}}")?; + Ok(()) + } +} + +impl<I: Interner> RenderAsRust<I> for OpaqueTyDatum<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + let s = &s.add_debrujin_index(None); + let bounds = self.bound.skip_binders(); + write!(f, "opaque type {}", self.opaque_ty_id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", s.binder_var_display(&self.bound.binders), ", ")?; + { + let s = &s.add_debrujin_index(Some(0)); + let clauses = bounds.bounds.skip_binders(); + write!( + f, + ": {} = ", + display_self_where_clauses_as_bounds(s, clauses) + )?; + } + write!( + f, + "{};", + s.db().hidden_opaque_type(self.opaque_ty_id).display(s) + )?; + Ok(()) + } +} + +impl<I: Interner> RenderAsRust<I> for AssociatedTyDatum<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // In lowering, a completely new empty environment is created for each + // AssociatedTyDatum, and it's given generic parameters for each generic + // parameter that its trait had. We want to map the new binders for + // those generic parameters back into their original names. To do that, + // first find their original names (trait_binder_names), then the names + // they have inside the AssociatedTyDatum (assoc_ty_names_for_trait_params), + // and then add that mapping to the WriterState when writing bounds and + // where clauses. + let trait_datum = s.db().trait_datum(self.trait_id); + // inverted Debrujin indices for the trait's parameters in the trait + // environment + let trait_param_names_in_trait_env = s.binder_var_indices(&trait_datum.binders.binders); + let s = &s.add_debrujin_index(None); + // inverted Debrujin indices for the trait's parameters in the + // associated type environment + let param_names_in_assoc_ty_env = s + .binder_var_indices(&self.binders.binders) + .collect::<Vec<_>>(); + // inverted Debrujin indices to render the trait's parameters in the + // associated type environment + let (trait_param_names_in_assoc_ty_env, _) = s + .db() + .split_associated_ty_parameters(¶m_names_in_assoc_ty_env, self); + + let s = &s.add_parameter_mapping( + trait_param_names_in_assoc_ty_env.iter().copied(), + trait_param_names_in_trait_env, + ); + + // rendered names for the associated type's generics in the associated + // type environment + let binder_display_in_assoc_ty = s + .binder_var_display(&self.binders.binders) + .collect::<Vec<_>>(); + + let (_, assoc_ty_params) = s + .db() + .split_associated_ty_parameters(&binder_display_in_assoc_ty, self); + write!(f, "type {}", self.id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", assoc_ty_params, ", ")?; + + let datum_bounds = &self.binders.skip_binders(); + + if !datum_bounds.bounds.is_empty() { + write!(f, ": ")?; + } + + // bounds is `A: V, B: D, C = E`? + // type Foo<A: V, B:D, C = E>: X + Y + Z; + let bounds = datum_bounds + .bounds + .iter() + .map(|bound| bound.display(s).to_string()) + .format(" + "); + write!(f, "{}", bounds)?; + + // where_clause is 'X: Y, Z: D' + // type Foo<...>: ... where X: Y, Z: D; + + // note: it's a quantified clause b/c we could have `for<'a> T: Foo<'a>` + // within 'where' + if !datum_bounds.where_clauses.is_empty() { + let where_s = &s.add_indent(); + let where_clauses = datum_bounds.where_clauses.display(where_s); + write!(f, "\n{}where\n{}", s.indent(), where_clauses)?; + } + write!(f, ";")?; + Ok(()) + } +} + +impl<I: Interner> RenderAsRust<I> for AssociatedTyValue<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // see comments for a similar empty env operation in AssociatedTyDatum's + // impl of RenderAsRust. + let assoc_ty_data = s.db().associated_ty_data(self.associated_ty_id); + let impl_datum = s.db().impl_datum(self.impl_id); + + let impl_param_names_in_impl_env = s.binder_var_indices(&impl_datum.binders.binders); + + let s = &s.add_debrujin_index(None); + let value = self.value.skip_binders(); + + let param_names_in_assoc_ty_value_env = s + .binder_var_indices(&self.value.binders) + .collect::<Vec<_>>(); + + let (impl_params_in_assoc_ty_value_env, _assoc_ty_value_params) = s + .db() + .split_associated_ty_value_parameters(¶m_names_in_assoc_ty_value_env, self); + + let s = &s.add_parameter_mapping( + impl_params_in_assoc_ty_value_env.iter().cloned(), + impl_param_names_in_impl_env, + ); + + let display_params = s + .binder_var_display(&self.value.binders) + .collect::<Vec<_>>(); + + let (_impl_display, assoc_ty_value_display) = s + .db() + .split_associated_ty_value_parameters(&display_params, self); + + write!(f, "{}type {}", s.indent(), assoc_ty_data.id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", assoc_ty_value_display, ", ")?; + write!(f, " = {};", value.ty.display(s))?; + Ok(()) + } +} + +impl<I: Interner> RenderAsRust<I> for FnDefDatum<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + let s = &s.add_debrujin_index(None); + let bound_datum = self.binders.skip_binders(); + + // declaration + // fn foo<T>(arg: u32, arg2: T) -> Result<T> where T: Bar + // ^^^^^^ + write!(f, "fn {}", s.db().fn_def_name(self.id))?; + + // binders + // fn foo<T>(arg: u32, arg2: T) -> Result<T> where T: Bar + // ^^^ + let binders = s.binder_var_display(&self.binders.binders); + write_joined_non_empty_list!(f, "<{}>", binders, ", ")?; + + { + let s = &s.add_debrujin_index(None); + let inputs_and_output = bound_datum.inputs_and_output.skip_binders(); + + // arguments + // fn foo<T>(arg: u32, arg2: T) -> Result<T> where T: Bar + // ^^^^^^^^^^^^^^^^^^^ + let arguments = inputs_and_output + .argument_types + .iter() + .enumerate() + .map(|(idx, arg)| format!("arg_{}: {}", idx, arg.display(s))) + .format(", "); + + write!(f, "({})", arguments)?; + + // return Type + // fn foo<T>(arg: u32, arg2: T) -> Result<T> where T: Bar + // ^^^^^^^^^^^^^ + write!(f, " -> {}", inputs_and_output.return_type.display(s))?; + } + + // where clause + // fn foo<T>(arg: u32, arg2: T) -> Result<T> where T: Bar + // ^^^^^^^^^^^^ + if !bound_datum.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}", bound_datum.where_clauses.display(s))?; + } + + write!(f, ";")?; + + Ok(()) + } +} diff --git a/vendor/chalk-solve/src/display/render_trait.rs b/vendor/chalk-solve/src/display/render_trait.rs new file mode 100644 index 000000000..a565f076c --- /dev/null +++ b/vendor/chalk-solve/src/display/render_trait.rs @@ -0,0 +1,30 @@ +//! `RenderAsRust` trait and related utils. +use std::fmt::{Display, Formatter, Result}; + +use chalk_ir::interner::Interner; + +use super::state::InternalWriterState; + +/// Displays `RenderAsRust` data. +/// +/// This is a utility struct for making `RenderAsRust` nice to use with rust format macros. +pub(in crate::display) struct DisplayRenderAsRust<'a, I: Interner, T> { + s: &'a InternalWriterState<'a, I>, + rar: &'a T, +} + +impl<I: Interner, T: RenderAsRust<I>> Display for DisplayRenderAsRust<'_, I, T> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + self.rar.fmt(self.s, f) + } +} + +pub(in crate::display) trait RenderAsRust<I: Interner> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result; + fn display<'a>(&'a self, s: &'a InternalWriterState<'a, I>) -> DisplayRenderAsRust<'a, I, Self> + where + Self: Sized, + { + DisplayRenderAsRust { s, rar: self } + } +} diff --git a/vendor/chalk-solve/src/display/state.rs b/vendor/chalk-solve/src/display/state.rs new file mode 100644 index 000000000..fed2f5ca5 --- /dev/null +++ b/vendor/chalk-solve/src/display/state.rs @@ -0,0 +1,352 @@ +//! Persistent state passed down between writers. +//! +//! This is essentially `InternalWriterState` and other things supporting that. +use core::hash::Hash; +use std::{ + borrow::Borrow, + collections::BTreeMap, + fmt::{Debug, Display, Formatter, Result}, + marker::PhantomData, + rc::Rc, + sync::{Arc, Mutex}, +}; + +use crate::RustIrDatabase; +use chalk_ir::{interner::Interner, *}; +use indexmap::IndexMap; +use itertools::Itertools; + +/// Like a BoundVar, but with the debrujin index inverted so as to create a +/// canonical name we can use anywhere for each bound variable. +/// +/// In BoundVar, the innermost bound variables have debrujin index `0`, and +/// each further out BoundVar has a debrujin index `1` higher. +/// +/// In InvertedBoundVar, the outermost variables have inverted_debrujin_idx `0`, +/// and the innermost have their depth, not the other way around. +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] +pub struct InvertedBoundVar { + /// The inverted debrujin index. Corresponds roughly to an inverted `DebrujinIndex::depth`. + inverted_debrujin_idx: i64, + /// The index within the debrujin index. Corresponds to `BoundVar::index`. + within_idx: IndexWithinBinding, +} + +impl Display for InvertedBoundVar { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "_{}_{}", self.inverted_debrujin_idx, self.within_idx) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +enum UnifiedId<I: Interner> { + AdtId(I::InternedAdtId), + DefId(I::DefId), +} + +#[derive(Debug)] +pub struct IdAliasStore<T> { + /// Map from the DefIds we've encountered to a u32 alias id unique to all ids + /// the same name. + aliases: IndexMap<T, u32>, + /// Map from each name to the next unused u32 alias id. + next_unused_for_name: BTreeMap<String, u32>, +} + +impl<T> Default for IdAliasStore<T> { + fn default() -> Self { + IdAliasStore { + aliases: IndexMap::default(), + next_unused_for_name: BTreeMap::default(), + } + } +} + +impl<T: Copy + Eq + Hash> IdAliasStore<T> { + fn alias_for_id_name(&mut self, id: T, name: String) -> String { + let next_unused_for_name = &mut self.next_unused_for_name; + let alias = *self.aliases.entry(id).or_insert_with(|| { + let next_unused: &mut u32 = next_unused_for_name.entry(name.clone()).or_default(); + let id = *next_unused; + *next_unused += 1; + id + }); + // If there are no conflicts, keep the name the same so that we don't + // need name-agnostic equality in display tests. + if alias == 0 { + name + } else { + format!("{}_{}", name, alias) + } + } +} + +#[derive(Debug)] +struct IdAliases<I: Interner> { + id_aliases: IdAliasStore<UnifiedId<I>>, +} + +impl<I: Interner> Default for IdAliases<I> { + fn default() -> Self { + IdAliases { + id_aliases: IdAliasStore::default(), + } + } +} + +/// Writer state which persists across multiple writes. +/// +/// Currently, this means keeping track of what IDs have been given what names, +/// including deduplication information. +/// +/// This data is stored using interior mutability - clones will point to the same underlying +/// data. +/// +/// Uses a separate type, `P`, for the database stored inside to account for +/// `Arc` or wrapping other storage mediums. +#[derive(Debug)] +pub struct WriterState<I, DB: ?Sized, P = DB> +where + DB: RustIrDatabase<I>, + P: Borrow<DB>, + I: Interner, +{ + pub(super) db: P, + id_aliases: Arc<Mutex<IdAliases<I>>>, + _phantom: PhantomData<DB>, +} + +impl<I, DB: ?Sized, P> Clone for WriterState<I, DB, P> +where + DB: RustIrDatabase<I>, + P: Borrow<DB> + Clone, + I: Interner, +{ + fn clone(&self) -> Self { + WriterState { + db: self.db.clone(), + id_aliases: self.id_aliases.clone(), + _phantom: PhantomData, + } + } +} + +impl<I, DB: ?Sized, P> WriterState<I, DB, P> +where + DB: RustIrDatabase<I>, + P: Borrow<DB>, + I: Interner, +{ + pub fn new(db: P) -> Self { + WriterState { + db, + id_aliases: Arc::new(Mutex::new(IdAliases::default())), + _phantom: PhantomData, + } + } + + /// Returns a new version of self containing a wrapped database which + /// references the outer data. + /// + /// `f` will be run on the internal database, and the returned result will + /// wrap the result from `f`. For consistency, `f` should always contain the + /// given database, and must keep the same ID<->item relationships. + pub(super) fn wrap_db_ref<'a, DB2: ?Sized, P2, F>(&'a self, f: F) -> WriterState<I, DB2, P2> + where + DB2: RustIrDatabase<I>, + P2: Borrow<DB2>, + // We need to pass in `&'a P` specifically to guarantee that the `&P` + // can outlive the function body, and thus that it's safe to store `&P` + // in `P2`. + F: FnOnce(&'a P) -> P2, + { + WriterState { + db: f(&self.db), + id_aliases: self.id_aliases.clone(), + _phantom: PhantomData, + } + } + + pub(crate) fn db(&self) -> &DB { + self.db.borrow() + } +} + +/// Writer state for a single write call, persistent only as long as necessary +/// to write a single item. +/// +/// Stores things necessary for . +#[derive(Clone, Debug)] +pub(super) struct InternalWriterState<'a, I: Interner> { + persistent_state: WriterState<I, dyn RustIrDatabase<I> + 'a, &'a dyn RustIrDatabase<I>>, + indent_level: usize, + debrujin_indices_deep: u32, + // lowered_(inverted_debrujin_idx, index) -> src_correct_(inverted_debrujin_idx, index) + remapping: Rc<BTreeMap<InvertedBoundVar, InvertedBoundVar>>, + // the inverted_bound_var which maps to "Self" + self_mapping: Option<InvertedBoundVar>, +} + +type IndexWithinBinding = usize; + +impl<'a, I: Interner> InternalWriterState<'a, I> { + pub fn new<DB, P>(persistent_state: &'a WriterState<I, DB, P>) -> Self + where + DB: RustIrDatabase<I>, + P: Borrow<DB>, + { + InternalWriterState { + persistent_state: persistent_state + .wrap_db_ref(|db| db.borrow() as &dyn RustIrDatabase<I>), + indent_level: 0, + debrujin_indices_deep: 0, + remapping: Rc::new(BTreeMap::new()), + self_mapping: None, + } + } + + pub(super) fn db(&self) -> &dyn RustIrDatabase<I> { + self.persistent_state.db + } + + pub(super) fn add_indent(&self) -> Self { + InternalWriterState { + indent_level: self.indent_level + 1, + ..self.clone() + } + } + + pub(super) fn indent(&self) -> impl Display { + std::iter::repeat(" ").take(self.indent_level).format("") + } + + pub(super) fn alias_for_adt_id_name(&self, id: I::InternedAdtId, name: String) -> impl Display { + self.persistent_state + .id_aliases + .lock() + .unwrap() + .id_aliases + .alias_for_id_name(UnifiedId::AdtId(id), name) + } + + pub(super) fn alias_for_id_name(&self, id: I::DefId, name: String) -> impl Display { + self.persistent_state + .id_aliases + .lock() + .unwrap() + .id_aliases + .alias_for_id_name(UnifiedId::DefId(id), name) + } + + /// Adds a level of debrujin index, and possibly a "Self" parameter. + /// + /// This should be called whenever recursing into the value within a + /// [`Binders`]. + /// + /// If `self_binding` is `Some`, then it will introduce a new variable named + /// `Self` with the within-debrujin index given within and the innermost + /// debrujian index after increasing debrujin index. + #[must_use = "this returns a new `InternalWriterState`, and does not modify the existing one"] + pub(super) fn add_debrujin_index(&self, self_binding: Option<IndexWithinBinding>) -> Self { + let mut new_state = self.clone(); + new_state.debrujin_indices_deep += 1; + new_state.self_mapping = self_binding + .map(|idx| new_state.indices_for_introduced_bound_var(idx)) + .or(self.self_mapping); + new_state + } + + /// Adds parameter remapping. + /// + /// Each of the parameters in `lowered_vars` will be mapped to its + /// corresponding variable in `original_vars` when printed through the + /// `InternalWriterState` returned from this method. + /// + /// `lowered_vars` and `original_vars` must have the same length. + pub(super) fn add_parameter_mapping( + &self, + lowered_vars: impl Iterator<Item = InvertedBoundVar>, + original_vars: impl Iterator<Item = InvertedBoundVar>, + ) -> Self { + let remapping = self + .remapping + .iter() + .map(|(a, b)| (*a, *b)) + .chain(lowered_vars.zip(original_vars)) + .collect::<BTreeMap<_, _>>(); + + InternalWriterState { + remapping: Rc::new(remapping), + ..self.clone() + } + } + + /// Inverts the debrujin index so as to create a canonical name we can + /// anywhere for each bound variable. + /// + /// See [`InvertedBoundVar`][InvertedBoundVar]. + pub(super) fn invert_debrujin_idx( + &self, + debrujin_idx: u32, + index: IndexWithinBinding, + ) -> InvertedBoundVar { + InvertedBoundVar { + inverted_debrujin_idx: (self.debrujin_indices_deep as i64) - (debrujin_idx as i64), + within_idx: index, + } + } + + pub(super) fn apply_mappings(&self, b: InvertedBoundVar) -> impl Display { + let remapped = self.remapping.get(&b).copied().unwrap_or(b); + if self.self_mapping == Some(remapped) { + "Self".to_owned() + } else { + remapped.to_string() + } + } + + pub(super) fn indices_for_bound_var(&self, b: &BoundVar) -> InvertedBoundVar { + self.invert_debrujin_idx(b.debruijn.depth(), b.index) + } + + pub(super) fn indices_for_introduced_bound_var( + &self, + idx: IndexWithinBinding, + ) -> InvertedBoundVar { + // freshly introduced bound vars will always have debrujin index of 0, + // they're always "innermost". + self.invert_debrujin_idx(0, idx) + } + + pub(super) fn display_bound_var(&self, b: &BoundVar) -> impl Display { + self.apply_mappings(self.indices_for_bound_var(b)) + } + + pub(super) fn name_for_introduced_bound_var(&self, idx: IndexWithinBinding) -> impl Display { + self.apply_mappings(self.indices_for_introduced_bound_var(idx)) + } + + pub(super) fn binder_var_indices<'b>( + &'b self, + binders: &'b VariableKinds<I>, + ) -> impl Iterator<Item = InvertedBoundVar> + 'b { + binders + .iter(self.db().interner()) + .enumerate() + .map(move |(idx, _param)| self.indices_for_introduced_bound_var(idx)) + } + + pub(super) fn binder_var_display<'b>( + &'b self, + binders: &'b VariableKinds<I>, + ) -> impl Iterator<Item = String> + 'b { + binders + .iter(self.db().interner()) + .zip(self.binder_var_indices(binders)) + .map(move |(parameter, var)| match parameter { + VariableKind::Ty(_) => format!("{}", self.apply_mappings(var)), + VariableKind::Lifetime => format!("'{}", self.apply_mappings(var)), + VariableKind::Const(_ty) => format!("const {}", self.apply_mappings(var)), + }) + } +} diff --git a/vendor/chalk-solve/src/display/stub.rs b/vendor/chalk-solve/src/display/stub.rs new file mode 100644 index 000000000..ec209bc91 --- /dev/null +++ b/vendor/chalk-solve/src/display/stub.rs @@ -0,0 +1,268 @@ +//! Contains a `LoggingIrDatabase` which returns stub versions of everything +//! queried. +use std::sync::Arc; + +use crate::rust_ir::{GeneratorDatum, GeneratorWitnessDatum}; +use crate::{ + rust_ir::{ + AdtDatumBound, AdtKind, AdtVariantDatum, AssociatedTyDatumBound, FnDefDatumBound, + OpaqueTyDatumBound, TraitDatumBound, + }, + RustIrDatabase, +}; +use chalk_ir::{ + interner::Interner, Binders, CanonicalVarKinds, GeneratorId, Substitution, Ty, + UnificationDatabase, VariableKinds, Variances, +}; + +#[derive(Debug)] +pub struct StubWrapper<'a, DB> { + db: &'a DB, +} + +impl<'a, DB> StubWrapper<'a, DB> { + pub fn new(db: &'a DB) -> Self { + StubWrapper { db } + } +} + +impl<I: Interner, DB: RustIrDatabase<I>> UnificationDatabase<I> for StubWrapper<'_, DB> { + fn fn_def_variance(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Variances<I> { + self.db.unification_database().fn_def_variance(fn_def_id) + } + + fn adt_variance(&self, adt_id: chalk_ir::AdtId<I>) -> Variances<I> { + self.db.unification_database().adt_variance(adt_id) + } +} + +impl<I: Interner, DB: RustIrDatabase<I>> RustIrDatabase<I> for StubWrapper<'_, DB> { + fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> { + self.db.custom_clauses() + } + + fn associated_ty_data( + &self, + ty: chalk_ir::AssocTypeId<I>, + ) -> std::sync::Arc<crate::rust_ir::AssociatedTyDatum<I>> { + let mut v = (*self.db.associated_ty_data(ty)).clone(); + v.binders = Binders::new( + v.binders.binders.clone(), + AssociatedTyDatumBound { + where_clauses: Vec::new(), + bounds: Vec::new(), + }, + ); + Arc::new(v) + } + + fn trait_datum( + &self, + trait_id: chalk_ir::TraitId<I>, + ) -> std::sync::Arc<crate::rust_ir::TraitDatum<I>> { + let mut v = (*self.db.trait_datum(trait_id)).clone(); + v.binders = Binders::new( + v.binders.binders.clone(), + TraitDatumBound { + where_clauses: Vec::new(), + }, + ); + Arc::new(v) + } + + fn adt_datum(&self, adt_id: chalk_ir::AdtId<I>) -> std::sync::Arc<crate::rust_ir::AdtDatum<I>> { + let mut v = (*self.db.adt_datum(adt_id)).clone(); + let variants = match v.kind { + AdtKind::Struct | AdtKind::Union => vec![AdtVariantDatum { fields: vec![] }], + AdtKind::Enum => vec![], + }; + v.binders = Binders::new( + v.binders.binders.clone(), + AdtDatumBound { + variants, + where_clauses: Vec::new(), + }, + ); + Arc::new(v) + } + + fn adt_repr(&self, id: chalk_ir::AdtId<I>) -> std::sync::Arc<crate::rust_ir::AdtRepr<I>> { + self.db.adt_repr(id) + } + + fn adt_size_align(&self, id: chalk_ir::AdtId<I>) -> Arc<crate::rust_ir::AdtSizeAlign> { + self.db.adt_size_align(id) + } + + fn fn_def_datum( + &self, + fn_def_id: chalk_ir::FnDefId<I>, + ) -> std::sync::Arc<crate::rust_ir::FnDefDatum<I>> { + let mut v = (*self.db.fn_def_datum(fn_def_id)).clone(); + v.binders = Binders::new( + v.binders.binders.clone(), + FnDefDatumBound { + inputs_and_output: v.binders.skip_binders().inputs_and_output.clone(), + where_clauses: Vec::new(), + }, + ); + Arc::new(v) + } + + fn impl_datum( + &self, + _impl_id: chalk_ir::ImplId<I>, + ) -> std::sync::Arc<crate::rust_ir::ImplDatum<I>> { + unreachable!("impl items should never be stubbed") + } + + fn associated_ty_value( + &self, + _id: crate::rust_ir::AssociatedTyValueId<I>, + ) -> std::sync::Arc<crate::rust_ir::AssociatedTyValue<I>> { + unreachable!("associated type values should never be stubbed") + } + + fn opaque_ty_data( + &self, + id: chalk_ir::OpaqueTyId<I>, + ) -> std::sync::Arc<crate::rust_ir::OpaqueTyDatum<I>> { + let mut v = (*self.db.opaque_ty_data(id)).clone(); + v.bound = Binders::new( + v.bound.binders, + OpaqueTyDatumBound { + bounds: Binders::new(VariableKinds::empty(self.db.interner()), Vec::new()), + where_clauses: Binders::new(VariableKinds::empty(self.db.interner()), Vec::new()), + }, + ); + Arc::new(v) + } + + fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<I>) -> chalk_ir::Ty<I> { + // Return a unit since the particular hidden type doesn't matter (If it + // did matter, it would have been recorded) + chalk_ir::TyKind::Tuple(0, Substitution::empty(self.db.interner())) + .intern(self.db.interner()) + } + + fn impls_for_trait( + &self, + _trait_id: chalk_ir::TraitId<I>, + _parameters: &[chalk_ir::GenericArg<I>], + _binders: &CanonicalVarKinds<I>, + ) -> Vec<chalk_ir::ImplId<I>> { + // We panic here because the returned ids may not be collected, + // resulting in unresolvable names. + unimplemented!("stub display code should call this") + } + + fn local_impls_to_coherence_check( + &self, + trait_id: chalk_ir::TraitId<I>, + ) -> Vec<chalk_ir::ImplId<I>> { + self.db.local_impls_to_coherence_check(trait_id) + } + + fn impl_provided_for( + &self, + _auto_trait_id: chalk_ir::TraitId<I>, + _ty: &chalk_ir::TyKind<I>, + ) -> bool { + // We panic here because the returned ids may not be collected, + // resulting in unresolvable names. + unimplemented!("stub display code should call this") + } + + fn well_known_trait_id( + &self, + well_known_trait: crate::rust_ir::WellKnownTrait, + ) -> Option<chalk_ir::TraitId<I>> { + self.db.well_known_trait_id(well_known_trait) + } + + fn program_clauses_for_env( + &self, + environment: &chalk_ir::Environment<I>, + ) -> chalk_ir::ProgramClauses<I> { + self.db.program_clauses_for_env(environment) + } + + fn interner(&self) -> I { + self.db.interner() + } + + fn is_object_safe(&self, trait_id: chalk_ir::TraitId<I>) -> bool { + self.db.is_object_safe(trait_id) + } + + fn closure_kind( + &self, + _closure_id: chalk_ir::ClosureId<I>, + _substs: &chalk_ir::Substitution<I>, + ) -> crate::rust_ir::ClosureKind { + unimplemented!("cannot stub closures") + } + + fn closure_inputs_and_output( + &self, + _closure_id: chalk_ir::ClosureId<I>, + _substs: &chalk_ir::Substitution<I>, + ) -> chalk_ir::Binders<crate::rust_ir::FnDefInputsAndOutputDatum<I>> { + unimplemented!("cannot stub closures") + } + + fn closure_upvars( + &self, + _closure_id: chalk_ir::ClosureId<I>, + _substs: &chalk_ir::Substitution<I>, + ) -> chalk_ir::Binders<chalk_ir::Ty<I>> { + unimplemented!("cannot stub closures") + } + + fn generator_datum(&self, _generator_id: GeneratorId<I>) -> Arc<GeneratorDatum<I>> { + unimplemented!("cannot stub generator") + } + + fn generator_witness_datum( + &self, + _generator_id: GeneratorId<I>, + ) -> Arc<GeneratorWitnessDatum<I>> { + unimplemented!("cannot stub generator witness") + } + + fn closure_fn_substitution( + &self, + _closure_id: chalk_ir::ClosureId<I>, + _substs: &chalk_ir::Substitution<I>, + ) -> chalk_ir::Substitution<I> { + unimplemented!("cannot stub closures") + } + + fn unification_database(&self) -> &dyn UnificationDatabase<I> { + self + } + + fn trait_name(&self, trait_id: chalk_ir::TraitId<I>) -> String { + self.db.trait_name(trait_id) + } + + fn adt_name(&self, struct_id: chalk_ir::AdtId<I>) -> String { + self.db.adt_name(struct_id) + } + + fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<I>) -> String { + self.db.assoc_type_name(assoc_ty_id) + } + + fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId<I>) -> String { + self.db.opaque_type_name(opaque_ty_id) + } + + fn fn_def_name(&self, fn_def_id: chalk_ir::FnDefId<I>) -> String { + self.db.fn_def_name(fn_def_id) + } + + fn discriminant_type(&self, ty: Ty<I>) -> Ty<I> { + self.db.discriminant_type(ty) + } +} diff --git a/vendor/chalk-solve/src/display/ty.rs b/vendor/chalk-solve/src/display/ty.rs new file mode 100644 index 000000000..b0186652e --- /dev/null +++ b/vendor/chalk-solve/src/display/ty.rs @@ -0,0 +1,303 @@ +//! Writer logic for types. +//! +//! Contains the highly-recursive logic for writing `TyKind` and its variants. +use std::fmt::{Formatter, Result}; + +use crate::split::Split; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +use super::{ + display_self_where_clauses_as_bounds, display_type_with_generics, render_trait::RenderAsRust, + state::InternalWriterState, +}; + +impl<I: Interner> RenderAsRust<I> for TyKind<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + match self { + TyKind::Adt(sid, substitution) => { + write!(f, "{}", sid.display(s))?; + let parameters = substitution.as_slice(interner); + let parameters = parameters.iter().map(|param| param.display(s)); + write_joined_non_empty_list!(f, "<{}>", parameters, ", ") + } + TyKind::AssociatedType(assoc_type_id, substitution) => { + // (Iterator::Item)(x) + // should be written in Rust as <X as Iterator>::Item + let datum = s.db().associated_ty_data(*assoc_type_id); + assert!( + substitution + .iter(interner) + .filter_map(move |p| p.ty(interner)) + .count() + >= 1, + "AssociatedType should have at least 1 parameter" + ); + write!( + f, + "<{} as {}>::{}", + substitution + .iter(interner) + .filter_map(move |p| p.ty(interner)) + .next() + .unwrap() + .display(s), + datum.trait_id.display(s), + datum.id.display(s), + )?; + let params = substitution.as_slice(interner); + write_joined_non_empty_list!( + f, + "<{}>", + params[1..].iter().map(|ty| ty.display(s)), + "," + ) + } + TyKind::Scalar(scalar) => write!(f, "{}", scalar.display(s)), + TyKind::Tuple(arity, substitution) => { + write!( + f, + "({}{})", + substitution + .as_slice(interner) + .iter() + .map(|p| p.display(s)) + .format(", "), + if *arity == 1 { + // need trailing single comma + "," + } else { + "" + } + ) + } + TyKind::OpaqueType(opaque_ty_id, substitution) => write!( + f, + "{}", + display_type_with_generics(s, *opaque_ty_id, substitution.as_slice(interner)) + ), + TyKind::Raw(mutability, ty) => match mutability { + Mutability::Mut => write!(f, "*mut {}", ty.display(s)), + Mutability::Not => write!(f, "*const {}", ty.display(s)), + }, + TyKind::Ref(mutability, lifetime, ty) => match mutability { + Mutability::Mut => write!(f, "&{} mut {}", lifetime.display(s), ty.display(s)), + Mutability::Not => write!(f, "&{} {}", lifetime.display(s), ty.display(s)), + }, + TyKind::Str => write!(f, "str"), + TyKind::Slice(ty) => write!(f, "[{}]", ty.display(s)), + TyKind::Error => write!(f, "{{error}}"), + TyKind::Never => write!(f, "!"), + + // FIXME: write out valid types for these variants + TyKind::FnDef(..) => write!(f, "<fn_def>"), + TyKind::Closure(..) => write!(f, "<closure>"), + TyKind::Foreign(..) => write!(f, "<foreign>"), + TyKind::Generator(..) => write!(f, "<generator>"), + TyKind::GeneratorWitness(..) => write!(f, "<generator_witness>"), + + TyKind::Array(ty, const_) => write!(f, "[{}; {}]", ty.display(s), const_.display(s),), + TyKind::Dyn(dyn_ty) => { + // the lifetime needs to be outside of the bounds, so we + // introduce a new scope for the bounds + { + let s = &s.add_debrujin_index(None); + // dyn_ty.bounds.binders creates a Self binding for the trait + let bounds = dyn_ty.bounds.skip_binders(); + + write!( + f, + "dyn {}", + display_self_where_clauses_as_bounds(s, bounds.as_slice(interner)), + )?; + } + + write!(f, " + {}", dyn_ty.lifetime.display(s))?; + Ok(()) + } + TyKind::BoundVar(bound_var) => write!(f, "{}", s.display_bound_var(bound_var)), + TyKind::InferenceVar(_, _) => write!(f, "_"), + TyKind::Alias(alias_ty) => alias_ty.fmt(s, f), + TyKind::Function(func) => func.fmt(s, f), + TyKind::Placeholder(_) => write!(f, "<placeholder>"), + } + } +} + +impl<I: Interner> RenderAsRust<I> for AliasTy<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + AliasTy::Projection(projection_ty) => projection_ty.fmt(s, f), + AliasTy::Opaque(opaque_ty) => opaque_ty.fmt(s, f), + } + } +} + +impl<I: Interner> RenderAsRust<I> for ProjectionTy<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // <X as Y<A1, A2, A3>>::Z<B1, B2, B3> + + // Now, we split out A*, Y/Z and B*: + // trait_params is X, A1, A2, A3, + // assoc_type_params is B1, B2, B3, + // assoc_ty_datum stores info about Y and Z. + let (assoc_ty_datum, trait_params, assoc_type_params) = s.db().split_projection(self); + write!( + f, + "<{} as {}>::{}", + trait_params[0].display(s), + display_type_with_generics(s, assoc_ty_datum.trait_id, &trait_params[1..]), + assoc_ty_datum.id.display(s), + )?; + write_joined_non_empty_list!( + f, + "<{}>", + assoc_type_params.iter().map(|param| param.display(s)), + ", " + )?; + Ok(()) + } +} + +impl<I: Interner> RenderAsRust<I> for OpaqueTy<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + write!( + f, + "{}", + display_type_with_generics(s, self.opaque_ty_id, self.substitution.as_slice(interner),) + ) + } +} + +impl<I: Interner> RenderAsRust<I> for FnPointer<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + let s = &s.add_debrujin_index(None); + if self.num_binders > 0 { + write!( + f, + "for<{}> ", + (0..self.num_binders) + .map(|n| format!("'{}", s.name_for_introduced_bound_var(n))) + .format(", ") + )?; + } + let parameters = self.substitution.0.as_slice(interner); + write!( + f, + "fn({}) -> {}", + parameters[..parameters.len() - 1] + .iter() + .map(|param| param.display(s)) + .format(", "), + parameters[parameters.len() - 1].display(s), + ) + } +} + +impl<I: Interner> RenderAsRust<I> for Scalar { + fn fmt(&self, _s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + use chalk_ir::{FloatTy::*, IntTy::*, UintTy::*}; + write!( + f, + "{}", + match self { + Scalar::Bool => "bool", + Scalar::Char => "char", + Scalar::Int(int) => match int { + Isize => "isize", + I8 => "i8", + I16 => "i16", + I32 => "i32", + I64 => "i64", + I128 => "i128", + }, + Scalar::Uint(uint) => match uint { + Usize => "usize", + U8 => "u8", + U16 => "u16", + U32 => "u32", + U64 => "u64", + U128 => "u128", + }, + Scalar::Float(float) => match float { + F32 => "f32", + F64 => "f64", + }, + } + ) + } +} + +impl<I: Interner> RenderAsRust<I> for LifetimeData<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + LifetimeData::BoundVar(v) => write!(f, "'{}", s.display_bound_var(v)), + LifetimeData::InferenceVar(_) => write!(f, "'_"), + LifetimeData::Placeholder(ix) => { + write!(f, "'_placeholder_{}_{}", ix.ui.counter, ix.idx) + } + LifetimeData::Static => write!(f, "'static"), + LifetimeData::Erased => write!(f, "'_"), + // Matching the void ensures at compile time that this code is + // unreachable + LifetimeData::Phantom(void, _) => match *void {}, + } + } +} + +impl<I: Interner> RenderAsRust<I> for ConstData<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + write!(f, "{}", self.value.display(s)) + } +} + +impl<I: Interner> RenderAsRust<I> for ConstValue<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + match self { + ConstValue::BoundVar(v) => write!(f, "{}", s.display_bound_var(v)), + ConstValue::InferenceVar(_) => write!(f, "_"), + ConstValue::Placeholder(_) => write!(f, "<const placeholder>"), + ConstValue::Concrete(value) => write!(f, "{:?}", value.interned), + } + } +} + +impl<I: Interner> RenderAsRust<I> for GenericArgData<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + GenericArgData::Ty(ty) => write!(f, "{}", ty.display(s)), + GenericArgData::Lifetime(lt) => write!(f, "{}", lt.display(s)), + GenericArgData::Const(const_ty) => write!(f, "{}", const_ty.display(s)), + } + } +} + +impl<I: Interner> RenderAsRust<I> for Ty<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // delegate to TyKind + self.kind(s.db().interner()).fmt(s, f) + } +} + +impl<I: Interner> RenderAsRust<I> for Lifetime<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // delegate to LifetimeData + self.data(s.db().interner()).fmt(s, f) + } +} + +impl<I: Interner> RenderAsRust<I> for Const<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + self.data(s.db().interner()).fmt(s, f) + } +} + +impl<I: Interner> RenderAsRust<I> for GenericArg<I> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // delegate to GenericArgData + self.data(s.db().interner()).fmt(s, f) + } +} diff --git a/vendor/chalk-solve/src/display/utils.rs b/vendor/chalk-solve/src/display/utils.rs new file mode 100644 index 000000000..306605616 --- /dev/null +++ b/vendor/chalk-solve/src/display/utils.rs @@ -0,0 +1,51 @@ +//! Render utilities which don't belong anywhere else. +use std::fmt::{Display, Formatter, Result}; + +pub fn as_display<F: Fn(&mut Formatter<'_>) -> Result>(f: F) -> impl Display { + struct ClosureDisplay<F: Fn(&mut Formatter<'_>) -> Result>(F); + + impl<F: Fn(&mut Formatter<'_>) -> Result> Display for ClosureDisplay<F> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + self.0(f) + } + } + + ClosureDisplay(f) +} + +macro_rules! write_joined_non_empty_list { + ($f:expr,$template:tt,$list:expr,$sep:expr) => {{ + let mut x = $list.into_iter().peekable(); + if x.peek().is_some() { + write!($f, $template, x.format($sep)) + } else { + Ok(()) + } + }}; +} + +/// Processes a name given by an [`Interner`][chalk_ir::interner::Interner] debug +/// method into something usable by the `display` module. +/// +/// This is specifically useful when implementing +/// [`RustIrDatabase`][crate::RustIrDatabase] `name_*` methods. +pub fn sanitize_debug_name(func: impl Fn(&mut Formatter<'_>) -> Option<Result>) -> String { + use std::fmt::Write; + + // First, write the debug method contents to a String. + let mut debug_out = String::new(); + // ignore if the result is `None`, as we can just as easily tell by looking + // to see if anything was written to `debug_out`. + write!( + debug_out, + "{}", + as_display(|fmt| { func(fmt).unwrap_or(Ok(())) }) + ) + .expect("expected writing to a String to succeed"); + if debug_out.is_empty() { + return "Unknown".to_owned(); + } + + // now the actual sanitization + debug_out.replace(|c: char| !c.is_ascii_alphanumeric(), "_") +} diff --git a/vendor/chalk-solve/src/ext.rs b/vendor/chalk-solve/src/ext.rs new file mode 100644 index 000000000..9cb8b774a --- /dev/null +++ b/vendor/chalk-solve/src/ext.rs @@ -0,0 +1,113 @@ +use crate::infer::InferenceTable; +use chalk_ir::fold::TypeFoldable; +use chalk_ir::interner::{HasInterner, Interner}; +use chalk_ir::*; + +pub trait CanonicalExt<T: HasInterner, I: Interner> { + fn map<OP, U>(self, interner: I, op: OP) -> Canonical<U> + where + OP: FnOnce(T) -> U, + T: TypeFoldable<I>, + U: TypeFoldable<I>, + U: HasInterner<Interner = I>; +} + +impl<T, I> CanonicalExt<T, I> for Canonical<T> +where + T: HasInterner<Interner = I>, + I: Interner, +{ + /// Maps the contents using `op`, but preserving the binders. + /// + /// NB. `op` will be invoked with an instantiated version of the + /// canonical value, where inference variables (from a fresh + /// inference context) are used in place of the quantified free + /// variables. The result should be in terms of those same + /// inference variables and will be re-canonicalized. + fn map<OP, U>(self, interner: I, op: OP) -> Canonical<U> + where + OP: FnOnce(T) -> U, + T: TypeFoldable<I>, + U: TypeFoldable<I>, + U: HasInterner<Interner = I>, + { + // Subtle: It is only quite rarely correct to apply `op` and + // just re-use our existing binders. For that to be valid, the + // result of `op` would have to ensure that it re-uses all the + // existing free variables and in the same order. Otherwise, + // the canonical form would be different: the variables might + // be numbered differently, or some may not longer be used. + // This would mean that two canonical values could no longer + // be compared with `Eq`, which defeats a key invariant of the + // `Canonical` type (indeed, its entire reason for existence). + let mut infer = InferenceTable::new(); + let snapshot = infer.snapshot(); + let instantiated_value = infer.instantiate_canonical(interner, self); + let mapped_value = op(instantiated_value); + let result = infer.canonicalize(interner, mapped_value); + infer.rollback_to(snapshot); + result.quantified + } +} + +pub trait GoalExt<I: Interner> { + fn into_peeled_goal(self, interner: I) -> UCanonical<InEnvironment<Goal<I>>>; + fn into_closed_goal(self, interner: I) -> UCanonical<InEnvironment<Goal<I>>>; +} + +impl<I: Interner> GoalExt<I> for Goal<I> { + /// Returns a canonical goal in which the outermost `exists<>` and + /// `forall<>` quantifiers (as well as implications) have been + /// "peeled" and are converted into free universal or existential + /// variables. Assumes that this goal is a "closed goal" which + /// does not -- at present -- contain any variables. Useful for + /// REPLs and tests but not much else. + fn into_peeled_goal(self, interner: I) -> UCanonical<InEnvironment<Goal<I>>> { + let mut infer = InferenceTable::new(); + let peeled_goal = { + let mut env_goal = InEnvironment::new(&Environment::new(interner), self); + loop { + let InEnvironment { environment, goal } = env_goal; + match goal.data(interner) { + GoalData::Quantified(QuantifierKind::ForAll, subgoal) => { + let subgoal = + infer.instantiate_binders_universally(interner, subgoal.clone()); + env_goal = InEnvironment::new(&environment, subgoal); + } + + GoalData::Quantified(QuantifierKind::Exists, subgoal) => { + let subgoal = + infer.instantiate_binders_existentially(interner, subgoal.clone()); + env_goal = InEnvironment::new(&environment, subgoal); + } + + GoalData::Implies(wc, subgoal) => { + let new_environment = + environment.add_clauses(interner, wc.iter(interner).cloned()); + env_goal = InEnvironment::new(&new_environment, Goal::clone(subgoal)); + } + + _ => break InEnvironment::new(&environment, goal), + } + } + }; + let canonical = infer.canonicalize(interner, peeled_goal).quantified; + InferenceTable::u_canonicalize(interner, &canonical).quantified + } + + /// Given a goal with no free variables (a "closed" goal), creates + /// a canonical form suitable for solving. This is a suitable + /// choice if you don't actually care about the values of any of + /// the variables within; otherwise, you might want + /// `into_peeled_goal`. + /// + /// # Panics + /// + /// Will panic if this goal does in fact contain free variables. + fn into_closed_goal(self, interner: I) -> UCanonical<InEnvironment<Goal<I>>> { + let mut infer = InferenceTable::new(); + let env_goal = InEnvironment::new(&Environment::new(interner), self); + let canonical_goal = infer.canonicalize(interner, env_goal).quantified; + InferenceTable::u_canonicalize(interner, &canonical_goal).quantified + } +} diff --git a/vendor/chalk-solve/src/goal_builder.rs b/vendor/chalk-solve/src/goal_builder.rs new file mode 100644 index 000000000..aa5c9c9eb --- /dev/null +++ b/vendor/chalk-solve/src/goal_builder.rs @@ -0,0 +1,152 @@ +use crate::RustIrDatabase; +use cast::CastTo; +use chalk_ir::cast::Cast; +use chalk_ir::cast::Caster; +use chalk_ir::*; +use fold::shift::Shift; +use fold::TypeFoldable; +use interner::{HasInterner, Interner}; + +pub struct GoalBuilder<'i, I: Interner> { + db: &'i dyn RustIrDatabase<I>, +} + +impl<'i, I: Interner> GoalBuilder<'i, I> { + pub fn new(db: &'i dyn RustIrDatabase<I>) -> Self { + GoalBuilder { db } + } + + /// Returns the database within the goal builder. + pub fn db(&self) -> &'i dyn RustIrDatabase<I> { + self.db + } + + /// Returns the interner within the goal builder. + pub fn interner(&self) -> I { + self.db.interner() + } + + /// Creates a goal that ensures all of the goals from the `goals` + /// iterator are met (e.g., `goals[0] && ... && goals[N]`). + pub fn all<GS, G>(&mut self, goals: GS) -> Goal<I> + where + GS: IntoIterator<Item = G>, + G: CastTo<Goal<I>>, + { + Goal::all(self.interner(), goals.into_iter().casted(self.interner())) + } + + /// Creates a goal `clauses => goal`. The clauses are given as an iterator + /// and the goal is returned via the contained closure. + pub fn implies<CS, C, G>(&mut self, clauses: CS, goal: impl FnOnce(&mut Self) -> G) -> Goal<I> + where + CS: IntoIterator<Item = C>, + C: CastTo<ProgramClause<I>>, + G: CastTo<Goal<I>>, + { + GoalData::Implies( + ProgramClauses::from_iter(self.interner(), clauses), + goal(self).cast(self.interner()), + ) + .intern(self.interner()) + } + + /// Given a bound value `binders` like `<P0..Pn> V`, + /// creates a goal `forall<Q0..Qn> { G }` where + /// the goal `G` is created by invoking a helper + /// function `body`. + /// + /// # Parameters to `body` + /// + /// `body` will be invoked with: + /// + /// * the goal builder `self` + /// * the substitution `Q0..Qn` + /// * the bound value `[P0..Pn => Q0..Qn] V` instantiated + /// with the substitution + /// * the value `passthru`, appropriately shifted so that + /// any debruijn indices within account for the new binder + /// + /// # Why is `body` a function and not a closure? + /// + /// This is to ensure that `body` doesn't accidentally reference + /// values from the environment whose debruijn indices do not + /// account for the new binder being created. + pub fn forall<G, B, P>( + &mut self, + binders: &Binders<B>, + passthru: P, + body: fn(&mut Self, Substitution<I>, &B, P) -> G, + ) -> Goal<I> + where + B: HasInterner<Interner = I>, + P: TypeFoldable<I>, + G: CastTo<Goal<I>>, + { + self.quantified(QuantifierKind::ForAll, binders, passthru, body) + } + + /// Like [`GoalBuilder::forall`], but for a `exists<Q0..Qn> { G }` goal. + pub fn exists<G, B, P>( + &mut self, + binders: &Binders<B>, + passthru: P, + body: fn(&mut Self, Substitution<I>, &B, P) -> G, + ) -> Goal<I> + where + B: HasInterner<Interner = I>, + P: TypeFoldable<I>, + G: CastTo<Goal<I>>, + { + self.quantified(QuantifierKind::Exists, binders, passthru, body) + } + + /// A combined helper functon for the various methods + /// to create `forall` and `exists` goals. See: + /// + /// * [`GoalBuilder::forall`] + /// * [`GoalBuilder::exists`] + /// + /// for details. + fn quantified<G, B, P>( + &mut self, + quantifier_kind: QuantifierKind, + binders: &Binders<B>, + passthru: P, + body: fn(&mut Self, Substitution<I>, &B, P) -> G, + ) -> Goal<I> + where + B: HasInterner<Interner = I>, + P: TypeFoldable<I>, + G: CastTo<Goal<I>>, + { + let interner = self.interner(); + + // Make an identity mapping `[0 => ^0.0, 1 => ^0.1, ..]` + // and so forth. This substitution is mapping from the `<P0..Pn>` variables + // in `binders` to the corresponding `P0..Pn` variables we're about to + // introduce in the form of a `forall<P0..Pn>` goal. Of course, it's + // actually an identity mapping, since this `forall` will be the innermost + // debruijn binder and so forth, so there's no actual reason to + // *do* the substitution, since it would effectively just be a clone. + let substitution = Substitution::from_iter( + interner, + binders + .binders + .iter(interner) + .enumerate() + .map(|p| p.to_generic_arg(interner)), + ); + + // Shift passthru into one level of binder, to account for the `forall<P0..Pn>` + // we are about to introduce. + let passthru_shifted = passthru.shifted_in(self.interner()); + + // Invoke `body` function, which returns a goal, and wrap that goal in the binders + // from `binders`, and finally a `forall` or `exists` goal. + let bound_goal = binders.map_ref(|bound_value| { + body(self, substitution, bound_value, passthru_shifted).cast(interner) + }); + GoalData::Quantified(quantifier_kind, bound_goal).intern(interner) + } +} diff --git a/vendor/chalk-solve/src/infer.rs b/vendor/chalk-solve/src/infer.rs new file mode 100644 index 000000000..6ede065e0 --- /dev/null +++ b/vendor/chalk-solve/src/infer.rs @@ -0,0 +1,212 @@ +use chalk_ir::interner::{HasInterner, Interner}; +use chalk_ir::*; +use chalk_ir::{cast::Cast, fold::TypeFoldable}; +use tracing::debug; + +mod canonicalize; +pub(crate) mod instantiate; +mod invert; +mod test; +pub mod ucanonicalize; +pub mod unify; +mod var; + +use self::var::*; + +#[derive(Clone)] +pub struct InferenceTable<I: Interner> { + unify: ena::unify::InPlaceUnificationTable<EnaVariable<I>>, + vars: Vec<EnaVariable<I>>, + max_universe: UniverseIndex, +} + +pub struct InferenceSnapshot<I: Interner> { + unify_snapshot: ena::unify::Snapshot<ena::unify::InPlace<EnaVariable<I>>>, + max_universe: UniverseIndex, + vars: Vec<EnaVariable<I>>, +} + +#[allow(type_alias_bounds)] +pub type ParameterEnaVariable<I: Interner> = WithKind<I, EnaVariable<I>>; + +impl<I: Interner> InferenceTable<I> { + /// Create an empty inference table with no variables. + pub fn new() -> Self { + InferenceTable { + unify: ena::unify::UnificationTable::new(), + vars: vec![], + max_universe: UniverseIndex::root(), + } + } + + /// Creates a new inference table, pre-populated with + /// `num_universes` fresh universes. Instantiates the canonical + /// value `canonical` within those universes (which must not + /// reference any universe greater than `num_universes`). Returns + /// the substitution mapping from each canonical binder to its + /// corresponding existential variable, along with the + /// instantiated result. + pub fn from_canonical<T>( + interner: I, + num_universes: usize, + canonical: Canonical<T>, + ) -> (Self, Substitution<I>, T) + where + T: HasInterner<Interner = I> + TypeFoldable<I> + Clone, + { + let mut table = InferenceTable::new(); + + assert!(num_universes >= 1); // always have U0 + for _ in 1..num_universes { + table.new_universe(); + } + + let subst = table.fresh_subst(interner, canonical.binders.as_slice(interner)); + let value = subst.apply(canonical.value, interner); + // let value = canonical.value.fold_with(&mut &subst, 0).unwrap(); + + (table, subst, value) + } + + /// Creates and returns a fresh universe that is distinct from all + /// others created within this inference table. This universe is + /// able to see all previously created universes (though hopefully + /// it is only brought into contact with its logical *parents*). + pub fn new_universe(&mut self) -> UniverseIndex { + let u = self.max_universe.next(); + self.max_universe = u; + debug!("created new universe: {:?}", u); + u + } + + /// Creates a new inference variable and returns its index. The + /// kind of the variable should be known by the caller, but is not + /// tracked directly by the inference table. + pub fn new_variable(&mut self, ui: UniverseIndex) -> EnaVariable<I> { + let var = self.unify.new_key(InferenceValue::Unbound(ui)); + self.vars.push(var); + debug!(?var, ?ui, "created new variable"); + var + } + + /// Takes a "snapshot" of the current state of the inference + /// table. Later, you must invoke either `rollback_to` or + /// `commit` with that snapshot. Snapshots can be nested, but you + /// must respect a stack discipline (i.e., rollback or commit + /// snapshots in reverse order of that with which they were + /// created). + pub fn snapshot(&mut self) -> InferenceSnapshot<I> { + let unify_snapshot = self.unify.snapshot(); + let vars = self.vars.clone(); + let max_universe = self.max_universe; + InferenceSnapshot { + unify_snapshot, + max_universe, + vars, + } + } + + /// Restore the table to the state it had when the snapshot was taken. + pub fn rollback_to(&mut self, snapshot: InferenceSnapshot<I>) { + self.unify.rollback_to(snapshot.unify_snapshot); + self.vars = snapshot.vars; + self.max_universe = snapshot.max_universe; + } + + /// Make permanent the changes made since the snapshot was taken. + pub fn commit(&mut self, snapshot: InferenceSnapshot<I>) { + self.unify.commit(snapshot.unify_snapshot); + } + + pub fn normalize_ty_shallow(&mut self, interner: I, leaf: &Ty<I>) -> Option<Ty<I>> { + // An integer/float type variable will never normalize to another + // variable; but a general type variable might normalize to an + // integer/float variable. So we potentially need to normalize twice to + // get at the actual value. + self.normalize_ty_shallow_inner(interner, leaf) + .map(|ty| self.normalize_ty_shallow_inner(interner, &ty).unwrap_or(ty)) + } + + fn normalize_ty_shallow_inner(&mut self, interner: I, leaf: &Ty<I>) -> Option<Ty<I>> { + self.probe_var(leaf.inference_var(interner)?) + .map(|p| p.assert_ty_ref(interner).clone()) + } + + pub fn normalize_lifetime_shallow( + &mut self, + interner: I, + leaf: &Lifetime<I>, + ) -> Option<Lifetime<I>> { + self.probe_var(leaf.inference_var(interner)?) + .map(|p| p.assert_lifetime_ref(interner).clone()) + } + + pub fn normalize_const_shallow(&mut self, interner: I, leaf: &Const<I>) -> Option<Const<I>> { + self.probe_var(leaf.inference_var(interner)?) + .map(|p| p.assert_const_ref(interner).clone()) + } + + pub fn ty_root(&mut self, interner: I, leaf: &Ty<I>) -> Option<Ty<I>> { + Some( + self.unify + .find(leaf.inference_var(interner)?) + .to_ty(interner), + ) + } + + pub fn lifetime_root(&mut self, interner: I, leaf: &Lifetime<I>) -> Option<Lifetime<I>> { + Some( + self.unify + .find(leaf.inference_var(interner)?) + .to_lifetime(interner), + ) + } + + /// Finds the root inference var for the given variable. + /// + /// The returned variable will be exactly equivalent to the given + /// variable except in name. All variables which have been unified to + /// eachother (but don't yet have a value) have the same "root". + /// + /// This is useful for `DeepNormalizer`. + pub fn inference_var_root(&mut self, var: InferenceVar) -> InferenceVar { + self.unify.find(var).into() + } + + /// If type `leaf` is a free inference variable, and that variable has been + /// bound, returns `Some(P)` where `P` is the parameter to which it has been bound. + pub fn probe_var(&mut self, leaf: InferenceVar) -> Option<GenericArg<I>> { + match self.unify.probe_value(EnaVariable::from(leaf)) { + InferenceValue::Unbound(_) => None, + InferenceValue::Bound(val) => Some(val), + } + } + + /// Given an unbound variable, returns its universe. + /// + /// # Panics + /// + /// Panics if the variable is bound. + fn universe_of_unbound_var(&mut self, var: EnaVariable<I>) -> UniverseIndex { + match self.unify.probe_value(var) { + InferenceValue::Unbound(ui) => ui, + InferenceValue::Bound(_) => panic!("var_universe invoked on bound variable"), + } + } +} + +pub trait ParameterEnaVariableExt<I: Interner> { + fn to_generic_arg(&self, interner: I) -> GenericArg<I>; +} + +impl<I: Interner> ParameterEnaVariableExt<I> for ParameterEnaVariable<I> { + fn to_generic_arg(&self, interner: I) -> GenericArg<I> { + // we are matching on kind, so skipping it is fine + let ena_variable = self.skip_kind(); + match &self.kind { + VariableKind::Ty(kind) => ena_variable.to_ty_with_kind(interner, *kind).cast(interner), + VariableKind::Lifetime => ena_variable.to_lifetime(interner).cast(interner), + VariableKind::Const(ty) => ena_variable.to_const(interner, ty.clone()).cast(interner), + } + } +} diff --git a/vendor/chalk-solve/src/infer/canonicalize.rs b/vendor/chalk-solve/src/infer/canonicalize.rs new file mode 100644 index 000000000..ddec0515d --- /dev/null +++ b/vendor/chalk-solve/src/infer/canonicalize.rs @@ -0,0 +1,237 @@ +use crate::debug_span; +use chalk_derive::FallibleTypeFolder; +use chalk_ir::fold::shift::Shift; +use chalk_ir::fold::{TypeFoldable, TypeFolder}; +use chalk_ir::interner::{HasInterner, Interner}; +use chalk_ir::*; +use std::cmp::max; +use tracing::{debug, instrument}; + +use super::{InferenceTable, ParameterEnaVariable}; + +impl<I: Interner> InferenceTable<I> { + /// Given a value `value` with variables in it, replaces those variables + /// with their instantiated values; any variables not yet instantiated are + /// replaced with a small integer index 0..N in order of appearance. The + /// result is a canonicalized representation of `value`. + /// + /// Example: + /// + /// ?22: Foo<?23> + /// + /// would be quantified to + /// + /// Canonical { value: `?0: Foo<?1>`, binders: [ui(?22), ui(?23)] } + /// + /// where `ui(?22)` and `ui(?23)` are the universe indices of `?22` and + /// `?23` respectively. + /// + /// A substitution mapping from the free variables to their re-bound form is + /// also returned. + pub fn canonicalize<T>(&mut self, interner: I, value: T) -> Canonicalized<T> + where + T: TypeFoldable<I>, + T: HasInterner<Interner = I>, + { + debug_span!("canonicalize", "{:#?}", value); + let mut q = Canonicalizer { + table: self, + free_vars: Vec::new(), + max_universe: UniverseIndex::root(), + interner, + }; + let value = value + .try_fold_with(&mut q, DebruijnIndex::INNERMOST) + .unwrap(); + let free_vars = q.free_vars.clone(); + + Canonicalized { + quantified: Canonical { + value, + binders: q.into_binders(), + }, + free_vars, + } + } +} + +#[derive(Debug)] +pub struct Canonicalized<T: HasInterner> { + /// The canonicalized result. + pub quantified: Canonical<T>, + + /// The free existential variables, along with the universes they inhabit. + pub free_vars: Vec<ParameterEnaVariable<T::Interner>>, +} + +#[derive(FallibleTypeFolder)] +struct Canonicalizer<'q, I: Interner> { + table: &'q mut InferenceTable<I>, + free_vars: Vec<ParameterEnaVariable<I>>, + max_universe: UniverseIndex, + interner: I, +} + +impl<'q, I: Interner> Canonicalizer<'q, I> { + fn into_binders(self) -> CanonicalVarKinds<I> { + let Canonicalizer { + table, + free_vars, + interner, + .. + } = self; + CanonicalVarKinds::from_iter( + interner, + free_vars + .into_iter() + .map(|p_v| p_v.map(|v| table.universe_of_unbound_var(v))), + ) + } + + fn add(&mut self, free_var: ParameterEnaVariable<I>) -> usize { + self.max_universe = max( + self.max_universe, + self.table.universe_of_unbound_var(*free_var.skip_kind()), + ); + + self.free_vars + .iter() + .position(|v| v.skip_kind() == free_var.skip_kind()) + .unwrap_or_else(|| { + let next_index = self.free_vars.len(); + self.free_vars.push(free_var); + next_index + }) + } +} + +impl<'i, I: Interner> TypeFolder<I> for Canonicalizer<'i, I> { + fn as_dyn(&mut self) -> &mut dyn TypeFolder<I> { + self + } + + fn fold_free_placeholder_ty( + &mut self, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Ty<I> { + let interner = self.interner; + self.max_universe = max(self.max_universe, universe.ui); + universe.to_ty(interner) + } + + fn fold_free_placeholder_lifetime( + &mut self, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Lifetime<I> { + let interner = self.interner; + self.max_universe = max(self.max_universe, universe.ui); + universe.to_lifetime(interner) + } + + fn fold_free_placeholder_const( + &mut self, + ty: Ty<I>, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Const<I> { + let interner = self.interner; + self.max_universe = max(self.max_universe, universe.ui); + universe.to_const(interner, ty) + } + + fn forbid_free_vars(&self) -> bool { + true + } + + #[instrument(level = "debug", skip(self))] + fn fold_inference_ty( + &mut self, + var: InferenceVar, + kind: TyVariableKind, + outer_binder: DebruijnIndex, + ) -> Ty<I> { + let interner = self.interner; + match self.table.probe_var(var) { + Some(ty) => { + let ty = ty.assert_ty_ref(interner); + debug!("bound to {:?}", ty); + ty.clone() + .fold_with(self, DebruijnIndex::INNERMOST) + .shifted_in_from(interner, outer_binder) + } + None => { + // If this variable is not yet bound, find its + // canonical index `root_var` in the union-find table, + // and then map `root_var` to a fresh index that is + // unique to this quantification. + let free_var = + ParameterEnaVariable::new(VariableKind::Ty(kind), self.table.unify.find(var)); + + let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); + debug!(position=?bound_var, "not yet unified"); + TyKind::BoundVar(bound_var.shifted_in_from(outer_binder)).intern(interner) + } + } + } + + #[instrument(level = "debug", skip(self))] + fn fold_inference_lifetime( + &mut self, + var: InferenceVar, + outer_binder: DebruijnIndex, + ) -> Lifetime<I> { + let interner = self.interner; + match self.table.probe_var(var) { + Some(l) => { + let l = l.assert_lifetime_ref(interner); + debug!("bound to {:?}", l); + l.clone() + .fold_with(self, DebruijnIndex::INNERMOST) + .shifted_in_from(interner, outer_binder) + } + None => { + let free_var = + ParameterEnaVariable::new(VariableKind::Lifetime, self.table.unify.find(var)); + let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); + debug!(position=?bound_var, "not yet unified"); + LifetimeData::BoundVar(bound_var.shifted_in_from(outer_binder)).intern(interner) + } + } + } + + #[instrument(level = "debug", skip(self, ty))] + fn fold_inference_const( + &mut self, + ty: Ty<I>, + var: InferenceVar, + outer_binder: DebruijnIndex, + ) -> Const<I> { + let interner = self.interner; + match self.table.probe_var(var) { + Some(c) => { + let c = c.assert_const_ref(interner); + debug!("bound to {:?}", c); + c.clone() + .fold_with(self, DebruijnIndex::INNERMOST) + .shifted_in_from(interner, outer_binder) + } + None => { + let free_var = ParameterEnaVariable::new( + VariableKind::Const(ty.clone()), + self.table.unify.find(var), + ); + let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); + debug!(position = ?bound_var, "not yet unified"); + bound_var + .shifted_in_from(outer_binder) + .to_const(interner, ty) + } + } + } + + fn interner(&self) -> I { + self.interner + } +} diff --git a/vendor/chalk-solve/src/infer/instantiate.rs b/vendor/chalk-solve/src/infer/instantiate.rs new file mode 100644 index 000000000..161271f23 --- /dev/null +++ b/vendor/chalk-solve/src/infer/instantiate.rs @@ -0,0 +1,111 @@ +use chalk_ir::fold::*; +use chalk_ir::interner::HasInterner; +use std::fmt::Debug; +use tracing::instrument; + +use super::*; + +impl<I: Interner> InferenceTable<I> { + /// Given the binders from a canonicalized value C, returns a + /// substitution S mapping each free variable in C to a fresh + /// inference variable. This substitution can then be applied to + /// C, which would be equivalent to + /// `self.instantiate_canonical(v)`. + pub(super) fn fresh_subst( + &mut self, + interner: I, + binders: &[CanonicalVarKind<I>], + ) -> Substitution<I> { + Substitution::from_iter( + interner, + binders.iter().map(|kind| { + let param_infer_var = kind.map_ref(|&ui| self.new_variable(ui)); + param_infer_var.to_generic_arg(interner) + }), + ) + } + + /// Variant on `instantiate` that takes a `Canonical<T>`. + pub fn instantiate_canonical<T>(&mut self, interner: I, bound: Canonical<T>) -> T + where + T: HasInterner<Interner = I> + TypeFoldable<I> + Debug, + { + let subst = self.fresh_subst(interner, bound.binders.as_slice(interner)); + subst.apply(bound.value, interner) + } + + /// Instantiates `arg` with fresh existential variables in the + /// given universe; the kinds of the variables are implied by + /// `binders`. This is used to apply a universally quantified + /// clause like `forall X, 'Y. P => Q`. Here the `binders` + /// argument is referring to `X, 'Y`. + fn instantiate_in<T>( + &mut self, + interner: I, + universe: UniverseIndex, + binders: impl Iterator<Item = VariableKind<I>>, + arg: T, + ) -> T + where + T: TypeFoldable<I>, + { + let binders: Vec<_> = binders + .map(|pk| CanonicalVarKind::new(pk, universe)) + .collect(); + let subst = self.fresh_subst(interner, &binders); + subst.apply(arg, interner) + } + + /// Variant on `instantiate_in` that takes a `Binders<T>`. + #[instrument(level = "debug", skip(self, interner))] + pub fn instantiate_binders_existentially<T>(&mut self, interner: I, arg: Binders<T>) -> T + where + T: TypeFoldable<I> + HasInterner<Interner = I>, + { + let (value, binders) = arg.into_value_and_skipped_binders(); + + let max_universe = self.max_universe; + self.instantiate_in( + interner, + max_universe, + binders.iter(interner).cloned(), + value, + ) + } + + #[instrument(level = "debug", skip(self, interner))] + pub fn instantiate_binders_universally<T>(&mut self, interner: I, arg: Binders<T>) -> T + where + T: TypeFoldable<I> + HasInterner<Interner = I>, + { + let (value, binders) = arg.into_value_and_skipped_binders(); + + let mut lazy_ui = None; + let mut ui = || { + lazy_ui.unwrap_or_else(|| { + let ui = self.new_universe(); + lazy_ui = Some(ui); + ui + }) + }; + let parameters: Vec<_> = binders + .iter(interner) + .cloned() + .enumerate() + .map(|(idx, pk)| { + let placeholder_idx = PlaceholderIndex { ui: ui(), idx }; + match pk { + VariableKind::Lifetime => { + let lt = placeholder_idx.to_lifetime(interner); + lt.cast(interner) + } + VariableKind::Ty(_) => placeholder_idx.to_ty(interner).cast(interner), + VariableKind::Const(ty) => { + placeholder_idx.to_const(interner, ty).cast(interner) + } + } + }) + .collect(); + Subst::apply(interner, ¶meters, value) + } +} diff --git a/vendor/chalk-solve/src/infer/invert.rs b/vendor/chalk-solve/src/infer/invert.rs new file mode 100644 index 000000000..e5bc3590c --- /dev/null +++ b/vendor/chalk-solve/src/infer/invert.rs @@ -0,0 +1,174 @@ +use chalk_derive::FallibleTypeFolder; +use chalk_ir::fold::shift::Shift; +use chalk_ir::fold::{TypeFoldable, TypeFolder}; +use chalk_ir::interner::HasInterner; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use rustc_hash::FxHashMap; + +use super::canonicalize::Canonicalized; +use super::{EnaVariable, InferenceTable}; + +impl<I: Interner> InferenceTable<I> { + /// Converts `value` into a "negation" value -- meaning one that, + /// if we can find any answer to it, then the negation fails. For + /// goals that do not contain any free variables, then this is a + /// no-op operation. + /// + /// If `value` contains any existential variables that have not + /// yet been assigned a value, then this function will return + /// `None`, indicating that we cannot prove negation for this goal + /// yet. This follows the approach in Clark's original + /// [negation-as-failure paper][1], where negative goals are only + /// permitted if they contain no free (existential) variables. + /// + /// [1]: https://www.doc.ic.ac.uk/~klc/NegAsFailure.pdf + /// + /// Restricting free existential variables is done because the + /// semantics of such queries is not what you expect: it basically + /// treats the existential as a universal. For example, consider: + /// + /// ```rust,ignore + /// struct Vec<T> {} + /// struct i32 {} + /// struct u32 {} + /// trait Foo {} + /// impl Foo for Vec<u32> {} + /// ``` + /// + /// If we ask `exists<T> { not { Vec<T>: Foo } }`, what should happen? + /// If we allow negative queries to be definitively answered even when + /// they contain free variables, we will get a definitive *no* to the + /// entire goal! From a logical perspective, that's just wrong: there + /// does exists a `T` such that `not { Vec<T>: Foo }`, namely `i32`. The + /// problem is that the proof search procedure is actually trying to + /// prove something stronger, that there is *no* such `T`. + /// + /// An additional complication arises around free universal + /// variables. Consider a query like `not { !0 = !1 }`, where + /// `!0` and `!1` are placeholders for universally quantified + /// types (i.e., `TyKind::Placeholder`). If we just tried to + /// prove `!0 = !1`, we would get false, because those types + /// cannot be unified -- this would then allow us to conclude that + /// `not { !0 = !1 }`, i.e., `forall<X, Y> { not { X = Y } }`, but + /// this is clearly not true -- what if X were to be equal to Y? + /// + /// Interestingly, the semantics of existential variables turns + /// out to be exactly what we want here. So, in addition to + /// forbidding existential variables in the original query, the + /// `negated` query also converts all universals *into* + /// existentials. Hence `negated` applies to `!0 = !1` would yield + /// `exists<X,Y> { X = Y }` (note that a canonical, i.e. closed, + /// result is returned). Naturally this has a solution, and hence + /// `not { !0 = !1 }` fails, as we expect. + /// + /// (One could imagine converting free existentials into + /// universals, rather than forbidding them altogether. This would + /// be conceivable, but overly strict. For example, the goal + /// `exists<T> { not { ?T: Clone }, ?T = Vec<i32> }` would come + /// back as false, when clearly this is true. This is because we + /// would wind up proving that `?T: Clone` can *never* be + /// satisfied (which is false), when we only really care about + /// `?T: Clone` in the case where `?T = Vec<i32>`. The current + /// version would delay processing the negative goal (i.e., return + /// `None`) until the second unification has occurred.) + pub fn invert<T>(&mut self, interner: I, value: T) -> Option<T> + where + T: TypeFoldable<I> + HasInterner<Interner = I>, + { + let Canonicalized { + free_vars, + quantified, + .. + } = self.canonicalize(interner, value); + + // If the original contains free existential variables, give up. + if !free_vars.is_empty() { + return None; + } + + // If this contains free universal variables, replace them with existentials. + assert!(quantified.binders.is_empty(interner)); + let inverted = quantified + .value + .try_fold_with(&mut Inverter::new(interner, self), DebruijnIndex::INNERMOST) + .unwrap(); + Some(inverted) + } + + /// As `negated_instantiated`, but canonicalizes before + /// returning. Just a convenience function. + pub fn invert_then_canonicalize<T>(&mut self, interner: I, value: T) -> Option<Canonical<T>> + where + T: TypeFoldable<I> + HasInterner<Interner = I>, + { + let snapshot = self.snapshot(); + let result = self.invert(interner, value); + let result = result.map(|r| self.canonicalize(interner, r).quantified); + self.rollback_to(snapshot); + result + } +} + +#[derive(FallibleTypeFolder)] +struct Inverter<'q, I: Interner> { + table: &'q mut InferenceTable<I>, + inverted_ty: FxHashMap<PlaceholderIndex, EnaVariable<I>>, + inverted_lifetime: FxHashMap<PlaceholderIndex, EnaVariable<I>>, + interner: I, +} + +impl<'q, I: Interner> Inverter<'q, I> { + fn new(interner: I, table: &'q mut InferenceTable<I>) -> Self { + Inverter { + table, + inverted_ty: FxHashMap::default(), + inverted_lifetime: FxHashMap::default(), + interner, + } + } +} + +impl<'i, I: Interner> TypeFolder<I> for Inverter<'i, I> { + fn as_dyn(&mut self) -> &mut dyn TypeFolder<I> { + self + } + + fn fold_free_placeholder_ty( + &mut self, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Ty<I> { + let table = &mut self.table; + self.inverted_ty + .entry(universe) + .or_insert_with(|| table.new_variable(universe.ui)) + .to_ty(TypeFolder::interner(self)) + .shifted_in(TypeFolder::interner(self)) + } + + fn fold_free_placeholder_lifetime( + &mut self, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Lifetime<I> { + let table = &mut self.table; + self.inverted_lifetime + .entry(universe) + .or_insert_with(|| table.new_variable(universe.ui)) + .to_lifetime(TypeFolder::interner(self)) + .shifted_in(TypeFolder::interner(self)) + } + + fn forbid_free_vars(&self) -> bool { + true + } + + fn forbid_inference_vars(&self) -> bool { + true + } + + fn interner(&self) -> I { + self.interner + } +} diff --git a/vendor/chalk-solve/src/infer/test.rs b/vendor/chalk-solve/src/infer/test.rs new file mode 100644 index 000000000..2ac35f027 --- /dev/null +++ b/vendor/chalk-solve/src/infer/test.rs @@ -0,0 +1,422 @@ +#![cfg(test)] + +use super::unify::RelationResult; +use super::*; +use chalk_integration::interner::ChalkIr; +use chalk_integration::{arg, lifetime, ty}; + +// We just use a vec of 20 `Invariant`, since this is zipped and no substs are +// longer than this +#[derive(Debug)] +struct TestDatabase; +impl UnificationDatabase<ChalkIr> for TestDatabase { + fn fn_def_variance(&self, _fn_def_id: FnDefId<ChalkIr>) -> Variances<ChalkIr> { + Variances::from_iter(ChalkIr, [Variance::Invariant; 20].iter().copied()) + } + + fn adt_variance(&self, _adt_id: AdtId<ChalkIr>) -> Variances<ChalkIr> { + Variances::from_iter(ChalkIr, [Variance::Invariant; 20].iter().copied()) + } +} + +#[test] +fn universe_error() { + // exists(A -> forall(X -> A = X)) ---> error + let interner = ChalkIr; + let mut table: InferenceTable<ChalkIr> = InferenceTable::new(); + let environment0 = Environment::new(interner); + let a = table.new_variable(U0).to_ty(interner); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &ty!(placeholder 1), + ) + .unwrap_err(); +} + +#[test] +fn cycle_error() { + // exists(A -> A = foo A) ---> error + let interner = ChalkIr; + let mut table: InferenceTable<ChalkIr> = InferenceTable::new(); + let environment0 = Environment::new(interner); + let a = table.new_variable(U0).to_ty(interner); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &ty!(apply (item 0) (expr a)), + ) + .unwrap_err(); + + // exists(A -> A = for<'a> A) + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &ty!(function 1 (infer 0)), + ) + .unwrap_err(); +} + +#[test] +fn cycle_indirect() { + // exists(A -> A = foo B, A = B) ---> error + let interner = ChalkIr; + let mut table: InferenceTable<ChalkIr> = InferenceTable::new(); + let environment0 = Environment::new(interner); + let a = table.new_variable(U0).to_ty(interner); + let b = table.new_variable(U0).to_ty(interner); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &ty!(apply (item 0) (expr b)), + ) + .unwrap(); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &b, + ) + .unwrap_err(); +} + +#[test] +fn universe_error_indirect_1() { + // exists(A -> forall(X -> exists(B -> B = X, A = B))) ---> error + let interner = ChalkIr; + let mut table: InferenceTable<ChalkIr> = InferenceTable::new(); + let environment0 = Environment::new(interner); + let a = table.new_variable(U0).to_ty(interner); + let b = table.new_variable(U1).to_ty(interner); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &b, + &ty!(placeholder 1), + ) + .unwrap(); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &b, + ) + .unwrap_err(); +} + +#[test] +fn universe_error_indirect_2() { + // exists(A -> forall(X -> exists(B -> B = A, B = X))) ---> error + let interner = ChalkIr; + let mut table: InferenceTable<ChalkIr> = InferenceTable::new(); + let environment0 = Environment::new(interner); + let a = table.new_variable(U0).to_ty(interner); + let b = table.new_variable(U1).to_ty(interner); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &b, + ) + .unwrap(); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &b, + &ty!(placeholder 1), + ) + .unwrap_err(); +} + +#[test] +fn universe_promote() { + // exists(A -> forall(X -> exists(B -> A = foo(B), A = foo(i32)))) ---> OK + let interner = ChalkIr; + let mut table: InferenceTable<ChalkIr> = InferenceTable::new(); + let environment0 = Environment::new(interner); + let a = table.new_variable(U0).to_ty(interner); + let b = table.new_variable(U1).to_ty(interner); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &ty!(apply (item 0) (expr b)), + ) + .unwrap(); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &ty!(apply (item 0) (apply (item 1))), + ) + .unwrap(); +} + +#[test] +fn universe_promote_bad() { + // exists(A -> forall(X -> exists(B -> A = foo(B), B = X))) ---> error + let interner = ChalkIr; + let mut table: InferenceTable<ChalkIr> = InferenceTable::new(); + let environment0 = Environment::new(interner); + let a = table.new_variable(U0).to_ty(interner); + let b = table.new_variable(U1).to_ty(interner); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &ty!(apply (item 0) (expr b)), + ) + .unwrap(); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &b, + &ty!(placeholder 1), + ) + .unwrap_err(); +} + +#[test] +fn projection_eq() { + // exists(A -> A = Item0<<A as Item1>::foo>) + // ^^^^^^^^^^^^ Can A repeat here? For now, + // we say no, but it's an interesting question. + let interner = ChalkIr; + let mut table: InferenceTable<ChalkIr> = InferenceTable::new(); + let environment0 = Environment::new(interner); + let a = table.new_variable(U0).to_ty(interner); + + // expect an error ("cycle during unification") + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &a, + &ty!(apply (item 0) (projection (item 1) (expr a))), + ) + .unwrap_err(); +} + +const U0: UniverseIndex = UniverseIndex { counter: 0 }; +const U1: UniverseIndex = UniverseIndex { counter: 1 }; +const U2: UniverseIndex = UniverseIndex { counter: 2 }; + +fn make_table() -> InferenceTable<ChalkIr> { + let mut table: InferenceTable<ChalkIr> = InferenceTable::new(); + let _ = table.new_universe(); // U1 + let _ = table.new_universe(); // U2 + table +} + +#[test] +fn quantify_simple() { + let interner = ChalkIr; + let mut table = make_table(); + let _ = table.new_variable(U0); + let _ = table.new_variable(U1); + let _ = table.new_variable(U2); + + assert_eq!( + table + .canonicalize(interner, ty!(apply (item 0) (infer 2) (infer 1) (infer 0))) + .quantified, + Canonical { + value: ty!(apply (item 0) (bound 0) (bound 1) (bound 2)), + binders: CanonicalVarKinds::from_iter( + interner, + vec![ + CanonicalVarKind::new(VariableKind::Ty(TyVariableKind::General), U2), + CanonicalVarKind::new(VariableKind::Ty(TyVariableKind::General), U1), + CanonicalVarKind::new(VariableKind::Ty(TyVariableKind::General), U0), + ] + ), + } + ); +} + +#[test] +fn quantify_bound() { + let interner = ChalkIr; + let mut table = make_table(); + let environment0 = Environment::new(interner); + + let v0 = table.new_variable(U0).to_ty(interner); + let v1 = table.new_variable(U1).to_ty(interner); + let v2a = table.new_variable(U2).to_ty(interner); + let v2b = table.new_variable(U2).to_ty(interner); + + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &v2b, + &ty!(apply (item 1) (expr v1) (expr v0)), + ) + .unwrap(); + + assert_eq!( + table + .canonicalize( + interner, + ty!(apply (item 0) (expr v2b) (expr v2a) (expr v1) (expr v0)) + ) + .quantified, + Canonical { + value: ty!(apply (item 0) (apply (item 1) (bound 0) (bound 1)) (bound 2) (bound 0) (bound 1)), + binders: CanonicalVarKinds::from_iter( + interner, + vec![ + CanonicalVarKind::new(VariableKind::Ty(TyVariableKind::General), U1), + CanonicalVarKind::new(VariableKind::Ty(TyVariableKind::General), U0), + CanonicalVarKind::new(VariableKind::Ty(TyVariableKind::General), U2), + ] + ), + } + ); +} + +#[test] +fn quantify_ty_under_binder() { + let interner = ChalkIr; + let mut table = make_table(); + let v0 = table.new_variable(U0); + let v1 = table.new_variable(U0); + let _r2 = table.new_variable(U0); + + // Unify v0 and v1. + let environment0 = Environment::new(interner); + table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &v0.to_ty(interner), + &v1.to_ty(interner), + ) + .unwrap(); + + // Here: the `function` introduces 3 binders, so in the result, + // `(bound 3)` references the first canonicalized inference + // variable. -- note that `infer 0` and `infer 1` have been + // unified above, as well. + assert_eq!( + table + .canonicalize( + interner, + ty!(function 3 (apply (item 0) (bound 1) (infer 0) (infer 1) (lifetime (infer 2)))) + ) + .quantified, + Canonical { + value: ty!(function 3 (apply (item 0) (bound 1) (bound 1 0) (bound 1 0) (lifetime (bound 1 1)))), + binders: CanonicalVarKinds::from_iter( + interner, + vec![ + CanonicalVarKind::new(VariableKind::Ty(TyVariableKind::General), U0), + CanonicalVarKind::new(VariableKind::Lifetime, U0) + ] + ), + } + ); +} + +#[test] +fn lifetime_constraint_indirect() { + let interner = ChalkIr; + let mut table: InferenceTable<ChalkIr> = InferenceTable::new(); + let _ = table.new_universe(); // U1 + + let _t_0 = table.new_variable(U0); + let _l_1 = table.new_variable(U1); + + let environment0 = Environment::new(interner); + + // Here, we unify '?1 (the lifetime variable in universe 1) with + // '!1. + let t_a = ty!(apply (item 0) (lifetime (placeholder 1))); + let t_b = ty!(apply (item 0) (lifetime (infer 1))); + let RelationResult { goals } = table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &t_a, + &t_b, + ) + .unwrap(); + assert!(goals.is_empty()); + + // Here, we try to unify `?0` (the type variable in universe 0) + // with something that involves `'?1`. Since `'?1` has been + // unified with `'!1`, and `'!1` is not visible from universe 0, + // we will replace `'!1` with a new variable `'?2` and introduce a + // (likely unsatisfiable) constraint relating them. + let t_c = ty!(infer 0); + let RelationResult { goals } = table + .relate( + interner, + &TestDatabase, + &environment0, + Variance::Invariant, + &t_c, + &t_b, + ) + .unwrap(); + assert_eq!(goals.len(), 2); + assert_eq!( + format!("{:?}", goals[0]), + "InEnvironment { environment: Env([]), goal: \'?2: \'!1_0 }", + ); + assert_eq!( + format!("{:?}", goals[1]), + "InEnvironment { environment: Env([]), goal: \'!1_0: \'?2 }", + ); +} diff --git a/vendor/chalk-solve/src/infer/ucanonicalize.rs b/vendor/chalk-solve/src/infer/ucanonicalize.rs new file mode 100644 index 000000000..b44880e37 --- /dev/null +++ b/vendor/chalk-solve/src/infer/ucanonicalize.rs @@ -0,0 +1,336 @@ +use crate::debug_span; +use chalk_derive::FallibleTypeFolder; +use chalk_ir::fold::{TypeFoldable, TypeFolder}; +use chalk_ir::interner::{HasInterner, Interner}; +use chalk_ir::visit::{TypeVisitable, TypeVisitor}; +use chalk_ir::*; +use std::ops::ControlFlow; + +use super::InferenceTable; + +impl<I: Interner> InferenceTable<I> { + pub fn u_canonicalize<T>(interner: I, value0: &Canonical<T>) -> UCanonicalized<T> + where + T: Clone + HasInterner<Interner = I> + TypeFoldable<I> + TypeVisitable<I>, + T: HasInterner<Interner = I>, + { + debug_span!("u_canonicalize", "{:#?}", value0); + + // First, find all the universes that appear in `value`. + let mut universes = UniverseMap::new(); + + for universe in value0.binders.iter(interner) { + universes.add(*universe.skip_kind()); + } + + value0.value.visit_with( + &mut UCollector { + universes: &mut universes, + interner, + }, + DebruijnIndex::INNERMOST, + ); + + // Now re-map the universes found in value. We have to do this + // in a second pass because it is only then that we know the + // full set of universes found in the original value. + let value1 = value0 + .value + .clone() + .try_fold_with( + &mut UMapToCanonical { + universes: &universes, + interner, + }, + DebruijnIndex::INNERMOST, + ) + .unwrap(); + let binders = CanonicalVarKinds::from_iter( + interner, + value0 + .binders + .iter(interner) + .map(|pk| pk.map_ref(|&ui| universes.map_universe_to_canonical(ui).unwrap())), + ); + + UCanonicalized { + quantified: UCanonical { + universes: universes.num_canonical_universes(), + canonical: Canonical { + value: value1, + binders, + }, + }, + universes, + } + } +} + +#[derive(Debug)] +pub struct UCanonicalized<T: HasInterner> { + /// The canonicalized result. + pub quantified: UCanonical<T>, + + /// A map between the universes in `quantified` and the original universes + pub universes: UniverseMap, +} + +pub trait UniverseMapExt { + fn add(&mut self, universe: UniverseIndex); + fn map_universe_to_canonical(&self, universe: UniverseIndex) -> Option<UniverseIndex>; + fn map_universe_from_canonical(&self, universe: UniverseIndex) -> UniverseIndex; + fn map_from_canonical<T, I>(&self, interner: I, canonical_value: &Canonical<T>) -> Canonical<T> + where + T: Clone + TypeFoldable<I> + HasInterner<Interner = I>, + T: HasInterner<Interner = I>, + I: Interner; +} +impl UniverseMapExt for UniverseMap { + fn add(&mut self, universe: UniverseIndex) { + if let Err(i) = self.universes.binary_search(&universe) { + self.universes.insert(i, universe); + } + } + + /// Given a universe U that appeared in our original value, return + /// the universe to use in the u-canonical value. This is done by + /// looking for the index I of U in `self.universes`. We will + /// return the universe with "counter" I. This effectively + /// "compresses" the range of universes to things from + /// `0..self.universes.len()`. If the universe is not present in the map, + /// we return `None`. + fn map_universe_to_canonical(&self, universe: UniverseIndex) -> Option<UniverseIndex> { + self.universes + .binary_search(&universe) + .ok() + .map(|index| UniverseIndex { counter: index }) + } + + /// Given a "canonical universe" -- one found in the + /// `u_canonicalize` result -- returns the original universe that + /// it corresponded to. + fn map_universe_from_canonical(&self, universe: UniverseIndex) -> UniverseIndex { + if universe.counter < self.universes.len() { + self.universes[universe.counter] + } else { + // If this universe is out of bounds, we assume an + // implicit `forall` binder, effectively, and map to a + // "big enough" universe in the original space. See + // comments on `map_from_canonical` for a detailed + // explanation. + let difference = universe.counter - self.universes.len(); + let max_counter = self.universes.last().unwrap().counter; + let new_counter = max_counter + difference + 1; + UniverseIndex { + counter: new_counter, + } + } + } + + /// Returns a mapped version of `value` where the universes have + /// been translated from canonical universes into the original + /// universes. + /// + /// In some cases, `value` may contain fresh universes that are + /// not described in the original map. This occurs when we return + /// region constraints -- for example, if we were to process a + /// constraint like `for<'a> 'a == 'b`, where `'b` is an inference + /// variable, that would generate a region constraint that `!2 == + /// ?0`. (This constraint is typically not, as it happens, + /// satisfiable, but it may be, depending on the bounds on `!2`.) + /// In effect, there is a "for all" binder around the constraint, + /// but it is not represented explicitly -- only implicitly, by + /// the presence of a U2 variable. + /// + /// If we encounter universes like this, which are "out of bounds" + /// from our original set of universes, we map them to a distinct + /// universe in the original space that is greater than all the + /// other universes in the map. That is, if we encounter a + /// canonical universe `Ux` where our canonical vector is (say) + /// `[U0, U3]`, we would compute the difference `d = x - 2` and + /// then return the universe `3 + d + 1`. + /// + /// The important thing is that we preserve (a) the relative order + /// of universes, since that determines visibility, and (b) that + /// the universe we produce does not correspond to any of the + /// other original universes. + fn map_from_canonical<T, I>(&self, interner: I, canonical_value: &Canonical<T>) -> Canonical<T> + where + T: Clone + TypeFoldable<I> + HasInterner<Interner = I>, + T: HasInterner<Interner = I>, + I: Interner, + { + debug_span!("map_from_canonical", ?canonical_value, universes = ?self.universes); + + let binders = canonical_value + .binders + .iter(interner) + .map(|cvk| cvk.map_ref(|&universe| self.map_universe_from_canonical(universe))); + + let value = canonical_value + .value + .clone() + .try_fold_with( + &mut UMapFromCanonical { + interner, + universes: self, + }, + DebruijnIndex::INNERMOST, + ) + .unwrap(); + + Canonical { + binders: CanonicalVarKinds::from_iter(interner, binders), + value, + } + } +} + +/// The `UCollector` is a "no-op" in terms of the value, but along the +/// way it collects all universes that were found into a vector. +struct UCollector<'q, I> { + universes: &'q mut UniverseMap, + interner: I, +} + +impl<I: Interner> TypeVisitor<I> for UCollector<'_, I> { + type BreakTy = (); + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> { + self + } + + fn visit_free_placeholder( + &mut self, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> ControlFlow<()> { + self.universes.add(universe.ui); + ControlFlow::Continue(()) + } + + fn forbid_inference_vars(&self) -> bool { + true + } + + fn interner(&self) -> I { + self.interner + } +} + +#[derive(FallibleTypeFolder)] +struct UMapToCanonical<'q, I: Interner> { + interner: I, + universes: &'q UniverseMap, +} + +impl<'i, I: Interner> TypeFolder<I> for UMapToCanonical<'i, I> { + fn as_dyn(&mut self) -> &mut dyn TypeFolder<I> { + self + } + + fn forbid_inference_vars(&self) -> bool { + true + } + + fn fold_free_placeholder_ty( + &mut self, + universe0: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Ty<I> { + let ui = self + .universes + .map_universe_to_canonical(universe0.ui) + .expect("Expected UCollector to encounter this universe"); + PlaceholderIndex { + ui, + idx: universe0.idx, + } + .to_ty(TypeFolder::interner(self)) + } + + fn fold_free_placeholder_lifetime( + &mut self, + universe0: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Lifetime<I> { + let universe = self + .universes + .map_universe_to_canonical(universe0.ui) + .expect("Expected UCollector to encounter this universe"); + + PlaceholderIndex { + ui: universe, + idx: universe0.idx, + } + .to_lifetime(TypeFolder::interner(self)) + } + + fn fold_free_placeholder_const( + &mut self, + ty: Ty<I>, + universe0: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Const<I> { + let universe = self + .universes + .map_universe_to_canonical(universe0.ui) + .expect("Expected UCollector to encounter this universe"); + + PlaceholderIndex { + ui: universe, + idx: universe0.idx, + } + .to_const(TypeFolder::interner(self), ty) + } + + fn interner(&self) -> I { + self.interner + } +} + +#[derive(FallibleTypeFolder)] +struct UMapFromCanonical<'q, I: Interner> { + interner: I, + universes: &'q UniverseMap, +} + +impl<'i, I: Interner> TypeFolder<I> for UMapFromCanonical<'i, I> { + fn as_dyn(&mut self) -> &mut dyn TypeFolder<I> { + self + } + + fn fold_free_placeholder_ty( + &mut self, + universe0: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Ty<I> { + let ui = self.universes.map_universe_from_canonical(universe0.ui); + PlaceholderIndex { + ui, + idx: universe0.idx, + } + .to_ty(TypeFolder::interner(self)) + } + + fn fold_free_placeholder_lifetime( + &mut self, + universe0: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Lifetime<I> { + let universe = self.universes.map_universe_from_canonical(universe0.ui); + PlaceholderIndex { + ui: universe, + idx: universe0.idx, + } + .to_lifetime(TypeFolder::interner(self)) + } + + fn forbid_inference_vars(&self) -> bool { + true + } + + fn interner(&self) -> I { + self.interner + } +} diff --git a/vendor/chalk-solve/src/infer/unify.rs b/vendor/chalk-solve/src/infer/unify.rs new file mode 100644 index 000000000..10086e651 --- /dev/null +++ b/vendor/chalk-solve/src/infer/unify.rs @@ -0,0 +1,1448 @@ +use super::var::*; +use super::*; +use crate::debug_span; +use chalk_ir::cast::Cast; +use chalk_ir::fold::{FallibleTypeFolder, TypeFoldable}; +use chalk_ir::interner::{HasInterner, Interner}; +use chalk_ir::zip::{Zip, Zipper}; +use chalk_ir::UnificationDatabase; +use std::fmt::Debug; +use tracing::{debug, instrument}; + +impl<I: Interner> InferenceTable<I> { + pub fn relate<T>( + &mut self, + interner: I, + db: &dyn UnificationDatabase<I>, + environment: &Environment<I>, + variance: Variance, + a: &T, + b: &T, + ) -> Fallible<RelationResult<I>> + where + T: ?Sized + Zip<I>, + { + let snapshot = self.snapshot(); + match Unifier::new(interner, db, self, environment).relate(variance, a, b) { + Ok(r) => { + self.commit(snapshot); + Ok(r) + } + Err(e) => { + self.rollback_to(snapshot); + Err(e) + } + } + } +} + +struct Unifier<'t, I: Interner> { + table: &'t mut InferenceTable<I>, + environment: &'t Environment<I>, + goals: Vec<InEnvironment<Goal<I>>>, + interner: I, + db: &'t dyn UnificationDatabase<I>, +} + +#[derive(Debug)] +pub struct RelationResult<I: Interner> { + pub goals: Vec<InEnvironment<Goal<I>>>, +} + +impl<'t, I: Interner> Unifier<'t, I> { + fn new( + interner: I, + db: &'t dyn UnificationDatabase<I>, + table: &'t mut InferenceTable<I>, + environment: &'t Environment<I>, + ) -> Self { + Unifier { + environment, + table, + goals: vec![], + interner, + db, + } + } + + /// The main entry point for the `Unifier` type and really the + /// only type meant to be called externally. Performs a + /// relation of `a` and `b` and returns the Unification Result. + #[instrument(level = "debug", skip(self))] + fn relate<T>(mut self, variance: Variance, a: &T, b: &T) -> Fallible<RelationResult<I>> + where + T: ?Sized + Zip<I>, + { + Zip::zip_with(&mut self, variance, a, b)?; + let interner = self.interner(); + let mut goals = self.goals; + let table = self.table; + // Sometimes we'll produce a lifetime outlives goal which we later solve by unification + // Technically, these *will* get canonicalized to the same bound var and so that will end up + // as a goal like `^0.0 <: ^0.0`, which is trivially true. But, we remove those *here*, which + // might help caching. + goals.retain(|g| match g.goal.data(interner) { + GoalData::SubtypeGoal(SubtypeGoal { a, b }) => { + let n_a = table.ty_root(interner, a); + let n_b = table.ty_root(interner, b); + let a = n_a.as_ref().unwrap_or(a); + let b = n_b.as_ref().unwrap_or(b); + a != b + } + _ => true, + }); + Ok(RelationResult { goals }) + } + + /// Relate `a`, `b` with the variance such that if `variance = Covariant`, `a` is + /// a subtype of `b`. + fn relate_ty_ty(&mut self, variance: Variance, a: &Ty<I>, b: &Ty<I>) -> Fallible<()> { + let interner = self.interner; + + let n_a = self.table.normalize_ty_shallow(interner, a); + let n_b = self.table.normalize_ty_shallow(interner, b); + let a = n_a.as_ref().unwrap_or(a); + let b = n_b.as_ref().unwrap_or(b); + + debug_span!("relate_ty_ty", ?variance, ?a, ?b); + + if a.kind(interner) == b.kind(interner) { + return Ok(()); + } + + match (a.kind(interner), b.kind(interner)) { + // Relating two inference variables: + // First, if either variable is a float or int kind, then we always + // unify if they match. This is because float and ints don't have + // subtype relationships. + // If both kinds are general then: + // If `Invariant`, unify them in the underlying ena table. + // If `Covariant` or `Contravariant`, push `SubtypeGoal` + (&TyKind::InferenceVar(var1, kind1), &TyKind::InferenceVar(var2, kind2)) => { + if matches!(kind1, TyVariableKind::General) + && matches!(kind2, TyVariableKind::General) + { + // Both variable kinds are general; so unify if invariant, otherwise push subtype goal + match variance { + Variance::Invariant => self.unify_var_var(var1, var2), + Variance::Covariant => { + self.push_subtype_goal(a.clone(), b.clone()); + Ok(()) + } + Variance::Contravariant => { + self.push_subtype_goal(b.clone(), a.clone()); + Ok(()) + } + } + } else if kind1 == kind2 { + // At least one kind is not general, but they match, so unify + self.unify_var_var(var1, var2) + } else if kind1 == TyVariableKind::General { + // First kind is general, second isn't, unify + self.unify_general_var_specific_ty(var1, b.clone()) + } else if kind2 == TyVariableKind::General { + // Second kind is general, first isn't, unify + self.unify_general_var_specific_ty(var2, a.clone()) + } else { + debug!( + "Tried to unify mis-matching inference variables: {:?} and {:?}", + kind1, kind2 + ); + Err(NoSolution) + } + } + + // Unifying `forall<X> { T }` with some other forall type `forall<X> { U }` + (&TyKind::Function(ref fn1), &TyKind::Function(ref fn2)) => { + if fn1.sig == fn2.sig { + Zip::zip_with( + self, + variance, + &fn1.clone().into_binders(interner), + &fn2.clone().into_binders(interner), + ) + } else { + Err(NoSolution) + } + } + + (&TyKind::Placeholder(ref p1), &TyKind::Placeholder(ref p2)) => { + Zip::zip_with(self, variance, p1, p2) + } + + // Unifying two dyn is possible if they have the same bounds. + (&TyKind::Dyn(ref qwc1), &TyKind::Dyn(ref qwc2)) => { + Zip::zip_with(self, variance, qwc1, qwc2) + } + + (TyKind::BoundVar(_), _) | (_, TyKind::BoundVar(_)) => panic!( + "unification encountered bound variable: a={:?} b={:?}", + a, b + ), + + // Unifying an alias type with some other type `U`. + (_, &TyKind::Alias(ref alias)) => self.relate_alias_ty(variance.invert(), alias, a), + (&TyKind::Alias(ref alias), _) => self.relate_alias_ty(variance, alias, b), + + (&TyKind::InferenceVar(var, kind), ty_data) => { + let ty = ty_data.clone().intern(interner); + self.relate_var_ty(variance, var, kind, &ty) + } + (ty_data, &TyKind::InferenceVar(var, kind)) => { + // We need to invert the variance if inference var is `b` because we pass it in + // as `a` to relate_var_ty + let ty = ty_data.clone().intern(interner); + self.relate_var_ty(variance.invert(), var, kind, &ty) + } + + // This would correspond to unifying a `fn` type with a non-fn + // type in Rust; error. + (&TyKind::Function(_), _) | (_, &TyKind::Function(_)) => Err(NoSolution), + + // Cannot unify (e.g.) some struct type `Foo` and a placeholder like `T` + (_, &TyKind::Placeholder(_)) | (&TyKind::Placeholder(_), _) => Err(NoSolution), + + // Cannot unify `dyn Trait` with things like structs or placeholders + (_, &TyKind::Dyn(_)) | (&TyKind::Dyn(_), _) => Err(NoSolution), + + (TyKind::Adt(id_a, substitution_a), TyKind::Adt(id_b, substitution_b)) => { + if id_a != id_b { + return Err(NoSolution); + } + self.zip_substs( + variance, + Some(self.unification_database().adt_variance(*id_a)), + substitution_a.as_slice(interner), + substitution_b.as_slice(interner), + ) + } + ( + TyKind::AssociatedType(id_a, substitution_a), + TyKind::AssociatedType(id_b, substitution_b), + ) => { + if id_a != id_b { + return Err(NoSolution); + } + self.zip_substs( + variance, + None, // TODO: AssociatedType variances? + substitution_a.as_slice(interner), + substitution_b.as_slice(interner), + ) + } + (TyKind::Scalar(scalar_a), TyKind::Scalar(scalar_b)) => { + Zip::zip_with(self, variance, scalar_a, scalar_b) + } + (TyKind::Str, TyKind::Str) => Ok(()), + (TyKind::Tuple(arity_a, substitution_a), TyKind::Tuple(arity_b, substitution_b)) => { + if arity_a != arity_b { + return Err(NoSolution); + } + self.zip_substs( + variance, + Some(Variances::from_iter( + self.interner, + std::iter::repeat(Variance::Covariant).take(*arity_a), + )), + substitution_a.as_slice(interner), + substitution_b.as_slice(interner), + ) + } + ( + TyKind::OpaqueType(id_a, substitution_a), + TyKind::OpaqueType(id_b, substitution_b), + ) => { + if id_a != id_b { + return Err(NoSolution); + } + self.zip_substs( + variance, + None, + substitution_a.as_slice(interner), + substitution_b.as_slice(interner), + ) + } + (TyKind::Slice(ty_a), TyKind::Slice(ty_b)) => Zip::zip_with(self, variance, ty_a, ty_b), + (TyKind::FnDef(id_a, substitution_a), TyKind::FnDef(id_b, substitution_b)) => { + if id_a != id_b { + return Err(NoSolution); + } + self.zip_substs( + variance, + Some(self.unification_database().fn_def_variance(*id_a)), + substitution_a.as_slice(interner), + substitution_b.as_slice(interner), + ) + } + ( + TyKind::Ref(mutability_a, lifetime_a, ty_a), + TyKind::Ref(mutability_b, lifetime_b, ty_b), + ) => { + if mutability_a != mutability_b { + return Err(NoSolution); + } + // The lifetime is `Contravariant` + Zip::zip_with( + self, + variance.xform(Variance::Contravariant), + lifetime_a, + lifetime_b, + )?; + // The type is `Covariant` when not mut, `Invariant` otherwise + let output_variance = match mutability_a { + Mutability::Not => Variance::Covariant, + Mutability::Mut => Variance::Invariant, + }; + Zip::zip_with(self, variance.xform(output_variance), ty_a, ty_b) + } + (TyKind::Raw(mutability_a, ty_a), TyKind::Raw(mutability_b, ty_b)) => { + if mutability_a != mutability_b { + return Err(NoSolution); + } + let ty_variance = match mutability_a { + Mutability::Not => Variance::Covariant, + Mutability::Mut => Variance::Invariant, + }; + Zip::zip_with(self, variance.xform(ty_variance), ty_a, ty_b) + } + (TyKind::Never, TyKind::Never) => Ok(()), + (TyKind::Array(ty_a, const_a), TyKind::Array(ty_b, const_b)) => { + Zip::zip_with(self, variance, ty_a, ty_b)?; + Zip::zip_with(self, variance, const_a, const_b) + } + (TyKind::Closure(id_a, substitution_a), TyKind::Closure(id_b, substitution_b)) => { + if id_a != id_b { + return Err(NoSolution); + } + self.zip_substs( + variance, + None, + substitution_a.as_slice(interner), + substitution_b.as_slice(interner), + ) + } + (TyKind::Generator(id_a, substitution_a), TyKind::Generator(id_b, substitution_b)) => { + if id_a != id_b { + return Err(NoSolution); + } + self.zip_substs( + variance, + None, + substitution_a.as_slice(interner), + substitution_b.as_slice(interner), + ) + } + ( + TyKind::GeneratorWitness(id_a, substitution_a), + TyKind::GeneratorWitness(id_b, substitution_b), + ) => { + if id_a != id_b { + return Err(NoSolution); + } + self.zip_substs( + variance, + None, + substitution_a.as_slice(interner), + substitution_b.as_slice(interner), + ) + } + (TyKind::Foreign(id_a), TyKind::Foreign(id_b)) => { + Zip::zip_with(self, variance, id_a, id_b) + } + (TyKind::Error, TyKind::Error) => Ok(()), + + (_, _) => Err(NoSolution), + } + } + + /// Unify two inference variables + #[instrument(level = "debug", skip(self))] + fn unify_var_var(&mut self, a: InferenceVar, b: InferenceVar) -> Fallible<()> { + let var1 = EnaVariable::from(a); + let var2 = EnaVariable::from(b); + self.table + .unify + .unify_var_var(var1, var2) + .expect("unification of two unbound variables cannot fail"); + Ok(()) + } + + /// Unify a general inference variable with a specific inference variable + /// (type kind is not `General`). For example, unify a `TyVariableKind::General` + /// inference variable with a `TyVariableKind::Integer` variable, resulting in the + /// general inference variable narrowing to an integer variable. + + #[instrument(level = "debug", skip(self))] + fn unify_general_var_specific_ty( + &mut self, + general_var: InferenceVar, + specific_ty: Ty<I>, + ) -> Fallible<()> { + self.table + .unify + .unify_var_value( + general_var, + InferenceValue::from_ty(self.interner, specific_ty), + ) + .unwrap(); + + Ok(()) + } + + #[instrument(level = "debug", skip(self))] + fn relate_binders<'a, T>( + &mut self, + variance: Variance, + a: &Binders<T>, + b: &Binders<T>, + ) -> Fallible<()> + where + T: Clone + TypeFoldable<I> + HasInterner<Interner = I> + Zip<I>, + 't: 'a, + { + // for<'a...> T == for<'b...> U + // + // if: + // + // for<'a...> exists<'b...> T == U && + // for<'b...> exists<'a...> T == U + + // for<'a...> T <: for<'b...> U + // + // if + // + // for<'b...> exists<'a...> T <: U + + let interner = self.interner; + + if let Variance::Invariant | Variance::Contravariant = variance { + let a_universal = self + .table + .instantiate_binders_universally(interner, a.clone()); + let b_existential = self + .table + .instantiate_binders_existentially(interner, b.clone()); + Zip::zip_with(self, Variance::Contravariant, &a_universal, &b_existential)?; + } + + if let Variance::Invariant | Variance::Covariant = variance { + let b_universal = self + .table + .instantiate_binders_universally(interner, b.clone()); + let a_existential = self + .table + .instantiate_binders_existentially(interner, a.clone()); + Zip::zip_with(self, Variance::Covariant, &a_existential, &b_universal)?; + } + + Ok(()) + } + + /// Relate an alias like `<T as Trait>::Item` or `impl Trait` with some other + /// type `ty`. If the variance is `Invariant`, creates a goal like + /// + /// ```notrust + /// AliasEq(<T as Trait>::Item = U) // associated type projection + /// AliasEq(impl Trait = U) // impl trait + /// ``` + /// Otherwise, this creates a new variable `?X`, creates a goal like + /// ```notrust + /// AliasEq(Alias = ?X) + /// ``` + /// and relates `?X` and `ty`. + #[instrument(level = "debug", skip(self))] + fn relate_alias_ty( + &mut self, + variance: Variance, + alias: &AliasTy<I>, + ty: &Ty<I>, + ) -> Fallible<()> { + let interner = self.interner; + match variance { + Variance::Invariant => { + self.goals.push(InEnvironment::new( + self.environment, + AliasEq { + alias: alias.clone(), + ty: ty.clone(), + } + .cast(interner), + )); + Ok(()) + } + Variance::Covariant | Variance::Contravariant => { + let var = self + .table + .new_variable(UniverseIndex::root()) + .to_ty(interner); + self.goals.push(InEnvironment::new( + self.environment, + AliasEq { + alias: alias.clone(), + ty: var.clone(), + } + .cast(interner), + )); + self.relate_ty_ty(variance, &var, ty) + } + } + } + + #[instrument(level = "debug", skip(self))] + fn generalize_ty( + &mut self, + ty: &Ty<I>, + universe_index: UniverseIndex, + variance: Variance, + ) -> Ty<I> { + let interner = self.interner; + match ty.kind(interner) { + TyKind::Adt(id, substitution) => { + let variances = if matches!(variance, Variance::Invariant) { + None + } else { + Some(self.unification_database().adt_variance(*id)) + }; + let get_variance = |i| { + variances + .as_ref() + .map(|v| v.as_slice(interner)[i]) + .unwrap_or(Variance::Invariant) + }; + TyKind::Adt( + *id, + self.generalize_substitution(substitution, universe_index, get_variance), + ) + .intern(interner) + } + TyKind::AssociatedType(id, substitution) => TyKind::AssociatedType( + *id, + self.generalize_substitution(substitution, universe_index, |_| variance), + ) + .intern(interner), + TyKind::Scalar(scalar) => TyKind::Scalar(*scalar).intern(interner), + TyKind::Str => TyKind::Str.intern(interner), + TyKind::Tuple(arity, substitution) => TyKind::Tuple( + *arity, + self.generalize_substitution(substitution, universe_index, |_| variance), + ) + .intern(interner), + TyKind::OpaqueType(id, substitution) => TyKind::OpaqueType( + *id, + self.generalize_substitution(substitution, universe_index, |_| variance), + ) + .intern(interner), + TyKind::Slice(ty) => { + TyKind::Slice(self.generalize_ty(ty, universe_index, variance)).intern(interner) + } + TyKind::FnDef(id, substitution) => { + let variances = if matches!(variance, Variance::Invariant) { + None + } else { + Some(self.unification_database().fn_def_variance(*id)) + }; + let get_variance = |i| { + variances + .as_ref() + .map(|v| v.as_slice(interner)[i]) + .unwrap_or(Variance::Invariant) + }; + TyKind::FnDef( + *id, + self.generalize_substitution(substitution, universe_index, get_variance), + ) + .intern(interner) + } + TyKind::Ref(mutability, lifetime, ty) => { + let lifetime_variance = variance.xform(Variance::Contravariant); + let ty_variance = match mutability { + Mutability::Not => Variance::Covariant, + Mutability::Mut => Variance::Invariant, + }; + TyKind::Ref( + *mutability, + self.generalize_lifetime(lifetime, universe_index, lifetime_variance), + self.generalize_ty(ty, universe_index, ty_variance), + ) + .intern(interner) + } + TyKind::Raw(mutability, ty) => { + let ty_variance = match mutability { + Mutability::Not => Variance::Covariant, + Mutability::Mut => Variance::Invariant, + }; + TyKind::Raw( + *mutability, + self.generalize_ty(ty, universe_index, ty_variance), + ) + .intern(interner) + } + TyKind::Never => TyKind::Never.intern(interner), + TyKind::Array(ty, const_) => TyKind::Array( + self.generalize_ty(ty, universe_index, variance), + self.generalize_const(const_, universe_index), + ) + .intern(interner), + TyKind::Closure(id, substitution) => TyKind::Closure( + *id, + self.generalize_substitution(substitution, universe_index, |_| variance), + ) + .intern(interner), + TyKind::Generator(id, substitution) => TyKind::Generator( + *id, + self.generalize_substitution(substitution, universe_index, |_| variance), + ) + .intern(interner), + TyKind::GeneratorWitness(id, substitution) => TyKind::GeneratorWitness( + *id, + self.generalize_substitution(substitution, universe_index, |_| variance), + ) + .intern(interner), + TyKind::Foreign(id) => TyKind::Foreign(*id).intern(interner), + TyKind::Error => TyKind::Error.intern(interner), + TyKind::Dyn(dyn_ty) => { + let DynTy { bounds, lifetime } = dyn_ty; + let lifetime = self.generalize_lifetime( + lifetime, + universe_index, + variance.xform(Variance::Contravariant), + ); + + let bounds = bounds.map_ref(|value| { + let iter = value.iter(interner).map(|sub_var| { + sub_var.map_ref(|clause| { + match clause { + WhereClause::Implemented(trait_ref) => { + let TraitRef { + ref substitution, + trait_id, + } = *trait_ref; + let substitution = self.generalize_substitution_skip_self( + substitution, + universe_index, + |_| Some(variance), + ); + WhereClause::Implemented(TraitRef { + substitution, + trait_id, + }) + } + WhereClause::AliasEq(alias_eq) => { + let AliasEq { alias, ty: _ } = alias_eq; + let alias = match alias { + AliasTy::Opaque(opaque_ty) => { + let OpaqueTy { + ref substitution, + opaque_ty_id, + } = *opaque_ty; + let substitution = self.generalize_substitution( + substitution, + universe_index, + |_| variance, + ); + AliasTy::Opaque(OpaqueTy { + substitution, + opaque_ty_id, + }) + } + AliasTy::Projection(projection_ty) => { + let ProjectionTy { + ref substitution, + associated_ty_id, + } = *projection_ty; + // TODO: We should be skipping "self", which + // would be the first element of + // "trait_params" if we had a + // `RustIrDatabase` to call + // `split_projection` on... + // let (assoc_ty_datum, trait_params, assoc_type_params) = s.db().split_projection(&self); + let substitution = self.generalize_substitution( + substitution, + universe_index, + |_| variance, + ); + AliasTy::Projection(ProjectionTy { + substitution, + associated_ty_id, + }) + } + }; + let ty = + self.table.new_variable(universe_index).to_ty(interner); + WhereClause::AliasEq(AliasEq { alias, ty }) + } + WhereClause::TypeOutlives(_) => { + let lifetime_var = self.table.new_variable(universe_index); + let lifetime = lifetime_var.to_lifetime(interner); + let ty_var = self.table.new_variable(universe_index); + let ty = ty_var.to_ty(interner); + WhereClause::TypeOutlives(TypeOutlives { ty, lifetime }) + } + WhereClause::LifetimeOutlives(_) => { + unreachable!("dyn Trait never contains LifetimeOutlive bounds") + } + } + }) + }); + QuantifiedWhereClauses::from_iter(interner, iter) + }); + + TyKind::Dyn(DynTy { bounds, lifetime }).intern(interner) + } + TyKind::Function(fn_ptr) => { + let FnPointer { + num_binders, + sig, + ref substitution, + } = *fn_ptr; + + let len = substitution.0.len(interner); + let vars = substitution.0.iter(interner).enumerate().map(|(i, var)| { + if i < len - 1 { + self.generalize_generic_var( + var, + universe_index, + variance.xform(Variance::Contravariant), + ) + } else { + self.generalize_generic_var( + substitution.0.as_slice(interner).last().unwrap(), + universe_index, + variance, + ) + } + }); + + let substitution = FnSubst(Substitution::from_iter(interner, vars)); + + TyKind::Function(FnPointer { + num_binders, + sig, + substitution, + }) + .intern(interner) + } + TyKind::Placeholder(_) | TyKind::BoundVar(_) => { + debug!("just generalizing to the ty itself: {:?}", ty); + // BoundVar and PlaceHolder have no internal values to be + // generic over, so we just relate directly to it + ty.clone() + } + TyKind::Alias(_) => { + let ena_var = self.table.new_variable(universe_index); + ena_var.to_ty(interner) + } + TyKind::InferenceVar(_var, kind) => { + if matches!(kind, TyVariableKind::Integer | TyVariableKind::Float) { + ty.clone() + } else if let Some(ty) = self.table.normalize_ty_shallow(interner, ty) { + self.generalize_ty(&ty, universe_index, variance) + } else if matches!(variance, Variance::Invariant) { + ty.clone() + } else { + let ena_var = self.table.new_variable(universe_index); + ena_var.to_ty(interner) + } + } + } + } + + #[instrument(level = "debug", skip(self))] + fn generalize_lifetime( + &mut self, + lifetime: &Lifetime<I>, + universe_index: UniverseIndex, + variance: Variance, + ) -> Lifetime<I> { + if matches!(lifetime.data(self.interner), LifetimeData::BoundVar(_)) + || matches!(variance, Variance::Invariant) + { + lifetime.clone() + } else { + self.table + .new_variable(universe_index) + .to_lifetime(self.interner) + } + } + + #[instrument(level = "debug", skip(self))] + fn generalize_const(&mut self, const_: &Const<I>, universe_index: UniverseIndex) -> Const<I> { + let data = const_.data(self.interner); + if matches!(data.value, ConstValue::BoundVar(_)) { + const_.clone() + } else { + self.table + .new_variable(universe_index) + .to_const(self.interner, data.ty.clone()) + } + } + + fn generalize_generic_var( + &mut self, + sub_var: &GenericArg<I>, + universe_index: UniverseIndex, + variance: Variance, + ) -> GenericArg<I> { + let interner = self.interner; + (match sub_var.data(interner) { + GenericArgData::Ty(ty) => { + GenericArgData::Ty(self.generalize_ty(ty, universe_index, variance)) + } + GenericArgData::Lifetime(lifetime) => GenericArgData::Lifetime( + self.generalize_lifetime(lifetime, universe_index, variance), + ), + GenericArgData::Const(const_value) => { + GenericArgData::Const(self.generalize_const(const_value, universe_index)) + } + }) + .intern(interner) + } + + /// Generalizes all but the first + #[instrument(level = "debug", skip(self, get_variance))] + fn generalize_substitution_skip_self<F: Fn(usize) -> Option<Variance>>( + &mut self, + substitution: &Substitution<I>, + universe_index: UniverseIndex, + get_variance: F, + ) -> Substitution<I> { + let interner = self.interner; + let vars = substitution.iter(interner).enumerate().map(|(i, sub_var)| { + if i == 0 { + sub_var.clone() + } else { + let variance = get_variance(i).unwrap_or(Variance::Invariant); + self.generalize_generic_var(sub_var, universe_index, variance) + } + }); + Substitution::from_iter(interner, vars) + } + + #[instrument(level = "debug", skip(self, get_variance))] + fn generalize_substitution<F: Fn(usize) -> Variance>( + &mut self, + substitution: &Substitution<I>, + universe_index: UniverseIndex, + get_variance: F, + ) -> Substitution<I> { + let interner = self.interner; + let vars = substitution.iter(interner).enumerate().map(|(i, sub_var)| { + let variance = get_variance(i); + self.generalize_generic_var(sub_var, universe_index, variance) + }); + + Substitution::from_iter(interner, vars) + } + + /// Unify an inference variable `var` with some non-inference + /// variable `ty`, just bind `var` to `ty`. But we must enforce two conditions: + /// + /// - `var` does not appear inside of `ty` (the standard `OccursCheck`) + /// - `ty` does not reference anything in a lifetime that could not be named in `var` + /// (the extended `OccursCheck` created to handle universes) + #[instrument(level = "debug", skip(self))] + fn relate_var_ty( + &mut self, + variance: Variance, + var: InferenceVar, + var_kind: TyVariableKind, + ty: &Ty<I>, + ) -> Fallible<()> { + let interner = self.interner; + + match (var_kind, ty.is_integer(interner), ty.is_float(interner)) { + // General inference variables can unify with any type + (TyVariableKind::General, _, _) + // Integer inference variables can only unify with integer types + | (TyVariableKind::Integer, true, _) + // Float inference variables can only unify with float types + | (TyVariableKind::Float, _, true) => { + }, + _ => return Err(NoSolution), + } + + let var = EnaVariable::from(var); + + // Determine the universe index associated with this + // variable. This is basically a count of the number of + // `forall` binders that had been introduced at the point + // this variable was created -- though it may change over time + // as the variable is unified. + let universe_index = self.table.universe_of_unbound_var(var); + // let universe_index = self.table.max_universe(); + + debug!("relate_var_ty: universe index of var: {:?}", universe_index); + + debug!("trying fold_with on {:?}", ty); + let ty1 = ty + .clone() + .try_fold_with( + &mut OccursCheck::new(self, var, universe_index), + DebruijnIndex::INNERMOST, + ) + .map_err(|e| { + debug!("failed to fold {:?}", ty); + e + })?; + + // "Generalize" types. This ensures that we aren't accidentally forcing + // too much onto `var`. Instead of directly setting `var` equal to `ty`, + // we just take the outermost structure we _know_ `var` holds, and then + // apply that to `ty`. This involves creating new inference vars for + // everything inside `var`, then calling `relate_ty_ty` to relate those + // inference vars to the things they generalized with the correct + // variance. + + // The main problem this solves is that lifetime relationships are + // relationships, not just eq ones. So when solving &'a u32 <: U, + // generalizing we would end up with U = &'a u32. Instead, we want + // U = &'b u32, with a lifetime constraint 'a <: 'b. This matters + // especially when solving multiple constraints - for example, &'a u32 + // <: U, &'b u32 <: U (where without generalizing, we'd end up with 'a + // <: 'b, where we really want 'a <: 'c, 'b <: 'c for some 'c). + + // Example operation: consider `ty` as `&'x SomeType`. To generalize + // this, we create two new vars `'0` and `1`. Then we relate `var` with + // `&'0 1` and `&'0 1` with `&'x SomeType`. The second relation will + // recurse, and we'll end up relating `'0` with `'x` and `1` with `SomeType`. + let generalized_val = self.generalize_ty(&ty1, universe_index, variance); + + debug!("var {:?} generalized to {:?}", var, generalized_val); + + self.table + .unify + .unify_var_value( + var, + InferenceValue::from_ty(interner, generalized_val.clone()), + ) + .unwrap(); + debug!("var {:?} set to {:?}", var, generalized_val); + + self.relate_ty_ty(variance, &generalized_val, &ty1)?; + + debug!( + "generalized version {:?} related to original {:?}", + generalized_val, ty1 + ); + + Ok(()) + } + + fn relate_lifetime_lifetime( + &mut self, + variance: Variance, + a: &Lifetime<I>, + b: &Lifetime<I>, + ) -> Fallible<()> { + let interner = self.interner; + + let n_a = self.table.normalize_lifetime_shallow(interner, a); + let n_b = self.table.normalize_lifetime_shallow(interner, b); + let a = n_a.as_ref().unwrap_or(a); + let b = n_b.as_ref().unwrap_or(b); + + debug_span!("relate_lifetime_lifetime", ?variance, ?a, ?b); + + match (a.data(interner), b.data(interner)) { + (&LifetimeData::InferenceVar(var_a), &LifetimeData::InferenceVar(var_b)) => { + let var_a = EnaVariable::from(var_a); + let var_b = EnaVariable::from(var_b); + debug!(?var_a, ?var_b); + self.table.unify.unify_var_var(var_a, var_b).unwrap(); + Ok(()) + } + + ( + &LifetimeData::InferenceVar(a_var), + &LifetimeData::Placeholder(PlaceholderIndex { ui, .. }), + ) => self.unify_lifetime_var(variance, a_var, b, ui), + + ( + &LifetimeData::Placeholder(PlaceholderIndex { ui, .. }), + &LifetimeData::InferenceVar(b_var), + ) => self.unify_lifetime_var(variance.invert(), b_var, a, ui), + + (&LifetimeData::InferenceVar(a_var), &LifetimeData::Erased) + | (&LifetimeData::InferenceVar(a_var), &LifetimeData::Static) => { + self.unify_lifetime_var(variance, a_var, b, UniverseIndex::root()) + } + + (&LifetimeData::Erased, &LifetimeData::InferenceVar(b_var)) + | (&LifetimeData::Static, &LifetimeData::InferenceVar(b_var)) => { + self.unify_lifetime_var(variance.invert(), b_var, a, UniverseIndex::root()) + } + + (&LifetimeData::Static, &LifetimeData::Static) + | (&LifetimeData::Erased, &LifetimeData::Erased) => Ok(()), + + (&LifetimeData::Static, &LifetimeData::Placeholder(_)) + | (&LifetimeData::Static, &LifetimeData::Erased) + | (&LifetimeData::Placeholder(_), &LifetimeData::Static) + | (&LifetimeData::Placeholder(_), &LifetimeData::Placeholder(_)) + | (&LifetimeData::Placeholder(_), &LifetimeData::Erased) + | (&LifetimeData::Erased, &LifetimeData::Static) + | (&LifetimeData::Erased, &LifetimeData::Placeholder(_)) => { + if a != b { + self.push_lifetime_outlives_goals(variance, a.clone(), b.clone()); + Ok(()) + } else { + Ok(()) + } + } + + (LifetimeData::BoundVar(_), _) | (_, LifetimeData::BoundVar(_)) => panic!( + "unification encountered bound variable: a={:?} b={:?}", + a, b + ), + + (LifetimeData::Phantom(..), _) | (_, LifetimeData::Phantom(..)) => unreachable!(), + } + } + + #[instrument(level = "debug", skip(self))] + fn unify_lifetime_var( + &mut self, + variance: Variance, + var: InferenceVar, + value: &Lifetime<I>, + value_ui: UniverseIndex, + ) -> Fallible<()> { + let var = EnaVariable::from(var); + let var_ui = self.table.universe_of_unbound_var(var); + if var_ui.can_see(value_ui) && matches!(variance, Variance::Invariant) { + debug!("{:?} in {:?} can see {:?}; unifying", var, var_ui, value_ui); + self.table + .unify + .unify_var_value( + var, + InferenceValue::from_lifetime(self.interner, value.clone()), + ) + .unwrap(); + Ok(()) + } else { + debug!( + "{:?} in {:?} cannot see {:?}; pushing constraint", + var, var_ui, value_ui + ); + self.push_lifetime_outlives_goals( + variance, + var.to_lifetime(self.interner), + value.clone(), + ); + Ok(()) + } + } + + fn relate_const_const<'a>( + &mut self, + variance: Variance, + a: &'a Const<I>, + b: &'a Const<I>, + ) -> Fallible<()> { + let interner = self.interner; + + let n_a = self.table.normalize_const_shallow(interner, a); + let n_b = self.table.normalize_const_shallow(interner, b); + let a = n_a.as_ref().unwrap_or(a); + let b = n_b.as_ref().unwrap_or(b); + + debug_span!("relate_const_const", ?variance, ?a, ?b); + + let ConstData { + ty: a_ty, + value: a_val, + } = a.data(interner); + let ConstData { + ty: b_ty, + value: b_val, + } = b.data(interner); + + self.relate_ty_ty(variance, a_ty, b_ty)?; + + match (a_val, b_val) { + // Unifying two inference variables: unify them in the underlying + // ena table. + (&ConstValue::InferenceVar(var1), &ConstValue::InferenceVar(var2)) => { + debug!(?var1, ?var2, "relate_ty_ty"); + let var1 = EnaVariable::from(var1); + let var2 = EnaVariable::from(var2); + self.table + .unify + .unify_var_var(var1, var2) + .expect("unification of two unbound variables cannot fail"); + Ok(()) + } + + // Unifying an inference variables with a non-inference variable. + (&ConstValue::InferenceVar(var), &ConstValue::Concrete(_)) + | (&ConstValue::InferenceVar(var), &ConstValue::Placeholder(_)) => { + debug!(?var, ty=?b, "unify_var_ty"); + self.unify_var_const(var, b) + } + + (&ConstValue::Concrete(_), &ConstValue::InferenceVar(var)) + | (&ConstValue::Placeholder(_), &ConstValue::InferenceVar(var)) => { + debug!(?var, ty=?a, "unify_var_ty"); + self.unify_var_const(var, a) + } + + (&ConstValue::Placeholder(p1), &ConstValue::Placeholder(p2)) => { + Zip::zip_with(self, variance, &p1, &p2) + } + + (&ConstValue::Concrete(ref ev1), &ConstValue::Concrete(ref ev2)) => { + if ev1.const_eq(a_ty, ev2, interner) { + Ok(()) + } else { + Err(NoSolution) + } + } + + (&ConstValue::Concrete(_), &ConstValue::Placeholder(_)) + | (&ConstValue::Placeholder(_), &ConstValue::Concrete(_)) => Err(NoSolution), + + (ConstValue::BoundVar(_), _) | (_, ConstValue::BoundVar(_)) => panic!( + "unification encountered bound variable: a={:?} b={:?}", + a, b + ), + } + } + + #[instrument(level = "debug", skip(self))] + fn unify_var_const(&mut self, var: InferenceVar, c: &Const<I>) -> Fallible<()> { + let interner = self.interner; + let var = EnaVariable::from(var); + + // Determine the universe index associated with this + // variable. This is basically a count of the number of + // `forall` binders that had been introduced at the point + // this variable was created -- though it may change over time + // as the variable is unified. + let universe_index = self.table.universe_of_unbound_var(var); + + let c1 = c.clone().try_fold_with( + &mut OccursCheck::new(self, var, universe_index), + DebruijnIndex::INNERMOST, + )?; + + debug!("unify_var_const: var {:?} set to {:?}", var, c1); + self.table + .unify + .unify_var_value(var, InferenceValue::from_const(interner, c1)) + .unwrap(); + + Ok(()) + } + + /// Relate `a`, `b` such that if `variance = Covariant`, `a` is a subtype of + /// `b` and thus `a` must outlive `b`. + fn push_lifetime_outlives_goals(&mut self, variance: Variance, a: Lifetime<I>, b: Lifetime<I>) { + debug!( + "pushing lifetime outlives goals for a={:?} b={:?} with variance {:?}", + a, b, variance + ); + if matches!(variance, Variance::Invariant | Variance::Contravariant) { + self.goals.push(InEnvironment::new( + self.environment, + WhereClause::LifetimeOutlives(LifetimeOutlives { + a: a.clone(), + b: b.clone(), + }) + .cast(self.interner), + )); + } + if matches!(variance, Variance::Invariant | Variance::Covariant) { + self.goals.push(InEnvironment::new( + self.environment, + WhereClause::LifetimeOutlives(LifetimeOutlives { a: b, b: a }).cast(self.interner), + )); + } + } + + /// Pushes a goal of `a` being a subtype of `b`. + fn push_subtype_goal(&mut self, a: Ty<I>, b: Ty<I>) { + let subtype_goal = GoalData::SubtypeGoal(SubtypeGoal { a, b }).intern(self.interner()); + self.goals + .push(InEnvironment::new(self.environment, subtype_goal)); + } +} + +impl<'i, I: Interner> Zipper<I> for Unifier<'i, I> { + fn zip_tys(&mut self, variance: Variance, a: &Ty<I>, b: &Ty<I>) -> Fallible<()> { + debug!("zip_tys {:?}, {:?}, {:?}", variance, a, b); + self.relate_ty_ty(variance, a, b) + } + + fn zip_lifetimes( + &mut self, + variance: Variance, + a: &Lifetime<I>, + b: &Lifetime<I>, + ) -> Fallible<()> { + self.relate_lifetime_lifetime(variance, a, b) + } + + fn zip_consts(&mut self, variance: Variance, a: &Const<I>, b: &Const<I>) -> Fallible<()> { + self.relate_const_const(variance, a, b) + } + + fn zip_binders<T>(&mut self, variance: Variance, a: &Binders<T>, b: &Binders<T>) -> Fallible<()> + where + T: Clone + HasInterner<Interner = I> + Zip<I> + TypeFoldable<I>, + { + // The binders that appear in types (apart from quantified types, which are + // handled in `unify_ty`) appear as part of `dyn Trait` and `impl Trait` types. + // + // They come in two varieties: + // + // * The existential binder from `dyn Trait` / `impl Trait` + // (representing the hidden "self" type) + // * The `for<..>` binders from higher-ranked traits. + // + // In both cases we can use the same `relate_binders` routine. + + self.relate_binders(variance, a, b) + } + + fn interner(&self) -> I { + self.interner + } + + fn unification_database(&self) -> &dyn UnificationDatabase<I> { + self.db + } +} + +struct OccursCheck<'u, 't, I: Interner> { + unifier: &'u mut Unifier<'t, I>, + var: EnaVariable<I>, + universe_index: UniverseIndex, +} + +impl<'u, 't, I: Interner> OccursCheck<'u, 't, I> { + fn new( + unifier: &'u mut Unifier<'t, I>, + var: EnaVariable<I>, + universe_index: UniverseIndex, + ) -> Self { + OccursCheck { + unifier, + var, + universe_index, + } + } +} + +impl<'i, I: Interner> FallibleTypeFolder<I> for OccursCheck<'_, 'i, I> { + type Error = NoSolution; + + fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<I, Error = Self::Error> { + self + } + + fn try_fold_free_placeholder_ty( + &mut self, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Fallible<Ty<I>> { + let interner = self.interner(); + if self.universe_index < universe.ui { + debug!( + "OccursCheck aborting because self.universe_index ({:?}) < universe.ui ({:?})", + self.universe_index, universe.ui + ); + Err(NoSolution) + } else { + Ok(universe.to_ty(interner)) // no need to shift, not relative to depth + } + } + + fn try_fold_free_placeholder_const( + &mut self, + ty: Ty<I>, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Fallible<Const<I>> { + let interner = self.interner(); + if self.universe_index < universe.ui { + Err(NoSolution) + } else { + Ok(universe.to_const(interner, ty)) // no need to shift, not relative to depth + } + } + + #[instrument(level = "debug", skip(self))] + fn try_fold_free_placeholder_lifetime( + &mut self, + ui: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Fallible<Lifetime<I>> { + let interner = self.interner(); + if self.universe_index < ui.ui { + // Scenario is like: + // + // exists<T> forall<'b> ?T = Foo<'b> + // + // unlike with a type variable, this **might** be + // ok. Ultimately it depends on whether the + // `forall` also introduced relations to lifetimes + // nameable in T. To handle that, we introduce a + // fresh region variable `'x` in same universe as `T` + // and add a side-constraint that `'x = 'b`: + // + // exists<'x> forall<'b> ?T = Foo<'x>, where 'x = 'b + + let tick_x = self.unifier.table.new_variable(self.universe_index); + self.unifier.push_lifetime_outlives_goals( + Variance::Invariant, + tick_x.to_lifetime(interner), + ui.to_lifetime(interner), + ); + Ok(tick_x.to_lifetime(interner)) + } else { + // If the `ui` is higher than `self.universe_index`, then we can name + // this lifetime, no problem. + Ok(ui.to_lifetime(interner)) // no need to shift, not relative to depth + } + } + + fn try_fold_inference_ty( + &mut self, + var: InferenceVar, + kind: TyVariableKind, + _outer_binder: DebruijnIndex, + ) -> Fallible<Ty<I>> { + let interner = self.interner(); + let var = EnaVariable::from(var); + match self.unifier.table.unify.probe_value(var) { + // If this variable already has a value, fold over that value instead. + InferenceValue::Bound(normalized_ty) => { + let normalized_ty = normalized_ty.assert_ty_ref(interner); + let normalized_ty = normalized_ty + .clone() + .try_fold_with(self, DebruijnIndex::INNERMOST)?; + assert!(!normalized_ty.needs_shift(interner)); + Ok(normalized_ty) + } + + // Otherwise, check the universe of the variable, and also + // check for cycles with `self.var` (which this will soon + // become the value of). + InferenceValue::Unbound(ui) => { + if self.unifier.table.unify.unioned(var, self.var) { + debug!( + "OccursCheck aborting because {:?} unioned with {:?}", + var, self.var, + ); + return Err(NoSolution); + } + + if self.universe_index < ui { + // Scenario is like: + // + // ?A = foo(?B) + // + // where ?A is in universe 0 and ?B is in universe 1. + // This is OK, if ?B is promoted to universe 0. + self.unifier + .table + .unify + .unify_var_value(var, InferenceValue::Unbound(self.universe_index)) + .unwrap(); + } + + Ok(var.to_ty_with_kind(interner, kind)) + } + } + } + + fn try_fold_inference_const( + &mut self, + ty: Ty<I>, + var: InferenceVar, + _outer_binder: DebruijnIndex, + ) -> Fallible<Const<I>> { + let interner = self.interner(); + let var = EnaVariable::from(var); + match self.unifier.table.unify.probe_value(var) { + // If this variable already has a value, fold over that value instead. + InferenceValue::Bound(normalized_const) => { + let normalized_const = normalized_const.assert_const_ref(interner); + let normalized_const = normalized_const + .clone() + .try_fold_with(self, DebruijnIndex::INNERMOST)?; + assert!(!normalized_const.needs_shift(interner)); + Ok(normalized_const) + } + + // Otherwise, check the universe of the variable, and also + // check for cycles with `self.var` (which this will soon + // become the value of). + InferenceValue::Unbound(ui) => { + if self.unifier.table.unify.unioned(var, self.var) { + return Err(NoSolution); + } + + if self.universe_index < ui { + // Scenario is like: + // + // forall<const A> exists<const B> ?C = Foo<B> + // + // where A is in universe 0 and B is in universe 1. + // This is OK, if B is promoted to universe 0. + self.unifier + .table + .unify + .unify_var_value(var, InferenceValue::Unbound(self.universe_index)) + .unwrap(); + } + + Ok(var.to_const(interner, ty)) + } + } + } + + fn try_fold_inference_lifetime( + &mut self, + var: InferenceVar, + outer_binder: DebruijnIndex, + ) -> Fallible<Lifetime<I>> { + // a free existentially bound region; find the + // inference variable it corresponds to + let interner = self.interner(); + let var = EnaVariable::from(var); + match self.unifier.table.unify.probe_value(var) { + InferenceValue::Unbound(ui) => { + if self.universe_index < ui { + // Scenario is like: + // + // exists<T> forall<'b> exists<'a> ?T = Foo<'a> + // + // where ?A is in universe 0 and `'b` is in universe 1. + // This is OK, if `'b` is promoted to universe 0. + self.unifier + .table + .unify + .unify_var_value(var, InferenceValue::Unbound(self.universe_index)) + .unwrap(); + } + Ok(var.to_lifetime(interner)) + } + + InferenceValue::Bound(l) => { + let l = l.assert_lifetime_ref(interner); + let l = l.clone().try_fold_with(self, outer_binder)?; + assert!(!l.needs_shift(interner)); + Ok(l) + } + } + } + + fn forbid_free_vars(&self) -> bool { + true + } + + fn interner(&self) -> I { + self.unifier.interner + } +} diff --git a/vendor/chalk-solve/src/infer/var.rs b/vendor/chalk-solve/src/infer/var.rs new file mode 100644 index 000000000..3fbf92002 --- /dev/null +++ b/vendor/chalk-solve/src/infer/var.rs @@ -0,0 +1,152 @@ +use chalk_ir::cast::Cast; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use ena::unify::{UnifyKey, UnifyValue}; +use std::cmp::min; +use std::fmt; +use std::marker::PhantomData; +use std::u32; + +/// Wrapper around `chalk_ir::InferenceVar` for coherence purposes. +/// An inference variable represents an unknown term -- either a type +/// or a lifetime. The variable itself is just an index into the +/// unification table; the unification table maps it to an +/// `InferenceValue`. +/// +/// Inference variables can be in one of two states (represents by the variants +/// of an `InferenceValue`): +/// +/// - Unbound(`ui`). In this case, the value of the variable is not yet known. We carry +/// along a universe index `ui` that tracks the universe in which the variable was +/// created; this determines what names may appear in the variable's value. +/// - In this state, we do **not** track the kind of this variable +/// (i.e., whether it represents a type or a lifetime). There is +/// no need: if it represents a lifetime, for example, then there +/// should only ever be constraints that relate it to other +/// lifetimes, or use it in lifetime position. +/// - Bound. In this case, the value of the variable is known. We +/// carry along the value. We discard the universe index in which +/// the variable was created, since that was only needed to help us +/// reject illegal values. Once the value of a variable is known, it +/// can never change. +/// - The value we actually store for variables is a +/// `ir::GenericArg`, and hence it does carry along the kind of the +/// variable via the enum variant. However, we should always know +/// the kind of the variable from context, and hence we typically +/// "downcast" the resulting variable using +/// e.g. `value.ty().unwrap()`. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct EnaVariable<I: Interner> { + var: InferenceVar, + phantom: PhantomData<I>, +} + +impl<I: Interner> From<InferenceVar> for EnaVariable<I> { + fn from(var: InferenceVar) -> EnaVariable<I> { + EnaVariable { + var, + phantom: PhantomData, + } + } +} + +impl<I: Interner> From<EnaVariable<I>> for InferenceVar { + fn from(ena_var: EnaVariable<I>) -> InferenceVar { + ena_var.var + } +} + +impl<I: Interner> EnaVariable<I> { + /// Convert this inference variable into a type. When using this + /// method, naturally you should know from context that the kind + /// of this inference variable is a type (we can't check it). + pub fn to_ty_with_kind(self, interner: I, kind: TyVariableKind) -> Ty<I> { + self.var.to_ty(interner, kind) + } + + /// Same as `to_ty_with_kind`, but the kind is set to `TyVariableKind::General`. + /// This should be used instead of `to_ty_with_kind` when creating a new + /// inference variable (when the kind is not known). + pub fn to_ty(self, interner: I) -> Ty<I> { + self.var.to_ty(interner, TyVariableKind::General) + } + + /// Convert this inference variable into a lifetime. When using this + /// method, naturally you should know from context that the kind + /// of this inference variable is a lifetime (we can't check it). + pub fn to_lifetime(self, interner: I) -> Lifetime<I> { + self.var.to_lifetime(interner) + } + + /// Convert this inference variable into a const. When using this + /// method, naturally you should know from context that the kind + /// of this inference variable is a const (we can't check it). + pub fn to_const(self, interner: I, ty: Ty<I>) -> Const<I> { + self.var.to_const(interner, ty) + } +} + +impl<I: Interner> UnifyKey for EnaVariable<I> { + type Value = InferenceValue<I>; + + fn index(&self) -> u32 { + self.var.index() + } + + fn from_index(u: u32) -> Self { + EnaVariable::from(InferenceVar::from(u)) + } + + fn tag() -> &'static str { + "EnaVariable" + } +} + +/// The value of an inference variable. We start out as `Unbound` with a +/// universe index; when the inference variable is assigned a value, it becomes +/// bound and records that value. See `EnaVariable` for more details. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum InferenceValue<I: Interner> { + Unbound(UniverseIndex), + Bound(GenericArg<I>), +} + +impl<I: Interner> InferenceValue<I> { + pub fn from_ty(interner: I, ty: Ty<I>) -> Self { + InferenceValue::Bound(ty.cast(interner)) + } + + pub fn from_lifetime(interner: I, lifetime: Lifetime<I>) -> Self { + InferenceValue::Bound(lifetime.cast(interner)) + } + + pub fn from_const(interner: I, constant: Const<I>) -> Self { + InferenceValue::Bound(constant.cast(interner)) + } +} + +impl<I: Interner> UnifyValue for InferenceValue<I> { + type Error = (InferenceValue<I>, InferenceValue<I>); + + fn unify_values( + a: &InferenceValue<I>, + b: &InferenceValue<I>, + ) -> Result<InferenceValue<I>, (InferenceValue<I>, InferenceValue<I>)> { + match (a, b) { + (&InferenceValue::Unbound(ui_a), &InferenceValue::Unbound(ui_b)) => { + Ok(InferenceValue::Unbound(min(ui_a, ui_b))) + } + (bound @ &InferenceValue::Bound(_), &InferenceValue::Unbound(_)) + | (&InferenceValue::Unbound(_), bound @ &InferenceValue::Bound(_)) => Ok(bound.clone()), + (&InferenceValue::Bound(_), &InferenceValue::Bound(_)) => { + panic!("we should not be asked to unify two bound things") + } + } + } +} + +impl<I: Interner> fmt::Debug for EnaVariable<I> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + write!(fmt, "{:?}", self.var) + } +} diff --git a/vendor/chalk-solve/src/lib.rs b/vendor/chalk-solve/src/lib.rs new file mode 100644 index 000000000..a870a0c49 --- /dev/null +++ b/vendor/chalk-solve/src/lib.rs @@ -0,0 +1,219 @@ +#![deny(rust_2018_idioms)] + +use crate::display::sanitize_debug_name; +use crate::rust_ir::*; +use chalk_ir::interner::Interner; + +use chalk_ir::*; +use std::fmt::Debug; +use std::sync::Arc; + +pub mod clauses; +pub mod coherence; +pub mod coinductive_goal; +pub mod display; +pub mod ext; +pub mod goal_builder; +pub mod infer; +pub mod logging; +pub mod logging_db; +pub mod rust_ir; +pub mod solve; +pub mod split; +pub mod wf; + +/// Trait representing access to a database of rust types. +/// +/// # `*_name` methods +/// +/// This trait has a number of `*_name` methods with default implementations. +/// These are used in the implementation for [`LoggingRustIrDatabase`], so that +/// when printing `.chalk` files equivalent to the data used, we can use real +/// names. +/// +/// The default implementations simply fall back to calling [`Interner`] debug +/// methods, and printing `"UnknownN"` (where `N` is the demultiplexing integer) +/// if those methods return `None`. +/// +/// The [`display::sanitize_debug_name`] utility is used in the default +/// implementations, and might be useful when providing custom implementations. +/// +/// [`LoggingRustIrDatabase`]: crate::logging_db::LoggingRustIrDatabase +/// [`display::sanitize_debug_name`]: crate::display::sanitize_debug_name +/// [`Interner`]: Interner +pub trait RustIrDatabase<I: Interner>: Debug { + /// Returns any "custom program clauses" that do not derive from + /// Rust IR. Used only in testing the underlying solver. + fn custom_clauses(&self) -> Vec<ProgramClause<I>>; + + /// Returns the datum for the associated type with the given id. + fn associated_ty_data(&self, ty: AssocTypeId<I>) -> Arc<AssociatedTyDatum<I>>; + + /// Returns the datum for the definition with the given id. + fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>>; + + /// Returns the datum for the ADT with the given id. + fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>>; + + /// Returns the generator datum for the generator with the given id. + fn generator_datum(&self, generator_id: GeneratorId<I>) -> Arc<GeneratorDatum<I>>; + + /// Returns the generator witness datum for the generator with the given id. + fn generator_witness_datum( + &self, + generator_id: GeneratorId<I>, + ) -> Arc<GeneratorWitnessDatum<I>>; + + /// Returns the representation for the ADT definition with the given id. + fn adt_repr(&self, id: AdtId<I>) -> Arc<AdtRepr<I>>; + + /// Returns the siza and alignment of the ADT definition with the given id. + fn adt_size_align(&self, id: AdtId<I>) -> Arc<AdtSizeAlign>; + + /// Returns the datum for the fn definition with the given id. + fn fn_def_datum(&self, fn_def_id: FnDefId<I>) -> Arc<FnDefDatum<I>>; + + /// Returns the datum for the impl with the given id. + fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>>; + + /// Returns the `AssociatedTyValue` with the given id. + fn associated_ty_value(&self, id: AssociatedTyValueId<I>) -> Arc<AssociatedTyValue<I>>; + + /// Returns the `OpaqueTyDatum` with the given id. + fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>>; + + /// Returns the "hidden type" corresponding with the opaque type. + fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I>; + + /// Returns a list of potentially relevant impls for a given + /// trait-id; we also supply the type parameters that we are + /// trying to match (if known: these parameters may contain + /// inference variables, for example). The implementor is + /// permitted to return any superset of the applicable impls; + /// chalk will narrow down the list to only those that truly + /// apply. The parameters are provided as a "hint" to help the + /// implementor do less work, but can be completely ignored if + /// desired. + /// + /// The `binders` are for the `parameters`; if the recursive solver is used, + /// the parameters can contain bound variables referring to these binders. + fn impls_for_trait( + &self, + trait_id: TraitId<I>, + parameters: &[GenericArg<I>], + binders: &CanonicalVarKinds<I>, + ) -> Vec<ImplId<I>>; + + /// Returns the impls that require coherence checking. This is not the + /// full set of impls that exist: + /// + /// - It can exclude impls not defined in the current crate. + /// - It can exclude "built-in" impls, like those for closures; only the + /// impls actually written by users need to be checked. + fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>>; + + /// Returns true if there is an explicit impl of the auto trait + /// `auto_trait_id` for the type `ty`. This is part of + /// the auto trait handling -- if there is no explicit impl given + /// by the user for `ty`, then we provide default impls + /// (otherwise, we rely on the impls the user gave). + fn impl_provided_for(&self, auto_trait_id: TraitId<I>, ty: &TyKind<I>) -> bool; + + /// Returns id of a trait lang item, if found + fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option<TraitId<I>>; + + /// Calculates program clauses from an env. This is intended to call the + /// `program_clauses_for_env` function and then possibly cache the clauses. + fn program_clauses_for_env(&self, environment: &Environment<I>) -> ProgramClauses<I>; + + fn interner(&self) -> I; + + /// Check if a trait is object safe + fn is_object_safe(&self, trait_id: TraitId<I>) -> bool; + + /// Gets the `ClosureKind` for a given closure and substitution. + fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind; + + /// Gets the inputs and output for a given closure id and substitution. We + /// pass both the `ClosureId` and it's `Substituion` to give implementors + /// the freedom to store associated data in the substitution (like rustc) or + /// separately (like chalk-integration). + fn closure_inputs_and_output( + &self, + closure_id: ClosureId<I>, + substs: &Substitution<I>, + ) -> Binders<FnDefInputsAndOutputDatum<I>>; + + /// Gets the upvars as a `Ty` for a given closure id and substitution. There + /// are no restrictions on the type of upvars. + fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>>; + + /// Gets the substitution for the closure when used as a function. + /// For example, for the following (not-quite-)rust code: + /// ```ignore + /// let foo = |a: &mut u32| { a += 1; }; + /// let c: &'a u32 = &0; + /// foo(c); + /// ``` + /// + /// This would return a `Substitution` of `[&'a]`. This could either be + /// substituted into the inputs and output, or into the upvars. + fn closure_fn_substitution( + &self, + closure_id: ClosureId<I>, + substs: &Substitution<I>, + ) -> Substitution<I>; + + fn unification_database(&self) -> &dyn UnificationDatabase<I>; + + /// Retrieves a trait's original name. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn trait_name(&self, trait_id: TraitId<I>) -> String { + sanitize_debug_name(|f| I::debug_trait_id(trait_id, f)) + } + + /// Retrieves a struct's original name. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn adt_name(&self, adt_id: AdtId<I>) -> String { + sanitize_debug_name(|f| I::debug_adt_id(adt_id, f)) + } + + /// Retrieves the name of an associated type. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String { + sanitize_debug_name(|f| I::debug_assoc_type_id(assoc_ty_id, f)) + } + + /// Retrieves the name of an opaque type. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String { + sanitize_debug_name(|f| I::debug_opaque_ty_id(opaque_ty_id, f)) + } + + /// Retrieves the name of a function definition. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String { + sanitize_debug_name(|f| I::debug_fn_def_id(fn_def_id, f)) + } + + // Retrieves the discriminant type for a type (mirror of rustc `TyS::discriminant_ty`) + fn discriminant_type(&self, ty: Ty<I>) -> Ty<I>; +} + +pub use clauses::program_clauses_for_env; + +pub use solve::Guidance; +pub use solve::Solution; +pub use solve::Solver; +pub use solve::SubstitutionResult; + +#[macro_use] +mod debug_macros { + #[macro_export] + macro_rules! debug_span { + ($($t: tt)*) => { + let __span = tracing::debug_span!($($t)*); + let __span = __span.enter(); + }; + } +} diff --git a/vendor/chalk-solve/src/logging.rs b/vendor/chalk-solve/src/logging.rs new file mode 100644 index 000000000..a5be4d4d4 --- /dev/null +++ b/vendor/chalk-solve/src/logging.rs @@ -0,0 +1,19 @@ +/// Run an action with a tracing log subscriber. The logging level is loaded +/// from `CHALK_DEBUG`. +#[cfg(feature = "tracing-full")] +pub fn with_tracing_logs<T>(action: impl FnOnce() -> T) -> T { + use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; + use tracing_tree::HierarchicalLayer; + let filter = EnvFilter::from_env("CHALK_DEBUG"); + let subscriber = Registry::default() + .with(filter) + .with(HierarchicalLayer::new(2).with_writer(std::io::stdout)); + tracing::subscriber::with_default(subscriber, action) +} + +/// Run an action with a tracing log subscriber. The logging level is loaded +/// from `CHALK_DEBUG`. +#[cfg(not(feature = "tracing-full"))] +pub fn with_tracing_logs<T>(action: impl FnOnce() -> T) -> T { + action() +} diff --git a/vendor/chalk-solve/src/logging_db.rs b/vendor/chalk-solve/src/logging_db.rs new file mode 100644 index 000000000..12d8b052a --- /dev/null +++ b/vendor/chalk-solve/src/logging_db.rs @@ -0,0 +1,593 @@ +//! Provides wrappers over `RustIrDatabase` which record used definitions and write +//! `.chalk` files containing those definitions. +use std::{ + borrow::Borrow, + fmt::{self, Debug, Display}, + io::Write, + marker::PhantomData, + sync::Arc, + sync::Mutex, +}; + +use crate::rust_ir::*; +use crate::{ + display::{self, WriterState}, + RustIrDatabase, +}; +use chalk_ir::{interner::Interner, *}; + +use indexmap::IndexSet; + +mod id_collector; + +/// Wraps another `RustIrDatabase` (`DB`) and records which definitions are +/// used. +/// +/// A full .chalk file containing all used definitions can be recovered through +/// `LoggingRustIrDatabase`'s `Display` implementation. +/// +/// Uses a separate type, `P`, for the database stored inside to account for +/// `Arc` or wrapping other storage mediums. +#[derive(Debug)] +pub struct LoggingRustIrDatabase<I, DB, P = DB> +where + DB: RustIrDatabase<I>, + P: Borrow<DB>, + I: Interner, +{ + ws: WriterState<I, DB, P>, + def_ids: Mutex<IndexSet<RecordedItemId<I>>>, + _phantom: PhantomData<DB>, +} + +impl<I, DB, P> LoggingRustIrDatabase<I, DB, P> +where + DB: RustIrDatabase<I>, + P: Borrow<DB>, + I: Interner, +{ + pub fn new(db: P) -> Self { + LoggingRustIrDatabase { + ws: WriterState::new(db), + def_ids: Default::default(), + _phantom: PhantomData, + } + } +} + +impl<I, DB, P> Display for LoggingRustIrDatabase<I, DB, P> +where + DB: RustIrDatabase<I>, + P: Borrow<DB>, + I: Interner, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let def_ids = self.def_ids.lock().unwrap(); + let stub_ids = id_collector::collect_unrecorded_ids(self.ws.db(), &def_ids); + display::write_stub_items(f, &self.ws, stub_ids)?; + display::write_items(f, &self.ws, def_ids.iter().copied()) + } +} + +impl<I, DB, P> LoggingRustIrDatabase<I, DB, P> +where + DB: RustIrDatabase<I>, + P: Borrow<DB>, + I: Interner, +{ + fn record(&self, id: impl Into<RecordedItemId<I>>) { + self.def_ids.lock().unwrap().insert(id.into()); + } + + fn record_all<T, U>(&self, ids: T) + where + T: IntoIterator<Item = U>, + U: Into<RecordedItemId<I>>, + { + self.def_ids + .lock() + .unwrap() + .extend(ids.into_iter().map(Into::into)); + } +} + +impl<I, DB, P> UnificationDatabase<I> for LoggingRustIrDatabase<I, DB, P> +where + DB: RustIrDatabase<I>, + P: Borrow<DB> + Debug, + I: Interner, +{ + fn fn_def_variance(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Variances<I> { + self.ws + .db() + .unification_database() + .fn_def_variance(fn_def_id) + } + + fn adt_variance(&self, adt_id: chalk_ir::AdtId<I>) -> Variances<I> { + self.ws.db().unification_database().adt_variance(adt_id) + } +} + +impl<I, DB, P> RustIrDatabase<I> for LoggingRustIrDatabase<I, DB, P> +where + DB: RustIrDatabase<I>, + P: Borrow<DB> + Debug, + I: Interner, +{ + fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> { + self.ws.db().custom_clauses() + } + + fn associated_ty_data( + &self, + ty: chalk_ir::AssocTypeId<I>, + ) -> Arc<crate::rust_ir::AssociatedTyDatum<I>> { + let ty_datum = self.ws.db().associated_ty_data(ty); + self.record(ty_datum.trait_id); + ty_datum + } + + fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>> { + self.record(trait_id); + self.ws.db().trait_datum(trait_id) + } + + fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>> { + self.record(adt_id); + self.ws.db().adt_datum(adt_id) + } + + fn generator_datum(&self, generator_id: GeneratorId<I>) -> Arc<GeneratorDatum<I>> { + self.record(generator_id); + self.ws.db().borrow().generator_datum(generator_id) + } + + fn generator_witness_datum( + &self, + generator_id: GeneratorId<I>, + ) -> Arc<GeneratorWitnessDatum<I>> { + self.record(generator_id); + self.ws.db().borrow().generator_witness_datum(generator_id) + } + + fn adt_repr(&self, id: AdtId<I>) -> Arc<AdtRepr<I>> { + self.record(id); + self.ws.db().adt_repr(id) + } + + fn adt_size_align(&self, id: chalk_ir::AdtId<I>) -> Arc<crate::rust_ir::AdtSizeAlign> { + self.record(id); + self.ws.db().adt_size_align(id) + } + + fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>> { + self.record(impl_id); + self.ws.db().impl_datum(impl_id) + } + + fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> { + self.record(id); + self.ws.db().hidden_opaque_type(id) + } + + fn associated_ty_value( + &self, + id: crate::rust_ir::AssociatedTyValueId<I>, + ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> { + let value = self.ws.db().associated_ty_value(id); + self.record(value.impl_id); + value + } + + fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> { + self.record(id); + self.ws.db().opaque_ty_data(id) + } + + fn impls_for_trait( + &self, + trait_id: TraitId<I>, + parameters: &[chalk_ir::GenericArg<I>], + binders: &CanonicalVarKinds<I>, + ) -> Vec<ImplId<I>> { + self.record(trait_id); + let impl_ids = self.ws.db().impls_for_trait(trait_id, parameters, binders); + self.record_all(impl_ids.iter().copied()); + impl_ids + } + + fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> { + self.record(trait_id); + self.ws.db().local_impls_to_coherence_check(trait_id) + } + + fn impl_provided_for(&self, auto_trait_id: TraitId<I>, ty: &TyKind<I>) -> bool { + self.record(auto_trait_id); + if let TyKind::Adt(adt_id, _) = ty { + self.record(*adt_id); + } + self.ws.db().impl_provided_for(auto_trait_id, ty) + } + + fn well_known_trait_id( + &self, + well_known_trait: crate::rust_ir::WellKnownTrait, + ) -> Option<TraitId<I>> { + let trait_id = self.ws.db().well_known_trait_id(well_known_trait); + if let Some(id) = trait_id { + self.record(id); + } + trait_id + } + + fn program_clauses_for_env( + &self, + environment: &chalk_ir::Environment<I>, + ) -> chalk_ir::ProgramClauses<I> { + self.ws.db().program_clauses_for_env(environment) + } + + fn interner(&self) -> I { + self.ws.db().interner() + } + + fn trait_name(&self, trait_id: TraitId<I>) -> String { + self.ws.db().trait_name(trait_id) + } + + fn adt_name(&self, adt_id: AdtId<I>) -> String { + self.ws.db().adt_name(adt_id) + } + + fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String { + self.ws.db().assoc_type_name(assoc_ty_id) + } + + fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String { + self.ws.db().opaque_type_name(opaque_ty_id) + } + + fn is_object_safe(&self, trait_id: TraitId<I>) -> bool { + self.record(trait_id); + self.ws.db().is_object_safe(trait_id) + } + + fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> { + self.record(fn_def_id); + self.ws.db().fn_def_datum(fn_def_id) + } + + fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String { + self.ws.db().fn_def_name(fn_def_id) + } + + fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind { + // TODO: record closure IDs + self.ws.db().closure_kind(closure_id, substs) + } + + fn closure_inputs_and_output( + &self, + closure_id: ClosureId<I>, + substs: &Substitution<I>, + ) -> Binders<FnDefInputsAndOutputDatum<I>> { + // TODO: record closure IDs + self.ws.db().closure_inputs_and_output(closure_id, substs) + } + + fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> { + // TODO: record closure IDs + self.ws.db().closure_upvars(closure_id, substs) + } + + fn closure_fn_substitution( + &self, + closure_id: ClosureId<I>, + substs: &Substitution<I>, + ) -> Substitution<I> { + // TODO: record closure IDs + self.ws.db().closure_fn_substitution(closure_id, substs) + } + + fn discriminant_type(&self, ty: Ty<I>) -> Ty<I> { + self.ws.db().discriminant_type(ty) + } + + fn unification_database(&self) -> &dyn UnificationDatabase<I> { + self + } +} + +/// Wraps a [`RustIrDatabase`], and, when dropped, writes out all used +/// definition to the given file. +/// +/// Uses [`LoggingRustIrDatabase`] internally. +/// +/// Uses a separate type, `P`, for the database stored inside to account for +/// `Arc` or wrapping other storage mediums. +pub struct WriteOnDropRustIrDatabase<I, W, DB, P = DB> +where + I: Interner, + W: Write, + DB: RustIrDatabase<I>, + P: Borrow<DB>, +{ + db: LoggingRustIrDatabase<I, DB, P>, + write: W, +} + +impl<I, W, DB, P> fmt::Debug for WriteOnDropRustIrDatabase<I, W, DB, P> +where + I: Interner, + W: Write, + DB: RustIrDatabase<I>, + P: Borrow<DB> + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("WriteOnDropRustIrDatabase") + .field("db", &self.db) + .field("write", &"<opaque>") + .finish() + } +} + +impl<I, W, DB, P> WriteOnDropRustIrDatabase<I, W, DB, P> +where + I: Interner, + W: Write, + DB: RustIrDatabase<I>, + P: Borrow<DB>, +{ + pub fn new(db: P, write: W) -> Self { + WriteOnDropRustIrDatabase { + db: LoggingRustIrDatabase::new(db), + write, + } + } + + pub fn from_logging_db(db: LoggingRustIrDatabase<I, DB, P>, write: W) -> Self { + WriteOnDropRustIrDatabase { db, write } + } +} + +impl<I, W, DB, P> Drop for WriteOnDropRustIrDatabase<I, W, DB, P> +where + I: Interner, + W: Write, + DB: RustIrDatabase<I>, + P: Borrow<DB>, +{ + fn drop(&mut self) { + write!(self.write, "{}", self.db) + .and_then(|_| self.write.flush()) + .expect("expected to be able to write rust ir database"); + } +} + +impl<I, W, DB, P> UnificationDatabase<I> for WriteOnDropRustIrDatabase<I, W, DB, P> +where + I: Interner, + W: Write, + DB: RustIrDatabase<I>, + P: Borrow<DB> + Debug, +{ + fn fn_def_variance(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Variances<I> { + self.db + .borrow() + .unification_database() + .fn_def_variance(fn_def_id) + } + + fn adt_variance(&self, adt_id: chalk_ir::AdtId<I>) -> Variances<I> { + self.db.borrow().unification_database().adt_variance(adt_id) + } +} + +impl<I, W, DB, P> RustIrDatabase<I> for WriteOnDropRustIrDatabase<I, W, DB, P> +where + I: Interner, + W: Write, + DB: RustIrDatabase<I>, + P: Borrow<DB> + Debug, +{ + fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> { + self.db.custom_clauses() + } + + fn associated_ty_data( + &self, + ty: chalk_ir::AssocTypeId<I>, + ) -> Arc<crate::rust_ir::AssociatedTyDatum<I>> { + self.db.associated_ty_data(ty) + } + + fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>> { + self.db.trait_datum(trait_id) + } + + fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>> { + self.db.adt_datum(adt_id) + } + + fn generator_datum(&self, generator_id: GeneratorId<I>) -> Arc<GeneratorDatum<I>> { + self.db.borrow().generator_datum(generator_id) + } + + /// Returns the generator witness datum for the generator with the given id. + fn generator_witness_datum( + &self, + generator_id: GeneratorId<I>, + ) -> Arc<GeneratorWitnessDatum<I>> { + self.db.borrow().generator_witness_datum(generator_id) + } + + fn adt_repr(&self, id: AdtId<I>) -> Arc<AdtRepr<I>> { + self.db.adt_repr(id) + } + + fn adt_size_align(&self, id: chalk_ir::AdtId<I>) -> Arc<crate::rust_ir::AdtSizeAlign> { + self.db.adt_size_align(id) + } + + fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>> { + self.db.impl_datum(impl_id) + } + + fn associated_ty_value( + &self, + id: crate::rust_ir::AssociatedTyValueId<I>, + ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> { + self.db.associated_ty_value(id) + } + + fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> { + self.db.opaque_ty_data(id) + } + + fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> { + self.db.hidden_opaque_type(id) + } + + fn impls_for_trait( + &self, + trait_id: TraitId<I>, + parameters: &[chalk_ir::GenericArg<I>], + binders: &CanonicalVarKinds<I>, + ) -> Vec<ImplId<I>> { + self.db.impls_for_trait(trait_id, parameters, binders) + } + + fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> { + self.db.local_impls_to_coherence_check(trait_id) + } + + fn impl_provided_for(&self, auto_trait_id: TraitId<I>, ty: &TyKind<I>) -> bool { + self.db.impl_provided_for(auto_trait_id, ty) + } + + fn well_known_trait_id( + &self, + well_known_trait: crate::rust_ir::WellKnownTrait, + ) -> Option<TraitId<I>> { + self.db.well_known_trait_id(well_known_trait) + } + + fn program_clauses_for_env( + &self, + environment: &chalk_ir::Environment<I>, + ) -> chalk_ir::ProgramClauses<I> { + self.db.program_clauses_for_env(environment) + } + + fn interner(&self) -> I { + self.db.interner() + } + + fn is_object_safe(&self, trait_id: TraitId<I>) -> bool { + self.db.is_object_safe(trait_id) + } + + fn unification_database(&self) -> &dyn UnificationDatabase<I> { + self + } + + fn trait_name(&self, trait_id: TraitId<I>) -> String { + self.db.trait_name(trait_id) + } + + fn adt_name(&self, adt_id: AdtId<I>) -> String { + self.db.adt_name(adt_id) + } + + fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String { + self.db.assoc_type_name(assoc_ty_id) + } + + fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String { + self.db.opaque_type_name(opaque_ty_id) + } + + fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> { + self.db.fn_def_datum(fn_def_id) + } + + fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String { + self.db.fn_def_name(fn_def_id) + } + + fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind { + // TODO: record closure IDs + self.db.closure_kind(closure_id, substs) + } + + fn closure_inputs_and_output( + &self, + closure_id: ClosureId<I>, + substs: &Substitution<I>, + ) -> Binders<FnDefInputsAndOutputDatum<I>> { + self.db.closure_inputs_and_output(closure_id, substs) + } + + fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> { + self.db.closure_upvars(closure_id, substs) + } + + fn closure_fn_substitution( + &self, + closure_id: ClosureId<I>, + substs: &Substitution<I>, + ) -> Substitution<I> { + self.db.closure_fn_substitution(closure_id, substs) + } + + fn discriminant_type(&self, ty: Ty<I>) -> Ty<I> { + self.db.discriminant_type(ty) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub enum RecordedItemId<I: Interner> { + Adt(AdtId<I>), + Trait(TraitId<I>), + Impl(ImplId<I>), + OpaqueTy(OpaqueTyId<I>), + FnDef(FnDefId<I>), + Generator(GeneratorId<I>), +} + +impl<I: Interner> From<AdtId<I>> for RecordedItemId<I> { + fn from(v: AdtId<I>) -> Self { + RecordedItemId::Adt(v) + } +} + +impl<I: Interner> From<TraitId<I>> for RecordedItemId<I> { + fn from(v: TraitId<I>) -> Self { + RecordedItemId::Trait(v) + } +} + +impl<I: Interner> From<ImplId<I>> for RecordedItemId<I> { + fn from(v: ImplId<I>) -> Self { + RecordedItemId::Impl(v) + } +} + +impl<I: Interner> From<OpaqueTyId<I>> for RecordedItemId<I> { + fn from(v: OpaqueTyId<I>) -> Self { + RecordedItemId::OpaqueTy(v) + } +} + +impl<I: Interner> From<FnDefId<I>> for RecordedItemId<I> { + fn from(v: FnDefId<I>) -> Self { + RecordedItemId::FnDef(v) + } +} + +impl<I: Interner> From<GeneratorId<I>> for RecordedItemId<I> { + fn from(v: GeneratorId<I>) -> Self { + RecordedItemId::Generator(v) + } +} diff --git a/vendor/chalk-solve/src/logging_db/id_collector.rs b/vendor/chalk-solve/src/logging_db/id_collector.rs new file mode 100644 index 000000000..41aa38166 --- /dev/null +++ b/vendor/chalk-solve/src/logging_db/id_collector.rs @@ -0,0 +1,162 @@ +use super::RecordedItemId; +use crate::RustIrDatabase; +use chalk_ir::{ + interner::Interner, + visit::TypeVisitor, + visit::{TypeSuperVisitable, TypeVisitable}, + AliasTy, DebruijnIndex, TyKind, WhereClause, +}; +use std::ops::ControlFlow; + +use indexmap::IndexSet; + +/// Collects the identifiers needed to resolve all the names for a given +/// set of identifers, excluding identifiers we already have. +/// +/// When recording identifiers to print, the `LoggingRustIrDatabase` only +/// records identifiers the solver uses. But the solver assumes well-formedness, +/// and thus skips over many names referenced in the definitions. +/// +/// For instance, if we have: +/// +/// ```rust,ignore +/// struct S {} +/// +/// trait Parent {} +/// trait Child where Self: Parent {} +/// impl Parent for S {} +/// impl Child for S {} +/// ``` +/// +/// And our goal is `S: Child`, we will only render `S`, `impl Child for S`, and +/// `trait Child`. This will not parse because the `Child` trait's definition +/// references parent. IdCollector solves this by collecting all of the directly +/// related identifiers, allowing those to be rendered as well, ensuring name +/// resolution is successful. +pub fn collect_unrecorded_ids<I: Interner, DB: RustIrDatabase<I>>( + db: &DB, + identifiers: &'_ IndexSet<RecordedItemId<I>>, +) -> IndexSet<RecordedItemId<I>> { + let mut collector = IdCollector { + db, + found_identifiers: IndexSet::new(), + }; + for id in identifiers { + match *id { + RecordedItemId::Adt(adt_id) => { + collector + .db + .adt_datum(adt_id) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + RecordedItemId::FnDef(fn_def) => { + collector + .db + .fn_def_datum(fn_def) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + RecordedItemId::Generator(_generator_id) => unimplemented!(), + RecordedItemId::Trait(trait_id) => { + let trait_datum = collector.db.trait_datum(trait_id); + + trait_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST); + for assoc_ty_id in &trait_datum.associated_ty_ids { + let assoc_ty_datum = collector.db.associated_ty_data(*assoc_ty_id); + assoc_ty_datum + .bounds_on_self(collector.db.interner()) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + assoc_ty_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + } + RecordedItemId::OpaqueTy(opaque_id) => { + collector + .db + .opaque_ty_data(opaque_id) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + collector + .db + .hidden_opaque_type(opaque_id) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + RecordedItemId::Impl(impl_id) => { + let impl_datum = collector.db.impl_datum(impl_id); + for id in &impl_datum.associated_ty_value_ids { + let assoc_ty_value = collector.db.associated_ty_value(*id); + assoc_ty_value.visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + impl_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + } + } + collector + .found_identifiers + .difference(identifiers) + .copied() + .collect() +} + +struct IdCollector<'i, I: Interner, DB: RustIrDatabase<I>> { + db: &'i DB, + found_identifiers: IndexSet<RecordedItemId<I>>, +} + +impl<'i, I: Interner, DB: RustIrDatabase<I>> IdCollector<'i, I, DB> { + fn record(&mut self, id: impl Into<RecordedItemId<I>>) { + self.found_identifiers.insert(id.into()); + } + + fn visit_alias(&mut self, alias: &AliasTy<I>) { + match alias { + AliasTy::Projection(projection_ty) => { + let assoc_ty_datum = self.db.associated_ty_data(projection_ty.associated_ty_id); + self.record(assoc_ty_datum.trait_id) + } + AliasTy::Opaque(opaque_ty) => self.record(opaque_ty.opaque_ty_id), + } + } +} + +impl<'i, I: Interner, DB: RustIrDatabase<I>> TypeVisitor<I> for IdCollector<'i, I, DB> { + type BreakTy = (); + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> { + self + } + fn interner(&self) -> I { + self.db.interner() + } + + fn visit_ty( + &mut self, + ty: &chalk_ir::Ty<I>, + outer_binder: chalk_ir::DebruijnIndex, + ) -> ControlFlow<()> { + match ty.kind(self.db.interner()) { + TyKind::Adt(adt, _) => self.record(*adt), + TyKind::FnDef(fn_def, _) => self.record(*fn_def), + TyKind::OpaqueType(opaque, _) => self.record(*opaque), + TyKind::Alias(alias) => self.visit_alias(alias), + TyKind::BoundVar(..) => (), + TyKind::Dyn(..) => (), + TyKind::Function(..) => (), + TyKind::InferenceVar(..) => (), + TyKind::Placeholder(..) => (), + _ => {} + } + ty.super_visit_with(self, outer_binder) + } + + fn visit_where_clause( + &mut self, + where_clause: &WhereClause<I>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<()> { + match where_clause { + WhereClause::Implemented(trait_ref) => self.record(trait_ref.trait_id), + WhereClause::AliasEq(alias_eq) => self.visit_alias(&alias_eq.alias), + WhereClause::LifetimeOutlives(_lifetime_outlives) => (), + WhereClause::TypeOutlives(_type_outlives) => (), + } + where_clause.super_visit_with(self.as_dyn(), outer_binder) + } +} diff --git a/vendor/chalk-solve/src/rust_ir.rs b/vendor/chalk-solve/src/rust_ir.rs new file mode 100644 index 000000000..935a29032 --- /dev/null +++ b/vendor/chalk-solve/src/rust_ir.rs @@ -0,0 +1,752 @@ +//! Contains the definition for the "Rust IR" -- this is basically a "lowered" +//! version of the AST, roughly corresponding to [the HIR] in the Rust +//! compiler. + +use chalk_derive::{HasInterner, TypeFoldable, TypeVisitable}; +use chalk_ir::cast::Cast; +use chalk_ir::fold::shift::Shift; +use chalk_ir::interner::Interner; +use chalk_ir::{ + try_break, visit::TypeVisitable, AdtId, AliasEq, AliasTy, AssocTypeId, Binders, DebruijnIndex, + FnDefId, GenericArg, ImplId, OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Substitution, + ToGenericArg, TraitId, TraitRef, Ty, TyKind, VariableKind, WhereClause, WithKind, +}; +use std::iter; +use std::ops::ControlFlow; + +/// Identifier for an "associated type value" found in some impl. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct AssociatedTyValueId<I: Interner>(pub I::DefId); + +chalk_ir::id_visit!(AssociatedTyValueId); +chalk_ir::id_fold!(AssociatedTyValueId); + +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeVisitable)] +pub struct ImplDatum<I: Interner> { + pub polarity: Polarity, + pub binders: Binders<ImplDatumBound<I>>, + pub impl_type: ImplType, + pub associated_ty_value_ids: Vec<AssociatedTyValueId<I>>, +} + +impl<I: Interner> ImplDatum<I> { + pub fn is_positive(&self) -> bool { + self.polarity.is_positive() + } + + pub fn trait_id(&self) -> TraitId<I> { + self.binders.skip_binders().trait_ref.trait_id + } + + pub fn self_type_adt_id(&self, interner: I) -> Option<AdtId<I>> { + match self + .binders + .skip_binders() + .trait_ref + .self_type_parameter(interner) + .kind(interner) + { + TyKind::Adt(id, _) => Some(*id), + _ => None, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner, TypeFoldable, TypeVisitable)] +pub struct ImplDatumBound<I: Interner> { + pub trait_ref: TraitRef<I>, + pub where_clauses: Vec<QuantifiedWhereClause<I>>, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum ImplType { + Local, + External, +} + +chalk_ir::const_visit!(ImplType); + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct DefaultImplDatum<I: Interner> { + pub binders: Binders<DefaultImplDatumBound<I>>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner)] +pub struct DefaultImplDatumBound<I: Interner> { + pub trait_ref: TraitRef<I>, + pub accessible_tys: Vec<Ty<I>>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeVisitable)] +pub struct AdtDatum<I: Interner> { + pub binders: Binders<AdtDatumBound<I>>, + pub id: AdtId<I>, + pub flags: AdtFlags, + pub kind: AdtKind, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub enum AdtKind { + Struct, + Enum, + Union, +} + +chalk_ir::const_visit!(AdtKind); + +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, HasInterner, TypeVisitable)] +pub struct AdtDatumBound<I: Interner> { + pub variants: Vec<AdtVariantDatum<I>>, + pub where_clauses: Vec<QuantifiedWhereClause<I>>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, HasInterner, TypeVisitable)] +pub struct AdtVariantDatum<I: Interner> { + pub fields: Vec<Ty<I>>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct AdtFlags { + pub upstream: bool, + pub fundamental: bool, + pub phantom_data: bool, +} + +chalk_ir::const_visit!(AdtFlags); + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct AdtRepr<I: Interner> { + pub c: bool, + pub packed: bool, + pub int: Option<chalk_ir::Ty<I>>, +} + +/// Information about the size and alignment of an ADT. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct AdtSizeAlign { + one_zst: bool, +} + +impl AdtSizeAlign { + pub fn from_one_zst(one_zst: bool) -> AdtSizeAlign { + AdtSizeAlign { one_zst } + } + + pub fn one_zst(&self) -> bool { + self.one_zst + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +/// A rust intermediate represention (rust_ir) of a function definition/declaration. +/// For example, in the following rust code: +/// +/// ```ignore +/// fn foo<T>() -> i32 where T: Eq; +/// ``` +/// +/// This would represent the declaration of `foo`. +/// +/// Note this is distinct from a function pointer, which points to +/// a function with a given type signature, whereas this represents +/// a specific function definition. +pub struct FnDefDatum<I: Interner> { + pub id: FnDefId<I>, + pub sig: chalk_ir::FnSig<I>, + pub binders: Binders<FnDefDatumBound<I>>, +} + +/// Avoids visiting `I::FnAbi` +impl<I: Interner> TypeVisitable<I> for FnDefDatum<I> { + fn visit_with<B>( + &self, + visitor: &mut dyn chalk_ir::visit::TypeVisitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + try_break!(self.id.visit_with(visitor, outer_binder)); + self.binders.visit_with(visitor, outer_binder) + } +} + +/// Represents the inputs and outputs on a `FnDefDatum`. This is split +/// from the where clauses, since these can contain bound lifetimes. +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, HasInterner, TypeVisitable)] +pub struct FnDefInputsAndOutputDatum<I: Interner> { + /// Types of the function's arguments + /// ```ignore + /// fn foo<T>(bar: i32, baz: T); + /// ^^^ ^ + /// ``` + /// + pub argument_types: Vec<Ty<I>>, + /// Return type of the function + /// ```ignore + /// fn foo<T>() -> i32; + /// ^^^ + /// ``` + pub return_type: Ty<I>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, HasInterner, TypeVisitable)] +/// Represents the bounds on a `FnDefDatum`, including +/// the function definition's type signature and where clauses. +pub struct FnDefDatumBound<I: Interner> { + /// Inputs and outputs defined on a function + /// These are needed for late-bound regions in rustc. For example the + /// lifetime `'a` in + /// ```ignore + /// fn foo<'a, T>(&'a T); + /// ^^ + /// ``` + /// Rustc doesn't pass in late-bound the regions in substs, but the inputs + /// and outputs may use them. `where_clauses` don't need an extra set of + /// `Binders`, since any lifetimes found in where clauses are not late-bound. + /// + /// For more information, see [this rustc-dev-guide chapter](https://rustc-dev-guide.rust-lang.org/early-late-bound.html). + pub inputs_and_output: Binders<FnDefInputsAndOutputDatum<I>>, + + /// Where clauses defined on the function + /// ```ignore + /// fn foo<T>() where T: Eq; + /// ^^^^^^^^^^^ + /// ``` + pub where_clauses: Vec<QuantifiedWhereClause<I>>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +// FIXME: unignore the doctest below when GATs hit stable. +/// A rust intermediate representation (rust_ir) of a Trait Definition. For +/// example, given the following rust code: +/// +/// ```ignore +/// use std::fmt::Debug; +/// +/// trait Foo<T> +/// where +/// T: Debug, +/// { +/// type Bar<U>; +/// } +/// ``` +/// +/// This would represent the `trait Foo` declaration. Note that the details of +/// the trait members (e.g., the associated type declaration (`type Bar<U>`) are +/// not contained in this type, and are represented separately (e.g., in +/// [`AssociatedTyDatum`]). +/// +/// Not to be confused with the rust_ir for a Trait Implementation, which is +/// represented by [`ImplDatum`] +/// +/// [`ImplDatum`]: struct.ImplDatum.html +/// [`AssociatedTyDatum`]: struct.AssociatedTyDatum.html +#[derive(TypeVisitable)] +pub struct TraitDatum<I: Interner> { + pub id: TraitId<I>, + + pub binders: Binders<TraitDatumBound<I>>, + + /// "Flags" indicate special kinds of traits, like auto traits. + /// In Rust syntax these are represented in different ways, but in + /// chalk we add annotations like `#[auto]`. + pub flags: TraitFlags, + + pub associated_ty_ids: Vec<AssocTypeId<I>>, + + /// If this is a well-known trait, which one? If `None`, this is a regular, + /// user-defined trait. + pub well_known: Option<WellKnownTrait>, +} + +/// A list of the traits that are "well known" to chalk, which means that +/// the chalk-solve crate has special, hard-coded impls for them. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub enum WellKnownTrait { + Sized, + Copy, + Clone, + Drop, + /// The trait `FnOnce<Args>` - the generic argument `Args` is always a tuple + /// corresponding to the arguments of a function implementing this trait. + /// E.g. `fn(u8, bool): FnOnce<(u8, bool)>` + FnOnce, + FnMut, + Fn, + Unsize, + Unpin, + CoerceUnsized, + DiscriminantKind, + Generator, + DispatchFromDyn, + Tuple, +} + +chalk_ir::const_visit!(WellKnownTrait); + +impl<I: Interner> TraitDatum<I> { + pub fn is_auto_trait(&self) -> bool { + self.flags.auto + } + + pub fn is_non_enumerable_trait(&self) -> bool { + self.flags.non_enumerable + } + + pub fn is_coinductive_trait(&self) -> bool { + self.flags.coinductive + } + + /// Gives access to the where clauses of the trait, quantified over the type parameters of the trait: + /// + /// ```ignore + /// trait Foo<T> where T: Debug { } + /// ^^^^^^^^^^^^^^ + /// ``` + pub fn where_clauses(&self) -> Binders<&Vec<QuantifiedWhereClause<I>>> { + self.binders.as_ref().map(|td| &td.where_clauses) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner, TypeVisitable)] +pub struct TraitDatumBound<I: Interner> { + /// Where clauses defined on the trait: + /// + /// ```ignore + /// trait Foo<T> where T: Debug { } + /// ^^^^^^^^^^^^^^ + /// ``` + pub where_clauses: Vec<QuantifiedWhereClause<I>>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct TraitFlags { + /// An "auto trait" is one that is "automatically implemented" for every + /// struct, so long as no explicit impl is given. + /// + /// Examples are `Send` and `Sync`. + pub auto: bool, + + pub marker: bool, + + /// Indicate that a trait is defined upstream (in a dependency), used during + /// coherence checking. + pub upstream: bool, + + /// A fundamental trait is a trait where adding an impl for an existing type + /// is considered a breaking change. Examples of fundamental traits are the + /// closure traits like `Fn` and `FnMut`. + /// + /// As of this writing (2020-03-27), fundamental traits are declared by the + /// unstable `#[fundamental]` attribute in rustc, and hence cannot appear + /// outside of the standard library. + pub fundamental: bool, + + /// Indicates that chalk cannot list all of the implementations of the given + /// trait, likely because it is a publicly exported trait in a library. + /// + /// Currently (2020-03-27) rustc and rust-analyzer mark all traits as + /// non_enumerable, and in the future it may become the only option. + pub non_enumerable: bool, + + pub coinductive: bool, +} + +chalk_ir::const_visit!(TraitFlags); + +/// An inline bound, e.g. `: Foo<K>` in `impl<K, T: Foo<K>> SomeType<T>`. +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)] +pub enum InlineBound<I: Interner> { + TraitBound(TraitBound<I>), + AliasEqBound(AliasEqBound<I>), +} + +#[allow(type_alias_bounds)] +pub type QuantifiedInlineBound<I: Interner> = Binders<InlineBound<I>>; + +pub trait IntoWhereClauses<I: Interner> { + type Output; + + fn into_where_clauses(&self, interner: I, self_ty: Ty<I>) -> Vec<Self::Output>; +} + +impl<I: Interner> IntoWhereClauses<I> for InlineBound<I> { + type Output = WhereClause<I>; + + /// Applies the `InlineBound` to `self_ty` and lowers to a + /// [`chalk_ir::DomainGoal`]. + /// + /// Because an `InlineBound` does not know anything about what it's binding, + /// you must provide that type as `self_ty`. + fn into_where_clauses(&self, interner: I, self_ty: Ty<I>) -> Vec<WhereClause<I>> { + match self { + InlineBound::TraitBound(b) => b.into_where_clauses(interner, self_ty), + InlineBound::AliasEqBound(b) => b.into_where_clauses(interner, self_ty), + } + } +} + +impl<I: Interner> IntoWhereClauses<I> for QuantifiedInlineBound<I> { + type Output = QuantifiedWhereClause<I>; + + fn into_where_clauses(&self, interner: I, self_ty: Ty<I>) -> Vec<QuantifiedWhereClause<I>> { + let self_ty = self_ty.shifted_in(interner); + self.map_ref(|b| b.into_where_clauses(interner, self_ty)) + .into_iter() + .collect() + } +} + +/// Represents a trait bound on e.g. a type or type parameter. +/// Does not know anything about what it's binding. +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] +pub struct TraitBound<I: Interner> { + pub trait_id: TraitId<I>, + pub args_no_self: Vec<GenericArg<I>>, +} + +impl<I: Interner> TraitBound<I> { + fn into_where_clauses(&self, interner: I, self_ty: Ty<I>) -> Vec<WhereClause<I>> { + let trait_ref = self.as_trait_ref(interner, self_ty); + vec![WhereClause::Implemented(trait_ref)] + } + + pub fn as_trait_ref(&self, interner: I, self_ty: Ty<I>) -> TraitRef<I> { + TraitRef { + trait_id: self.trait_id, + substitution: Substitution::from_iter( + interner, + iter::once(self_ty.cast(interner)).chain(self.args_no_self.iter().cloned()), + ), + } + } +} + +/// Represents an alias equality bound on e.g. a type or type parameter. +/// Does not know anything about what it's binding. +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] +pub struct AliasEqBound<I: Interner> { + pub trait_bound: TraitBound<I>, + pub associated_ty_id: AssocTypeId<I>, + /// Does not include trait parameters. + pub parameters: Vec<GenericArg<I>>, + pub value: Ty<I>, +} + +impl<I: Interner> AliasEqBound<I> { + fn into_where_clauses(&self, interner: I, self_ty: Ty<I>) -> Vec<WhereClause<I>> { + let trait_ref = self.trait_bound.as_trait_ref(interner, self_ty); + + let substitution = Substitution::from_iter( + interner, + self.parameters + .iter() + .cloned() + .chain(trait_ref.substitution.iter(interner).cloned()), + ); + + vec![ + WhereClause::Implemented(trait_ref), + WhereClause::AliasEq(AliasEq { + alias: AliasTy::Projection(ProjectionTy { + associated_ty_id: self.associated_ty_id, + substitution, + }), + ty: self.value.clone(), + }), + ] + } +} + +pub trait Anonymize<I: Interner> { + /// Utility function that converts from a list of generic arguments + /// which *have* associated data (`WithKind<I, T>`) to a list of + /// "anonymous" generic parameters that just preserves their + /// kinds (`VariableKind<I>`). Often convenient in lowering. + fn anonymize(&self) -> Vec<VariableKind<I>>; +} + +impl<I: Interner, T> Anonymize<I> for [WithKind<I, T>] { + fn anonymize(&self) -> Vec<VariableKind<I>> { + self.iter().map(|pk| pk.kind.clone()).collect() + } +} + +/// Represents an associated type declaration found inside of a trait: +/// +/// ```notrust +/// trait Foo<P1..Pn> { // P0 is Self +/// type Bar<Pn..Pm>: [bounds] +/// where +/// [where_clauses]; +/// } +/// ``` +/// +/// The meaning of each of these parts: +/// +/// * The *parameters* `P0...Pm` are all in scope for this associated type. +/// * The *bounds* `bounds` are things that the impl must prove to be true. +/// * The *where clauses* `where_clauses` are things that the impl can *assume* to be true +/// (but which projectors must prove). +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct AssociatedTyDatum<I: Interner> { + /// The trait this associated type is defined in. + pub trait_id: TraitId<I>, + + /// The ID of this associated type + pub id: AssocTypeId<I>, + + /// Name of this associated type. + pub name: I::Identifier, + + /// These binders represent the `P0...Pm` variables. The binders + /// are in the order `[Pn..Pm; P0..Pn]`. That is, the variables + /// from `Bar` come first (corresponding to the de bruijn concept + /// that "inner" binders are lower indices, although within a + /// given binder we do not have an ordering). + pub binders: Binders<AssociatedTyDatumBound<I>>, +} + +// Manual implementation to avoid I::Identifier type. +impl<I: Interner> TypeVisitable<I> for AssociatedTyDatum<I> { + fn visit_with<B>( + &self, + visitor: &mut dyn chalk_ir::visit::TypeVisitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + try_break!(self.trait_id.visit_with(visitor, outer_binder)); + try_break!(self.id.visit_with(visitor, outer_binder)); + self.binders.visit_with(visitor, outer_binder) + } +} + +/// Encodes the parts of `AssociatedTyDatum` where the parameters +/// `P0..Pm` are in scope (`bounds` and `where_clauses`). +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)] +pub struct AssociatedTyDatumBound<I: Interner> { + /// Bounds on the associated type itself. + /// + /// These must be proven by the implementer, for all possible parameters that + /// would result in a well-formed projection. + pub bounds: Vec<QuantifiedInlineBound<I>>, + + /// Where clauses that must hold for the projection to be well-formed. + pub where_clauses: Vec<QuantifiedWhereClause<I>>, +} + +impl<I: Interner> AssociatedTyDatum<I> { + /// Returns the associated ty's bounds applied to the projection type, e.g.: + /// + /// ```notrust + /// Implemented(<?0 as Foo>::Item<?1>: Sized) + /// ``` + /// + /// these quantified where clauses are in the scope of the + /// `binders` field. + pub fn bounds_on_self(&self, interner: I) -> Vec<QuantifiedWhereClause<I>> { + let (binders, assoc_ty_datum) = self.binders.as_ref().into(); + // Create a list `P0...Pn` of references to the binders in + // scope for this associated type: + let substitution = Substitution::from_iter( + interner, + binders + .iter(interner) + .enumerate() + .map(|p| p.to_generic_arg(interner)), + ); + + // The self type will be `<P0 as Foo<P1..Pn>>::Item<Pn..Pm>` etc + let self_ty = TyKind::Alias(AliasTy::Projection(ProjectionTy { + associated_ty_id: self.id, + substitution, + })) + .intern(interner); + + // Now use that as the self type for the bounds, transforming + // something like `type Bar<Pn..Pm>: Debug` into + // + // ``` + // <P0 as Foo<P1..Pn>>::Item<Pn..Pm>: Debug + // ``` + assoc_ty_datum + .bounds + .iter() + .flat_map(|b| b.into_where_clauses(interner, self_ty.clone())) + .collect() + } +} + +/// Represents the *value* of an associated type that is assigned +/// from within some impl. +/// +/// ```ignore +/// impl Iterator for Foo { +/// type Item = XXX; // <-- represents this line! +/// } +/// ``` +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] +pub struct AssociatedTyValue<I: Interner> { + /// Impl in which this associated type value is found. You might + /// need to look at this to find the generic parameters defined on + /// the impl, for example. + /// + /// ```ignore + /// impl Iterator for Foo { // <-- refers to this impl + /// type Item = XXX; // <-- (where this is self) + /// } + /// ``` + pub impl_id: ImplId<I>, + + /// Associated type being defined. + /// + /// ```ignore + /// impl Iterator for Foo { + /// type Item = XXX; // <-- (where this is self) + /// } + /// ... + /// trait Iterator { + /// type Item; // <-- refers to this declaration here! + /// } + /// ``` + pub associated_ty_id: AssocTypeId<I>, + + /// Additional binders declared on the associated type itself, + /// beyond those from the impl. This would be empty for normal + /// associated types, but non-empty for generic associated types. + /// + /// ```ignore + /// impl<T> Iterable for Vec<T> { + /// type Iter<'a> = vec::Iter<'a, T>; + /// // ^^^^ refers to these generics here + /// } + /// ``` + pub value: Binders<AssociatedTyValueBound<I>>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)] +pub struct AssociatedTyValueBound<I: Interner> { + /// Type that we normalize to. The X in `type Foo<'a> = X`. + pub ty: Ty<I>, +} + +/// Represents the bounds for an `impl Trait` type. +/// +/// ```ignore +/// opaque type T: A + B = HiddenTy; +/// ``` +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] +pub struct OpaqueTyDatum<I: Interner> { + /// The placeholder `!T` that corresponds to the opaque type `T`. + pub opaque_ty_id: OpaqueTyId<I>, + + /// The type bound to when revealed. + pub bound: Binders<OpaqueTyDatumBound<I>>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, HasInterner, TypeVisitable)] +pub struct OpaqueTyDatumBound<I: Interner> { + /// Trait bounds for the opaque type. These are bounds that the hidden type must meet. + pub bounds: Binders<Vec<QuantifiedWhereClause<I>>>, + /// Where clauses that inform well-formedness conditions for the opaque type. + /// These are conditions on the generic parameters of the opaque type which must be true + /// for a reference to the opaque type to be well-formed. + pub where_clauses: Binders<Vec<QuantifiedWhereClause<I>>>, +} + +// The movability of a generator: whether a generator contains self-references, +// causing it to be !Unpin +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Movability { + Static, + Movable, +} +chalk_ir::copy_fold!(Movability); + +/// Represents a generator type. +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, HasInterner)] +pub struct GeneratorDatum<I: Interner> { + // Can the generator be moved (is Unpin or not) + pub movability: Movability, + /// All of the nested types for this generator. The `Binder` + /// represents the types and lifetimes that this generator is generic over - + /// this behaves in the same way as `AdtDatum.binders` + pub input_output: Binders<GeneratorInputOutputDatum<I>>, +} + +/// The nested types for a generator. This always appears inside a `GeneratorDatum` +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, HasInterner)] +pub struct GeneratorInputOutputDatum<I: Interner> { + /// The generator resume type - a value of this type + /// is supplied by the caller when resuming the generator. + /// Currently, this plays no rule in goal resolution. + pub resume_type: Ty<I>, + /// The generator yield type - a value of this type + /// is supplied by the generator during a yield. + /// Currently, this plays no role in goal resolution. + pub yield_type: Ty<I>, + /// The generator return type - a value of this type + /// is supplied by the generator when it returns. + /// Currently, this plays no role in goal resolution + pub return_type: Ty<I>, + /// The upvars stored by the generator. These represent + /// types captured from the generator's environment, + /// and are stored across all yields. These types (along with the witness types) + /// are considered 'constituent types' for the purposes of determining auto trait + /// implementations - that its, a generator impls an auto trait A + /// iff all of its constituent types implement A. + pub upvars: Vec<Ty<I>>, +} + +/// The generator witness data. Each `GeneratorId` has both a `GeneratorDatum` +/// and a `GeneratorWitnessDatum` - these represent two distinct types in Rust. +/// `GeneratorWitnessDatum` is logically 'inside' a generator - this only +/// matters when we treat the witness type as a 'constituent type for the +/// purposes of determining auto trait implementations. +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, HasInterner)] +pub struct GeneratorWitnessDatum<I: Interner> { + /// This binder is identical to the `input_output` binder in `GeneratorWitness` - + /// it binds the types and lifetimes that the generator is generic over. + /// There is an additional binder inside `GeneratorWitnessExistential`, which + /// is treated specially. + pub inner_types: Binders<GeneratorWitnessExistential<I>>, +} + +/// The generator witness types, together with existentially bound lifetimes. +/// Each 'witness type' represents a type stored inside the generator across +/// a yield. When a generator type is constructed, the precise region relationships +/// found in the generator body are erased. As a result, we are left with existential +/// lifetimes - each type is parameterized over *some* lifetimes, but we do not +/// know their precise values. +/// +/// Unlike the binder in `GeneratorWitnessDatum`, this `Binder` never gets substituted +/// via an `Ty`. Instead, we handle this `Binders` specially when determining +/// auto trait impls. See `push_auto_trait_impls_generator_witness` for more details. +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, HasInterner)] +pub struct GeneratorWitnessExistential<I: Interner> { + pub types: Binders<Vec<Ty<I>>>, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +pub enum Polarity { + Positive, + Negative, +} + +chalk_ir::const_visit!(Polarity); + +impl Polarity { + pub fn is_positive(&self) -> bool { + match *self { + Polarity::Positive => true, + Polarity::Negative => false, + } + } +} + +/// Indicates the "most permissive" Fn-like trait that the closure implements. +/// If the closure kind for a closure is FnMut, for example, then the closure +/// implements FnMut and FnOnce. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +pub enum ClosureKind { + Fn, + FnMut, + FnOnce, +} diff --git a/vendor/chalk-solve/src/solve.rs b/vendor/chalk-solve/src/solve.rs new file mode 100644 index 000000000..0734fc53e --- /dev/null +++ b/vendor/chalk-solve/src/solve.rs @@ -0,0 +1,350 @@ +use crate::RustIrDatabase; +use chalk_derive::HasInterner; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use std::fmt; +use tracing::debug; + +pub mod truncate; + +/// A (possible) solution for a proposed goal. +#[derive(Clone, Debug, PartialEq, Eq, HasInterner)] +pub enum Solution<I: Interner> { + /// The goal indeed holds, and there is a unique value for all existential + /// variables. In this case, we also record a set of lifetime constraints + /// which must also hold for the goal to be valid. + Unique(Canonical<ConstrainedSubst<I>>), + + /// The goal may be provable in multiple ways, but regardless we may have some guidance + /// for type inference. In this case, we don't return any lifetime + /// constraints, since we have not "committed" to any particular solution + /// yet. + Ambig(Guidance<I>), +} + +/// When a goal holds ambiguously (e.g., because there are multiple possible +/// solutions), we issue a set of *guidance* back to type inference. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Guidance<I: Interner> { + /// The existential variables *must* have the given values if the goal is + /// ever to hold, but that alone isn't enough to guarantee the goal will + /// actually hold. + Definite(Canonical<Substitution<I>>), + + /// There are multiple plausible values for the existentials, but the ones + /// here are suggested as the preferred choice heuristically. These should + /// be used for inference fallback only. + Suggested(Canonical<Substitution<I>>), + + /// There's no useful information to feed back to type inference + Unknown, +} + +impl<I: Interner> Solution<I> { + /// There are multiple candidate solutions, which may or may not agree on + /// the values for existential variables; attempt to combine them. This + /// operation does not depend on the order of its arguments. + /// + /// This actually isn't as precise as it could be, in two ways: + /// + /// a. It might be that while there are multiple distinct candidates, they + /// all agree about *some things*. To be maximally precise, we would + /// compute the intersection of what they agree on. It's not clear though + /// that this is actually what we want Rust's inference to do, and it's + /// certainly not what it does today. + /// + /// b. There might also be an ambiguous candidate and a successful candidate, + /// both with the same refined-goal. In that case, we could probably claim + /// success, since if the conditions of the ambiguous candidate were met, + /// we know the success would apply. Example: `?0: Clone` yields ambiguous + /// candidate `Option<?0>: Clone` and successful candidate `Option<?0>: + /// Clone`. + /// + /// But you get the idea. + pub fn combine(self, other: Solution<I>, interner: I) -> Solution<I> { + use self::Guidance::*; + + if self == other { + return self; + } + + // Special case hack: if one solution is "true" without any constraints, + // that is always the combined result. + // + // This is not as general as it could be: ideally, if we had one solution + // that is Unique with a simpler substitution than the other one, or region constraints + // which are a subset, we'd combine them. + if self.is_trivial_and_always_true(interner) { + return self; + } + if other.is_trivial_and_always_true(interner) { + return other; + } + + debug!( + "combine {} with {}", + self.display(interner), + other.display(interner) + ); + + // Otherwise, always downgrade to Ambig: + + let guidance = match (self.into_guidance(), other.into_guidance()) { + (Definite(ref subst1), Definite(ref subst2)) if subst1 == subst2 => { + Definite(subst1.clone()) + } + (Suggested(ref subst1), Suggested(ref subst2)) if subst1 == subst2 => { + Suggested(subst1.clone()) + } + _ => Unknown, + }; + Solution::Ambig(guidance) + } + + pub fn is_trivial_and_always_true(&self, interner: I) -> bool { + match self { + Solution::Unique(constrained_subst) => { + constrained_subst.value.subst.is_identity_subst(interner) + && constrained_subst.value.constraints.is_empty(interner) + } + Solution::Ambig(_) => false, + } + } + + /// View this solution purely in terms of type inference guidance + pub fn into_guidance(self) -> Guidance<I> { + match self { + Solution::Unique(constrained) => Guidance::Definite(Canonical { + value: constrained.value.subst, + binders: constrained.binders, + }), + Solution::Ambig(guidance) => guidance, + } + } + + /// Extract a constrained substitution from this solution, even if ambiguous. + pub fn constrained_subst(&self, interner: I) -> Option<Canonical<ConstrainedSubst<I>>> { + match *self { + Solution::Unique(ref constrained) => Some(constrained.clone()), + Solution::Ambig(Guidance::Definite(ref canonical)) + | Solution::Ambig(Guidance::Suggested(ref canonical)) => { + let value = ConstrainedSubst { + subst: canonical.value.clone(), + constraints: Constraints::empty(interner), + }; + Some(Canonical { + value, + binders: canonical.binders.clone(), + }) + } + Solution::Ambig(_) => None, + } + } + + /// Determine whether this solution contains type information that *must* + /// hold, and returns the subst in that case. + pub fn definite_subst(&self, interner: I) -> Option<Canonical<ConstrainedSubst<I>>> { + match self { + Solution::Unique(constrained) => Some(constrained.clone()), + Solution::Ambig(Guidance::Definite(canonical)) => { + let value = ConstrainedSubst { + subst: canonical.value.clone(), + constraints: Constraints::empty(interner), + }; + Some(Canonical { + value, + binders: canonical.binders.clone(), + }) + } + _ => None, + } + } + + pub fn is_unique(&self) -> bool { + matches!(*self, Solution::Unique(..)) + } + + pub fn is_ambig(&self) -> bool { + matches!(*self, Solution::Ambig(_)) + } + + pub fn display(&self, interner: I) -> SolutionDisplay<'_, I> { + SolutionDisplay { + solution: self, + interner, + } + } +} + +pub struct SolutionDisplay<'a, I: Interner> { + solution: &'a Solution<I>, + interner: I, +} + +impl<'a, I: Interner> fmt::Display for SolutionDisplay<'a, I> { + #[rustfmt::skip] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + let SolutionDisplay { solution, interner } = self; + match solution { + // If a `Unique` solution has no associated data, omit the trailing semicolon. + // This makes blessed test output nicer to read. + Solution::Unique(Canonical { binders, value: ConstrainedSubst { subst, constraints } } ) + if interner.constraints_data(constraints.interned()).is_empty() + && interner.substitution_data(subst.interned()).is_empty() + && interner.canonical_var_kinds_data(binders.interned()).is_empty() + => write!(f, "Unique"), + + Solution::Unique(constrained) => write!(f, "Unique; {}", constrained.display(*interner)), + + Solution::Ambig(Guidance::Definite(subst)) => write!( + f, + "Ambiguous; definite substitution {}", + subst.display(*interner) + ), + Solution::Ambig(Guidance::Suggested(subst)) => write!( + f, + "Ambiguous; suggested substitution {}", + subst.display(*interner) + ), + Solution::Ambig(Guidance::Unknown) => write!(f, "Ambiguous; no inference guidance"), + } + } +} + +#[derive(Debug)] +pub enum SubstitutionResult<S> { + Definite(S), + Ambiguous(S), + Floundered, +} + +impl<S> SubstitutionResult<S> { + pub fn as_ref(&self) -> SubstitutionResult<&S> { + match self { + SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(subst), + SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(subst), + SubstitutionResult::Floundered => SubstitutionResult::Floundered, + } + } + pub fn map<U, F: FnOnce(S) -> U>(self, f: F) -> SubstitutionResult<U> { + match self { + SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(f(subst)), + SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(f(subst)), + SubstitutionResult::Floundered => SubstitutionResult::Floundered, + } + } +} + +impl<S: fmt::Display> fmt::Display for SubstitutionResult<S> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SubstitutionResult::Definite(subst) => write!(fmt, "{}", subst), + SubstitutionResult::Ambiguous(subst) => write!(fmt, "Ambiguous({})", subst), + SubstitutionResult::Floundered => write!(fmt, "Floundered"), + } + } +} + +/// Finds the solution to "goals", or trait queries -- i.e., figures +/// out what sets of types implement which traits. Also, between +/// queries, this struct stores the cached state from previous solver +/// attempts, which can then be re-used later. +pub trait Solver<I: Interner> +where + Self: fmt::Debug, +{ + /// Attempts to solve the given goal, which must be in canonical + /// form. Returns a unique solution (if one exists). This will do + /// only as much work towards `goal` as it has to (and that work + /// is cached for future attempts). + /// + /// # Parameters + /// + /// - `program` -- defines the program clauses in scope. + /// - **Important:** You must supply the same set of program clauses + /// each time you invoke `solve`, as otherwise the cached data may be + /// invalid. + /// - `goal` the goal to solve + /// + /// # Returns + /// + /// - `None` is the goal cannot be proven. + /// - `Some(solution)` if we succeeded in finding *some* answers, + /// although `solution` may reflect ambiguity and unknowns. + fn solve( + &mut self, + program: &dyn RustIrDatabase<I>, + goal: &UCanonical<InEnvironment<Goal<I>>>, + ) -> Option<Solution<I>>; + + /// Attempts to solve the given goal, which must be in canonical + /// form. Returns a unique solution (if one exists). This will do + /// only as much work towards `goal` as it has to (and that work + /// is cached for future attempts). In addition, the solving of the + /// goal can be limited by returning `false` from `should_continue`. + /// + /// # Parameters + /// + /// - `program` -- defines the program clauses in scope. + /// - **Important:** You must supply the same set of program clauses + /// each time you invoke `solve`, as otherwise the cached data may be + /// invalid. + /// - `goal` the goal to solve + /// - `should_continue` if `false` is returned, the no further solving + /// will be done. A `Guidance(Suggested(...))` will be returned a + /// `Solution`, using any answers that were generated up to that point. + /// + /// # Returns + /// + /// - `None` is the goal cannot be proven. + /// - `Some(solution)` if we succeeded in finding *some* answers, + /// although `solution` may reflect ambiguity and unknowns. + fn solve_limited( + &mut self, + program: &dyn RustIrDatabase<I>, + goal: &UCanonical<InEnvironment<Goal<I>>>, + should_continue: &dyn std::ops::Fn() -> bool, + ) -> Option<Solution<I>>; + + /// Attempts to solve the given goal, which must be in canonical + /// form. Provides multiple solutions to function `f`. This will do + /// only as much work towards `goal` as it has to (and that work + /// is cached for future attempts). + /// + /// # Parameters + /// + /// - `program` -- defines the program clauses in scope. + /// - **Important:** You must supply the same set of program clauses + /// each time you invoke `solve`, as otherwise the cached data may be + /// invalid. + /// - `goal` the goal to solve + /// - `f` -- function to proceed solution. New solutions will be generated + /// while function returns `true`. + /// - first argument is solution found + /// - second argument is the next solution present + /// - returns true if next solution should be handled + /// + /// # Returns + /// + /// - `true` all solutions were processed with the function. + /// - `false` the function returned `false` and solutions were interrupted. + fn solve_multiple( + &mut self, + program: &dyn RustIrDatabase<I>, + goal: &UCanonical<InEnvironment<Goal<I>>>, + f: &mut dyn FnMut(SubstitutionResult<Canonical<ConstrainedSubst<I>>>, bool) -> bool, + ) -> bool; + + /// A convenience method for when one doesn't need the actual solution, + /// only whether or not one exists. + fn has_unique_solution( + &mut self, + program: &dyn RustIrDatabase<I>, + goal: &UCanonical<InEnvironment<Goal<I>>>, + ) -> bool { + match self.solve(program, goal) { + Some(sol) => sol.is_unique(), + None => false, + } + } +} diff --git a/vendor/chalk-solve/src/solve/test/bench.rs b/vendor/chalk-solve/src/solve/test/bench.rs new file mode 100644 index 000000000..6ef6eb1f9 --- /dev/null +++ b/vendor/chalk-solve/src/solve/test/bench.rs @@ -0,0 +1,111 @@ +//! Benchmarking tests. + +extern crate test; +use self::test::Bencher; + +use crate::db::ChalkDatabase; +use crate::query::{ProgramSolverChoice, ProgramText}; +use chalk_solve::SolverChoice; +use ir; +use std::sync::Arc; + +use super::{assert_result, parse_and_lower_goal, parse_and_lower_program}; + +fn run_bench( + program_text: &str, + solver_choice: SolverChoice, + goal_text: &str, + bencher: &mut Bencher, + expected: &str, +) { + ChalkDatabase::with_program(Arc::new(program_text.to_string()), solver_choice, |db| { + let program = db.lowered_program().unwrap(); + let env = db.environment().unwrap(); + ir::tls::set_current_program(&program, || { + let goal = parse_and_lower_goal(&program, goal_text).unwrap(); + let peeled_goal = goal.into_peeled_goal(); + + // Execute once to get an expected result. + let result = solver_choice.solve_root_goal(&env, &peeled_goal); + + // Check expectation. + assert_result(&result, expected); + + // Then do it many times to measure time. + bencher.iter(|| solver_choice.solve_root_goal(&env, &peeled_goal)); + }); + }); +} + +const CYCLEY: &str = " +trait AsRef<T> { } +trait Clone { } +trait Copy where Self: Clone { } +trait Sized { } + +struct i32 { } +impl Copy for i32 { } +impl Clone for i32 { } +impl Sized for i32 { } + +struct u32 { } +impl Copy for u32 { } +impl Clone for u32 { } +impl Sized for u32 { } + +struct Rc<T> { } +impl<T> Clone for Rc<T> { } +impl<T> Sized for Rc<T> { } + +struct Box<T> { } +impl<T> AsRef<T> for Box<T> where T: Sized { } +impl<T> Clone for Box<T> where T: Clone { } +impl<T> Sized for Box<T> { } + +// Meant to be [T] +struct Slice<T> where T: Sized { } +impl<T> Sized for Slice<T> { } +impl<T> AsRef<Slice<T>> for Slice<T> where T: Sized { } + +struct Vec<T> where T: Sized { } +impl<T> AsRef<Slice<T>> for Vec<T> where T: Sized { } +impl<T> AsRef<Vec<T>> for Vec<T> where T: Sized { } +impl<T> Clone for Vec<T> where T: Clone, T: Sized { } +impl<T> Sized for Vec<T> where T: Sized { } + +trait SliceExt + where <Self as SliceExt>::Item: Clone +{ + type Item; +} + +impl<T> SliceExt for Slice<T> + where T: Clone +{ + type Item = T; +} +"; + +const CYCLEY_GOAL: &str = " +forall<T> { + if ( + <Slice<T> as SliceExt>::Item: Clone; + <Slice<T> as SliceExt>::Item: Sized; + T: Clone; + T: Sized + ) { + T: Sized + } +} +"; + +#[bench] +fn cycley_slg(b: &mut Bencher) { + run_bench( + CYCLEY, + SolverChoice::SLG { max_size: 20 }, + CYCLEY_GOAL, + b, + "Unique", + ); +} diff --git a/vendor/chalk-solve/src/solve/truncate.rs b/vendor/chalk-solve/src/solve/truncate.rs new file mode 100644 index 000000000..1ed47b94f --- /dev/null +++ b/vendor/chalk-solve/src/solve/truncate.rs @@ -0,0 +1,134 @@ +//! + +use crate::infer::InferenceTable; +use chalk_ir::interner::Interner; +use chalk_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use chalk_ir::*; +use std::cmp::max; +use std::ops::ControlFlow; + +/// "Truncation" (called "abstraction" in the papers referenced below) +/// refers to the act of modifying a goal or answer that has become +/// too large in order to guarantee termination. +/// +/// Currently we don't perform truncation (but it might me readded later). +/// +/// Citations: +/// +/// - Terminating Evaluation of Logic Programs with Finite Three-Valued Models +/// - Riguzzi and Swift; ACM Transactions on Computational Logic 2013 +/// - Radial Restraint +/// - Grosof and Swift; 2013 +pub fn needs_truncation<I: Interner>( + interner: I, + infer: &mut InferenceTable<I>, + max_size: usize, + value: impl TypeVisitable<I>, +) -> bool { + let mut visitor = TySizeVisitor::new(interner, infer); + value.visit_with(&mut visitor, DebruijnIndex::INNERMOST); + + visitor.max_size > max_size +} + +struct TySizeVisitor<'infer, I: Interner> { + interner: I, + infer: &'infer mut InferenceTable<I>, + size: usize, + depth: usize, + max_size: usize, +} + +impl<'infer, I: Interner> TySizeVisitor<'infer, I> { + fn new(interner: I, infer: &'infer mut InferenceTable<I>) -> Self { + Self { + interner, + infer, + size: 0, + depth: 0, + max_size: 0, + } + } +} + +impl<'infer, I: Interner> TypeVisitor<I> for TySizeVisitor<'infer, I> { + type BreakTy = (); + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> { + self + } + + fn visit_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> ControlFlow<()> { + if let Some(normalized_ty) = self.infer.normalize_ty_shallow(self.interner, ty) { + normalized_ty.visit_with(self, outer_binder); + return ControlFlow::Continue(()); + } + + self.size += 1; + self.max_size = max(self.size, self.max_size); + + self.depth += 1; + ty.super_visit_with(self, outer_binder); + self.depth -= 1; + + // When we get back to the first invocation, clear the counters. + // We process each outermost type independently. + if self.depth == 0 { + self.size = 0; + } + ControlFlow::Continue(()) + } + + fn interner(&self) -> I { + self.interner + } +} + +#[cfg(test)] +mod tests { + use super::*; + use chalk_integration::{arg, ty}; + + #[test] + fn one_type() { + use chalk_integration::interner::ChalkIr; + let interner = ChalkIr; + let mut table = InferenceTable::<chalk_integration::interner::ChalkIr>::new(); + let _u1 = table.new_universe(); + + // Vec<Vec<Vec<Vec<T>>>> + let ty0 = ty!(apply (item 0) + (apply (item 0) + (apply (item 0) + (apply (item 0) + (placeholder 1))))); + + let mut visitor = TySizeVisitor::new(interner, &mut table); + ty0.visit_with(&mut visitor, DebruijnIndex::INNERMOST); + assert!(visitor.max_size == 5); + } + + #[test] + fn multiple_types() { + use chalk_integration::interner::ChalkIr; + let interner = ChalkIr; + let mut table = InferenceTable::<chalk_integration::interner::ChalkIr>::new(); + let _u1 = table.new_universe(); + + // Vec<Vec<Vec<Vec<T>>>> + let ty0 = ty!(apply (item 0) + (apply (item 0) + (apply (item 0) + (apply (item 0) + (placeholder 1))))); + + let ty1 = ty!(apply (item 0) + (apply (item 0) + (apply (item 0) + (placeholder 1)))); + + let mut visitor = TySizeVisitor::new(interner, &mut table); + vec![&ty0, &ty1].visit_with(&mut visitor, DebruijnIndex::INNERMOST); + assert!(visitor.max_size == 5); + } +} diff --git a/vendor/chalk-solve/src/split.rs b/vendor/chalk-solve/src/split.rs new file mode 100644 index 000000000..bea24044d --- /dev/null +++ b/vendor/chalk-solve/src/split.rs @@ -0,0 +1,199 @@ +use crate::rust_ir::*; +use crate::RustIrDatabase; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use std::sync::Arc; +use tracing::{debug, instrument}; + +/// Methods for splitting up the projections for associated types from +/// the surrounding context. +pub trait Split<I: Interner>: RustIrDatabase<I> { + /// Given a projection of an associated type, split the type + /// parameters into those that come from the *trait* and those + /// that come from the *associated type itself*. So e.g. if you + /// have `(Iterator::Item)<F>`, this would return `([F], [])`, + /// since `Iterator::Item` is not generic and hence doesn't have + /// any type parameters itself. + fn split_projection<'p>( + &self, + projection: &'p ProjectionTy<I>, + ) -> ( + Arc<AssociatedTyDatum<I>>, + &'p [GenericArg<I>], + &'p [GenericArg<I>], + ) { + let interner = self.interner(); + let ProjectionTy { + associated_ty_id, + ref substitution, + } = *projection; + let parameters = substitution.as_slice(interner); + let associated_ty_data = &self.associated_ty_data(associated_ty_id); + let (trait_params, other_params) = + self.split_associated_ty_parameters(parameters, &**associated_ty_data); + (associated_ty_data.clone(), trait_params, other_params) + } + + /// Given a projection `<P0 as Trait<P1..Pn>>::Item<Pn..Pm>`, + /// returns the trait parameters `[P0..Pn]` (see + /// `split_projection`). + fn trait_parameters_from_projection<'p>( + &self, + projection: &'p ProjectionTy<I>, + ) -> &'p [GenericArg<I>] { + let (_, trait_params, _) = self.split_projection(projection); + trait_params + } + + /// Given a projection `<P0 as Trait<P1..Pn>>::Item<Pn..Pm>`, + /// returns the trait parameters `[P0..Pn]` (see + /// `split_projection`). + fn trait_ref_from_projection(&self, projection: &ProjectionTy<I>) -> TraitRef<I> { + let interner = self.interner(); + let (associated_ty_data, trait_params, _) = self.split_projection(projection); + TraitRef { + trait_id: associated_ty_data.trait_id, + substitution: Substitution::from_iter(interner, trait_params), + } + } + + /// Given the full set of parameters (or binders) for an + /// associated type *value* (which appears in an impl), splits + /// them into the substitutions for the *impl* and those for the + /// *associated type*. + /// + /// # Example + /// + /// ```ignore (example) + /// impl<T> Iterable for Vec<T> { + /// type Iter<'a>; + /// } + /// ``` + /// + /// in this example, the full set of parameters would be `['x, + /// Y]`, where `'x` is the value for `'a` and `Y` is the value for + /// `T`. + /// + /// # Returns + /// + /// Returns the pair of: + /// + /// * the parameters for the impl (`[Y]`, in our example) + /// * the parameters for the associated type value (`['a]`, in our example) + fn split_associated_ty_value_parameters<'p, P>( + &self, + parameters: &'p [P], + associated_ty_value: &AssociatedTyValue<I>, + ) -> (&'p [P], &'p [P]) { + let interner = self.interner(); + let impl_datum = self.impl_datum(associated_ty_value.impl_id); + let impl_params_len = impl_datum.binders.len(interner); + assert!(parameters.len() >= impl_params_len); + + // the impl parameters are a suffix + // + // [ P0..Pn, Pn...Pm ] + // ^^^^^^^ impl parameters + let split_point = parameters.len() - impl_params_len; + let (other_params, impl_params) = parameters.split_at(split_point); + (impl_params, other_params) + } + + /// Given the full set of parameters for an associated type *value* + /// (which appears in an impl), returns the trait reference + /// and projection that are being satisfied by that value. + /// + /// # Example + /// + /// ```ignore (example) + /// impl<T> Iterable for Vec<T> { + /// type Iter<'a>; + /// } + /// ``` + /// + /// Here we expect the full set of parameters for `Iter`, which + /// would be `['x, Y]`, where `'x` is the value for `'a` and `Y` + /// is the value for `T`. + /// + /// Returns the pair of: + /// + /// * the parameters that apply to the impl (`Y`, in our example) + /// * the projection `<Vec<Y> as Iterable>::Iter<'x>` + #[instrument(level = "debug", skip(self, associated_ty_value))] + fn impl_parameters_and_projection_from_associated_ty_value<'p>( + &self, + parameters: &'p [GenericArg<I>], + associated_ty_value: &AssociatedTyValue<I>, + ) -> (&'p [GenericArg<I>], ProjectionTy<I>) { + let interner = self.interner(); + + let impl_datum = self.impl_datum(associated_ty_value.impl_id); + + // Get the trait ref from the impl -- so in our example above + // this would be `Box<!T>: Foo`. + let (impl_parameters, atv_parameters) = + self.split_associated_ty_value_parameters(parameters, associated_ty_value); + let trait_ref = { + let opaque_ty_ref = impl_datum.binders.map_ref(|b| &b.trait_ref).cloned(); + debug!(?opaque_ty_ref); + opaque_ty_ref.substitute(interner, impl_parameters) + }; + + // Create the parameters for the projection -- in our example + // above, this would be `['!a, Box<!T>]`, corresponding to + // `<Box<!T> as Foo>::Item<'!a>` + let projection_substitution = Substitution::from_iter( + interner, + atv_parameters + .iter() + .chain(trait_ref.substitution.iter(interner)) + .cloned(), + ); + + let projection = ProjectionTy { + associated_ty_id: associated_ty_value.associated_ty_id, + substitution: projection_substitution, + }; + + debug!(?impl_parameters, ?trait_ref, ?projection); + + (impl_parameters, projection) + } + + /// Given the full set of parameters (or binders) for an + /// associated type datum (the one appearing in a trait), splits + /// them into the parameters for the *trait* and those for the + /// *associated type*. + /// + /// # Example + /// + /// ```ignore (example) + /// trait Foo<T> { + /// type Assoc<'a>; + /// } + /// ``` + /// + /// in this example, the full set of parameters would be `['x, + /// Y]`, where `'x` is the value for `'a` and `Y` is the value for + /// `T`. + /// + /// # Returns + /// + /// Returns the tuple of: + /// + /// * the parameters for the impl (`[Y]`, in our example) + /// * the parameters for the associated type value (`['a]`, in our example) + fn split_associated_ty_parameters<'p, P>( + &self, + parameters: &'p [P], + associated_ty_datum: &AssociatedTyDatum<I>, + ) -> (&'p [P], &'p [P]) { + let trait_datum = &self.trait_datum(associated_ty_datum.trait_id); + let trait_num_params = trait_datum.binders.len(self.interner()); + let split_point = parameters.len() - trait_num_params; + let (other_params, trait_params) = parameters.split_at(split_point); + (trait_params, other_params) + } +} + +impl<DB: RustIrDatabase<I> + ?Sized, I: Interner> Split<I> for DB {} diff --git a/vendor/chalk-solve/src/wf.rs b/vendor/chalk-solve/src/wf.rs new file mode 100644 index 000000000..d552cdde7 --- /dev/null +++ b/vendor/chalk-solve/src/wf.rs @@ -0,0 +1,1202 @@ +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, + } + } +} |