Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22168 from ChayimFriedman2/type-must-be-known-v2
feat: Feature a "type annotations needed" diagnostic when an infer var cannot be resolved at the end of inference
Chayim Refael Friedman 4 weeks ago
parent 04ec801 · parent a8b5abd · commit 91be466
-rw-r--r--crates/hir-def/src/expr_store.rs1
-rw-r--r--crates/hir-def/src/expr_store/lower.rs10
-rw-r--r--crates/hir-def/src/expr_store/pretty.rs1
-rw-r--r--crates/hir-def/src/hir.rs3
-rw-r--r--crates/hir-ty/src/autoderef.rs4
-rw-r--r--crates/hir-ty/src/db.rs2
-rw-r--r--crates/hir-ty/src/diagnostics/unsafe_check.rs2
-rw-r--r--crates/hir-ty/src/infer.rs238
-rw-r--r--crates/hir-ty/src/infer/callee.rs67
-rw-r--r--crates/hir-ty/src/infer/closure.rs76
-rw-r--r--crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs4
-rw-r--r--crates/hir-ty/src/infer/coerce.rs35
-rw-r--r--crates/hir-ty/src/infer/expr.rs86
-rw-r--r--crates/hir-ty/src/infer/mutability.rs1
-rw-r--r--crates/hir-ty/src/infer/op.rs4
-rw-r--r--crates/hir-ty/src/infer/pat.rs30
-rw-r--r--crates/hir-ty/src/infer/path.rs27
-rw-r--r--crates/hir-ty/src/infer/place_op.rs27
-rw-r--r--crates/hir-ty/src/infer/unify.rs319
-rw-r--r--crates/hir-ty/src/lib.rs44
-rw-r--r--crates/hir-ty/src/lower.rs2
-rw-r--r--crates/hir-ty/src/lower/path.rs12
-rw-r--r--crates/hir-ty/src/method_resolution.rs26
-rw-r--r--crates/hir-ty/src/method_resolution/confirm.rs26
-rw-r--r--crates/hir-ty/src/method_resolution/probe.rs24
-rw-r--r--crates/hir-ty/src/mir/lower.rs2
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs2
-rw-r--r--crates/hir-ty/src/next_solver/format_proof_tree.rs4
-rw-r--r--crates/hir-ty/src/next_solver/fulfill.rs35
-rw-r--r--crates/hir-ty/src/next_solver/generic_arg.rs38
-rw-r--r--crates/hir-ty/src/next_solver/infer/at.rs9
-rw-r--r--crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs12
-rw-r--r--crates/hir-ty/src/next_solver/infer/canonical/mod.rs25
-rw-r--r--crates/hir-ty/src/next_solver/infer/context.rs25
-rw-r--r--crates/hir-ty/src/next_solver/infer/mod.rs202
-rw-r--r--crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs51
-rw-r--r--crates/hir-ty/src/next_solver/infer/relate/generalize.rs22
-rw-r--r--crates/hir-ty/src/next_solver/infer/relate/lattice.rs29
-rw-r--r--crates/hir-ty/src/next_solver/infer/select.rs24
-rw-r--r--crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs48
-rw-r--r--crates/hir-ty/src/next_solver/infer/traits.rs25
-rw-r--r--crates/hir-ty/src/next_solver/infer/type_variable.rs93
-rw-r--r--crates/hir-ty/src/next_solver/infer/unify_key.rs63
-rw-r--r--crates/hir-ty/src/next_solver/inspect.rs62
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs8
-rw-r--r--crates/hir-ty/src/next_solver/normalize.rs2
-rw-r--r--crates/hir-ty/src/next_solver/region.rs2
-rw-r--r--crates/hir-ty/src/next_solver/solver.rs57
-rw-r--r--crates/hir-ty/src/next_solver/structural_normalize.rs2
-rw-r--r--crates/hir-ty/src/next_solver/ty.rs69
-rw-r--r--crates/hir-ty/src/opaques.rs4
-rw-r--r--crates/hir-ty/src/specialization.rs3
-rw-r--r--crates/hir-ty/src/traits.rs3
-rw-r--r--crates/hir/src/attrs.rs2
-rw-r--r--crates/hir/src/diagnostics.rs43
-rw-r--r--crates/hir/src/lib.rs16
-rw-r--r--crates/hir/src/semantics.rs14
-rw-r--r--crates/ide-diagnostics/src/handlers/await_outside_of_async.rs3
-rw-r--r--crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs2
-rw-r--r--crates/ide-diagnostics/src/handlers/incorrect_case.rs10
-rw-r--r--crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs12
-rw-r--r--crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs2
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_fields.rs7
-rw-r--r--crates/ide-diagnostics/src/handlers/type_mismatch.rs1
-rw-r--r--crates/ide-diagnostics/src/handlers/type_must_be_known.rs79
-rw-r--r--crates/ide-diagnostics/src/handlers/typed_hole.rs2
-rw-r--r--crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs9
-rw-r--r--crates/macros/src/lib.rs14
-rw-r--r--crates/test-utils/src/minicore.rs25
69 files changed, 1451 insertions, 782 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs
index 497ed7d37f..51951896f2 100644
--- a/crates/hir-def/src/expr_store.rs
+++ b/crates/hir-def/src/expr_store.rs
@@ -561,6 +561,7 @@ impl ExpressionStore {
| Pat::ConstBlock(..)
| Pat::Wild
| Pat::Missing
+ | Pat::Rest
| Pat::Expr(_) => {}
&Pat::Bind { subpat, .. } => {
if let Some(subpat) = subpat {
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index 3440fbee6d..fd8b50d714 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -2622,15 +2622,7 @@ impl<'db> ExprCollector<'db> {
let expr_id = self.alloc_expr(expr, expr_ptr);
Pat::Lit(expr_id)
}
- ast::Pat::RestPat(_) => {
- // `RestPat` requires special handling and should not be mapped
- // to a Pat. Here we are using `Pat::Missing` as a fallback for
- // when `RestPat` is mapped to `Pat`, which can easily happen
- // when the source code being analyzed has a malformed pattern
- // which includes `..` in a place where it isn't valid.
-
- Pat::Missing
- }
+ ast::Pat::RestPat(_) => Pat::Rest,
ast::Pat::BoxPat(boxpat) => {
let inner = self.collect_pat_opt(boxpat.pat(), binding_list);
Pat::Box { inner }
diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs
index fdd0654508..bb35009f36 100644
--- a/crates/hir-def/src/expr_store/pretty.rs
+++ b/crates/hir-def/src/expr_store/pretty.rs
@@ -895,6 +895,7 @@ impl Printer<'_> {
match pat {
Pat::Missing => w!(self, "�"),
+ Pat::Rest => w!(self, ".."),
Pat::Wild => w!(self, "_"),
Pat::Tuple { args, ellipsis } => {
w!(self, "(");
diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs
index a1a346cabc..93fa7ff961 100644
--- a/crates/hir-def/src/hir.rs
+++ b/crates/hir-def/src/hir.rs
@@ -666,6 +666,8 @@ pub struct RecordFieldPat {
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Pat {
Missing,
+ /// A rest pattern. Not valid outside special context.
+ Rest,
Wild,
Tuple {
args: Box<[PatId]>,
@@ -721,6 +723,7 @@ impl Pat {
| Pat::ConstBlock(..)
| Pat::Wild
| Pat::Missing
+ | Pat::Rest
| Pat::Expr(_) => {}
Pat::Bind { subpat, .. } => {
subpat.iter().copied().for_each(f);
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index abab3bfb25..2c2400a14a 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -10,7 +10,7 @@ use rustc_type_ir::inherent::{IntoKind, Ty as _};
use tracing::debug;
use crate::{
- ParamEnvAndCrate,
+ ParamEnvAndCrate, Span,
db::HirDatabase,
infer::InferenceContext,
next_solver::{
@@ -39,7 +39,7 @@ pub fn autoderef<'db>(
) -> impl Iterator<Item = Ty<'db>> + use<'db> {
let interner = DbInterner::new_with(db, env.krate);
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
- let (ty, _) = infcx.instantiate_canonical(&ty);
+ let (ty, _) = infcx.instantiate_canonical(Span::Dummy, &ty);
let autoderef = Autoderef::new(&infcx, env.param_env, ty);
let mut v = Vec::new();
for (ty, _steps) in autoderef {
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 3bf2d9a6a6..99bad2682b 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -147,7 +147,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
#[salsa::invoke(crate::lower::const_param_ty_query)]
#[salsa::transparent]
- fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> Ty<'db>;
+ fn const_param_ty<'db>(&'db self, def: ConstParamId) -> Ty<'db>;
#[salsa::invoke(crate::lower::impl_trait_with_diagnostics)]
#[salsa::transparent]
diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs
index ee33f7d158..4893d72a5c 100644
--- a/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -258,7 +258,7 @@ impl<'db> UnsafeVisitor<'db> {
self.on_unsafe_op(current.into(), UnsafetyReason::UnionField)
}
// `Or` only wraps other patterns, and `Missing`/`Wild` do not constitute a read.
- Pat::Missing | Pat::Wild | Pat::Or(_) => {}
+ Pat::Missing | Pat::Rest | Pat::Wild | Pat::Or(_) => {}
}
}
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 8b0702c483..4aeb5ec71c 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -29,7 +29,7 @@ mod path;
mod place_op;
pub(crate) mod unify;
-use std::{cell::OnceCell, convert::identity, fmt, iter, ops::Deref};
+use std::{cell::OnceCell, convert::identity, fmt, ops::Deref};
use base_db::{Crate, FxIndexMap};
use either::Either;
@@ -50,11 +50,12 @@ use hir_def::{
use hir_expand::{mod_path::ModPath, name::Name};
use indexmap::IndexSet;
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 _},
+ inherent::{AdtDef, Const as _, IntoKind, Ty as _},
};
use smallvec::SmallVec;
use span::Edition;
@@ -62,7 +63,7 @@ use stdx::never;
use thin_vec::ThinVec;
use crate::{
- ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, TargetFeatures,
+ ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, Span, TargetFeatures,
closure_analysis::PlaceBase,
collect_type_inference_vars,
db::{HirDatabase, InternedOpaqueTyId},
@@ -76,14 +77,15 @@ use crate::{
diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext},
expr::ExprIsRead,
pat::PatOrigin,
+ unify::resolve_completely::WriteBackCtxt,
},
lower::{
ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic,
},
method_resolution::CandidateId,
next_solver::{
- AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArgs, Region, StoredGenericArgs,
- StoredTy, StoredTys, Ty, TyKind, Tys,
+ AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArgs, Region, StoredGenericArg,
+ StoredGenericArgs, StoredTy, StoredTys, Term, Ty, TyKind, Tys,
abi::Safety,
infer::{InferCtxt, ObligationInspector, traits::ObligationCause},
},
@@ -188,7 +190,7 @@ fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceRe
// 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(
+ RootExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty(
ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }),
)),
// Path const generic args: determining the expected type requires
@@ -307,107 +309,152 @@ 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,
},
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,
},
MismatchedArgCount {
+ #[type_visitable(ignore)]
call_expr: ExprId,
+ #[type_visitable(ignore)]
expected: usize,
+ #[type_visitable(ignore)]
found: usize,
},
MismatchedTupleStructPatArgCount {
+ #[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,
},
InvalidLhsOfAssignment {
+ #[type_visitable(ignore)]
lhs: ExprId,
},
TypeMustBeKnown {
- at_point: ExprOrPatId,
+ #[type_visitable(ignore)]
+ at_point: Span,
+ top_term: Option<StoredGenericArg>,
},
}
/// A mismatch between an expected and an inferred type.
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash, TypeVisitable, TypeFoldable)]
pub struct TypeMismatch {
pub expected: StoredTy,
pub actual: StoredTy,
@@ -1181,7 +1228,7 @@ pub(crate) struct InferenceContext<'body, 'db> {
deferred_call_resolutions: FxHashMap<ExprId, Vec<DeferredCallResolution<'db>>>,
diagnostics: Diagnostics,
- vars_emitted_type_must_be_known_for: FxHashSet<Ty<'db>>,
+ vars_emitted_type_must_be_known_for: FxHashSet<Term<'db>>,
}
#[derive(Clone, Debug)]
@@ -1331,14 +1378,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 {
@@ -1359,30 +1407,28 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
pat_adjustments,
binding_modes: _,
expr_adjustments,
- tuple_field_access_types: _,
+ tuple_field_access_types,
coercion_casts: _,
- diagnostics: _,
+ diagnostics: result_diagnostics,
} = &mut result;
+ 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();
@@ -1390,61 +1436,25 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
if let Some(type_mismatches) = 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();
+ resolver.resolve_type_mismatch(mismatch);
}
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 adjustments in pat_adjustments.values_mut() {
for adjustment in &mut *adjustments {
- adjustment.source = table.resolve_completely(adjustment.source.as_ref()).store();
- *has_errors = *has_errors || adjustment.source.as_ref().references_non_lt_error();
+ resolver.resolve_completely(&mut adjustment.source);
}
adjustments.shrink_to_fit();
}
@@ -1458,7 +1468,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();
@@ -1469,7 +1479,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();
@@ -1481,17 +1491,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
}
@@ -1502,6 +1513,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
&data.store,
InferenceTyDiagnosticSource::Signature,
LifetimeElisionKind::for_const(self.interner(), id.loc(self.db).container),
+ Span::Dummy,
);
self.return_ty = return_ty;
@@ -1513,6 +1525,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
&data.store,
InferenceTyDiagnosticSource::Signature,
LifetimeElisionKind::Elided(self.types.regions.statik),
+ Span::Dummy,
);
self.return_ty = return_ty;
@@ -1537,7 +1550,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(),
@@ -1545,15 +1558,16 @@ 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);
+ let ty = self.process_user_written_ty(Span::Dummy, ty);
self.write_binding_ty(self_param, ty);
}
- for (ty, pat) in param_tys.zip(params) {
- let ty = self.process_user_written_ty(ty);
+ 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(Span::Dummy, ty);
self.infer_top_pat(*pat, ty, PatOrigin::Param);
}
@@ -1568,7 +1582,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
ctx.lower_ty(return_ty)
},
);
- self.process_user_written_ty(return_ty)
+ self.process_user_written_ty(Span::Dummy, return_ty)
}
None => self.types.types.unit,
};
@@ -1602,10 +1616,10 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
/// 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();
+ 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);
+ self.vars_emitted_type_must_be_known_for.insert(var.into());
var
} else {
@@ -1613,6 +1627,10 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
}
+ pub(super) fn insert_const_vars_shallow(&mut self, c: Const<'db>) -> Const<'db> {
+ if c.is_ct_error() { self.table.next_const_var(Span::Dummy) } else { c }
+ }
+
fn infer_body(&mut self, body_expr: ExprId) {
match self.return_coercion {
Some(_) => self.infer_return(body_expr),
@@ -1746,10 +1764,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
store: &ExpressionStore,
type_source: InferenceTyDiagnosticSource,
lifetime_elision: LifetimeElisionKind<'db>,
+ span: Span,
) -> 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);
+ let ty = self.process_user_written_ty(span, 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.
@@ -1776,6 +1795,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
self.store,
InferenceTyDiagnosticSource::Body,
LifetimeElisionKind::Infer,
+ type_ref.into(),
)
}
@@ -1786,17 +1806,22 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
LifetimeElisionKind::Infer,
|ctx| ctx.lower_const(const_ref, ty),
);
- self.insert_type_vars(const_)
+ self.insert_type_vars(const_, const_ref.expr.into())
}
- pub(crate) fn make_path_as_body_const(&mut self, path: &Path, ty: Ty<'db>) -> Const<'db> {
+ pub(crate) fn make_path_as_body_const(
+ &mut self,
+ type_ref: TypeRefId,
+ path: &Path,
+ ty: Ty<'db>,
+ ) -> Const<'db> {
let const_ = self.with_ty_lowering(
self.store,
InferenceTyDiagnosticSource::Body,
LifetimeElisionKind::Infer,
|ctx| ctx.lower_path_as_const(path, ty),
);
- self.insert_type_vars(const_)
+ self.insert_type_vars(const_, type_ref.into())
}
fn err_ty(&self) -> Ty<'db> {
@@ -1810,14 +1835,14 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
LifetimeElisionKind::Infer,
|ctx| ctx.lower_lifetime(lifetime_ref),
);
- self.insert_type_vars(lt)
+ self.insert_type_vars(lt, Span::Dummy)
}
- fn insert_type_vars<T>(&mut self, ty: T) -> T
+ fn insert_type_vars<T>(&mut self, ty: T, span: Span) -> T
where
T: TypeFoldable<DbInterner<'db>>,
{
- self.table.insert_type_vars(ty)
+ self.table.insert_type_vars(ty, span)
}
/// Attempts to returns the deeply last field of nested structures, but
@@ -1882,8 +1907,8 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
/// Whenever you lower a user-written type, you should call this.
- fn process_user_written_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
- self.table.process_user_written_ty(ty)
+ fn process_user_written_ty(&mut self, span: Span, ty: Ty<'db>) -> Ty<'db> {
+ self.table.process_user_written_ty(span, ty)
}
/// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation,
@@ -1974,8 +1999,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
node: ExprOrPatId,
ty: Ty<'db>,
) -> Ty<'db> {
- if self.vars_emitted_type_must_be_known_for.insert(ty) {
- self.push_diagnostic(InferenceDiagnostic::TypeMustBeKnown { at_point: node });
+ 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
}
@@ -2024,7 +2052,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
return (self.err_ty(), None);
}
let (mut ty, type_ns) = ctx.lower_ty_ext(type_anchor);
- ty = self.table.process_user_written_ty(ty);
+ ty = self.table.process_user_written_ty(type_anchor.into(), ty);
if let Some(TypeNs::SelfType(impl_)) = type_ns
&& let Some(trait_ref) = self.db.impl_trait(impl_)
@@ -2036,7 +2064,11 @@ 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 = self.infcx().fill_rest_fresh_args(
+ node.into(),
+ assoc_type.into(),
+ trait_ref.args,
+ );
let alias = Ty::new_alias(
self.interner(),
AliasTy::new_from_args(
@@ -2090,14 +2122,14 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
.db
.ty(var.lookup(self.db).parent.into())
.instantiate(interner, args);
- let ty = self.insert_type_vars(ty);
+ let ty = self.insert_type_vars(ty, Span::Dummy);
return (ty, Some(var.into()));
}
ValueNs::StructId(strukt) => {
let args = path_ctx.substs_from_path(strukt.into(), true, false);
drop(ctx);
let ty = self.db.ty(strukt.into()).instantiate(interner, args);
- let ty = self.insert_type_vars(ty);
+ let ty = self.insert_type_vars(ty, Span::Dummy);
return (ty, Some(strukt.into()));
}
ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
@@ -2119,21 +2151,21 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
let args = path_ctx.substs_from_path(strukt.into(), true, false);
drop(ctx);
let ty = self.db.ty(strukt.into()).instantiate(interner, args);
- let ty = self.insert_type_vars(ty);
+ let ty = self.insert_type_vars(ty, Span::Dummy);
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);
drop(ctx);
let ty = self.db.ty(u.into()).instantiate(interner, args);
- let ty = self.insert_type_vars(ty);
+ let ty = self.insert_type_vars(ty, Span::Dummy);
forbid_unresolved_segments(self, (ty, Some(u.into())), unresolved)
}
TypeNs::EnumVariantId(var) => {
let args = path_ctx.substs_from_path(var.into(), true, false);
drop(ctx);
let ty = self.db.ty(var.lookup(self.db).parent.into()).instantiate(interner, args);
- let ty = self.insert_type_vars(ty);
+ let ty = self.insert_type_vars(ty, Span::Dummy);
forbid_unresolved_segments(self, (ty, Some(var.into())), unresolved)
}
TypeNs::SelfType(impl_id) => {
@@ -2188,7 +2220,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
(ty, _) = path_ctx.lower_partly_resolved_path(resolution, true);
tried_resolving_once = true;
- ty = self.table.process_user_written_ty(ty);
+ ty = self.table.process_user_written_ty(node.into(), ty);
if ty.is_ty_error() {
return (self.err_ty(), None);
}
@@ -2219,7 +2251,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
let (mut ty, _) = path_ctx.lower_partly_resolved_path(resolution, true);
- ty = self.table.process_user_written_ty(ty);
+ ty = self.table.process_user_written_ty(node.into(), ty);
if let Some(segment) = remaining_segments.get(1)
&& let Some((AdtId::EnumId(id), _)) = ty.as_adt()
@@ -2256,7 +2288,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
drop(ctx);
let interner = DbInterner::conjure();
let ty = self.db.ty(it.into()).instantiate(interner, args);
- let ty = self.insert_type_vars(ty);
+ let ty = self.insert_type_vars(ty, Span::Dummy);
self.resolve_variant_on_alias(ty, unresolved, mod_path)
}
@@ -2487,8 +2519,8 @@ impl<'db> Expectation<'db> {
}
}
- 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:
diff --git a/crates/hir-ty/src/infer/callee.rs b/crates/hir-ty/src/infer/callee.rs
index a470c92124..ffdde58c48 100644
--- a/crates/hir-ty/src/infer/callee.rs
+++ b/crates/hir-ty/src/infer/callee.rs
@@ -5,7 +5,9 @@ use std::iter;
use intern::sym;
use tracing::debug;
-use hir_def::{CallableDefId, hir::ExprId, signatures::FunctionSignature};
+use hir_def::{
+ CallableDefId, ConstParamId, TypeOrConstParamId, hir::ExprId, signatures::FunctionSignature,
+};
use rustc_type_ir::{
InferTy, Interner,
inherent::{GenericArgs as _, IntoKind, Ty as _},
@@ -20,7 +22,7 @@ use crate::{
},
method_resolution::{MethodCallee, TreatNotYetDefinedOpaques},
next_solver::{
- FnSig, Ty, TyKind,
+ ConstKind, FnSig, Ty, TyKind,
infer::{BoundRegionConversionTime, traits::ObligationCause},
},
};
@@ -82,7 +84,7 @@ impl<'db> InferenceContext<'_, 'db> {
}
Some(CallStep::Builtin(callee_ty)) => {
- self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected)
+ self.confirm_builtin_call(callee_expr, call_expr, callee_ty, arg_exprs, expected)
}
Some(CallStep::DeferredClosure(_def_id, fn_sig)) => {
@@ -128,6 +130,7 @@ impl<'db> InferenceContext<'_, 'db> {
{
let closure_sig = args.as_closure().sig();
let closure_sig = autoderef.ctx().infcx().instantiate_binder_with_fresh_vars(
+ callee_expr.into(),
BoundRegionConversionTime::FnCall,
closure_sig,
);
@@ -158,15 +161,16 @@ impl<'db> InferenceContext<'_, 'db> {
let closure_args = args.as_coroutine_closure();
let coroutine_closure_sig =
autoderef.ctx().infcx().instantiate_binder_with_fresh_vars(
+ callee_expr.into(),
BoundRegionConversionTime::FnCall,
closure_args.coroutine_closure_sig(),
);
- let tupled_upvars_ty = autoderef.ctx().table.next_ty_var();
+ let tupled_upvars_ty = autoderef.ctx().table.next_ty_var(call_expr.into());
// We may actually receive a coroutine back whose kind is different
// from the closure that this dispatched from. This is because when
// we have no captures, we automatically implement `FnOnce`. This
// impl forces the closure kind to `FnOnce` i.e. `u8`.
- let kind_ty = autoderef.ctx().table.next_ty_var();
+ let kind_ty = autoderef.ctx().table.next_ty_var(call_expr.into());
let interner = autoderef.ctx().interner();
let call_sig = interner.mk_fn_sig(
[coroutine_closure_sig.tupled_inputs_ty],
@@ -297,7 +301,7 @@ impl<'db> InferenceContext<'_, 'db> {
let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
Ty::new_tup_from_iter(
self.interner(),
- arg_exprs.iter().map(|_| self.table.next_ty_var()),
+ arg_exprs.iter().map(|&arg| self.table.next_ty_var(arg.into())),
)
});
@@ -347,12 +351,26 @@ impl<'db> InferenceContext<'_, 'db> {
fn check_legacy_const_generics(
&mut self,
callee: Option<CallableDefId>,
+ callee_ty: Ty<'db>,
args: &[ExprId],
) -> Box<[u32]> {
- let func = match callee {
- Some(CallableDefId::FunctionId(func)) => func,
+ let (func, fn_generic_args) = match (callee, callee_ty.kind()) {
+ (Some(CallableDefId::FunctionId(func)), TyKind::FnDef(_, fn_generic_args)) => {
+ (func, fn_generic_args)
+ }
_ => return Default::default(),
};
+ let generics = crate::generics::generics(self.db, func.into());
+ let const_params = generics
+ .iter_self_type_or_consts()
+ .filter(|(_, param_data)| param_data.const_param().is_some())
+ .map(|(idx, _)| {
+ ConstParamId::from_unchecked(TypeOrConstParamId {
+ parent: func.into(),
+ local_id: idx,
+ })
+ })
+ .collect::<Vec<_>>();
let data = FunctionSignature::of(self.db, func);
let Some(legacy_const_generics_indices) = data.legacy_const_generics_indices(self.db, func)
@@ -374,11 +392,29 @@ impl<'db> InferenceContext<'_, 'db> {
}
// check legacy const parameters
- for arg_idx in legacy_const_generics_indices.iter().copied() {
+ for (const_idx, arg_idx) in legacy_const_generics_indices.iter().copied().enumerate() {
if arg_idx >= args.len() as u32 {
continue;
}
- let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly
+
+ if let Some(const_arg) = fn_generic_args.get(const_idx).and_then(|it| it.konst())
+ && let ConstKind::Infer(_) = const_arg.kind()
+ {
+ // Instantiate the generic arg with an error type, to prevent errors from it.
+ // FIXME: Actually lower the expression as const.
+ _ = self
+ .table
+ .at(&ObligationCause::dummy())
+ .eq(self.types.consts.error, const_arg)
+ .map(|infer_ok| self.table.register_infer_ok(infer_ok));
+ }
+
+ let expected = if let Some(&const_param) = const_params.get(const_idx) {
+ Expectation::has_type(self.db.const_param_ty(const_param))
+ } else {
+ Expectation::None
+ };
+
self.infer_expr(args[arg_idx as usize], &expected, ExprIsRead::Yes);
// FIXME: evaluate and unify with the const
}
@@ -388,6 +424,7 @@ impl<'db> InferenceContext<'_, 'db> {
fn confirm_builtin_call(
&mut self,
+ callee_expr: ExprId,
call_expr: ExprId,
callee_ty: Ty<'db>,
arg_exprs: &[ExprId],
@@ -411,11 +448,13 @@ impl<'db> InferenceContext<'_, 'db> {
// renormalize the associated types at this point, since they
// previously appeared within a `Binder<>` and hence would not
// have been normalized before.
- let fn_sig = self
- .infcx()
- .instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, fn_sig);
+ let fn_sig = self.infcx().instantiate_binder_with_fresh_vars(
+ callee_expr.into(),
+ BoundRegionConversionTime::FnCall,
+ fn_sig,
+ );
- let indices_to_skip = self.check_legacy_const_generics(def_id, arg_exprs);
+ let indices_to_skip = self.check_legacy_const_generics(def_id, callee_ty, arg_exprs);
self.check_call_arguments(
call_expr,
fn_sig.inputs(),
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index a53ab7daaa..93c98f2542 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -65,19 +65,19 @@ impl<'db> InferenceContext<'_, 'db> {
let (expected_sig, expected_kind) = match expected.to_option(&mut self.table) {
Some(ty) => {
let ty = self.table.try_structurally_resolve_type(ty);
- self.deduce_closure_signature(ty, closure_kind)
+ self.deduce_closure_signature(closure_expr, ty, closure_kind)
}
None => (None, None),
};
let ClosureSignatures { bound_sig, mut liberated_sig } =
- self.sig_of_closure(arg_types, ret_type, expected_sig);
+ self.sig_of_closure(closure_expr, arg_types, ret_type, expected_sig);
debug!(?bound_sig, ?liberated_sig);
let parent_args = GenericArgs::identity_for_item(interner, self.generic_def.into());
- let tupled_upvars_ty = self.table.next_ty_var();
+ let tupled_upvars_ty = self.table.next_ty_var(closure_expr.into());
// FIXME: We could probably actually just unify this further --
// instead of having a `FnSig` and a `Option<CoroutineTypes>`,
@@ -103,7 +103,7 @@ impl<'db> InferenceContext<'_, 'db> {
Some(kind) => Ty::from_closure_kind(interner, kind),
// Create a type variable (for now) to represent the closure kind.
// It will be unified during the upvar inference phase (`upvar.rs`)
- None => self.table.next_ty_var(),
+ None => self.table.next_ty_var(closure_expr.into()),
};
let closure_args = ClosureArgs::new(
@@ -123,7 +123,7 @@ impl<'db> InferenceContext<'_, 'db> {
}
ClosureKind::Coroutine(_) | ClosureKind::AsyncBlock { .. } => {
let yield_ty = match closure_kind {
- ClosureKind::Coroutine(_) => self.table.next_ty_var(),
+ ClosureKind::Coroutine(_) => self.table.next_ty_var(closure_expr.into()),
ClosureKind::AsyncBlock { .. } => self.types.types.unit,
_ => unreachable!(),
};
@@ -138,7 +138,7 @@ impl<'db> InferenceContext<'_, 'db> {
// ty of `().`
let kind_ty = match closure_kind {
ClosureKind::AsyncBlock { source: CoroutineSource::Closure } => {
- self.table.next_ty_var()
+ self.table.next_ty_var(closure_expr.into())
}
_ => self.types.types.unit,
};
@@ -169,17 +169,17 @@ impl<'db> InferenceContext<'_, 'db> {
let (bound_return_ty, bound_yield_ty) =
(bound_sig.skip_binder().output(), self.types.types.unit);
// Compute all of the variables that will be used to populate the coroutine.
- let resume_ty = self.table.next_ty_var();
+ let resume_ty = self.table.next_ty_var(closure_expr.into());
let closure_kind_ty = match expected_kind {
Some(kind) => Ty::from_closure_kind(interner, kind),
// Create a type variable (for now) to represent the closure kind.
// It will be unified during the upvar inference phase (`upvar.rs`)
- None => self.table.next_ty_var(),
+ None => self.table.next_ty_var(closure_expr.into()),
};
- let coroutine_captures_by_ref_ty = self.table.next_ty_var();
+ let coroutine_captures_by_ref_ty = self.table.next_ty_var(closure_expr.into());
let closure_args = CoroutineClosureArgs::new(
interner,
@@ -214,10 +214,10 @@ impl<'db> InferenceContext<'_, 'db> {
// Create a type variable (for now) to represent the closure kind.
// It will be unified during the upvar inference phase (`upvar.rs`)
- None => self.table.next_ty_var(),
+ None => self.table.next_ty_var(closure_expr.into()),
};
- let coroutine_upvars_ty = self.table.next_ty_var();
+ let coroutine_upvars_ty = self.table.next_ty_var(closure_expr.into());
let coroutine_closure_id = InternedCoroutineClosureId::new(
self.db,
@@ -316,12 +316,14 @@ impl<'db> InferenceContext<'_, 'db> {
/// are about to type check:
fn deduce_closure_signature(
&mut self,
+ closure_expr: ExprId,
expected_ty: Ty<'db>,
closure_kind: ClosureKind,
) -> (Option<PolyFnSig<'db>>, Option<rustc_type_ir::ClosureKind>) {
match expected_ty.kind() {
TyKind::Alias(AliasTy { kind: rustc_type_ir::Opaque { def_id }, args, .. }) => self
.deduce_closure_signature_from_predicates(
+ closure_expr,
expected_ty,
closure_kind,
def_id
@@ -333,7 +335,7 @@ impl<'db> InferenceContext<'_, 'db> {
TyKind::Dynamic(object_type, ..) => {
let sig = object_type.projection_bounds().into_iter().find_map(|pb| {
let pb = pb.with_self_ty(self.interner(), Ty::new_unit(self.interner()));
- self.deduce_sig_from_projection(closure_kind, pb)
+ self.deduce_sig_from_projection(closure_expr, closure_kind, pb)
});
let kind = object_type
.principal_def_id()
@@ -342,6 +344,7 @@ impl<'db> InferenceContext<'_, 'db> {
}
TyKind::Infer(rustc_type_ir::TyVar(vid)) => self
.deduce_closure_signature_from_predicates(
+ closure_expr,
Ty::new_var(self.interner(), self.table.infer_ctxt.root_var(vid)),
closure_kind,
self.table.obligations_for_self_ty(vid).into_iter().map(|obl| obl.predicate),
@@ -361,6 +364,7 @@ impl<'db> InferenceContext<'_, 'db> {
fn deduce_closure_signature_from_predicates(
&mut self,
+ closure_expr: ExprId,
expected_ty: Ty<'db>,
closure_kind: ClosureKind,
predicates: impl DoubleEndedIterator<Item = Predicate<'db>>,
@@ -388,6 +392,7 @@ impl<'db> InferenceContext<'_, 'db> {
bound_predicate.skip_binder()
{
let inferred_sig = self.deduce_sig_from_projection(
+ closure_expr,
closure_kind,
bound_predicate.rebind(proj_predicate),
);
@@ -430,7 +435,7 @@ impl<'db> InferenceContext<'_, 'db> {
// This is a bit weird and means we may wind up discarding the goal due to it naming `expected_ty`
// even though the normalized form may not name `expected_ty`. However, this matches the existing
// behaviour of the old solver and would be technically a breaking change to fix.
- let generalized_fnptr_sig = self.table.next_ty_var();
+ let generalized_fnptr_sig = self.table.next_ty_var(closure_expr.into());
let inferred_fnptr_sig = Ty::new_fn_ptr(self.interner(), inferred_sig);
// FIXME: Report diagnostics.
_ = self
@@ -500,6 +505,7 @@ impl<'db> InferenceContext<'_, 'db> {
/// know that.
fn deduce_sig_from_projection(
&mut self,
+ closure_expr: ExprId,
closure_kind: ClosureKind,
projection: PolyProjectionPredicate<'db>,
) -> Option<PolyFnSig<'db>> {
@@ -518,7 +524,7 @@ impl<'db> InferenceContext<'_, 'db> {
// `F: FnOnce() -> Fut, Fut: Future<Output = T>` style bound. Let's still
// guide inference here, since it's beneficial for the user.
ClosureKind::AsyncClosure if Some(def_id) == self.lang_items.FnOnceOutput => {
- self.extract_sig_from_projection_and_future_bound(projection)
+ self.extract_sig_from_projection_and_future_bound(closure_expr, projection)
}
_ => None,
}
@@ -573,6 +579,7 @@ impl<'db> InferenceContext<'_, 'db> {
/// projection, and the output will be an unconstrained type variable instead.
fn extract_sig_from_projection_and_future_bound(
&mut self,
+ closure_expr: ExprId,
projection: PolyProjectionPredicate<'db>,
) -> Option<PolyFnSig<'db>> {
let projection = self.resolve_vars_if_possible(projection);
@@ -624,7 +631,7 @@ impl<'db> InferenceContext<'_, 'db> {
//
// FIXME: We probably should store this signature inference output in a way
// that does not misuse a `FnSig` type, but that can be done separately.
- let return_ty = return_ty.unwrap_or_else(|| self.table.next_ty_var());
+ let return_ty = return_ty.unwrap_or_else(|| self.table.next_ty_var(closure_expr.into()));
let sig = projection.rebind(self.interner().mk_fn_sig_safe_rust_abi(input_tys, return_ty));
@@ -633,14 +640,15 @@ impl<'db> InferenceContext<'_, 'db> {
fn sig_of_closure(
&mut self,
+ closure_expr: ExprId,
decl_inputs: &[Option<TypeRefId>],
decl_output: Option<TypeRefId>,
expected_sig: Option<PolyFnSig<'db>>,
) -> ClosureSignatures<'db> {
if let Some(e) = expected_sig {
- self.sig_of_closure_with_expectation(decl_inputs, decl_output, e)
+ self.sig_of_closure_with_expectation(closure_expr, decl_inputs, decl_output, e)
} else {
- self.sig_of_closure_no_expectation(decl_inputs, decl_output)
+ self.sig_of_closure_no_expectation(closure_expr, decl_inputs, decl_output)
}
}
@@ -648,10 +656,11 @@ impl<'db> InferenceContext<'_, 'db> {
/// types that the user gave into a signature.
fn sig_of_closure_no_expectation(
&mut self,
+ closure_expr: ExprId,
decl_inputs: &[Option<TypeRefId>],
decl_output: Option<TypeRefId>,
) -> ClosureSignatures<'db> {
- let bound_sig = self.supplied_sig_of_closure(decl_inputs, decl_output);
+ let bound_sig = self.supplied_sig_of_closure(closure_expr, decl_inputs, decl_output);
self.closure_sigs(bound_sig)
}
@@ -705,6 +714,7 @@ impl<'db> InferenceContext<'_, 'db> {
/// regions with depth 1, which are bound then by the closure.
fn sig_of_closure_with_expectation(
&mut self,
+ closure_expr: ExprId,
decl_inputs: &[Option<TypeRefId>],
decl_output: Option<TypeRefId>,
expected_sig: PolyFnSig<'db>,
@@ -713,7 +723,7 @@ impl<'db> InferenceContext<'_, 'db> {
// expectation if things don't see to match up with what we
// expect.
if expected_sig.c_variadic() {
- return self.sig_of_closure_no_expectation(decl_inputs, decl_output);
+ return self.sig_of_closure_no_expectation(closure_expr, decl_inputs, decl_output);
} else if expected_sig.skip_binder().inputs_and_output.len() != decl_inputs.len() + 1 {
return self
.sig_of_closure_with_mismatched_number_of_arguments(decl_inputs, decl_output);
@@ -745,9 +755,14 @@ impl<'db> InferenceContext<'_, 'db> {
// Along the way, it also writes out entries for types that the user
// wrote into our typeck results, which are then later used by the privacy
// check.
- match self.merge_supplied_sig_with_expectation(decl_inputs, decl_output, closure_sigs) {
+ match self.merge_supplied_sig_with_expectation(
+ closure_expr,
+ decl_inputs,
+ decl_output,
+ closure_sigs,
+ ) {
Ok(infer_ok) => self.table.register_infer_ok(infer_ok),
- Err(_) => self.sig_of_closure_no_expectation(decl_inputs, decl_output),
+ Err(_) => self.sig_of_closure_no_expectation(closure_expr, decl_inputs, decl_output),
}
}
@@ -766,6 +781,7 @@ impl<'db> InferenceContext<'_, 'db> {
/// strategy.
fn merge_supplied_sig_with_expectation(
&mut self,
+ closure_expr: ExprId,
decl_inputs: &[Option<TypeRefId>],
decl_output: Option<TypeRefId>,
mut expected_sigs: ClosureSignatures<'db>,
@@ -774,7 +790,7 @@ impl<'db> InferenceContext<'_, 'db> {
//
// (See comment on `sig_of_closure_with_expectation` for the
// meaning of these letters.)
- let supplied_sig = self.supplied_sig_of_closure(decl_inputs, decl_output);
+ let supplied_sig = self.supplied_sig_of_closure(closure_expr, decl_inputs, decl_output);
debug!(?supplied_sig);
@@ -795,6 +811,7 @@ impl<'db> InferenceContext<'_, 'db> {
self.table.commit_if_ok(|table| {
let mut all_obligations = PredicateObligations::new();
let supplied_sig = table.infer_ctxt.instantiate_binder_with_fresh_vars(
+ closure_expr.into(),
BoundRegionConversionTime::FnCall,
supplied_sig,
);
@@ -842,25 +859,20 @@ impl<'db> InferenceContext<'_, 'db> {
/// Also, record this closure signature for later.
fn supplied_sig_of_closure(
&mut self,
+ closure_expr: ExprId,
decl_inputs: &[Option<TypeRefId>],
decl_output: Option<TypeRefId>,
) -> PolyFnSig<'db> {
let interner = self.interner();
let supplied_return = match decl_output {
- Some(output) => {
- let output = self.make_body_ty(output);
- self.process_user_written_ty(output)
- }
- None => self.table.next_ty_var(),
+ Some(output) => self.make_body_ty(output),
+ None => self.table.next_ty_var(closure_expr.into()),
};
// First, convert the types that the user supplied (if any).
let supplied_arguments = decl_inputs.iter().map(|&input| match input {
- Some(input) => {
- let input = self.make_body_ty(input);
- self.process_user_written_ty(input)
- }
- None => self.table.next_ty_var(),
+ Some(input) => self.make_body_ty(input),
+ None => self.table.next_ty_var(closure_expr.into()),
});
Binder::dummy(interner.mk_fn_sig(
diff --git a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs
index f140b12491..0fd3cda31d 100644
--- a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs
+++ b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs
@@ -1026,7 +1026,8 @@ impl<'a, 'b, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'b, 'db, D> {
| Pat::Ref { .. }
| Pat::Tuple { .. }
| Pat::Wild
- | Pat::Missing => {
+ | Pat::Missing
+ | Pat::Rest => {
// If the PatKind is Or, Box, Ref, Guard, or Tuple, the relevant accesses
// are made later as these patterns contains subpatterns.
// If the PatKind is Missing, Wild or Err, any relevant accesses are made when processing
@@ -1671,6 +1672,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> {
| Pat::ConstBlock(..)
| Pat::Range { .. }
| Pat::Missing
+ | Pat::Rest
| Pat::Wild => {
// always ok
}
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index 962fc752a5..55e02a6933 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -52,7 +52,7 @@ use smallvec::SmallVec;
use tracing::{debug, instrument};
use crate::{
- Adjust, Adjustment, AutoBorrow, ParamEnvAndCrate, PointerCast, TargetFeatures,
+ Adjust, Adjustment, AutoBorrow, ParamEnvAndCrate, PointerCast, Span, TargetFeatures,
autoderef::Autoderef,
db::{HirDatabase, InternedClosure, InternedClosureId},
infer::{
@@ -316,7 +316,8 @@ where
if b.is_infer() {
// Two unresolved type variables: create a `Coerce` predicate.
- let target_ty = if self.use_lub { self.infcx().next_ty_var() } else { b };
+ let target_ty =
+ if self.use_lub { self.infcx().next_ty_var(self.cause.span()) } else { b };
let mut obligations = PredicateObligations::with_capacity(2);
for &source_ty in &[a, b] {
@@ -463,7 +464,7 @@ where
} else {
if r_borrow_var.is_none() {
// create var lazily, at most once
- let r = self.infcx().next_region_var();
+ let r = self.infcx().next_region_var(self.cause.span());
r_borrow_var = Some(r); // [4] above
}
r_borrow_var.unwrap()
@@ -624,7 +625,7 @@ where
(TyKind::Ref(_, ty_a, mutbl_a), TyKind::Ref(_, _, mutbl_b)) => {
coerce_mutbls(mutbl_a, mutbl_b)?;
- let r_borrow = self.infcx().next_region_var();
+ let r_borrow = self.infcx().next_region_var(self.cause.span());
// We don't allow two-phase borrows here, at least for initial
// implementation. If it happens that this coercion is a function argument,
@@ -658,7 +659,7 @@ where
// the `CoerceUnsized` target type and the expected type.
// We only have the latter, so we use an inference variable
// for the former and let type inference do the rest.
- let coerce_target = self.infcx().next_ty_var();
+ let coerce_target = self.infcx().next_ty_var(self.cause.span());
let mut coercion = self.unify_and(
coerce_target,
@@ -688,6 +689,7 @@ where
errored: false,
unsize_did,
coerce_unsized_did,
+ span: self.cause.span(),
},
)
.is_break()
@@ -899,7 +901,7 @@ impl<'db> InferenceContext<'_, 'db> {
target = self.table.try_structurally_resolve_type(target);
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
- let cause = ObligationCause::new();
+ let cause = ObligationCause::with_span(expr.into());
let coerce_never = self.expr_guaranteed_to_constitute_read_for_never(expr, expr_is_read);
let mut coerce = Coerce {
delegate: InferenceCoercionDelegate(self),
@@ -974,8 +976,12 @@ impl<'db> InferenceContext<'_, 'db> {
match self.table.commit_if_ok(|table| {
// We need to eagerly handle nested obligations due to lazy norm.
let mut ocx = ObligationCtxt::new(&table.infer_ctxt);
- let value =
- ocx.lub(&ObligationCause::new(), table.param_env, prev_ty, new_ty)?;
+ let value = ocx.lub(
+ &ObligationCause::with_span(new.into()),
+ table.param_env,
+ prev_ty,
+ new_ty,
+ )?;
if ocx.try_evaluate_obligations().is_empty() {
Ok(InferOk { value, obligations: ocx.into_pending_obligations() })
} else {
@@ -1023,7 +1029,7 @@ impl<'db> InferenceContext<'_, 'db> {
let sig = self
.table
.infer_ctxt
- .at(&ObligationCause::new(), self.table.param_env)
+ .at(&ObligationCause::with_span(new.into()), self.table.param_env)
.lub(a_sig, b_sig)
.map(|ok| self.table.register_infer_ok(ok))?;
@@ -1069,7 +1075,7 @@ impl<'db> InferenceContext<'_, 'db> {
// operate on values and not places, so a never coercion is valid.
let mut coerce = Coerce {
delegate: InferenceCoercionDelegate(self),
- cause: ObligationCause::new(),
+ cause: ObligationCause::with_span(new.into()),
allow_two_phase: AllowTwoPhase::No,
coerce_never: true,
use_lub: true,
@@ -1105,7 +1111,7 @@ impl<'db> InferenceContext<'_, 'db> {
.commit_if_ok(|table| {
table
.infer_ctxt
- .at(&ObligationCause::new(), table.param_env)
+ .at(&ObligationCause::with_span(new.into()), table.param_env)
.lub(prev_ty, new_ty)
})
.unwrap_err())
@@ -1451,7 +1457,7 @@ fn coerce<'db>(
) -> Result<(Vec<Adjustment>, Ty<'db>), TypeError<DbInterner<'db>>> {
let interner = DbInterner::new_with(db, env.krate);
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
- let ((ty1_with_vars, ty2_with_vars), vars) = infcx.instantiate_canonical(tys);
+ let ((ty1_with_vars, ty2_with_vars), vars) = infcx.instantiate_canonical(Span::Dummy, tys);
let cause = ObligationCause::new();
// FIXME: Target features.
@@ -1611,11 +1617,16 @@ struct CoerceVisitor<'a, D> {
errored: bool,
unsize_did: TraitId,
coerce_unsized_did: TraitId,
+ span: Span,
}
impl<'a, 'db, D: CoerceDelegate<'db>> ProofTreeVisitor<'db> for CoerceVisitor<'a, D> {
type Result = ControlFlow<()>;
+ fn span(&self) -> Span {
+ self.span
+ }
+
fn visit_goal(&mut self, goal: &InspectGoal<'_, 'db>) -> Self::Result {
let Some(pred) = goal.goal().predicate.as_trait_clause() else {
return ControlFlow::Continue(());
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index e179ca4bd3..a6c8cda404 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -27,7 +27,7 @@ use syntax::ast::RangeOp;
use tracing::debug;
use crate::{
- Adjust, Adjustment, CallableDefId, Rawness, consteval,
+ Adjust, Adjustment, CallableDefId, Rawness, Span, consteval,
infer::{AllowTwoPhase, BreakableKind, coerce::CoerceMany, find_continuable, pat::PatOrigin},
lower::lower_mutability,
method_resolution::{self, CandidateId, MethodCallee, MethodError},
@@ -176,7 +176,7 @@ impl<'db> InferenceContext<'_, 'db> {
fn pat_guaranteed_to_constitute_read_for_never(&self, pat: PatId) -> bool {
match &self.store[pat] {
// Does not constitute a read.
- Pat::Wild => false,
+ Pat::Wild | Pat::Rest => false,
// This is unnecessarily restrictive when the pattern that doesn't
// constitute a read is unreachable.
@@ -343,7 +343,7 @@ impl<'db> InferenceContext<'_, 'db> {
coercion_sites[1] = else_branch;
}
let mut coerce = CoerceMany::with_coercion_sites(
- expected.coercion_target_type(&mut self.table),
+ expected.coercion_target_type(&mut self.table, then_branch.into()),
&coercion_sites,
);
coerce.coerce(self, &ObligationCause::new(), then_branch, then_ty, ExprIsRead::Yes);
@@ -397,7 +397,7 @@ impl<'db> InferenceContext<'_, 'db> {
.1
}
&Expr::Loop { body, label } => {
- let ty = expected.coercion_target_type(&mut self.table);
+ let ty = expected.coercion_target_type(&mut self.table, tgt_expr.into());
let (breaks, ()) =
self.with_breakable_ctx(BreakableKind::Loop, Some(ty), label, |this| {
this.infer_expr(
@@ -466,7 +466,7 @@ impl<'db> InferenceContext<'_, 'db> {
// We don't coerce to `()` so that if the match expression is a
// statement it's branches can have any consistent type.
Expectation::HasType(ty) if *ty != self.types.types.unit => *ty,
- _ => self.table.next_ty_var(),
+ _ => self.table.next_ty_var((*expr).into()),
};
let mut coerce = CoerceMany::new(result_ty);
@@ -629,7 +629,7 @@ impl<'db> InferenceContext<'_, 'db> {
match rawness {
Rawness::RawPtr => Ty::new_ptr(self.interner(), inner_ty, mutability),
Rawness::Ref => {
- let lt = self.table.next_region_var();
+ let lt = self.table.next_region_var(tgt_expr.into());
Ty::new_ref(self.interner(), lt, inner_ty, mutability)
}
}
@@ -675,7 +675,7 @@ impl<'db> InferenceContext<'_, 'db> {
// However, rustc lowers destructuring assignments into blocks, and blocks return `!` if they have no tail
// expression and they diverge. Therefore, we have to do the same here, even though we don't lower destructuring
// assignments into blocks.
- self.table.new_maybe_never_var()
+ self.table.new_maybe_never_var(value.into())
} else {
self.types.types.unit
}
@@ -731,7 +731,7 @@ impl<'db> InferenceContext<'_, 'db> {
let idx_t = self.infer_expr_no_expect(*index, ExprIsRead::Yes);
let base_t = self.structurally_resolve_type((*base).into(), base_t);
- match self.lookup_indexing(tgt_expr, *base, base_t, idx_t) {
+ match self.lookup_indexing(tgt_expr, *base, *index, base_t, idx_t) {
Some((trait_index_ty, trait_element_ty)) => {
// two-phase not needed because index_ty is never mutable
self.demand_coerce(
@@ -755,10 +755,10 @@ impl<'db> InferenceContext<'_, 'db> {
{
Some(TyKind::Tuple(substs)) => substs
.iter()
- .chain(repeat_with(|| self.table.next_ty_var()))
+ .chain(repeat_with(|| self.table.next_ty_var(Span::Dummy)))
.take(exprs.len())
.collect::<Vec<_>>(),
- _ => (0..exprs.len()).map(|_| self.table.next_ty_var()).collect(),
+ _ => exprs.iter().map(|&expr| self.table.next_ty_var(expr.into())).collect(),
};
for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
@@ -768,7 +768,7 @@ impl<'db> InferenceContext<'_, 'db> {
Ty::new_tup(self.interner(), &tys)
}
- Expr::Array(array) => self.infer_expr_array(array, expected),
+ Expr::Array(array) => self.infer_expr_array(tgt_expr, array, expected),
Expr::Literal(lit) => match lit {
Literal::Bool(..) => self.types.types.bool,
Literal::String(..) => self.types.types.static_str_ref,
@@ -1119,7 +1119,7 @@ impl<'db> InferenceContext<'_, 'db> {
if self.features.type_changing_struct_update {
if matches!(adt_id, AdtId::StructId(_)) {
// Make some fresh generic parameters for our ADT type.
- let fresh_args = self.table.fresh_args_for_item(adt_id.into());
+ let fresh_args = self.table.fresh_args_for_item(expr.into(), adt_id.into());
// We do subtyping on the FRU fields first, so we can
// learn exactly what types we expect the base expr
// needs constrained to be compatible with the struct
@@ -1266,7 +1266,7 @@ impl<'db> InferenceContext<'_, 'db> {
// ...but otherwise we want to use any supertype of the
// scrutinee. This is sort of a workaround, see note (*) in
// `check_pat` for some details.
- let scrut_ty = self.table.next_ty_var();
+ let scrut_ty = self.table.next_ty_var(scrut.into());
self.infer_expr_coerce_never(scrut, &Expectation::HasType(scrut_ty), scrutinee_is_read);
scrut_ty
}
@@ -1328,13 +1328,19 @@ impl<'db> InferenceContext<'_, 'db> {
}
oprnd_t
}
- fn infer_expr_array(&mut self, array: &Array, expected: &Expectation<'db>) -> Ty<'db> {
+
+ fn infer_expr_array(
+ &mut self,
+ expr: ExprId,
+ array: &Array,
+ expected: &Expectation<'db>,
+ ) -> Ty<'db> {
let elem_ty = match expected
.to_option(&mut self.table)
.map(|t| self.table.try_structurally_resolve_type(t).kind())
{
Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st,
- _ => self.table.next_ty_var(),
+ _ => self.table.next_ty_var(expr.into()),
};
let krate = self.resolver.krate();
@@ -1371,7 +1377,7 @@ impl<'db> InferenceContext<'_, 'db> {
let len = match self.store[repeat] {
Expr::Underscore => {
self.write_expr_ty(repeat, usize);
- self.table.next_const_var()
+ self.table.next_const_var(repeat.into())
}
_ => {
self.infer_expr(repeat, &Expectation::HasType(usize), ExprIsRead::Yes);
@@ -1383,7 +1389,7 @@ impl<'db> InferenceContext<'_, 'db> {
}
};
// Try to evaluate unevaluated constant, and insert variable if is not possible.
- let len = self.table.insert_const_vars_shallow(len);
+ let len = self.insert_const_vars_shallow(len);
Ty::new_array_with_const_len(self.interner(), elem_ty, len)
}
@@ -1477,7 +1483,7 @@ impl<'db> InferenceContext<'_, 'db> {
label: Option<LabelId>,
expected: &Expectation<'db>,
) -> Ty<'db> {
- let coerce_ty = expected.coercion_target_type(&mut self.table);
+ let coerce_ty = expected.coercion_target_type(&mut self.table, expr.into());
let g = self.resolver.update_to_inner_scope(self.db, self.owner, expr);
let (break_ty, ty) =
@@ -1488,7 +1494,7 @@ impl<'db> InferenceContext<'_, 'db> {
let decl_ty = type_ref
.as_ref()
.map(|&tr| this.make_body_ty(tr))
- .unwrap_or_else(|| this.table.next_ty_var());
+ .unwrap_or_else(|| this.table.next_ty_var((*pat).into()));
let ty = if let Some(expr) = initializer {
// If we have a subpattern that performs a read, we want to consider this
@@ -1561,7 +1567,7 @@ impl<'db> InferenceContext<'_, 'db> {
// `!`).
if this.diverges.is_always() {
// we don't even make an attempt at coercion
- this.table.new_maybe_never_var()
+ this.table.new_maybe_never_var(expr.into())
} else if let Some(t) = expected.only_has_type(&mut this.table) {
if this
.coerce(
@@ -1728,10 +1734,13 @@ impl<'db> InferenceContext<'_, 'db> {
fn instantiate_erroneous_method(&mut self, def_id: FunctionId) -> MethodCallee<'db> {
// FIXME: Using fresh infer vars for the method args isn't optimal,
// we can do better by going thorough the full probe/confirm machinery.
- let args = self.table.fresh_args_for_item(def_id.into());
+ let args = self.table.fresh_args_for_item(Span::Dummy, def_id.into());
let sig = self.db.callable_item_signature(def_id.into()).instantiate(self.interner(), args);
- let sig =
- self.infcx().instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, sig);
+ let sig = self.infcx().instantiate_binder_with_fresh_vars(
+ Span::Dummy,
+ BoundRegionConversionTime::FnCall,
+ sig,
+ );
MethodCallee { def_id, args, sig }
}
@@ -1810,20 +1819,21 @@ impl<'db> InferenceContext<'_, 'db> {
None => None,
};
- let assoc_func_with_same_name = self.with_method_resolution(|ctx| {
- if !matches!(
- receiver_ty.kind(),
- TyKind::Infer(InferTy::TyVar(_)) | TyKind::Error(_)
- ) {
- ctx.probe_for_name(
- method_resolution::Mode::Path,
- method_name.clone(),
- receiver_ty,
- )
- } else {
- Err(MethodError::ErrorReported)
- }
- });
+ let assoc_func_with_same_name =
+ self.with_method_resolution(tgt_expr.into(), receiver.into(), |ctx| {
+ if !matches!(
+ receiver_ty.kind(),
+ TyKind::Infer(InferTy::TyVar(_)) | TyKind::Error(_)
+ ) {
+ ctx.probe_for_name(
+ method_resolution::Mode::Path,
+ method_name.clone(),
+ receiver_ty,
+ )
+ } else {
+ Err(MethodError::ErrorReported)
+ }
+ });
let assoc_func_with_same_name = match assoc_func_with_same_name {
Ok(method_resolution::Pick {
item: CandidateId::FunctionId(def_id), ..
@@ -1928,7 +1938,7 @@ impl<'db> InferenceContext<'_, 'db> {
let formal_input_tys: Vec<_> = formal_input_tys
.iter()
.map(|&ty| {
- let generalized_ty = self.table.next_ty_var();
+ let generalized_ty = self.table.next_ty_var(call_expr.into());
let _ = self.demand_eqtype(call_expr.into(), ty, generalized_ty);
generalized_ty
})
diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs
index b2369f6a87..c3b532638f 100644
--- a/crates/hir-ty/src/infer/mutability.rs
+++ b/crates/hir-ty/src/infer/mutability.rs
@@ -32,6 +32,7 @@ impl<'db> InferenceContext<'_, 'db> {
};
if let Some(infer_ok) = Self::try_mutable_overloaded_place_op(
&self.table,
+ tgt_expr,
source_ty,
None,
PlaceOp::Deref,
diff --git a/crates/hir-ty/src/infer/op.rs b/crates/hir-ty/src/infer/op.rs
index 2916a46ca3..5900027a98 100644
--- a/crates/hir-ty/src/infer/op.rs
+++ b/crates/hir-ty/src/infer/op.rs
@@ -180,7 +180,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
// e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
// in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
let lhs_ty = self.infer_expr_no_expect(lhs_expr, ExprIsRead::Yes);
- let fresh_var = self.table.next_ty_var();
+ let fresh_var = self.table.next_ty_var(lhs_expr.into());
self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No, ExprIsRead::Yes)
}
};
@@ -192,7 +192,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
// using this variable as the expected type, which sometimes lets
// us do better coercions than we would be able to do otherwise,
// particularly for things like `String + &String`.
- let rhs_ty_var = self.table.next_ty_var();
+ let rhs_ty_var = self.table.next_ty_var(rhs_expr.into());
let result = self.lookup_op_method(
lhs_ty,
Some((rhs_expr, rhs_ty_var)),
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 3cd7461cf3..ac209adef8 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -26,7 +26,7 @@ use span::Edition;
use tracing::{debug, instrument, trace};
use crate::{
- BindingMode, InferenceDiagnostic,
+ BindingMode, InferenceDiagnostic, Span,
infer::{
AllowTwoPhase, ByRef, Expectation, InferenceContext, PatAdjust, PatAdjustment,
TypeMismatch, expr::ExprIsRead,
@@ -446,7 +446,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
pat_info,
)
}
- Pat::Missing | Pat::Wild => expected,
+ Pat::Missing => self.types.types.error,
+ Pat::Wild | Pat::Rest => expected,
// We allow any type here; we ensure that the type is uninhabited during match checking.
// Pat::Never => expected,
Pat::Path(_) => {
@@ -658,8 +659,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
Pat::Ref { .. }
// No need to do anything on a missing pattern.
| Pat::Missing
- // A `_` pattern works with any expected type, so there's no need to do anything.
- | Pat::Wild
+ // A `_`/`..` pattern works with any expected type, so there's no need to do anything.
+ | Pat::Wild | Pat::Rest
// Bindings also work with whatever the expected type is,
// and moreover if we peel references off, that will give us the wrong binding type.
// Also, we can have a subpattern `binding @ pat`.
@@ -928,7 +929,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
// `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)`
// is required. However, we use equality, which is stronger.
// See (note_1) for an explanation.
- self.new_ref_ty(mutbl, expected)
+ self.new_ref_ty(pat.into(), mutbl, expected)
}
// Otherwise, the type of x is the expected type `T`.
ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1).
@@ -1110,7 +1111,9 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
}
let max_len = cmp::max(expected_len, elements.len());
- let element_tys_iter = (0..max_len).map(|_| self.table.next_ty_var());
+ let element_tys_iter = (0..max_len).map(|i| {
+ self.table.next_ty_var(elements.get(i).copied().map(Span::PatId).unwrap_or(Span::Dummy))
+ });
let element_tys = Tys::new_from_iter(interner, element_tys_iter);
let pat_ty = Ty::new(interner, TyKind::Tuple(element_tys));
if self.demand_eqtype(pat.into(), expected, pat_ty).is_err() {
@@ -1249,7 +1252,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
.map(|()| {
// Here, `demand::subtype` is good enough, but I don't
// think any errors can be introduced by using `demand::eqtype`.
- let inner_ty = self.table.next_ty_var();
+ let inner_ty = self.table.next_ty_var(inner.into());
let box_ty = Ty::new_box(interner, inner_ty);
_ = self.demand_eqtype(pat.into(), expected, box_ty);
(box_ty, inner_ty)
@@ -1472,8 +1475,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
(expected, r_ty)
}
_ => {
- let inner_ty = self.table.next_ty_var();
- let ref_ty = self.new_ref_ty(pat_mutbl, inner_ty);
+ let inner_ty = self.table.next_ty_var(inner.into());
+ let ref_ty = self.new_ref_ty(inner.into(), pat_mutbl, inner_ty);
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
_ = self.demand_eqtype(pat.into(), expected, ref_ty);
@@ -1492,8 +1495,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
}
/// Create a reference or pinned reference type with a fresh region variable.
- fn new_ref_ty(&self, mutbl: Mutability, ty: Ty<'db>) -> Ty<'db> {
- let region = self.table.next_region_var();
+ fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'db>) -> Ty<'db> {
+ let region = self.table.next_region_var(span);
Ty::new_ref(self.interner(), region, ty, mutbl)
}
@@ -1501,6 +1504,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
&self,
before: &[PatId],
slice: Option<PatId>,
+ pat: PatId,
) -> Option<Ty<'db>> {
if slice.is_some() {
return None;
@@ -1508,7 +1512,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
let interner = self.interner();
let len = before.len();
- let inner_ty = self.table.next_ty_var();
+ let inner_ty = self.table.next_ty_var(pat.into());
Some(Ty::new_array(interner, inner_ty, len.try_into().unwrap()))
}
@@ -1576,7 +1580,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
// to an array if the given pattern allows it. See issue #76342
if self.pat_is_irrefutable(pat_info.pat_origin)
&& expected.is_ty_var()
- && let Some(resolved_arr_ty) = self.try_resolve_slice_ty_to_array_ty(before, slice)
+ && let Some(resolved_arr_ty) = self.try_resolve_slice_ty_to_array_ty(before, slice, pat)
{
debug!(?resolved_arr_ty);
let _ = self.demand_eqtype(pat.into(), expected, resolved_arr_ty);
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 0687d56024..c020c9812b 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -11,7 +11,7 @@ use rustc_type_ir::inherent::{SliceLike, Ty as _};
use stdx::never;
use crate::{
- InferenceDiagnostic, ValueTyDefId,
+ InferenceDiagnostic, Span, ValueTyDefId,
infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
lower::{GenericPredicates, LifetimeElisionKind},
method_resolution::{self, CandidateId, MethodError},
@@ -38,7 +38,7 @@ impl<'db> InferenceContext<'_, 'db> {
}
ValuePathResolution::NonGeneric(ty) => return Some((value, ty)),
};
- let args = self.insert_type_vars(substs);
+ let args = self.insert_type_vars(substs, id.into());
self.add_required_obligations_for_value_path(generic_def, args);
@@ -91,7 +91,7 @@ impl<'db> InferenceContext<'_, 'db> {
};
}
ValueNs::GenericParam(it) => {
- return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty_ns(it)));
+ return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty(it)));
}
};
@@ -157,12 +157,12 @@ impl<'db> InferenceContext<'_, 'db> {
let last = path.segments().last()?;
let (ty, orig_ns) = path_ctx.ty_ctx().lower_ty_ext(type_ref);
- let ty = self.table.process_user_written_ty(ty);
+ let ty = self.table.process_user_written_ty(type_ref.into(), ty);
path_ctx.ignore_last_segment();
let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns, true);
drop_ctx(ctx, no_diagnostics);
- let ty = self.table.process_user_written_ty(ty);
+ let ty = self.table.process_user_written_ty(id.into(), ty);
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
} else {
let hygiene = self.store.expr_or_pat_path_hygiene(id);
@@ -187,7 +187,7 @@ impl<'db> InferenceContext<'_, 'db> {
let (resolution, substs) = match (def, is_before_last) {
(TypeNs::TraitId(trait_), true) => {
- let self_ty = self.table.next_ty_var();
+ let self_ty = self.table.next_ty_var(id.into());
let trait_ref =
path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty, true);
drop_ctx(ctx, no_diagnostics);
@@ -205,7 +205,7 @@ impl<'db> InferenceContext<'_, 'db> {
return None;
}
- let ty = self.process_user_written_ty(ty);
+ let ty = self.process_user_written_ty(id.into(), ty);
self.resolve_ty_assoc_item(ty, last_segment.name, id)
}
@@ -290,7 +290,7 @@ impl<'db> InferenceContext<'_, 'db> {
return Some(result);
}
- let res = self.with_method_resolution(|ctx| {
+ let res = self.with_method_resolution(Span::Dummy, Span::Dummy, |ctx| {
ctx.probe_for_name(method_resolution::Mode::Path, name.clone(), ty)
});
let (item, visible) = match res {
@@ -310,7 +310,7 @@ impl<'db> InferenceContext<'_, 'db> {
};
let substs = match container {
ItemContainerId::ImplId(impl_id) => {
- let impl_substs = self.table.fresh_args_for_item(impl_id.into());
+ let impl_substs = self.table.fresh_args_for_item(id.into(), impl_id.into());
let impl_self_ty =
self.db.impl_self_ty(impl_id).instantiate(self.interner(), impl_substs);
_ = self.demand_eqtype(id, impl_self_ty, ty);
@@ -318,9 +318,12 @@ impl<'db> InferenceContext<'_, 'db> {
}
ItemContainerId::TraitId(trait_) => {
// we're picking this method
- GenericArgs::fill_rest(self.interner(), trait_.into(), [ty.into()], |_, id, _| {
- self.table.next_var_for_param(id)
- })
+ GenericArgs::fill_rest(
+ self.interner(),
+ trait_.into(),
+ [ty.into()],
+ |_, param, _| self.table.var_for_def(param, id.into()),
+ )
}
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
never!("assoc item contained in module/extern block");
diff --git a/crates/hir-ty/src/infer/place_op.rs b/crates/hir-ty/src/infer/place_op.rs
index 1671b67d34..63841af682 100644
--- a/crates/hir-ty/src/infer/place_op.rs
+++ b/crates/hir-ty/src/infer/place_op.rs
@@ -29,9 +29,10 @@ pub(super) enum PlaceOp {
impl<'a, 'db> InferenceContext<'a, 'db> {
pub(super) fn try_overloaded_deref(
&self,
+ expr: ExprId,
base_ty: Ty<'db>,
) -> Option<InferOk<'db, MethodCallee<'db>>> {
- self.try_overloaded_place_op(base_ty, None, PlaceOp::Deref)
+ self.try_overloaded_place_op(expr, base_ty, None, PlaceOp::Deref)
}
/// For the overloaded place expressions (`*x`, `x[3]`), the trait
@@ -57,7 +58,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
return Some(ty);
}
- let ok = self.try_overloaded_deref(oprnd_ty)?;
+ let ok = self.try_overloaded_deref(expr, oprnd_ty)?;
let method = self.table.register_infer_ok(ok);
if let TyKind::Ref(_, _, Mutability::Not) = method.sig.inputs_and_output.inputs()[0].kind()
{
@@ -81,6 +82,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
&mut self,
expr: ExprId,
base_expr: ExprId,
+ index_expr: ExprId,
base_ty: Ty<'db>,
idx_ty: Ty<'db>,
) -> Option<(/*index type*/ Ty<'db>, /*element type*/ Ty<'db>)> {
@@ -91,7 +93,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
let mut autoderef = InferenceContextAutoderef::new_from_inference_context(self, base_ty);
let mut result = None;
while result.is_none() && autoderef.next().is_some() {
- result = Self::try_index_step(expr, base_expr, &mut autoderef, idx_ty);
+ result = Self::try_index_step(expr, base_expr, index_expr, &mut autoderef, idx_ty);
}
result
}
@@ -104,6 +106,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
fn try_index_step(
expr: ExprId,
base_expr: ExprId,
+ index_expr: ExprId,
autoderef: &mut InferenceContextAutoderef<'_, 'a, 'db>,
index_ty: Ty<'db>,
) -> Option<(/*index type*/ Ty<'db>, /*element type*/ Ty<'db>)> {
@@ -136,9 +139,13 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
// If some lookup succeeds, write callee into table and extract index/element
// type from the method signature.
// If some lookup succeeded, install method in table
- let input_ty = autoderef.ctx().table.next_ty_var();
- let method =
- autoderef.ctx().try_overloaded_place_op(self_ty, Some(input_ty), PlaceOp::Index);
+ let input_ty = autoderef.ctx().table.next_ty_var(index_expr.into());
+ let method = autoderef.ctx().try_overloaded_place_op(
+ expr,
+ self_ty,
+ Some(input_ty),
+ PlaceOp::Index,
+ );
if let Some(result) = method {
debug!("try_index_step: success, using overloaded indexing");
@@ -180,6 +187,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
/// `convert_place_derefs_to_mutable`.
pub(super) fn try_overloaded_place_op(
&self,
+ expr: ExprId,
base_ty: Ty<'db>,
opt_rhs_ty: Option<Ty<'db>>,
op: PlaceOp,
@@ -198,7 +206,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
// opaque types as rigid here to support `impl Deref<Target = impl Index<usize>>`.
let treat_opaques = TreatNotYetDefinedOpaques::AsInfer;
self.table.lookup_method_for_operator(
- ObligationCause::new(),
+ ObligationCause::with_span(expr.into()),
imm_op,
imm_tr,
base_ty,
@@ -209,6 +217,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
pub(super) fn try_mutable_overloaded_place_op(
table: &InferenceTable<'db>,
+ expr: ExprId,
base_ty: Ty<'db>,
opt_rhs_ty: Option<Ty<'db>>,
op: PlaceOp,
@@ -230,7 +239,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
// of the opaque.
let treat_opaques = TreatNotYetDefinedOpaques::AsInfer;
table.lookup_method_for_operator(
- ObligationCause::new(),
+ ObligationCause::with_span(expr.into()),
mut_op,
mut_tr,
base_ty,
@@ -276,7 +285,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
))
}
};
- let method = Self::try_mutable_overloaded_place_op(&self.table, base_ty, arg_ty, op);
+ let method = Self::try_mutable_overloaded_place_op(&self.table, expr, base_ty, arg_ty, op);
let method = match method {
Some(ok) => self.table.register_infer_ok(ok),
// Couldn't find the mutable variant of the place op, keep the
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index be4d370c24..4342375621 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -7,12 +7,13 @@ use hir_def::{ExpressionStoreOwnerId, GenericParamId, TraitId};
use rustc_hash::FxHashSet;
use rustc_type_ir::{
TyVid, TypeFoldable, TypeVisitableExt,
- inherent::{Const as _, GenericArg as _, IntoKind, Ty as _},
+ inherent::{GenericArg as _, IntoKind, Ty as _},
solve::Certainty,
};
use smallvec::SmallVec;
use crate::{
+ Span,
db::HirDatabase,
next_solver::{
Canonical, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
@@ -41,6 +42,10 @@ struct NestedObligationsForSelfTy<'a, 'db> {
impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> {
type Result = ();
+ fn span(&self) -> Span {
+ self.root_cause.span()
+ }
+
fn config(&self) -> InspectConfig {
// Using an intentionally low depth to minimize the chance of future
// breaking changes in case we adapt the approach later on. This also
@@ -112,7 +117,7 @@ fn could_unify_impl<'db>(
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
let cause = ObligationCause::dummy();
let at = infcx.at(&cause, env.param_env);
- let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(tys);
+ let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(Span::Dummy, tys);
let mut ctxt = ObligationCtxt::new(&infcx);
let can_unify = at
.eq(ty1_with_vars, ty2_with_vars)
@@ -245,12 +250,12 @@ impl<'db> InferenceTable<'db> {
self.diverging_type_vars.insert(ty);
}
- pub(crate) fn next_ty_var(&self) -> Ty<'db> {
- self.infer_ctxt.next_ty_var()
+ pub(crate) fn next_ty_var(&self, span: Span) -> Ty<'db> {
+ self.infer_ctxt.next_ty_var(span)
}
- pub(crate) fn next_const_var(&self) -> Const<'db> {
- self.infer_ctxt.next_const_var()
+ pub(crate) fn next_const_var(&self, span: Span) -> Const<'db> {
+ self.infer_ctxt.next_const_var(span)
}
pub(crate) fn next_int_var(&self) -> Ty<'db> {
@@ -261,31 +266,18 @@ impl<'db> InferenceTable<'db> {
self.infer_ctxt.next_float_var()
}
- pub(crate) fn new_maybe_never_var(&mut self) -> Ty<'db> {
- let var = self.next_ty_var();
+ pub(crate) fn new_maybe_never_var(&mut self, span: Span) -> Ty<'db> {
+ let var = self.next_ty_var(span);
self.set_diverging(var);
var
}
- pub(crate) fn next_region_var(&self) -> Region<'db> {
- self.infer_ctxt.next_region_var()
+ pub(crate) fn next_region_var(&self, span: Span) -> Region<'db> {
+ self.infer_ctxt.next_region_var(span)
}
- pub(crate) fn next_var_for_param(&self, id: GenericParamId) -> GenericArg<'db> {
- self.infer_ctxt.next_var_for_param(id)
- }
-
- pub(crate) fn resolve_completely<T>(&mut self, value: T) -> T
- where
- T: TypeFoldable<DbInterner<'db>>,
- {
- let value = self.infer_ctxt.resolve_vars_if_possible(value);
-
- let mut goals = vec![];
-
- // FIXME(next-solver): Handle `goals`.
-
- value.fold_with(&mut resolve_completely::Resolver::new(self, true, &mut goals))
+ pub(crate) fn var_for_def(&self, id: GenericParamId, span: Span) -> GenericArg<'db> {
+ self.infer_ctxt.var_for_def(id, span)
}
pub(crate) fn at<'a>(&'a self, cause: &'a ObligationCause) -> At<'a, 'db> {
@@ -319,8 +311,8 @@ impl<'db> InferenceTable<'db> {
}
/// Create a `GenericArgs` full of infer vars for `def`.
- pub(crate) fn fresh_args_for_item(&self, def: SolverDefId) -> GenericArgs<'db> {
- self.infer_ctxt.fresh_args_for_item(def)
+ pub(crate) fn fresh_args_for_item(&self, span: Span, def: SolverDefId) -> GenericArgs<'db> {
+ self.infer_ctxt.fresh_args_for_item(span, def)
}
/// Try to resolve `ty` to a structural type, normalizing aliases.
@@ -399,19 +391,21 @@ impl<'db> InferenceTable<'db> {
where
I: IntoIterator<Item = PredicateObligation<'db>>,
{
- obligations.into_iter().for_each(|obligation| {
- self.register_predicate(obligation);
- });
+ self.fulfillment_cx.register_predicate_obligations(&self.infer_ctxt, obligations);
}
/// checking later, during regionck, that `arg` is well-formed.
pub(crate) fn register_wf_obligation(&mut self, term: Term<'db>, cause: ObligationCause) {
- self.register_predicate(Obligation::new(
- self.interner(),
- cause,
- self.param_env,
- ClauseKind::WellFormed(term),
- ));
+ let _ = (term, cause);
+ // FIXME: We don't currently register an obligation here because we don't implement
+ // wf checking anyway and this function is currently often passed dummy spans, which could
+ // prevent reporting "type annotation needed" errors.
+ // self.register_predicate(Obligation::new(
+ // self.interner(),
+ // cause,
+ // self.param_env,
+ // ClauseKind::WellFormed(term),
+ // ));
}
/// Registers obligations that all `args` are well-formed.
@@ -421,34 +415,29 @@ impl<'db> InferenceTable<'db> {
}
}
- pub(super) fn insert_type_vars<T>(&mut self, ty: T) -> T
+ pub(super) fn insert_type_vars<T>(&mut self, ty: T, span: Span) -> T
where
T: TypeFoldable<DbInterner<'db>>,
{
- self.infer_ctxt.insert_type_vars(ty)
+ self.infer_ctxt.insert_type_vars(ty, span)
}
/// Whenever you lower a user-written type, you should call this.
- pub(crate) fn process_user_written_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
- self.process_remote_user_written_ty(ty)
- // FIXME: Register a well-formed obligation.
+ pub(crate) fn process_user_written_ty(&mut self, span: Span, ty: Ty<'db>) -> Ty<'db> {
+ let ty = self.insert_type_vars(ty, span);
+ self.try_structurally_resolve_type(ty)
}
/// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation,
/// while `process_user_written_ty()` should (but doesn't currently).
pub(crate) fn process_remote_user_written_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
- let ty = self.insert_type_vars(ty);
+ let ty = self.insert_type_vars(ty, Span::Dummy);
// See https://github.com/rust-lang/rust/blob/cdb45c87e2cd43495379f7e867e3cc15dcee9f93/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs#L487-L495:
// Even though the new solver only lazily normalizes usually, here we eagerly normalize so that not everything needs
// to normalize before inspecting the `TyKind`.
// FIXME(next-solver): We should not deeply normalize here, only shallowly.
self.try_structurally_resolve_type(ty)
}
-
- /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
- pub(super) fn insert_const_vars_shallow(&mut self, c: Const<'db>) -> Const<'db> {
- if c.is_ct_error() { self.next_const_var() } else { c }
- }
}
impl fmt::Debug for InferenceTable<'_> {
@@ -460,20 +449,234 @@ impl fmt::Debug for InferenceTable<'_> {
}
}
-mod resolve_completely {
- use rustc_type_ir::{DebruijnIndex, Flags, TypeFolder, TypeSuperFoldable};
+pub(super) mod resolve_completely {
+ use rustc_hash::FxHashSet;
+ use rustc_type_ir::{
+ DebruijnIndex, Flags, InferConst, InferTy, TypeFlags, TypeFoldable, TypeFolder,
+ TypeSuperFoldable, TypeVisitableExt, inherent::IntoKind,
+ };
+ use stdx::never;
+ use thin_vec::ThinVec;
use crate::{
- infer::unify::InferenceTable,
+ InferenceDiagnostic, Span,
+ infer::{TypeMismatch, unify::InferenceTable},
next_solver::{
- Const, DbInterner, Goal, Predicate, Region, Term, Ty,
+ Const, ConstKind, DbInterner, DefaultAny, GenericArg, Goal, Predicate, Region, Term,
+ TermKind, Ty, TyKind,
infer::{resolve::ReplaceInferWithError, traits::ObligationCause},
normalize::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals,
},
};
+ pub(crate) struct WriteBackCtxt<'db> {
+ table: InferenceTable<'db>,
+ diagnostics: ThinVec<InferenceDiagnostic>,
+ has_errors: bool,
+ spans_emitted_type_must_be_known_for: FxHashSet<Span>,
+ types: &'db DefaultAny<'db>,
+ }
+
+ impl<'db> WriteBackCtxt<'db> {
+ pub(crate) fn new(
+ table: InferenceTable<'db>,
+ diagnostics: ThinVec<InferenceDiagnostic>,
+ vars_emitted_type_must_be_known_for: FxHashSet<Term<'db>>,
+ ) -> Self {
+ let spans_emitted_type_must_be_known_for = vars_emitted_type_must_be_known_for
+ .into_iter()
+ .filter_map(|term| match term.kind() {
+ TermKind::Ty(ty) => match ty.kind() {
+ TyKind::Infer(InferTy::TyVar(vid)) => {
+ Some(table.infer_ctxt.type_var_span(vid))
+ }
+ _ => None,
+ },
+ TermKind::Const(ct) => match ct.kind() {
+ ConstKind::Infer(InferConst::Var(vid)) => {
+ table.infer_ctxt.const_var_span(vid)
+ }
+ _ => None,
+ },
+ })
+ .collect();
+
+ Self {
+ types: table.interner().default_types(),
+ table,
+ diagnostics,
+ has_errors: false,
+ spans_emitted_type_must_be_known_for,
+ }
+ }
+
+ pub(crate) fn resolve_type_mismatch(&mut self, value_ref: &mut TypeMismatch) {
+ // Ignore diagnostics from type mismatches, which are diagnostics themselves.
+ // FIXME: We should make type mismatches just regular diagnostics.
+ let prev_diagnostics_len = self.diagnostics.len();
+ self.resolve_completely(value_ref);
+ self.diagnostics.truncate(prev_diagnostics_len);
+ }
+
+ pub(crate) fn resolve_completely<T>(&mut self, value_ref: &mut T)
+ where
+ T: TypeFoldable<DbInterner<'db>>,
+ {
+ self.resolve_completely_with_default(value_ref, value_ref.clone());
+ }
+
+ pub(crate) fn resolve_completely_with_default<T>(&mut self, value_ref: &mut T, default: T)
+ where
+ T: TypeFoldable<DbInterner<'db>>,
+ {
+ let value = std::mem::replace(value_ref, default);
+
+ let value = self.table.resolve_vars_if_possible(value);
+
+ let mut goals = vec![];
+
+ // FIXME(next-solver): Handle `goals`.
+
+ *value_ref = value.fold_with(&mut Resolver::new(self, true, &mut goals));
+ }
+
+ pub(crate) fn resolve_diagnostics(mut self) -> (ThinVec<InferenceDiagnostic>, bool) {
+ let has_errors = self.has_errors;
+
+ // Ignore diagnostics made from resolving diagnostics.
+ let mut diagnostics = std::mem::take(&mut self.diagnostics);
+ diagnostics.retain_mut(|diagnostic| {
+ self.resolve_completely(diagnostic);
+
+ if let InferenceDiagnostic::ExpectedFunction { found: ty, .. }
+ | InferenceDiagnostic::UnresolvedField { receiver: ty, .. }
+ | InferenceDiagnostic::UnresolvedMethodCall { receiver: ty, .. } = diagnostic
+ && ty.as_ref().references_non_lt_error()
+ {
+ false
+ } else {
+ true
+ }
+ });
+ diagnostics.shrink_to_fit();
+
+ (diagnostics, has_errors)
+ }
+ }
+
+ struct DiagnoseInferVars<'a, 'db> {
+ ctx: &'a mut WriteBackCtxt<'db>,
+ top_term: Term<'db>,
+ }
+
+ impl<'db> DiagnoseInferVars<'_, 'db> {
+ const TYPE_FLAGS: TypeFlags = TypeFlags::HAS_INFER.union(TypeFlags::HAS_NON_REGION_ERROR);
+
+ fn err_on_span(&mut self, span: Span) {
+ if !self.ctx.spans_emitted_type_must_be_known_for.insert(span) {
+ // Suppress duplicate diagnostics.
+ return;
+ }
+
+ if span.is_dummy() {
+ return;
+ }
+
+ // We have to be careful not to insert infer vars here, as we won't resolve this new diagnostic.
+ let top_term = self.top_term.fold_with(&mut ReplaceInferWithError::new(self.cx()));
+ self.ctx.diagnostics.push(InferenceDiagnostic::TypeMustBeKnown {
+ at_point: span,
+ top_term: Some(GenericArg::from(top_term).store()),
+ });
+ }
+ }
+
+ impl<'db> TypeFolder<DbInterner<'db>> for DiagnoseInferVars<'_, 'db> {
+ fn cx(&self) -> DbInterner<'db> {
+ self.ctx.table.interner()
+ }
+
+ fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
+ if !t.has_type_flags(Self::TYPE_FLAGS) {
+ return t;
+ }
+
+ match t.kind() {
+ TyKind::Error(_) => {
+ self.ctx.has_errors = true;
+ t
+ }
+ TyKind::Infer(infer_ty) => match infer_ty {
+ InferTy::TyVar(vid) => {
+ self.err_on_span(self.ctx.table.infer_ctxt.type_var_span(vid));
+ self.ctx.has_errors = true;
+ self.ctx.types.types.error
+ }
+ InferTy::IntVar(_) => {
+ never!("fallback should have resolved all int vars");
+ self.ctx.types.types.i32
+ }
+ InferTy::FloatVar(_) => {
+ never!("fallback should have resolved all float vars");
+ self.ctx.types.types.f64
+ }
+ InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_) => {
+ never!("should not have fresh infer vars outside of caching");
+ self.ctx.has_errors = true;
+ self.ctx.types.types.error
+ }
+ },
+ _ => t.super_fold_with(self),
+ }
+ }
+
+ fn fold_const(&mut self, c: Const<'db>) -> Const<'db> {
+ if !c.has_type_flags(Self::TYPE_FLAGS) {
+ return c;
+ }
+
+ match c.kind() {
+ ConstKind::Error(_) => {
+ self.ctx.has_errors = true;
+ c
+ }
+ ConstKind::Infer(infer_ct) => match infer_ct {
+ InferConst::Var(vid) => {
+ if let Some(span) = self.ctx.table.infer_ctxt.const_var_span(vid) {
+ self.err_on_span(span);
+ }
+ self.ctx.has_errors = true;
+ self.ctx.types.consts.error
+ }
+ InferConst::Fresh(_) => {
+ never!("should not have fresh infer vars outside of caching");
+ self.ctx.has_errors = true;
+ self.ctx.types.consts.error
+ }
+ },
+ _ => c.super_fold_with(self),
+ }
+ }
+
+ fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> {
+ if !p.has_type_flags(Self::TYPE_FLAGS) {
+ return p;
+ }
+ p.super_fold_with(self)
+ }
+
+ fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
+ if r.is_var() {
+ // For now, we don't error on regions.
+ self.ctx.types.regions.error
+ } else {
+ r
+ }
+ }
+ }
+
pub(super) struct Resolver<'a, 'db> {
- ctx: &'a mut InferenceTable<'db>,
+ ctx: &'a mut WriteBackCtxt<'db>,
/// Whether we should normalize, disabled when resolving predicates.
should_normalize: bool,
nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>,
@@ -481,7 +684,7 @@ mod resolve_completely {
impl<'a, 'db> Resolver<'a, 'db> {
pub(super) fn new(
- ctx: &'a mut InferenceTable<'db>,
+ ctx: &'a mut WriteBackCtxt<'db>,
should_normalize: bool,
nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>,
) -> Resolver<'a, 'db> {
@@ -498,7 +701,7 @@ mod resolve_completely {
{
let value = if self.should_normalize {
let cause = ObligationCause::new();
- let at = self.ctx.at(&cause);
+ let at = self.ctx.table.at(&cause);
let universes = vec![None; outer_exclusive_binder(value).as_usize()];
match deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
at, value, universes,
@@ -516,17 +719,17 @@ mod resolve_completely {
value
};
- value.fold_with(&mut ReplaceInferWithError::new(self.ctx.interner()))
+ value.fold_with(&mut DiagnoseInferVars { ctx: self.ctx, top_term: value.into() })
}
}
- impl<'cx, 'db> TypeFolder<DbInterner<'db>> for Resolver<'cx, 'db> {
+ impl<'db> TypeFolder<DbInterner<'db>> for Resolver<'_, 'db> {
fn cx(&self) -> DbInterner<'db> {
- self.ctx.interner()
+ self.ctx.table.interner()
}
fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
- if r.is_var() { Region::error(self.ctx.interner()) } else { r }
+ if r.is_var() { self.ctx.types.regions.error } else { r }
}
fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 2973b970f3..4433dd6425 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -62,7 +62,10 @@ use std::{hash::Hash, ops::ControlFlow};
use hir_def::{
CallableDefId, ExpressionStoreOwnerId, GenericDefId, TypeAliasId, TypeOrConstParamId,
- TypeParamId, resolver::TypeNs, type_ref::Rawness,
+ TypeParamId,
+ hir::{ExprId, ExprOrPatId, PatId},
+ resolver::TypeNs,
+ type_ref::{Rawness, TypeRefId},
};
use hir_expand::name::Name;
use indexmap::{IndexMap, map::Entry};
@@ -74,6 +77,7 @@ use rustc_type_ir::{
BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt,
inherent::{IntoKind, Ty as _},
};
+use stdx::impl_from;
use syntax::ast::{ConstArg, make};
use traits::FnTrait;
@@ -541,7 +545,7 @@ pub fn callable_sig_from_fn_trait<'db>(
let impls_trait = |trait_: FnTrait| {
let mut ocx = ObligationCtxt::new(&infcx);
- let tupled_args = infcx.next_ty_var();
+ let tupled_args = infcx.next_ty_var(Span::Dummy);
let args = GenericArgs::new_from_slice(&[self_ty.into(), tupled_args.into()]);
let trait_id = trait_.get_id(lang_items)?;
let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args);
@@ -661,6 +665,42 @@ pub fn known_const_to_ast<'db>(
Some(make::expr_const_value(konst.display(db, display_target).to_string().as_str()))
}
+/// A `Span` represents some location in lowered code - a type, expression or pattern.
+///
+/// It has no meaning outside its body therefore it should not exit the pass it was created in
+/// (e.g. inference). It is usually associated with a solver obligation or an infer var, which
+/// should also not cross the pass they were created in.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Span {
+ ExprId(ExprId),
+ PatId(PatId),
+ TypeRefId(TypeRefId),
+ /// An unimportant location. Errors on this will be suppressed.
+ Dummy,
+}
+impl_from!(ExprId, PatId, TypeRefId for Span);
+
+impl From<ExprOrPatId> for Span {
+ fn from(value: ExprOrPatId) -> Self {
+ match value {
+ ExprOrPatId::ExprId(idx) => idx.into(),
+ ExprOrPatId::PatId(idx) => idx.into(),
+ }
+ }
+}
+
+impl Span {
+ pub(crate) fn pick_best(a: Span, b: Span) -> Span {
+ // We prefer dummy spans to minimize the risk of false errors.
+ if b.is_dummy() { b } else { a }
+ }
+
+ #[inline]
+ pub fn is_dummy(&self) -> bool {
+ matches!(self, Self::Dummy)
+ }
+}
+
pub fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> {
use std::env;
use std::sync::LazyLock;
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 335aff2c1d..7325cd0ef8 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -2379,7 +2379,7 @@ fn push_const_arg_has_type_predicates<'db>(
interner,
ParamConst { id: param_id, index: (param_index + const_params_offset) as u32 },
),
- db.const_param_ty_ns(param_id),
+ db.const_param_ty(param_id),
)
.upcast(interner),
));
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index a364894539..d6b9c375fc 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -736,6 +736,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
fn provided_type_like_const(
&mut self,
+ _type_ref: TypeRefId,
const_ty: Ty<'db>,
arg: TypeLikeConst<'_>,
) -> Const<'db> {
@@ -1002,8 +1003,12 @@ pub(crate) trait GenericArgsLowerer<'db> {
arg: &HirGenericArg,
) -> GenericArg<'db>;
- fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>)
- -> Const<'db>;
+ fn provided_type_like_const(
+ &mut self,
+ type_ref: TypeRefId,
+ const_ty: Ty<'db>,
+ arg: TypeLikeConst<'_>,
+ ) -> Const<'db>;
fn inferred_kind(
&mut self,
@@ -1225,7 +1230,8 @@ pub(crate) fn substs_from_args_and_bindings<'db>(
panic!("unmatching param kinds");
};
let const_ty = const_param_ty_query(db, param_id);
- substs.push(ctx.provided_type_like_const(const_ty, konst).into());
+ substs
+ .push(ctx.provided_type_like_const(*type_ref, const_ty, konst).into());
args.next();
params.next();
} else {
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 25c2df0d9f..2c6c7ed9a5 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -36,7 +36,7 @@ use stdx::impl_from;
use triomphe::Arc;
use crate::{
- all_super_traits,
+ Span, all_super_traits,
db::HirDatabase,
infer::{InferenceContext, unify::InferenceTable},
lower::GenericPredicates,
@@ -65,6 +65,8 @@ pub struct MethodResolutionContext<'a, 'db> {
pub traits_in_scope: &'a FxHashSet<TraitId>,
pub edition: Edition,
pub features: &'a UnstableFeatures,
+ pub call_span: Span,
+ pub receiver_span: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)]
@@ -134,7 +136,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
receiver: ExprId,
call_expr: ExprId,
) -> Result<(MethodCallee<'db>, bool), MethodError<'db>> {
- let (pick, is_visible) = match self.lookup_probe(name, self_ty) {
+ let (pick, is_visible) = match self.lookup_probe(call_expr, receiver, name, self_ty) {
Ok(it) => (it, true),
Err(MethodError::PrivateMatch(it)) => {
// FIXME: Report error.
@@ -159,10 +161,12 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
#[instrument(level = "debug", skip(self))]
pub(crate) fn lookup_probe(
&self,
+ call_expr: ExprId,
+ receiver: ExprId,
method_name: Name,
self_ty: Ty<'db>,
) -> probe::PickResult<'db> {
- self.with_method_resolution(|ctx| {
+ self.with_method_resolution(call_expr.into(), receiver.into(), |ctx| {
let pick = ctx.probe_for_name(probe::Mode::MethodCall, method_name, self_ty)?;
Ok(pick)
})
@@ -170,6 +174,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
pub(crate) fn with_method_resolution<R>(
&self,
+ call_span: Span,
+ receiver_span: Span,
f: impl FnOnce(&MethodResolutionContext<'_, 'db>) -> R,
) -> R {
let traits_in_scope = self.get_traits_in_scope();
@@ -184,6 +190,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
traits_in_scope,
edition: self.edition,
features: self.features,
+ call_span,
+ receiver_span,
};
f(&ctx)
}
@@ -240,7 +248,7 @@ impl<'db> InferenceTable<'db> {
// FIXME: We should stop passing `None` for the failure case
// when probing for call exprs. I.e. `opt_rhs_ty` should always
// be set when it needs to be.
- self.next_var_for_param(param_id)
+ self.var_for_def(param_id, cause.span())
}
}
},
@@ -248,7 +256,7 @@ impl<'db> InferenceTable<'db> {
let obligation = Obligation::new(
self.interner(),
- cause,
+ cause.clone(),
self.param_env,
TraitRef::new_from_args(self.interner(), trait_def_id.into(), args),
);
@@ -291,9 +299,11 @@ impl<'db> InferenceTable<'db> {
// with bound regions.
let fn_sig =
self.db.callable_item_signature(method_item.into()).instantiate(interner, args);
- let fn_sig = self
- .infer_ctxt
- .instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, fn_sig);
+ let fn_sig = self.infer_ctxt.instantiate_binder_with_fresh_vars(
+ cause.span(),
+ BoundRegionConversionTime::FnCall,
+ fn_sig,
+ );
// Register obligations for the parameters. This will include the
// `Self` parameter, which in turn has a bound of the main trait,
diff --git a/crates/hir-ty/src/method_resolution/confirm.rs b/crates/hir-ty/src/method_resolution/confirm.rs
index 3bdef44dd3..a29e3db18d 100644
--- a/crates/hir-ty/src/method_resolution/confirm.rs
+++ b/crates/hir-ty/src/method_resolution/confirm.rs
@@ -5,6 +5,7 @@ use hir_def::{
FunctionId, GenericDefId, GenericParamId, ItemContainerId, TraitId,
expr_store::path::{GenericArg as HirGenericArg, GenericArgs as HirGenericArgs},
hir::{ExprId, generics::GenericParamDataRef},
+ type_ref::TypeRefId,
};
use rustc_type_ir::{
TypeFoldable,
@@ -15,7 +16,7 @@ use tracing::debug;
use crate::{
Adjust, Adjustment, AutoBorrow, IncorrectGenericsLenKind, InferenceDiagnostic,
- LifetimeElisionKind, PointerCast,
+ LifetimeElisionKind, PointerCast, Span,
db::HirDatabase,
infer::{AllowTwoPhase, AutoBorrowMutability, InferenceContext, TypeMismatch},
lower::{
@@ -190,7 +191,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
self.ctx.table.register_infer_ok(autoderef.adjust_steps_as_infer_ok());
match pick.autoref_or_ptr_adjustment {
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
- let region = self.infcx().next_region_var();
+ let region = self.infcx().next_region_var(self.expr.into());
// Type we're wrapping in a reference, used later for unsizing
let base_ty = target;
@@ -254,7 +255,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
) -> GenericArgs<'db> {
match pick.kind {
probe::InherentImplPick(impl_def_id) => {
- self.infcx().fresh_args_for_item(impl_def_id.into())
+ self.infcx().fresh_args_for_item(self.expr.into(), impl_def_id.into())
}
probe::ObjectPick(trait_def_id) => {
@@ -296,7 +297,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
// the process we will unify the transformed-self-type
// of the method with the actual type in order to
// unify some of these variables.
- self.infcx().fresh_args_for_item(trait_def_id.into())
+ self.infcx().fresh_args_for_item(self.expr.into(), trait_def_id.into())
}
probe::WhereClausePick(poly_trait_ref) => {
@@ -400,7 +401,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
let GenericParamId::ConstParamId(const_id) = param_id else {
unreachable!("non-const param ID for const param");
};
- let const_ty = self.ctx.db.const_param_ty_ns(const_id);
+ let const_ty = self.ctx.db.const_param_ty(const_id);
self.ctx.make_body_const(*konst, const_ty).into()
}
_ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
@@ -409,12 +410,15 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
fn provided_type_like_const(
&mut self,
+ type_ref: TypeRefId,
const_ty: Ty<'db>,
arg: TypeLikeConst<'_>,
) -> Const<'db> {
match arg {
- TypeLikeConst::Path(path) => self.ctx.make_path_as_body_const(path, const_ty),
- TypeLikeConst::Infer => self.ctx.table.next_const_var(),
+ TypeLikeConst::Path(path) => {
+ self.ctx.make_path_as_body_const(type_ref, path, const_ty)
+ }
+ TypeLikeConst::Infer => self.ctx.table.next_const_var(Span::Dummy),
}
}
@@ -428,7 +432,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
) -> GenericArg<'db> {
// Always create an inference var, even when `infer_args == false`. This helps with diagnostics,
// and I think it's also required in the presence of `impl Trait` (that must be inferred).
- self.ctx.table.next_var_for_param(param_id)
+ self.ctx.table.var_for_def(param_id, Span::Dummy)
}
fn parent_arg(&mut self, param_idx: u32, _param_id: GenericParamId) -> GenericArg<'db> {
@@ -609,6 +613,10 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
where
T: TypeFoldable<DbInterner<'db>> + Copy,
{
- self.infcx().instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, value)
+ self.infcx().instantiate_binder_with_fresh_vars(
+ self.expr.into(),
+ BoundRegionConversionTime::FnCall,
+ value,
+ )
}
}
diff --git a/crates/hir-ty/src/method_resolution/probe.rs b/crates/hir-ty/src/method_resolution/probe.rs
index afdc62183e..8a28b16724 100644
--- a/crates/hir-ty/src/method_resolution/probe.rs
+++ b/crates/hir-ty/src/method_resolution/probe.rs
@@ -284,7 +284,8 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> {
// special handling for this "trivial case" is a good idea.
let infcx = self.infcx;
- let (self_ty, var_values) = infcx.instantiate_canonical(&query_input);
+ let (self_ty, var_values) =
+ infcx.instantiate_canonical(self.call_span, &query_input);
debug!(?self_ty, ?query_input, "probe_op: Mode::Path");
let prev_opaque_entries =
self.infcx.inner.borrow_mut().opaque_types().num_entries();
@@ -380,7 +381,8 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> {
// chain to support recursive calls. We do error if the final
// infer var is not an opaque.
let infcx = self.infcx;
- let (self_ty, inference_vars) = infcx.instantiate_canonical(self_ty);
+ let (self_ty, inference_vars) =
+ infcx.instantiate_canonical(self.receiver_span, self_ty);
let prev_opaque_entries = infcx.inner.borrow_mut().opaque_types().num_entries();
let self_ty_is_opaque = |ty: Ty<'_>| {
@@ -921,7 +923,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
// will still match the original object type, but it won't pollute our
// type variables in any form, so just do that!
let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) =
- self.infcx().instantiate_canonical(self_ty);
+ self.infcx().instantiate_canonical(self.ctx.call_span, self_ty);
self.assemble_inherent_candidates_from_object(generalized_self_ty);
self.assemble_inherent_impl_candidates_for_type(
@@ -1117,7 +1119,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
#[instrument(level = "debug", skip(self))]
fn assemble_extension_candidates_for_trait(&mut self, trait_def_id: TraitId) {
- let trait_args = self.infcx().fresh_args_for_item(trait_def_id.into());
+ let trait_args = self.infcx().fresh_args_for_item(self.ctx.call_span, trait_def_id.into());
let trait_ref = TraitRef::new_from_args(self.interner(), trait_def_id.into(), trait_args);
self.with_trait_item(trait_def_id, |this, item| {
@@ -1510,6 +1512,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
}
TraitCandidate(trait_ref) => self.infcx().probe(|_| {
let trait_ref = self.infcx().instantiate_binder_with_fresh_vars(
+ self.ctx.call_span,
BoundRegionConversionTime::FnCall,
trait_ref,
);
@@ -1574,7 +1577,8 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
match probe.kind {
InherentImplCandidate { impl_def_id, .. } => {
- let impl_args = self.infcx().fresh_args_for_item(impl_def_id.into());
+ let impl_args =
+ self.infcx().fresh_args_for_item(self.ctx.call_span, impl_def_id.into());
let impl_ty =
self.db().impl_self_ty(impl_def_id).instantiate(self.interner(), impl_args);
(xform_self_ty, xform_ret_ty) =
@@ -1632,6 +1636,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
}
let trait_ref = self.infcx().instantiate_binder_with_fresh_vars(
+ self.ctx.call_span,
BoundRegionConversionTime::FnCall,
poly_trait_ref,
);
@@ -1667,6 +1672,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
}
ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => {
let trait_ref = self.infcx().instantiate_binder_with_fresh_vars(
+ self.ctx.call_span,
BoundRegionConversionTime::FnCall,
poly_trait_ref,
);
@@ -2029,8 +2035,12 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
// In general, during probe we erase regions.
Region::new_erased(self.interner()).into()
}
- GenericParamId::TypeParamId(_) => self.infcx().next_ty_var().into(),
- GenericParamId::ConstParamId(_) => self.infcx().next_const_var().into(),
+ GenericParamId::TypeParamId(_) => {
+ self.infcx().next_ty_var(self.ctx.call_span).into()
+ }
+ GenericParamId::ConstParamId(_) => {
+ self.infcx().next_const_var(self.ctx.call_span).into()
+ }
}
}
},
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index b935a6ed32..49fb6f5305 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -581,7 +581,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
ParamConst { id: p, index },
)
.store(),
- ty: self.db.const_param_ty_ns(p).store(),
+ ty: self.db.const_param_ty(p).store(),
},
span: None,
}),
diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 68b1c8b3b6..03c608f4b2 100644
--- a/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -132,7 +132,7 @@ impl<'db> MirLowerCtx<'_, 'db> {
.into(),
);
Ok(match &self.store[pattern] {
- Pat::Missing => return Err(MirLowerError::IncompletePattern),
+ Pat::Missing | Pat::Rest => return Err(MirLowerError::IncompletePattern),
Pat::Wild => (current, current_else),
Pat::Tuple { args, ellipsis } => {
let subst = match self.infer.pat_ty(pattern).kind() {
diff --git a/crates/hir-ty/src/next_solver/format_proof_tree.rs b/crates/hir-ty/src/next_solver/format_proof_tree.rs
index 66da6d5400..4b2f66a17d 100644
--- a/crates/hir-ty/src/next_solver/format_proof_tree.rs
+++ b/crates/hir-ty/src/next_solver/format_proof_tree.rs
@@ -3,7 +3,7 @@ use serde_derive::{Deserialize, Serialize};
use crate::next_solver::inspect::{InspectCandidate, InspectGoal};
use crate::next_solver::{AnyImplId, infer::InferCtxt};
-use crate::next_solver::{DbInterner, Span};
+use crate::{Span, next_solver::DbInterner};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProofTreeData {
@@ -59,7 +59,7 @@ impl<'a, 'db> ProofTreeSerializer<'a, 'db> {
let mut nested = Vec::new();
self.infcx.probe(|_| {
- for nested_goal in candidate.instantiate_nested_goals() {
+ for nested_goal in candidate.instantiate_nested_goals(Span::Dummy) {
nested.push(self.serialize_goal(&nested_goal));
}
});
diff --git a/crates/hir-ty/src/next_solver/fulfill.rs b/crates/hir-ty/src/next_solver/fulfill.rs
index cd0cb59760..ba9cd39d44 100644
--- a/crates/hir-ty/src/next_solver/fulfill.rs
+++ b/crates/hir-ty/src/next_solver/fulfill.rs
@@ -9,17 +9,20 @@ use rustc_next_trait_solver::{
};
use rustc_type_ir::{
Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
- inherent::{IntoKind, Span as _},
+ inherent::IntoKind,
solve::{Certainty, NoSolution},
};
-use crate::next_solver::{
- DbInterner, SolverContext, SolverDefId, Span, Ty, TyKind, TypingMode,
- infer::{
- InferCtxt,
- traits::{PredicateObligation, PredicateObligations},
+use crate::{
+ Span,
+ next_solver::{
+ DbInterner, SolverContext, SolverDefId, Ty, TyKind, TypingMode,
+ infer::{
+ InferCtxt,
+ traits::{PredicateObligation, PredicateObligations},
+ },
+ inspect::ProofTreeVisitor,
},
- inspect::ProofTreeVisitor,
};
type PendingObligations<'db> =
@@ -97,7 +100,7 @@ impl<'db> ObligationStorage<'db> {
let goal = o.as_goal();
let result = <&SolverContext<'db>>::from(infcx).evaluate_root_goal(
goal,
- Span::dummy(),
+ o.cause.span(),
stalled_on.take(),
);
matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. }))
@@ -169,7 +172,9 @@ impl<'db> FulfillmentCtxt<'db> {
let goal = obligation.as_goal();
let delegate = <&SolverContext<'db>>::from(infcx);
- if let Some(certainty) = delegate.compute_goal_fast_path(goal, Span::dummy()) {
+ if let Some(certainty) =
+ delegate.compute_goal_fast_path(goal, obligation.cause.span())
+ {
match certainty {
Certainty::Yes => {}
Certainty::Maybe { .. } => {
@@ -179,9 +184,11 @@ impl<'db> FulfillmentCtxt<'db> {
continue;
}
- let result = delegate.evaluate_root_goal(goal, Span::dummy(), stalled_on);
+ let result = delegate.evaluate_root_goal(goal, obligation.cause.span(), stalled_on);
infcx.inspect_evaluated_obligation(&obligation, &result, || {
- Some(delegate.evaluate_root_goal_for_proof_tree(goal, Span::dummy()).1)
+ Some(
+ delegate.evaluate_root_goal_for_proof_tree(goal, obligation.cause.span()).1,
+ )
});
let GoalEvaluation { goal: _, certainty, has_changed, stalled_on } = match result {
Ok(result) => result,
@@ -259,6 +266,7 @@ impl<'db> FulfillmentCtxt<'db> {
obl.as_goal(),
&mut StalledOnCoroutines {
stalled_coroutines,
+ span: obl.cause.span(),
cache: Default::default(),
},
)
@@ -280,12 +288,17 @@ impl<'db> FulfillmentCtxt<'db> {
/// so we want to keep this visitor *precise* too.
pub struct StalledOnCoroutines<'a, 'db> {
pub stalled_coroutines: &'a [SolverDefId],
+ pub span: Span,
pub cache: FxHashSet<Ty<'db>>,
}
impl<'db> ProofTreeVisitor<'db> for StalledOnCoroutines<'_, 'db> {
type Result = ControlFlow<()>;
+ fn span(&self) -> Span {
+ self.span
+ }
+
fn visit_goal(&mut self, inspect_goal: &super::inspect::InspectGoal<'_, 'db>) -> Self::Result {
inspect_goal.goal().predicate.visit_with(self)?;
diff --git a/crates/hir-ty/src/next_solver/generic_arg.rs b/crates/hir-ty/src/next_solver/generic_arg.rs
index 72cf2f9f07..05955d060b 100644
--- a/crates/hir-ty/src/next_solver/generic_arg.rs
+++ b/crates/hir-ty/src/next_solver/generic_arg.rs
@@ -194,6 +194,25 @@ impl std::fmt::Debug for StoredGenericArg {
}
}
+impl<'db> TypeVisitable<DbInterner<'db>> for StoredGenericArg {
+ fn visit_with<V: TypeVisitor<DbInterner<'db>>>(&self, visitor: &mut V) -> V::Result {
+ self.as_ref().visit_with(visitor)
+ }
+}
+
+impl<'db> TypeFoldable<DbInterner<'db>> for StoredGenericArg {
+ fn try_fold_with<F: FallibleTypeFolder<DbInterner<'db>>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self.as_ref().try_fold_with(folder)?.store())
+ }
+
+ fn fold_with<F: TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
+ self.as_ref().fold_with(folder).store()
+ }
+}
+
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct GenericArg<'db> {
ptr: GenericArgImpl<'db>,
@@ -457,6 +476,25 @@ impl_foldable_for_interned_slice!(GenericArgs);
impl<'db> rustc_type_ir::inherent::GenericArg<DbInterner<'db>> for GenericArg<'db> {}
+impl<'db> TypeVisitable<DbInterner<'db>> for StoredGenericArgs {
+ fn visit_with<V: TypeVisitor<DbInterner<'db>>>(&self, visitor: &mut V) -> V::Result {
+ self.as_ref().visit_with(visitor)
+ }
+}
+
+impl<'db> TypeFoldable<DbInterner<'db>> for StoredGenericArgs {
+ fn try_fold_with<F: FallibleTypeFolder<DbInterner<'db>>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self.as_ref().try_fold_with(folder)?.store())
+ }
+
+ fn fold_with<F: TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
+ self.as_ref().fold_with(folder).store()
+ }
+}
+
impl<'db> GenericArgs<'db> {
/// Creates an `GenericArgs` for generic parameter definitions,
/// by calling closures to obtain each kind.
diff --git a/crates/hir-ty/src/next_solver/infer/at.rs b/crates/hir-ty/src/next_solver/infer/at.rs
index dc0b584084..4784edf60f 100644
--- a/crates/hir-ty/src/next_solver/infer/at.rs
+++ b/crates/hir-ty/src/next_solver/infer/at.rs
@@ -28,13 +28,12 @@
use rustc_type_ir::{
FnSig, GenericArgKind, TypeFoldable, TypingMode, Variance,
error::ExpectedFound,
- inherent::Span as _,
relate::{Relate, TypeRelation, solver_relating::RelateExt},
};
use crate::next_solver::{
AliasTerm, AliasTy, Binder, Const, DbInterner, GenericArg, Goal, ParamEnv,
- PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, Predicate, Region, Span, Term,
+ PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, Predicate, Region, Term,
TraitRef, Ty,
fulfill::NextSolverError,
infer::relate::lattice::{LatticeOp, LatticeOpKind},
@@ -109,7 +108,7 @@ impl<'a, 'db> At<'a, 'db> {
expected,
Variance::Contravariant,
actual,
- Span::dummy(),
+ self.cause.span(),
)
.map(|goals| self.goals_to_obligations(goals))
}
@@ -125,7 +124,7 @@ impl<'a, 'db> At<'a, 'db> {
expected,
Variance::Covariant,
actual,
- Span::dummy(),
+ self.cause.span(),
)
.map(|goals| self.goals_to_obligations(goals))
}
@@ -141,7 +140,7 @@ impl<'a, 'db> At<'a, 'db> {
expected,
Variance::Invariant,
actual,
- Span::dummy(),
+ self.cause.span(),
)
.map(|goals| self.goals_to_obligations(goals))
}
diff --git a/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs b/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs
index 1738552a8e..bda418cf20 100644
--- a/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs
+++ b/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs
@@ -404,13 +404,17 @@ impl<'db> InferCtxt<'db> {
if kind.universe() != UniverseIndex::ROOT {
// A variable from inside a binder of the query. While ideally these shouldn't
// exist at all, we have to deal with them for now.
- self.instantiate_canonical_var(kind, var_values, |u| universe_map[u.as_usize()])
+ self.instantiate_canonical_var(cause.span(), kind, var_values, |u| {
+ universe_map[u.as_usize()]
+ })
} else if kind.is_existential() {
match opt_values[BoundVar::new(var_values.len())] {
Some(k) => k,
- None => self.instantiate_canonical_var(kind, var_values, |u| {
- universe_map[u.as_usize()]
- }),
+ None => {
+ self.instantiate_canonical_var(cause.span(), kind, var_values, |u| {
+ universe_map[u.as_usize()]
+ })
+ }
}
} else {
// For placeholders which were already part of the input, we simply map this
diff --git a/crates/hir-ty/src/next_solver/infer/canonical/mod.rs b/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
index 1fefc0f265..a5e29e7836 100644
--- a/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
@@ -21,10 +21,13 @@
//!
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
-use crate::next_solver::{
- ArgOutlivesPredicate, Canonical, CanonicalVarValues, Const, DbInterner, GenericArg,
- OpaqueTypeKey, PlaceholderConst, PlaceholderRegion, PlaceholderType, Region, Ty, TyKind,
- infer::InferCtxt,
+use crate::{
+ Span,
+ next_solver::{
+ ArgOutlivesPredicate, Canonical, CanonicalVarValues, Const, DbInterner, GenericArg,
+ OpaqueTypeKey, PlaceholderConst, PlaceholderRegion, PlaceholderType, Region, Ty, TyKind,
+ infer::InferCtxt,
+ },
};
use instantiate::CanonicalExt;
use macros::{TypeFoldable, TypeVisitable};
@@ -50,6 +53,7 @@ impl<'db> InferCtxt<'db> {
/// for each of the canonical inputs to your query.
pub fn instantiate_canonical<T>(
&self,
+ span: Span,
canonical: &Canonical<'db, T>,
) -> (T, CanonicalVarValues<'db>)
where
@@ -71,7 +75,9 @@ impl<'db> InferCtxt<'db> {
let var_values = CanonicalVarValues::instantiate(
self.interner,
canonical.var_kinds,
- |var_values, info| self.instantiate_canonical_var(info, var_values, |ui| universes[ui]),
+ |var_values, info| {
+ self.instantiate_canonical_var(span, info, var_values, |ui| universes[ui])
+ },
);
let result = canonical.instantiate(self.interner, &var_values);
(result, var_values)
@@ -87,13 +93,14 @@ impl<'db> InferCtxt<'db> {
/// We should somehow deduplicate all of this.
pub fn instantiate_canonical_var(
&self,
+ span: Span,
cv_info: CanonicalVarKind<DbInterner<'db>>,
previous_var_values: &[GenericArg<'db>],
universe_map: impl Fn(UniverseIndex) -> UniverseIndex,
) -> GenericArg<'db> {
match cv_info {
CanonicalVarKind::Ty { ui, sub_root } => {
- let vid = self.next_ty_var_id_in_universe(universe_map(ui));
+ let vid = self.next_ty_var_id_in_universe(universe_map(ui), span);
// If this inference variable is related to an earlier variable
// via subtyping, we need to add that info to the inference context.
if let Some(prev) = previous_var_values.get(sub_root.as_usize()) {
@@ -117,7 +124,7 @@ impl<'db> InferCtxt<'db> {
}
CanonicalVarKind::Region(ui) => {
- self.next_region_var_in_universe(universe_map(ui)).into()
+ self.next_region_var_in_universe(universe_map(ui), span).into()
}
CanonicalVarKind::PlaceholderRegion(PlaceholderRegion { universe, bound, .. }) => {
@@ -126,7 +133,9 @@ impl<'db> InferCtxt<'db> {
Region::new_placeholder(self.interner, placeholder_mapped).into()
}
- CanonicalVarKind::Const(ui) => self.next_const_var_in_universe(universe_map(ui)).into(),
+ CanonicalVarKind::Const(ui) => {
+ self.next_const_var_in_universe(universe_map(ui), span).into()
+ }
CanonicalVarKind::PlaceholderConst(PlaceholderConst { universe, bound, .. }) => {
let universe_mapped = universe_map(universe);
let placeholder_mapped = PlaceholderConst::new(universe_mapped, bound);
diff --git a/crates/hir-ty/src/next_solver/infer/context.rs b/crates/hir-ty/src/next_solver/infer/context.rs
index 397986e2ed..9ea4665000 100644
--- a/crates/hir-ty/src/next_solver/infer/context.rs
+++ b/crates/hir-ty/src/next_solver/infer/context.rs
@@ -7,10 +7,13 @@ use rustc_type_ir::{
relate::combine::PredicateEmittingRelation,
};
-use crate::next_solver::{
- Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, Region,
- SolverDefId, Span, Ty, TyKind,
- infer::opaque_types::{OpaqueHiddenType, table::OpaqueTypeStorageEntries},
+use crate::{
+ Span,
+ next_solver::{
+ Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, Region,
+ SolverDefId, Ty, TyKind,
+ infer::opaque_types::{OpaqueHiddenType, table::OpaqueTypeStorageEntries},
+ },
};
use super::{BoundRegionConversionTime, InferCtxt, relate::RelateResult};
@@ -139,26 +142,30 @@ impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> {
}
fn next_ty_infer(&self) -> Ty<'db> {
- self.next_ty_var()
+ self.next_ty_var(Span::Dummy)
}
fn next_region_infer(&self) -> <Self::Interner as rustc_type_ir::Interner>::Region {
- self.next_region_var()
+ self.next_region_var(Span::Dummy)
}
fn next_const_infer(&self) -> Const<'db> {
- self.next_const_var()
+ self.next_const_var(Span::Dummy)
}
fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> {
- self.fresh_args_for_item(def_id)
+ self.fresh_args_for_item(Span::Dummy, def_id)
}
fn instantiate_binder_with_infer<T: TypeFoldable<DbInterner<'db>> + Clone>(
&self,
value: Binder<'db, T>,
) -> T {
- self.instantiate_binder_with_fresh_vars(BoundRegionConversionTime::HigherRankedType, value)
+ self.instantiate_binder_with_fresh_vars(
+ Span::Dummy,
+ BoundRegionConversionTime::HigherRankedType,
+ value,
+ )
}
fn enter_forall<T: TypeFoldable<DbInterner<'db>> + Clone, U>(
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs
index 1eacc295c9..f038c47a8b 100644
--- a/crates/hir-ty/src/next_solver/infer/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/mod.rs
@@ -28,16 +28,18 @@ use rustc_type_ir::{
use snapshot::undo_log::InferCtxtUndoLogs;
use tracing::{debug, instrument};
use traits::{ObligationCause, PredicateObligations};
-use type_variable::TypeVariableOrigin;
-use unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
+use unify_key::{ConstVariableValue, ConstVidKey};
pub use crate::next_solver::infer::traits::ObligationInspector;
-use crate::next_solver::{
- ArgOutlivesPredicate, BoundConst, BoundRegion, BoundTy, BoundVariableKind, Goal, Predicate,
- SolverContext,
- fold::BoundVarReplacerDelegate,
- infer::{at::ToTrace, select::EvaluationResult, traits::PredicateObligation},
- obligation_ctxt::ObligationCtxt,
+use crate::{
+ Span,
+ next_solver::{
+ ArgOutlivesPredicate, BoundConst, BoundRegion, BoundTy, BoundVariableKind, Goal, Predicate,
+ SolverContext,
+ fold::BoundVarReplacerDelegate,
+ infer::{at::ToTrace, select::EvaluationResult, traits::PredicateObligation},
+ obligation_ctxt::ObligationCtxt,
+ },
};
use super::{
@@ -364,13 +366,14 @@ impl<'db> InferCtxtBuilder<'db> {
/// (in other words, `S(C) = V`).
pub fn build_with_canonical<T>(
mut self,
+ span: Span,
input: &CanonicalQueryInput<'db, T>,
) -> (InferCtxt<'db>, T, CanonicalVarValues<'db>)
where
T: TypeFoldable<DbInterner<'db>>,
{
let infcx = self.build(input.typing_mode.0);
- let (value, args) = infcx.instantiate_canonical(&input.canonical);
+ let (value, args) = infcx.instantiate_canonical(span, &input.canonical);
(infcx, value, args)
}
@@ -427,12 +430,13 @@ impl<'db> InferCtxt<'db> {
))
}
- pub(crate) fn insert_type_vars<T>(&self, ty: T) -> T
+ pub(crate) fn insert_type_vars<T>(&self, ty: T, span: Span) -> T
where
T: TypeFoldable<DbInterner<'db>>,
{
struct Folder<'a, 'db> {
infcx: &'a InferCtxt<'db>,
+ span: Span,
}
impl<'db> TypeFolder<DbInterner<'db>> for Folder<'_, 'db> {
fn cx(&self) -> DbInterner<'db> {
@@ -444,7 +448,11 @@ impl<'db> InferCtxt<'db> {
return ty;
}
- if ty.is_ty_error() { self.infcx.next_ty_var() } else { ty.super_fold_with(self) }
+ if ty.is_ty_error() {
+ self.infcx.next_ty_var(self.span)
+ } else {
+ ty.super_fold_with(self)
+ }
}
fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
@@ -453,18 +461,18 @@ impl<'db> InferCtxt<'db> {
}
if ct.is_ct_error() {
- self.infcx.next_const_var()
+ self.infcx.next_const_var(self.span)
} else {
ct.super_fold_with(self)
}
}
fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
- if r.is_error() { self.infcx.next_region_var() } else { r }
+ if r.is_error() { self.infcx.next_region_var(self.span) } else { r }
}
}
- ty.fold_with(&mut Folder { infcx: self })
+ ty.fold_with(&mut Folder { infcx: self, span })
}
/// Evaluates whether the predicate can be satisfied in the given
@@ -737,80 +745,49 @@ impl<'db> InferCtxt<'db> {
self.inner.borrow_mut().type_variables().num_vars()
}
- pub fn next_var_for_param(&self, id: GenericParamId) -> GenericArg<'db> {
- match id {
- GenericParamId::TypeParamId(_) => self.next_ty_var().into(),
- GenericParamId::ConstParamId(_) => self.next_const_var().into(),
- GenericParamId::LifetimeParamId(_) => self.next_region_var().into(),
- }
+ pub fn next_ty_var(&self, span: Span) -> Ty<'db> {
+ let vid = self.next_ty_vid(span);
+ Ty::new_var(self.interner, vid)
}
- pub fn next_ty_var(&self) -> Ty<'db> {
- self.next_ty_var_with_origin(TypeVariableOrigin { param_def_id: None })
+ pub fn next_ty_vid(&self, span: Span) -> TyVid {
+ self.next_ty_var_id_in_universe(self.universe(), span)
}
- pub fn next_ty_vid(&self) -> TyVid {
- self.inner
- .borrow_mut()
- .type_variables()
- .new_var(self.universe(), TypeVariableOrigin { param_def_id: None })
+ pub fn next_ty_var_id_in_universe(&self, universe: UniverseIndex, span: Span) -> TyVid {
+ self.inner.borrow_mut().type_variables().new_var(universe, span)
}
- pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'db> {
- let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin);
+ pub fn next_ty_var_in_universe(&self, universe: UniverseIndex, span: Span) -> Ty<'db> {
+ let vid = self.next_ty_var_id_in_universe(universe, span);
Ty::new_var(self.interner, vid)
}
- pub fn next_ty_var_id_in_universe(&self, universe: UniverseIndex) -> TyVid {
- let origin = TypeVariableOrigin { param_def_id: None };
- self.inner.borrow_mut().type_variables().new_var(universe, origin)
- }
-
- pub fn next_ty_var_in_universe(&self, universe: UniverseIndex) -> Ty<'db> {
- let vid = self.next_ty_var_id_in_universe(universe);
- Ty::new_var(self.interner, vid)
+ pub fn next_const_var(&self, span: Span) -> Const<'db> {
+ let vid = self.next_const_vid(span);
+ Const::new_var(self.interner, vid)
}
- pub fn next_const_var(&self) -> Const<'db> {
- self.next_const_var_with_origin(ConstVariableOrigin {})
+ pub fn next_const_vid(&self, span: Span) -> ConstVid {
+ self.next_const_vid_in_universe(self.universe(), span)
}
- pub fn next_const_vid(&self) -> ConstVid {
+ pub fn next_const_vid_in_universe(&self, universe: UniverseIndex, span: Span) -> ConstVid {
self.inner
.borrow_mut()
.const_unification_table()
- .new_key(ConstVariableValue::Unknown {
- origin: ConstVariableOrigin {},
- universe: self.universe(),
- })
+ .new_key(ConstVariableValue::Unknown { span, universe })
.vid
}
- pub fn next_const_var_with_origin(&self, origin: ConstVariableOrigin) -> Const<'db> {
- let vid = self
- .inner
- .borrow_mut()
- .const_unification_table()
- .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
- .vid;
- Const::new_var(self.interner, vid)
- }
-
- pub fn next_const_var_in_universe(&self, universe: UniverseIndex) -> Const<'db> {
- let origin = ConstVariableOrigin {};
- let vid = self
- .inner
- .borrow_mut()
- .const_unification_table()
- .new_key(ConstVariableValue::Unknown { origin, universe })
- .vid;
+ pub fn next_const_var_in_universe(&self, universe: UniverseIndex, span: Span) -> Const<'db> {
+ let vid = self.next_const_vid_in_universe(universe, span);
Const::new_var(self.interner, vid)
}
pub fn next_int_var(&self) -> Ty<'db> {
- let next_int_var_id =
- self.inner.borrow_mut().int_unification_table().new_key(IntVarValue::Unknown);
- Ty::new_int_var(self.interner, next_int_var_id)
+ let vid = self.next_int_vid();
+ Ty::new_int_var(self.interner, vid)
}
pub fn next_int_vid(&self) -> IntVid {
@@ -828,27 +805,27 @@ impl<'db> InferCtxt<'db> {
/// Creates a fresh region variable with the next available index.
/// The variable will be created in the maximum universe created
/// thus far, allowing it to name any region created thus far.
- pub fn next_region_var(&self) -> Region<'db> {
- self.next_region_var_in_universe(self.universe())
+ pub fn next_region_var(&self, span: Span) -> Region<'db> {
+ self.next_region_var_in_universe(self.universe(), span)
}
- pub fn next_region_vid(&self) -> RegionVid {
- self.inner.borrow_mut().unwrap_region_constraints().new_region_var(self.universe())
+ pub fn next_region_vid(&self, span: Span) -> RegionVid {
+ self.inner.borrow_mut().unwrap_region_constraints().new_region_var(self.universe(), span)
}
/// Creates a fresh region variable with the next available index
/// in the given universe; typically, you can use
/// `next_region_var` and just use the maximal universe.
- pub fn next_region_var_in_universe(&self, universe: UniverseIndex) -> Region<'db> {
+ pub fn next_region_var_in_universe(&self, universe: UniverseIndex, span: Span) -> Region<'db> {
let region_var =
- self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe);
+ self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe, span);
Region::new_var(self.interner, region_var)
}
- pub fn next_term_var_of_kind(&self, term: Term<'db>) -> Term<'db> {
+ pub fn next_term_var_of_kind(&self, term: Term<'db>, span: Span) -> Term<'db> {
match term.kind() {
- TermKind::Ty(_) => self.next_ty_var().into(),
- TermKind::Const(_) => self.next_const_var().into(),
+ TermKind::Ty(_) => self.next_ty_var(span).into(),
+ TermKind::Const(_) => self.next_const_var(span).into(),
}
}
@@ -866,24 +843,12 @@ impl<'db> InferCtxt<'db> {
self.inner.borrow_mut().unwrap_region_constraints().num_region_vars()
}
- /// Just a convenient wrapper of `next_region_var` for using during NLL.
- #[instrument(skip(self), level = "debug")]
- pub fn next_nll_region_var(&self) -> Region<'db> {
- self.next_region_var()
- }
-
- /// Just a convenient wrapper of `next_region_var` for using during NLL.
- #[instrument(skip(self), level = "debug")]
- pub fn next_nll_region_var_in_universe(&self, universe: UniverseIndex) -> Region<'db> {
- self.next_region_var_in_universe(universe)
- }
-
- fn var_for_def(&self, id: GenericParamId) -> GenericArg<'db> {
+ pub fn var_for_def(&self, id: GenericParamId, span: Span) -> GenericArg<'db> {
match id {
GenericParamId::LifetimeParamId(_) => {
// Create a region inference variable for the given
// region parameter definition.
- self.next_region_var().into()
+ self.next_region_var(span).into()
}
GenericParamId::TypeParamId(_) => {
// Create a type inference variable for the given
@@ -894,41 +859,27 @@ impl<'db> InferCtxt<'db> {
// used in a path such as `Foo::<T, U>::new()` will
// use an inference variable for `C` with `[T, U]`
// as the generic parameters for the default, `(T, U)`.
- let ty_var_id = self
- .inner
- .borrow_mut()
- .type_variables()
- .new_var(self.universe(), TypeVariableOrigin { param_def_id: None });
-
- Ty::new_var(self.interner, ty_var_id).into()
- }
- GenericParamId::ConstParamId(_) => {
- let origin = ConstVariableOrigin {};
- let const_var_id = self
- .inner
- .borrow_mut()
- .const_unification_table()
- .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
- .vid;
- Const::new_var(self.interner, const_var_id).into()
+ self.next_ty_var(span).into()
}
+ GenericParamId::ConstParamId(_) => self.next_const_var(span).into(),
}
}
/// Given a set of generics defined on a type or impl, returns the generic parameters mapping
/// each type/region parameter to a fresh inference variable.
- pub fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> {
- GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind))
+ pub fn fresh_args_for_item(&self, span: Span, def_id: SolverDefId) -> GenericArgs<'db> {
+ GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind, span))
}
/// Like `fresh_args_for_item()`, but first uses the args from `first`.
pub fn fill_rest_fresh_args(
&self,
+ span: Span,
def_id: SolverDefId,
first: impl IntoIterator<Item = GenericArg<'db>>,
) -> GenericArgs<'db> {
GenericArgs::fill_rest(self.interner, def_id, first, |_index, kind, _| {
- self.var_for_def(kind)
+ self.var_for_def(kind, span)
})
}
@@ -995,8 +946,8 @@ impl<'db> InferCtxt<'db> {
use self::type_variable::TypeVariableValue;
match self.inner.borrow_mut().type_variables().probe(vid) {
- TypeVariableValue::Known { value } => Ok(value),
- TypeVariableValue::Unknown { universe } => Err(universe),
+ TypeVariableValue::Known { value, .. } => Ok(value),
+ TypeVariableValue::Unknown { universe, .. } => Err(universe),
}
}
@@ -1064,6 +1015,13 @@ impl<'db> InferCtxt<'db> {
}
}
+ pub fn shallow_resolve_term(&self, term: Term<'db>) -> Term<'db> {
+ match term.kind() {
+ TermKind::Ty(ty) => self.shallow_resolve(ty).into(),
+ TermKind::Const(ct) => self.shallow_resolve_const(ct).into(),
+ }
+ }
+
pub fn root_var(&self, var: TyVid) -> TyVid {
self.inner.borrow_mut().type_variables().root_var(var)
}
@@ -1141,7 +1099,22 @@ impl<'db> InferCtxt<'db> {
pub fn probe_const_var(&self, vid: ConstVid) -> Result<Const<'db>, UniverseIndex> {
match self.inner.borrow_mut().const_unification_table().probe_value(vid) {
ConstVariableValue::Known { value } => Ok(value),
- ConstVariableValue::Unknown { origin: _, universe } => Err(universe),
+ ConstVariableValue::Unknown { span: _, universe } => Err(universe),
+ }
+ }
+
+ /// Returns the span of the type variable identified by `vid`.
+ ///
+ /// No attempt is made to resolve `vid` to its root variable.
+ pub fn type_var_span(&self, vid: TyVid) -> Span {
+ self.inner.borrow_mut().type_variables().var_span(vid)
+ }
+
+ /// Returns the span of the const variable identified by `vid`
+ pub fn const_var_span(&self, vid: ConstVid) -> Option<Span> {
+ match self.inner.borrow_mut().const_unification_table().probe_value(vid) {
+ ConstVariableValue::Known { .. } => None,
+ ConstVariableValue::Unknown { span, .. } => Some(span),
}
}
@@ -1154,6 +1127,7 @@ impl<'db> InferCtxt<'db> {
// use [`InferCtxt::enter_forall`] instead.
pub fn instantiate_binder_with_fresh_vars<T>(
&self,
+ span: Span,
_lbrct: BoundRegionConversionTime,
value: Binder<'db, T>,
) -> T
@@ -1169,9 +1143,9 @@ impl<'db> InferCtxt<'db> {
for bound_var_kind in bound_vars {
let arg: GenericArg<'db> = match bound_var_kind {
- BoundVariableKind::Ty(_) => self.next_ty_var().into(),
- BoundVariableKind::Region(_) => self.next_region_var().into(),
- BoundVariableKind::Const => self.next_const_var().into(),
+ BoundVariableKind::Ty(_) => self.next_ty_var(span).into(),
+ BoundVariableKind::Region(_) => self.next_region_var(span).into(),
+ BoundVariableKind::Const => self.next_const_var(span).into(),
};
args.push(arg);
}
diff --git a/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs b/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs
index 7bb39519f5..544d79daf0 100644
--- a/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs
@@ -15,9 +15,12 @@ use self::CombineMapType::*;
use self::UndoLog::*;
use super::MemberConstraint;
use super::unify_key::RegionVidKey;
-use crate::next_solver::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot};
use crate::next_solver::infer::unify_key::RegionVariableValue;
use crate::next_solver::{AliasTy, Binder, DbInterner, ParamTy, PlaceholderType, Region, Ty};
+use crate::{
+ Span,
+ next_solver::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot},
+};
#[derive(Debug, Clone, Default)]
pub struct RegionConstraintStorage<'db> {
@@ -281,6 +284,7 @@ pub struct RegionVariableInfo {
// This would be currently unsound as it would cause us to drop the universe
// changes in `lexical_region_resolve`.
pub universe: UniverseIndex,
+ pub span: Span,
}
pub(crate) struct RegionSnapshot {
@@ -350,8 +354,12 @@ impl<'db> RegionConstraintCollector<'db, '_> {
*any_unifications = false;
// Manually inlined `self.unification_table_mut()` as `self` is used in the closure.
ut::UnificationTable::with_log(&mut self.storage.unification_table, &mut self.undo_log)
- .reset_unifications(|key| RegionVariableValue::Unknown {
- universe: self.storage.var_infos[key.vid].universe,
+ .reset_unifications(|key| {
+ let var_info = &self.storage.var_infos[key.vid];
+ RegionVariableValue::Unknown {
+ universe: var_info.universe,
+ span: var_info.span,
+ }
});
}
@@ -372,10 +380,11 @@ impl<'db> RegionConstraintCollector<'db, '_> {
self.storage.any_unifications = snapshot.any_unifications;
}
- pub(super) fn new_region_var(&mut self, universe: UniverseIndex) -> RegionVid {
- let vid = self.storage.var_infos.push(RegionVariableInfo { universe });
+ pub(super) fn new_region_var(&mut self, universe: UniverseIndex, span: Span) -> RegionVid {
+ let vid = self.storage.var_infos.push(RegionVariableInfo { universe, span });
- let u_vid = self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe });
+ let u_vid =
+ self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe, span });
assert_eq!(vid, u_vid.vid);
self.undo_log.push(AddVar(vid));
debug!("created new region variable {:?} in {:?}", vid, universe);
@@ -409,7 +418,7 @@ impl<'db> RegionConstraintCollector<'db, '_> {
debug!("make_eqregion: unifying {:?} with {:?}", vid, b);
if self
.unification_table_mut()
- .unify_var_value(vid, RegionVariableValue::Known { value: b })
+ .unify_var_value(vid, RegionVariableValue::Known { value: b, span: None })
.is_ok()
{
self.storage.any_unifications = true;
@@ -419,7 +428,7 @@ impl<'db> RegionConstraintCollector<'db, '_> {
debug!("make_eqregion: unifying {:?} with {:?}", a, vid);
if self
.unification_table_mut()
- .unify_var_value(vid, RegionVariableValue::Known { value: a })
+ .unify_var_value(vid, RegionVariableValue::Known { value: a, span: None })
.is_ok()
{
self.storage.any_unifications = true;
@@ -459,6 +468,7 @@ impl<'db> RegionConstraintCollector<'db, '_> {
pub(super) fn lub_regions(
&mut self,
db: DbInterner<'db>,
+ origin: Span,
a: Region<'db>,
b: Region<'db>,
) -> Region<'db> {
@@ -470,13 +480,14 @@ impl<'db> RegionConstraintCollector<'db, '_> {
} else if a == b {
a // LUB(a,a) = a
} else {
- self.combine_vars(db, Lub, a, b)
+ self.combine_vars(db, Lub, a, b, origin)
}
}
pub(super) fn glb_regions(
&mut self,
db: DbInterner<'db>,
+ origin: Span,
a: Region<'db>,
b: Region<'db>,
) -> Region<'db> {
@@ -490,7 +501,7 @@ impl<'db> RegionConstraintCollector<'db, '_> {
} else if a == b {
a // GLB(a,a) = a
} else {
- self.combine_vars(db, Glb, a, b)
+ self.combine_vars(db, Glb, a, b, origin)
}
}
@@ -504,15 +515,15 @@ impl<'db> RegionConstraintCollector<'db, '_> {
let mut ut = self.unification_table_mut();
let root_vid = ut.find(vid).vid;
match ut.probe_value(root_vid) {
- RegionVariableValue::Known { value } => value,
+ RegionVariableValue::Known { value, .. } => value,
RegionVariableValue::Unknown { .. } => Region::new_var(cx, root_vid),
}
}
pub fn probe_value(&mut self, vid: RegionVid) -> Result<Region<'db>, UniverseIndex> {
match self.unification_table_mut().probe_value(vid) {
- RegionVariableValue::Known { value } => Ok(value),
- RegionVariableValue::Unknown { universe } => Err(universe),
+ RegionVariableValue::Known { value, .. } => Ok(value),
+ RegionVariableValue::Unknown { universe, .. } => Err(universe),
}
}
@@ -529,6 +540,7 @@ impl<'db> RegionConstraintCollector<'db, '_> {
t: CombineMapType,
a: Region<'db>,
b: Region<'db>,
+ origin: Span,
) -> Region<'db> {
let vars = TwoRegions { a, b };
if let Some(c) = self.combine_map(t.clone()).get(&vars) {
@@ -537,7 +549,7 @@ impl<'db> RegionConstraintCollector<'db, '_> {
let a_universe = self.universe(a);
let b_universe = self.universe(b);
let c_universe = cmp::max(a_universe, b_universe);
- let c = self.new_region_var(c_universe);
+ let c = self.new_region_var(c_universe, origin);
self.combine_map(t.clone()).insert(vars.clone(), c);
self.undo_log.push(AddCombination(t.clone(), vars));
let new_r = Region::new_var(cx, c);
@@ -567,8 +579,15 @@ impl<'db> RegionConstraintCollector<'db, '_> {
}
}
- pub fn vars_since_snapshot(&self, value_count: usize) -> Range<RegionVid> {
- RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len())
+ pub fn vars_since_snapshot(&self, value_count: usize) -> (Range<RegionVid>, Vec<Span>) {
+ let range =
+ RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len());
+ (
+ range.clone(),
+ (range.start.as_usize()..range.end.as_usize())
+ .map(|index| self.storage.var_infos[RegionVid::from_usize(index)].span)
+ .collect(),
+ )
}
/// See `InferCtxt::region_constraints_added_in_snapshot`.
diff --git a/crates/hir-ty/src/next_solver/infer/relate/generalize.rs b/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
index d621dd4906..e55e43a4cd 100644
--- a/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
+++ b/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
@@ -16,7 +16,6 @@ use tracing::{debug, instrument, warn};
use super::{
PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
};
-use crate::next_solver::infer::unify_key::ConstVariableValue;
use crate::next_solver::infer::{InferCtxt, relate};
use crate::next_solver::util::MaxUniverse;
use crate::next_solver::{
@@ -24,6 +23,7 @@ use crate::next_solver::{
Term, TermVid, Ty, TyKind, TypingMode, UnevaluatedConst,
};
use crate::next_solver::{GenericArgs, infer::type_variable::TypeVariableValue};
+use crate::{Span, next_solver::infer::unify_key::ConstVariableValue};
impl<'db> InferCtxt<'db> {
/// The idea is that we should ensure that the type variable `target_vid`
@@ -60,6 +60,7 @@ impl<'db> InferCtxt<'db> {
// `?1 <: ?3`.
let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self
.generalize(
+ relation.span(),
relation.structurally_relate_aliases(),
target_vid,
instantiation_variance,
@@ -179,6 +180,7 @@ impl<'db> InferCtxt<'db> {
// constants and generic expressions are not yet handled correctly.
let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = self
.generalize(
+ relation.span(),
relation.structurally_relate_aliases(),
target_vid,
Variance::Invariant,
@@ -220,6 +222,7 @@ impl<'db> InferCtxt<'db> {
/// This checks for cycles -- that is, whether `source_term` references `target_vid`.
fn generalize<T: Into<Term<'db>> + Relate<DbInterner<'db>>>(
&self,
+ span: Span,
structurally_relate_aliases: StructurallyRelateAliases,
target_vid: impl Into<TermVid>,
ambient_variance: Variance,
@@ -238,6 +241,7 @@ impl<'db> InferCtxt<'db> {
let mut generalizer = Generalizer {
infcx: self,
+ span,
structurally_relate_aliases,
root_vid,
for_universe,
@@ -270,6 +274,8 @@ impl<'db> InferCtxt<'db> {
struct Generalizer<'me, 'db> {
infcx: &'me InferCtxt<'db>,
+ span: Span,
+
/// Whether aliases should be related structurally. If not, we have to
/// be careful when generalizing aliases.
structurally_relate_aliases: StructurallyRelateAliases,
@@ -318,7 +324,7 @@ impl<'db> Generalizer<'_, 'db> {
/// if we're currently in a bivariant context.
fn next_ty_var_for_alias(&mut self) -> Ty<'db> {
self.has_unconstrained_ty_var |= self.ambient_variance == Variance::Bivariant;
- self.infcx.next_ty_var_in_universe(self.for_universe)
+ self.infcx.next_ty_var_in_universe(self.for_universe, self.span)
}
/// An occurs check failure inside of an alias does not mean
@@ -453,11 +459,11 @@ impl<'db> TypeRelation<DbInterner<'db>> for Generalizer<'_, 'db> {
} else {
let probe = inner.type_variables().probe(vid);
match probe {
- TypeVariableValue::Known { value: u } => {
+ TypeVariableValue::Known { value: u, .. } => {
drop(inner);
self.relate(u, u)
}
- TypeVariableValue::Unknown { universe } => {
+ TypeVariableValue::Unknown { universe, .. } => {
match self.ambient_variance {
// Invariant: no need to make a fresh type variable
// if we can name the universe.
@@ -477,7 +483,7 @@ impl<'db> TypeRelation<DbInterner<'db>> for Generalizer<'_, 'db> {
Variance::Covariant | Variance::Contravariant => (),
}
- let origin = inner.type_variables().var_origin(vid);
+ let origin = inner.type_variables().var_span(vid);
let new_var_id =
inner.type_variables().new_var(self.for_universe, origin);
// If we're in the new solver and create a new inference
@@ -579,7 +585,7 @@ impl<'db> TypeRelation<DbInterner<'db>> for Generalizer<'_, 'db> {
}
}
- Ok(self.infcx.next_region_var_in_universe(self.for_universe))
+ Ok(self.infcx.next_region_var_in_universe(self.for_universe, self.span))
}
#[instrument(level = "debug", skip(self, c2), ret)]
@@ -605,13 +611,13 @@ impl<'db> TypeRelation<DbInterner<'db>> for Generalizer<'_, 'db> {
drop(inner);
self.relate(u, u)
}
- ConstVariableValue::Unknown { origin, universe } => {
+ ConstVariableValue::Unknown { span, universe } => {
if self.for_universe.can_name(universe) {
Ok(c)
} else {
let new_var_id = variable_table
.new_key(ConstVariableValue::Unknown {
- origin,
+ span,
universe: self.for_universe,
})
.vid;
diff --git a/crates/hir-ty/src/next_solver/infer/relate/lattice.rs b/crates/hir-ty/src/next_solver/infer/relate/lattice.rs
index 3522827a9e..0443dbd814 100644
--- a/crates/hir-ty/src/next_solver/infer/relate/lattice.rs
+++ b/crates/hir-ty/src/next_solver/infer/relate/lattice.rs
@@ -19,7 +19,7 @@
use rustc_type_ir::{
AliasRelationDirection, Interner, TypeVisitableExt, Upcast, Variance,
- inherent::{IntoKind, Span as _},
+ inherent::IntoKind,
relate::{
Relate, StructurallyRelateAliases, TypeRelation, VarianceDiagInfo,
combine::{
@@ -28,13 +28,16 @@ use rustc_type_ir::{
},
};
-use crate::next_solver::{
- AliasTy, Binder, Const, DbInterner, GenericArgs, Goal, ParamEnv, Predicate, PredicateKind,
- Region, SolverDefId, Span, Ty, TyKind,
- infer::{
- InferCtxt, TypeTrace,
- relate::RelateResult,
- traits::{Obligation, PredicateObligations},
+use crate::{
+ Span,
+ next_solver::{
+ AliasTy, Binder, Const, DbInterner, GenericArgs, Goal, ParamEnv, Predicate, PredicateKind,
+ Region, SolverDefId, Ty, TyKind,
+ infer::{
+ InferCtxt, TypeTrace,
+ relate::RelateResult,
+ traits::{Obligation, PredicateObligations},
+ },
},
};
@@ -154,12 +157,12 @@ impl<'db> TypeRelation<DbInterner<'db>> for LatticeOp<'_, 'db> {
// iterate on the subtype obligations that are returned, but I
// think this suffices. -nmatsakis
(TyKind::Infer(rustc_type_ir::TyVar(..)), _) => {
- let v = infcx.next_ty_var();
+ let v = infcx.next_ty_var(self.span());
self.relate_bound(v, b, a)?;
Ok(v)
}
(_, TyKind::Infer(rustc_type_ir::TyVar(..))) => {
- let v = infcx.next_ty_var();
+ let v = infcx.next_ty_var(self.span());
self.relate_bound(v, a, b)?;
Ok(v)
}
@@ -178,10 +181,10 @@ impl<'db> TypeRelation<DbInterner<'db>> for LatticeOp<'_, 'db> {
let mut constraints = inner.unwrap_region_constraints();
Ok(match self.kind {
// GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
- LatticeOpKind::Glb => constraints.lub_regions(self.cx(), a, b),
+ LatticeOpKind::Glb => constraints.lub_regions(self.cx(), self.span(), a, b),
// LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
- LatticeOpKind::Lub => constraints.glb_regions(self.cx(), a, b),
+ LatticeOpKind::Lub => constraints.glb_regions(self.cx(), self.span(), a, b),
})
}
@@ -239,7 +242,7 @@ impl<'infcx, 'db> LatticeOp<'infcx, 'db> {
impl<'db> PredicateEmittingRelation<InferCtxt<'db>> for LatticeOp<'_, 'db> {
fn span(&self) -> Span {
- Span::dummy()
+ self.trace.cause.span()
}
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
diff --git a/crates/hir-ty/src/next_solver/infer/select.rs b/crates/hir-ty/src/next_solver/infer/select.rs
index bbfc8a4757..d6f0379c11 100644
--- a/crates/hir-ty/src/next_solver/infer/select.rs
+++ b/crates/hir-ty/src/next_solver/infer/select.rs
@@ -10,6 +10,7 @@ use rustc_type_ir::{
};
use crate::{
+ Span,
db::InternedOpaqueTyId,
next_solver::{
AnyImplId, Const, ErrorGuaranteed, GenericArgs, Goal, TraitRef, Ty, TypeError,
@@ -263,18 +264,24 @@ impl<'db> InferCtxt<'db> {
) -> SelectionResult<'db, Selection<'db>> {
self.visit_proof_tree(
Goal::new(self.interner, obligation.param_env, obligation.predicate),
- &mut Select {},
+ &mut Select { span: obligation.cause.span() },
)
.break_value()
.unwrap()
}
}
-struct Select {}
+struct Select {
+ span: Span,
+}
impl<'db> ProofTreeVisitor<'db> for Select {
type Result = ControlFlow<SelectionResult<'db, Selection<'db>>>;
+ fn span(&self) -> Span {
+ self.span
+ }
+
fn visit_goal(&mut self, goal: &InspectGoal<'_, 'db>) -> Self::Result {
let mut candidates = goal.candidates();
candidates.retain(|cand| cand.result().is_ok());
@@ -286,7 +293,10 @@ impl<'db> ProofTreeVisitor<'db> for Select {
// One candidate, no need to winnow.
if candidates.len() == 1 {
- return ControlFlow::Break(Ok(to_selection(candidates.into_iter().next().unwrap())));
+ return ControlFlow::Break(Ok(to_selection(
+ self.span,
+ candidates.into_iter().next().unwrap(),
+ )));
}
// Don't winnow until `Certainty::Yes` -- we don't need to winnow until
@@ -311,7 +321,7 @@ impl<'db> ProofTreeVisitor<'db> for Select {
}
}
- ControlFlow::Break(Ok(to_selection(candidates.into_iter().next().unwrap())))
+ ControlFlow::Break(Ok(to_selection(self.span, candidates.into_iter().next().unwrap())))
}
}
@@ -368,7 +378,7 @@ fn candidate_should_be_dropped_in_favor_of<'db>(
}
}
-fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>> {
+fn to_selection<'db>(span: Span, cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>> {
if let Certainty::Maybe { .. } = cand.shallow_certainty() {
return None;
}
@@ -376,7 +386,7 @@ fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>>
let nested = match cand.result().expect("expected positive result") {
Certainty::Yes => Vec::new(),
Certainty::Maybe { .. } => cand
- .instantiate_nested_goals()
+ .instantiate_nested_goals(span)
.into_iter()
.map(|nested| {
Obligation::new(
@@ -396,7 +406,7 @@ fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>>
// For impl candidates, we do the rematch manually to compute the args.
ImplSource::UserDefined(ImplSourceUserDefinedData {
impl_def_id,
- args: cand.instantiate_impl_args(),
+ args: cand.instantiate_impl_args(span),
nested,
})
}
diff --git a/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs b/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs
index 5902f8043b..7cb3ab09d4 100644
--- a/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs
+++ b/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs
@@ -5,17 +5,19 @@ use ena::{
unify::{self as ut, UnifyKey},
};
use rustc_type_ir::{
- ConstVid, FloatVid, IntVid, RegionKind, RegionVid, TyVid, TypeFoldable, TypeFolder,
- TypeSuperFoldable, TypeVisitableExt, inherent::IntoKind,
+ ConstVid, FloatVid, IntVid, RegionVid, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable,
+ TypeVisitableExt, inherent::IntoKind,
};
-use crate::next_solver::{
- Const, ConstKind, DbInterner, Region, Ty, TyKind,
- infer::{
- InferCtxt, UnificationTable, iter_idx_range,
- snapshot::VariableLengths,
- type_variable::TypeVariableOrigin,
- unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey},
+use crate::{
+ Span,
+ next_solver::{
+ Const, ConstKind, DbInterner, Region, RegionKind, Ty, TyKind,
+ infer::{
+ InferCtxt, UnificationTable, iter_idx_range,
+ snapshot::VariableLengths,
+ unify_key::{ConstVariableValue, ConstVidKey},
+ },
},
};
@@ -33,7 +35,7 @@ where
fn const_vars_since_snapshot<'db>(
table: &mut UnificationTable<'_, 'db, ConstVidKey<'db>>,
snapshot_var_len: usize,
-) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) {
+) -> (Range<ConstVid>, Vec<Span>) {
let range = vars_since_snapshot(table, snapshot_var_len);
let range = range.start.vid..range.end.vid;
@@ -41,8 +43,8 @@ fn const_vars_since_snapshot<'db>(
range.clone(),
iter_idx_range(range)
.map(|index| match table.probe_value(index) {
- ConstVariableValue::Known { value: _ } => ConstVariableOrigin {},
- ConstVariableValue::Unknown { origin, universe: _ } => origin,
+ ConstVariableValue::Known { value: _ } => Span::Dummy,
+ ConstVariableValue::Unknown { span, universe: _ } => span,
})
.collect(),
)
@@ -128,11 +130,11 @@ impl<'db> InferCtxt<'db> {
}
struct SnapshotVarData {
- region_vars: Range<RegionVid>,
- type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
+ region_vars: (Range<RegionVid>, Vec<Span>),
+ type_vars: (Range<TyVid>, Vec<Span>),
int_vars: Range<IntVid>,
float_vars: Range<FloatVid>,
- const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
+ const_vars: (Range<ConstVid>, Vec<Span>),
}
impl SnapshotVarData {
@@ -156,7 +158,7 @@ impl SnapshotVarData {
fn is_empty(&self) -> bool {
let SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } = self;
- region_vars.is_empty()
+ region_vars.0.is_empty()
&& type_vars.0.is_empty()
&& int_vars.is_empty()
&& float_vars.is_empty()
@@ -182,8 +184,8 @@ impl<'a, 'db> TypeFolder<DbInterner<'db>> for InferenceFudger<'a, 'db> {
// This variable was created during the fudging.
// Recreate it with a fresh variable here.
let idx = vid.as_usize() - self.snapshot_vars.type_vars.0.start.as_usize();
- let origin = self.snapshot_vars.type_vars.1[idx];
- self.infcx.next_ty_var_with_origin(origin)
+ let span = self.snapshot_vars.type_vars.1[idx];
+ self.infcx.next_ty_var(span)
} else {
// This variable was created before the
// "fudging". Since we refresh all type
@@ -225,8 +227,10 @@ impl<'a, 'db> TypeFolder<DbInterner<'db>> for InferenceFudger<'a, 'db> {
fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
if let RegionKind::ReVar(vid) = r.kind() {
- if self.snapshot_vars.region_vars.contains(&vid) {
- self.infcx.next_region_var()
+ if self.snapshot_vars.region_vars.0.contains(&vid) {
+ let idx = vid.index() - self.snapshot_vars.region_vars.0.start.index();
+ let span = self.snapshot_vars.region_vars.1[idx];
+ self.infcx.next_region_var(span)
} else {
r
}
@@ -241,8 +245,8 @@ impl<'a, 'db> TypeFolder<DbInterner<'db>> for InferenceFudger<'a, 'db> {
rustc_type_ir::InferConst::Var(vid) => {
if self.snapshot_vars.const_vars.0.contains(&vid) {
let idx = vid.index() - self.snapshot_vars.const_vars.0.start.index();
- let origin = self.snapshot_vars.const_vars.1[idx];
- self.infcx.next_const_var_with_origin(origin)
+ let span = self.snapshot_vars.const_vars.1[idx];
+ self.infcx.next_const_var(span)
} else {
ct
}
diff --git a/crates/hir-ty/src/next_solver/infer/traits.rs b/crates/hir-ty/src/next_solver/infer/traits.rs
index 5b875d2960..1edf256d01 100644
--- a/crates/hir-ty/src/next_solver/infer/traits.rs
+++ b/crates/hir-ty/src/next_solver/infer/traits.rs
@@ -16,9 +16,12 @@ use rustc_type_ir::{
};
use tracing::debug;
-use crate::next_solver::{
- Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, Span, TraitPredicate,
- TraitRef, Ty,
+use crate::{
+ Span,
+ next_solver::{
+ Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, TraitPredicate,
+ TraitRef, Ty,
+ },
};
use super::InferCtxt;
@@ -33,15 +36,18 @@ use super::InferCtxt;
/// only live for a short period of time.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ObligationCause {
- // FIXME: This should contain an `ExprId`/`PatId` etc., and a cause code. But for now we
- // don't report trait solving diagnostics, so this is irrelevant.
- _private: (),
+ span: Span,
}
impl ObligationCause {
#[inline]
pub fn new() -> ObligationCause {
- ObligationCause { _private: () }
+ ObligationCause { span: Span::Dummy }
+ }
+
+ #[inline]
+ pub fn with_span(span: Span) -> ObligationCause {
+ ObligationCause { span }
}
#[inline]
@@ -53,6 +59,11 @@ impl ObligationCause {
pub fn misc() -> ObligationCause {
ObligationCause::new()
}
+
+ #[inline]
+ pub(crate) fn span(&self) -> Span {
+ self.span
+ }
}
impl Default for ObligationCause {
diff --git a/crates/hir-ty/src/next_solver/infer/type_variable.rs b/crates/hir-ty/src/next_solver/infer/type_variable.rs
index 29e7b883c9..6b3936ba80 100644
--- a/crates/hir-ty/src/next_solver/infer/type_variable.rs
+++ b/crates/hir-ty/src/next_solver/infer/type_variable.rs
@@ -7,13 +7,12 @@ use std::ops::Range;
use ena::snapshot_vec as sv;
use ena::undo_log::Rollback;
use ena::unify as ut;
-use rustc_index::IndexVec;
use rustc_type_ir::TyVid;
use rustc_type_ir::UniverseIndex;
use rustc_type_ir::inherent::Ty as _;
use tracing::debug;
-use crate::next_solver::SolverDefId;
+use crate::Span;
use crate::next_solver::Ty;
use crate::next_solver::infer::{InferCtxtUndoLogs, iter_idx_range};
@@ -61,8 +60,6 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> {
#[derive(Debug, Clone, Default)]
pub(crate) struct TypeVariableStorage<'db> {
- /// The origins of each type variable.
- values: IndexVec<TyVid, TypeVariableData>,
/// Two variables are unified in `eq_relations` when we have a
/// constraint `?X == ?Y`. This table also stores, for each key,
/// the known value.
@@ -94,20 +91,7 @@ pub(crate) struct TypeVariableTable<'a, 'db> {
undo_log: &'a mut InferCtxtUndoLogs<'db>,
}
-#[derive(Copy, Clone, Debug)]
-pub struct TypeVariableOrigin {
- /// `DefId` of the type parameter this was instantiated for, if any.
- ///
- /// This should only be used for diagnostics.
- pub param_def_id: Option<SolverDefId>,
-}
-
-#[derive(Debug, Clone)]
-pub(crate) struct TypeVariableData {
- origin: TypeVariableOrigin,
-}
-
-#[derive(Clone, Debug)]
+#[derive(Clone, Copy, Debug)]
pub(crate) enum TypeVariableValue<'db> {
Known { value: Ty<'db> },
Unknown { universe: UniverseIndex },
@@ -119,7 +103,7 @@ impl<'db> TypeVariableValue<'db> {
pub(crate) fn known(&self) -> Option<Ty<'db>> {
match self {
TypeVariableValue::Unknown { .. } => None,
- TypeVariableValue::Known { value } => Some(*value),
+ TypeVariableValue::Known { value, .. } => Some(*value),
}
}
@@ -145,19 +129,14 @@ impl<'db> TypeVariableStorage<'db> {
&self.eq_relations
}
- pub(super) fn finalize_rollback(&mut self) {
- debug_assert!(self.values.len() >= self.eq_relations.len());
- self.values.truncate(self.eq_relations.len());
- }
+ pub(super) fn finalize_rollback(&mut self) {}
}
impl<'db> TypeVariableTable<'_, 'db> {
- /// Returns the origin that was given when `vid` was created.
- ///
- /// Note that this function does not return care whether
- /// `vid` has been unified with something else or not.
- pub(crate) fn var_origin(&self, vid: TyVid) -> TypeVariableOrigin {
- self.storage.values[vid].origin
+ pub(crate) fn var_span(&mut self, vid: TyVid) -> Span {
+ // We return the span from unification and not equation, since when equating we also unify,
+ // and we want to prevent duplicate diagnostics from vars that were unified.
+ self.sub_unification_table().probe_value(vid).span
}
/// Records that `a == b`, depending on `dir`.
@@ -195,33 +174,20 @@ impl<'db> TypeVariableTable<'_, 'db> {
self.eq_relations().union_value(vid, TypeVariableValue::Known { value: ty });
}
- /// Creates a new type variable.
- ///
- /// - `diverging`: indicates if this is a "diverging" type
- /// variable, e.g., one created as the type of a `return`
- /// expression. The code in this module doesn't care if a
- /// variable is diverging, but the main Rust type-checker will
- /// sometimes "unify" such variables with the `!` or `()` types.
- /// - `origin`: indicates *why* the type variable was created.
- /// The code in this module doesn't care, but it can be useful
- /// for improving error messages.
- pub(crate) fn new_var(&mut self, universe: UniverseIndex, origin: TypeVariableOrigin) -> TyVid {
+ pub(crate) fn new_var(&mut self, universe: UniverseIndex, span: Span) -> TyVid {
let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });
- let sub_key = self.sub_unification_table().new_key(());
+ let sub_key = self.sub_unification_table().new_key(TypeVariableSubValue { span });
debug_assert_eq!(eq_key.vid, sub_key.vid);
- let index = self.storage.values.push(TypeVariableData { origin });
- debug_assert_eq!(eq_key.vid, index);
-
- debug!("new_var(index={:?}, universe={:?}, origin={:?})", eq_key.vid, universe, origin);
+ debug!("new_var(index={:?}, universe={:?}, span={:?})", eq_key.vid, universe, span);
- index
+ eq_key.vid
}
/// Returns the number of type variables created thus far.
pub(crate) fn num_vars(&self) -> usize {
- self.storage.values.len()
+ self.storage.eq_relations.len()
}
/// Returns the "root" variable of `vid` in the `eq_relations`
@@ -268,12 +234,9 @@ impl<'db> TypeVariableTable<'_, 'db> {
}
/// Returns a range of the type variables created during the snapshot.
- pub(crate) fn vars_since_snapshot(
- &mut self,
- value_count: usize,
- ) -> (Range<TyVid>, Vec<TypeVariableOrigin>) {
+ pub(crate) fn vars_since_snapshot(&mut self, value_count: usize) -> (Range<TyVid>, Vec<Span>) {
let range = TyVid::from_usize(value_count)..TyVid::from_usize(self.num_vars());
- (range.clone(), iter_idx_range(range).map(|index| self.var_origin(index)).collect())
+ (range.clone(), iter_idx_range(range).map(|index| self.var_span(index)).collect())
}
/// Returns indices of all variables that are not yet
@@ -324,9 +287,6 @@ impl<'db> ut::UnifyKey for TyVidEqKey<'db> {
fn tag() -> &'static str {
"TyVidEqKey"
}
- fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> {
- if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) }
- }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -341,8 +301,13 @@ impl From<TyVid> for TyVidSubKey {
}
}
+#[derive(Debug, Clone, Copy)]
+pub(crate) struct TypeVariableSubValue {
+ span: Span,
+}
+
impl ut::UnifyKey for TyVidSubKey {
- type Value = ();
+ type Value = TypeVariableSubValue;
#[inline]
fn index(&self) -> u32 {
self.vid.as_u32()
@@ -356,6 +321,14 @@ impl ut::UnifyKey for TyVidSubKey {
}
}
+impl ut::UnifyValue for TypeVariableSubValue {
+ type Error = ut::NoError;
+
+ fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
+ Ok(TypeVariableSubValue { span: Span::pick_best(value1.span, value2.span) })
+ }
+}
+
impl<'db> ut::UnifyValue for TypeVariableValue<'db> {
type Error = ut::NoError;
@@ -369,11 +342,9 @@ impl<'db> ut::UnifyValue for TypeVariableValue<'db> {
}
// If one side is known, prefer that one.
- (&TypeVariableValue::Known { .. }, &TypeVariableValue::Unknown { .. }) => {
- Ok(value1.clone())
- }
- (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => {
- Ok(value2.clone())
+ (&TypeVariableValue::Known { value }, &TypeVariableValue::Unknown { .. })
+ | (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { value }) => {
+ Ok(TypeVariableValue::Known { value })
}
// If both sides are *unknown*, it hardly matters, does it?
diff --git a/crates/hir-ty/src/next_solver/infer/unify_key.rs b/crates/hir-ty/src/next_solver/infer/unify_key.rs
index a09f65f082..061b8531d3 100644
--- a/crates/hir-ty/src/next_solver/infer/unify_key.rs
+++ b/crates/hir-ty/src/next_solver/infer/unify_key.rs
@@ -6,12 +6,15 @@ use std::marker::PhantomData;
use ena::unify::{NoError, UnifyKey, UnifyValue};
use rustc_type_ir::{ConstVid, RegionKind, RegionVid, UniverseIndex, inherent::IntoKind};
-use crate::next_solver::{Const, Region};
+use crate::{
+ Span,
+ next_solver::{Const, Region},
+};
-#[derive(Clone, Debug)]
+#[derive(Clone, Copy, Debug)]
pub(crate) enum RegionVariableValue<'db> {
- Known { value: Region<'db> },
- Unknown { universe: UniverseIndex },
+ Known { value: Region<'db>, span: Option<Span> },
+ Unknown { universe: UniverseIndex, span: Span },
}
#[derive(PartialEq, Copy, Clone, Debug)]
@@ -51,9 +54,15 @@ impl<'db> UnifyValue for RegionVariableValue<'db> {
Err(RegionUnificationError)
}
- (RegionVariableValue::Known { value }, RegionVariableValue::Unknown { universe })
- | (RegionVariableValue::Unknown { universe }, RegionVariableValue::Known { value }) => {
- let universe_of_value = match (*value).kind() {
+ (
+ &RegionVariableValue::Known { value, span: span_known },
+ &RegionVariableValue::Unknown { universe, span: span_unknown },
+ )
+ | (
+ &RegionVariableValue::Unknown { universe, span: span_unknown },
+ &RegionVariableValue::Known { value, span: span_known },
+ ) => {
+ let universe_of_value = match value.kind() {
RegionKind::ReStatic
| RegionKind::ReErased
| RegionKind::ReLateParam(..)
@@ -65,23 +74,28 @@ impl<'db> UnifyValue for RegionVariableValue<'db> {
}
};
+ let span = match span_known {
+ Some(span_known) => Span::pick_best(span_known, span_unknown),
+ None => span_unknown,
+ };
if universe.can_name(universe_of_value) {
- Ok(RegionVariableValue::Known { value: *value })
+ Ok(RegionVariableValue::Known { value, span: Some(span) })
} else {
Err(RegionUnificationError)
}
}
(
- RegionVariableValue::Unknown { universe: a },
- RegionVariableValue::Unknown { universe: b },
+ &RegionVariableValue::Unknown { universe: a, span: span1 },
+ &RegionVariableValue::Unknown { universe: b, span: span2 },
) => {
// If we unify two unconstrained regions then whatever
// value they wind up taking (which must be the same value) must
// be nameable by both universes. Therefore, the resulting
// universe is the minimum of the two universes, because that is
// the one which contains the fewest names in scope.
- Ok(RegionVariableValue::Unknown { universe: (*a).min(*b) })
+ let span = Span::pick_best(span1, span2);
+ Ok(RegionVariableValue::Unknown { universe: a.min(b), span })
}
}
}
@@ -89,13 +103,10 @@ impl<'db> UnifyValue for RegionVariableValue<'db> {
// Generic consts.
-#[derive(Copy, Clone, Debug)]
-pub struct ConstVariableOrigin {}
-
-#[derive(Clone, Debug)]
+#[derive(Clone, Copy, Debug)]
pub(crate) enum ConstVariableValue<'db> {
Known { value: Const<'db> },
- Unknown { origin: ConstVariableOrigin, universe: UniverseIndex },
+ Unknown { span: Span, universe: UniverseIndex },
}
impl<'db> ConstVariableValue<'db> {
@@ -134,9 +145,6 @@ impl<'db> UnifyKey for ConstVidKey<'db> {
fn tag() -> &'static str {
"ConstVidKey"
}
- fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> {
- if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) }
- }
}
impl<'db> UnifyValue for ConstVariableValue<'db> {
@@ -149,25 +157,22 @@ impl<'db> UnifyValue for ConstVariableValue<'db> {
}
// If one side is known, prefer that one.
- (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => {
- Ok(value1.clone())
- }
- (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => {
- Ok(value2.clone())
- }
+ (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => Ok(*value1),
+ (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => Ok(*value2),
// If both sides are *unknown*, it hardly matters, does it?
(
- ConstVariableValue::Unknown { origin, universe: universe1 },
- ConstVariableValue::Unknown { origin: _, universe: universe2 },
+ &ConstVariableValue::Unknown { span: span1, universe: universe1 },
+ &ConstVariableValue::Unknown { span: span2, universe: universe2 },
) => {
// If we unify two unbound variables, ?T and ?U, then whatever
// value they wind up taking (which must be the same value) must
// be nameable by both universes. Therefore, the resulting
// universe is the minimum of the two universes, because that is
// the one which contains the fewest names in scope.
- let universe = cmp::min(*universe1, *universe2);
- Ok(ConstVariableValue::Unknown { origin: *origin, universe })
+ let universe = cmp::min(universe1, universe2);
+ let span = Span::pick_best(span1, span2);
+ Ok(ConstVariableValue::Unknown { span, universe })
}
}
}
diff --git a/crates/hir-ty/src/next_solver/inspect.rs b/crates/hir-ty/src/next_solver/inspect.rs
index 63a225b98f..566f72fbd8 100644
--- a/crates/hir-ty/src/next_solver/inspect.rs
+++ b/crates/hir-ty/src/next_solver/inspect.rs
@@ -6,19 +6,22 @@ use rustc_next_trait_solver::{
};
use rustc_type_ir::{
VisitorResult,
- inherent::{IntoKind, Span as _},
+ inherent::IntoKind,
solve::{Certainty, GoalSource, MaybeCause, NoSolution},
};
-use crate::next_solver::{
- DbInterner, GenericArg, GenericArgs, Goal, NormalizesTo, ParamEnv, Predicate, PredicateKind,
- QueryResult, SolverContext, Span, Term,
- fulfill::NextSolverError,
- infer::{
- InferCtxt,
- traits::{Obligation, ObligationCause},
+use crate::{
+ Span,
+ next_solver::{
+ DbInterner, GenericArg, GenericArgs, Goal, NormalizesTo, ParamEnv, Predicate,
+ PredicateKind, QueryResult, SolverContext, Term,
+ fulfill::NextSolverError,
+ infer::{
+ InferCtxt,
+ traits::{Obligation, ObligationCause},
+ },
+ obligation_ctxt::ObligationCtxt,
},
- obligation_ctxt::ObligationCtxt,
};
pub(crate) struct InspectConfig {
@@ -142,7 +145,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> {
&self,
visitor: &mut V,
) -> V::Result {
- for goal in self.instantiate_nested_goals() {
+ for goal in self.instantiate_nested_goals(visitor.span()) {
try_visit!(goal.visit_with(visitor));
}
@@ -153,7 +156,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> {
/// inference constraints. This function modifies the state of the `infcx`.
///
/// See [`Self::instantiate_impl_args`] if you need the impl args too.
- pub(crate) fn instantiate_nested_goals(&self) -> Vec<InspectGoal<'a, 'db>> {
+ pub(crate) fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'db>> {
let infcx = self.goal.infcx;
let param_env = self.goal.goal.param_env;
let mut orig_values = self.goal.orig_values.to_vec();
@@ -163,13 +166,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> {
match **step {
inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push((
source,
- instantiate_canonical_state(
- infcx,
- Span::dummy(),
- param_env,
- &mut orig_values,
- goal,
- ),
+ instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal),
)),
inspect::ProbeStep::RecordImplArgs { .. } => {}
inspect::ProbeStep::MakeCanonicalResponse { .. }
@@ -177,13 +174,8 @@ impl<'a, 'db> InspectCandidate<'a, 'db> {
}
}
- let () = instantiate_canonical_state(
- infcx,
- Span::dummy(),
- param_env,
- &mut orig_values,
- self.final_state,
- );
+ let () =
+ instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state);
if let Some(term_hack) = &self.goal.normalizes_to_term_hack {
// FIXME: We ignore the expected term of `NormalizesTo` goals
@@ -194,14 +186,14 @@ impl<'a, 'db> InspectCandidate<'a, 'db> {
instantiated_goals
.into_iter()
- .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal))
+ .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span))
.collect()
}
/// Instantiate the args of an impl if this candidate came from a
/// `CandidateSource::Impl`. This function modifies the state of the
/// `infcx`.
- pub(crate) fn instantiate_impl_args(&self) -> GenericArgs<'db> {
+ pub(crate) fn instantiate_impl_args(&self, span: Span) -> GenericArgs<'db> {
let infcx = self.goal.infcx;
let param_env = self.goal.goal.param_env;
let mut orig_values = self.goal.orig_values.to_vec();
@@ -211,7 +203,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> {
inspect::ProbeStep::RecordImplArgs { impl_args } => {
let impl_args = instantiate_canonical_state(
infcx,
- Span::dummy(),
+ span,
param_env,
&mut orig_values,
impl_args,
@@ -219,7 +211,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> {
let () = instantiate_canonical_state(
infcx,
- Span::dummy(),
+ span,
param_env,
&mut orig_values,
self.final_state,
@@ -246,11 +238,12 @@ impl<'a, 'db> InspectCandidate<'a, 'db> {
&self,
source: GoalSource,
goal: Goal<'db, Predicate<'db>>,
+ span: Span,
) -> InspectGoal<'a, 'db> {
let infcx = self.goal.infcx;
match goal.predicate.kind().no_bound_vars() {
Some(PredicateKind::NormalizesTo(NormalizesTo { alias, term })) => {
- let unconstrained_term = infcx.next_term_var_of_kind(term);
+ let unconstrained_term = infcx.next_term_var_of_kind(term, span);
let goal =
goal.with(infcx.interner, NormalizesTo { alias, term: unconstrained_term });
// We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
@@ -265,8 +258,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> {
// considering the constrained RHS, and pass the resulting certainty to
// `InspectGoal::new` so that the goal has the right result (and maintains
// the impression that we don't do this normalizes-to infer hack at all).
- let (nested, proof_tree) =
- infcx.evaluate_root_goal_for_proof_tree(goal, Span::dummy());
+ let (nested, proof_tree) = infcx.evaluate_root_goal_for_proof_tree(goal, span);
let nested_goals_result = nested.and_then(|nested| {
normalizes_to_term_hack.constrain_and(
infcx,
@@ -300,7 +292,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> {
// constraints, we get an ICE if we already applied the constraints
// from the chosen candidate.
let proof_tree =
- infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, Span::dummy()).1);
+ infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, span).1);
InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
}
}
@@ -469,6 +461,8 @@ impl<'a, 'db> InspectGoal<'a, 'db> {
pub(crate) trait ProofTreeVisitor<'db> {
type Result: VisitorResult;
+ fn span(&self) -> Span;
+
fn config(&self) -> InspectConfig {
InspectConfig { max_depth: 10 }
}
@@ -496,7 +490,7 @@ impl<'db> InferCtxt<'db> {
visitor: &mut V,
) -> V::Result {
let (_, proof_tree) = <&SolverContext<'db>>::from(self)
- .evaluate_root_goal_for_proof_tree(goal, Span::dummy());
+ .evaluate_root_goal_for_proof_tree(goal, visitor.span());
visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc))
}
}
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index 4095dbe47d..af3798f1da 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -37,7 +37,7 @@ use rustc_type_ir::{
};
use crate::{
- FnAbi,
+ FnAbi, Span,
db::{HirDatabase, InternedClosure, InternedCoroutineId},
lower::GenericPredicates,
method_resolution::TraitImpls,
@@ -382,13 +382,9 @@ impl<'db> DbInterner<'db> {
}
}
-// This is intentionally left as `()`
-#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
-pub struct Span(());
-
impl<'db> inherent::Span<DbInterner<'db>> for Span {
fn dummy() -> Self {
- Span(())
+ Span::Dummy
}
}
diff --git a/crates/hir-ty/src/next_solver/normalize.rs b/crates/hir-ty/src/next_solver/normalize.rs
index 5d8f3fe519..aa6f27c4c2 100644
--- a/crates/hir-ty/src/next_solver/normalize.rs
+++ b/crates/hir-ty/src/next_solver/normalize.rs
@@ -99,7 +99,7 @@ impl<'db> NormalizationFolder<'_, 'db> {
self.depth += 1;
- let infer_term = infcx.next_term_var_of_kind(alias_term);
+ let infer_term = infcx.next_term_var_of_kind(alias_term, self.at.cause.span());
let obligation = Obligation::new(
interner,
self.at.cause.clone(),
diff --git a/crates/hir-ty/src/next_solver/region.rs b/crates/hir-ty/src/next_solver/region.rs
index 3f0aebac2d..7acbcbf4aa 100644
--- a/crates/hir-ty/src/next_solver/region.rs
+++ b/crates/hir-ty/src/next_solver/region.rs
@@ -136,7 +136,7 @@ impl<'db> Region<'db> {
}
RegionKind::ReError(..) => {
flags |= TypeFlags::HAS_FREE_REGIONS;
- flags |= TypeFlags::HAS_ERROR;
+ flags |= TypeFlags::HAS_RE_ERROR;
}
}
diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs
index d45ac6c959..6abc87f088 100644
--- a/crates/hir-ty/src/next_solver/solver.rs
+++ b/crates/hir-ty/src/next_solver/solver.rs
@@ -6,7 +6,7 @@ use hir_def::{
};
use rustc_next_trait_solver::delegate::SolverDelegate;
use rustc_type_ir::{
- AliasTyKind, GenericArgKind, InferCtxtLike, Interner, PredicatePolarity, TypeFlags,
+ AliasTyKind, GenericArgKind, InferCtxtLike, InferTy, Interner, PredicatePolarity, TypeFlags,
TypeVisitableExt,
inherent::{IntoKind, Term as _, Ty as _},
lang_items::SolverTraitLangItem,
@@ -15,7 +15,7 @@ use rustc_type_ir::{
use tracing::debug;
use crate::{
- ParamEnvAndCrate,
+ ParamEnvAndCrate, Span,
next_solver::{
AliasTy, AnyImplId, CanonicalVarKind, Clause, ClauseKind, CoercePredicate, GenericArgs,
ParamEnv, Predicate, PredicateKind, SubtypePredicate, Ty, TyKind, UnevaluatedConst,
@@ -24,7 +24,7 @@ use crate::{
};
use super::{
- Const, DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span,
+ Const, DbInterner, ErrorGuaranteed, GenericArg, SolverDefId,
infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt},
};
@@ -63,15 +63,15 @@ impl<'db> SolverDelegate for SolverContext<'db> {
where
V: rustc_type_ir::TypeFoldable<Self::Interner>,
{
- let (infcx, value, vars) = cx.infer_ctxt().build_with_canonical(canonical);
+ let (infcx, value, vars) = cx.infer_ctxt().build_with_canonical(Span::Dummy, canonical);
(SolverContext(infcx), value, vars)
}
- fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, _span: Span) -> GenericArg<'db> {
+ fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, span: Span) -> GenericArg<'db> {
match arg.kind() {
- GenericArgKind::Lifetime(_) => self.next_region_var().into(),
- GenericArgKind::Type(_) => self.next_ty_var().into(),
- GenericArgKind::Const(_) => self.next_const_var().into(),
+ GenericArgKind::Lifetime(_) => self.next_region_var(span).into(),
+ GenericArgKind::Type(_) => self.next_ty_var(span).into(),
+ GenericArgKind::Const(_) => self.next_const_var(span).into(),
}
}
@@ -124,11 +124,11 @@ impl<'db> SolverDelegate for SolverContext<'db> {
fn instantiate_canonical_var(
&self,
kind: CanonicalVarKind<'db>,
- _span: <Self::Interner as Interner>::Span,
+ span: Span,
var_values: &[GenericArg<'db>],
universe_map: impl Fn(rustc_type_ir::UniverseIndex) -> rustc_type_ir::UniverseIndex,
) -> GenericArg<'db> {
- self.0.instantiate_canonical_var(kind, var_values, universe_map)
+ self.0.instantiate_canonical_var(span, kind, var_values, universe_map)
}
fn add_item_bounds_for_hidden_type(
@@ -293,10 +293,10 @@ impl<'db> SolverDelegate for SolverContext<'db> {
}
if trait_pred.polarity() == PredicatePolarity::Positive {
- match self.0.cx().as_trait_lang_item(trait_pred.def_id()) {
+ match self.0.interner.as_trait_lang_item(trait_pred.def_id()) {
Some(SolverTraitLangItem::Sized) | Some(SolverTraitLangItem::MetaSized) => {
let predicate = self.resolve_vars_if_possible(goal.predicate);
- if sizedness_fast_path(self.cx(), predicate, goal.param_env) {
+ if sizedness_fast_path(self.interner, predicate, goal.param_env) {
return Some(Certainty::Yes);
}
}
@@ -322,17 +322,31 @@ impl<'db> SolverDelegate for SolverContext<'db> {
let pred = goal.predicate.kind();
match pred.no_bound_vars()? {
- PredicateKind::Clause(ClauseKind::RegionOutlives(_outlives)) => Some(Certainty::Yes),
- PredicateKind::Clause(ClauseKind::TypeOutlives(_outlives)) => Some(Certainty::Yes),
+ PredicateKind::DynCompatible(def_id)
+ if self.0.interner.trait_is_dyn_compatible(def_id) =>
+ {
+ Some(Certainty::Yes)
+ }
+ PredicateKind::Clause(ClauseKind::RegionOutlives(outlives)) => {
+ self.0.sub_regions(outlives.1, outlives.0);
+ Some(Certainty::Yes)
+ }
+ PredicateKind::Clause(ClauseKind::TypeOutlives(outlives)) => {
+ self.0.register_type_outlives_constraint(outlives.0, outlives.1);
+
+ Some(Certainty::Yes)
+ }
PredicateKind::Subtype(SubtypePredicate { a, b, .. })
| PredicateKind::Coerce(CoercePredicate { a, b }) => {
- if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() {
- // FIXME: We also need to register a subtype relation between these vars
- // when those are added, and if they aren't in the same sub root then
- // we should mark this goal as `has_changed`.
- Some(Certainty::AMBIGUOUS)
- } else {
- None
+ match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) {
+ (
+ TyKind::Infer(InferTy::TyVar(a_vid)),
+ TyKind::Infer(InferTy::TyVar(b_vid)),
+ ) => {
+ self.sub_unify_ty_vids_raw(a_vid, b_vid);
+ Some(Certainty::AMBIGUOUS)
+ }
+ _ => None,
}
}
PredicateKind::Clause(ClauseKind::ConstArgHasType(ct, _)) => {
@@ -343,6 +357,7 @@ impl<'db> SolverDelegate for SolverContext<'db> {
}
}
PredicateKind::Clause(ClauseKind::WellFormed(arg)) => {
+ let arg = self.shallow_resolve_term(arg);
if arg.is_trivially_wf(self.interner) {
Some(Certainty::Yes)
} else if arg.is_infer() {
diff --git a/crates/hir-ty/src/next_solver/structural_normalize.rs b/crates/hir-ty/src/next_solver/structural_normalize.rs
index 00c3708358..7a70bae97c 100644
--- a/crates/hir-ty/src/next_solver/structural_normalize.rs
+++ b/crates/hir-ty/src/next_solver/structural_normalize.rs
@@ -34,7 +34,7 @@ impl<'db> At<'_, 'db> {
return Ok(term);
}
- let new_infer = self.infcx.next_term_var_of_kind(term);
+ let new_infer = self.infcx.next_term_var_of_kind(term, self.cause.span());
// We simply emit an `alias-eq` goal here, since that will take care of
// normalizing the LHS of the projection until it is a rigid projection
diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs
index 0fd02eb8ca..511259ecd8 100644
--- a/crates/hir-ty/src/next_solver/ty.rs
+++ b/crates/hir-ty/src/next_solver/ty.rs
@@ -17,7 +17,7 @@ use rustc_type_ir::{
IntVid, Interner, TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor, UintTy, Upcast, WithCachedTypeInfo,
inherent::{
- AdtDef as _, BoundExistentialPredicates, Const as _, GenericArgs as _, IntoKind, ParamLike,
+ AdtDef as _, BoundExistentialPredicates, GenericArgs as _, IntoKind, ParamLike,
Safety as _, SliceLike, Ty as _,
},
relate::Relate,
@@ -31,8 +31,8 @@ use crate::{
lower::GenericPredicates,
next_solver::{
AdtDef, AliasTy, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const,
- CoroutineClosureIdWrapper, CoroutineIdWrapper, FnSig, GenericArgKind, PolyFnSig, Region,
- TraitRef, TypeAliasIdWrapper,
+ CoroutineClosureIdWrapper, CoroutineIdWrapper, FnSig, GenericArgKind, PolyFnSig, Predicate,
+ Region, TraitRef, TypeAliasIdWrapper,
abi::Safety,
impl_foldable_for_interned_slice, impl_stored_interned, interned_slice,
util::{CoroutineArgsExt, IntegerTypeExt},
@@ -817,25 +817,11 @@ impl<'db> Ty<'db> {
}
pub fn references_non_lt_error<'db, T: TypeVisitableExt<DbInterner<'db>>>(t: &T) -> bool {
- t.references_error() && t.visit_with(&mut ReferencesNonLifetimeError).is_break()
-}
-
-struct ReferencesNonLifetimeError;
-
-impl<'db> TypeVisitor<DbInterner<'db>> for ReferencesNonLifetimeError {
- type Result = ControlFlow<()>;
-
- fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result {
- if ty.is_ty_error() { ControlFlow::Break(()) } else { ty.super_visit_with(self) }
- }
-
- fn visit_const(&mut self, c: Const<'db>) -> Self::Result {
- if c.is_ct_error() { ControlFlow::Break(()) } else { c.super_visit_with(self) }
- }
+ t.has_non_region_error()
}
pub fn references_only_ty_error<'db, T: TypeVisitableExt<DbInterner<'db>>>(t: &T) -> bool {
- t.references_error() && t.visit_with(&mut ReferencesOnlyTyError).is_break()
+ references_non_lt_error(t) && t.visit_with(&mut ReferencesOnlyTyError).is_break()
}
struct ReferencesOnlyTyError;
@@ -844,7 +830,29 @@ impl<'db> TypeVisitor<DbInterner<'db>> for ReferencesOnlyTyError {
type Result = ControlFlow<()>;
fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result {
- if ty.is_ty_error() { ControlFlow::Break(()) } else { ty.super_visit_with(self) }
+ if !ty.references_non_lt_error() {
+ ControlFlow::Continue(())
+ } else if ty.is_ty_error() {
+ ControlFlow::Break(())
+ } else {
+ ty.super_visit_with(self)
+ }
+ }
+
+ fn visit_const(&mut self, c: Const<'db>) -> Self::Result {
+ if !references_non_lt_error(&c) {
+ ControlFlow::Continue(())
+ } else {
+ c.super_visit_with(self)
+ }
+ }
+
+ fn visit_predicate(&mut self, p: Predicate<'db>) -> Self::Result {
+ if !references_non_lt_error(&p) {
+ ControlFlow::Continue(())
+ } else {
+ p.super_visit_with(self)
+ }
}
}
@@ -880,6 +888,15 @@ impl<'db> TypeVisitable<DbInterner<'db>> for Ty<'db> {
}
}
+impl<'db> TypeVisitable<DbInterner<'db>> for StoredTy {
+ fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
+ &self,
+ visitor: &mut V,
+ ) -> V::Result {
+ self.as_ref().visit_with(visitor)
+ }
+}
+
impl<'db> TypeSuperVisitable<DbInterner<'db>> for Ty<'db> {
fn super_visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
&self,
@@ -946,6 +963,18 @@ impl<'db> TypeFoldable<DbInterner<'db>> for Ty<'db> {
}
}
+impl<'db> TypeFoldable<DbInterner<'db>> for StoredTy {
+ fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self.as_ref().try_fold_with(folder)?.store())
+ }
+ fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
+ self.as_ref().fold_with(folder).store()
+ }
+}
+
impl<'db> TypeSuperFoldable<DbInterner<'db>> for Ty<'db> {
fn try_super_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
self,
diff --git a/crates/hir-ty/src/opaques.rs b/crates/hir-ty/src/opaques.rs
index 2e85beea91..c78e9d7c5d 100644
--- a/crates/hir-ty/src/opaques.rs
+++ b/crates/hir-ty/src/opaques.rs
@@ -10,7 +10,7 @@ use rustc_type_ir::inherent::Ty as _;
use syntax::ast;
use crate::{
- ImplTraitId, InferenceResult,
+ ImplTraitId, InferenceResult, Span,
db::{HirDatabase, InternedOpaqueTyId},
lower::{ImplTraitIdx, ImplTraits},
next_solver::{
@@ -140,7 +140,7 @@ pub(crate) fn tait_hidden_types<'db>(
}
// In the presence of errors, we attempt to create a unified type from all
// types. rustc doesn't do that, but this should improve the experience.
- let hidden_type = infcx.insert_type_vars(hidden_type.as_ref());
+ let hidden_type = infcx.insert_type_vars(hidden_type.as_ref(), Span::Dummy);
match result.entry(opaque_idx) {
la_arena::Entry::Vacant(entry) => {
entry.insert(StoredEarlyBinder::bind(hidden_type.store()));
diff --git a/crates/hir-ty/src/specialization.rs b/crates/hir-ty/src/specialization.rs
index a0bac48250..7e4d3a8354 100644
--- a/crates/hir-ty/src/specialization.rs
+++ b/crates/hir-ty/src/specialization.rs
@@ -7,6 +7,7 @@ use hir_def::{
use tracing::debug;
use crate::{
+ Span,
db::HirDatabase,
lower::GenericPredicates,
next_solver::{
@@ -91,7 +92,7 @@ fn specializes_query(
let mut ocx = ObligationCtxt::new(&infcx);
- let parent_args = infcx.fresh_args_for_item(parent_impl_def_id.into());
+ let parent_args = infcx.fresh_args_for_item(Span::Dummy, parent_impl_def_id.into());
let parent_impl_trait_ref = db
.impl_trait(parent_impl_def_id)
.expect("expected source impl to be a trait impl")
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index 0dc834ddcc..ad668f2eee 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -21,6 +21,7 @@ use rustc_type_ir::{
};
use crate::{
+ Span,
db::HirDatabase,
next_solver::{
DbInterner, GenericArgs, ParamEnv, StoredClauses, Ty, TyKind,
@@ -121,7 +122,7 @@ pub fn implements_trait_unique<'db>(
trait_: TraitId,
) -> bool {
implements_trait_unique_impl(db, env, trait_, &mut |infcx| {
- infcx.fill_rest_fresh_args(trait_.into(), [ty.into()])
+ infcx.fill_rest_fresh_args(Span::Dummy, trait_.into(), [ty.into()])
})
}
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 9943b718fd..f9cf05e73a 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -504,6 +504,8 @@ fn resolve_impl_trait_item<'db>(
traits_in_scope: &traits_in_scope,
edition: krate.edition(db),
features,
+ call_span: hir_ty::Span::Dummy,
+ receiver_span: hir_ty::Span::Dummy,
};
let resolution = ctx.probe_for_name(method_resolution::Mode::Path, name.clone(), ty.ty);
let resolution = match resolution {
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 8f9465cf1b..18f28541af 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -6,9 +6,9 @@
use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_def::{
- DefWithBodyId, GenericParamId, SyntheticSyntax,
+ DefWithBodyId, GenericParamId, HasModule, SyntheticSyntax,
expr_store::{
- ExprOrPatPtr, ExprOrPatSource, ExpressionStoreSourceMap, hir_assoc_type_binding_to_ast,
+ ExprOrPatPtr, ExpressionStoreSourceMap, hir_assoc_type_binding_to_ast,
hir_generic_arg_to_ast, hir_segment_to_ast_segment,
},
hir::ExprOrPatId,
@@ -19,6 +19,7 @@ use hir_ty::{
PathLoweringDiagnostic, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
db::HirDatabase,
diagnostics::{BodyValidationDiagnostic, UnsafetyReason},
+ display::{DisplayTarget, HirDisplay},
};
use syntax::{
AstNode, AstPtr, SyntaxError, SyntaxNodePtr, TextRange,
@@ -108,7 +109,7 @@ diagnostics![AnyDiagnostic<'db> ->
IncorrectGenericsOrder,
MissingLifetime,
ElidedLifetimesInPath,
- TypeMustBeKnown,
+ TypeMustBeKnown<'db>,
];
#[derive(Debug)]
@@ -446,8 +447,9 @@ pub struct ElidedLifetimesInPath {
}
#[derive(Debug)]
-pub struct TypeMustBeKnown {
- pub at_point: ExprOrPatSource,
+pub struct TypeMustBeKnown<'db> {
+ pub at_point: InFile<AstPtr<Either<ast::Type, Either<ast::Expr, ast::Pat>>>>,
+ pub top_term: Option<Either<Type<'db>, String>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -631,6 +633,12 @@ impl<'db> AnyDiagnostic<'db> {
.inspect_err(|_| stdx::never!("inference diagnostic in desugared pattern"))
.ok()
};
+ let type_syntax = |pat| {
+ source_map
+ .type_syntax(pat)
+ .inspect_err(|_| stdx::never!("inference diagnostic in desugared type"))
+ .ok()
+ };
let expr_or_pat_syntax = |id| match id {
ExprOrPatId::ExprId(expr) => expr_syntax(expr),
ExprOrPatId::PatId(pat) => pat_syntax(pat),
@@ -806,8 +814,29 @@ impl<'db> AnyDiagnostic<'db> {
let lhs = expr_syntax(lhs)?;
InvalidLhsOfAssignment { lhs }.into()
}
- &InferenceDiagnostic::TypeMustBeKnown { at_point } => {
- TypeMustBeKnown { at_point: expr_or_pat_syntax(at_point)? }.into()
+ &InferenceDiagnostic::TypeMustBeKnown { at_point, ref top_term } => {
+ let at_point = match at_point {
+ hir_ty::Span::ExprId(idx) => expr_syntax(idx)?.map(|it| it.wrap_right()),
+ hir_ty::Span::PatId(idx) => pat_syntax(idx)?.map(|it| it.wrap_right()),
+ hir_ty::Span::TypeRefId(idx) => type_syntax(idx)?.map(|it| it.wrap_left()),
+ hir_ty::Span::Dummy => unreachable!(
+ "should never create TypeMustBeKnown diagnostic for dummy spans"
+ ),
+ };
+ let top_term = top_term.as_ref().map(|top_term| match top_term.as_ref().kind() {
+ rustc_type_ir::GenericArgKind::Type(ty) => Either::Left(Type {
+ ty,
+ env: crate::body_param_env_from_has_crate(db, def),
+ }),
+ // FIXME: Printing the const to string is definitely not the correct thing to do here.
+ rustc_type_ir::GenericArgKind::Const(konst) => Either::Right(
+ konst.display(db, DisplayTarget::from_crate(db, def.krate(db))).to_string(),
+ ),
+ rustc_type_ir::GenericArgKind::Lifetime(_) => {
+ unreachable!("we currently don't emit TypeMustBeKnown for lifetimes")
+ }
+ });
+ TypeMustBeKnown { at_point, top_term }.into()
}
})
}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 11598f2a10..8cc82113b3 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1525,7 +1525,7 @@ impl Struct {
}
pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedStruct<'db> {
- let args = infer_ctxt.fresh_args_for_item(self.id.into());
+ let args = infer_ctxt.fresh_args_for_item(hir_ty::Span::Dummy, self.id.into());
InstantiatedStruct { inner: self, args }
}
}
@@ -1804,8 +1804,10 @@ impl EnumVariant {
}
pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedVariant<'db> {
- let args =
- infer_ctxt.fresh_args_for_item(self.parent_enum(infer_ctxt.interner.db()).id.into());
+ let args = infer_ctxt.fresh_args_for_item(
+ hir_ty::Span::Dummy,
+ self.parent_enum(infer_ctxt.interner.db()).id.into(),
+ );
InstantiatedVariant { inner: self, args }
}
}
@@ -4793,7 +4795,7 @@ impl ConstParam {
}
pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
- Type::new(db, self.id.parent(), db.const_param_ty_ns(self.id))
+ Type::new(db, self.id.parent(), db.const_param_ty(self.id))
}
pub fn default(
@@ -6191,6 +6193,8 @@ impl<'db> Type<'db> {
traits_in_scope,
edition: resolver.krate().data(db).edition,
features,
+ call_span: hir_ty::Span::Dummy,
+ receiver_span: hir_ty::Span::Dummy,
};
f(&ctx)
}
@@ -6217,7 +6221,7 @@ impl<'db> Type<'db> {
self.with_method_resolution(db, scope.resolver(), traits_in_scope, |ctx| {
// There should be no inference vars in types passed here
let canonical = hir_ty::replace_errors_with_variables(ctx.infcx.interner, &self.ty);
- let (self_ty, _) = ctx.infcx.instantiate_canonical(&canonical);
+ let (self_ty, _) = ctx.infcx.instantiate_canonical(hir_ty::Span::Dummy, &canonical);
match name {
Some(name) => {
@@ -6325,7 +6329,7 @@ impl<'db> Type<'db> {
self.with_method_resolution(db, scope.resolver(), traits_in_scope, |ctx| {
// There should be no inference vars in types passed here
let canonical = hir_ty::replace_errors_with_variables(ctx.infcx.interner, &self.ty);
- let (self_ty, _) = ctx.infcx.instantiate_canonical(&canonical);
+ let (self_ty, _) = ctx.infcx.instantiate_canonical(hir_ty::Span::Dummy, &canonical);
match name {
Some(name) => {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 9d97dc7421..252f4ac7f2 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -36,20 +36,19 @@ use hir_ty::{
diagnostics::unsafe_operations,
infer_query_with_inspect,
next_solver::{
- AnyImplId, DbInterner, Span,
+ AnyImplId, DbInterner,
format_proof_tree::{ProofTreeData, dump_proof_tree_structured},
},
};
use intern::{Interned, Symbol, sym};
use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
-use rustc_type_ir::inherent::Span as _;
use smallvec::{SmallVec, smallvec};
use span::{FileId, SyntaxContext};
use stdx::{TupleExt, always};
use syntax::{
- AstNode, AstToken, Direction, SmolStr, SmolStrBuilder, SyntaxElement, SyntaxKind, SyntaxNode,
- SyntaxNodePtr, SyntaxToken, T, TextRange, TextSize,
+ AstNode, AstPtr, AstToken, Direction, SmolStr, SmolStrBuilder, SyntaxElement, SyntaxKind,
+ SyntaxNode, SyntaxNodePtr, SyntaxToken, T, TextRange, TextSize,
algo::skip_trivia_token,
ast::{self, HasAttrs as _, HasGenericParams},
};
@@ -544,6 +543,10 @@ impl<'db> SemanticsImpl<'db> {
node
}
+ pub fn to_node<N: AstNode>(&self, ptr: InFile<AstPtr<N>>) -> N {
+ ptr.value.to_node(&self.parse_or_expand(ptr.file_id))
+ }
+
pub fn expand(&self, file_id: MacroCallId) -> ExpandResult<SyntaxNode> {
let res = self.db.parse_macro_expansion(file_id).map(|it| it.0.syntax_node());
self.cache(res.value.clone(), file_id.into());
@@ -2459,7 +2462,8 @@ impl<'db> SemanticsImpl<'db> {
if result.is_err()
&& let Some(tree) = proof_tree
{
- let data = dump_proof_tree_structured(tree, Span::dummy(), infer_ctxt);
+ let data =
+ dump_proof_tree_structured(tree, hir_ty::Span::Dummy, infer_ctxt);
RESULT.with(|ctx| ctx.borrow_mut().push(data));
}
}),
diff --git a/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs b/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
index 2a7b0098ed..7cadff84fb 100644
--- a/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
+++ b/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
@@ -52,6 +52,7 @@ async fn bar() {
fn await_inside_closure() {
check_diagnostics(
r#"
+//- minicore: future
async fn foo() {}
async fn bar() {
@@ -66,6 +67,7 @@ async fn bar() {
fn await_inside_async_block() {
check_diagnostics(
r#"
+//- minicore: future
async fn foo() {}
fn bar() {
@@ -79,6 +81,7 @@ fn bar() {
fn await_in_complex_context() {
check_diagnostics(
r#"
+//- minicore: future
async fn foo() {}
fn bar() {
diff --git a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
index cbcaab6c74..02f3cab565 100644
--- a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
+++ b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
@@ -147,7 +147,7 @@ fn test() {
r#"
//- minicore: option, try
fn test() {
- try {
+ let _: Option<_> = try {
|| {
let x = Some(2);
Some(x?)
diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index 5410f8b58a..5a456504e1 100644
--- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -1006,18 +1006,18 @@ fn func() {
#![allow(unused_variables)]
#[warn(nonstandard_style)]
fn foo() {
- let BAR;
+ let BAR: i32;
// ^^^ 💡 warn: Variable `BAR` should have snake_case name, e.g. `bar`
#[allow(non_snake_case)]
- let FOO;
+ let FOO: i32;
}
#[warn(nonstandard_style)]
fn foo() {
- let BAR;
+ let BAR: i32;
// ^^^ 💡 warn: Variable `BAR` should have snake_case name, e.g. `bar`
#[expect(non_snake_case)]
- let FOO;
+ let FOO: i32;
#[allow(non_snake_case)]
struct qux;
// ^^^ 💡 warn: Structure `qux` should have UpperCamelCase name, e.g. `Qux`
@@ -1060,7 +1060,7 @@ mod FINE_WITH_BAD_CASE;
struct QUX;
const foo: i32 = 0;
fn BAR() {
- let BAZ;
+ let BAZ: i32;
_ = BAZ;
}
"#,
diff --git a/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs b/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
index 25220704e0..2a31a41fbc 100644
--- a/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
+++ b/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
@@ -43,6 +43,8 @@ struct Bar<T, U>(T, U);
fn foo() {
let _ = Bar::<()>;
// ^^^^^^ error: this struct takes 2 generic arguments but 1 generic argument was supplied
+ // ^^^^^^^^^ error: type annotations needed
+ // | full type: `fn Bar<(), {unknown}>((), {unknown}) -> Bar<(), {unknown}>`
}
"#,
@@ -51,6 +53,10 @@ fn foo() {
#[test]
fn enum_variant() {
+ // FIXME: We should not have a "type annotations needed" error here, but to do that
+ // we'll need to have access to the `InferenceContext` in `TyLoweringContext`, to
+ // generate the infer var with a dummy span (instead of inserting it after the fact
+ // with a non-dummy span).
check_diagnostics(
r#"
enum Enum<T, U> {
@@ -60,8 +66,12 @@ enum Enum<T, U> {
fn foo() {
let _ = Enum::<()>::Variant;
// ^^^^^^ error: this enum takes 2 generic arguments but 1 generic argument was supplied
+ // ^^^^^^^^^^^^^^^^^^^ error: type annotations needed
+ // | full type: `fn Variant<(), {unknown}>((), {unknown}) -> Enum<(), {unknown}>`
let _ = Enum::Variant::<()>;
// ^^^^^^ error: this enum takes 2 generic arguments but 1 generic argument was supplied
+ // ^^^^^^^^^^^^^^^^^^^ error: type annotations needed
+ // | full type: `fn Variant<(), {unknown}>((), {unknown}) -> Enum<(), {unknown}>`
}
"#,
@@ -127,6 +137,8 @@ struct Bar<T, const N: usize>(T);
fn bar() {
let _ = Bar::<()>;
// ^^^^^^ error: this struct takes 2 generic arguments but 1 generic argument was supplied
+ // ^^^^^^^^^ error: type annotations needed
+ // | full type: `fn Bar<(), _>(()) -> Bar<(), _>`
}
"#,
);
diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 4c0985c7ae..b900a8f5cc 100644
--- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -453,6 +453,8 @@ fn g() {
b::<1, 3>(0, 2);
b(0, 1, 2);
+ // ^ error: type annotations needed
+ // | full type: `fn b<_, _>(u8, u8)`
//^ error: expected 4 arguments, found 3
}
"#,
diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 85368cc09f..117702923b 100644
--- a/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -293,12 +293,15 @@ fn baz(s: S) -> i32 {
#[test]
fn missing_record_pat_field_box() {
check_diagnostics(
- r"
+ r#"
+#![feature(lang_items)]
+#[lang = "owned_box"]
+struct Box<T>(T);
struct S { s: Box<u32> }
fn x(a: S) {
let S { box s } = a;
}
-",
+"#,
)
}
diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 355617a2b1..a845e0b59a 100644
--- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1340,6 +1340,7 @@ pub fn foo<T: Foo>(_: T) -> (T::Out,) { loop { } }
fn main() {
let _x = foo(2);
+ // ^^ error: type annotations needed
}
"#,
);
diff --git a/crates/ide-diagnostics/src/handlers/type_must_be_known.rs b/crates/ide-diagnostics/src/handlers/type_must_be_known.rs
index 4b72497408..5363f4a5ce 100644
--- a/crates/ide-diagnostics/src/handlers/type_must_be_known.rs
+++ b/crates/ide-diagnostics/src/handlers/type_must_be_known.rs
@@ -1,17 +1,56 @@
+use either::Either;
+use hir::HirDisplay;
+use stdx::format_to;
+use syntax::{AstNode, SyntaxNodePtr, ast};
+
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
// Diagnostic: type-must-be-known
//
// This diagnostic is triggered when rust-analyzer cannot infer some type.
-pub(crate) fn type_must_be_known(
- ctx: &DiagnosticsContext<'_>,
- d: &hir::TypeMustBeKnown,
+pub(crate) fn type_must_be_known<'db>(
+ ctx: &DiagnosticsContext<'db>,
+ d: &hir::TypeMustBeKnown<'db>,
) -> Diagnostic {
+ let mut at_point = d.at_point.map(|it| it.syntax_node_ptr());
+ let mut top_term = d.top_term.clone();
+
+ // Do some adjustments to the node: FIXME: We should probably do that at the emitting site.
+ let node = ctx.sema.to_node(d.at_point);
+ if let Either::Right(Either::Left(expr)) = &node
+ && let Some(Either::Left(top_ty)) = &d.top_term
+ && let Some(expr_ty) = ctx.sema.type_of_expr(expr)
+ && expr_ty.original == *top_ty
+ && !top_ty.is_unknown()
+ && let Some(parent) = expr.syntax().parent().and_then(ast::CallExpr::cast)
+ && let Some(callable) = top_ty.as_callable(ctx.db())
+ && let ret_ty = callable.return_type()
+ && ret_ty.contains_unknown()
+ {
+ top_term = Some(Either::Left(ret_ty));
+ at_point.value = SyntaxNodePtr::new(parent.syntax());
+ }
+
+ let message = match &top_term {
+ Some(top_term) if !matches!(top_term, Either::Left(ty) if ty.is_unknown()) => {
+ let mut message = "type annotations needed\nfull type: `".to_owned();
+ match top_term {
+ Either::Left(ty) => {
+ format_to!(message, "{}", ty.display(ctx.db(), ctx.display_target))
+ }
+ Either::Right(konst) => message.push_str(konst),
+ }
+ message.push_str("`\n");
+ message
+ }
+ Some(_) => "type annotations needed".to_owned(),
+ None => "type annotations needed; type must be known at this point".to_owned(),
+ };
Diagnostic::new_with_syntax_node_ptr(
ctx,
DiagnosticCode::RustcHardError("E0282"),
- "type annotations needed; type must be known at this point",
- d.at_point.map(|it| it.into()),
+ message,
+ at_point,
)
}
@@ -20,7 +59,7 @@ mod tests {
use crate::tests::check_diagnostics;
#[test]
- fn smoke_test() {
+ fn some_expressions_require_knowing_type() {
check_diagnostics(
r#"
fn foo() {
@@ -36,4 +75,32 @@ fn foo() {
"#,
);
}
+
+ #[test]
+ fn binding_without_type() {
+ check_diagnostics(
+ r#"
+fn any<T>() -> T { loop {} }
+fn foo() {
+ let _x = any();
+ // ^^^^^ error: type annotations needed
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn struct_with_generic() {
+ check_diagnostics(
+ r#"
+struct X<T>(T);
+fn any<T>() -> X<T> { loop {} }
+fn foo() {
+ let _x = any();
+ // ^^^^^ error: type annotations needed
+ // | full type: `X<{unknown}>`
+}
+ "#,
+ );
+ }
}
diff --git a/crates/ide-diagnostics/src/handlers/typed_hole.rs b/crates/ide-diagnostics/src/handlers/typed_hole.rs
index fd1674e2a4..ddd1dd402e 100644
--- a/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -166,6 +166,8 @@ fn t<T>() -> T { loop {} }
r#"
fn main() {
let _x = [(); _];
+ // ^ error: type annotations needed
+ // | full type: `[(); _]`
// FIXME: This should trigger error
// let _y: [(); 10] = [(); _];
_ = 0;
diff --git a/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs b/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs
index 9883bcc84f..301613e920 100644
--- a/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs
+++ b/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs
@@ -2722,6 +2722,13 @@ fn foo() {
tracing::error!();
}
"#,
- &["E0432", "inactive-code", "unresolved-macro-call", "syntax-error", "macro-error"],
+ &[
+ "E0432",
+ "E0282",
+ "inactive-code",
+ "unresolved-macro-call",
+ "syntax-error",
+ "macro-error",
+ ],
);
}
diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs
index de8c3f2e55..9088efeca4 100644
--- a/crates/macros/src/lib.rs
+++ b/crates/macros/src/lib.rs
@@ -5,7 +5,7 @@ use syn::parse_quote;
use synstructure::decl_derive;
decl_derive!(
- [TypeFoldable, attributes(type_foldable)] =>
+ [TypeFoldable, attributes(type_foldable, type_visitable)] =>
/// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported).
///
/// The fold will produce a value of the same struct or enum variant as the input, with
@@ -102,8 +102,10 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
vi.construct(|_, index| {
let bind = &bindings[index];
- // retain value of fields with #[type_foldable(identity)]
- if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
+ // retain value of fields with #[type_foldable(identity)] or #[type_visitable(ignore)]
+ if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity")
+ || has_ignore_attr(&bind.ast().attrs, "type_visitable", "ignore")
+ {
bind.to_token_stream()
} else {
quote! {
@@ -118,8 +120,10 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
vi.construct(|_, index| {
let bind = &bindings[index];
- // retain value of fields with #[type_foldable(identity)]
- if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
+ // retain value of fields with #[type_foldable(identity)] or #[type_visitable(ignore)]
+ if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity")
+ || has_ignore_attr(&bind.ast().attrs, "type_visitable", "ignore")
+ {
bind.to_token_stream()
} else {
quote! {
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index c447870e96..33a20951da 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -67,7 +67,7 @@
//! size_of: sized
//! sized:
//! slice:
-//! str:
+//! str: sized, result
//! sync: sized
//! transmute:
//! try: infallible
@@ -1726,6 +1726,22 @@ pub mod iter {
}
}
+ pub struct Map<I, F> {
+ iter: I,
+ f: F,
+ }
+ impl<B, I: Iterator, F> Iterator for Map<I, F>
+ where
+ F: FnMut(I::Item) -> B,
+ {
+ type Item = B;
+
+ #[inline]
+ fn next(&mut self) -> B {
+ loop {}
+ }
+ }
+
pub struct FilterMap<I, F> {
iter: I,
f: F,
@@ -1800,6 +1816,13 @@ pub mod iter {
{
loop {}
}
+ fn map<B, F>(self, _f: F) -> crate::iter::Map<Self, F>
+ where
+ Self: Sized,
+ F: FnMut(Self::Item) -> B,
+ {
+ loop {}
+ }
fn filter_map<B, F>(self, _f: F) -> crate::iter::FilterMap<Self, F>
where
Self: Sized,