5319: Chalk upgrade r=flodiebold a=flodiebold

 - upgrade Chalk
 - make use of Chalk's `Unsize` impls, remove ours
 - use Chalk's built-in array type
 - search efficiently for impls for an int/float variable
 - output Chalk tracing logs in hir_ty tests

Fixes #2534.
Fixes #5057.
Fixes #4374.
Fixes #4281.

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
Co-authored-by: Florian Diebold <florian.diebold@freiheit.com>
This commit is contained in:
bors[bot] 2020-07-12 20:20:36 +00:00 committed by GitHub
commit 39e049d2a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 428 additions and 361 deletions

101
Cargo.lock generated
View file

@ -33,6 +33,15 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "anyhow"
version = "1.0.31"
@ -51,6 +60,17 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi 0.3.9",
]
[[package]]
name = "autocfg"
version = "1.0.0"
@ -124,9 +144,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chalk-derive"
version = "0.15.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7379caa72d04103fcfd9bde5642b816f58e3ffd6a0d39347e9e35a066648226"
checksum = "9396f12a23b1a40d5019aa81bc0cbd7ccd2c9736d6bc4afc95868533c2346dcb"
dependencies = [
"proc-macro2",
"quote",
@ -134,36 +154,36 @@ dependencies = [
"synstructure",
]
[[package]]
name = "chalk-engine"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8afe48b5663504b485791ab4fae69cf4864869a71ceec9c758fd4d03423722"
dependencies = [
"chalk-derive",
"chalk-ir",
"rustc-hash",
"tracing",
]
[[package]]
name = "chalk-ir"
version = "0.15.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "231e391a03c1fc45874171d92be9542efedc939bac59d9501ee28b9521feb406"
checksum = "87e9c67d500717d65ede27affb7ae40efe240d86fbefff1006fe0ffb62d4caf9"
dependencies = [
"chalk-derive",
"lazy_static",
]
[[package]]
name = "chalk-solve"
version = "0.15.0"
name = "chalk-recursive"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72c969c0fd06ad50538253327ca3445ff02cc9d0209f94c3cbf198ad9d365b48"
checksum = "a8fd2ac0fc06c857b95614d229bbe8ea317d1d94a7e8b9442a3f05c9a2c2d5f4"
dependencies = [
"chalk-derive",
"chalk-ir",
"chalk-solve",
"rustc-hash",
"tracing",
]
[[package]]
name = "chalk-solve"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a79166f2405c1e51eadcc1344f5ee833c7b391532dd78f64a0731a9a123cc58"
dependencies = [
"chalk-derive",
"chalk-engine",
"chalk-ir",
"ena",
"itertools",
@ -171,6 +191,7 @@ dependencies = [
"rustc-hash",
"tracing",
"tracing-subscriber",
"tracing-tree",
]
[[package]]
@ -971,6 +992,16 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "quanta"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7a1905379198075914bc93d32a5465c40474f90a078bb13439cb00c547bcc"
dependencies = [
"libc",
"winapi 0.3.9",
]
[[package]]
name = "quote"
version = "1.0.7"
@ -1103,6 +1134,7 @@ version = "0.1.0"
dependencies = [
"arrayvec",
"chalk-ir",
"chalk-recursive",
"chalk-solve",
"ena",
"expect",
@ -1120,6 +1152,9 @@ dependencies = [
"smallvec",
"stdx",
"test_utils",
"tracing",
"tracing-subscriber",
"tracing-tree",
]
[[package]]
@ -1722,6 +1757,15 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.1.13"
@ -1856,7 +1900,7 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c72c8cf3ec4ed69fef614d011a5ae4274537a8a8c59133558029bd731eb71659"
dependencies = [
"ansi_term",
"ansi_term 0.11.0",
"chrono",
"lazy_static",
"matchers",
@ -1870,6 +1914,21 @@ dependencies = [
"tracing-serde",
]
[[package]]
name = "tracing-tree"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a389731c9e6c56fef11e438e5b6afae861d5bc301c8b4bdca8d19f0e830d82"
dependencies = [
"ansi_term 0.12.1",
"atty",
"chrono",
"quanta",
"termcolor",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "unicode-bidi"
version = "0.3.4"

View file

@ -27,9 +27,14 @@ test_utils = { path = "../test_utils" }
scoped-tls = "1"
chalk-solve = { version = "0.15.0" }
chalk-ir = { version = "0.15.0" }
chalk-solve = { version = "0.17.0" }
chalk-ir = { version = "0.17.0" }
chalk-recursive = { version = "0.17.0" }
[dev-dependencies]
insta = "0.16.0"
expect = { path = "../expect" }
tracing = "0.1"
tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
tracing-tree = { version = "0.1.3" }

View file

@ -6,8 +6,10 @@ use std::{iter, sync::Arc};
use arrayvec::ArrayVec;
use hir_def::{
lang_item::LangItemTarget, type_ref::Mutability, AssocContainerId, AssocItemId, FunctionId,
HasModule, ImplId, Lookup, TraitId,
builtin_type::{IntBitness, Signedness},
lang_item::LangItemTarget,
type_ref::Mutability,
AssocContainerId, AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId,
};
use hir_expand::name::Name;
use ra_db::CrateId;
@ -16,9 +18,12 @@ use rustc_hash::{FxHashMap, FxHashSet};
use super::Substs;
use crate::{
autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy,
Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor,
TypeWalk,
autoderef,
db::HirDatabase,
primitive::{FloatBitness, FloatTy, IntTy},
utils::all_super_traits,
ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind,
TypeCtor, TypeWalk,
};
/// This is used as a key for indexing impls.
@ -39,6 +44,62 @@ impl TyFingerprint {
}
}
pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::X8,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::X16,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::X32,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::X64,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::X128,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::Xsize,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::X8,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::X16,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::X32,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::X64,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::X128,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::Xsize,
})),
];
pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 })),
TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 })),
];
/// Trait impls defined or available in some crate.
#[derive(Debug, Eq, PartialEq)]
pub struct TraitImpls {

View file

@ -37,6 +37,15 @@ use crate::{
// against snapshots of the expected results using insta. Use cargo-insta to
// update the snapshots.
fn setup_tracing() -> tracing::subscriber::DefaultGuard {
use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
use tracing_tree::HierarchicalLayer;
let filter = EnvFilter::from_env("CHALK_DEBUG");
let layer = HierarchicalLayer::default().with_indent_amount(2).with_writer(std::io::stderr);
let subscriber = Registry::default().with(filter).with(layer);
tracing::subscriber::set_default(subscriber)
}
fn check_types(ra_fixture: &str) {
check_types_impl(ra_fixture, false)
}
@ -46,6 +55,7 @@ fn check_types_source_code(ra_fixture: &str) {
}
fn check_types_impl(ra_fixture: &str, display_source: bool) {
let _tracing = setup_tracing();
let db = TestDB::with_files(ra_fixture);
let mut checked_one = false;
for (file_id, annotations) in db.extract_annotations() {
@ -86,6 +96,7 @@ fn infer(ra_fixture: &str) -> String {
}
fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let _tracing = setup_tracing();
let (db, file_id) = TestDB::with_single_file(content);
let mut buf = String::new();

View file

@ -662,7 +662,53 @@ fn test() {
}
#[test]
fn coerce_unsize_trait_object() {
fn coerce_unsize_trait_object_simple() {
assert_snapshot!(
infer_with_mismatches(r#"
#[lang = "sized"]
pub trait Sized {}
#[lang = "unsize"]
pub trait Unsize<T> {}
#[lang = "coerce_unsized"]
pub trait CoerceUnsized<T> {}
impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
trait Foo<T, U> {}
trait Bar<U, T, X>: Foo<T, U> {}
trait Baz<T, X>: Bar<usize, T, X> {}
struct S<T, X>;
impl<T, X> Foo<T, usize> for S<T, X> {}
impl<T, X> Bar<usize, T, X> for S<T, X> {}
impl<T, X> Baz<T, X> for S<T, X> {}
fn test() {
let obj: &dyn Baz<i8, i16> = &S;
let obj: &dyn Bar<_, i8, i16> = &S;
let obj: &dyn Foo<i8, _> = &S;
}
"#, true),
@r###"
424..539 '{ ... &S; }': ()
434..437 'obj': &dyn Baz<i8, i16>
459..461 '&S': &S<i8, i16>
460..461 'S': S<i8, i16>
471..474 'obj': &dyn Bar<usize, i8, i16>
499..501 '&S': &S<i8, i16>
500..501 'S': S<i8, i16>
511..514 'obj': &dyn Foo<i8, usize>
534..536 '&S': &S<i8, {unknown}>
535..536 'S': S<i8, {unknown}>
"###
);
}
#[test]
// The rust reference says this should be possible, but rustc doesn't implement
// it. We used to support it, but Chalk doesn't.
#[ignore]
fn coerce_unsize_trait_object_to_trait_object() {
assert_snapshot!(
infer_with_mismatches(r#"
#[lang = "sized"]
@ -735,16 +781,17 @@ impl D for S {}
fn test() {
let obj: &dyn D = &S;
let obj: &dyn A = obj;
let obj: &dyn A = &S;
}
"#, true),
@r###"
328..384 '{ ...obj; }': ()
328..383 '{ ... &S; }': ()
338..341 'obj': &dyn D
352..354 '&S': &S
353..354 'S': S
364..367 'obj': &dyn A
378..381 'obj': &dyn D
378..380 '&S': &S
379..380 'S': S
"###
);
}

View file

@ -1991,6 +1991,28 @@ fn test() {
);
}
#[test]
fn fn_item_fn_trait() {
check_types(
r#"
#[lang = "fn_once"]
trait FnOnce<Args> {
type Output;
}
struct S;
fn foo() -> S {}
fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() }
fn test() {
takes_closure(foo);
} //^^^^^^^^^^^^^^^^^^ S
"#,
);
}
#[test]
fn unselected_projection_in_trait_env_1() {
check_types(
@ -3000,74 +3022,47 @@ fn infer_box_fn_arg() {
#[test]
fn infer_dyn_fn_output() {
assert_snapshot!(
infer(
r#"
//- /lib.rs deps:std
check_types(
r#"
#[lang = "fn_once"]
pub trait FnOnce<Args> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
#[lang = "fn_once"]
pub trait FnOnce<Args> {
type Output;
#[lang = "fn"]
pub trait Fn<Args>: FnOnce<Args> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
#[lang = "fn"]
pub trait Fn<Args>:FnOnce<Args> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
#[lang = "deref"]
pub trait Deref {
type Target: ?Sized;
fn deref(&self) -> &Self::Target;
}
#[lang = "owned_box"]
pub struct Box<T: ?Sized> {
inner: *mut T,
}
impl<T: ?Sized> Deref for Box<T> {
type Target = T;
fn deref(&self) -> &T {
&self.inner
}
}
fn foo() {
let f: Box<dyn Fn() -> i32> = box(|| 5);
let x = f();
}
"#
),
@r###"
100..104 'self': Self
106..110 'args': Args
219..223 'self': &Self
225..229 'args': Args
333..337 'self': &Self
503..507 'self': &Box<T>
515..542 '{ ... }': &T
525..536 '&self.inner': &*mut T
526..530 'self': &Box<T>
526..536 'self.inner': *mut T
555..620 '{ ...f(); }': ()
565..566 'f': Box<dyn Fn<(), Output = i32>>
591..600 'box(|| 5)': Box<|| -> i32>
595..599 '|| 5': || -> i32
598..599 '5': i32
610..611 'x': FnOnce::Output<dyn Fn<(), Output = i32>, ()>
614..615 'f': Box<dyn Fn<(), Output = i32>>
614..617 'f()': FnOnce::Output<dyn Fn<(), Output = i32>, ()>
"###
fn foo() {
let f: &dyn Fn() -> i32;
f();
//^^^ i32
}"#,
);
}
#[test]
fn variable_kinds() {
fn infer_dyn_fn_once_output() {
check_types(
r#"
#[lang = "fn_once"]
pub trait FnOnce<Args> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
fn foo() {
let f: dyn FnOnce() -> i32;
f();
//^^^ i32
}"#,
);
}
#[test]
fn variable_kinds_1() {
check_types(
r#"
trait Trait<T> { fn get(self, t: T) -> T; }
@ -3083,3 +3078,20 @@ fn test() {
"#,
);
}
#[test]
fn variable_kinds_2() {
check_types(
r#"
trait Trait { fn get(self) -> Self; }
impl Trait for u128 {}
impl Trait for f32 {}
fn test() {
1.get();
//^^^^^^^ u128
(1.).get();
//^^^^^^^^^^ f32
}
"#,
);
}

View file

@ -2,6 +2,7 @@
use std::sync::Arc;
use chalk_ir::cast::Cast;
use chalk_solve::Solver;
use hir_def::{
expr::ExprId, lang_item::LangItemTarget, DefWithBodyId, ImplId, TraitId, TypeAliasId,
};
@ -32,9 +33,10 @@ struct ChalkContext<'a> {
krate: CrateId,
}
fn create_chalk_solver() -> chalk_solve::Solver<Interner> {
let solver_choice = chalk_solve::SolverChoice::recursive();
solver_choice.into_solver()
fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
let overflow_depth = 100;
let caching_enabled = true;
chalk_recursive::RecursiveSolver::new(overflow_depth, caching_enabled)
}
/// A set of clauses that we assume to be true. E.g. if we are inside this function:
@ -293,13 +295,8 @@ pub enum Impl {
/// A normal impl from an impl block.
ImplDef(ImplId),
/// Closure types implement the Fn traits synthetically.
// FIXME: implement closure support from Chalk, remove this
ClosureFnTraitImpl(ClosureFnTraitImplData),
/// [T; n]: Unsize<[T]>
UnsizeArray,
/// T: Unsize<dyn Trait> where T: Trait
UnsizeToTraitObject(TraitId),
/// dyn Trait: Unsize<dyn SuperTrait> if Trait: SuperTrait
UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData),
}
/// This exists just for Chalk, because our ImplIds are only unique per module.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -1,15 +1,12 @@
//! This module provides the built-in trait implementations, e.g. to make
//! closures implement `Fn`.
use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId};
use hir_def::{expr::Expr, TraitId, TypeAliasId};
use hir_expand::name::name;
use ra_db::CrateId;
use super::{AssocTyValue, Impl, UnsizeToSuperTraitObjectData};
use super::{AssocTyValue, Impl};
use crate::{
db::HirDatabase,
utils::{all_super_traits, generics},
ApplicationTy, Binders, BoundVar, DebruijnIndex, GenericPredicate, Substs, TraitRef, Ty,
TypeCtor, TypeWalk,
db::HirDatabase, ApplicationTy, BoundVar, DebruijnIndex, Substs, TraitRef, Ty, TypeCtor,
};
pub(super) struct BuiltinImplData {
@ -31,7 +28,7 @@ pub(super) fn get_builtin_impls(
krate: CrateId,
ty: &Ty,
// The first argument for the trait, if present
arg: &Option<Ty>,
_arg: &Option<Ty>,
trait_: TraitId,
mut callback: impl FnMut(Impl),
) {
@ -50,60 +47,12 @@ pub(super) fn get_builtin_impls(
}
}
}
let unsize_trait = get_unsize_trait(db, krate);
if let Some(actual_trait) = unsize_trait {
if trait_ == actual_trait {
get_builtin_unsize_impls(db, krate, ty, arg, callback);
}
}
}
fn get_builtin_unsize_impls(
db: &dyn HirDatabase,
krate: CrateId,
ty: &Ty,
// The first argument for the trait, if present
arg: &Option<Ty>,
mut callback: impl FnMut(Impl),
) {
if !check_unsize_impl_prerequisites(db, krate) {
return;
}
if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty {
callback(Impl::UnsizeArray);
return; // array is unsized, the rest of the impls shouldn't apply
}
if let Some(target_trait) = arg.as_ref().and_then(|t| t.dyn_trait_ref()) {
// FIXME what about more complicated dyn tys with marker traits?
if let Some(trait_ref) = ty.dyn_trait_ref() {
if trait_ref.trait_ != target_trait.trait_ {
let super_traits = all_super_traits(db.upcast(), trait_ref.trait_);
if super_traits.contains(&target_trait.trait_) {
callback(Impl::UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData {
trait_: trait_ref.trait_,
super_trait: target_trait.trait_,
}));
}
}
} else {
// FIXME only for sized types
callback(Impl::UnsizeToTraitObject(target_trait.trait_));
}
}
}
pub(super) fn impl_datum(db: &dyn HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData {
match impl_ {
Impl::ImplDef(_) => unreachable!(),
Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
Impl::UnsizeArray => array_unsize_impl_datum(db, krate),
Impl::UnsizeToTraitObject(trait_) => trait_object_unsize_impl_datum(db, krate, trait_),
Impl::UnsizeToSuperTraitObject(data) => {
super_trait_object_unsize_impl_datum(db, krate, data)
}
}
}
@ -227,145 +176,3 @@ fn closure_fn_trait_output_assoc_ty_value(
value: output_ty,
}
}
// Array unsizing
fn check_unsize_impl_prerequisites(db: &dyn HirDatabase, krate: CrateId) -> bool {
// the Unsize trait needs to exist and have two type parameters (Self and T)
let unsize_trait = match get_unsize_trait(db, krate) {
Some(t) => t,
None => return false,
};
let generic_params = generics(db.upcast(), unsize_trait.into());
generic_params.len() == 2
}
fn array_unsize_impl_datum(db: &dyn HirDatabase, krate: CrateId) -> BuiltinImplData {
// impl<T> Unsize<[T]> for [T; _]
// (this can be a single impl because we don't distinguish array sizes currently)
let trait_ = get_unsize_trait(db, krate) // get unsize trait
// the existence of the Unsize trait has been checked before
.expect("Unsize trait missing");
let var = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
let substs = Substs::builder(2)
.push(Ty::apply_one(TypeCtor::Array, var.clone()))
.push(Ty::apply_one(TypeCtor::Slice, var))
.build();
let trait_ref = TraitRef { trait_, substs };
BuiltinImplData {
num_vars: 1,
trait_ref,
where_clauses: Vec::new(),
assoc_ty_values: Vec::new(),
}
}
// Trait object unsizing
fn trait_object_unsize_impl_datum(
db: &dyn HirDatabase,
krate: CrateId,
trait_: TraitId,
) -> BuiltinImplData {
// impl<T, T1, ...> Unsize<dyn Trait<T1, ...>> for T where T: Trait<T1, ...>
let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
// the existence of the Unsize trait has been checked before
.expect("Unsize trait missing");
let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
let target_substs = Substs::build_for_def(db, trait_)
.push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
.fill_with_bound_vars(DebruijnIndex::ONE, 1)
.build();
let num_vars = target_substs.len();
let target_trait_ref = TraitRef { trait_, substs: target_substs };
let target_bounds = vec![GenericPredicate::Implemented(target_trait_ref)];
let self_substs =
Substs::build_for_def(db, trait_).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
let self_trait_ref = TraitRef { trait_, substs: self_substs };
let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)];
let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build();
let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs };
BuiltinImplData { num_vars, trait_ref, where_clauses, assoc_ty_values: Vec::new() }
}
fn super_trait_object_unsize_impl_datum(
db: &dyn HirDatabase,
krate: CrateId,
data: UnsizeToSuperTraitObjectData,
) -> BuiltinImplData {
// impl<T1, ...> Unsize<dyn SuperTrait> for dyn Trait<T1, ...>
let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
// the existence of the Unsize trait has been checked before
.expect("Unsize trait missing");
let self_substs = Substs::build_for_def(db, data.trait_)
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
.build();
let self_trait_ref = TraitRef { trait_: data.trait_, substs: self_substs.clone() };
let num_vars = self_substs.len() - 1;
// we need to go from our trait to the super trait, substituting type parameters
let path = crate::utils::find_super_trait_path(db.upcast(), data.trait_, data.super_trait);
let mut current_trait_ref = self_trait_ref.clone();
for t in path.into_iter().skip(1) {
let bounds = db.generic_predicates(current_trait_ref.trait_.into());
let super_trait_ref = bounds
.iter()
.find_map(|b| match &b.value {
GenericPredicate::Implemented(tr)
if tr.trait_ == t
&& tr.substs[0]
== Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)) =>
{
Some(Binders { value: tr, num_binders: b.num_binders })
}
_ => None,
})
.expect("trait bound for known super trait not found");
current_trait_ref = super_trait_ref.cloned().subst(&current_trait_ref.substs);
}
// We need to renumber the variables a bit now: from ^0.0, ^0.1, ^0.2, ...
// to ^0.0, ^1.0, ^1.1. The reason for this is that the first variable comes
// from the dyn Trait binder, while the other variables come from the impl.
let new_substs = Substs::builder(num_vars + 1)
.push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
.fill_with_bound_vars(DebruijnIndex::ONE, 0)
.build();
let self_bounds =
vec![GenericPredicate::Implemented(self_trait_ref.subst_bound_vars(&new_substs))];
let super_bounds =
vec![GenericPredicate::Implemented(current_trait_ref.subst_bound_vars(&new_substs))];
let substs = Substs::builder(2)
.push(Ty::Dyn(self_bounds.into()))
.push(Ty::Dyn(super_bounds.into()))
.build();
let trait_ref = TraitRef { trait_: unsize_trait, substs };
BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() }
}
fn get_unsize_trait(db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
let target = db.lang_item(krate, "unsize".into())?;
match target {
LangItemTarget::TraitId(t) => Some(t),
_ => None,
}
}

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use log::debug;
use chalk_ir::{fold::shift::Shift, GenericArg, TypeName};
use chalk_ir::{fold::shift::Shift, CanonicalVarKinds, GenericArg, TypeName};
use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
use hir_def::{
@ -14,7 +14,10 @@ use ra_db::{salsa::InternKey, CrateId};
use super::{builtin, AssocTyValue, ChalkContext, Impl};
use crate::{
db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
db::HirDatabase,
display::HirDisplay,
method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
utils::generics,
CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor,
};
use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders};
@ -66,13 +69,31 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
&self,
trait_id: TraitId,
parameters: &[GenericArg<Interner>],
binders: &CanonicalVarKinds<Interner>,
) -> Vec<ImplId> {
debug!("impls_for_trait {:?}", trait_id);
let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
fn binder_kind(ty: &Ty, binders: &CanonicalVarKinds<Interner>) -> Option<chalk_ir::TyKind> {
if let Ty::Bound(bv) = ty {
let binders = binders.as_slice(&Interner);
if bv.debruijn == DebruijnIndex::INNERMOST {
if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind {
return Some(tk);
}
}
}
None
}
let self_ty_fp = TyFingerprint::for_impl(&ty);
let fps: &[TyFingerprint] = match binder_kind(&ty, binders) {
Some(chalk_ir::TyKind::Integer) => &ALL_INT_FPS,
Some(chalk_ir::TyKind::Float) => &ALL_FLOAT_FPS,
_ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
};
// Note: Since we're using impls_for_trait, only impls where the trait
// can be resolved should ever reach Chalk. `impl_datum` relies on that
@ -83,17 +104,21 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db);
let mut result: Vec<_> = match self_ty_fp {
Some(fp) => impl_maps
.iter()
.flat_map(|crate_impl_defs| {
crate_impl_defs.for_trait_and_self_ty(trait_, fp).map(id_to_chalk)
})
.collect(),
None => impl_maps
let mut result: Vec<_> = if fps.is_empty() {
debug!("Unrestricted search for {:?} impls...", trait_);
impl_maps
.iter()
.flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk))
.collect(),
.collect()
} else {
impl_maps
.iter()
.flat_map(|crate_impl_defs| {
fps.iter().flat_map(move |fp| {
crate_impl_defs.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
})
})
.collect()
};
let arg: Option<Ty> =
@ -219,6 +244,22 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
// FIXME: implement closure support
unimplemented!()
}
fn trait_name(&self, _trait_id: chalk_ir::TraitId<Interner>) -> String {
unimplemented!()
}
fn adt_name(&self, _struct_id: chalk_ir::AdtId<Interner>) -> String {
unimplemented!()
}
fn assoc_type_name(&self, _assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String {
unimplemented!()
}
fn opaque_type_name(&self, _opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String {
unimplemented!()
}
fn fn_def_name(&self, _fn_def_id: chalk_ir::FnDefId<Interner>) -> String {
unimplemented!()
}
}
pub(crate) fn program_clauses_for_chalk_env_query(
@ -354,12 +395,18 @@ pub(crate) fn struct_datum_query(
fundamental: false,
phantom_data: false,
};
let struct_datum_bound = rust_ir::AdtDatumBound {
fields: Vec::new(), // FIXME add fields (only relevant for auto traits)
where_clauses,
// FIXME provide enum variants properly (for auto traits)
let variant = rust_ir::AdtVariantDatum {
fields: Vec::new(), // FIXME add fields (only relevant for auto traits),
};
let struct_datum_bound = rust_ir::AdtDatumBound { variants: vec![variant], where_clauses };
let struct_datum = StructDatum {
// FIXME set ADT kind
kind: rust_ir::AdtKind::Struct,
id: struct_id,
binders: make_binders(struct_datum_bound, num_params),
flags,
};
let struct_datum =
StructDatum { id: struct_id, binders: make_binders(struct_datum_bound, num_params), flags };
Arc::new(struct_datum)
}

View file

@ -39,6 +39,7 @@ impl chalk_ir::interner::Interner for Interner {
type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>;
type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>;
type DefId = InternId;
type InternedAdtId = crate::TypeCtorId;
type Identifier = TypeAliasId;
@ -349,6 +350,20 @@ impl chalk_ir::interner::Interner for Interner {
) -> &'a [chalk_ir::CanonicalVarKind<Self>] {
&canonical_var_kinds
}
fn intern_constraints<E>(
&self,
data: impl IntoIterator<Item = Result<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>, E>>,
) -> Result<Self::InternedConstraints, E> {
data.into_iter().collect()
}
fn constraints_data<'a>(
&self,
constraints: &'a Self::InternedConstraints,
) -> &'a [chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>] {
constraints
}
}
impl chalk_ir::interner::HasInterner for Interner {

View file

@ -29,6 +29,7 @@ impl ToChalk for Ty {
match self {
Ty::Apply(apply_ty) => match apply_ty.ctor {
TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
TypeCtor::Array => array_to_chalk(db, apply_ty.parameters),
TypeCtor::FnPtr { num_args: _ } => {
let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner);
chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution })
@ -61,13 +62,13 @@ impl ToChalk for Ty {
Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner),
Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
Ty::Dyn(predicates) => {
let where_clauses = chalk_ir::QuantifiedWhereClauses::from(
let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter(
&Interner,
predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)),
);
let bounded_ty = chalk_ir::DynTy {
bounds: make_binders(where_clauses, 1),
lifetime: LIFETIME_PLACEHOLDER.to_lifetime(&Interner),
lifetime: FAKE_PLACEHOLDER.to_lifetime(&Interner),
};
chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner)
}
@ -92,6 +93,7 @@ impl ToChalk for Ty {
chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name {
TypeName::Error => Ty::Unknown,
TypeName::Ref(m) => ref_from_chalk(db, m, apply_ty.substitution),
TypeName::Array => array_from_chalk(db, apply_ty.substitution),
_ => {
let ctor = from_chalk(db, apply_ty.name);
let parameters = from_chalk(db, apply_ty.substitution);
@ -138,7 +140,7 @@ impl ToChalk for Ty {
}
}
const LIFETIME_PLACEHOLDER: PlaceholderIndex =
const FAKE_PLACEHOLDER: PlaceholderIndex =
PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX };
/// We currently don't model lifetimes, but Chalk does. So, we have to insert a
@ -149,10 +151,10 @@ fn ref_to_chalk(
subst: Substs,
) -> chalk_ir::Ty<Interner> {
let arg = subst[0].clone().to_chalk(db);
let lifetime = LIFETIME_PLACEHOLDER.to_lifetime(&Interner);
let lifetime = FAKE_PLACEHOLDER.to_lifetime(&Interner);
chalk_ir::ApplicationTy {
name: TypeName::Ref(mutability.to_chalk(db)),
substitution: chalk_ir::Substitution::from(
substitution: chalk_ir::Substitution::from_iter(
&Interner,
vec![lifetime.cast(&Interner), arg.cast(&Interner)],
),
@ -173,11 +175,40 @@ fn ref_from_chalk(
Ty::apply(TypeCtor::Ref(from_chalk(db, mutability)), Substs(tys))
}
/// We currently don't model constants, but Chalk does. So, we have to insert a
/// fake constant here, because Chalks built-in logic may expect it to be there.
fn array_to_chalk(db: &dyn HirDatabase, subst: Substs) -> chalk_ir::Ty<Interner> {
let arg = subst[0].clone().to_chalk(db);
let usize_ty = chalk_ir::ApplicationTy {
name: TypeName::Scalar(Scalar::Uint(chalk_ir::UintTy::Usize)),
substitution: chalk_ir::Substitution::empty(&Interner),
}
.intern(&Interner);
let const_ = FAKE_PLACEHOLDER.to_const(&Interner, usize_ty);
chalk_ir::ApplicationTy {
name: TypeName::Array,
substitution: chalk_ir::Substitution::from_iter(
&Interner,
vec![arg.cast(&Interner), const_.cast(&Interner)],
),
}
.intern(&Interner)
}
/// Here we remove the const from the type we got from Chalk.
fn array_from_chalk(db: &dyn HirDatabase, subst: chalk_ir::Substitution<Interner>) -> Ty {
let tys = subst
.iter(&Interner)
.filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone())))
.collect();
Ty::apply(TypeCtor::Array, Substs(tys))
}
impl ToChalk for Substs {
type Chalk = chalk_ir::Substitution<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> {
chalk_ir::Substitution::from(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db)))
chalk_ir::Substitution::from_iter(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db)))
}
fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs {
@ -263,6 +294,7 @@ impl ToChalk for TypeCtor {
TypeCtor::Tuple { cardinality } => TypeName::Tuple(cardinality.into()),
TypeCtor::RawPtr(mutability) => TypeName::Raw(mutability.to_chalk(db)),
TypeCtor::Slice => TypeName::Slice,
TypeCtor::Array => TypeName::Array,
TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)),
TypeCtor::Str => TypeName::Str,
TypeCtor::FnDef(callable_def) => {
@ -271,10 +303,8 @@ impl ToChalk for TypeCtor {
}
TypeCtor::Never => TypeName::Never,
TypeCtor::Adt(_)
| TypeCtor::Array
| TypeCtor::FnPtr { .. }
| TypeCtor::Closure { .. } => {
// FIXME convert these
TypeCtor::Adt(_) | TypeCtor::FnPtr { .. } | TypeCtor::Closure { .. } => {
// other TypeCtors get interned and turned into a chalk StructId
let struct_id = db.intern_type_ctor(self).into();
TypeName::Adt(struct_id)
@ -492,6 +522,11 @@ impl ToChalk for GenericPredicate {
// we shouldn't get these from Chalk
panic!("encountered LifetimeOutlives from Chalk")
}
chalk_ir::WhereClause::TypeOutlives(_) => {
// we shouldn't get these from Chalk
panic!("encountered TypeOutlives from Chalk")
}
}
}
}
@ -570,7 +605,10 @@ where
)
});
let value = self.value.to_chalk(db);
chalk_ir::Canonical { value, binders: chalk_ir::CanonicalVarKinds::from(&Interner, kinds) }
chalk_ir::Canonical {
value,
binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds),
}
}
fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
@ -691,7 +729,7 @@ where
T: HasInterner<Interner = Interner>,
{
chalk_ir::Binders::new(
chalk_ir::VariableKinds::from(
chalk_ir::VariableKinds::from_iter(
&Interner,
std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)).take(num_vars),
),

View file

@ -157,7 +157,7 @@ impl DebugContext<'_> {
_ => panic!("associated type not in trait"),
};
let trait_data = self.0.trait_data(trait_);
let params = projection_ty.substitution.parameters(&Interner);
let params = projection_ty.substitution.as_slice(&Interner);
write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?;
if params.len() > 1 {
write!(

View file

@ -110,38 +110,6 @@ pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) ->
result
}
/// Finds a path from a trait to one of its super traits. Returns an empty
/// vector if there is no path.
pub(super) fn find_super_trait_path(
db: &dyn DefDatabase,
trait_: TraitId,
super_trait: TraitId,
) -> Vec<TraitId> {
let mut result = Vec::with_capacity(2);
result.push(trait_);
return if go(db, super_trait, &mut result) { result } else { Vec::new() };
fn go(db: &dyn DefDatabase, super_trait: TraitId, path: &mut Vec<TraitId>) -> bool {
let trait_ = *path.last().unwrap();
if trait_ == super_trait {
return true;
}
for tt in direct_super_traits(db, trait_) {
if path.contains(&tt) {
continue;
}
path.push(tt);
if go(db, super_trait, path) {
return true;
} else {
path.pop();
}
}
false
}
}
pub(super) fn associated_type_by_name_including_super_traits(
db: &dyn HirDatabase,
trait_ref: TraitRef,