Skip to content

fix: sort and deduplicate auto traits in trait object types #12793

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions crates/hir-ty/src/lower.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -969,13 +969,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(
Expand Down
92 changes: 92 additions & 0 deletions crates/hir-ty/src/tests/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
"#,
);
}
2 changes: 1 addition & 1 deletion crates/ide/src/inlay_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down