Skip to content

Commit 569ac44

Browse files
committed
Skip checks for cast to dyn traits
1 parent e35227d commit 569ac44

File tree

3 files changed

+139
-0
lines changed

3 files changed

+139
-0
lines changed

crates/hir-ty/src/infer/cast.rs

+39
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ impl CastCheck {
120120
});
121121
}
122122

123+
// Chalk doesn't support trait upcasting and fails to solve some obvious goals
124+
// when the trait environment contains some recursive traits (See issue #18047)
125+
// We skip cast checks for such cases for now, until the next-gen solver.
126+
if contains_dyn_trait(&self.cast_ty) {
127+
return Ok(());
128+
}
129+
123130
if let Ok((adj, _)) = table.coerce(&self.expr_ty, &self.cast_ty) {
124131
apply_adjustments(self.source_expr, adj);
125132
set_coercion_cast(self.source_expr);
@@ -410,3 +417,35 @@ fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<Pointe
410417
}
411418
}
412419
}
420+
421+
fn contains_dyn_trait(ty: &Ty) -> bool {
422+
use std::ops::ControlFlow;
423+
424+
use chalk_ir::{
425+
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
426+
DebruijnIndex,
427+
};
428+
429+
struct DynTraitVisitor;
430+
431+
impl TypeVisitor<Interner> for DynTraitVisitor {
432+
type BreakTy = ();
433+
434+
fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
435+
self
436+
}
437+
438+
fn interner(&self) -> Interner {
439+
Interner
440+
}
441+
442+
fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<Self::BreakTy> {
443+
match ty.kind(Interner) {
444+
TyKind::Dyn(_) => ControlFlow::Break(()),
445+
_ => ty.super_visit_with(self.as_dyn(), outer_binder),
446+
}
447+
}
448+
}
449+
450+
ty.visit_with(DynTraitVisitor.as_dyn(), DebruijnIndex::INNERMOST).is_break()
451+
}

crates/hir-ty/src/infer/unify.rs

+4
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,10 @@ impl<'a> InferenceTable<'a> {
902902

903903
/// Check if given type is `Sized` or not
904904
pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool {
905+
// Early return for some obvious types
906+
if matches!(ty.kind(Interner), TyKind::Scalar(..) | TyKind::Ref(..) | TyKind::Raw(..)) {
907+
return true;
908+
}
905909
if let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
906910
let struct_data = self.db.struct_data(id);
907911
if let Some((last_field, _)) = struct_data.variant_data.fields().iter().last() {

crates/ide-diagnostics/src/handlers/invalid_cast.rs

+96
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@ fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) {
556556
);
557557
}
558558

559+
#[ignore = "issue #18047"]
559560
#[test]
560561
fn ptr_to_trait_obj_wrap_upcast() {
561562
check_diagnostics(
@@ -1004,4 +1005,99 @@ fn _slice(bar: &[i32]) -> bool {
10041005
&["E0308"],
10051006
);
10061007
}
1008+
1009+
#[test]
1010+
fn trait_upcasting() {
1011+
check_diagnostics(
1012+
r#"
1013+
//- minicore: coerce_unsized, dispatch_from_dyn
1014+
#![feature(trait_upcasting)]
1015+
trait Foo {}
1016+
trait Bar: Foo {}
1017+
1018+
impl dyn Bar {
1019+
fn bar(&self) {
1020+
_ = self as &dyn Foo;
1021+
}
1022+
}
1023+
"#,
1024+
);
1025+
}
1026+
1027+
#[test]
1028+
fn issue_18047() {
1029+
check_diagnostics(
1030+
r#"
1031+
//- minicore: coerce_unsized, dispatch_from_dyn
1032+
trait LocalFrom<T> {
1033+
fn from(_: T) -> Self;
1034+
}
1035+
trait LocalInto<T> {
1036+
fn into(self) -> T;
1037+
}
1038+
1039+
impl<T, U> LocalInto<U> for T
1040+
where
1041+
U: LocalFrom<T>,
1042+
{
1043+
fn into(self) -> U {
1044+
U::from(self)
1045+
}
1046+
}
1047+
1048+
impl<T> LocalFrom<T> for T {
1049+
fn from(t: T) -> T {
1050+
t
1051+
}
1052+
}
1053+
1054+
trait Foo {
1055+
type ErrorType;
1056+
type Assoc;
1057+
}
1058+
1059+
trait Bar {
1060+
type ErrorType;
1061+
}
1062+
1063+
struct ErrorLike;
1064+
1065+
impl<E> LocalFrom<E> for ErrorLike
1066+
where
1067+
E: Trait + 'static,
1068+
{
1069+
fn from(_: E) -> Self {
1070+
loop {}
1071+
}
1072+
}
1073+
1074+
trait Baz {
1075+
type Assoc: Bar;
1076+
type Error: LocalInto<ErrorLike>;
1077+
}
1078+
1079+
impl<T, U> Baz for T
1080+
where
1081+
T: Foo<Assoc = U>,
1082+
T::ErrorType: LocalInto<ErrorLike>,
1083+
U: Bar,
1084+
<U as Bar>::ErrorType: LocalInto<ErrorLike>,
1085+
{
1086+
type Assoc = U;
1087+
type Error = T::ErrorType;
1088+
}
1089+
struct S;
1090+
trait Trait {}
1091+
impl Trait for S {}
1092+
1093+
fn test<T>()
1094+
where
1095+
T: Baz,
1096+
T::Assoc: 'static,
1097+
{
1098+
let _ = &S as &dyn Trait;
1099+
}
1100+
"#,
1101+
);
1102+
}
10071103
}

0 commit comments

Comments
 (0)