mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Skip checks for cast to dyn traits
This commit is contained in:
parent
e35227d186
commit
569ac44daf
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) {
|
if let Ok((adj, _)) = table.coerce(&self.expr_ty, &self.cast_ty) {
|
||||||
apply_adjustments(self.source_expr, adj);
|
apply_adjustments(self.source_expr, adj);
|
||||||
set_coercion_cast(self.source_expr);
|
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
|
/// Check if given type is `Sized` or not
|
||||||
pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool {
|
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() {
|
if let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
|
||||||
let struct_data = self.db.struct_data(id);
|
let struct_data = self.db.struct_data(id);
|
||||||
if let Some((last_field, _)) = struct_data.variant_data.fields().iter().last() {
|
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]
|
#[test]
|
||||||
fn ptr_to_trait_obj_wrap_upcast() {
|
fn ptr_to_trait_obj_wrap_upcast() {
|
||||||
check_diagnostics(
|
check_diagnostics(
|
||||||
|
@ -1004,4 +1005,99 @@ fn _slice(bar: &[i32]) -> bool {
|
||||||
&["E0308"],
|
&["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