Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer.rs')
-rw-r--r--crates/hir-ty/src/infer.rs1120
1 files changed, 668 insertions, 452 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 339ce7933a..39ffb91a8c 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -29,31 +29,39 @@ mod path;
mod place_op;
pub(crate) mod unify;
-use std::{cell::OnceCell, convert::identity, fmt, iter, ops::Deref};
+use std::{
+ cell::{OnceCell, RefCell},
+ convert::identity,
+ fmt,
+ hash::Hash,
+ ops::Deref,
+};
use base_db::{Crate, FxIndexMap};
use either::Either;
use hir_def::{
- AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwnerId, FieldId,
- FunctionId, GenericDefId, GenericParamId, ItemContainerId, LocalFieldId, Lookup, TraitId,
- TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId,
- expr_store::{Body, ExpressionStore, HygieneId, RootExprOrigin, path::Path},
- hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
+ AdtId, AssocItemId, AttrDefId, ConstId, DefWithBodyId, ExpressionStoreOwnerId, FieldId,
+ FunctionId, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, StaticId, TraitId,
+ TupleFieldId, TupleId, VariantId,
+ attrs::AttrFlags,
+ expr_store::{Body, ExpressionStore, HygieneId, path::Path},
+ hir::{BindingId, ExprId, ExprOrPatId, LabelId, PatId},
lang_item::LangItems,
layout::Integer,
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature},
- type_ref::{ConstRef, LifetimeRefId, TypeRef, TypeRefId},
+ type_ref::{LifetimeRefId, TypeRefId},
+ unstable_features::UnstableFeatures,
};
use hir_expand::{mod_path::ModPath, name::Name};
use indexmap::IndexSet;
-use intern::sym;
use la_arena::ArenaMap;
+use macros::{TypeFoldable, TypeVisitable};
use rustc_ast_ir::Mutability;
use rustc_hash::{FxHashMap, FxHashSet};
use rustc_type_ir::{
- AliasTyKind, TypeFoldable,
- inherent::{AdtDef, IntoKind, Ty as _},
+ AliasTyKind, TypeFoldable, TypeVisitableExt,
+ inherent::{GenericArgs as _, IntoKind, Ty as _},
};
use smallvec::SmallVec;
use span::Edition;
@@ -61,10 +69,12 @@ use stdx::never;
use thin_vec::ThinVec;
use crate::{
- ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, TargetFeatures,
+ ImplTraitId, IncorrectGenericsLenKind, InferBodyId, PathLoweringDiagnostic, Span,
+ TargetFeatures,
closure_analysis::PlaceBase,
- collect_type_inference_vars,
- db::{HirDatabase, InternedOpaqueTyId},
+ consteval::{create_anon_const, path_to_const},
+ db::{AnonConstId, GeneralConstId, HirDatabase, InternedOpaqueTyId},
+ generics::Generics,
infer::{
callee::DeferredCallResolution,
closure::analysis::{
@@ -72,19 +82,25 @@ use crate::{
expr_use_visitor::{FakeReadCause, Place},
},
coerce::{CoerceMany, DynamicCoerceMany},
- diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext},
+ diagnostics::{
+ Diagnostics, InferenceTyLoweringContext as TyLoweringContext,
+ InferenceTyLoweringVarsCtx,
+ },
expr::ExprIsRead,
+ pat::PatOrigin,
+ unify::resolve_completely::WriteBackCtxt,
},
lower::{
ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic,
},
- method_resolution::{CandidateId, MethodResolutionUnstableFeatures},
+ method_resolution::CandidateId,
next_solver::{
- AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Region,
- StoredGenericArgs, StoredTy, StoredTys, Ty, TyKind, Tys,
+ AliasTy, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, Region,
+ StoredGenericArg, StoredGenericArgs, StoredTy, StoredTys, Term, Ty, TyKind, Tys,
abi::Safety,
infer::{InferCtxt, ObligationInspector, traits::ObligationCause},
},
+ solver_errors::SolverDiagnostic,
utils::TargetFeatureIsSafeInTarget,
};
@@ -111,17 +127,24 @@ pub fn infer_query_with_inspect<'db>(
let _p = tracing::info_span!("infer_query").entered();
let resolver = def.resolver(db);
let body = Body::of(db, def);
- let mut ctx =
- InferenceContext::new(db, ExpressionStoreOwnerId::Body(def), &body.store, resolver);
+ let mut ctx = InferenceContext::new(
+ db,
+ InferBodyId::DefWithBodyId(def),
+ ExpressionStoreOwnerId::Body(def),
+ def.generic_def(db),
+ &body.store,
+ resolver,
+ true,
+ );
if let Some(inspect) = inspect {
ctx.table.infer_ctxt.attach_obligation_inspector(inspect);
}
match def {
- DefWithBodyId::FunctionId(f) => ctx.collect_fn(f, body.self_param, &body.params),
+ DefWithBodyId::FunctionId(f) => ctx.collect_fn(f, body.self_param(), &body.params),
DefWithBodyId::ConstId(c) => ctx.collect_const(c, ConstSignature::of(db, c)),
- DefWithBodyId::StaticId(s) => ctx.collect_static(StaticSignature::of(db, s)),
+ DefWithBodyId::StaticId(s) => ctx.collect_static(s, StaticSignature::of(db, s)),
DefWithBodyId::VariantId(v) => {
ctx.return_ty = match EnumSignature::variant_body_type(db, v.lookup(db).parent) {
hir_def::layout::IntegerType::Pointer(signed) => match signed {
@@ -162,91 +185,38 @@ fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> I
}
}
-/// Infer types for all const expressions in an item's signature.
-///
-/// This handles const expressions that appear in type positions within a generic
-/// item's signature, such as array lengths (`[T; N]`) and const generic arguments
-/// (`Foo<{ expr }>`). Each root expression is inferred independently within
-/// a shared `InferenceContext`, accumulating results into a single `InferenceResult`.
-fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult {
- let _p = tracing::info_span!("infer_signature_query").entered();
- let store = ExpressionStore::of(db, def.into());
- let mut roots = store.expr_roots_with_origins().peekable();
- let Some(_) = roots.peek() else {
- return InferenceResult::new(crate::next_solver::default_types(db).types.error);
- };
-
- let resolver = def.resolver(db);
- let owner = ExpressionStoreOwnerId::Signature(def);
-
- let mut ctx = InferenceContext::new(db, owner, store, resolver);
-
- for (root_expr, origin) in roots {
- let expected = match origin {
- // Array lengths are always `usize`.
- RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize),
- // Const parameter default: look up the param's declared type.
- RootExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty_ns(
- ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }),
- )),
- // Path const generic args: determining the expected type requires
- // path resolution.
- // FIXME
- RootExprOrigin::GenericArgsPath => Expectation::None,
- RootExprOrigin::BodyRoot => Expectation::None,
- };
- ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes);
- }
-
- infer_finalize(ctx)
-}
-
-fn infer_variant_fields_query(db: &dyn HirDatabase, def: VariantId) -> InferenceResult {
- let _p = tracing::info_span!("infer_variant_fields_query").entered();
- let store = ExpressionStore::of(db, def.into());
- let mut roots = store.expr_roots_with_origins().peekable();
- let Some(_) = roots.peek() else {
- return InferenceResult::new(crate::next_solver::default_types(db).types.error);
- };
-
- let resolver = def.resolver(db);
- let owner = ExpressionStoreOwnerId::VariantFields(def);
-
- let mut ctx = InferenceContext::new(db, owner, store, resolver);
-
- for (root_expr, origin) in roots {
- let expected = match origin {
- // Array lengths are always `usize`.
- RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize),
- // unreachable
- RootExprOrigin::ConstParam(_) => Expectation::None,
- // Path const generic args: determining the expected type requires
- // path resolution.
- // FIXME
- RootExprOrigin::GenericArgsPath => Expectation::None,
- RootExprOrigin::BodyRoot => Expectation::None,
- };
- ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes);
- }
+/// Infer types for an anonymous const expression.
+fn infer_anon_const_query(db: &dyn HirDatabase, def: AnonConstId) -> InferenceResult {
+ let _p = tracing::info_span!("infer_anon_const_query").entered();
+ let loc = def.loc(db);
+ let store_owner = loc.owner;
+ let store = ExpressionStore::of(db, store_owner);
+
+ let resolver = store_owner.resolver(db);
+
+ let mut ctx = InferenceContext::new(
+ db,
+ InferBodyId::AnonConstId(def),
+ store_owner,
+ loc.owner.generic_def(db),
+ store,
+ resolver,
+ loc.allow_using_generic_params,
+ );
+
+ ctx.infer_expr(
+ loc.expr,
+ &Expectation::has_type(loc.ty.get().instantiate_identity().skip_norm_wip()),
+ ExprIsRead::Yes,
+ );
infer_finalize(ctx)
}
-fn infer_signature_cycle_result(
+fn infer_anon_const_cycle_result(
db: &dyn HirDatabase,
_: salsa::Id,
- _: GenericDefId,
-) -> InferenceResult {
- InferenceResult {
- has_errors: true,
- ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed))
- }
-}
-
-fn infer_variant_fields_cycle_result(
- db: &dyn HirDatabase,
- _: salsa::Id,
- _: VariantId,
+ _: AnonConstId,
) -> InferenceResult {
InferenceResult {
has_errors: true,
@@ -280,27 +250,25 @@ fn infer_finalize(mut ctx: InferenceContext<'_, '_>) -> InferenceResult {
ctx.handle_opaque_type_uses();
+ ctx.merge_anon_consts();
+
ctx.resolve_all()
}
-/// Binding modes inferred for patterns.
-/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
-pub enum BindingMode {
- #[default]
- Move,
- Ref(Mutability),
-}
-impl BindingMode {
- fn convert(annotation: BindingAnnotation) -> BindingMode {
- match annotation {
- BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move,
- BindingAnnotation::Ref => BindingMode::Ref(Mutability::Not),
- BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut),
- }
- }
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ByRef {
+ Yes(Mutability),
+ No,
}
+/// The mode of a binding (`mut`, `ref mut`, etc).
+/// Used for both the explicit binding annotations given in the HIR for a binding
+/// and the final binding mode that we infer after type inference/match ergonomics.
+/// `.0` is the by-reference mode (`ref`, `ref mut`, or by value),
+/// `.1` is the mutability of the binding.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct BindingMode(pub ByRef, pub Mutability);
+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum InferenceTyDiagnosticSource {
/// Diagnostics that come from types in the body.
@@ -309,104 +277,188 @@ pub enum InferenceTyDiagnosticSource {
Signature,
}
-#[derive(Debug, PartialEq, Eq, Clone)]
+#[derive(Debug, PartialEq, Eq, Clone, TypeVisitable, TypeFoldable)]
pub enum InferenceDiagnostic {
NoSuchField {
+ #[type_visitable(ignore)]
field: ExprOrPatId,
+ #[type_visitable(ignore)]
private: Option<LocalFieldId>,
+ #[type_visitable(ignore)]
+ variant: VariantId,
+ },
+ MismatchedArrayPatLen {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ #[type_visitable(ignore)]
+ expected: u128,
+ #[type_visitable(ignore)]
+ found: u128,
+ #[type_visitable(ignore)]
+ has_rest: bool,
+ },
+ ExpectedArrayOrSlicePat {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ found: StoredTy,
+ },
+ DuplicateField {
+ #[type_visitable(ignore)]
+ field: ExprOrPatId,
+ #[type_visitable(ignore)]
variant: VariantId,
},
PrivateField {
+ #[type_visitable(ignore)]
expr: ExprId,
+ #[type_visitable(ignore)]
field: FieldId,
},
PrivateAssocItem {
+ #[type_visitable(ignore)]
id: ExprOrPatId,
+ #[type_visitable(ignore)]
item: AssocItemId,
},
UnresolvedField {
+ #[type_visitable(ignore)]
expr: ExprId,
receiver: StoredTy,
+ #[type_visitable(ignore)]
name: Name,
+ #[type_visitable(ignore)]
method_with_same_name_exists: bool,
},
UnresolvedMethodCall {
+ #[type_visitable(ignore)]
expr: ExprId,
receiver: StoredTy,
+ #[type_visitable(ignore)]
name: Name,
/// Contains the type the field resolves to
field_with_same_name: Option<StoredTy>,
+ #[type_visitable(ignore)]
assoc_func_with_same_name: Option<FunctionId>,
},
UnresolvedAssocItem {
+ #[type_visitable(ignore)]
id: ExprOrPatId,
},
UnresolvedIdent {
+ #[type_visitable(ignore)]
id: ExprOrPatId,
},
// FIXME: This should be emitted in body lowering
BreakOutsideOfLoop {
+ #[type_visitable(ignore)]
expr: ExprId,
+ #[type_visitable(ignore)]
is_break: bool,
+ #[type_visitable(ignore)]
bad_value_break: bool,
},
+ NonExhaustiveRecordExpr {
+ #[type_visitable(ignore)]
+ expr: ExprId,
+ },
+ FunctionalRecordUpdateOnNonStruct {
+ #[type_visitable(ignore)]
+ base_expr: ExprId,
+ },
MismatchedArgCount {
+ #[type_visitable(ignore)]
call_expr: ExprId,
+ #[type_visitable(ignore)]
expected: usize,
+ #[type_visitable(ignore)]
found: usize,
},
MismatchedTupleStructPatArgCount {
- pat: ExprOrPatId,
+ #[type_visitable(ignore)]
+ pat: PatId,
+ #[type_visitable(ignore)]
expected: usize,
+ #[type_visitable(ignore)]
found: usize,
},
ExpectedFunction {
+ #[type_visitable(ignore)]
call_expr: ExprId,
found: StoredTy,
},
TypedHole {
+ #[type_visitable(ignore)]
expr: ExprId,
expected: StoredTy,
},
CastToUnsized {
+ #[type_visitable(ignore)]
expr: ExprId,
cast_ty: StoredTy,
},
InvalidCast {
+ #[type_visitable(ignore)]
expr: ExprId,
+ #[type_visitable(ignore)]
error: CastError,
expr_ty: StoredTy,
cast_ty: StoredTy,
},
TyDiagnostic {
+ #[type_visitable(ignore)]
source: InferenceTyDiagnosticSource,
+ #[type_visitable(ignore)]
diag: TyLoweringDiagnostic,
},
PathDiagnostic {
+ #[type_visitable(ignore)]
node: ExprOrPatId,
+ #[type_visitable(ignore)]
diag: PathLoweringDiagnostic,
},
MethodCallIncorrectGenericsLen {
+ #[type_visitable(ignore)]
expr: ExprId,
+ #[type_visitable(ignore)]
provided_count: u32,
+ #[type_visitable(ignore)]
expected_count: u32,
+ #[type_visitable(ignore)]
kind: IncorrectGenericsLenKind,
+ #[type_visitable(ignore)]
def: GenericDefId,
},
MethodCallIncorrectGenericsOrder {
+ #[type_visitable(ignore)]
expr: ExprId,
+ #[type_visitable(ignore)]
param_id: GenericParamId,
+ #[type_visitable(ignore)]
arg_idx: u32,
/// Whether the `GenericArgs` contains a `Self` arg.
+ #[type_visitable(ignore)]
has_self_arg: bool,
},
-}
-
-/// A mismatch between an expected and an inferred type.
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct TypeMismatch {
- pub expected: StoredTy,
- pub actual: StoredTy,
+ InvalidLhsOfAssignment {
+ #[type_visitable(ignore)]
+ lhs: ExprId,
+ },
+ TypeMustBeKnown {
+ #[type_visitable(ignore)]
+ at_point: Span,
+ top_term: Option<StoredGenericArg>,
+ },
+ UnionExprMustHaveExactlyOneField {
+ #[type_visitable(ignore)]
+ expr: ExprId,
+ },
+ TypeMismatch {
+ #[type_visitable(ignore)]
+ node: ExprOrPatId,
+ expected: StoredTy,
+ found: StoredTy,
+ },
+ SolverDiagnostic(SolverDiagnostic),
}
/// Represents coercing a value to a different type of value.
@@ -575,6 +627,27 @@ pub enum PointerCast {
Unsize,
}
+/// Represents an implicit coercion applied to the scrutinee of a match before testing a pattern
+/// against it. Currently, this is used only for implicit dereferences.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct PatAdjustment {
+ pub kind: PatAdjust,
+ /// The type of the scrutinee before the adjustment is applied, or the "adjusted type" of the
+ /// pattern.
+ pub source: StoredTy,
+}
+
+/// Represents implicit coercions of patterns' types, rather than values' types.
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum PatAdjust {
+ /// An implicit dereference before matching, such as when matching the pattern `0` against a
+ /// scrutinee of type `&u8` or `&mut u8`.
+ BuiltinDeref,
+ /// An implicit call to `Deref(Mut)::deref(_mut)` before matching, such as when matching the
+ /// pattern `[..]` against a scrutinee of type `Vec<T>`.
+ OverloadedDeref,
+}
+
/// The result of type inference: A mapping from expressions and patterns to types.
///
/// When you add a field that stores types (including `Substitution` and the like), don't forget
@@ -605,7 +678,6 @@ pub struct InferenceResult {
pub(crate) type_of_type_placeholder: FxHashMap<TypeRefId, StoredTy>,
pub(crate) type_of_opaque: FxHashMap<InternedOpaqueTyId, StoredTy>,
- pub(crate) type_mismatches: Option<Box<FxHashMap<ExprOrPatId, TypeMismatch>>>,
/// Whether there are any type-mismatching errors in the result.
// FIXME: This isn't as useful as initially thought due to us falling back placeholders to
// `TyKind::Error`.
@@ -613,6 +685,8 @@ pub struct InferenceResult {
pub(crate) has_errors: bool,
/// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead.
diagnostics: ThinVec<InferenceDiagnostic>,
+ // FIXME: Remove this, change it to be in `InferenceContext`:
+ nodes_with_type_mismatches: Option<Box<FxHashSet<ExprOrPatId>>>,
/// Interned `Error` type to return references to.
// FIXME: Remove this.
@@ -620,7 +694,7 @@ pub struct InferenceResult {
pub(crate) expr_adjustments: FxHashMap<ExprId, Box<[Adjustment]>>,
/// Stores the types which were implicitly dereferenced in pattern binding modes.
- pub(crate) pat_adjustments: FxHashMap<PatId, Vec<StoredTy>>,
+ pub(crate) pat_adjustments: FxHashMap<PatId, Vec<PatAdjustment>>,
/// Stores the binding mode (`ref` in `let ref x = 2`) of bindings.
///
/// This one is tied to the `PatId` instead of `BindingId`, because in some rare cases, a binding in an
@@ -636,9 +710,15 @@ pub struct InferenceResult {
/// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`.
pub(crate) binding_modes: ArenaMap<PatId, BindingMode>,
+ /// Set of reference patterns that match against a match-ergonomics inserted reference
+ /// (as opposed to against a reference in the scrutinee type).
+ skipped_ref_pats: FxHashSet<PatId>,
+
pub(crate) coercion_casts: FxHashSet<ExprId>,
pub closures_data: FxHashMap<ExprId, ClosureData>,
+
+ defined_anon_consts: ThinVec<AnonConstId>,
}
#[derive(Clone, PartialEq, Eq, Debug, Default)]
@@ -870,30 +950,21 @@ impl InferenceResult {
/// Returns an `InferenceResult` containing type information for array lengths,
/// const generic arguments, and other const expressions appearing in type
/// positions within the item's signature.
- #[salsa::tracked(returns(ref), cycle_result = infer_signature_cycle_result)]
- fn for_signature(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult {
- infer_signature_query(db, def)
- }
-
- #[salsa::tracked(returns(ref), cycle_result = infer_variant_fields_cycle_result)]
- fn for_variant_fields(db: &dyn HirDatabase, def: VariantId) -> InferenceResult {
- infer_variant_fields_query(db, def)
+ #[salsa::tracked(returns(ref), cycle_result = infer_anon_const_cycle_result)]
+ fn for_anon_const(db: &dyn HirDatabase, def: AnonConstId) -> InferenceResult {
+ infer_anon_const_query(db, def)
}
-}
-impl InferenceResult {
- pub fn of(db: &dyn HirDatabase, def: impl Into<ExpressionStoreOwnerId>) -> &InferenceResult {
+ #[inline]
+ pub fn of(db: &dyn HirDatabase, def: impl Into<InferBodyId>) -> &InferenceResult {
match def.into() {
- ExpressionStoreOwnerId::Signature(generic_def_id) => {
- Self::for_signature(db, generic_def_id)
- }
- ExpressionStoreOwnerId::Body(def_with_body_id) => Self::for_body(db, def_with_body_id),
- ExpressionStoreOwnerId::VariantFields(variant_id) => {
- Self::for_variant_fields(db, variant_id)
- }
+ InferBodyId::DefWithBodyId(it) => InferenceResult::for_body(db, it),
+ InferBodyId::AnonConstId(it) => InferenceResult::for_anon_const(db, it),
}
}
+}
+impl InferenceResult {
fn new(error_ty: Ty<'_>) -> Self {
Self {
method_resolutions: Default::default(),
@@ -902,12 +973,13 @@ impl InferenceResult {
assoc_resolutions: Default::default(),
tuple_field_access_types: Default::default(),
diagnostics: Default::default(),
+ nodes_with_type_mismatches: Default::default(),
type_of_expr: Default::default(),
type_of_pat: Default::default(),
type_of_binding: Default::default(),
type_of_type_placeholder: Default::default(),
type_of_opaque: Default::default(),
- type_mismatches: Default::default(),
+ skipped_ref_pats: Default::default(),
has_errors: Default::default(),
error_ty: error_ty.store(),
pat_adjustments: Default::default(),
@@ -915,6 +987,7 @@ impl InferenceResult {
expr_adjustments: Default::default(),
coercion_casts: Default::default(),
closures_data: Default::default(),
+ defined_anon_consts: Default::default(),
}
}
@@ -957,26 +1030,22 @@ impl InferenceResult {
ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id),
}
}
- pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
- self.type_mismatches.as_deref()?.get(&expr.into())
+ pub fn expr_or_pat_has_type_mismatch(&self, node: ExprOrPatId) -> bool {
+ self.nodes_with_type_mismatches.as_ref().is_some_and(|it| it.contains(&node))
}
- pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> {
- self.type_mismatches.as_deref()?.get(&pat.into())
+ pub fn expr_has_type_mismatch(&self, expr: ExprId) -> bool {
+ self.expr_or_pat_has_type_mismatch(expr.into())
}
- pub fn type_mismatches(&self) -> impl Iterator<Item = (ExprOrPatId, &TypeMismatch)> {
- self.type_mismatches
- .as_deref()
- .into_iter()
- .flatten()
- .map(|(expr_or_pat, mismatch)| (*expr_or_pat, mismatch))
- }
- pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> {
- self.type_mismatches.as_deref().into_iter().flatten().filter_map(
- |(expr_or_pat, mismatch)| match *expr_or_pat {
- ExprOrPatId::ExprId(expr) => Some((expr, mismatch)),
- _ => None,
- },
- )
+ pub fn pat_has_type_mismatch(&self, pat: PatId) -> bool {
+ self.expr_or_pat_has_type_mismatch(pat.into())
+ }
+ pub fn exprs_have_type_mismatches(&self) -> bool {
+ self.nodes_with_type_mismatches
+ .as_ref()
+ .is_some_and(|it| it.iter().any(|node| node.is_expr()))
+ }
+ pub fn has_type_mismatches(&self) -> bool {
+ self.nodes_with_type_mismatches.is_some()
}
pub fn placeholder_types<'db>(&self) -> impl Iterator<Item = (TypeRefId, Ty<'db>)> {
self.type_of_type_placeholder.iter().map(|(&type_ref, ty)| (type_ref, ty.as_ref()))
@@ -1007,10 +1076,10 @@ impl InferenceResult {
None => self.type_of_expr.get(id).map(|it| it.as_ref()),
}
}
- pub fn type_of_pat_with_adjust<'db>(&self, id: PatId) -> Option<Ty<'db>> {
+ pub fn type_of_pat_with_adjust<'db>(&self, id: PatId) -> Ty<'db> {
match self.pat_adjustments.get(&id).and_then(|adjustments| adjustments.last()) {
- Some(adjusted) => Some(adjusted.as_ref()),
- None => self.type_of_pat.get(id).map(|it| it.as_ref()),
+ Some(adjusted) => adjusted.source.as_ref(),
+ None => self.pat_ty(id),
}
}
pub fn is_erroneous(&self) -> bool {
@@ -1025,7 +1094,7 @@ impl InferenceResult {
self.tuple_field_access_types[id.0 as usize].as_ref()
}
- pub fn pat_adjustment(&self, id: PatId) -> Option<&[StoredTy]> {
+ pub fn pat_adjustment(&self, id: PatId) -> Option<&[PatAdjustment]> {
self.pat_adjustments.get(&id).map(|it| &**it)
}
@@ -1100,23 +1169,37 @@ impl InferenceResult {
.values()
.flat_map(|captures| captures.iter().map(|capture| capture.captured_ty(db)))
}
+
+ pub fn is_skipped_ref_pat(&self, pat: PatId) -> bool {
+ self.skipped_ref_pats.contains(&pat)
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+enum DerefPatBorrowMode {
+ Borrow(Mutability),
+ Box,
}
/// The inference context contains all information needed during type inference.
-#[derive(Clone, Debug)]
+#[derive(Debug)]
pub(crate) struct InferenceContext<'body, 'db> {
pub(crate) db: &'db dyn HirDatabase,
- pub(crate) owner: ExpressionStoreOwnerId,
+ pub(crate) owner: InferBodyId,
+ pub(crate) store_owner: ExpressionStoreOwnerId,
+ pub(crate) generic_def: GenericDefId,
pub(crate) store: &'body ExpressionStore,
/// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext
/// and resolve the path via its methods. This will ensure proper error reporting.
pub(crate) resolver: Resolver<'db>,
target_features: OnceCell<(TargetFeatures<'db>, TargetFeatureIsSafeInTarget)>,
- pub(crate) unstable_features: MethodResolutionUnstableFeatures,
pub(crate) edition: Edition,
- pub(crate) generic_def: GenericDefId,
+ allow_using_generic_params: bool,
+ generics: OnceCell<Generics<'db>>,
+ identity_args: OnceCell<GenericArgs<'db>>,
pub(crate) table: unify::InferenceTable<'db>,
pub(crate) lang_items: &'db LangItems,
+ pub(crate) features: &'db UnstableFeatures,
/// The traits in scope, disregarding block modules. This is used for caching purposes.
traits_in_scope: FxHashSet<TraitId>,
pub(crate) result: InferenceResult,
@@ -1147,6 +1230,9 @@ pub(crate) struct InferenceContext<'body, 'db> {
deferred_call_resolutions: FxHashMap<ExprId, Vec<DeferredCallResolution<'db>>>,
diagnostics: Diagnostics,
+ vars_emitted_type_must_be_known_for: FxHashSet<Term<'db>>,
+
+ defined_anon_consts: RefCell<ThinVec<AnonConstId>>,
}
#[derive(Clone, Debug)]
@@ -1196,32 +1282,23 @@ fn find_continuable<'a, 'db>(
impl<'body, 'db> InferenceContext<'body, 'db> {
fn new(
db: &'db dyn HirDatabase,
- owner: ExpressionStoreOwnerId,
+ owner: InferBodyId,
+ store_owner: ExpressionStoreOwnerId,
+ generic_def: GenericDefId,
store: &'body ExpressionStore,
resolver: Resolver<'db>,
+ allow_using_generic_params: bool,
) -> Self {
- let trait_env = match owner {
- ExpressionStoreOwnerId::Signature(generic_def_id) => {
- db.trait_environment(ExpressionStoreOwnerId::from(generic_def_id))
- }
- ExpressionStoreOwnerId::Body(def_with_body_id) => {
- db.trait_environment(ExpressionStoreOwnerId::Body(def_with_body_id))
- }
- ExpressionStoreOwnerId::VariantFields(variant_id) => {
- db.trait_environment(ExpressionStoreOwnerId::VariantFields(variant_id))
- }
- };
- let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner));
+ let trait_env = db.trait_environment(store_owner);
+ let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), store_owner);
let types = crate::next_solver::default_types(db);
InferenceContext {
result: InferenceResult::new(types.types.error),
return_ty: types.types.error, // set in collect_* calls
types,
target_features: OnceCell::new(),
- unstable_features: MethodResolutionUnstableFeatures::from_def_map(
- resolver.top_level_def_map(),
- ),
lang_items: table.interner().lang_items(),
+ features: resolver.top_level_def_map().features(),
edition: resolver.krate().data(db).edition,
table,
tuple_field_accesses_rev: Default::default(),
@@ -1229,7 +1306,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
return_coercion: None,
db,
owner,
- generic_def: owner.generic_def(db),
+ store_owner,
+ generic_def,
+ allow_using_generic_params,
+ generics: OnceCell::new(),
+ identity_args: OnceCell::new(),
store,
traits_in_scope: resolver.traits_in_scope(db),
resolver,
@@ -1238,7 +1319,99 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
deferred_cast_checks: Vec::new(),
inside_assignment: false,
diagnostics: Diagnostics::default(),
+ vars_emitted_type_must_be_known_for: FxHashSet::default(),
deferred_call_resolutions: FxHashMap::default(),
+ defined_anon_consts: RefCell::new(ThinVec::new()),
+ }
+ }
+
+ fn merge(&mut self, other: &InferenceResult) {
+ let InferenceResult {
+ method_resolutions,
+ field_resolutions,
+ variant_resolutions,
+ assoc_resolutions,
+ tuple_field_access_types: _,
+ type_of_expr,
+ type_of_pat,
+ type_of_binding,
+ type_of_type_placeholder,
+ type_of_opaque,
+ has_errors: _,
+ diagnostics: _,
+ error_ty: _,
+ expr_adjustments,
+ pat_adjustments,
+ binding_modes,
+ skipped_ref_pats,
+ coercion_casts,
+ closures_data,
+ nodes_with_type_mismatches,
+ defined_anon_consts: _,
+ } = &mut self.result;
+ merge_hash_maps(method_resolutions, &other.method_resolutions);
+ merge_hash_maps(variant_resolutions, &other.variant_resolutions);
+ merge_hash_maps(assoc_resolutions, &other.assoc_resolutions);
+ field_resolutions.extend(other.field_resolutions.iter().map(
+ |(&field_expr, &field_resolution)| {
+ let mut field_resolution = field_resolution;
+ if let Either::Right(tuple_field) = &mut field_resolution {
+ let tys = other.tuple_field_access_type(tuple_field.tuple);
+ tuple_field.tuple =
+ TupleId(self.tuple_field_accesses_rev.insert_full(tys).0 as u32);
+ };
+ (field_expr, field_resolution)
+ },
+ ));
+ merge_arena_maps(type_of_expr, &other.type_of_expr);
+ merge_arena_maps(type_of_pat, &other.type_of_pat);
+ merge_arena_maps(type_of_binding, &other.type_of_binding);
+ merge_hash_maps(type_of_type_placeholder, &other.type_of_type_placeholder);
+ merge_hash_maps(type_of_opaque, &other.type_of_opaque);
+ merge_hash_maps(expr_adjustments, &other.expr_adjustments);
+ merge_hash_maps(pat_adjustments, &other.pat_adjustments);
+ merge_arena_maps(binding_modes, &other.binding_modes);
+ merge_hash_set(skipped_ref_pats, &other.skipped_ref_pats);
+ merge_hash_set(coercion_casts, &other.coercion_casts);
+ merge_hash_maps(closures_data, &other.closures_data);
+ if let Some(other_nodes_with_type_mismatches) = &other.nodes_with_type_mismatches {
+ merge_hash_set(
+ nodes_with_type_mismatches.get_or_insert_default(),
+ other_nodes_with_type_mismatches,
+ );
+ }
+ self.defined_anon_consts.borrow_mut().extend(other.defined_anon_consts.iter().copied());
+
+ fn merge_hash_set<T: Hash + Eq + Clone>(dest: &mut FxHashSet<T>, source: &FxHashSet<T>) {
+ dest.extend(source.iter().cloned());
+ }
+
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn merge_hash_maps<K: Hash + Eq + Clone, V: Clone + PartialEq>(
+ dest: &mut FxHashMap<K, V>,
+ source: &FxHashMap<K, V>,
+ ) {
+ if cfg!(debug_assertions) {
+ for (key, src) in source {
+ assert!(dest.get(key).is_none_or(|dst| dst == src));
+ }
+ }
+
+ dest.extend(source.iter().map(|(k, v)| (k.clone(), v.clone())));
+ }
+
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn merge_arena_maps<K, V: Clone + PartialEq>(
+ dest: &mut ArenaMap<la_arena::Idx<K>, V>,
+ source: &ArenaMap<la_arena::Idx<K>, V>,
+ ) {
+ if cfg!(debug_assertions) {
+ for (key, src) in source.iter() {
+ assert!(dest.get(key).is_none_or(|dst| dst == src));
+ }
+ }
+
+ dest.extend(source.iter().map(|(k, v)| (k, v.clone())));
}
}
@@ -1249,7 +1422,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
fn target_features(&self) -> (&TargetFeatures<'db>, TargetFeatureIsSafeInTarget) {
let (target_features, target_feature_is_safe) = self.target_features.get_or_init(|| {
- let target_features = match self.owner {
+ let target_features = match self.store_owner {
ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => {
TargetFeatures::from_fn(self.db, id)
}
@@ -1264,31 +1437,43 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
(target_features, *target_feature_is_safe)
}
+ /// How should a deref pattern find the place for its inner pattern to match on?
+ ///
+ /// In most cases, if the pattern recursively contains a `ref mut` binding, we find the inner
+ /// pattern's scrutinee by calling `DerefMut::deref_mut`, and otherwise we call `Deref::deref`.
+ /// However, for boxes we can use a built-in deref instead, which doesn't borrow the scrutinee;
+ /// in this case, we return `DerefPatBorrowMode::Box`.
+ fn deref_pat_borrow_mode(&self, pointer_ty: Ty<'_>, inner: PatId) -> DerefPatBorrowMode {
+ if pointer_ty.is_box() {
+ DerefPatBorrowMode::Box
+ } else {
+ let mutability =
+ if self.pat_has_ref_mut_binding(inner) { Mutability::Mut } else { Mutability::Not };
+ DerefPatBorrowMode::Borrow(mutability)
+ }
+ }
+
#[inline]
fn set_tainted_by_errors(&mut self) {
self.result.has_errors = true;
}
- /// Clones `self` and calls `resolve_all()` on it.
- // FIXME: Remove this.
- pub(crate) fn fixme_resolve_all_clone(&self) -> InferenceResult {
- let mut ctx = self.clone();
-
- ctx.type_inference_fallback();
-
- // Comment from rustc:
- // Even though coercion casts provide type hints, we check casts after fallback for
- // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
- let cast_checks = std::mem::take(&mut ctx.deferred_cast_checks);
- for mut cast in cast_checks.into_iter() {
- if let Err(diag) = cast.check(&mut ctx) {
- ctx.diagnostics.push(diag);
+ /// Copy the inference of defined anon consts to ourselves, so that we don't need to lookup the defining
+ /// anon const when looking the type of something.
+ fn merge_anon_consts(&mut self) {
+ let mut defined_anon_consts = std::mem::take(&mut *self.defined_anon_consts.borrow_mut());
+ defined_anon_consts.retain(|&konst| {
+ if konst.loc(self.db).owner != self.store_owner {
+ // This comes from the signature, we don't define it.
+ return false;
}
- }
-
- ctx.table.select_obligations_where_possible();
- ctx.resolve_all()
+ let const_infer = InferenceResult::of(self.db, konst);
+ self.merge(const_infer);
+ true
+ });
+ // Caution, other defined anon consts might have been added by `merge()`!
+ self.defined_anon_consts.borrow_mut().append(&mut defined_anon_consts);
}
// FIXME: This function should be private in module. It is currently only used in the consteval, since we need
@@ -1297,14 +1482,15 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
// there is no problem in it being `pub(crate)`, remove this comment.
fn resolve_all(self) -> InferenceResult {
let InferenceContext {
- mut table,
+ table,
mut result,
tuple_field_accesses_rev,
diagnostics,
types,
+ vars_emitted_type_must_be_known_for,
..
} = self;
- let mut diagnostics = diagnostics.finish();
+ let diagnostics = diagnostics.finish();
// Destructure every single field so whenever new fields are added to `InferenceResult` we
// don't forget to handle them here.
let InferenceResult {
@@ -1317,97 +1503,66 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
type_of_binding,
type_of_type_placeholder,
type_of_opaque,
- type_mismatches,
+ skipped_ref_pats,
closures_data,
has_errors,
error_ty: _,
pat_adjustments,
binding_modes: _,
expr_adjustments,
- tuple_field_access_types: _,
+ tuple_field_access_types,
coercion_casts: _,
- diagnostics: _,
+ diagnostics: result_diagnostics,
+ nodes_with_type_mismatches,
+ defined_anon_consts: result_defined_anon_consts,
} = &mut result;
+ *result_defined_anon_consts = self.defined_anon_consts.into_inner();
+ result_defined_anon_consts.shrink_to_fit();
+
+ let mut resolver =
+ WriteBackCtxt::new(table, diagnostics, vars_emitted_type_must_be_known_for);
+
+ skipped_ref_pats.shrink_to_fit();
for ty in type_of_expr.values_mut() {
- *ty = table.resolve_completely(ty.as_ref()).store();
- *has_errors = *has_errors || ty.as_ref().references_non_lt_error();
+ resolver.resolve_completely(ty);
}
type_of_expr.shrink_to_fit();
for ty in type_of_pat.values_mut() {
- *ty = table.resolve_completely(ty.as_ref()).store();
- *has_errors = *has_errors || ty.as_ref().references_non_lt_error();
+ resolver.resolve_completely(ty);
}
type_of_pat.shrink_to_fit();
for ty in type_of_binding.values_mut() {
- *ty = table.resolve_completely(ty.as_ref()).store();
- *has_errors = *has_errors || ty.as_ref().references_non_lt_error();
+ resolver.resolve_completely(ty);
}
type_of_binding.shrink_to_fit();
for ty in type_of_type_placeholder.values_mut() {
- *ty = table.resolve_completely(ty.as_ref()).store();
- *has_errors = *has_errors || ty.as_ref().references_non_lt_error();
+ resolver.resolve_completely(ty);
}
type_of_type_placeholder.shrink_to_fit();
type_of_opaque.shrink_to_fit();
- if let Some(type_mismatches) = type_mismatches {
+ if let Some(nodes_with_type_mismatches) = nodes_with_type_mismatches {
*has_errors = true;
- for mismatch in type_mismatches.values_mut() {
- mismatch.expected = table.resolve_completely(mismatch.expected.as_ref()).store();
- mismatch.actual = table.resolve_completely(mismatch.actual.as_ref()).store();
- }
- type_mismatches.shrink_to_fit();
+ nodes_with_type_mismatches.shrink_to_fit();
}
- diagnostics.retain_mut(|diagnostic| {
- use InferenceDiagnostic::*;
- match diagnostic {
- ExpectedFunction { found: ty, .. }
- | UnresolvedField { receiver: ty, .. }
- | UnresolvedMethodCall { receiver: ty, .. } => {
- *ty = table.resolve_completely(ty.as_ref()).store();
- // FIXME: Remove this when we are on par with rustc in terms of inference
- if ty.as_ref().references_non_lt_error() {
- return false;
- }
-
- if let UnresolvedMethodCall { field_with_same_name, .. } = diagnostic
- && let Some(ty) = field_with_same_name
- {
- *ty = table.resolve_completely(ty.as_ref()).store();
- if ty.as_ref().references_non_lt_error() {
- *field_with_same_name = None;
- }
- }
- }
- TypedHole { expected: ty, .. } => {
- *ty = table.resolve_completely(ty.as_ref()).store();
- }
- _ => (),
- }
- true
- });
- diagnostics.shrink_to_fit();
for (_, subst) in method_resolutions.values_mut() {
- *subst = table.resolve_completely(subst.as_ref()).store();
- *has_errors =
- *has_errors || subst.as_ref().types().any(|ty| ty.references_non_lt_error());
+ resolver.resolve_completely(subst);
}
method_resolutions.shrink_to_fit();
for (_, subst) in assoc_resolutions.values_mut() {
- *subst = table.resolve_completely(subst.as_ref()).store();
- *has_errors =
- *has_errors || subst.as_ref().types().any(|ty| ty.references_non_lt_error());
+ resolver.resolve_completely(subst);
}
assoc_resolutions.shrink_to_fit();
for adjustment in expr_adjustments.values_mut().flatten() {
- adjustment.target = table.resolve_completely(adjustment.target.as_ref()).store();
- *has_errors = *has_errors || adjustment.target.as_ref().references_non_lt_error();
+ resolver.resolve_completely(&mut adjustment.target);
}
expr_adjustments.shrink_to_fit();
- for adjustment in pat_adjustments.values_mut().flatten() {
- *adjustment = table.resolve_completely(adjustment.as_ref()).store();
- *has_errors = *has_errors || adjustment.as_ref().references_non_lt_error();
+ for adjustments in pat_adjustments.values_mut() {
+ for adjustment in &mut *adjustments {
+ resolver.resolve_completely(&mut adjustment.source);
+ }
+ adjustments.shrink_to_fit();
}
pat_adjustments.shrink_to_fit();
for closure_data in closures_data.values_mut() {
@@ -1419,7 +1574,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
};
for (place, _, sources) in fake_reads {
- *place = table.resolve_completely(std::mem::replace(place, dummy_place()));
+ resolver.resolve_completely_with_default(place, dummy_place());
place.projections.shrink_to_fit();
for source in &mut *sources {
source.shrink_to_fit();
@@ -1430,7 +1585,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
for min_capture in min_captures.values_mut() {
for captured in &mut *min_capture {
let CapturedPlace { place, info, mutability: _ } = captured;
- *place = table.resolve_completely(std::mem::replace(place, dummy_place()));
+ resolver.resolve_completely_with_default(place, dummy_place());
let CaptureInfo { sources, capture_kind: _ } = info;
for source in &mut *sources {
source.shrink_to_fit();
@@ -1442,17 +1597,18 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
min_captures.shrink_to_fit();
}
closures_data.shrink_to_fit();
- result.tuple_field_access_types = tuple_field_accesses_rev
+ *tuple_field_access_types = tuple_field_accesses_rev
.into_iter()
- .map(|subst| table.resolve_completely(subst).store())
- .inspect(|subst| {
- *has_errors =
- *has_errors || subst.as_ref().iter().any(|ty| ty.references_non_lt_error());
+ .map(|mut subst| {
+ resolver.resolve_completely(&mut subst);
+ subst.store()
})
.collect();
- result.tuple_field_access_types.shrink_to_fit();
+ tuple_field_access_types.shrink_to_fit();
- result.diagnostics = diagnostics;
+ let (diagnostics, resolver_has_errors) = resolver.resolve_diagnostics();
+ *result_diagnostics = diagnostics;
+ *has_errors |= resolver_has_errors;
result
}
@@ -1462,17 +1618,19 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
data.type_ref,
&data.store,
InferenceTyDiagnosticSource::Signature,
+ ExpressionStoreOwnerId::Signature(id.into()),
LifetimeElisionKind::for_const(self.interner(), id.loc(self.db).container),
);
self.return_ty = return_ty;
}
- fn collect_static(&mut self, data: &StaticSignature) {
+ fn collect_static(&mut self, id: StaticId, data: &StaticSignature) {
let return_ty = self.make_ty(
data.type_ref,
&data.store,
InferenceTyDiagnosticSource::Signature,
+ ExpressionStoreOwnerId::Signature(id.into()),
LifetimeElisionKind::Elided(self.types.regions.statik),
);
@@ -1484,6 +1642,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
let mut param_tys = self.with_ty_lowering(
&data.store,
InferenceTyDiagnosticSource::Signature,
+ ExpressionStoreOwnerId::Signature(func.into()),
LifetimeElisionKind::for_fn_params(data),
|ctx| data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>(),
);
@@ -1498,7 +1657,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
GenericArgs::for_item_with_defaults(
self.interner(),
va_list.into(),
- |_, id, _| self.table.next_var_for_param(id),
+ |_, id, _| self.table.var_for_def(id, Span::Dummy),
),
),
None => self.err_ty(),
@@ -1506,23 +1665,25 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
param_tys.push(va_list_ty);
}
- let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.next_ty_var()));
+ let mut param_tys = param_tys.into_iter();
if let Some(self_param) = self_param
&& let Some(ty) = param_tys.next()
{
let ty = self.process_user_written_ty(ty);
self.write_binding_ty(self_param, ty);
}
- for (ty, pat) in param_tys.zip(params) {
+ for pat in params {
+ let ty = param_tys.next().unwrap_or_else(|| self.table.next_ty_var(Span::Dummy));
let ty = self.process_user_written_ty(ty);
- self.infer_top_pat(*pat, ty, None);
+ self.infer_top_pat(*pat, ty, PatOrigin::Param);
}
self.return_ty = match data.ret_type {
Some(return_ty) => {
let return_ty = self.with_ty_lowering(
&data.store,
InferenceTyDiagnosticSource::Signature,
+ ExpressionStoreOwnerId::Signature(func.into()),
LifetimeElisionKind::for_fn_ret(self.interner()),
|ctx| {
ctx.impl_trait_mode(ImplTraitLoweringMode::Opaque);
@@ -1547,6 +1708,33 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
&self.table.infer_ctxt
}
+ /// If `ty` is an error, returns an infer var instead. Otherwise, returns it.
+ ///
+ /// "Refreshing" types like this is useful for getting better types, but it is also
+ /// very dangerous: we might create duplicate diagnostics, for example if we try
+ /// to resolve it and fail. rustc doesn't do that for this reason (and is in general
+ /// more strict with how it uses error types; an error type in inputs will almost
+ /// always cause it to infer an error type in output, while we infer some type as much
+ /// as we can).
+ ///
+ /// Unfortunately, we cannot allow ourselves to do that. Not only we more often work
+ /// with incomplete code, we also have assists, for example "Generate constant", that
+ /// will assume the inferred type is the expected type even if the expression itself
+ /// cannot be inferred. Therefore, we choose a middle ground: refresh the type,
+ /// but if we return a new var, mark it so that no diagnostics will be issued on it.
+ fn insert_type_vars_shallow(&mut self, ty: Ty<'db>) -> Ty<'db> {
+ if ty.is_ty_error() {
+ let var = self.table.next_ty_var(Span::Dummy);
+
+ // Suppress future errors on this var. Add more things here when we add more diagnostics.
+ self.vars_emitted_type_must_be_known_for.insert(var.into());
+
+ var
+ } else {
+ ty
+ }
+ }
+
fn infer_body(&mut self, body_expr: ExprId) {
match self.return_coercion {
Some(_) => self.infer_return(body_expr),
@@ -1590,13 +1778,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
}
- fn write_pat_adj(&mut self, pat: PatId, adjustments: Box<[StoredTy]>) {
- if adjustments.is_empty() {
- return;
- }
- self.result.pat_adjustments.entry(pat).or_default().extend(adjustments);
- }
-
pub(crate) fn write_method_resolution(
&mut self,
expr: ExprId,
@@ -1623,10 +1804,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
self.result.type_of_pat.insert(pat, ty.store());
}
- fn write_type_placeholder_ty(&mut self, type_ref: TypeRefId, ty: Ty<'db>) {
- self.result.type_of_type_placeholder.insert(type_ref, ty.store());
- }
-
fn write_binding_ty(&mut self, id: BindingId, ty: Ty<'db>) {
self.result.type_of_binding.insert(id, ty.store());
}
@@ -1654,17 +1831,30 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
&mut self,
store: &ExpressionStore,
types_source: InferenceTyDiagnosticSource,
+ store_owner: ExpressionStoreOwnerId,
lifetime_elision: LifetimeElisionKind<'db>,
f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> R,
) -> R {
+ let infer_vars = match types_source {
+ InferenceTyDiagnosticSource::Body => Some(&mut InferenceTyLoweringVarsCtx {
+ table: &mut self.table,
+ type_of_type_placeholder: &mut self.result.type_of_type_placeholder,
+ } as _),
+ InferenceTyDiagnosticSource::Signature => None,
+ };
let mut ctx = TyLoweringContext::new(
self.db,
&self.resolver,
store,
&self.diagnostics,
types_source,
+ store_owner,
self.generic_def,
+ &self.generics,
lifetime_elision,
+ self.allow_using_generic_params,
+ infer_vars,
+ &self.defined_anon_consts,
);
f(&mut ctx)
}
@@ -1676,6 +1866,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
self.with_ty_lowering(
self.store,
InferenceTyDiagnosticSource::Body,
+ self.store_owner,
LifetimeElisionKind::Infer,
f,
)
@@ -1686,29 +1877,13 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
type_ref: TypeRefId,
store: &ExpressionStore,
type_source: InferenceTyDiagnosticSource,
+ store_owner: ExpressionStoreOwnerId,
lifetime_elision: LifetimeElisionKind<'db>,
) -> Ty<'db> {
- let ty = self
- .with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref));
- let ty = self.process_user_written_ty(ty);
-
- // Record the association from placeholders' TypeRefId to type variables.
- // We only record them if their number matches. This assumes TypeRef::walk and TypeVisitable process the items in the same order.
- let type_variables = collect_type_inference_vars(&ty);
- let mut placeholder_ids = vec![];
- TypeRef::walk(type_ref, store, &mut |type_ref_id, type_ref| {
- if matches!(type_ref, TypeRef::Placeholder) {
- placeholder_ids.push(type_ref_id);
- }
+ let ty = self.with_ty_lowering(store, type_source, store_owner, lifetime_elision, |ctx| {
+ ctx.lower_ty(type_ref)
});
-
- if placeholder_ids.len() == type_variables.len() {
- for (placeholder_id, type_variable) in placeholder_ids.into_iter().zip(type_variables) {
- self.write_type_placeholder_ty(placeholder_id, type_variable);
- }
- }
-
- ty
+ self.process_user_written_ty(ty)
}
pub(crate) fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> {
@@ -1716,28 +1891,57 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
type_ref,
self.store,
InferenceTyDiagnosticSource::Body,
+ self.store_owner,
LifetimeElisionKind::Infer,
)
}
- pub(crate) fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty<'db>) -> Const<'db> {
- let const_ = self.with_ty_lowering(
- self.store,
- InferenceTyDiagnosticSource::Body,
- LifetimeElisionKind::Infer,
- |ctx| ctx.lower_const(const_ref, ty),
- );
- self.insert_type_vars(const_)
+ fn generics(&self) -> &Generics<'db> {
+ self.generics.get_or_init(|| crate::generics::generics(self.db, self.generic_def))
+ }
+
+ fn identity_args(&self) -> GenericArgs<'db> {
+ *self.identity_args.get_or_init(|| {
+ GenericArgs::identity_for_item(self.interner(), self.store_owner.into())
+ })
}
- pub(crate) fn make_path_as_body_const(&mut self, path: &Path, ty: Ty<'db>) -> Const<'db> {
- let const_ = self.with_ty_lowering(
+ pub(crate) fn create_body_anon_const(
+ &mut self,
+ expr: ExprId,
+ expected_ty: Ty<'db>,
+ allow_using_generic_params: bool,
+ ) -> Const<'db> {
+ never!(expected_ty.has_infer(), "cannot have infer vars in an anon const's ty");
+ let konst = create_anon_const(
+ self.interner(),
+ self.store_owner,
self.store,
- InferenceTyDiagnosticSource::Body,
- LifetimeElisionKind::Infer,
- |ctx| ctx.lower_path_as_const(path, ty),
+ expr,
+ &self.resolver,
+ expected_ty,
+ &|| self.generics(),
+ Some(&mut |span| self.table.next_const_var(span)),
+ (!(allow_using_generic_params && self.allow_using_generic_params)).then_some(0),
);
- self.insert_type_vars(const_)
+
+ if let Ok(konst) = konst
+ && let ConstKind::Unevaluated(konst) = konst.kind()
+ && let GeneralConstId::AnonConstId(konst) = konst.def.0
+ {
+ self.defined_anon_consts.borrow_mut().push(konst);
+ }
+
+ self.write_expr_ty(expr, expected_ty);
+ // FIXME: Report an error if needed.
+ konst.unwrap_or_else(|_| self.table.next_const_var(Span::Dummy))
+ }
+
+ pub(crate) fn make_path_as_body_const(&mut self, path: &Path) -> Const<'db> {
+ let forbid_params_after = if self.allow_using_generic_params { None } else { Some(0) };
+ // FIXME: Report errors.
+ path_to_const(self.db, &self.resolver, &|| self.generics(), forbid_params_after, path)
+ .unwrap_or_else(|_| self.table.next_const_var(Span::Dummy))
}
fn err_ty(&self) -> Ty<'db> {
@@ -1748,17 +1952,13 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
let lt = self.with_ty_lowering(
self.store,
InferenceTyDiagnosticSource::Body,
+ self.store_owner,
LifetimeElisionKind::Infer,
|ctx| ctx.lower_lifetime(lifetime_ref),
);
self.insert_type_vars(lt)
}
- /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it.
- fn insert_type_vars_shallow(&mut self, ty: Ty<'db>) -> Ty<'db> {
- self.table.insert_type_vars_shallow(ty)
- }
-
fn insert_type_vars<T>(&mut self, ty: T) -> T
where
T: TypeFoldable<DbInterner<'db>>,
@@ -1766,10 +1966,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
self.table.insert_type_vars(ty)
}
- fn unify(&mut self, ty1: Ty<'db>, ty2: Ty<'db>) -> bool {
- self.table.unify(ty1, ty2)
- }
-
/// Attempts to returns the deeply last field of nested structures, but
/// does not apply any normalization in its search. Returns the same type
/// if input `ty` is not a structure at all.
@@ -1796,7 +1992,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
return self.err_ty();
}
match ty.kind() {
- TyKind::Adt(adt_def, substs) => match adt_def.def_id().0 {
+ TyKind::Adt(adt_def, substs) => match adt_def.def_id() {
AdtId::StructId(struct_id) => {
match self
.db
@@ -1806,7 +2002,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
.map(|it| it.get())
{
Some(field) => {
- ty = field.instantiate(self.interner(), substs);
+ ty = field.instantiate(self.interner(), substs).skip_norm_wip();
}
None => break,
}
@@ -1846,12 +2042,28 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
self.table.shallow_resolve(ty)
}
- fn resolve_associated_type(
+ pub(crate) fn resolve_vars_if_possible<T: TypeFoldable<DbInterner<'db>>>(&self, t: T) -> T {
+ self.table.resolve_vars_if_possible(t)
+ }
+
+ pub(crate) fn structurally_resolve_type(&mut self, node: ExprOrPatId, ty: Ty<'db>) -> Ty<'db> {
+ let result = self.table.try_structurally_resolve_type(node.into(), ty);
+ if result.is_ty_var() { self.type_must_be_known_at_this_point(node, ty) } else { result }
+ }
+
+ pub(crate) fn emit_type_mismatch(
&mut self,
- inner_ty: Ty<'db>,
- assoc_ty: Option<TypeAliasId>,
- ) -> Ty<'db> {
- self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
+ node: ExprOrPatId,
+ expected: Ty<'db>,
+ found: Ty<'db>,
+ ) {
+ if self.result.nodes_with_type_mismatches.get_or_insert_default().insert(node) {
+ self.diagnostics.push(InferenceDiagnostic::TypeMismatch {
+ node,
+ expected: expected.store(),
+ found: found.store(),
+ });
+ }
}
fn demand_eqtype(
@@ -1860,14 +2072,15 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
expected: Ty<'db>,
actual: Ty<'db>,
) -> Result<(), ()> {
- let result = self.demand_eqtype_fixme_no_diag(expected, actual);
+ let result = self
+ .table
+ .at(&ObligationCause::new(id))
+ .eq(expected, actual)
+ .map(|infer_ok| self.table.register_infer_ok(infer_ok));
if result.is_err() {
- self.result
- .type_mismatches
- .get_or_insert_default()
- .insert(id, TypeMismatch { expected: expected.store(), actual: actual.store() });
+ self.emit_type_mismatch(id, expected, actual);
}
- result
+ result.map_err(drop)
}
fn demand_eqtype_fixme_no_diag(
@@ -1877,21 +2090,27 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
) -> Result<(), ()> {
let result = self
.table
- .at(&ObligationCause::new())
+ .at(&ObligationCause::dummy())
.eq(expected, actual)
.map(|infer_ok| self.table.register_infer_ok(infer_ok));
result.map_err(drop)
}
- fn demand_suptype(&mut self, expected: Ty<'db>, actual: Ty<'db>) {
+ fn demand_suptype(
+ &mut self,
+ id: ExprOrPatId,
+ expected: Ty<'db>,
+ actual: Ty<'db>,
+ ) -> Result<(), ()> {
let result = self
.table
- .at(&ObligationCause::new())
+ .at(&ObligationCause::new(id))
.sup(expected, actual)
.map(|infer_ok| self.table.register_infer_ok(infer_ok));
- if let Err(_err) = result {
- // FIXME: Emit diagnostic.
+ if result.is_err() {
+ self.emit_type_mismatch(id, expected, actual);
}
+ result.map_err(drop)
}
fn demand_coerce(
@@ -1902,7 +2121,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
allow_two_phase: AllowTwoPhase,
expr_is_read: ExprIsRead,
) -> Ty<'db> {
- let result = self.coerce(expr.into(), checked_ty, expected, allow_two_phase, expr_is_read);
+ let result = self.coerce(expr, checked_ty, expected, allow_two_phase, expr_is_read);
if let Err(_err) = result {
// FIXME: Emit diagnostic.
}
@@ -1910,19 +2129,24 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
pub(crate) fn type_must_be_known_at_this_point(
- &self,
- _id: ExprOrPatId,
- _ty: Ty<'db>,
+ &mut self,
+ node: ExprOrPatId,
+ ty: Ty<'db>,
) -> Ty<'db> {
- // FIXME: Emit an diagnostic.
+ if self.vars_emitted_type_must_be_known_for.insert(ty.into()) {
+ self.push_diagnostic(InferenceDiagnostic::TypeMustBeKnown {
+ at_point: node.into(),
+ top_term: None,
+ });
+ }
self.types.types.error
}
- pub(crate) fn require_type_is_sized(&mut self, ty: Ty<'db>) {
+ pub(crate) fn require_type_is_sized(&mut self, ty: Ty<'db>, span: Span) {
if !ty.references_non_lt_error()
&& let Some(sized_trait) = self.lang_items.Sized
{
- self.table.register_bound(ty, sized_trait, ObligationCause::new());
+ self.table.register_bound(ty, sized_trait, ObligationCause::new(span));
}
}
@@ -1940,39 +2164,16 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
ty.unwrap_or_else(|| self.expr_ty(e))
}
- fn resolve_associated_type_with_params(
- &mut self,
- inner_ty: Ty<'db>,
- assoc_ty: Option<TypeAliasId>,
- // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
- // handled when we support them.
- params: &[GenericArg<'db>],
- ) -> Ty<'db> {
- match assoc_ty {
- Some(res_assoc_ty) => {
- let alias = Ty::new_alias(
- self.interner(),
- AliasTy::new(
- self.interner(),
- AliasTyKind::Projection { def_id: res_assoc_ty.into() },
- iter::once(inner_ty.into()).chain(params.iter().copied()),
- ),
- );
- self.table.try_structurally_resolve_type(alias)
- }
- None => self.err_ty(),
- }
- }
-
fn resolve_variant(
&mut self,
node: ExprOrPatId,
- path: Option<&Path>,
+ path: &Path,
value_ns: bool,
) -> (Ty<'db>, Option<VariantId>) {
- let path = match path {
- Some(path) => path,
- None => return (self.err_ty(), None),
+ let interner = self.interner();
+ let mut vars_ctx = InferenceTyLoweringVarsCtx {
+ table: &mut self.table,
+ type_of_type_placeholder: &mut self.result.type_of_type_placeholder,
};
let mut ctx = TyLoweringContext::new(
self.db,
@@ -1980,21 +2181,26 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
self.store,
&self.diagnostics,
InferenceTyDiagnosticSource::Body,
+ self.store_owner,
self.generic_def,
+ &self.generics,
LifetimeElisionKind::Infer,
+ self.allow_using_generic_params,
+ Some(&mut vars_ctx),
+ &self.defined_anon_consts,
);
if let Some(type_anchor) = path.type_anchor() {
let mut segments = path.segments();
if segments.is_empty() {
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
}
let (mut ty, type_ns) = ctx.lower_ty_ext(type_anchor);
- ty = self.table.process_user_written_ty(ty);
+ ty = ctx.expect_table().process_user_written_ty(ty);
if let Some(TypeNs::SelfType(impl_)) = type_ns
&& let Some(trait_ref) = self.db.impl_trait(impl_)
- && let trait_ref = trait_ref.instantiate_identity()
+ && let trait_ref = trait_ref.instantiate_identity().skip_norm_wip()
&& let Some(assoc_type) = trait_ref
.def_id
.0
@@ -2002,16 +2208,20 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
.associated_type_by_name(segments.first().unwrap().name)
{
// `<Self>::AssocType`
- let args = self.infcx().fill_rest_fresh_args(assoc_type.into(), trait_ref.args);
+ let args = ctx.expect_table().infer_ctxt.fill_rest_fresh_args(
+ node.into(),
+ assoc_type.into(),
+ trait_ref.args,
+ );
let alias = Ty::new_alias(
- self.interner(),
+ interner,
AliasTy::new_from_args(
- self.interner(),
+ interner,
AliasTyKind::Projection { def_id: assoc_type.into() },
args,
),
);
- ty = self.table.try_structurally_resolve_type(alias);
+ ty = ctx.expect_table().try_structurally_resolve_type(node.into(), alias);
segments = segments.skip(1);
}
@@ -2027,15 +2237,15 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
segments = segments.skip(1);
variant.into()
} else {
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
}
}
- None => return (self.err_ty(), None),
+ None => return (self.types.types.error, None),
};
if !segments.is_empty() {
// FIXME: Report an error.
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
} else {
return (ty, Some(variant));
}
@@ -2045,31 +2255,34 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
let interner = DbInterner::conjure();
let (resolution, unresolved) = if value_ns {
let Some(res) = path_ctx.resolve_path_in_value_ns(HygieneId::ROOT) else {
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
};
match res {
ResolveValueResult::ValueNs(value) => match value {
ValueNs::EnumVariantId(var) => {
- let args = path_ctx.substs_from_path(var.into(), true, false);
+ let args = path_ctx.substs_from_path(var.into(), true, false, node.into());
drop(ctx);
let ty = self
.db
.ty(var.lookup(self.db).parent.into())
- .instantiate(interner, args);
+ .instantiate(interner, args)
+ .skip_norm_wip();
let ty = self.insert_type_vars(ty);
return (ty, Some(var.into()));
}
ValueNs::StructId(strukt) => {
- let args = path_ctx.substs_from_path(strukt.into(), true, false);
+ let args =
+ path_ctx.substs_from_path(strukt.into(), true, false, node.into());
drop(ctx);
- let ty = self.db.ty(strukt.into()).instantiate(interner, args);
+ let ty =
+ self.db.ty(strukt.into()).instantiate(interner, args).skip_norm_wip();
let ty = self.insert_type_vars(ty);
return (ty, Some(strukt.into()));
}
ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
_ => {
drop(ctx);
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
}
},
ResolveValueResult::Partial(typens, unresolved) => (typens, Some(unresolved)),
@@ -2077,41 +2290,45 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
} else {
match path_ctx.resolve_path_in_type_ns() {
Some((it, idx)) => (it, idx),
- None => return (self.err_ty(), None),
+ None => return (self.types.types.error, None),
}
};
return match resolution {
TypeNs::AdtId(AdtId::StructId(strukt)) => {
- let args = path_ctx.substs_from_path(strukt.into(), true, false);
+ let args = path_ctx.substs_from_path(strukt.into(), true, false, node.into());
drop(ctx);
- let ty = self.db.ty(strukt.into()).instantiate(interner, args);
+ let ty = self.db.ty(strukt.into()).instantiate(interner, args).skip_norm_wip();
let ty = self.insert_type_vars(ty);
forbid_unresolved_segments(self, (ty, Some(strukt.into())), unresolved)
}
TypeNs::AdtId(AdtId::UnionId(u)) => {
- let args = path_ctx.substs_from_path(u.into(), true, false);
+ let args = path_ctx.substs_from_path(u.into(), true, false, node.into());
drop(ctx);
- let ty = self.db.ty(u.into()).instantiate(interner, args);
+ let ty = self.db.ty(u.into()).instantiate(interner, args).skip_norm_wip();
let ty = self.insert_type_vars(ty);
forbid_unresolved_segments(self, (ty, Some(u.into())), unresolved)
}
TypeNs::EnumVariantId(var) => {
- let args = path_ctx.substs_from_path(var.into(), true, false);
+ let args = path_ctx.substs_from_path(var.into(), true, false, node.into());
drop(ctx);
- let ty = self.db.ty(var.lookup(self.db).parent.into()).instantiate(interner, args);
+ let ty = self
+ .db
+ .ty(var.lookup(self.db).parent.into())
+ .instantiate(interner, args)
+ .skip_norm_wip();
let ty = self.insert_type_vars(ty);
forbid_unresolved_segments(self, (ty, Some(var.into())), unresolved)
}
TypeNs::SelfType(impl_id) => {
- let mut ty = self.db.impl_self_ty(impl_id).instantiate_identity();
+ let mut ty = self.db.impl_self_ty(impl_id).instantiate_identity().skip_norm_wip();
let Some(remaining_idx) = unresolved else {
drop(ctx);
let Some(mod_path) = path.mod_path() else {
never!("resolver should always resolve lang item paths");
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
};
- return self.resolve_variant_on_alias(ty, None, mod_path);
+ return self.resolve_variant_on_alias(node, ty, None, mod_path);
};
let mut remaining_segments = path.segments().skip(remaining_idx);
@@ -2127,7 +2344,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
// If we can resolve to an enum variant, it takes priority over associated type
// of the same name.
if let TyKind::Adt(adt_def, _) = ty.kind()
- && let AdtId::EnumId(id) = adt_def.def_id().0
+ && let AdtId::EnumId(id) = adt_def.def_id()
{
let enum_data = id.enum_variants(self.db);
if let Some(variant) = enum_data.variant(current_segment.name) {
@@ -2137,7 +2354,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
// We still have unresolved paths, but enum variants never have
// associated types!
// FIXME: Report an error.
- (self.err_ty(), None)
+ (self.types.types.error, None)
};
}
}
@@ -2151,12 +2368,12 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
// `lower_partly_resolved_path()` returns `None` as type namespace unless
// `remaining_segments` is empty, which is never the case here. We don't know
// which namespace the new `ty` is in until normalized anyway.
- (ty, _) = path_ctx.lower_partly_resolved_path(resolution, true);
+ (ty, _) = path_ctx.lower_partly_resolved_path(resolution, true, node.into());
tried_resolving_once = true;
- ty = self.table.process_user_written_ty(ty);
+ ty = path_ctx.expect_table().process_user_written_ty(ty);
if ty.is_ty_error() {
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
}
remaining_segments = remaining_segments.skip(1);
@@ -2175,7 +2392,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
TypeNs::TraitId(_) => {
let Some(remaining_idx) = unresolved else {
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
};
let remaining_segments = path.segments().skip(remaining_idx);
@@ -2184,8 +2401,9 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
path_ctx.ignore_last_segment();
}
- let (mut ty, _) = path_ctx.lower_partly_resolved_path(resolution, true);
- ty = self.table.process_user_written_ty(ty);
+ let (mut ty, _) =
+ path_ctx.lower_partly_resolved_path(resolution, true, node.into());
+ ty = ctx.expect_table().process_user_written_ty(ty);
if let Some(segment) = remaining_segments.get(1)
&& let Some((AdtId::EnumId(id), _)) = ty.as_adt()
@@ -2198,7 +2416,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
// We still have unresolved paths, but enum variants never have
// associated types!
// FIXME: Report an error.
- (self.err_ty(), None)
+ (self.types.types.error, None)
};
}
}
@@ -2216,27 +2434,28 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
TypeNs::TypeAliasId(it) => {
let Some(mod_path) = path.mod_path() else {
never!("resolver should always resolve lang item paths");
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
};
- let args = path_ctx.substs_from_path_segment(it.into(), true, None, false);
+ let args =
+ path_ctx.substs_from_path_segment(it.into(), true, None, false, node.into());
drop(ctx);
let interner = DbInterner::conjure();
- let ty = self.db.ty(it.into()).instantiate(interner, args);
+ let ty = self.db.ty(it.into()).instantiate(interner, args).skip_norm_wip();
let ty = self.insert_type_vars(ty);
- self.resolve_variant_on_alias(ty, unresolved, mod_path)
+ self.resolve_variant_on_alias(node, ty, unresolved, mod_path)
}
TypeNs::AdtSelfType(_) => {
// FIXME this could happen in array size expressions, once we're checking them
- (self.err_ty(), None)
+ (self.types.types.error, None)
}
TypeNs::GenericParam(_) => {
// FIXME potentially resolve assoc type
- (self.err_ty(), None)
+ (self.types.types.error, None)
}
TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::ModuleId(_) => {
// FIXME diagnostic
- (self.err_ty(), None)
+ (self.types.types.error, None)
}
};
@@ -2256,12 +2475,13 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
fn resolve_variant_on_alias(
&mut self,
+ node: ExprOrPatId,
ty: Ty<'db>,
unresolved: Option<usize>,
path: &ModPath,
) -> (Ty<'db>, Option<VariantId>) {
let remaining = unresolved.map(|it| path.segments()[it..].len()).filter(|it| it > &0);
- let ty = self.table.try_structurally_resolve_type(ty);
+ let ty = self.table.try_structurally_resolve_type(node.into(), ty);
match remaining {
None => {
let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id {
@@ -2293,19 +2513,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
}
- fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> {
- trait_.trait_items(self.db).associated_type_by_name(&Name::new_symbol_root(sym::Output))
- }
-
- fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
- let ItemContainerId::TraitId(trait_) =
- self.lang_items.IntoFutureIntoFuture?.lookup(self.db).container
- else {
- return None;
- };
- self.resolve_output_on(trait_)
- }
-
fn resolve_boxed_box(&self) -> Option<AdtId> {
let struct_ = self.lang_items.OwnedBox?;
Some(struct_.into())
@@ -2317,7 +2524,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
fn has_new_range_feature(&self) -> bool {
- self.resolver.top_level_def_map().is_unstable_feature_enabled(&sym::new_range)
+ self.features.new_range
}
fn resolve_range(&self) -> Option<AdtId> {
@@ -2374,6 +2581,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
Either::Right(&self.traits_in_scope)
}
}
+
+ fn has_applicable_non_exhaustive(&self, def: AttrDefId) -> bool {
+ AttrFlags::query(self.db, def).contains(AttrFlags::NON_EXHAUSTIVE)
+ && def.krate(self.db) != self.krate()
+ }
}
/// When inferring an expression, we propagate downward whatever type hint we
@@ -2432,7 +2644,7 @@ impl<'db> Expectation<'db> {
Expectation::None
}
- fn resolve(&self, table: &mut unify::InferenceTable<'db>) -> Expectation<'db> {
+ fn resolve(&self, table: &unify::InferenceTable<'db>) -> Expectation<'db> {
match self {
Expectation::None => Expectation::None,
Expectation::HasType(t) => Expectation::HasType(table.shallow_resolve(*t)),
@@ -2443,7 +2655,7 @@ impl<'db> Expectation<'db> {
}
}
- fn to_option(&self, table: &mut unify::InferenceTable<'db>) -> Option<Ty<'db>> {
+ fn to_option(&self, table: &unify::InferenceTable<'db>) -> Option<Ty<'db>> {
match self.resolve(table) {
Expectation::None => None,
Expectation::HasType(t)
@@ -2454,15 +2666,15 @@ impl<'db> Expectation<'db> {
fn only_has_type(&self, table: &mut unify::InferenceTable<'db>) -> Option<Ty<'db>> {
match self {
- Expectation::HasType(t) => Some(table.shallow_resolve(*t)),
+ Expectation::HasType(t) => Some(table.resolve_vars_if_possible(*t)),
Expectation::Castable(_) | Expectation::RValueLikeUnsized(_) | Expectation::None => {
None
}
}
}
- fn coercion_target_type(&self, table: &mut unify::InferenceTable<'db>) -> Ty<'db> {
- self.only_has_type(table).unwrap_or_else(|| table.next_ty_var())
+ fn coercion_target_type(&self, table: &mut unify::InferenceTable<'db>, span: Span) -> Ty<'db> {
+ self.only_has_type(table).unwrap_or_else(|| table.next_ty_var(span))
}
/// Comment copied from rustc:
@@ -2482,10 +2694,14 @@ impl<'db> Expectation<'db> {
/// 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<'db>) -> Expectation<'db> {
+ fn adjust_for_branches(
+ &self,
+ table: &mut unify::InferenceTable<'db>,
+ span: Span,
+ ) -> Expectation<'db> {
match *self {
Expectation::HasType(ety) => {
- let ety = table.structurally_resolve_type(ety);
+ let ety = table.try_structurally_resolve_type(span, ety);
if ety.is_ty_var() { Expectation::None } else { Expectation::HasType(ety) }
}
Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety),