mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 23:12:02 +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
@ -1,8 +1,8 @@
|
||||
//! 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
|
||||
//! type: The entry point for this is `Ty::from_hir`.
|
||||
//! - Building the type for an item: This happens through the `type_for_def` query.
|
||||
//! type: The entry point for this is `TyLoweringContext::lower_ty`.
|
||||
//! - Building the type for an item: This happens through the `ty` query.
|
||||
//!
|
||||
//! This usually involves resolving names, collecting generic arguments etc.
|
||||
use std::{
|
||||
@ -47,7 +47,7 @@ use crate::{
|
||||
consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic},
|
||||
db::HirDatabase,
|
||||
make_binders,
|
||||
mapping::ToChalk,
|
||||
mapping::{from_chalk_trait_id, ToChalk},
|
||||
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
|
||||
utils::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 {
|
||||
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
||||
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,
|
||||
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(
|
||||
|
@ -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> {}
|
||||
|
||||
trait Display {}
|
||||
trait Sync {}
|
||||
auto trait Sync {}
|
||||
|
||||
fn main() {
|
||||
// The block expression wrapping disables the constructor hint hiding logic
|
||||
|
Loading…
Reference in New Issue
Block a user