Auto merge of #14120 - Veykril:castable, r=Veykril

internal: Revert castable expectation and simplify

Unfixes https://github.com/rust-lang/rust-analyzer/issues/11571, the PR for that introduced some regressions (tried fixing them but doing what rustc does there specifically does not help, probably because something else affects it as well there)
This commit is contained in:
bors 2023-02-10 15:44:04 +00:00
commit d9c020d426
5 changed files with 101 additions and 43 deletions

View file

@ -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

View file

@ -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`
@ -67,7 +67,7 @@ impl InferenceContext<'_> {
let arg = projection.substitution.as_slice(Interner).get(1)?;
if let Some(subst) = arg.ty(Interner)?.as_tuple() {
let generic_args = subst.as_slice(Interner);
let mut sig_tys = Vec::new();
let mut sig_tys = Vec::with_capacity(generic_args.len() + 1);
for arg in generic_args {
sig_tys.push(arg.ty(Interner)?.clone());
}

View file

@ -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
@ -234,7 +235,7 @@ impl<'a> InferenceContext<'a> {
Expr::Closure { body, args, ret_type, arg_types, closure_kind } => {
assert_eq!(args.len(), arg_types.len());
let mut sig_tys = Vec::new();
let mut sig_tys = Vec::with_capacity(arg_types.len() + 1);
// collect explicitly written argument types
for arg_type in arg_types.iter() {
@ -255,7 +256,8 @@ impl<'a> InferenceContext<'a> {
num_binders: 0,
sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
substitution: FnSubst(
Substitution::from_iter(Interner, sig_tys.clone()).shifted_in(Interner),
Substitution::from_iter(Interner, sig_tys.iter().cloned())
.shifted_in(Interner),
),
})
.intern(Interner);
@ -317,16 +319,16 @@ impl<'a> InferenceContext<'a> {
Expr::Call { callee, args, .. } => {
let callee_ty = self.infer_expr(*callee, &Expectation::none());
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone());
let mut res = None;
let mut derefed_callee = callee_ty.clone();
// manual loop to be able to access `derefs.table`
while let Some((callee_deref_ty, _)) = derefs.next() {
res = derefs.table.callable_sig(&callee_deref_ty, args.len());
if res.is_some() {
derefed_callee = callee_deref_ty;
break;
let (res, derefed_callee) = 'b: {
// manual loop to be able to access `derefs.table`
while let Some((callee_deref_ty, _)) = derefs.next() {
let res = derefs.table.callable_sig(&callee_deref_ty, args.len());
if res.is_some() {
break 'b (res, callee_deref_ty);
}
}
}
(None, callee_ty.clone())
};
// if the function is unresolved, we use is_varargs=true to
// suppress the arg count diagnostic here
let is_varargs =
@ -382,12 +384,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 +399,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 +424,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 +438,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 +456,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 +465,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 +478,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 +610,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 +828,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 +851,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 +1147,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()),
);
}

View file

@ -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()),
})
})

View file

@ -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
"#]],
);
}