mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-28 04:45:05 +00:00
Auto merge of #12793 - lowr:fix/12739, r=Veykril
fix: sort and deduplicate auto traits in trait object types
Fixes #12739
Chalk solver doesn't sort and deduplicate auto traits in trait object types, so we need to handle them ourselves in the lowering phase, just like [`rustc`](880416180b/compiler/rustc_typeck/src/astconv/mod.rs (L1487-L1488)
) and [`chalk-integration`](https://github.com/rust-lang/chalk/blob/master/chalk-integration/src/lowering.rs#L575) do.
Quoting from [the Chalk book](https://rust-lang.github.io/chalk/book/types/rust_types.html#dyn-types):
> Note that -- for this purpose -- ordering of bounds is significant. That means that if you create a `dyn Foo + Send` and a `dyn Send + Foo`, chalk would consider them distinct types. The assumption is that bounds are ordered in some canonical fashion somewhere else.
Also, trait object types with more than one non-auto traits were previously allowed, but are now disallowed with this patch.
This commit is contained in:
commit
56d888689b
3 changed files with 132 additions and 9 deletions
|
@ -1,8 +1,8 @@
|
||||||
//! Methods for lowering the HIR to types. There are two main cases here:
|
//! Methods for lowering the HIR to types. There are two main cases here:
|
||||||
//!
|
//!
|
||||||
//! - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a
|
//! - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a
|
||||||
//! type: The entry point for this is `Ty::from_hir`.
|
//! type: The entry point for this is `TyLoweringContext::lower_ty`.
|
||||||
//! - Building the type for an item: This happens through the `type_for_def` query.
|
//! - Building the type for an item: This happens through the `ty` query.
|
||||||
//!
|
//!
|
||||||
//! This usually involves resolving names, collecting generic arguments etc.
|
//! This usually involves resolving names, collecting generic arguments etc.
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -47,7 +47,7 @@ use crate::{
|
||||||
consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic},
|
consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic},
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
make_binders,
|
make_binders,
|
||||||
mapping::ToChalk,
|
mapping::{from_chalk_trait_id, ToChalk},
|
||||||
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
|
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
|
||||||
utils::Generics,
|
utils::Generics,
|
||||||
utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
|
utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
|
||||||
|
@ -982,13 +982,44 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
|
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
|
||||||
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
||||||
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||||
QuantifiedWhereClauses::from_iter(
|
let bounds =
|
||||||
|
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false));
|
||||||
|
|
||||||
|
let mut auto_traits = SmallVec::<[_; 8]>::new();
|
||||||
|
let mut regular_traits = SmallVec::<[_; 2]>::new();
|
||||||
|
let mut other_bounds = SmallVec::<[_; 8]>::new();
|
||||||
|
for bound in bounds {
|
||||||
|
if let Some(id) = bound.trait_id() {
|
||||||
|
if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto {
|
||||||
|
auto_traits.push(bound);
|
||||||
|
} else {
|
||||||
|
regular_traits.push(bound);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
other_bounds.push(bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if regular_traits.len() > 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap());
|
||||||
|
auto_traits.dedup();
|
||||||
|
|
||||||
|
Some(QuantifiedWhereClauses::from_iter(
|
||||||
Interner,
|
Interner,
|
||||||
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
|
regular_traits.into_iter().chain(other_bounds).chain(auto_traits),
|
||||||
)
|
))
|
||||||
});
|
});
|
||||||
let bounds = crate::make_single_type_binders(bounds);
|
|
||||||
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
if let Some(bounds) = bounds {
|
||||||
|
let bounds = crate::make_single_type_binders(bounds);
|
||||||
|
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
||||||
|
} else {
|
||||||
|
// FIXME: report error (additional non-auto traits)
|
||||||
|
TyKind::Error.intern(Interner)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_impl_trait(
|
fn lower_impl_trait(
|
||||||
|
|
|
@ -3833,3 +3833,95 @@ fn test() {
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dyn_multiple_auto_traits_in_different_order() {
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
auto trait Send {}
|
||||||
|
auto trait Sync {}
|
||||||
|
|
||||||
|
fn f(t: &(dyn Sync + Send)) {}
|
||||||
|
fn g(t: &(dyn Send + Sync)) {
|
||||||
|
f(t);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
auto trait Send {}
|
||||||
|
auto trait Sync {}
|
||||||
|
trait T {}
|
||||||
|
|
||||||
|
fn f(t: &(dyn T + Send + Sync)) {}
|
||||||
|
fn g(t: &(dyn Sync + T + Send)) {
|
||||||
|
f(t);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
check_infer_with_mismatches(
|
||||||
|
r#"
|
||||||
|
auto trait Send {}
|
||||||
|
auto trait Sync {}
|
||||||
|
trait T1 {}
|
||||||
|
trait T2 {}
|
||||||
|
|
||||||
|
fn f(t: &(dyn T1 + T2 + Send + Sync)) {}
|
||||||
|
fn g(t: &(dyn Sync + T2 + T1 + Send)) {
|
||||||
|
f(t);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
68..69 't': &{unknown}
|
||||||
|
101..103 '{}': ()
|
||||||
|
109..110 't': &{unknown}
|
||||||
|
142..155 '{ f(t); }': ()
|
||||||
|
148..149 'f': fn f(&{unknown})
|
||||||
|
148..152 'f(t)': ()
|
||||||
|
150..151 't': &{unknown}
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
auto trait Send {}
|
||||||
|
auto trait Sync {}
|
||||||
|
trait T {
|
||||||
|
type Proj: Send + Sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(t: &(dyn T<Proj = ()> + Send + Sync)) {}
|
||||||
|
fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
|
||||||
|
f(t);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dyn_duplicate_auto_trait() {
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
auto trait Send {}
|
||||||
|
|
||||||
|
fn f(t: &(dyn Send + Send)) {}
|
||||||
|
fn g(t: &(dyn Send)) {
|
||||||
|
f(t);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
auto trait Send {}
|
||||||
|
trait T {}
|
||||||
|
|
||||||
|
fn f(t: &(dyn T + Send + Send)) {}
|
||||||
|
fn g(t: &(dyn T + Send)) {
|
||||||
|
f(t);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1910,7 +1910,7 @@ impl<T> Vec<T> {
|
||||||
pub struct Box<T> {}
|
pub struct Box<T> {}
|
||||||
|
|
||||||
trait Display {}
|
trait Display {}
|
||||||
trait Sync {}
|
auto trait Sync {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// The block expression wrapping disables the constructor hint hiding logic
|
// The block expression wrapping disables the constructor hint hiding logic
|
||||||
|
|
Loading…
Reference in a new issue