Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/infer.rs7
-rw-r--r--crates/hir-ty/src/infer/closure.rs2
-rw-r--r--crates/hir-ty/src/infer/expr.rs50
-rw-r--r--crates/hir-ty/src/infer/path.rs2
-rw-r--r--crates/hir-ty/src/tests/simple.rs58
5 files changed, 88 insertions, 31 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 43a24c7136..767afdf9eb 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -219,6 +219,7 @@ struct InternedStandardTypes {
unknown: Ty,
bool_: Ty,
unit: Ty,
+ never: Ty,
}
impl Default for InternedStandardTypes {
@@ -227,6 +228,7 @@ impl Default for InternedStandardTypes {
unknown: TyKind::Error.intern(Interner),
bool_: TyKind::Scalar(Scalar::Bool).intern(Interner),
unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
+ never: TyKind::Never.intern(Interner),
}
}
}
@@ -1024,6 +1026,7 @@ impl<'a> InferenceContext<'a> {
pub(crate) enum Expectation {
None,
HasType(Ty),
+ #[allow(dead_code)]
Castable(Ty),
RValueLikeUnsized(Ty),
}
@@ -1102,6 +1105,10 @@ impl Expectation {
}
}
+ fn coercion_target_type(&self, table: &mut unify::InferenceTable<'_>) -> Ty {
+ self.only_has_type(table).unwrap_or_else(|| table.new_type_var())
+ }
+
/// Comment copied from rustc:
/// Disregard "castable to" expectations because they
/// can lead us astray. Consider for example `if cond
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 094e460dbf..7aa2176d67 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -51,7 +51,7 @@ impl InferenceContext<'_> {
.map(to_chalk_trait_id)
.collect();
- let self_ty = TyKind::Error.intern(Interner);
+ let self_ty = self.result.standard_types.unknown.clone();
let bounds = dyn_ty.bounds.clone().substitute(Interner, &[self_ty.cast(Interner)]);
for bound in bounds.iter(Interner) {
// NOTE(skip_binders): the extracted types are rebound by the returned `FnPointer`
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index f0655291b8..9f97261486 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -87,16 +87,15 @@ impl<'a> InferenceContext<'a> {
let expected = &expected.adjust_for_branches(&mut self.table);
self.infer_expr(
condition,
- &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
+ &Expectation::HasType(self.result.standard_types.bool_.clone()),
);
let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let mut both_arms_diverge = Diverges::Always;
- let result_ty = self.table.new_type_var();
let then_ty = self.infer_expr_inner(then_branch, expected);
both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
- let mut coerce = CoerceMany::new(result_ty);
+ let mut coerce = CoerceMany::new(expected.coercion_target_type(&mut self.table));
coerce.coerce(self, Some(then_branch), &then_ty);
let else_ty = match else_branch {
Some(else_branch) => self.infer_expr_inner(else_branch, expected),
@@ -113,7 +112,7 @@ impl<'a> InferenceContext<'a> {
&Expr::Let { pat, expr } => {
let input_ty = self.infer_expr(expr, &Expectation::none());
self.infer_pat(pat, &input_ty, BindingMode::default());
- TyKind::Scalar(Scalar::Bool).intern(Interner)
+ self.result.standard_types.bool_.clone()
}
Expr::Block { statements, tail, label, id: _ } => {
let old_resolver = mem::replace(
@@ -188,10 +187,12 @@ impl<'a> InferenceContext<'a> {
.intern(Interner)
}
&Expr::Loop { body, label } => {
+ // FIXME: should be:
+ // let ty = expected.coercion_target_type(&mut self.table);
let ty = self.table.new_type_var();
let (breaks, ()) =
self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| {
- this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+ this.infer_expr(body, &Expectation::HasType(TyBuilder::unit()));
});
match breaks {
@@ -199,16 +200,16 @@ impl<'a> InferenceContext<'a> {
self.diverges = Diverges::Maybe;
breaks
}
- None => TyKind::Never.intern(Interner),
+ None => self.result.standard_types.never.clone(),
}
}
&Expr::While { condition, body, label } => {
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
this.infer_expr(
condition,
- &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
+ &Expectation::HasType(this.result.standard_types.bool_.clone()),
);
- this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+ this.infer_expr(body, &Expectation::HasType(TyBuilder::unit()));
});
// the body may not run, so it diverging doesn't mean we diverge
@@ -224,7 +225,7 @@ impl<'a> InferenceContext<'a> {
self.infer_pat(pat, &pat_ty, BindingMode::default());
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
- this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+ this.infer_expr(body, &Expectation::HasType(TyBuilder::unit()));
});
// the body may not run, so it diverging doesn't mean we diverge
@@ -382,12 +383,9 @@ impl<'a> InferenceContext<'a> {
let expected = expected.adjust_for_branches(&mut self.table);
let result_ty = if arms.is_empty() {
- TyKind::Never.intern(Interner)
+ self.result.standard_types.never.clone()
} else {
- match &expected {
- Expectation::HasType(ty) => ty.clone(),
- _ => self.table.new_type_var(),
- }
+ expected.coercion_target_type(&mut self.table)
};
let mut coerce = CoerceMany::new(result_ty);
@@ -400,7 +398,7 @@ impl<'a> InferenceContext<'a> {
if let Some(guard_expr) = arm.guard {
self.infer_expr(
guard_expr,
- &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
+ &Expectation::HasType(self.result.standard_types.bool_.clone()),
);
}
@@ -425,7 +423,7 @@ impl<'a> InferenceContext<'a> {
is_break: false,
});
};
- TyKind::Never.intern(Interner)
+ self.result.standard_types.never.clone()
}
Expr::Break { expr, label } => {
let val_ty = if let Some(expr) = *expr {
@@ -439,7 +437,7 @@ impl<'a> InferenceContext<'a> {
// avoiding the borrowck
let mut coerce = mem::replace(
&mut ctxt.coerce,
- CoerceMany::new(self.result.standard_types.unknown.clone()),
+ CoerceMany::new(expected.coercion_target_type(&mut self.table)),
);
// FIXME: create a synthetic `()` during lowering so we have something to refer to here?
@@ -457,7 +455,7 @@ impl<'a> InferenceContext<'a> {
});
}
}
- TyKind::Never.intern(Interner)
+ self.result.standard_types.never.clone()
}
Expr::Return { expr } => {
if let Some(expr) = expr {
@@ -466,7 +464,7 @@ impl<'a> InferenceContext<'a> {
let unit = TyBuilder::unit();
let _ = self.coerce(Some(tgt_expr), &unit, &self.return_ty.clone());
}
- TyKind::Never.intern(Interner)
+ self.result.standard_types.never.clone()
}
Expr::Yield { expr } => {
if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
@@ -479,14 +477,14 @@ impl<'a> InferenceContext<'a> {
resume_ty
} else {
// FIXME: report error (yield expr in non-generator)
- TyKind::Error.intern(Interner)
+ self.result.standard_types.unknown.clone()
}
}
Expr::Yeet { expr } => {
if let &Some(expr) = expr {
self.infer_expr_inner(expr, &Expectation::None);
}
- TyKind::Never.intern(Interner)
+ self.result.standard_types.never.clone()
}
Expr::RecordLit { path, fields, spread, .. } => {
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
@@ -611,8 +609,8 @@ impl<'a> InferenceContext<'a> {
}
Expr::Cast { expr, type_ref } => {
let cast_ty = self.make_ty(type_ref);
- let _inner_ty =
- self.infer_expr_inner(*expr, &Expectation::Castable(cast_ty.clone()));
+ // FIXME: propagate the "castable to" expectation
+ let _inner_ty = self.infer_expr_inner(*expr, &Expectation::None);
// FIXME check the cast...
cast_ty
}
@@ -829,7 +827,7 @@ impl<'a> InferenceContext<'a> {
self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
self.infer_expr(
repeat,
- &Expectation::has_type(
+ &Expectation::HasType(
TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
),
);
@@ -852,7 +850,7 @@ impl<'a> InferenceContext<'a> {
TyKind::Array(coerce.complete(), len).intern(Interner)
}
Expr::Literal(lit) => match lit {
- Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
+ Literal::Bool(..) => self.result.standard_types.bool_.clone(),
Literal::String(..) => {
TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner))
.intern(Interner)
@@ -1148,7 +1146,7 @@ impl<'a> InferenceContext<'a> {
if let Some(expr) = else_branch {
self.infer_expr_coerce(
*expr,
- &Expectation::has_type(Ty::new(Interner, TyKind::Never)),
+ &Expectation::HasType(self.result.standard_types.never.clone()),
);
}
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 8bd17c0f39..0a8527afbd 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -112,7 +112,7 @@ impl<'a> InferenceContext<'a> {
let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
.fill(|x| {
it.next().unwrap_or_else(|| match x {
- ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
+ ParamKind::Type => self.result.standard_types.unknown.clone().cast(Interner),
ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
})
})
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 6f6b334c94..2e5787b701 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -3200,6 +3200,8 @@ fn func() {
"#,
);
}
+
+// FIXME
#[test]
fn castable_to() {
check_infer(
@@ -3224,10 +3226,60 @@ fn func() {
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..160 'Box::new': fn new<[{unknown}; 0]>([{unknown}; 0]) -> Box<[{unknown}; 0]>
+ 152..164 'Box::new([])': Box<[{unknown}; 0]>
152..181 'Box::n...2; 0]>': Box<[i32; 0]>
- 161..163 '[]': [i32; 0]
+ 161..163 '[]': [{unknown}; 0]
+ "#]],
+ );
+}
+
+#[test]
+fn castable_to1() {
+ check_infer(
+ r#"
+struct Ark<T>(T);
+impl<T> Ark<T> {
+ fn foo(&self) -> *const T {
+ &self.0
+ }
+}
+fn f<T>(t: Ark<T>) {
+ Ark::foo(&t) as *const ();
+}
+"#,
+ expect![[r#"
+ 47..51 'self': &Ark<T>
+ 65..88 '{ ... }': *const T
+ 75..82 '&self.0': &T
+ 76..80 'self': &Ark<T>
+ 76..82 'self.0': T
+ 99..100 't': Ark<T>
+ 110..144 '{ ... (); }': ()
+ 116..124 'Ark::foo': fn foo<T>(&Ark<T>) -> *const T
+ 116..128 'Ark::foo(&t)': *const T
+ 116..141 'Ark::f...nst ()': *const ()
+ 125..127 '&t': &Ark<T>
+ 126..127 't': Ark<T>
+ "#]],
+ );
+}
+
+// FIXME
+#[test]
+fn castable_to2() {
+ check_infer(
+ r#"
+fn func() {
+ let x = &0u32 as *const _;
+}
+"#,
+ expect![[r#"
+ 10..44 '{ ...t _; }': ()
+ 20..21 'x': *const {unknown}
+ 24..29 '&0u32': &u32
+ 24..41 '&0u32 ...onst _': *const {unknown}
+ 25..29 '0u32': u32
"#]],
);
}