internal: Revert castable expectation and simplify

This commit is contained in:
Lukas Wirth 2023-02-10 16:08:47 +01:00
parent 8f5deb4ff2
commit 79492cb8ae
5 changed files with 88 additions and 31 deletions

View File

@ -219,6 +219,7 @@ struct InternedStandardTypes {
unknown: Ty, unknown: Ty,
bool_: Ty, bool_: Ty,
unit: Ty, unit: Ty,
never: Ty,
} }
impl Default for InternedStandardTypes { impl Default for InternedStandardTypes {
@ -227,6 +228,7 @@ impl Default for InternedStandardTypes {
unknown: TyKind::Error.intern(Interner), unknown: TyKind::Error.intern(Interner),
bool_: TyKind::Scalar(Scalar::Bool).intern(Interner), bool_: TyKind::Scalar(Scalar::Bool).intern(Interner),
unit: TyKind::Tuple(0, Substitution::empty(Interner)).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 { pub(crate) enum Expectation {
None, None,
HasType(Ty), HasType(Ty),
#[allow(dead_code)]
Castable(Ty), Castable(Ty),
RValueLikeUnsized(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: /// Comment copied from rustc:
/// Disregard "castable to" expectations because they /// Disregard "castable to" expectations because they
/// can lead us astray. Consider for example `if cond /// can lead us astray. Consider for example `if cond

View File

@ -51,7 +51,7 @@ impl InferenceContext<'_> {
.map(to_chalk_trait_id) .map(to_chalk_trait_id)
.collect(); .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)]); let bounds = dyn_ty.bounds.clone().substitute(Interner, &[self_ty.cast(Interner)]);
for bound in bounds.iter(Interner) { for bound in bounds.iter(Interner) {
// NOTE(skip_binders): the extracted types are rebound by the returned `FnPointer` // NOTE(skip_binders): the extracted types are rebound by the returned `FnPointer`

View File

@ -87,16 +87,15 @@ impl<'a> InferenceContext<'a> {
let expected = &expected.adjust_for_branches(&mut self.table); let expected = &expected.adjust_for_branches(&mut self.table);
self.infer_expr( self.infer_expr(
condition, 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 condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let mut both_arms_diverge = Diverges::Always; 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); let then_ty = self.infer_expr_inner(then_branch, expected);
both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); 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); coerce.coerce(self, Some(then_branch), &then_ty);
let else_ty = match else_branch { let else_ty = match else_branch {
Some(else_branch) => self.infer_expr_inner(else_branch, expected), Some(else_branch) => self.infer_expr_inner(else_branch, expected),
@ -113,7 +112,7 @@ impl<'a> InferenceContext<'a> {
&Expr::Let { pat, expr } => { &Expr::Let { pat, expr } => {
let input_ty = self.infer_expr(expr, &Expectation::none()); let input_ty = self.infer_expr(expr, &Expectation::none());
self.infer_pat(pat, &input_ty, BindingMode::default()); 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: _ } => { Expr::Block { statements, tail, label, id: _ } => {
let old_resolver = mem::replace( let old_resolver = mem::replace(
@ -188,10 +187,12 @@ impl<'a> InferenceContext<'a> {
.intern(Interner) .intern(Interner)
} }
&Expr::Loop { body, label } => { &Expr::Loop { body, label } => {
// FIXME: should be:
// let ty = expected.coercion_target_type(&mut self.table);
let ty = self.table.new_type_var(); let ty = self.table.new_type_var();
let (breaks, ()) = let (breaks, ()) =
self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| { 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 { match breaks {
@ -199,16 +200,16 @@ impl<'a> InferenceContext<'a> {
self.diverges = Diverges::Maybe; self.diverges = Diverges::Maybe;
breaks breaks
} }
None => TyKind::Never.intern(Interner), None => self.result.standard_types.never.clone(),
} }
} }
&Expr::While { condition, body, label } => { &Expr::While { condition, body, label } => {
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| { self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
this.infer_expr( this.infer_expr(
condition, 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 // 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.infer_pat(pat, &pat_ty, BindingMode::default());
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| { 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 // 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 expected = expected.adjust_for_branches(&mut self.table);
let result_ty = if arms.is_empty() { let result_ty = if arms.is_empty() {
TyKind::Never.intern(Interner) self.result.standard_types.never.clone()
} else { } else {
match &expected { expected.coercion_target_type(&mut self.table)
Expectation::HasType(ty) => ty.clone(),
_ => self.table.new_type_var(),
}
}; };
let mut coerce = CoerceMany::new(result_ty); let mut coerce = CoerceMany::new(result_ty);
@ -400,7 +398,7 @@ impl<'a> InferenceContext<'a> {
if let Some(guard_expr) = arm.guard { if let Some(guard_expr) = arm.guard {
self.infer_expr( self.infer_expr(
guard_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, is_break: false,
}); });
}; };
TyKind::Never.intern(Interner) self.result.standard_types.never.clone()
} }
Expr::Break { expr, label } => { Expr::Break { expr, label } => {
let val_ty = if let Some(expr) = *expr { let val_ty = if let Some(expr) = *expr {
@ -439,7 +437,7 @@ impl<'a> InferenceContext<'a> {
// avoiding the borrowck // avoiding the borrowck
let mut coerce = mem::replace( let mut coerce = mem::replace(
&mut ctxt.coerce, &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? // 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 } => { Expr::Return { expr } => {
if let Some(expr) = expr { if let Some(expr) = expr {
@ -466,7 +464,7 @@ impl<'a> InferenceContext<'a> {
let unit = TyBuilder::unit(); let unit = TyBuilder::unit();
let _ = self.coerce(Some(tgt_expr), &unit, &self.return_ty.clone()); let _ = self.coerce(Some(tgt_expr), &unit, &self.return_ty.clone());
} }
TyKind::Never.intern(Interner) self.result.standard_types.never.clone()
} }
Expr::Yield { expr } => { Expr::Yield { expr } => {
if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() { if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
@ -479,14 +477,14 @@ impl<'a> InferenceContext<'a> {
resume_ty resume_ty
} else { } else {
// FIXME: report error (yield expr in non-generator) // FIXME: report error (yield expr in non-generator)
TyKind::Error.intern(Interner) self.result.standard_types.unknown.clone()
} }
} }
Expr::Yeet { expr } => { Expr::Yeet { expr } => {
if let &Some(expr) = expr { if let &Some(expr) = expr {
self.infer_expr_inner(expr, &Expectation::None); self.infer_expr_inner(expr, &Expectation::None);
} }
TyKind::Never.intern(Interner) self.result.standard_types.never.clone()
} }
Expr::RecordLit { path, fields, spread, .. } => { Expr::RecordLit { path, fields, spread, .. } => {
let (ty, def_id) = self.resolve_variant(path.as_deref(), false); let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
@ -611,8 +609,8 @@ impl<'a> InferenceContext<'a> {
} }
Expr::Cast { expr, type_ref } => { Expr::Cast { expr, type_ref } => {
let cast_ty = self.make_ty(type_ref); let cast_ty = self.make_ty(type_ref);
let _inner_ty = // FIXME: propagate the "castable to" expectation
self.infer_expr_inner(*expr, &Expectation::Castable(cast_ty.clone())); let _inner_ty = self.infer_expr_inner(*expr, &Expectation::None);
// FIXME check the cast... // FIXME check the cast...
cast_ty cast_ty
} }
@ -829,7 +827,7 @@ impl<'a> InferenceContext<'a> {
self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty)); self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
self.infer_expr( self.infer_expr(
repeat, repeat,
&Expectation::has_type( &Expectation::HasType(
TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
), ),
); );
@ -852,7 +850,7 @@ impl<'a> InferenceContext<'a> {
TyKind::Array(coerce.complete(), len).intern(Interner) TyKind::Array(coerce.complete(), len).intern(Interner)
} }
Expr::Literal(lit) => match lit { Expr::Literal(lit) => match lit {
Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner), Literal::Bool(..) => self.result.standard_types.bool_.clone(),
Literal::String(..) => { Literal::String(..) => {
TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner)) TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner))
.intern(Interner) .intern(Interner)
@ -1148,7 +1146,7 @@ impl<'a> InferenceContext<'a> {
if let Some(expr) = else_branch { if let Some(expr) = else_branch {
self.infer_expr_coerce( self.infer_expr_coerce(
*expr, *expr,
&Expectation::has_type(Ty::new(Interner, TyKind::Never)), &Expectation::HasType(self.result.standard_types.never.clone()),
); );
} }

View File

@ -112,7 +112,7 @@ impl<'a> InferenceContext<'a> {
let ty = TyBuilder::value_ty(self.db, typable, parent_substs) let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
.fill(|x| { .fill(|x| {
it.next().unwrap_or_else(|| match 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()), ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
}) })
}) })

View File

@ -3200,6 +3200,8 @@ fn func() {
"#, "#,
); );
} }
// FIXME
#[test] #[test]
fn castable_to() { fn castable_to() {
check_infer( check_infer(
@ -3224,10 +3226,60 @@ fn func() {
120..122 '{}': () 120..122 '{}': ()
138..184 '{ ...0]>; }': () 138..184 '{ ...0]>; }': ()
148..149 'x': Box<[i32; 0]> 148..149 'x': Box<[i32; 0]>
152..160 'Box::new': fn new<[i32; 0]>([i32; 0]) -> Box<[i32; 0]> 152..160 'Box::new': fn new<[{unknown}; 0]>([{unknown}; 0]) -> Box<[{unknown}; 0]>
152..164 'Box::new([])': Box<[i32; 0]> 152..164 'Box::new([])': Box<[{unknown}; 0]>
152..181 'Box::n...2; 0]>': Box<[i32; 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
"#]], "#]],
); );
} }