2019-02-23 14:24:07 +00:00
|
|
|
//! Type inference, i.e. the process of walking through the code and determining
|
|
|
|
//! the type of each expression and pattern.
|
|
|
|
//!
|
|
|
|
//! For type inference, compare the implementations in rustc (the various
|
|
|
|
//! check_* methods in librustc_typeck/check/mod.rs are a good entry point) and
|
|
|
|
//! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for
|
|
|
|
//! inference here is the `infer` function, which infers the types of all
|
|
|
|
//! expressions in a given function.
|
|
|
|
//!
|
|
|
|
//! During inference, types (i.e. the `Ty` struct) can contain type 'variables'
|
|
|
|
//! which represent currently unknown types; as we walk through the expressions,
|
|
|
|
//! we might determine that certain variables need to be equal to each other, or
|
|
|
|
//! to certain types. To record this, we use the union-find implementation from
|
|
|
|
//! the `ena` crate, which is extracted from rustc.
|
|
|
|
|
Refactor autoderef and method resolution
- don't return the receiver type from method resolution; instead just
return the autorefs/autoderefs that happened and repeat them. This
ensures all the effects like trait obligations and whatever we learned
about type variables from derefing them are actually applied. Also, it
allows us to get rid of `decanonicalize_ty`, which was just wrong in
principle.
- Autoderef itself now directly works with an inference table. Sadly
this has the effect of making it harder to use as an iterator, often
requiring manual `while let` loops. (rustc works around this by using
inner mutability in the inference context, so that things like unifying
types don't require a unique reference.)
- We now record the adjustments (autoref/deref) for method receivers
and index expressions, which we didn't before.
- Removed the redundant crate parameter from method resolution, since
the trait_env contains the crate as well.
- in the HIR API, the methods now take a scope to determine the trait env.
`Type` carries a trait env, but I think that's probably a bad decision
because it's easy to create it with the wrong env, e.g. by using
`Adt::ty`. This mostly didn't matter so far because
`iterate_method_candidates` took a crate parameter and ignored
`self.krate`, but the trait env would still have been wrong in those
cases, which I think would give some wrong results in some edge cases.
Fixes #10058.
2022-02-16 16:44:03 +00:00
|
|
|
use std::ops::Index;
|
2019-02-23 14:24:07 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2022-03-09 18:50:24 +00:00
|
|
|
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
2019-10-30 14:28:30 +00:00
|
|
|
use hir_def::{
|
2019-11-27 12:56:20 +00:00
|
|
|
body::Body,
|
2020-05-10 15:08:28 +00:00
|
|
|
data::{ConstData, FunctionData, StaticData},
|
2021-08-22 15:21:47 +00:00
|
|
|
expr::{BindingAnnotation, ExprId, PatId},
|
2019-12-29 16:39:31 +00:00
|
|
|
lang_item::LangItemTarget,
|
2019-12-13 21:32:44 +00:00
|
|
|
path::{path, Path},
|
2021-07-22 11:40:18 +00:00
|
|
|
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
|
2021-03-01 18:30:34 +00:00
|
|
|
type_ref::TypeRef,
|
2021-05-16 13:50:28 +00:00
|
|
|
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
|
|
|
|
TraitId, TypeAliasId, VariantId,
|
2019-10-30 14:28:30 +00:00
|
|
|
};
|
2021-12-09 17:13:15 +00:00
|
|
|
use hir_expand::name::{name, Name};
|
2022-03-09 18:50:24 +00:00
|
|
|
use itertools::Either;
|
2021-01-15 00:11:07 +00:00
|
|
|
use la_arena::ArenaMap;
|
2020-07-13 14:16:53 +00:00
|
|
|
use rustc_hash::FxHashMap;
|
|
|
|
use stdx::impl_from;
|
2019-02-23 14:24:07 +00:00
|
|
|
|
2020-01-24 14:22:00 +00:00
|
|
|
use crate::{
|
2022-03-17 11:39:42 +00:00
|
|
|
db::HirDatabase, fold_tys_and_consts, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
|
|
|
|
to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal, GenericArg, Goal, InEnvironment,
|
|
|
|
Interner, ProjectionTy, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
2020-01-24 14:22:00 +00:00
|
|
|
};
|
2019-02-23 14:24:07 +00:00
|
|
|
|
2021-03-16 15:45:46 +00:00
|
|
|
// This lint has a false positive here. See the link below for details.
|
|
|
|
//
|
|
|
|
// https://github.com/rust-lang/rust/issues/57411
|
2022-03-21 17:54:20 +00:00
|
|
|
#[allow(unreachable_pub)]
|
2022-03-20 23:08:12 +00:00
|
|
|
pub use coerce::could_coerce;
|
2021-03-16 15:45:46 +00:00
|
|
|
#[allow(unreachable_pub)]
|
|
|
|
pub use unify::could_unify;
|
2019-12-01 21:14:28 +00:00
|
|
|
|
Refactor autoderef and method resolution
- don't return the receiver type from method resolution; instead just
return the autorefs/autoderefs that happened and repeat them. This
ensures all the effects like trait obligations and whatever we learned
about type variables from derefing them are actually applied. Also, it
allows us to get rid of `decanonicalize_ty`, which was just wrong in
principle.
- Autoderef itself now directly works with an inference table. Sadly
this has the effect of making it harder to use as an iterator, often
requiring manual `while let` loops. (rustc works around this by using
inner mutability in the inference context, so that things like unifying
types don't require a unique reference.)
- We now record the adjustments (autoref/deref) for method receivers
and index expressions, which we didn't before.
- Removed the redundant crate parameter from method resolution, since
the trait_env contains the crate as well.
- in the HIR API, the methods now take a scope to determine the trait env.
`Type` carries a trait env, but I think that's probably a bad decision
because it's easy to create it with the wrong env, e.g. by using
`Adt::ty`. This mostly didn't matter so far because
`iterate_method_candidates` took a crate parameter and ignored
`self.krate`, but the trait env would still have been wrong in those
cases, which I think would give some wrong results in some edge cases.
Fixes #10058.
2022-02-16 16:44:03 +00:00
|
|
|
pub(crate) mod unify;
|
2019-09-23 16:53:52 +00:00
|
|
|
mod path;
|
2019-10-12 15:39:20 +00:00
|
|
|
mod expr;
|
|
|
|
mod pat;
|
|
|
|
mod coerce;
|
2021-06-29 15:35:37 +00:00
|
|
|
mod closure;
|
2019-04-20 10:34:36 +00:00
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
/// The entry point of type inference.
|
2020-03-13 15:05:46 +00:00
|
|
|
pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
|
2020-08-12 14:32:36 +00:00
|
|
|
let _p = profile::span("infer_query");
|
2020-03-13 15:05:46 +00:00
|
|
|
let resolver = def.resolver(db.upcast());
|
2019-11-12 13:46:27 +00:00
|
|
|
let mut ctx = InferenceContext::new(db, def, resolver);
|
2019-02-23 14:24:07 +00:00
|
|
|
|
2019-11-27 13:02:33 +00:00
|
|
|
match def {
|
|
|
|
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
|
|
|
|
DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)),
|
2020-05-10 15:08:28 +00:00
|
|
|
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
|
2019-03-30 11:17:31 +00:00
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
|
|
|
|
ctx.infer_body();
|
|
|
|
|
|
|
|
Arc::new(ctx.resolve_all())
|
|
|
|
}
|
|
|
|
|
2021-11-27 13:13:47 +00:00
|
|
|
/// Fully normalize all the types found within `ty` in context of `owner` body definition.
|
|
|
|
///
|
|
|
|
/// This is appropriate to use only after type-check: it assumes
|
|
|
|
/// that normalization will succeed, for example.
|
|
|
|
pub(crate) fn normalize(db: &dyn HirDatabase, owner: DefWithBodyId, ty: Ty) -> Ty {
|
|
|
|
if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) {
|
|
|
|
return ty;
|
|
|
|
}
|
|
|
|
let krate = owner.module(db.upcast()).krate();
|
|
|
|
let trait_env = owner
|
|
|
|
.as_generic_def_id()
|
|
|
|
.map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
|
2022-03-12 13:35:25 +00:00
|
|
|
let mut table = unify::InferenceTable::new(db, trait_env);
|
2021-11-27 13:13:47 +00:00
|
|
|
|
|
|
|
let ty_with_vars = table.normalize_associated_types_in(ty);
|
|
|
|
table.resolve_obligations_as_possible();
|
|
|
|
table.propagate_diverging_flag();
|
|
|
|
table.resolve_completely(ty_with_vars)
|
|
|
|
}
|
|
|
|
|
2019-03-02 19:05:37 +00:00
|
|
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
2019-03-04 14:49:18 +00:00
|
|
|
enum ExprOrPatId {
|
2019-03-04 14:52:48 +00:00
|
|
|
ExprId(ExprId),
|
|
|
|
PatId(PatId),
|
2019-03-01 23:26:49 +00:00
|
|
|
}
|
2020-07-13 14:16:53 +00:00
|
|
|
impl_from!(ExprId, PatId for ExprOrPatId);
|
2019-03-01 23:26:49 +00:00
|
|
|
|
2019-03-16 18:13:13 +00:00
|
|
|
/// Binding modes inferred for patterns.
|
2021-06-14 04:57:10 +00:00
|
|
|
/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
|
2019-03-16 18:13:13 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
2021-12-12 09:24:10 +00:00
|
|
|
pub enum BindingMode {
|
2019-03-16 18:13:13 +00:00
|
|
|
Move,
|
|
|
|
Ref(Mutability),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BindingMode {
|
2020-11-02 15:31:38 +00:00
|
|
|
fn convert(annotation: BindingAnnotation) -> BindingMode {
|
2019-03-16 18:13:13 +00:00
|
|
|
match annotation {
|
|
|
|
BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move,
|
2021-03-01 18:30:34 +00:00
|
|
|
BindingAnnotation::Ref => BindingMode::Ref(Mutability::Not),
|
2019-03-16 18:13:13 +00:00
|
|
|
BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-17 18:46:01 +00:00
|
|
|
impl Default for BindingMode {
|
|
|
|
fn default() -> Self {
|
|
|
|
BindingMode::Move
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-01 19:53:10 +00:00
|
|
|
#[derive(Debug)]
|
2021-07-06 16:05:40 +00:00
|
|
|
pub(crate) struct InferOk<T> {
|
|
|
|
value: T,
|
2021-05-16 16:27:17 +00:00
|
|
|
goals: Vec<InEnvironment<Goal>>,
|
2021-05-01 19:53:10 +00:00
|
|
|
}
|
2021-07-06 16:05:40 +00:00
|
|
|
|
|
|
|
impl<T> InferOk<T> {
|
|
|
|
fn map<U>(self, f: impl FnOnce(T) -> U) -> InferOk<U> {
|
|
|
|
InferOk { value: f(self.value), goals: self.goals }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-01 19:53:10 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub(crate) struct TypeError;
|
2021-07-06 16:05:40 +00:00
|
|
|
pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
|
2021-05-01 19:53:10 +00:00
|
|
|
|
2021-06-12 14:17:23 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
|
|
pub enum InferenceDiagnostic {
|
|
|
|
NoSuchField { expr: ExprId },
|
|
|
|
BreakOutsideOfLoop { expr: ExprId },
|
|
|
|
}
|
|
|
|
|
2019-08-11 10:40:08 +00:00
|
|
|
/// A mismatch between an expected and an inferred type.
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
|
|
|
pub struct TypeMismatch {
|
|
|
|
pub expected: Ty,
|
|
|
|
pub actual: Ty,
|
|
|
|
}
|
|
|
|
|
2021-03-14 16:25:29 +00:00
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
struct InternedStandardTypes {
|
|
|
|
unknown: Ty,
|
2021-08-22 15:21:47 +00:00
|
|
|
bool_: Ty,
|
|
|
|
unit: Ty,
|
2021-03-14 16:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for InternedStandardTypes {
|
|
|
|
fn default() -> Self {
|
2021-08-22 15:21:47 +00:00
|
|
|
InternedStandardTypes {
|
2021-12-19 16:58:39 +00:00
|
|
|
unknown: TyKind::Error.intern(Interner),
|
|
|
|
bool_: TyKind::Scalar(Scalar::Bool).intern(Interner),
|
|
|
|
unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
|
2021-08-22 15:21:47 +00:00
|
|
|
}
|
2021-03-14 16:25:29 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-08 12:31:16 +00:00
|
|
|
/// Represents coercing a value to a different type of value.
|
|
|
|
///
|
|
|
|
/// We transform values by following a number of `Adjust` steps in order.
|
|
|
|
/// See the documentation on variants of `Adjust` for more details.
|
|
|
|
///
|
|
|
|
/// Here are some common scenarios:
|
|
|
|
///
|
|
|
|
/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
|
|
|
|
/// Here the pointer will be dereferenced N times (where a dereference can
|
|
|
|
/// happen to raw or borrowed pointers or any smart pointer which implements
|
|
|
|
/// Deref, including Box<_>). The types of dereferences is given by
|
|
|
|
/// `autoderefs`. It can then be auto-referenced zero or one times, indicated
|
|
|
|
/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
|
|
|
|
/// `false`.
|
|
|
|
///
|
|
|
|
/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
|
|
|
|
/// with a thin pointer, deref a number of times, unsize the underlying data,
|
|
|
|
/// then autoref. The 'unsize' phase may change a fixed length array to a
|
|
|
|
/// dynamically sized one, a concrete object to a trait object, or statically
|
|
|
|
/// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
|
|
|
|
/// represented by:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// Deref(None) -> [i32; 4],
|
|
|
|
/// Borrow(AutoBorrow::Ref) -> &[i32; 4],
|
|
|
|
/// Unsize -> &[i32],
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
|
|
|
|
/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
|
|
|
|
/// The autoderef and -ref are the same as in the above example, but the type
|
|
|
|
/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
|
|
|
|
/// the underlying conversions from `[i32; 4]` to `[i32]`.
|
|
|
|
///
|
|
|
|
/// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
|
|
|
|
/// that case, we have the pointer we need coming in, so there are no
|
|
|
|
/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
|
|
|
|
/// At some point, of course, `Box` should move out of the compiler, in which
|
|
|
|
/// case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
|
|
|
|
/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
|
2021-07-06 16:05:40 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub struct Adjustment {
|
|
|
|
pub kind: Adjust,
|
|
|
|
pub target: Ty,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub enum Adjust {
|
|
|
|
/// Go from ! to any type.
|
|
|
|
NeverToAny,
|
|
|
|
/// Dereference once, producing a place.
|
|
|
|
Deref(Option<OverloadedDeref>),
|
|
|
|
/// Take the address and produce either a `&` or `*` pointer.
|
|
|
|
Borrow(AutoBorrow),
|
|
|
|
Pointer(PointerCast),
|
|
|
|
}
|
|
|
|
|
2021-07-08 12:31:16 +00:00
|
|
|
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
|
|
|
|
/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
|
|
|
|
/// The target type is `U` in both cases, with the region and mutability
|
|
|
|
/// being those shared by both the receiver and the returned reference.
|
2021-07-06 16:05:40 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
Refactor autoderef and method resolution
- don't return the receiver type from method resolution; instead just
return the autorefs/autoderefs that happened and repeat them. This
ensures all the effects like trait obligations and whatever we learned
about type variables from derefing them are actually applied. Also, it
allows us to get rid of `decanonicalize_ty`, which was just wrong in
principle.
- Autoderef itself now directly works with an inference table. Sadly
this has the effect of making it harder to use as an iterator, often
requiring manual `while let` loops. (rustc works around this by using
inner mutability in the inference context, so that things like unifying
types don't require a unique reference.)
- We now record the adjustments (autoref/deref) for method receivers
and index expressions, which we didn't before.
- Removed the redundant crate parameter from method resolution, since
the trait_env contains the crate as well.
- in the HIR API, the methods now take a scope to determine the trait env.
`Type` carries a trait env, but I think that's probably a bad decision
because it's easy to create it with the wrong env, e.g. by using
`Adt::ty`. This mostly didn't matter so far because
`iterate_method_candidates` took a crate parameter and ignored
`self.krate`, but the trait env would still have been wrong in those
cases, which I think would give some wrong results in some edge cases.
Fixes #10058.
2022-02-16 16:44:03 +00:00
|
|
|
pub struct OverloadedDeref(pub Mutability);
|
2021-07-06 16:05:40 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub enum AutoBorrow {
|
2021-07-08 12:31:16 +00:00
|
|
|
/// Converts from T to &T.
|
2021-07-06 16:05:40 +00:00
|
|
|
Ref(Mutability),
|
2021-07-08 12:31:16 +00:00
|
|
|
/// Converts from T to *T.
|
2021-07-06 16:05:40 +00:00
|
|
|
RawPtr(Mutability),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub enum PointerCast {
|
|
|
|
/// Go from a fn-item type to a fn-pointer type.
|
|
|
|
ReifyFnPointer,
|
|
|
|
|
|
|
|
/// Go from a safe fn pointer to an unsafe fn pointer.
|
|
|
|
UnsafeFnPointer,
|
|
|
|
|
|
|
|
/// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
|
|
|
|
/// It cannot convert a closure that requires unsafe.
|
|
|
|
ClosureFnPointer(Safety),
|
|
|
|
|
|
|
|
/// Go from a mut raw pointer to a const raw pointer.
|
|
|
|
MutToConstPointer,
|
|
|
|
|
2022-02-02 12:35:46 +00:00
|
|
|
#[allow(dead_code)]
|
2021-07-06 16:05:40 +00:00
|
|
|
/// Go from `*const [T; N]` to `*const T`
|
|
|
|
ArrayToPointer,
|
|
|
|
|
|
|
|
/// Unsize a pointer/reference value, e.g., `&[T; n]` to
|
|
|
|
/// `&[T]`. Note that the source could be a thin or fat pointer.
|
|
|
|
/// This will do things like convert thin pointers to fat
|
|
|
|
/// pointers, or convert structs containing thin pointers to
|
|
|
|
/// structs containing fat pointers, or convert between fat
|
|
|
|
/// pointers. We don't store the details of how the transform is
|
|
|
|
/// done (in fact, we don't know that, because it might depend on
|
|
|
|
/// the precise type parameters). We just store the target
|
|
|
|
/// type. Codegen backends and miri figure out what has to be done
|
|
|
|
/// based on the precise source/target type at hand.
|
|
|
|
Unsize,
|
|
|
|
}
|
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
/// The result of type inference: A mapping from expressions and patterns to types.
|
2019-07-14 12:23:44 +00:00
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Default)]
|
2019-02-23 14:24:07 +00:00
|
|
|
pub struct InferenceResult {
|
|
|
|
/// For each method call expr, records the function it resolves to.
|
2021-05-23 14:59:23 +00:00
|
|
|
method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>,
|
2019-02-23 14:24:07 +00:00
|
|
|
/// For each field access expr, records the field it resolves to.
|
2020-04-25 12:23:34 +00:00
|
|
|
field_resolutions: FxHashMap<ExprId, FieldId>,
|
2021-04-06 17:44:28 +00:00
|
|
|
/// For each struct literal or pattern, records the variant it resolves to.
|
2019-11-27 13:25:01 +00:00
|
|
|
variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
|
2019-03-02 19:05:37 +00:00
|
|
|
/// For each associated item record what it resolves to
|
2019-11-27 13:02:33 +00:00
|
|
|
assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
|
2021-06-12 14:17:23 +00:00
|
|
|
pub diagnostics: Vec<InferenceDiagnostic>,
|
2019-11-27 14:46:02 +00:00
|
|
|
pub type_of_expr: ArenaMap<ExprId, Ty>,
|
2021-05-19 04:23:16 +00:00
|
|
|
/// For each pattern record the type it resolves to.
|
|
|
|
///
|
|
|
|
/// **Note**: When a pattern type is resolved it may still contain
|
|
|
|
/// unresolved or missing subpatterns or subpatterns of mismatched types.
|
2019-11-27 14:46:02 +00:00
|
|
|
pub type_of_pat: ArenaMap<PatId, Ty>,
|
2021-05-19 04:23:16 +00:00
|
|
|
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
2021-03-14 16:25:29 +00:00
|
|
|
/// Interned Unknown to return references to.
|
|
|
|
standard_types: InternedStandardTypes,
|
2021-06-01 20:29:07 +00:00
|
|
|
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
2021-07-06 16:05:40 +00:00
|
|
|
pub pat_adjustments: FxHashMap<PatId, Vec<Adjustment>>,
|
2021-12-12 09:24:10 +00:00
|
|
|
pub pat_binding_modes: FxHashMap<PatId, BindingMode>,
|
2021-07-06 16:05:40 +00:00
|
|
|
pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl InferenceResult {
|
2021-05-23 14:59:23 +00:00
|
|
|
pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> {
|
|
|
|
self.method_resolutions.get(&expr).cloned()
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2020-04-25 12:23:34 +00:00
|
|
|
pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
|
2019-07-04 17:26:44 +00:00
|
|
|
self.field_resolutions.get(&expr).copied()
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2019-11-27 13:25:01 +00:00
|
|
|
pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
|
2019-07-21 11:11:45 +00:00
|
|
|
self.variant_resolutions.get(&id.into()).copied()
|
|
|
|
}
|
2019-11-27 13:25:01 +00:00
|
|
|
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
|
2019-07-21 11:11:45 +00:00
|
|
|
self.variant_resolutions.get(&id.into()).copied()
|
2019-07-12 16:56:18 +00:00
|
|
|
}
|
2019-11-27 13:02:33 +00:00
|
|
|
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> {
|
2019-07-04 17:26:44 +00:00
|
|
|
self.assoc_resolutions.get(&id.into()).copied()
|
2019-03-04 14:49:18 +00:00
|
|
|
}
|
2019-11-27 13:02:33 +00:00
|
|
|
pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItemId> {
|
2019-07-04 17:26:44 +00:00
|
|
|
self.assoc_resolutions.get(&id.into()).copied()
|
2019-03-01 23:26:49 +00:00
|
|
|
}
|
2019-08-11 10:40:08 +00:00
|
|
|
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
|
2021-05-19 04:23:16 +00:00
|
|
|
self.type_mismatches.get(&expr.into())
|
|
|
|
}
|
|
|
|
pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> {
|
|
|
|
self.type_mismatches.get(&pat.into())
|
|
|
|
}
|
|
|
|
pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> {
|
|
|
|
self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
|
|
|
|
ExprOrPatId::ExprId(expr) => Some((expr, mismatch)),
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
pub fn pat_type_mismatches(&self) -> impl Iterator<Item = (PatId, &TypeMismatch)> {
|
|
|
|
self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
|
|
|
|
ExprOrPatId::PatId(pat) => Some((pat, mismatch)),
|
|
|
|
_ => None,
|
|
|
|
})
|
2019-08-11 10:40:08 +00:00
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Index<ExprId> for InferenceResult {
|
|
|
|
type Output = Ty;
|
|
|
|
|
|
|
|
fn index(&self, expr: ExprId) -> &Ty {
|
2021-03-14 16:25:29 +00:00
|
|
|
self.type_of_expr.get(expr).unwrap_or(&self.standard_types.unknown)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Index<PatId> for InferenceResult {
|
|
|
|
type Output = Ty;
|
|
|
|
|
|
|
|
fn index(&self, pat: PatId) -> &Ty {
|
2021-03-14 16:25:29 +00:00
|
|
|
self.type_of_pat.get(pat).unwrap_or(&self.standard_types.unknown)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The inference context contains all information needed during type inference.
|
|
|
|
#[derive(Clone, Debug)]
|
2022-03-09 18:50:24 +00:00
|
|
|
pub(crate) struct InferenceContext<'a> {
|
|
|
|
pub(crate) db: &'a dyn HirDatabase,
|
2019-11-27 13:02:33 +00:00
|
|
|
owner: DefWithBodyId,
|
2022-03-09 18:50:24 +00:00
|
|
|
pub(crate) body: Arc<Body>,
|
|
|
|
pub(crate) resolver: Resolver,
|
2021-04-11 09:20:45 +00:00
|
|
|
table: unify::InferenceTable<'a>,
|
2019-07-09 19:34:23 +00:00
|
|
|
trait_env: Arc<TraitEnvironment>,
|
2019-07-14 12:23:44 +00:00
|
|
|
result: InferenceResult,
|
2022-03-23 22:39:35 +00:00
|
|
|
/// The return type of the function being inferred, the closure or async block if we're
|
2019-12-20 15:41:32 +00:00
|
|
|
/// currently within one.
|
|
|
|
///
|
|
|
|
/// We might consider using a nested inference context for checking
|
|
|
|
/// closures, but currently this is the only field that will change there,
|
|
|
|
/// so it doesn't make sense.
|
2019-02-23 14:24:07 +00:00
|
|
|
return_ty: Ty,
|
2020-05-08 15:36:11 +00:00
|
|
|
diverges: Diverges,
|
2020-05-08 15:59:58 +00:00
|
|
|
breakables: Vec<BreakableContext>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
struct BreakableContext {
|
2020-11-02 12:13:32 +00:00
|
|
|
may_break: bool,
|
2021-07-09 12:56:49 +00:00
|
|
|
coerce: CoerceMany,
|
2020-11-02 12:13:32 +00:00
|
|
|
label: Option<name::Name>,
|
2020-05-31 08:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn find_breakable<'c>(
|
|
|
|
ctxs: &'c mut [BreakableContext],
|
|
|
|
label: Option<&name::Name>,
|
|
|
|
) -> Option<&'c mut BreakableContext> {
|
|
|
|
match label {
|
|
|
|
Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label),
|
|
|
|
None => ctxs.last_mut(),
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2020-03-13 15:05:46 +00:00
|
|
|
impl<'a> InferenceContext<'a> {
|
|
|
|
fn new(db: &'a dyn HirDatabase, owner: DefWithBodyId, resolver: Resolver) -> Self {
|
2021-05-16 13:50:28 +00:00
|
|
|
let krate = owner.module(db.upcast()).krate();
|
|
|
|
let trait_env = owner
|
|
|
|
.as_generic_def_id()
|
|
|
|
.map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
|
2019-02-23 14:24:07 +00:00
|
|
|
InferenceContext {
|
2019-07-14 12:23:44 +00:00
|
|
|
result: InferenceResult::default(),
|
2021-04-11 09:20:45 +00:00
|
|
|
table: unify::InferenceTable::new(db, trait_env.clone()),
|
|
|
|
trait_env,
|
2021-12-19 16:58:39 +00:00
|
|
|
return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
|
2019-02-23 14:24:07 +00:00
|
|
|
db,
|
2019-11-12 13:46:27 +00:00
|
|
|
owner,
|
2020-02-18 12:53:02 +00:00
|
|
|
body: db.body(owner),
|
2019-02-23 14:24:07 +00:00
|
|
|
resolver,
|
2020-05-08 15:36:11 +00:00
|
|
|
diverges: Diverges::Maybe,
|
2020-05-08 15:59:58 +00:00
|
|
|
breakables: Vec::new(),
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-13 13:44:51 +00:00
|
|
|
fn err_ty(&self) -> Ty {
|
2021-05-16 15:56:38 +00:00
|
|
|
self.result.standard_types.unknown.clone()
|
2021-03-13 13:44:51 +00:00
|
|
|
}
|
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
fn resolve_all(mut self) -> InferenceResult {
|
2019-03-31 18:02:16 +00:00
|
|
|
// FIXME resolve obligations as well (use Guidance if necessary)
|
2021-05-16 13:50:28 +00:00
|
|
|
self.table.resolve_obligations_as_possible();
|
2021-05-15 17:28:58 +00:00
|
|
|
|
|
|
|
// make sure diverging type variables are marked as such
|
|
|
|
self.table.propagate_diverging_flag();
|
2020-02-18 12:53:02 +00:00
|
|
|
let mut result = std::mem::take(&mut self.result);
|
2019-07-14 12:23:44 +00:00
|
|
|
for ty in result.type_of_expr.values_mut() {
|
2021-05-23 14:59:23 +00:00
|
|
|
*ty = self.table.resolve_completely(ty.clone());
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2019-07-14 12:23:44 +00:00
|
|
|
for ty in result.type_of_pat.values_mut() {
|
2021-05-23 14:59:23 +00:00
|
|
|
*ty = self.table.resolve_completely(ty.clone());
|
2021-05-16 15:56:38 +00:00
|
|
|
}
|
|
|
|
for mismatch in result.type_mismatches.values_mut() {
|
2021-05-23 14:59:23 +00:00
|
|
|
mismatch.expected = self.table.resolve_completely(mismatch.expected.clone());
|
|
|
|
mismatch.actual = self.table.resolve_completely(mismatch.actual.clone());
|
|
|
|
}
|
|
|
|
for (_, subst) in result.method_resolutions.values_mut() {
|
|
|
|
*subst = self.table.resolve_completely(subst.clone());
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2021-07-10 16:19:23 +00:00
|
|
|
for adjustment in result.expr_adjustments.values_mut().flatten() {
|
|
|
|
adjustment.target = self.table.resolve_completely(adjustment.target.clone());
|
|
|
|
}
|
|
|
|
for adjustment in result.pat_adjustments.values_mut().flatten() {
|
|
|
|
adjustment.target = self.table.resolve_completely(adjustment.target.clone());
|
|
|
|
}
|
2019-07-14 12:23:44 +00:00
|
|
|
result
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) {
|
2019-07-14 12:23:44 +00:00
|
|
|
self.result.type_of_expr.insert(expr, ty);
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2021-07-06 16:05:40 +00:00
|
|
|
fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
|
|
|
|
self.result.expr_adjustments.insert(expr, adjustments);
|
|
|
|
}
|
|
|
|
|
2021-05-23 14:59:23 +00:00
|
|
|
fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
|
|
|
|
self.result.method_resolutions.insert(expr, (func, subst));
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2019-11-27 13:25:01 +00:00
|
|
|
fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) {
|
2019-07-21 11:11:45 +00:00
|
|
|
self.result.variant_resolutions.insert(id, variant);
|
2019-07-12 16:56:18 +00:00
|
|
|
}
|
|
|
|
|
2019-11-27 09:31:40 +00:00
|
|
|
fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) {
|
2020-02-18 12:53:02 +00:00
|
|
|
self.result.assoc_resolutions.insert(id, item);
|
2019-03-01 23:26:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
|
2019-07-14 12:23:44 +00:00
|
|
|
self.result.type_of_pat.insert(pat, ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) {
|
|
|
|
self.result.diagnostics.push(diagnostic);
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2020-01-24 14:22:00 +00:00
|
|
|
fn make_ty_with_mode(
|
|
|
|
&mut self,
|
|
|
|
type_ref: &TypeRef,
|
|
|
|
impl_trait_mode: ImplTraitLoweringMode,
|
|
|
|
) -> Ty {
|
2020-01-24 13:32:47 +00:00
|
|
|
// FIXME use right resolver for block
|
2020-02-07 14:13:15 +00:00
|
|
|
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
|
|
|
|
.with_impl_trait_mode(impl_trait_mode);
|
2021-03-13 21:44:36 +00:00
|
|
|
let ty = ctx.lower_ty(type_ref);
|
2019-08-07 20:06:09 +00:00
|
|
|
let ty = self.insert_type_vars(ty);
|
|
|
|
self.normalize_associated_types_in(ty)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2020-01-24 14:22:00 +00:00
|
|
|
fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
|
|
|
|
self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
|
|
|
|
}
|
|
|
|
|
2022-03-09 18:50:24 +00:00
|
|
|
/// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
|
|
|
|
fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
|
|
|
|
let data = c.data(Interner);
|
|
|
|
match data.value {
|
|
|
|
ConstValue::Concrete(cc) => match cc.interned {
|
|
|
|
hir_def::type_ref::ConstScalar::Usize(_) => c,
|
|
|
|
hir_def::type_ref::ConstScalar::Unknown => {
|
|
|
|
self.table.new_const_var(data.ty.clone())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => c,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
/// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
|
|
|
|
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
|
2021-12-19 16:58:39 +00:00
|
|
|
match ty.kind(Interner) {
|
2021-04-05 12:37:11 +00:00
|
|
|
TyKind::Error => self.table.new_type_var(),
|
2021-05-16 15:56:38 +00:00
|
|
|
TyKind::InferenceVar(..) => {
|
|
|
|
let ty_resolved = self.resolve_ty_shallow(&ty);
|
|
|
|
if ty_resolved.is_unknown() {
|
|
|
|
self.table.new_type_var()
|
|
|
|
} else {
|
|
|
|
ty
|
|
|
|
}
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
_ => ty,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn insert_type_vars(&mut self, ty: Ty) -> Ty {
|
2022-03-09 18:50:24 +00:00
|
|
|
fold_tys_and_consts(
|
|
|
|
ty,
|
|
|
|
|x, _| match x {
|
|
|
|
Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
|
|
|
|
Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
|
|
|
|
},
|
|
|
|
DebruijnIndex::INNERMOST,
|
|
|
|
)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2019-03-31 18:02:16 +00:00
|
|
|
fn resolve_obligations_as_possible(&mut self) {
|
2021-05-16 13:50:28 +00:00
|
|
|
self.table.resolve_obligations_as_possible();
|
2019-03-31 18:02:16 +00:00
|
|
|
}
|
|
|
|
|
2021-04-01 19:45:44 +00:00
|
|
|
fn push_obligation(&mut self, o: DomainGoal) {
|
2021-12-19 16:58:39 +00:00
|
|
|
self.table.register_obligation(o.cast(Interner));
|
2021-04-01 19:45:44 +00:00
|
|
|
}
|
|
|
|
|
2019-12-01 19:30:28 +00:00
|
|
|
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
|
|
|
|
self.table.unify(ty1, ty2)
|
|
|
|
}
|
|
|
|
|
2021-05-16 13:56:27 +00:00
|
|
|
fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
|
2021-05-16 15:56:38 +00:00
|
|
|
self.resolve_obligations_as_possible();
|
2019-12-01 19:30:28 +00:00
|
|
|
self.table.resolve_ty_shallow(ty)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2019-12-13 11:44:07 +00:00
|
|
|
fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
|
2019-12-19 04:45:07 +00:00
|
|
|
self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_associated_type_with_params(
|
|
|
|
&mut self,
|
|
|
|
inner_ty: Ty,
|
|
|
|
assoc_ty: Option<TypeAliasId>,
|
2022-03-09 18:50:24 +00:00
|
|
|
params: &[GenericArg],
|
2019-12-19 04:45:07 +00:00
|
|
|
) -> Ty {
|
2019-12-13 11:44:07 +00:00
|
|
|
match assoc_ty {
|
|
|
|
Some(res_assoc_ty) => {
|
2020-07-03 15:39:06 +00:00
|
|
|
let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
|
2021-12-07 16:31:26 +00:00
|
|
|
hir_def::ItemContainerId::TraitId(trait_) => trait_,
|
2020-07-03 15:39:06 +00:00
|
|
|
_ => panic!("resolve_associated_type called with non-associated type"),
|
|
|
|
};
|
2019-12-13 11:44:07 +00:00
|
|
|
let ty = self.table.new_type_var();
|
2022-03-09 18:50:24 +00:00
|
|
|
let mut param_iter = params.iter().cloned();
|
2021-04-03 19:50:52 +00:00
|
|
|
let trait_ref = TyBuilder::trait_ref(self.db, trait_)
|
2019-12-19 19:04:55 +00:00
|
|
|
.push(inner_ty)
|
2022-03-09 18:50:24 +00:00
|
|
|
.fill(|_| param_iter.next().unwrap())
|
2020-07-03 15:39:06 +00:00
|
|
|
.build();
|
2021-03-19 01:07:15 +00:00
|
|
|
let alias_eq = AliasEq {
|
|
|
|
alias: AliasTy::Projection(ProjectionTy {
|
2021-03-14 15:26:12 +00:00
|
|
|
associated_ty_id: to_assoc_type_id(res_assoc_ty),
|
2021-04-03 19:50:52 +00:00
|
|
|
substitution: trait_ref.substitution.clone(),
|
2021-03-19 01:07:15 +00:00
|
|
|
}),
|
|
|
|
ty: ty.clone(),
|
2019-12-13 11:44:07 +00:00
|
|
|
};
|
2021-12-19 16:58:39 +00:00
|
|
|
self.push_obligation(trait_ref.cast(Interner));
|
|
|
|
self.push_obligation(alias_eq.cast(Interner));
|
2021-05-16 15:56:38 +00:00
|
|
|
ty
|
2019-12-13 11:44:07 +00:00
|
|
|
}
|
2021-03-13 13:44:51 +00:00
|
|
|
None => self.err_ty(),
|
2019-12-13 11:44:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-11 11:52:34 +00:00
|
|
|
/// Recurses through the given type, normalizing associated types mentioned
|
|
|
|
/// in it by replacing them by type variables and registering obligations to
|
|
|
|
/// resolve later. This should be done once for every type we get from some
|
|
|
|
/// type annotation (e.g. from a let type annotation, field type or function
|
|
|
|
/// call). `make_ty` handles this already, but e.g. for field types we need
|
|
|
|
/// to do it as well.
|
2019-08-07 20:06:09 +00:00
|
|
|
fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
|
2021-05-16 13:50:28 +00:00
|
|
|
self.table.normalize_associated_types_in(ty)
|
2019-08-07 20:06:09 +00:00
|
|
|
}
|
|
|
|
|
2021-07-22 11:40:18 +00:00
|
|
|
fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Option<VariantId>) {
|
2019-02-23 14:24:07 +00:00
|
|
|
let path = match path {
|
|
|
|
Some(path) => path,
|
2021-03-13 13:44:51 +00:00
|
|
|
None => return (self.err_ty(), None),
|
2019-02-23 14:24:07 +00:00
|
|
|
};
|
|
|
|
let resolver = &self.resolver;
|
2020-01-25 22:38:33 +00:00
|
|
|
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
|
2019-11-26 18:04:24 +00:00
|
|
|
// FIXME: this should resolve assoc items as well, see this example:
|
|
|
|
// https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
|
2021-07-22 11:40:18 +00:00
|
|
|
let (resolution, unresolved) = if value_ns {
|
|
|
|
match resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path()) {
|
|
|
|
Some(ResolveValueResult::ValueNs(value)) => match value {
|
|
|
|
ValueNs::EnumVariantId(var) => {
|
|
|
|
let substs = ctx.substs_from_path(path, var.into(), true);
|
|
|
|
let ty = self.db.ty(var.parent.into());
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
2021-07-22 11:40:18 +00:00
|
|
|
return (ty, Some(var.into()));
|
|
|
|
}
|
|
|
|
ValueNs::StructId(strukt) => {
|
|
|
|
let substs = ctx.substs_from_path(path, strukt.into(), true);
|
|
|
|
let ty = self.db.ty(strukt.into());
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
2021-07-22 11:40:18 +00:00
|
|
|
return (ty, Some(strukt.into()));
|
|
|
|
}
|
|
|
|
_ => return (self.err_ty(), None),
|
|
|
|
},
|
|
|
|
Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)),
|
|
|
|
None => return (self.err_ty(), None),
|
|
|
|
}
|
|
|
|
} else {
|
2020-05-15 15:15:40 +00:00
|
|
|
match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
|
|
|
|
Some(it) => it,
|
2021-03-13 13:44:51 +00:00
|
|
|
None => return (self.err_ty(), None),
|
2021-07-22 11:40:18 +00:00
|
|
|
}
|
|
|
|
};
|
2020-05-15 15:15:40 +00:00
|
|
|
return match resolution {
|
|
|
|
TypeNs::AdtId(AdtId::StructId(strukt)) => {
|
2021-03-13 21:44:36 +00:00
|
|
|
let substs = ctx.substs_from_path(path, strukt.into(), true);
|
2019-11-26 18:04:24 +00:00
|
|
|
let ty = self.db.ty(strukt.into());
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
2020-05-15 15:15:40 +00:00
|
|
|
forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2020-08-07 13:24:20 +00:00
|
|
|
TypeNs::AdtId(AdtId::UnionId(u)) => {
|
2021-03-13 21:44:36 +00:00
|
|
|
let substs = ctx.substs_from_path(path, u.into(), true);
|
2020-08-07 13:24:20 +00:00
|
|
|
let ty = self.db.ty(u.into());
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
2020-08-07 13:24:20 +00:00
|
|
|
forbid_unresolved_segments((ty, Some(u.into())), unresolved)
|
|
|
|
}
|
2020-05-15 15:15:40 +00:00
|
|
|
TypeNs::EnumVariantId(var) => {
|
2021-03-13 21:44:36 +00:00
|
|
|
let substs = ctx.substs_from_path(path, var.into(), true);
|
2019-11-26 18:04:24 +00:00
|
|
|
let ty = self.db.ty(var.parent.into());
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
2020-05-15 15:15:40 +00:00
|
|
|
forbid_unresolved_segments((ty, Some(var.into())), unresolved)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2020-05-15 15:15:40 +00:00
|
|
|
TypeNs::SelfType(impl_id) => {
|
2020-03-13 15:05:46 +00:00
|
|
|
let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
|
2022-03-09 18:50:24 +00:00
|
|
|
let substs = generics.placeholder_subst(self.db);
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
|
2021-04-07 09:31:50 +00:00
|
|
|
self.resolve_variant_on_alias(ty, unresolved, path)
|
2020-03-06 14:26:49 +00:00
|
|
|
}
|
2020-05-15 15:15:40 +00:00
|
|
|
TypeNs::TypeAliasId(it) => {
|
2021-04-03 20:18:02 +00:00
|
|
|
let ty = TyBuilder::def_ty(self.db, it.into())
|
2022-03-17 11:39:42 +00:00
|
|
|
.fill_with_inference_vars(&mut self.table)
|
2020-03-06 14:26:49 +00:00
|
|
|
.build();
|
2021-04-07 09:31:50 +00:00
|
|
|
self.resolve_variant_on_alias(ty, unresolved, path)
|
2020-05-15 15:15:40 +00:00
|
|
|
}
|
|
|
|
TypeNs::AdtSelfType(_) => {
|
|
|
|
// FIXME this could happen in array size expressions, once we're checking them
|
2021-03-13 13:44:51 +00:00
|
|
|
(self.err_ty(), None)
|
2020-05-15 15:15:40 +00:00
|
|
|
}
|
|
|
|
TypeNs::GenericParam(_) => {
|
|
|
|
// FIXME potentially resolve assoc type
|
2021-03-13 13:44:51 +00:00
|
|
|
(self.err_ty(), None)
|
2020-05-15 15:15:40 +00:00
|
|
|
}
|
2020-08-07 13:24:20 +00:00
|
|
|
TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => {
|
2020-05-15 15:15:40 +00:00
|
|
|
// FIXME diagnostic
|
2021-03-13 13:44:51 +00:00
|
|
|
(self.err_ty(), None)
|
2020-03-06 14:26:49 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-05-15 15:15:40 +00:00
|
|
|
fn forbid_unresolved_segments(
|
|
|
|
result: (Ty, Option<VariantId>),
|
|
|
|
unresolved: Option<usize>,
|
|
|
|
) -> (Ty, Option<VariantId>) {
|
|
|
|
if unresolved.is_none() {
|
|
|
|
result
|
|
|
|
} else {
|
|
|
|
// FIXME diagnostic
|
2021-12-19 16:58:39 +00:00
|
|
|
(TyKind::Error.intern(Interner), None)
|
2020-05-15 15:15:40 +00:00
|
|
|
}
|
|
|
|
}
|
2021-04-07 09:31:50 +00:00
|
|
|
}
|
2020-05-15 15:15:40 +00:00
|
|
|
|
2021-04-07 09:31:50 +00:00
|
|
|
fn resolve_variant_on_alias(
|
|
|
|
&mut self,
|
|
|
|
ty: Ty,
|
|
|
|
unresolved: Option<usize>,
|
|
|
|
path: &Path,
|
|
|
|
) -> (Ty, Option<VariantId>) {
|
|
|
|
match unresolved {
|
|
|
|
None => {
|
|
|
|
let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id {
|
|
|
|
AdtId::StructId(s) => Some(VariantId::StructId(s)),
|
|
|
|
AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
|
|
|
|
AdtId::EnumId(_) => {
|
|
|
|
// FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
|
|
|
|
None
|
|
|
|
}
|
|
|
|
});
|
|
|
|
(ty, variant)
|
|
|
|
}
|
|
|
|
Some(1) => {
|
|
|
|
let segment = path.mod_path().segments().last().unwrap();
|
|
|
|
// this could be an enum variant or associated type
|
|
|
|
if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
|
|
|
|
let enum_data = self.db.enum_data(enum_id);
|
|
|
|
if let Some(local_id) = enum_data.variant(segment) {
|
|
|
|
let variant = EnumVariantId { parent: enum_id, local_id };
|
|
|
|
return (ty, Some(variant.into()));
|
|
|
|
}
|
2020-03-06 14:26:49 +00:00
|
|
|
}
|
2021-04-07 09:31:50 +00:00
|
|
|
// FIXME potentially resolve assoc type
|
|
|
|
(self.err_ty(), None)
|
|
|
|
}
|
|
|
|
Some(_) => {
|
|
|
|
// FIXME diagnostic
|
|
|
|
(self.err_ty(), None)
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-18 17:07:35 +00:00
|
|
|
fn collect_const(&mut self, data: &ConstData) {
|
2019-11-22 15:46:39 +00:00
|
|
|
self.return_ty = self.make_ty(&data.type_ref);
|
2019-03-30 11:17:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-10 15:08:28 +00:00
|
|
|
fn collect_static(&mut self, data: &StaticData) {
|
|
|
|
self.return_ty = self.make_ty(&data.type_ref);
|
|
|
|
}
|
|
|
|
|
2019-11-22 14:10:51 +00:00
|
|
|
fn collect_fn(&mut self, data: &FunctionData) {
|
2019-02-23 14:24:07 +00:00
|
|
|
let body = Arc::clone(&self.body); // avoid borrow checker problem
|
2020-02-07 14:13:15 +00:00
|
|
|
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
|
|
|
|
.with_impl_trait_mode(ImplTraitLoweringMode::Param);
|
|
|
|
let param_tys =
|
2021-12-20 14:24:37 +00:00
|
|
|
data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
|
2020-02-02 12:04:22 +00:00
|
|
|
for (ty, pat) in param_tys.into_iter().zip(body.params.iter()) {
|
|
|
|
let ty = self.insert_type_vars(ty);
|
|
|
|
let ty = self.normalize_associated_types_in(ty);
|
2019-02-23 14:24:07 +00:00
|
|
|
|
2019-03-17 18:46:01 +00:00
|
|
|
self.infer_pat(*pat, &ty, BindingMode::default());
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2021-05-29 16:16:20 +00:00
|
|
|
let error_ty = &TypeRef::Error;
|
|
|
|
let return_ty = if data.is_async() {
|
|
|
|
data.async_ret_type.as_deref().unwrap_or(error_ty)
|
|
|
|
} else {
|
|
|
|
&*data.ret_type
|
|
|
|
};
|
|
|
|
let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Disallowed); // FIXME implement RPIT
|
2020-02-07 14:13:00 +00:00
|
|
|
self.return_ty = return_ty;
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn infer_body(&mut self) {
|
2019-12-20 17:27:51 +00:00
|
|
|
self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2019-07-07 07:31:09 +00:00
|
|
|
|
2021-12-09 17:13:15 +00:00
|
|
|
fn resolve_lang_item(&self, name: Name) -> Option<LangItemTarget> {
|
2019-12-29 16:39:31 +00:00
|
|
|
let krate = self.resolver.krate()?;
|
2021-12-09 17:13:15 +00:00
|
|
|
self.db.lang_item(krate, name.to_smol_str())
|
2019-12-29 16:39:31 +00:00
|
|
|
}
|
|
|
|
|
2019-11-27 12:56:20 +00:00
|
|
|
fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
|
2020-06-11 14:22:31 +00:00
|
|
|
let path = path![core::iter::IntoIterator];
|
2020-03-13 15:05:46 +00:00
|
|
|
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
2019-12-13 21:01:06 +00:00
|
|
|
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
|
2019-07-07 07:31:09 +00:00
|
|
|
}
|
2019-07-08 15:02:15 +00:00
|
|
|
|
2019-11-27 12:56:20 +00:00
|
|
|
fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
|
2021-05-25 14:08:18 +00:00
|
|
|
// FIXME resolve via lang_item once try v2 is stable
|
2020-06-11 14:22:31 +00:00
|
|
|
let path = path![core::ops::Try];
|
2020-03-13 15:05:46 +00:00
|
|
|
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
2021-05-25 12:59:54 +00:00
|
|
|
let trait_data = self.db.trait_data(trait_);
|
|
|
|
trait_data
|
2021-05-25 14:08:18 +00:00
|
|
|
// FIXME remove once try v2 is stable
|
2021-05-25 12:59:54 +00:00
|
|
|
.associated_type_by_name(&name![Ok])
|
|
|
|
.or_else(|| trait_data.associated_type_by_name(&name![Output]))
|
2019-07-08 15:02:15 +00:00
|
|
|
}
|
2019-07-20 11:11:18 +00:00
|
|
|
|
2019-12-13 11:44:42 +00:00
|
|
|
fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
|
2021-12-09 17:13:15 +00:00
|
|
|
let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
|
2019-12-13 21:01:06 +00:00
|
|
|
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
|
2019-12-13 11:44:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
|
2021-12-09 17:13:15 +00:00
|
|
|
let trait_ = self.resolve_lang_item(name![not])?.as_trait()?;
|
2019-12-13 21:01:06 +00:00
|
|
|
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
|
2019-12-13 11:44:42 +00:00
|
|
|
}
|
|
|
|
|
2019-11-27 12:56:20 +00:00
|
|
|
fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
|
2021-12-09 17:13:15 +00:00
|
|
|
let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?;
|
2019-12-13 21:01:06 +00:00
|
|
|
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
|
2019-07-20 11:11:18 +00:00
|
|
|
}
|
2019-09-11 15:53:41 +00:00
|
|
|
|
2019-11-26 11:29:12 +00:00
|
|
|
fn resolve_boxed_box(&self) -> Option<AdtId> {
|
2021-12-09 17:13:15 +00:00
|
|
|
let struct_ = self.resolve_lang_item(name![owned_box])?.as_struct()?;
|
2019-11-26 11:29:12 +00:00
|
|
|
Some(struct_.into())
|
2019-09-11 15:53:41 +00:00
|
|
|
}
|
2019-11-28 19:10:16 +00:00
|
|
|
|
|
|
|
fn resolve_range_full(&self) -> Option<AdtId> {
|
2020-06-11 14:22:31 +00:00
|
|
|
let path = path![core::ops::RangeFull];
|
2020-03-13 15:05:46 +00:00
|
|
|
let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_range(&self) -> Option<AdtId> {
|
2020-06-11 14:22:31 +00:00
|
|
|
let path = path![core::ops::Range];
|
2020-03-13 15:05:46 +00:00
|
|
|
let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_range_inclusive(&self) -> Option<AdtId> {
|
2020-06-11 14:22:31 +00:00
|
|
|
let path = path![core::ops::RangeInclusive];
|
2020-03-13 15:05:46 +00:00
|
|
|
let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_range_from(&self) -> Option<AdtId> {
|
2020-06-11 14:22:31 +00:00
|
|
|
let path = path![core::ops::RangeFrom];
|
2020-03-13 15:05:46 +00:00
|
|
|
let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_range_to(&self) -> Option<AdtId> {
|
2020-06-11 14:22:31 +00:00
|
|
|
let path = path![core::ops::RangeTo];
|
2020-03-13 15:05:46 +00:00
|
|
|
let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
|
2020-06-11 14:22:31 +00:00
|
|
|
let path = path![core::ops::RangeToInclusive];
|
2020-03-13 15:05:46 +00:00
|
|
|
let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
2019-12-19 04:45:07 +00:00
|
|
|
|
2020-02-29 21:48:23 +00:00
|
|
|
fn resolve_ops_index(&self) -> Option<TraitId> {
|
2021-12-09 17:13:15 +00:00
|
|
|
self.resolve_lang_item(name![index])?.as_trait()
|
2020-02-29 21:48:23 +00:00
|
|
|
}
|
|
|
|
|
2019-12-19 04:45:07 +00:00
|
|
|
fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
|
2020-02-29 21:48:23 +00:00
|
|
|
let trait_ = self.resolve_ops_index()?;
|
2019-12-19 04:45:07 +00:00
|
|
|
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// When inferring an expression, we propagate downward whatever type hint we
|
|
|
|
/// are able in the form of an `Expectation`.
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
2022-03-09 18:50:24 +00:00
|
|
|
pub(crate) enum Expectation {
|
2021-05-21 15:41:20 +00:00
|
|
|
None,
|
|
|
|
HasType(Ty),
|
|
|
|
// Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts
|
|
|
|
RValueLikeUnsized(Ty),
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Expectation {
|
|
|
|
/// The expectation that the type of the expression needs to equal the given
|
|
|
|
/// type.
|
|
|
|
fn has_type(ty: Ty) -> Self {
|
2021-05-21 15:41:20 +00:00
|
|
|
if ty.is_unknown() {
|
|
|
|
// FIXME: get rid of this?
|
|
|
|
Expectation::None
|
|
|
|
} else {
|
|
|
|
Expectation::HasType(ty)
|
|
|
|
}
|
2020-02-29 14:31:07 +00:00
|
|
|
}
|
|
|
|
|
2021-08-22 15:21:47 +00:00
|
|
|
fn from_option(ty: Option<Ty>) -> Self {
|
|
|
|
ty.map_or(Expectation::None, Expectation::HasType)
|
|
|
|
}
|
|
|
|
|
2020-02-29 14:31:07 +00:00
|
|
|
/// The following explanation is copied straight from rustc:
|
|
|
|
/// Provides an expectation for an rvalue expression given an *optional*
|
|
|
|
/// hint, which is not required for type safety (the resulting type might
|
|
|
|
/// be checked higher up, as is the case with `&expr` and `box expr`), but
|
|
|
|
/// is useful in determining the concrete type.
|
|
|
|
///
|
|
|
|
/// The primary use case is where the expected type is a fat pointer,
|
|
|
|
/// like `&[isize]`. For example, consider the following statement:
|
|
|
|
///
|
|
|
|
/// let x: &[isize] = &[1, 2, 3];
|
|
|
|
///
|
|
|
|
/// In this case, the expected type for the `&[1, 2, 3]` expression is
|
|
|
|
/// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
|
|
|
|
/// expectation `ExpectHasType([isize])`, that would be too strong --
|
|
|
|
/// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
|
|
|
|
/// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
|
|
|
|
/// to the type `&[isize]`. Therefore, we propagate this more limited hint,
|
|
|
|
/// which still is useful, because it informs integer literals and the like.
|
|
|
|
/// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
|
|
|
|
/// for examples of where this comes up,.
|
2021-07-15 18:02:58 +00:00
|
|
|
fn rvalue_hint(table: &mut unify::InferenceTable, ty: Ty) -> Self {
|
|
|
|
// FIXME: do struct_tail_without_normalization
|
2021-12-19 16:58:39 +00:00
|
|
|
match table.resolve_ty_shallow(&ty).kind(Interner) {
|
2021-05-21 15:41:20 +00:00
|
|
|
TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty),
|
|
|
|
_ => Expectation::has_type(ty),
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This expresses no expectation on the type.
|
|
|
|
fn none() -> Self {
|
2021-05-21 15:41:20 +00:00
|
|
|
Expectation::None
|
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
}
|
2021-03-14 16:25:29 +00:00
|
|
|
}
|
2020-02-29 14:31:07 +00:00
|
|
|
}
|
|
|
|
|
2021-05-21 15:41:20 +00:00
|
|
|
fn to_option(&self, table: &mut unify::InferenceTable) -> Option<Ty> {
|
|
|
|
match self.resolve(table) {
|
|
|
|
Expectation::None => None,
|
|
|
|
Expectation::HasType(t) |
|
|
|
|
// Expectation::Castable(t) |
|
|
|
|
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,
|
2020-02-29 14:31:07 +00:00
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2021-06-03 21:12:35 +00:00
|
|
|
|
|
|
|
/// Comment copied from rustc:
|
|
|
|
/// Disregard "castable to" expectations because they
|
|
|
|
/// can lead us astray. Consider for example `if cond
|
|
|
|
/// {22} else {c} as u8` -- if we propagate the
|
|
|
|
/// "castable to u8" constraint to 22, it will pick the
|
|
|
|
/// type 22u8, which is overly constrained (c might not
|
|
|
|
/// be a u8). In effect, the problem is that the
|
|
|
|
/// "castable to" expectation is not the tightest thing
|
|
|
|
/// we can say, so we want to drop it in this case.
|
|
|
|
/// The tightest thing we can say is "must unify with
|
|
|
|
/// else branch". Note that in the case of a "has type"
|
|
|
|
/// constraint, this limitation does not hold.
|
|
|
|
///
|
|
|
|
/// If the expected type is just a type variable, then don't use
|
|
|
|
/// an expected type. Otherwise, we might write parts of the type
|
|
|
|
/// when checking the 'then' block which are incompatible with the
|
|
|
|
/// 'else' branch.
|
|
|
|
fn adjust_for_branches(&self, table: &mut unify::InferenceTable) -> Expectation {
|
|
|
|
match self {
|
|
|
|
Expectation::HasType(ety) => {
|
2021-06-13 03:54:16 +00:00
|
|
|
let ety = table.resolve_ty_shallow(ety);
|
2021-06-03 21:12:35 +00:00
|
|
|
if !ety.is_ty_var() {
|
|
|
|
Expectation::HasType(ety)
|
|
|
|
} else {
|
|
|
|
Expectation::None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()),
|
|
|
|
_ => Expectation::None,
|
|
|
|
}
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2019-03-23 13:28:47 +00:00
|
|
|
|
2020-05-08 15:36:11 +00:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
|
|
enum Diverges {
|
|
|
|
Maybe,
|
|
|
|
Always,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Diverges {
|
|
|
|
fn is_always(self) -> bool {
|
|
|
|
self == Diverges::Always
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::ops::BitAnd for Diverges {
|
|
|
|
type Output = Self;
|
|
|
|
fn bitand(self, other: Self) -> Self {
|
|
|
|
std::cmp::min(self, other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::ops::BitOr for Diverges {
|
|
|
|
type Output = Self;
|
|
|
|
fn bitor(self, other: Self) -> Self {
|
|
|
|
std::cmp::max(self, other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::ops::BitAndAssign for Diverges {
|
|
|
|
fn bitand_assign(&mut self, other: Self) {
|
|
|
|
*self = *self & other;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::ops::BitOrAssign for Diverges {
|
|
|
|
fn bitor_assign(&mut self, other: Self) {
|
|
|
|
*self = *self | other;
|
|
|
|
}
|
|
|
|
}
|