Unnamed repository; edit this file 'description' to name the repository.
Skip checks for cast to dyn traits
Shoyu Vanilla 2024-09-10
parent e35227d · commit 569ac44
-rw-r--r--crates/hir-ty/src/infer/cast.rs39
-rw-r--r--crates/hir-ty/src/infer/unify.rs4
-rw-r--r--crates/ide-diagnostics/src/handlers/invalid_cast.rs96
3 files changed, 139 insertions, 0 deletions
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
index ae91404436..caa3960a22 100644
--- a/crates/hir-ty/src/infer/cast.rs
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -120,6 +120,13 @@ impl CastCheck {
});
}
+ // Chalk doesn't support trait upcasting and fails to solve some obvious goals
+ // when the trait environment contains some recursive traits (See issue #18047)
+ // We skip cast checks for such cases for now, until the next-gen solver.
+ if contains_dyn_trait(&self.cast_ty) {
+ return Ok(());
+ }
+
if let Ok((adj, _)) = table.coerce(&self.expr_ty, &self.cast_ty) {
apply_adjustments(self.source_expr, adj);
set_coercion_cast(self.source_expr);
@@ -410,3 +417,35 @@ fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<Pointe
}
}
}
+
+fn contains_dyn_trait(ty: &Ty) -> bool {
+ use std::ops::ControlFlow;
+
+ use chalk_ir::{
+ visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
+ DebruijnIndex,
+ };
+
+ struct DynTraitVisitor;
+
+ impl TypeVisitor<Interner> for DynTraitVisitor {
+ type BreakTy = ();
+
+ fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
+ self
+ }
+
+ fn interner(&self) -> Interner {
+ Interner
+ }
+
+ fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<Self::BreakTy> {
+ match ty.kind(Interner) {
+ TyKind::Dyn(_) => ControlFlow::Break(()),
+ _ => ty.super_visit_with(self.as_dyn(), outer_binder),
+ }
+ }
+ }
+
+ ty.visit_with(DynTraitVisitor.as_dyn(), DebruijnIndex::INNERMOST).is_break()
+}
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 99ad678980..d38380e4a3 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -902,6 +902,10 @@ impl<'a> InferenceTable<'a> {
/// Check if given type is `Sized` or not
pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool {
+ // Early return for some obvious types
+ if matches!(ty.kind(Interner), TyKind::Scalar(..) | TyKind::Ref(..) | TyKind::Raw(..)) {
+ return true;
+ }
if let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
let struct_data = self.db.struct_data(id);
if let Some((last_field, _)) = struct_data.variant_data.fields().iter().last() {
diff --git a/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index 9eb4e618c0..90527c578e 100644
--- a/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -556,6 +556,7 @@ fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) {
);
}
+ #[ignore = "issue #18047"]
#[test]
fn ptr_to_trait_obj_wrap_upcast() {
check_diagnostics(
@@ -1004,4 +1005,99 @@ fn _slice(bar: &[i32]) -> bool {
&["E0308"],
);
}
+
+ #[test]
+ fn trait_upcasting() {
+ check_diagnostics(
+ r#"
+//- minicore: coerce_unsized, dispatch_from_dyn
+#![feature(trait_upcasting)]
+trait Foo {}
+trait Bar: Foo {}
+
+impl dyn Bar {
+ fn bar(&self) {
+ _ = self as &dyn Foo;
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn issue_18047() {
+ check_diagnostics(
+ r#"
+//- minicore: coerce_unsized, dispatch_from_dyn
+trait LocalFrom<T> {
+ fn from(_: T) -> Self;
+}
+trait LocalInto<T> {
+ fn into(self) -> T;
+}
+
+impl<T, U> LocalInto<U> for T
+where
+ U: LocalFrom<T>,
+{
+ fn into(self) -> U {
+ U::from(self)
+ }
+}
+
+impl<T> LocalFrom<T> for T {
+ fn from(t: T) -> T {
+ t
+ }
+}
+
+trait Foo {
+ type ErrorType;
+ type Assoc;
+}
+
+trait Bar {
+ type ErrorType;
+}
+
+struct ErrorLike;
+
+impl<E> LocalFrom<E> for ErrorLike
+where
+ E: Trait + 'static,
+{
+ fn from(_: E) -> Self {
+ loop {}
+ }
+}
+
+trait Baz {
+ type Assoc: Bar;
+ type Error: LocalInto<ErrorLike>;
+}
+
+impl<T, U> Baz for T
+where
+ T: Foo<Assoc = U>,
+ T::ErrorType: LocalInto<ErrorLike>,
+ U: Bar,
+ <U as Bar>::ErrorType: LocalInto<ErrorLike>,
+{
+ type Assoc = U;
+ type Error = T::ErrorType;
+}
+struct S;
+trait Trait {}
+impl Trait for S {}
+
+fn test<T>()
+where
+ T: Baz,
+ T::Assoc: 'static,
+{
+ let _ = &S as &dyn Trait;
+}
+"#,
+ );
+ }
}