Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22313 from ChayimFriedman2/visit-traits
internal: Refactor visiting and tracking of placeholder types
Lukas Wirth 3 days ago
parent 20a5e4f · parent da71dd6 · commit e674e18
-rw-r--r--crates/hir-def/src/expr_store.rs291
-rw-r--r--crates/hir-def/src/hir/type_ref.rs70
-rw-r--r--crates/hir-ty/src/consteval.rs10
-rw-r--r--crates/hir-ty/src/infer.rs25
-rw-r--r--crates/hir-ty/src/infer/diagnostics.rs36
-rw-r--r--crates/hir-ty/src/infer/path.rs15
-rw-r--r--crates/hir-ty/src/lib.rs3
-rw-r--r--crates/hir-ty/src/lower.rs58
-rw-r--r--crates/hir-ty/src/lower/path.rs2
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs62
-rw-r--r--crates/hir/src/source_analyzer.rs52
11 files changed, 361 insertions, 263 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs
index c195106498..4dc7267231 100644
--- a/crates/hir-def/src/expr_store.rs
+++ b/crates/hir-def/src/expr_store.rs
@@ -28,14 +28,18 @@ use tt::TextRange;
use crate::{
AdtId, BlockId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax,
db::DefDatabase,
- expr_store::path::Path,
+ expr_store::path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
hir::{
Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, InlineAsm, Label,
- LabelId, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, Statement,
+ LabelId, MatchArm, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread,
+ Statement,
},
nameres::{DefMap, block_def_map},
signatures::VariantFields,
- type_ref::{LifetimeRef, LifetimeRefId, PathId, TypeRef, TypeRefId},
+ type_ref::{
+ ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, PathId, RefType, TypeBound,
+ TypeRef, TypeRefId, UseArgRef,
+ },
};
pub use self::body::{Body, BodySourceMap};
@@ -602,38 +606,46 @@ impl ExpressionStore {
});
}
- pub fn walk_pats_shallow(&self, pat_id: PatId, mut f: impl FnMut(PatId)) {
+ pub fn visit_pat_children(&self, pat_id: PatId, mut visitor: impl StoreVisitor) {
// Do not use `..` patterns or field accesses here, only destructuring, to ensure we cover all cases
// (we've had multiple bugs with this in the past).
let pat = &self[pat_id];
match pat {
- Pat::Range { start: _, end: _, range_type: _ }
- | Pat::Lit(_)
- | Pat::Path(_)
- | Pat::ConstBlock(_)
- | Pat::Wild
- | Pat::Missing
- | Pat::Rest
- | Pat::Expr(_) => {}
- &Pat::Bind { subpat, id: _ } => {
- if let Some(subpat) = subpat {
- f(subpat);
- }
+ Pat::Range { start, end, range_type: _ } => {
+ visitor.on_expr_opt(*start);
+ visitor.on_expr_opt(*end);
}
- Pat::Or(args)
- | Pat::Tuple { args, ellipsis: _ }
- | Pat::TupleStruct { args, ellipsis: _, path: _ } => {
- args.iter().copied().for_each(f);
+ Pat::Lit(expr) | Pat::ConstBlock(expr) | Pat::Expr(expr) => visitor.on_expr(*expr),
+ Pat::Path(_) | Pat::Wild | Pat::Missing | Pat::Rest => {}
+ &Pat::Bind { subpat, id: _ } => visitor.on_pat_opt(subpat),
+ Pat::Or(args) | Pat::Tuple { args, ellipsis: _ } => visitor.on_pats(args),
+ Pat::TupleStruct { args, ellipsis: _, path } => {
+ visitor.on_pats(args);
+ visitor.on_path(path);
}
- Pat::Ref { pat, mutability: _ } => f(*pat),
+ Pat::Ref { pat, mutability: _ } => visitor.on_pat(*pat),
Pat::Slice { prefix, slice, suffix } => {
- let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
- total_iter.copied().for_each(f);
+ visitor.on_pats(prefix);
+ visitor.on_pat_opt(*slice);
+ visitor.on_pats(suffix);
}
- Pat::Record { args, ellipsis: _, path: _ } => {
- args.iter().for_each(|RecordFieldPat { pat, name: _ }| f(*pat));
+ Pat::Record { args, ellipsis: _, path } => {
+ args.iter().for_each(|RecordFieldPat { pat, name: _ }| visitor.on_pat(*pat));
+ visitor.on_path(path);
+ }
+ Pat::Box { inner } | Pat::Deref { inner } => visitor.on_pat(*inner),
+ }
+ }
+
+ pub fn walk_pats_shallow(&self, pat_id: PatId, f: impl FnMut(PatId)) {
+ return self.visit_pat_children(pat_id, Visitor(f));
+
+ struct Visitor<F>(F);
+
+ impl<F: FnMut(PatId)> StoreVisitor for Visitor<F> {
+ fn on_pat(&mut self, pat: PatId) {
+ (self.0)(pat);
}
- Pat::Box { inner } | Pat::Deref { inner } => f(*inner),
}
}
@@ -659,16 +671,13 @@ impl ExpressionStore {
self.expr_only.as_ref()?.binding_owners.get(&id).copied()
}
- fn walk_child_exprs_impl(&self, expr_id: ExprId, mut visitor: impl ExprVisitor) {
+ pub fn visit_expr_children(&self, expr_id: ExprId, mut visitor: impl StoreVisitor) {
// Do not use `..` patterns or field accesses here, only destructuring, to ensure we cover all cases
// (we've had multiple bugs with this in the past).
match &self[expr_id] {
- Expr::Continue { label: _ }
- | Expr::Missing
- | Expr::Path(_)
- | Expr::OffsetOf(_)
- | Expr::Literal(_)
- | Expr::Underscore => {}
+ Expr::OffsetOf(OffsetOf { container, fields: _ }) => visitor.on_type(*container),
+ Expr::Path(path) => visitor.on_path(path),
+ Expr::Continue { label: _ } | Expr::Missing | Expr::Literal(_) | Expr::Underscore => {}
Expr::InlineAsm(InlineAsm { operands, options: _, kind: _ }) => {
operands.iter().for_each(|(_, op)| match op {
AsmOperand::In { expr, reg: _ }
@@ -696,10 +705,11 @@ impl ExpressionStore {
| Expr::Unsafe { statements, tail, id: _ } => {
for stmt in statements {
match stmt {
- Statement::Let { initializer, else_branch, pat, type_ref: _ } => {
+ Statement::Let { initializer, else_branch, pat, type_ref } => {
visitor.on_expr_opt(*initializer);
visitor.on_expr_opt(*else_branch);
visitor.on_pat(*pat);
+ visitor.on_type_opt(*type_ref);
}
Statement::Expr { expr: expression, has_semi: _ } => {
visitor.on_expr(*expression)
@@ -714,9 +724,10 @@ impl ExpressionStore {
visitor.on_expr(*callee);
visitor.on_exprs(args);
}
- Expr::MethodCall { receiver, args, generic_args: _, method_name: _ } => {
+ Expr::MethodCall { receiver, args, generic_args, method_name: _ } => {
visitor.on_expr(*receiver);
visitor.on_exprs(args);
+ visitor.on_generic_args_opt(generic_args);
}
Expr::Match { expr, arms } => {
visitor.on_expr(*expr);
@@ -731,7 +742,7 @@ impl ExpressionStore {
| Expr::Yield { expr }
| Expr::Yeet { expr } => visitor.on_expr_opt(*expr),
Expr::Become { expr } => visitor.on_expr(*expr),
- Expr::RecordLit { fields, spread, path: _ } => {
+ Expr::RecordLit { fields, spread, path } => {
for RecordLitField { name: _, expr } in fields.iter() {
visitor.on_expr(*expr);
}
@@ -739,17 +750,13 @@ impl ExpressionStore {
RecordSpread::Expr(expr) => visitor.on_expr(*expr),
RecordSpread::None | RecordSpread::FieldDefaults => {}
}
+ visitor.on_path(path);
}
- Expr::Closure {
- body,
- args,
- arg_types: _,
- capture_by: _,
- closure_kind: _,
- ret_type: _,
- } => {
+ Expr::Closure { body, args, arg_types, ret_type, capture_by: _, closure_kind: _ } => {
visitor.on_expr(*body);
visitor.on_pats(args);
+ arg_types.iter().for_each(|arg_type| visitor.on_type_opt(*arg_type));
+ visitor.on_type_opt(*ret_type);
}
Expr::BinaryOp { lhs, rhs, op: _ } => {
visitor.on_expr(*lhs);
@@ -763,9 +770,12 @@ impl ExpressionStore {
visitor.on_expr(*base);
visitor.on_expr(*index);
}
+ Expr::Cast { expr, type_ref } => {
+ visitor.on_expr(*expr);
+ visitor.on_type(*type_ref);
+ }
Expr::Field { expr, name: _ }
| Expr::Await { expr }
- | Expr::Cast { expr, type_ref: _ }
| Expr::Ref { expr, mutability: _, rawness: _ }
| Expr::UnaryOp { expr, op: _ }
| Expr::Box { expr }
@@ -777,7 +787,7 @@ impl ExpressionStore {
Array::ElementList { elements } => visitor.on_exprs(elements),
Array::Repeat { initializer, repeat } => {
visitor.on_expr(*initializer);
- visitor.on_expr(*repeat)
+ visitor.on_anon_const_expr(*repeat)
}
},
&Expr::Assignment { target, value } => {
@@ -789,14 +799,14 @@ impl ExpressionStore {
/// Walks the immediate children expressions and calls `f` for each child expression.
pub fn walk_child_exprs(&self, expr_id: ExprId, callback: impl FnMut(ExprId)) {
- return self.walk_child_exprs_impl(expr_id, Visitor { callback, store: self });
+ return self.visit_expr_children(expr_id, Visitor { callback, store: self });
struct Visitor<'a, F> {
callback: F,
store: &'a ExpressionStore,
}
- impl<F: FnMut(ExprId)> ExprVisitor for Visitor<'_, F> {
+ impl<F: FnMut(ExprId)> StoreVisitor for Visitor<'_, F> {
fn on_expr(&mut self, expr: ExprId) {
(self.callback)(expr);
}
@@ -810,48 +820,61 @@ impl ExpressionStore {
/// Walks the immediate children expressions and calls `f` for each child expression but does
/// not walk expressions within patterns.
pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, callback: impl FnMut(ExprId)) {
- return self.walk_child_exprs_impl(expr_id, Visitor { callback });
+ return self.visit_expr_children(expr_id, Visitor { callback });
struct Visitor<F> {
callback: F,
}
- impl<F: FnMut(ExprId)> ExprVisitor for Visitor<F> {
+ impl<F: FnMut(ExprId)> StoreVisitor for Visitor<F> {
fn on_expr(&mut self, expr: ExprId) {
(self.callback)(expr);
}
+ }
+ }
- fn on_pat(&mut self, _pat: PatId) {}
+ pub fn walk_exprs_in_pat(&self, pat_id: PatId, callback: impl FnMut(ExprId)) {
+ return Visitor { callback, store: self }.on_pat(pat_id);
+
+ struct Visitor<'a, F> {
+ callback: F,
+ store: &'a ExpressionStore,
+ }
+
+ impl<F: FnMut(ExprId)> StoreVisitor for Visitor<'_, F> {
+ fn on_expr(&mut self, expr: ExprId) {
+ (self.callback)(expr);
+ }
+
+ fn on_pat(&mut self, pat: PatId) {
+ self.store.visit_pat_children(pat, self);
+ }
}
}
- pub fn walk_exprs_in_pat(&self, pat_id: PatId, mut f: impl FnMut(ExprId)) {
- self.walk_pats(pat_id, &mut |pat| match self[pat] {
- Pat::Expr(expr) | Pat::ConstBlock(expr) | Pat::Lit(expr) => {
- f(expr);
+ pub fn visit_type_ref_children(&self, type_ref: TypeRefId, mut visitor: impl StoreVisitor) {
+ match &self[type_ref] {
+ TypeRef::Never | TypeRef::Placeholder | TypeRef::TypeParam(_) | TypeRef::Error => {}
+ TypeRef::Tuple(types) => visitor.on_types(types),
+ TypeRef::Path(path) => visitor.on_path(path),
+ TypeRef::RawPtr(inner, _) | TypeRef::Slice(inner) => visitor.on_type(*inner),
+ TypeRef::Reference(ref_type) => {
+ let RefType { ty, lifetime, mutability: _ } = &**ref_type;
+ visitor.on_type(*ty);
+ visitor.on_lifetime_opt(*lifetime);
}
- Pat::Range { start, end, range_type: _ } => {
- if let Some(start) = start {
- f(start);
- }
- if let Some(end) = end {
- f(end);
- }
+ TypeRef::Array(ArrayType { ty, len: ConstRef { expr: len } }) => {
+ visitor.on_type(*ty);
+ visitor.on_anon_const_expr(*len);
}
- Pat::Missing
- | Pat::Rest
- | Pat::Wild
- | Pat::Tuple { .. }
- | Pat::Or(_)
- | Pat::Record { .. }
- | Pat::Slice { .. }
- | Pat::Path(_)
- | Pat::Bind { .. }
- | Pat::TupleStruct { .. }
- | Pat::Ref { .. }
- | Pat::Box { .. }
- | Pat::Deref { .. } => {}
- });
+ TypeRef::Fn(fn_type) => {
+ let FnType { params, is_varargs: _, is_unsafe: _, abi: _ } = &**fn_type;
+ params.iter().for_each(|(_, param_ty)| visitor.on_type(*param_ty));
+ }
+ TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
+ visitor.on_type_bounds(bounds)
+ }
+ }
}
#[inline]
@@ -918,21 +941,127 @@ impl ExpressionStore {
}
}
-trait ExprVisitor {
- fn on_expr(&mut self, expr: ExprId);
- fn on_pat(&mut self, pat: PatId);
+pub trait StoreVisitor {
+ fn on_expr(&mut self, expr: ExprId) {
+ let _ = expr;
+ }
+ fn on_anon_const_expr(&mut self, expr: ExprId) {
+ self.on_expr(expr);
+ }
+ fn on_pat(&mut self, pat: PatId) {
+ let _ = pat;
+ }
+ fn on_type(&mut self, ty: TypeRefId) {
+ let _ = ty;
+ }
+ fn on_lifetime(&mut self, lifetime: LifetimeRefId) {
+ let _ = lifetime;
+ }
+}
+
+impl<V: StoreVisitor> StoreVisitor for &mut V {
+ fn on_expr(&mut self, expr: ExprId) {
+ V::on_expr(self, expr);
+ }
+ fn on_anon_const_expr(&mut self, expr: ExprId) {
+ V::on_anon_const_expr(self, expr);
+ }
+ fn on_pat(&mut self, pat: PatId) {
+ V::on_pat(self, pat);
+ }
+ fn on_type(&mut self, ty: TypeRefId) {
+ V::on_type(self, ty);
+ }
+ fn on_lifetime(&mut self, lifetime: LifetimeRefId) {
+ V::on_lifetime(self, lifetime);
+ }
+}
+
+trait StoreVisitorExt: StoreVisitor {
+ fn on_generic_args(&mut self, args: &GenericArgs) {
+ let GenericArgs { args, bindings, parenthesized: _, has_self_type: _ } = args;
+ for arg in args {
+ match arg {
+ GenericArg::Type(arg) => self.on_type(*arg),
+ GenericArg::Const(ConstRef { expr }) => self.on_anon_const_expr(*expr),
+ GenericArg::Lifetime(arg) => self.on_lifetime(*arg),
+ }
+ }
+ for AssociatedTypeBinding { name: _, args, type_ref, bounds } in bindings {
+ self.on_generic_args_opt(args);
+ self.on_type_opt(*type_ref);
+ self.on_type_bounds(bounds);
+ }
+ }
+
+ fn on_type_bound(&mut self, bound: &TypeBound) {
+ match bound {
+ TypeBound::Path(path_id, _) => self.on_type(path_id.type_ref()),
+ TypeBound::ForLifetime(_, path_id) => self.on_type(path_id.type_ref()),
+ TypeBound::Lifetime(lifetime) => self.on_lifetime(*lifetime),
+ TypeBound::Use(args) => {
+ for arg in args {
+ match arg {
+ UseArgRef::Lifetime(lifetime) => self.on_lifetime(*lifetime),
+ UseArgRef::Name(_) => {}
+ }
+ }
+ }
+ TypeBound::Error => {}
+ }
+ }
+
+ fn on_path(&mut self, path: &Path) {
+ match path {
+ Path::Normal(path) => {
+ let NormalPath { generic_args, type_anchor, mod_path: _ } = &**path;
+ generic_args.iter().for_each(|generic_arg| self.on_generic_args_opt(generic_arg));
+ self.on_type_opt(*type_anchor);
+ }
+ Path::BarePath(_) | Path::LangItem(..) => {}
+ }
+ }
+
fn on_expr_opt(&mut self, expr: Option<ExprId>) {
if let Some(expr) = expr {
self.on_expr(expr);
}
}
+ fn on_pat_opt(&mut self, pat: Option<PatId>) {
+ if let Some(pat) = pat {
+ self.on_pat(pat);
+ }
+ }
+ fn on_type_opt(&mut self, ty: Option<TypeRefId>) {
+ if let Some(ty) = ty {
+ self.on_type(ty);
+ }
+ }
+ fn on_lifetime_opt(&mut self, lifetime: Option<LifetimeRefId>) {
+ if let Some(lifetime) = lifetime {
+ self.on_lifetime(lifetime);
+ }
+ }
+ fn on_generic_args_opt(&mut self, args: &Option<impl Borrow<GenericArgs>>) {
+ if let Some(args) = args {
+ self.on_generic_args(args.borrow());
+ }
+ }
+
fn on_exprs(&mut self, exprs: impl IntoIterator<Item: Borrow<ExprId>>) {
exprs.into_iter().for_each(|expr| self.on_expr(*expr.borrow()));
}
- fn on_pats(&mut self, exprs: impl IntoIterator<Item: Borrow<PatId>>) {
- exprs.into_iter().for_each(|expr| self.on_pat(*expr.borrow()));
+ fn on_pats(&mut self, pats: impl IntoIterator<Item: Borrow<PatId>>) {
+ pats.into_iter().for_each(|pat| self.on_pat(*pat.borrow()));
+ }
+ fn on_types(&mut self, types: impl IntoIterator<Item: Borrow<TypeRefId>>) {
+ types.into_iter().for_each(|ty| self.on_type(*ty.borrow()));
+ }
+ fn on_type_bounds(&mut self, bounds: impl IntoIterator<Item: Borrow<TypeBound>>) {
+ bounds.into_iter().for_each(|bound| self.on_type_bound(bound.borrow()));
}
}
+impl<V: StoreVisitor> StoreVisitorExt for V {}
impl Index<ExprId> for ExpressionStore {
type Output = Expr;
diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs
index 1f48a82a89..43e29c1f5f 100644
--- a/crates/hir-def/src/hir/type_ref.rs
+++ b/crates/hir-def/src/hir/type_ref.rs
@@ -8,10 +8,7 @@ use thin_vec::ThinVec;
use crate::{
LifetimeParamId, TypeParamId,
- expr_store::{
- ExpressionStore,
- path::{GenericArg, Path},
- },
+ expr_store::{ExpressionStore, path::Path},
hir::ExprId,
};
@@ -191,71 +188,6 @@ impl TypeRef {
pub(crate) fn unit() -> TypeRef {
TypeRef::Tuple(ThinVec::new())
}
-
- pub fn walk(this: TypeRefId, map: &ExpressionStore, f: &mut impl FnMut(TypeRefId, &TypeRef)) {
- go(this, f, map);
-
- fn go(
- type_ref_id: TypeRefId,
- f: &mut impl FnMut(TypeRefId, &TypeRef),
- map: &ExpressionStore,
- ) {
- let type_ref = &map[type_ref_id];
- f(type_ref_id, type_ref);
- match type_ref {
- TypeRef::Fn(fn_) => {
- fn_.params.iter().for_each(|&(_, param_type)| go(param_type, f, map))
- }
- TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)),
- TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map),
- TypeRef::Reference(it) => go(it.ty, f, map),
- TypeRef::Array(it) => go(it.ty, f, map),
- TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
- for bound in bounds {
- match bound {
- &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => {
- go_path(&map[path], f, map)
- }
- TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
- }
- }
- }
- TypeRef::Path(path) => go_path(path, f, map),
- TypeRef::Never | TypeRef::Placeholder | TypeRef::Error | TypeRef::TypeParam(_) => {}
- };
- }
-
- fn go_path(path: &Path, f: &mut impl FnMut(TypeRefId, &TypeRef), map: &ExpressionStore) {
- if let Some(type_ref) = path.type_anchor() {
- go(type_ref, f, map);
- }
- for segment in path.segments().iter() {
- if let Some(args_and_bindings) = segment.args_and_bindings {
- for arg in args_and_bindings.args.iter() {
- match arg {
- GenericArg::Type(type_ref) => {
- go(*type_ref, f, map);
- }
- GenericArg::Const(_) | GenericArg::Lifetime(_) => {}
- }
- }
- for binding in args_and_bindings.bindings.iter() {
- if let Some(type_ref) = binding.type_ref {
- go(type_ref, f, map);
- }
- for bound in binding.bounds.iter() {
- match bound {
- &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => {
- go_path(&map[path], f, map)
- }
- TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
- }
- }
- }
- }
- }
- }
- }
}
impl TypeBound {
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 21e368c88f..e1d6cec594 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -19,7 +19,7 @@ use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _};
use stdx::never;
use crate::{
- ParamEnvAndCrate,
+ ParamEnvAndCrate, Span,
db::{AnonConstId, AnonConstLoc, GeneralConstId, HirDatabase},
display::DisplayTarget,
generics::Generics,
@@ -27,7 +27,7 @@ use crate::{
next_solver::{
Allocation, Const, ConstKind, Consts, DbInterner, DefaultAny, GenericArgs, ParamConst,
ScalarInt, StoredAllocation, StoredEarlyBinder, StoredGenericArgs, Ty, TyKind,
- UnevaluatedConst, ValTreeKind, default_types, infer::InferCtxt,
+ UnevaluatedConst, ValTreeKind, default_types,
},
traits::StoredParamEnvAndCrate,
};
@@ -351,13 +351,13 @@ pub(crate) fn create_anon_const<'a, 'db>(
resolver: &Resolver<'db>,
expected_ty: Ty<'db>,
generics: &dyn Fn() -> &'a Generics<'db>,
- infcx: Option<&InferCtxt<'db>>,
+ create_var: Option<&mut dyn FnMut(Span) -> Const<'db>>,
forbid_params_after: Option<u32>,
) -> Result<Const<'db>, CreateConstError<'db>> {
match &store[expr] {
Expr::Literal(literal) => intern_const_ref(interner, literal, expected_ty),
- Expr::Underscore => match infcx {
- Some(infcx) => Ok(infcx.next_const_var(expr.into())),
+ Expr::Underscore => match create_var {
+ Some(create_var) => Ok(create_var(expr.into())),
None => Err(CreateConstError::UnderscoreExpr),
},
Expr::Path(path)
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 1185073316..39ffb91a8c 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -82,14 +82,16 @@ use crate::{
expr_use_visitor::{FakeReadCause, Place},
},
coerce::{CoerceMany, DynamicCoerceMany},
- diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext},
+ diagnostics::{
+ Diagnostics, InferenceTyLoweringContext as TyLoweringContext,
+ InferenceTyLoweringVarsCtx,
+ },
expr::ExprIsRead,
pat::PatOrigin,
unify::resolve_completely::WriteBackCtxt,
},
lower::{
- ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, TyLoweringInferVarsCtx,
- diagnostics::TyLoweringDiagnostic,
+ ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic,
},
method_resolution::CandidateId,
next_solver::{
@@ -1834,10 +1836,10 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> R,
) -> R {
let infer_vars = match types_source {
- InferenceTyDiagnosticSource::Body => Some(TyLoweringInferVarsCtx {
+ InferenceTyDiagnosticSource::Body => Some(&mut InferenceTyLoweringVarsCtx {
table: &mut self.table,
- type_of_placeholder: &mut self.result.type_of_type_placeholder,
- }),
+ type_of_type_placeholder: &mut self.result.type_of_type_placeholder,
+ } as _),
InferenceTyDiagnosticSource::Signature => None,
};
let mut ctx = TyLoweringContext::new(
@@ -1919,7 +1921,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
&self.resolver,
expected_ty,
&|| self.generics(),
- Some(self.infcx()),
+ Some(&mut |span| self.table.next_const_var(span)),
(!(allow_using_generic_params && self.allow_using_generic_params)).then_some(0),
);
@@ -2169,6 +2171,10 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
value_ns: bool,
) -> (Ty<'db>, Option<VariantId>) {
let interner = self.interner();
+ let mut vars_ctx = InferenceTyLoweringVarsCtx {
+ table: &mut self.table,
+ type_of_type_placeholder: &mut self.result.type_of_type_placeholder,
+ };
let mut ctx = TyLoweringContext::new(
self.db,
&self.resolver,
@@ -2180,10 +2186,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
&self.generics,
LifetimeElisionKind::Infer,
self.allow_using_generic_params,
- Some(TyLoweringInferVarsCtx {
- table: &mut self.table,
- type_of_placeholder: &mut self.result.type_of_type_placeholder,
- }),
+ Some(&mut vars_ctx),
&self.defined_anon_consts,
);
diff --git a/crates/hir-ty/src/infer/diagnostics.rs b/crates/hir-ty/src/infer/diagnostics.rs
index 50feab8dd4..dd0efea4d7 100644
--- a/crates/hir-ty/src/infer/diagnostics.rs
+++ b/crates/hir-ty/src/infer/diagnostics.rs
@@ -6,21 +6,24 @@ use std::cell::{OnceCell, RefCell};
use std::ops::{Deref, DerefMut};
use either::Either;
-use hir_def::expr_store::ExpressionStore;
use hir_def::expr_store::path::Path;
use hir_def::{ExpressionStoreOwnerId, GenericDefId};
+use hir_def::{expr_store::ExpressionStore, type_ref::TypeRefId};
use hir_def::{hir::ExprOrPatId, resolver::Resolver};
use la_arena::{Idx, RawIdx};
+use rustc_hash::FxHashMap;
use thin_vec::ThinVec;
use crate::{
- InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic,
+ InferenceDiagnostic, InferenceTyDiagnosticSource, Span, TyLoweringDiagnostic,
db::{AnonConstId, HirDatabase},
generics::Generics,
+ infer::unify::InferenceTable,
lower::{
ForbidParamsAfterReason, LifetimeElisionKind, TyLoweringContext, TyLoweringInferVarsCtx,
path::{PathDiagnosticCallback, PathLoweringContext},
},
+ next_solver::{Const, Region, StoredTy, Ty},
};
// Unfortunately, this struct needs to use interior mutability (but we encapsulate it)
@@ -55,6 +58,33 @@ pub(crate) struct PathDiagnosticCallbackData<'a> {
diagnostics: &'a Diagnostics,
}
+pub(super) struct InferenceTyLoweringVarsCtx<'a, 'db> {
+ pub(super) table: &'a mut InferenceTable<'db>,
+ pub(super) type_of_type_placeholder: &'a mut FxHashMap<TypeRefId, StoredTy>,
+}
+
+impl<'db> TyLoweringInferVarsCtx<'db> for InferenceTyLoweringVarsCtx<'_, 'db> {
+ fn next_ty_var(&mut self, span: Span) -> Ty<'db> {
+ let ty = self.table.infer_ctxt.next_ty_var(span);
+
+ if let Span::TypeRefId(type_ref) = span {
+ self.type_of_type_placeholder.insert(type_ref, ty.store());
+ }
+
+ ty
+ }
+ fn next_const_var(&mut self, span: Span) -> Const<'db> {
+ self.table.infer_ctxt.next_const_var(span)
+ }
+ fn next_region_var(&mut self, span: Span) -> Region<'db> {
+ self.table.infer_ctxt.next_region_var(span)
+ }
+
+ fn as_table(&mut self) -> Option<&mut InferenceTable<'db>> {
+ Some(self.table)
+ }
+}
+
pub(super) struct InferenceTyLoweringContext<'db, 'a> {
ctx: TyLoweringContext<'db, 'a>,
diagnostics: &'a Diagnostics,
@@ -75,7 +105,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> {
generics: &'a OnceCell<Generics<'db>>,
lifetime_elision: LifetimeElisionKind<'db>,
allow_using_generic_params: bool,
- infer_vars: Option<TyLoweringInferVarsCtx<'a, 'db>>,
+ infer_vars: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>,
defined_anon_consts: &'a RefCell<ThinVec<AnonConstId>>,
) -> Self {
let mut ctx = TyLoweringContext::new(
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index c5b3d184b1..704f15cc86 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -12,8 +12,10 @@ use stdx::never;
use crate::{
InferenceDiagnostic, Span, ValueTyDefId,
- infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
- lower::{GenericPredicates, LifetimeElisionKind, TyLoweringInferVarsCtx},
+ infer::{
+ InferenceTyLoweringVarsCtx, diagnostics::InferenceTyLoweringContext as TyLoweringContext,
+ },
+ lower::{GenericPredicates, LifetimeElisionKind},
method_resolution::{self, CandidateId, MethodError},
next_solver::{
GenericArg, GenericArgs, TraitRef, Ty, Unnormalized, infer::traits::ObligationCause,
@@ -139,6 +141,10 @@ impl<'db> InferenceContext<'_, 'db> {
no_diagnostics: bool,
) -> Option<(ValueNs, Option<GenericArgs<'db>>)> {
// Don't use `self.make_ty()` here as we need `orig_ns`.
+ let mut vars_ctx = InferenceTyLoweringVarsCtx {
+ table: &mut self.table,
+ type_of_type_placeholder: &mut self.result.type_of_type_placeholder,
+ };
let mut ctx = TyLoweringContext::new(
self.db,
&self.resolver,
@@ -150,10 +156,7 @@ impl<'db> InferenceContext<'_, 'db> {
&self.generics,
LifetimeElisionKind::Infer,
self.allow_using_generic_params,
- Some(TyLoweringInferVarsCtx {
- table: &mut self.table,
- type_of_placeholder: &mut self.result.type_of_type_placeholder,
- }),
+ Some(&mut vars_ctx),
&self.defined_anon_consts,
);
let mut path_ctx = if no_diagnostics {
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 4c80921423..91e3b85aa1 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -110,7 +110,8 @@ pub use infer::{
};
pub use lower::{
GenericDefaults, GenericDefaultsRef, GenericPredicates, ImplTraits, LifetimeElisionKind,
- TyDefId, TyLoweringContext, TyLoweringResult, ValueTyDefId, diagnostics::*,
+ TyDefId, TyLoweringContext, TyLoweringInferVarsCtx, TyLoweringResult, ValueTyDefId,
+ diagnostics::*,
};
pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db};
pub use target_feature::TargetFeatures;
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 67cc34a404..5b0bcd2be8 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -39,7 +39,7 @@ use la_arena::{Arena, ArenaMap, Idx};
use path::{PathDiagnosticCallback, PathLoweringContext};
use rustc_abi::ExternAbi;
use rustc_ast_ir::Mutability;
-use rustc_hash::{FxHashMap, FxHashSet};
+use rustc_hash::FxHashSet;
use rustc_type_ir::{
AliasTyKind, BoundVarIndexKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection,
ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, TyKind, TypeFoldable,
@@ -185,10 +185,15 @@ pub(crate) enum ForbidParamsAfterReason {
ConstParamTy,
}
-pub(crate) struct TyLoweringInferVarsCtx<'a, 'db> {
- // Technically we can just put an `&InferCtxt` here, but borrowck constraints requires us to put this:
- pub(crate) table: &'a mut InferenceTable<'db>,
- pub(crate) type_of_placeholder: &'a mut FxHashMap<TypeRefId, StoredTy>,
+pub trait TyLoweringInferVarsCtx<'db> {
+ fn next_ty_var(&mut self, span: Span) -> Ty<'db>;
+ fn next_const_var(&mut self, span: Span) -> Const<'db>;
+ fn next_region_var(&mut self, span: Span) -> Region<'db>;
+
+ #[expect(private_interfaces)]
+ fn as_table(&mut self) -> Option<&mut InferenceTable<'db>> {
+ None
+ }
}
pub struct TyLoweringContext<'db, 'a> {
@@ -210,7 +215,7 @@ pub struct TyLoweringContext<'db, 'a> {
forbid_params_after: Option<u32>,
forbid_params_after_reason: ForbidParamsAfterReason,
pub(crate) defined_anon_consts: ThinVec<AnonConstId>,
- infer_vars: Option<TyLoweringInferVarsCtx<'a, 'db>>,
+ infer_vars: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>,
}
impl<'db, 'a> TyLoweringContext<'db, 'a> {
@@ -286,9 +291,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
self.forbid_params_after_reason = reason;
}
- pub(crate) fn with_infer_vars_behavior(
+ pub fn with_infer_vars_behavior(
mut self,
- behavior: Option<TyLoweringInferVarsCtx<'a, 'db>>,
+ behavior: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>,
) -> Self {
self.infer_vars = behavior;
self
@@ -300,26 +305,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
#[track_caller]
pub(crate) fn expect_table(&mut self) -> &mut InferenceTable<'db> {
- self.infer_vars.as_mut().unwrap().table
- }
-
- fn next_ty_var(&mut self, type_ref: TypeRefId) -> Ty<'db> {
- match &mut self.infer_vars {
- Some(infer_vars) => {
- let var = infer_vars.table.next_ty_var(type_ref.into());
- infer_vars.type_of_placeholder.insert(type_ref, var.store());
- var
- }
- None => {
- // FIXME: Emit an error: no infer vars allowed here.
- self.types.types.error
- }
- }
+ self.infer_vars.as_mut().unwrap().as_table().unwrap()
}
- fn next_ty_var_no_placeholder(&mut self, span: Span) -> Ty<'db> {
+ fn next_ty_var(&mut self, span: Span) -> Ty<'db> {
match &mut self.infer_vars {
- Some(infer_vars) => infer_vars.table.next_ty_var(span),
+ Some(infer_vars) => infer_vars.next_ty_var(span),
None => {
// FIXME: Emit an error: no infer vars allowed here.
self.types.types.error
@@ -329,7 +320,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
fn next_const_var(&mut self, span: Span) -> Const<'db> {
match &mut self.infer_vars {
- Some(infer_vars) => infer_vars.table.next_const_var(span),
+ Some(infer_vars) => infer_vars.next_const_var(span),
None => {
// FIXME: Emit an error: no infer vars allowed here.
self.types.consts.error
@@ -339,7 +330,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
fn next_region_var(&mut self, span: Span) -> Region<'db> {
match &mut self.infer_vars {
- Some(infer_vars) => infer_vars.table.next_region_var(span),
+ Some(infer_vars) => infer_vars.next_region_var(span),
None => {
// FIXME: Emit an error: no infer vars allowed here.
self.types.regions.error
@@ -366,6 +357,13 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
}
pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> {
+ #[expect(clippy::manual_map, reason = "a `map()` here generates a borrowck error")]
+ let create_var = match &mut self.infer_vars {
+ Some(infer_vars) => Some(
+ (&mut |span| infer_vars.next_const_var(span)) as &mut dyn FnMut(Span) -> Const<'db>,
+ ),
+ None => None,
+ };
let konst = create_anon_const(
self.interner,
self.def,
@@ -373,8 +371,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
const_ref.expr,
self.resolver,
const_type,
- &|| self.generics(),
- self.infer_vars.as_ref().map(|vars_ctx| &vars_ctx.table.infer_ctxt),
+ &|| self.generics.get_or_init(|| generics(self.db, self.generic_def)),
+ create_var,
self.forbid_params_after,
);
@@ -470,7 +468,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
ref_.lifetime.map_or(self.types.regions.error, |lr| self.lower_lifetime(lr));
Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability))
}
- TypeRef::Placeholder => self.next_ty_var(type_ref_id),
+ TypeRef::Placeholder => self.next_ty_var(type_ref_id.into()),
TypeRef::Fn(fn_) => self.lower_fn_ptr(fn_),
TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
TypeRef::ImplTrait(bounds) => {
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index 0757d57500..ff9718af11 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -792,7 +792,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
{
return default;
}
- self.ctx.ctx.next_ty_var_no_placeholder(span).into()
+ self.ctx.ctx.next_ty_var(span).into()
}
GenericParamDataRef::ConstParamData(param) => {
if !infer_args
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index 46c03e5ac1..b3d31dd40b 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -14,8 +14,8 @@ use hir_def::{
AdtId, CallableDefId, EnumId, HasModule, ItemContainerId, StructId, TraitId, TypeAliasId,
UnionId, VariantId,
attrs::AttrFlags,
- expr_store::ExpressionStore,
- hir::{ClosureKind as HirClosureKind, CoroutineKind as HirCoroutineKind, ExprId},
+ expr_store::{ExpressionStore, StoreVisitor},
+ hir::{ClosureKind as HirClosureKind, CoroutineKind as HirCoroutineKind, ExprId, PatId},
lang_item::LangItems,
signatures::{
EnumFlags, EnumSignature, FnFlags, FunctionSignature, ImplFlags, ImplSignature,
@@ -1966,41 +1966,41 @@ impl<'db> Interner for DbInterner<'db> {
// Collect coroutines.
let (store, root_expr) = def_id.store_and_root_expr(db);
// We can't just visit all exprs, since this may end up in unrelated anon consts.
- append_coroutines_in_expr(db, def_id, store, root_expr, &mut result);
+ CoroutinesVisitor { db: self.db, owner: def_id, store, coroutines: &mut result }
+ .on_expr(root_expr);
return SolverDefIds::new_from_slice(&result);
- fn append_coroutines_in_expr(
- db: &dyn HirDatabase,
+ struct CoroutinesVisitor<'a> {
+ db: &'a dyn HirDatabase,
owner: InferBodyId,
- store: &ExpressionStore,
- expr_id: ExprId,
- result: &mut Vec<SolverDefId>,
- ) {
- let expr = &store[expr_id];
-
- if let hir_def::hir::Expr::Closure {
- closure_kind:
- kind @ (hir_def::hir::ClosureKind::Coroutine { .. }
- | hir_def::hir::ClosureKind::OldCoroutine(_)),
- ..
- } = *expr
- {
- let coroutine =
- InternedCoroutineId::new(db, InternedClosure { owner, expr: expr_id, kind });
- result.push(coroutine.into());
- }
+ store: &'a ExpressionStore,
+ coroutines: &'a mut Vec<SolverDefId>,
+ }
- match expr {
- // The repeat is an anon const.
- &hir_def::hir::Expr::Array(hir_def::hir::Array::Repeat {
- initializer,
- repeat: _,
- }) => append_coroutines_in_expr(db, owner, store, initializer, result),
- _ => store.walk_child_exprs(expr_id, |expr_id| {
- append_coroutines_in_expr(db, owner, store, expr_id, result)
- }),
+ impl StoreVisitor for CoroutinesVisitor<'_> {
+ fn on_expr(&mut self, expr: ExprId) {
+ if let hir_def::hir::Expr::Closure {
+ closure_kind:
+ kind @ (hir_def::hir::ClosureKind::Coroutine { .. }
+ | hir_def::hir::ClosureKind::OldCoroutine(_)),
+ ..
+ } = self.store[expr]
+ {
+ let coroutine = InternedCoroutineId::new(
+ self.db,
+ InternedClosure { owner: self.owner, expr, kind },
+ );
+ self.coroutines.push(coroutine.into());
+ }
+
+ self.store.visit_expr_children(expr, self);
+ }
+ fn on_pat(&mut self, pat: PatId) {
+ self.store.visit_pat_children(pat, self);
}
+ // Do not visit anon consts, they're separate bodies.
+ fn on_anon_const_expr(&mut self, _expr: ExprId) {}
}
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index d5540c4dab..06182620c8 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -24,7 +24,7 @@ use hir_def::{
lang_item::LangItems,
nameres::MacroSubNs,
resolver::{Resolver, TypeNs, ValueNs, resolver_for_scope},
- type_ref::{Mutability, TypeRef, TypeRefId},
+ type_ref::{Mutability, TypeRefId},
};
use hir_expand::{
HirFileId, InFile,
@@ -33,7 +33,7 @@ use hir_expand::{
};
use hir_ty::{
Adjustment, InferBodyId, InferenceResult, LifetimeElisionKind, ParamEnvAndCrate,
- TyLoweringContext,
+ TyLoweringContext, TyLoweringInferVarsCtx,
diagnostics::{
InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields,
unsafe_operations,
@@ -41,8 +41,8 @@ use hir_ty::{
lang_items::lang_items_for_bin_op,
method_resolution::{self, CandidateId},
next_solver::{
- AliasTy, DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, Ty, TyKind, TypingMode,
- infer::DbInternerInferExt,
+ AliasTy, DbInterner, DefaultAny, ErrorGuaranteed, GenericArgs, ParamEnv, Region, Ty,
+ TyKind, TypingMode, infer::DbInternerInferExt,
},
traits::structurally_normalize_ty,
};
@@ -378,7 +378,8 @@ impl<'db> SourceAnalyzer<'db> {
let generic_def = self.resolver.generic_def()?;
let generics = OnceCell::new();
- let mut ty = TyLoweringContext::new(
+ let mut vars_cts = VarsCtx { types: interner.default_types(), infer: self.infer() };
+ let ty = TyLoweringContext::new(
db,
&self.resolver,
self.store()?,
@@ -390,29 +391,30 @@ impl<'db> SourceAnalyzer<'db> {
// small problem).
LifetimeElisionKind::Infer,
)
+ .with_infer_vars_behavior(Some(&mut vars_cts))
.lower_ty(type_ref);
- // Try and substitute unknown types using InferenceResult
- if let Some(infer) = self.infer()
- && let Some(store) = self.store()
- {
- let mut inferred_types = vec![];
- TypeRef::walk(type_ref, store, &mut |type_ref_id, type_ref| {
- if matches!(type_ref, TypeRef::Placeholder) {
- inferred_types.push(infer.type_of_type_placeholder(type_ref_id));
+ struct VarsCtx<'a, 'db> {
+ types: &'db DefaultAny<'db>,
+ infer: Option<&'a InferenceResult>,
+ }
+
+ impl<'db> TyLoweringInferVarsCtx<'db> for VarsCtx<'_, 'db> {
+ fn next_ty_var(&mut self, span: hir_ty::Span) -> Ty<'db> {
+ if let hir_ty::Span::TypeRefId(type_ref) = span
+ && let Some(ty) =
+ self.infer.and_then(|infer| infer.type_of_type_placeholder(type_ref))
+ {
+ ty
+ } else {
+ self.types.types.error
}
- });
- let mut inferred_types = inferred_types.into_iter();
-
- let substituted_ty = hir_ty::next_solver::fold::fold_tys(interner, ty, |ty| {
- if ty.is_ty_error() { inferred_types.next().flatten().unwrap_or(ty) } else { ty }
- });
-
- // Only used the result if the placeholder and unknown type counts matched
- let success =
- inferred_types.next().is_none() && !substituted_ty.references_non_lt_error();
- if success {
- ty = substituted_ty;
+ }
+ fn next_const_var(&mut self, _span: hir_ty::Span) -> hir_ty::next_solver::Const<'db> {
+ self.types.consts.error
+ }
+ fn next_region_var(&mut self, _span: hir_ty::Span) -> Region<'db> {
+ self.types.regions.error
}
}