Skip to content

Commit dd026ce

Browse files
committed
Auto merge of #18093 - ShoyuVanilla:skip-dyn-trait-cast-check, r=Veykril
Skip checks for cast to dyn traits It seems that chalk fails to solve some obvious goals when there are some recursiveness in trait environments. And it doesn't support trait upcasting yet. rust-lang/chalk#796 This PR just skips for casting into types containing `dyn Trait` to prevent false positive diagnostics like #18047 and #18083
2 parents bcc7089 + 569ac44 commit dd026ce

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)