Skip to content

Commit b86387e

Browse files
committed
fix: sort and deduplicate auto traits in trait objects
1 parent 5543dd8 commit b86387e

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},
@@ -969,13 +969,44 @@ impl<'a> TyLoweringContext<'a> {
969969
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
970970
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
971971
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
972-
QuantifiedWhereClauses::from_iter(
972+
let bounds =
973+
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false));
974+
975+
let mut auto_traits = SmallVec::<[_; 8]>::new();
976+
let mut regular_traits = SmallVec::<[_; 2]>::new();
977+
let mut other_bounds = SmallVec::<[_; 8]>::new();
978+
for bound in bounds {
979+
if let Some(id) = bound.trait_id() {
980+
if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto {
981+
auto_traits.push(bound);
982+
} else {
983+
regular_traits.push(bound);
984+
}
985+
} else {
986+
other_bounds.push(bound);
987+
}
988+
}
989+
990+
if regular_traits.len() > 1 {
991+
return None;
992+
}
993+
994+
auto_traits.sort_by_key(|b| b.trait_id().unwrap());
995+
auto_traits.dedup();
996+
997+
Some(QuantifiedWhereClauses::from_iter(
973998
Interner,
974-
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
975-
)
999+
regular_traits.into_iter().chain(other_bounds).chain(auto_traits),
1000+
))
9761001
});
977-
let bounds = crate::make_single_type_binders(bounds);
978-
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
1002+
1003+
if let Some(bounds) = bounds {
1004+
let bounds = crate::make_single_type_binders(bounds);
1005+
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
1006+
} else {
1007+
// FIXME: report error (additional non-auto traits)
1008+
TyKind::Error.intern(Interner)
1009+
}
9791010
}
9801011

9811012
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)