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.
|
|
|
|
|
|
|
|
use std::ops::Index;
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
2021-04-08 11:32:48 +00:00
|
|
|
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability};
|
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},
|
2020-10-13 18:48:08 +00:00
|
|
|
expr::{ArithOp, BinaryOp, 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},
|
2019-11-21 12:39:09 +00:00
|
|
|
resolver::{HasResolver, Resolver, TypeNs},
|
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
|
|
|
};
|
internal: move diagnostics to hir
The idea here is to eventually get rid of `dyn Diagnostic` and
`DiagnosticSink` infrastructure altogether, and just have a `enum
hir::Diagnostic` instead.
The problem with `dyn Diagnostic` is that it is defined in the lowest
level of the stack (hir_expand), but is used by the highest level (ide).
As a first step, we free hir_expand and hir_def from `dyn Diagnostic`
and kick the can up to `hir_ty`, as an intermediate state. The plan is
then to move DiagnosticSink similarly to the hir crate, and, as final
third step, remove its usage from the ide.
One currently unsolved problem is testing. You can notice that the test
which checks precise diagnostic ranges, unresolved_import_in_use_tree,
was moved to the ide layer. Logically, only IDE should have the infra to
render a specific range.
At the same time, the range is determined with the data produced in
hir_def and hir crates, so this layering is rather unfortunate. Working
on hir_def shouldn't require compiling `ide` for testing.
2021-05-23 20:31:59 +00:00
|
|
|
use hir_expand::name::name;
|
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;
|
2020-08-12 16:26:51 +00:00
|
|
|
use syntax::SmolStr;
|
2019-02-23 14:24:07 +00:00
|
|
|
|
2021-05-16 13:50:28 +00:00
|
|
|
use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
|
2020-01-24 14:22:00 +00:00
|
|
|
use crate::{
|
2021-06-12 14:39:46 +00:00
|
|
|
db::HirDatabase, fold_tys, lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy,
|
|
|
|
Goal, Interner, Substitution, 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
|
|
|
|
#[allow(unreachable_pub)]
|
|
|
|
pub use unify::could_unify;
|
2019-12-03 12:58:02 +00:00
|
|
|
pub(crate) use unify::unify;
|
2019-12-01 21:14:28 +00:00
|
|
|
|
2019-04-20 10:34:36 +00:00
|
|
|
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;
|
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())
|
|
|
|
}
|
|
|
|
|
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)]
|
|
|
|
enum BindingMode {
|
|
|
|
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)]
|
|
|
|
pub(crate) struct InferOk {
|
2021-05-16 16:27:17 +00:00
|
|
|
goals: Vec<InEnvironment<Goal>>,
|
2021-05-01 19:53:10 +00:00
|
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub(crate) struct TypeError;
|
|
|
|
pub(crate) type InferResult = Result<InferOk, TypeError>;
|
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for InternedStandardTypes {
|
|
|
|
fn default() -> Self {
|
2021-04-05 12:37:11 +00:00
|
|
|
InternedStandardTypes { unknown: TyKind::Error.intern(&Interner) }
|
2021-03-14 16:25:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
|
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)]
|
2020-03-13 15:05:46 +00:00
|
|
|
struct InferenceContext<'a> {
|
|
|
|
db: &'a dyn HirDatabase,
|
2019-11-27 13:02:33 +00:00
|
|
|
owner: DefWithBodyId,
|
2019-02-23 14:24:07 +00:00
|
|
|
body: Arc<Body>,
|
|
|
|
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,
|
2019-12-20 15:41:32 +00:00
|
|
|
/// The return type of the function being inferred, or the closure if we're
|
|
|
|
/// 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,
|
|
|
|
break_ty: Ty,
|
|
|
|
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-05-16 13:50:28 +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
|
|
|
}
|
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-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
|
|
|
}
|
|
|
|
|
2020-04-25 12:23:34 +00:00
|
|
|
fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) {
|
2019-07-14 12:23:44 +00:00
|
|
|
self.result.field_resolutions.insert(expr, field);
|
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)
|
|
|
|
}
|
|
|
|
|
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-04-03 11:08:29 +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 {
|
2021-04-08 11:32:48 +00:00
|
|
|
fold_tys(ty, |ty, _| self.insert_type_vars_shallow(ty), 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-05-16 13:50:28 +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>,
|
|
|
|
params: &[Ty],
|
|
|
|
) -> 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 {
|
|
|
|
hir_def::AssocContainerId::TraitId(trait_) => trait_,
|
|
|
|
_ => panic!("resolve_associated_type called with non-associated type"),
|
|
|
|
};
|
2019-12-13 11:44:07 +00:00
|
|
|
let ty = self.table.new_type_var();
|
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)
|
2020-07-03 15:39:06 +00:00
|
|
|
.fill(params.iter().cloned())
|
|
|
|
.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-04-01 19:45:44 +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
|
|
|
}
|
|
|
|
|
2019-11-27 13:25:01 +00:00
|
|
|
fn resolve_variant(&mut self, path: Option<&Path>) -> (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
|
2020-05-15 15:15:40 +00:00
|
|
|
let (resolution, unresolved) =
|
|
|
|
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),
|
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-04-05 16:49:26 +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-04-05 16:49:26 +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-04-05 16:49:26 +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());
|
2021-04-04 11:07:06 +00:00
|
|
|
let substs = generics.type_params_subst(self.db);
|
2021-04-05 16:49:26 +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())
|
2020-03-06 14:26:49 +00:00
|
|
|
.fill(std::iter::repeat_with(|| self.table.new_type_var()))
|
|
|
|
.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-04-05 12:37:11 +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-03-13 21:44:36 +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
|
|
|
|
2019-12-29 16:39:31 +00:00
|
|
|
fn resolve_lang_item(&self, name: &str) -> Option<LangItemTarget> {
|
|
|
|
let krate = self.resolver.krate()?;
|
2020-09-23 06:45:35 +00:00
|
|
|
let name = SmolStr::new_inline(name);
|
2019-12-29 16:39:31 +00:00
|
|
|
self.db.lang_item(krate, name)
|
|
|
|
}
|
|
|
|
|
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> {
|
2019-12-29 16:39:31 +00:00
|
|
|
let trait_ = self.resolve_lang_item("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> {
|
2019-12-29 16:39:31 +00:00
|
|
|
let trait_ = self.resolve_lang_item("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> {
|
2019-12-29 16:39:31 +00:00
|
|
|
let trait_ = self.resolve_lang_item("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
|
|
|
|
2020-10-13 18:48:08 +00:00
|
|
|
fn resolve_binary_op_output(&self, bop: &BinaryOp) -> Option<TypeAliasId> {
|
|
|
|
let lang_item = match bop {
|
|
|
|
BinaryOp::ArithOp(aop) => match aop {
|
|
|
|
ArithOp::Add => "add",
|
|
|
|
ArithOp::Sub => "sub",
|
|
|
|
ArithOp::Mul => "mul",
|
|
|
|
ArithOp::Div => "div",
|
|
|
|
ArithOp::Shl => "shl",
|
|
|
|
ArithOp::Shr => "shr",
|
|
|
|
ArithOp::Rem => "rem",
|
|
|
|
ArithOp::BitXor => "bitxor",
|
|
|
|
ArithOp::BitOr => "bitor",
|
|
|
|
ArithOp::BitAnd => "bitand",
|
|
|
|
},
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let trait_ = self.resolve_lang_item(lang_item)?.as_trait();
|
|
|
|
|
|
|
|
self.db.trait_data(trait_?).associated_type_by_name(&name![Output])
|
|
|
|
}
|
|
|
|
|
2019-11-26 11:29:12 +00:00
|
|
|
fn resolve_boxed_box(&self) -> Option<AdtId> {
|
2019-12-29 16:39:31 +00:00
|
|
|
let struct_ = self.resolve_lang_item("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> {
|
|
|
|
self.resolve_lang_item("index")?.as_trait()
|
|
|
|
}
|
|
|
|
|
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)]
|
2021-05-21 15:41:20 +00:00
|
|
|
enum Expectation {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/// 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,.
|
|
|
|
fn rvalue_hint(ty: Ty) -> Self {
|
2021-05-21 15:41:20 +00:00
|
|
|
match ty.strip_references().kind(&Interner) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|