mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 07:04:22 +00:00
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
This commit is contained in:
commit
dd026ce6a4
3 changed files with 139 additions and 0 deletions
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue