mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 22:01:37 +00:00
Refactor expectation handling
So as to not use `TyKind::Error` as "no expectation".
This commit is contained in:
parent
99c73537fa
commit
556c9cebdb
3 changed files with 88 additions and 54 deletions
|
@ -370,10 +370,6 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
|
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
|
||||||
// TODO handle expectations properly
|
|
||||||
if ty2.is_unknown() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
self.table.unify(ty1, ty2)
|
self.table.unify(ty1, ty2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,17 +675,23 @@ impl<'a> InferenceContext<'a> {
|
||||||
/// When inferring an expression, we propagate downward whatever type hint we
|
/// When inferring an expression, we propagate downward whatever type hint we
|
||||||
/// are able in the form of an `Expectation`.
|
/// are able in the form of an `Expectation`.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
struct Expectation {
|
enum Expectation {
|
||||||
ty: Ty,
|
None,
|
||||||
/// See the `rvalue_hint` method.
|
HasType(Ty),
|
||||||
rvalue_hint: bool,
|
// Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts
|
||||||
|
RValueLikeUnsized(Ty),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expectation {
|
impl Expectation {
|
||||||
/// The expectation that the type of the expression needs to equal the given
|
/// The expectation that the type of the expression needs to equal the given
|
||||||
/// type.
|
/// type.
|
||||||
fn has_type(ty: Ty) -> Self {
|
fn has_type(ty: Ty) -> Self {
|
||||||
Expectation { ty, rvalue_hint: false }
|
if ty.is_unknown() {
|
||||||
|
// FIXME: get rid of this?
|
||||||
|
Expectation::None
|
||||||
|
} else {
|
||||||
|
Expectation::HasType(ty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The following explanation is copied straight from rustc:
|
/// The following explanation is copied straight from rustc:
|
||||||
|
@ -713,24 +715,41 @@ impl Expectation {
|
||||||
/// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
|
/// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
|
||||||
/// for examples of where this comes up,.
|
/// for examples of where this comes up,.
|
||||||
fn rvalue_hint(ty: Ty) -> Self {
|
fn rvalue_hint(ty: Ty) -> Self {
|
||||||
Expectation { ty, rvalue_hint: true }
|
match ty.strip_references().kind(&Interner) {
|
||||||
|
TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty),
|
||||||
|
_ => Expectation::has_type(ty),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This expresses no expectation on the type.
|
/// This expresses no expectation on the type.
|
||||||
fn none() -> Self {
|
fn none() -> Self {
|
||||||
Expectation {
|
Expectation::None
|
||||||
// FIXME
|
}
|
||||||
ty: TyKind::Error.intern(&Interner),
|
|
||||||
rvalue_hint: false,
|
fn resolve(&self, table: &mut unify::InferenceTable) -> Expectation {
|
||||||
|
match self {
|
||||||
|
Expectation::None => Expectation::None,
|
||||||
|
Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)),
|
||||||
|
Expectation::RValueLikeUnsized(t) => {
|
||||||
|
Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coercion_target(&self) -> Ty {
|
fn to_option(&self, table: &mut unify::InferenceTable) -> Option<Ty> {
|
||||||
if self.rvalue_hint {
|
match self.resolve(table) {
|
||||||
// FIXME
|
Expectation::None => None,
|
||||||
TyKind::Error.intern(&Interner)
|
Expectation::HasType(t) |
|
||||||
} else {
|
// Expectation::Castable(t) |
|
||||||
self.ty.clone()
|
Expectation::RValueLikeUnsized(t) => Some(t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn only_has_type(&self, table: &mut unify::InferenceTable) -> Option<Ty> {
|
||||||
|
match self {
|
||||||
|
Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)),
|
||||||
|
// Expectation::Castable(_) |
|
||||||
|
Expectation::RValueLikeUnsized(_) | Expectation::None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,6 @@ impl<'a> InferenceContext<'a> {
|
||||||
pub(super) fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
|
pub(super) fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
|
||||||
let from_ty = self.resolve_ty_shallow(from_ty);
|
let from_ty = self.resolve_ty_shallow(from_ty);
|
||||||
let to_ty = self.resolve_ty_shallow(to_ty);
|
let to_ty = self.resolve_ty_shallow(to_ty);
|
||||||
// TODO handle expectations properly
|
|
||||||
if to_ty.is_unknown() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
match self.coerce_inner(from_ty, &to_ty) {
|
match self.coerce_inner(from_ty, &to_ty) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
self.table.register_infer_ok(result);
|
self.table.register_infer_ok(result);
|
||||||
|
|
|
@ -39,13 +39,15 @@ impl<'a> InferenceContext<'a> {
|
||||||
// Any expression that produces a value of type `!` must have diverged
|
// Any expression that produces a value of type `!` must have diverged
|
||||||
self.diverges = Diverges::Always;
|
self.diverges = Diverges::Always;
|
||||||
}
|
}
|
||||||
let could_unify = self.unify(&ty, &expected.ty);
|
if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
|
||||||
|
let could_unify = self.unify(&ty, &expected_ty);
|
||||||
if !could_unify {
|
if !could_unify {
|
||||||
self.result.type_mismatches.insert(
|
self.result.type_mismatches.insert(
|
||||||
tgt_expr.into(),
|
tgt_expr.into(),
|
||||||
TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
|
TypeMismatch { expected: expected_ty.clone(), actual: ty.clone() },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,18 +55,20 @@ impl<'a> InferenceContext<'a> {
|
||||||
/// Return the type after possible coercion.
|
/// Return the type after possible coercion.
|
||||||
pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
|
pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
|
||||||
let ty = self.infer_expr_inner(expr, &expected);
|
let ty = self.infer_expr_inner(expr, &expected);
|
||||||
let ty = if !self.coerce(&ty, &expected.coercion_target()) {
|
let ty = if let Some(target) = expected.only_has_type(&mut self.table) {
|
||||||
|
if !self.coerce(&ty, &target) {
|
||||||
self.result.type_mismatches.insert(
|
self.result.type_mismatches.insert(
|
||||||
expr.into(),
|
expr.into(),
|
||||||
TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
|
TypeMismatch { expected: target.clone(), actual: ty.clone() },
|
||||||
);
|
);
|
||||||
// Return actual type when type mismatch.
|
// Return actual type when type mismatch.
|
||||||
// This is needed for diagnostic when return type mismatch.
|
// This is needed for diagnostic when return type mismatch.
|
||||||
ty
|
ty
|
||||||
} else if expected.coercion_target().is_unknown() {
|
|
||||||
ty
|
|
||||||
} else {
|
} else {
|
||||||
expected.ty.clone()
|
target.clone()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ty
|
||||||
};
|
};
|
||||||
|
|
||||||
ty
|
ty
|
||||||
|
@ -280,7 +284,9 @@ impl<'a> InferenceContext<'a> {
|
||||||
// Eagerly try to relate the closure type with the expected
|
// Eagerly try to relate the closure type with the expected
|
||||||
// type, otherwise we often won't have enough information to
|
// type, otherwise we often won't have enough information to
|
||||||
// infer the body.
|
// infer the body.
|
||||||
self.coerce(&closure_ty, &expected.ty);
|
if let Some(t) = expected.only_has_type(&mut self.table) {
|
||||||
|
self.coerce(&closure_ty, &t);
|
||||||
|
}
|
||||||
|
|
||||||
// Now go through the argument patterns
|
// Now go through the argument patterns
|
||||||
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
|
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
|
||||||
|
@ -413,7 +419,9 @@ impl<'a> InferenceContext<'a> {
|
||||||
self.write_variant_resolution(tgt_expr.into(), variant);
|
self.write_variant_resolution(tgt_expr.into(), variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.unify(&ty, &expected.ty);
|
if let Some(t) = expected.only_has_type(&mut self.table) {
|
||||||
|
self.unify(&ty, &t);
|
||||||
|
}
|
||||||
|
|
||||||
let substs = ty
|
let substs = ty
|
||||||
.as_adt()
|
.as_adt()
|
||||||
|
@ -516,6 +524,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
|
self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
|
||||||
}
|
}
|
||||||
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 _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);
|
||||||
// FIXME check the cast...
|
// FIXME check the cast...
|
||||||
|
@ -523,14 +532,16 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
Expr::Ref { expr, rawness, mutability } => {
|
Expr::Ref { expr, rawness, mutability } => {
|
||||||
let mutability = lower_to_chalk_mutability(*mutability);
|
let mutability = lower_to_chalk_mutability(*mutability);
|
||||||
let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) =
|
let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected
|
||||||
&self.resolve_ty_shallow(&expected.ty).as_reference_or_ptr()
|
.only_has_type(&mut self.table)
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|t| t.as_reference_or_ptr())
|
||||||
{
|
{
|
||||||
if *exp_mutability == Mutability::Mut && mutability == Mutability::Not {
|
if exp_mutability == Mutability::Mut && mutability == Mutability::Not {
|
||||||
// FIXME: record type error - expected mut reference but found shared ref,
|
// FIXME: record type error - expected mut reference but found shared ref,
|
||||||
// which cannot be coerced
|
// which cannot be coerced
|
||||||
}
|
}
|
||||||
if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr {
|
if exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr {
|
||||||
// FIXME: record type error - expected reference but found ptr,
|
// FIXME: record type error - expected reference but found ptr,
|
||||||
// which cannot be coerced
|
// which cannot be coerced
|
||||||
}
|
}
|
||||||
|
@ -701,8 +712,12 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Tuple { exprs } => {
|
Expr::Tuple { exprs } => {
|
||||||
let mut tys = match self.resolve_ty_shallow(&expected.ty).kind(&Interner) {
|
let mut tys = match expected
|
||||||
TyKind::Tuple(_, substs) => substs
|
.only_has_type(&mut self.table)
|
||||||
|
.as_ref()
|
||||||
|
.map(|t| t.kind(&Interner))
|
||||||
|
{
|
||||||
|
Some(TyKind::Tuple(_, substs)) => substs
|
||||||
.iter(&Interner)
|
.iter(&Interner)
|
||||||
.map(|a| a.assert_ty_ref(&Interner).clone())
|
.map(|a| a.assert_ty_ref(&Interner).clone())
|
||||||
.chain(repeat_with(|| self.table.new_type_var()))
|
.chain(repeat_with(|| self.table.new_type_var()))
|
||||||
|
@ -718,14 +733,16 @@ impl<'a> InferenceContext<'a> {
|
||||||
TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner)
|
TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner)
|
||||||
}
|
}
|
||||||
Expr::Array(array) => {
|
Expr::Array(array) => {
|
||||||
let elem_ty = match self.resolve_ty_shallow(&expected.ty).kind(&Interner) {
|
let elem_ty =
|
||||||
TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(),
|
match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(&Interner)) {
|
||||||
|
Some(TyKind::Array(st, _)) | Some(TyKind::Slice(st)) => st.clone(),
|
||||||
_ => self.table.new_type_var(),
|
_ => self.table.new_type_var(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let len = match array {
|
let len = match array {
|
||||||
Array::ElementList(items) => {
|
Array::ElementList(items) => {
|
||||||
for expr in items.iter() {
|
for expr in items.iter() {
|
||||||
|
// FIXME: use CoerceMany (coerce_merge_branch)
|
||||||
self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone()));
|
self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone()));
|
||||||
}
|
}
|
||||||
Some(items.len() as u64)
|
Some(items.len() as u64)
|
||||||
|
@ -839,7 +856,9 @@ impl<'a> InferenceContext<'a> {
|
||||||
// we don't even make an attempt at coercion
|
// we don't even make an attempt at coercion
|
||||||
self.table.new_maybe_never_var()
|
self.table.new_maybe_never_var()
|
||||||
} else {
|
} else {
|
||||||
self.coerce(&TyBuilder::unit(), &expected.coercion_target());
|
if let Some(t) = expected.only_has_type(&mut self.table) {
|
||||||
|
self.coerce(&TyBuilder::unit(), &t);
|
||||||
|
}
|
||||||
TyBuilder::unit()
|
TyBuilder::unit()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue