Skip to content

Commit 56d8886

Browse files
committed
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`](https://github.com/rust-lang/rust/blob/880416180b0a9ee1141c07d4d17667edb77daebd/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.
2 parents b613896 + 7ecead2 commit 56d8886

File tree

3 files changed

+132
-9
lines changed

3 files changed

+132
-9
lines changed

crates/hir-ty/src/lower.rs

+39-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Methods for lowering the HIR to types. There are two main cases here:
22
//!
33
//! - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a
4-
//! type: The entry point for this is `Ty::from_hir`.
5-
//! - Building the type for an item: This happens through the `type_for_def` query.
4+
//! type: The entry point for this is `TyLoweringContext::lower_ty`.
5+
//! - Building the type for an item: This happens through the `ty` query.
66
//!
77
//! This usually involves resolving names, collecting generic arguments etc.
88
use std::{
@@ -47,7 +47,7 @@ use crate::{
4747
consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic},
4848
db::HirDatabase,
4949
make_binders,
50-
mapping::ToChalk,
50+
mapping::{from_chalk_trait_id, ToChalk},
5151
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
5252
utils::Generics,
5353
utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
@@ -982,13 +982,44 @@ impl<'a> TyLoweringContext<'a> {
982982
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
983983
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
984984
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
985-
QuantifiedWhereClauses::from_iter(
985+
let bounds =
986+
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false));
987+
988+
let mut auto_traits = SmallVec::<[_; 8]>::new();
989+
let mut regular_traits = SmallVec::<[_; 2]>::new();
990+
let mut other_bounds = SmallVec::<[_; 8]>::new();
991+
for bound in bounds {
992+
if let Some(id) = bound.trait_id() {
993+
if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto {
994+
auto_traits.push(bound);
995+
} else {
996+
regular_traits.push(bound);
997+
}
998+
} else {
999+
other_bounds.push(bound);
1000+
}
1001+
}
1002+
1003+
if regular_traits.len() > 1 {
1004+
return None;
1005+
}
1006+
1007+
auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap());
1008+
auto_traits.dedup();
1009+
1010+
Some(QuantifiedWhereClauses::from_iter(
9861011
Interner,
987-
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
988-
)
1012+
regular_traits.into_iter().chain(other_bounds).chain(auto_traits),
1013+
))
9891014
});
990-
let bounds = crate::make_single_type_binders(bounds);
991-
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
1015+
1016+
if let Some(bounds) = bounds {
1017+
let bounds = crate::make_single_type_binders(bounds);
1018+
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
1019+
} else {
1020+
// FIXME: report error (additional non-auto traits)
1021+
TyKind::Error.intern(Interner)
1022+
}
9921023
}
9931024

9941025
fn lower_impl_trait(

crates/hir-ty/src/tests/traits.rs

+92
Original file line numberDiff line numberDiff line change
@@ -3833,3 +3833,95 @@ fn test() {
38333833
"#,
38343834
)
38353835
}
3836+
3837+
#[test]
3838+
fn dyn_multiple_auto_traits_in_different_order() {
3839+
check_no_mismatches(
3840+
r#"
3841+
auto trait Send {}
3842+
auto trait Sync {}
3843+
3844+
fn f(t: &(dyn Sync + Send)) {}
3845+
fn g(t: &(dyn Send + Sync)) {
3846+
f(t);
3847+
}
3848+
"#,
3849+
);
3850+
3851+
check_no_mismatches(
3852+
r#"
3853+
auto trait Send {}
3854+
auto trait Sync {}
3855+
trait T {}
3856+
3857+
fn f(t: &(dyn T + Send + Sync)) {}
3858+
fn g(t: &(dyn Sync + T + Send)) {
3859+
f(t);
3860+
}
3861+
"#,
3862+
);
3863+
3864+
check_infer_with_mismatches(
3865+
r#"
3866+
auto trait Send {}
3867+
auto trait Sync {}
3868+
trait T1 {}
3869+
trait T2 {}
3870+
3871+
fn f(t: &(dyn T1 + T2 + Send + Sync)) {}
3872+
fn g(t: &(dyn Sync + T2 + T1 + Send)) {
3873+
f(t);
3874+
}
3875+
"#,
3876+
expect![[r#"
3877+
68..69 't': &{unknown}
3878+
101..103 '{}': ()
3879+
109..110 't': &{unknown}
3880+
142..155 '{ f(t); }': ()
3881+
148..149 'f': fn f(&{unknown})
3882+
148..152 'f(t)': ()
3883+
150..151 't': &{unknown}
3884+
"#]],
3885+
);
3886+
3887+
check_no_mismatches(
3888+
r#"
3889+
auto trait Send {}
3890+
auto trait Sync {}
3891+
trait T {
3892+
type Proj: Send + Sync;
3893+
}
3894+
3895+
fn f(t: &(dyn T<Proj = ()> + Send + Sync)) {}
3896+
fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
3897+
f(t);
3898+
}
3899+
"#,
3900+
);
3901+
}
3902+
3903+
#[test]
3904+
fn dyn_duplicate_auto_trait() {
3905+
check_no_mismatches(
3906+
r#"
3907+
auto trait Send {}
3908+
3909+
fn f(t: &(dyn Send + Send)) {}
3910+
fn g(t: &(dyn Send)) {
3911+
f(t);
3912+
}
3913+
"#,
3914+
);
3915+
3916+
check_no_mismatches(
3917+
r#"
3918+
auto trait Send {}
3919+
trait T {}
3920+
3921+
fn f(t: &(dyn T + Send + Send)) {}
3922+
fn g(t: &(dyn T + Send)) {
3923+
f(t);
3924+
}
3925+
"#,
3926+
);
3927+
}

crates/ide/src/inlay_hints.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1910,7 +1910,7 @@ impl<T> Vec<T> {
19101910
pub struct Box<T> {}
19111911
19121912
trait Display {}
1913-
trait Sync {}
1913+
auto trait Sync {}
19141914
19151915
fn main() {
19161916
// The block expression wrapping disables the constructor hint hiding logic

0 commit comments

Comments
 (0)