Skip to content

Commit f63fb1d

Browse files
committed
fix: sort and deduplicate auto traits in trait objects
1 parent 8e379ce commit f63fb1d

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},
@@ -242,13 +242,44 @@ impl<'a> TyLoweringContext<'a> {
242242
let self_ty =
243243
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
244244
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
245-
QuantifiedWhereClauses::from_iter(
245+
let bounds =
246+
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false));
247+
248+
let mut auto_traits = SmallVec::<[_; 8]>::new();
249+
let mut regular_traits = SmallVec::<[_; 2]>::new();
250+
let mut other_bounds = SmallVec::<[_; 8]>::new();
251+
for bound in bounds {
252+
if let Some(id) = bound.trait_id() {
253+
if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto {
254+
auto_traits.push(bound);
255+
} else {
256+
regular_traits.push(bound);
257+
}
258+
} else {
259+
other_bounds.push(bound);
260+
}
261+
}
262+
263+
if regular_traits.len() > 1 {
264+
return None;
265+
}
266+
267+
auto_traits.sort_by_key(|b| b.trait_id().unwrap());
268+
auto_traits.dedup();
269+
270+
Some(QuantifiedWhereClauses::from_iter(
246271
Interner,
247-
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
248-
)
272+
regular_traits.into_iter().chain(other_bounds).chain(auto_traits),
273+
))
249274
});
250-
let bounds = crate::make_single_type_binders(bounds);
251-
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
275+
276+
if let Some(bounds) = bounds {
277+
let bounds = crate::make_single_type_binders(bounds);
278+
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
279+
} else {
280+
// FIXME: report error (additional non-auto traits)
281+
TyKind::Error.intern(Interner)
282+
}
252283
}
253284
TypeRef::ImplTrait(bounds) => {
254285
match self.impl_trait_mode {

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

+92
Original file line numberDiff line numberDiff line change
@@ -3780,3 +3780,95 @@ fn test() {
37803780
"#,
37813781
)
37823782
}
3783+
3784+
#[test]
3785+
fn dyn_multiple_auto_traits_in_different_order() {
3786+
check_no_mismatches(
3787+
r#"
3788+
auto trait Send {}
3789+
auto trait Sync {}
3790+
3791+
fn f(t: &(dyn Sync + Send)) {}
3792+
fn g(t: &(dyn Send + Sync)) {
3793+
f(t);
3794+
}
3795+
"#,
3796+
);
3797+
3798+
check_no_mismatches(
3799+
r#"
3800+
auto trait Send {}
3801+
auto trait Sync {}
3802+
trait T {}
3803+
3804+
fn f(t: &(dyn T + Send + Sync)) {}
3805+
fn g(t: &(dyn Sync + T + Send)) {
3806+
f(t);
3807+
}
3808+
"#,
3809+
);
3810+
3811+
check_infer_with_mismatches(
3812+
r#"
3813+
auto trait Send {}
3814+
auto trait Sync {}
3815+
trait T1 {}
3816+
trait T2 {}
3817+
3818+
fn f(t: &(dyn T1 + T2 + Send + Sync)) {}
3819+
fn g(t: &(dyn Sync + T2 + T1 + Send)) {
3820+
f(t);
3821+
}
3822+
"#,
3823+
expect![[r#"
3824+
68..69 't': &{unknown}
3825+
101..103 '{}': ()
3826+
109..110 't': &{unknown}
3827+
142..155 '{ f(t); }': ()
3828+
148..149 'f': fn f(&{unknown})
3829+
148..152 'f(t)': ()
3830+
150..151 't': &{unknown}
3831+
"#]],
3832+
);
3833+
3834+
check_no_mismatches(
3835+
r#"
3836+
auto trait Send {}
3837+
auto trait Sync {}
3838+
trait T {
3839+
type Proj: Send + Sync;
3840+
}
3841+
3842+
fn f(t: &(dyn T<Proj = ()> + Send + Sync)) {}
3843+
fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
3844+
f(t);
3845+
}
3846+
"#,
3847+
);
3848+
}
3849+
3850+
#[test]
3851+
fn dyn_duplicate_auto_trait() {
3852+
check_no_mismatches(
3853+
r#"
3854+
auto trait Send {}
3855+
3856+
fn f(t: &(dyn Send + Send)) {}
3857+
fn g(t: &(dyn Send)) {
3858+
f(t);
3859+
}
3860+
"#,
3861+
);
3862+
3863+
check_no_mismatches(
3864+
r#"
3865+
auto trait Send {}
3866+
trait T {}
3867+
3868+
fn f(t: &(dyn T + Send + Send)) {}
3869+
fn g(t: &(dyn T + Send)) {
3870+
f(t);
3871+
}
3872+
"#,
3873+
);
3874+
}

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)