fix: Implement Expactation::Castable and add a test case for it

This commit is contained in:
Lukas Wirth 2023-02-08 12:57:08 +01:00
parent 5e6208b1df
commit f8f1cb93e0
3 changed files with 41 additions and 8 deletions

View file

@ -1024,7 +1024,7 @@ impl<'a> InferenceContext<'a> {
pub(crate) enum Expectation { pub(crate) enum Expectation {
None, None,
HasType(Ty), HasType(Ty),
// Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts Castable(Ty),
RValueLikeUnsized(Ty), RValueLikeUnsized(Ty),
} }
@ -1077,6 +1077,7 @@ impl Expectation {
match self { match self {
Expectation::None => Expectation::None, Expectation::None => Expectation::None,
Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)), Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)),
Expectation::Castable(t) => Expectation::Castable(table.resolve_ty_shallow(t)),
Expectation::RValueLikeUnsized(t) => { Expectation::RValueLikeUnsized(t) => {
Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t)) Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t))
} }
@ -1086,17 +1087,18 @@ impl Expectation {
fn to_option(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> { fn to_option(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
match self.resolve(table) { match self.resolve(table) {
Expectation::None => None, Expectation::None => None,
Expectation::HasType(t) | Expectation::HasType(t)
// Expectation::Castable(t) | | Expectation::Castable(t)
Expectation::RValueLikeUnsized(t) => Some(t), | Expectation::RValueLikeUnsized(t) => Some(t),
} }
} }
fn only_has_type(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> { fn only_has_type(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
match self { match self {
Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)), Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)),
// Expectation::Castable(_) | Expectation::Castable(_) | Expectation::RValueLikeUnsized(_) | Expectation::None => {
Expectation::RValueLikeUnsized(_) | Expectation::None => None, None
}
} }
} }

View file

@ -610,9 +610,9 @@ impl<'a> InferenceContext<'a> {
} }
} }
Expr::Cast { expr, type_ref } => { Expr::Cast { expr, type_ref } => {
// FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
let cast_ty = self.make_ty(type_ref); let cast_ty = self.make_ty(type_ref);
let _inner_ty =
self.infer_expr_inner(*expr, &Expectation::Castable(cast_ty.clone()));
// FIXME check the cast... // FIXME check the cast...
cast_ty cast_ty
} }

View file

@ -3200,3 +3200,34 @@ fn func() {
"#, "#,
); );
} }
#[test]
fn castable_to() {
check_infer(
r#"
//- minicore: sized
#[lang = "owned_box"]
pub struct Box<T: ?Sized> {
inner: *mut T,
}
impl<T> Box<T> {
fn new(t: T) -> Self { loop {} }
}
fn func() {
let x = Box::new([]) as Box<[i32; 0]>;
}
"#,
expect![[r#"
99..100 't': T
113..124 '{ loop {} }': Box<T>
115..122 'loop {}': !
120..122 '{}': ()
138..184 '{ ...0]>; }': ()
148..149 'x': Box<[i32; 0]>
152..160 'Box::new': fn new<[i32; 0]>([i32; 0]) -> Box<[i32; 0]>
152..164 'Box::new([])': Box<[i32; 0]>
152..181 'Box::n...2; 0]>': Box<[i32; 0]>
161..163 '[]': [i32; 0]
"#]],
);
}