Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir-def/src/expr_store.rs | 291 | ||||
| -rw-r--r-- | crates/hir-def/src/hir/type_ref.rs | 70 | ||||
| -rw-r--r-- | crates/hir-ty/src/consteval.rs | 10 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 25 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/diagnostics.rs | 36 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/path.rs | 15 | ||||
| -rw-r--r-- | crates/hir-ty/src/lib.rs | 3 | ||||
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 58 | ||||
| -rw-r--r-- | crates/hir-ty/src/lower/path.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/next_solver/interner.rs | 62 | ||||
| -rw-r--r-- | crates/hir/src/source_analyzer.rs | 52 |
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 } } |