mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-29 19:17:12 +00:00 
			
		
		
		
	Adapt for new cycle handling changing in Salsa
This commit is contained in:
		
							parent
							
								
									db72e2ff41
								
							
						
					
					
						commit
						57c019a3c5
					
				
					 15 changed files with 133 additions and 339 deletions
				
			
		|  | @ -619,7 +619,7 @@ impl_from!( | ||||||
| 
 | 
 | ||||||
| /// A constant, which might appears as a const item, an anonymous const block in expressions
 | /// A constant, which might appears as a const item, an anonymous const block in expressions
 | ||||||
| /// or patterns, or as a constant in types with const generics.
 | /// or patterns, or as a constant in types with const generics.
 | ||||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] | ||||||
| pub enum GeneralConstId { | pub enum GeneralConstId { | ||||||
|     ConstId(ConstId), |     ConstId(ConstId), | ||||||
|     StaticId(StaticId), |     StaticId(StaticId), | ||||||
|  |  | ||||||
|  | @ -10,7 +10,6 @@ use hir_def::{ | ||||||
|     type_ref::LiteralConstRef, |     type_ref::LiteralConstRef, | ||||||
| }; | }; | ||||||
| use hir_expand::Lookup; | use hir_expand::Lookup; | ||||||
| use salsa::Cycle; |  | ||||||
| use stdx::never; | use stdx::never; | ||||||
| use triomphe::Arc; | use triomphe::Arc; | ||||||
| 
 | 
 | ||||||
|  | @ -220,9 +219,8 @@ pub fn try_const_isize(db: &dyn HirDatabase, c: &Const) -> Option<i128> { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn const_eval_recover( | pub(crate) fn const_eval_cycle_result( | ||||||
|     _: &dyn HirDatabase, |     _: &dyn HirDatabase, | ||||||
|     _: &Cycle, |  | ||||||
|     _: GeneralConstId, |     _: GeneralConstId, | ||||||
|     _: Substitution, |     _: Substitution, | ||||||
|     _: Option<Arc<TraitEnvironment>>, |     _: Option<Arc<TraitEnvironment>>, | ||||||
|  | @ -230,17 +228,15 @@ pub(crate) fn const_eval_recover( | ||||||
|     Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) |     Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn const_eval_static_recover( | pub(crate) fn const_eval_static_cycle_result( | ||||||
|     _: &dyn HirDatabase, |     _: &dyn HirDatabase, | ||||||
|     _: &Cycle, |  | ||||||
|     _: StaticId, |     _: StaticId, | ||||||
| ) -> Result<Const, ConstEvalError> { | ) -> Result<Const, ConstEvalError> { | ||||||
|     Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) |     Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn const_eval_discriminant_recover( | pub(crate) fn const_eval_discriminant_cycle_result( | ||||||
|     _: &dyn HirDatabase, |     _: &dyn HirDatabase, | ||||||
|     _: &Cycle, |  | ||||||
|     _: EnumVariantId, |     _: EnumVariantId, | ||||||
| ) -> Result<i128, ConstEvalError> { | ) -> Result<i128, ConstEvalError> { | ||||||
|     Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) |     Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) | ||||||
|  |  | ||||||
|  | @ -36,14 +36,14 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     // region:mir
 |     // region:mir
 | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::mir::mir_body_query)] |     #[salsa::invoke(crate::mir::mir_body_query)] | ||||||
|     #[salsa::cycle(crate::mir::mir_body_recover)] |     #[salsa::cycle(cycle_result = crate::mir::mir_body_cycle_result)] | ||||||
|     fn mir_body(&self, def: DefWithBodyId) -> Result<Arc<MirBody>, MirLowerError>; |     fn mir_body(&self, def: DefWithBodyId) -> Result<Arc<MirBody>, MirLowerError>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::mir::mir_body_for_closure_query)] |     #[salsa::invoke(crate::mir::mir_body_for_closure_query)] | ||||||
|     fn mir_body_for_closure(&self, def: InternedClosureId) -> Result<Arc<MirBody>, MirLowerError>; |     fn mir_body_for_closure(&self, def: InternedClosureId) -> Result<Arc<MirBody>, MirLowerError>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::mir::monomorphized_mir_body_query)] |     #[salsa::invoke(crate::mir::monomorphized_mir_body_query)] | ||||||
|     #[salsa::cycle(crate::mir::monomorphized_mir_body_recover)] |     #[salsa::cycle(cycle_result = crate::mir::monomorphized_mir_body_cycle_result)] | ||||||
|     fn monomorphized_mir_body( |     fn monomorphized_mir_body( | ||||||
|         &self, |         &self, | ||||||
|         def: DefWithBodyId, |         def: DefWithBodyId, | ||||||
|  | @ -64,7 +64,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     fn borrowck(&self, def: DefWithBodyId) -> Result<Arc<[BorrowckResult]>, MirLowerError>; |     fn borrowck(&self, def: DefWithBodyId) -> Result<Arc<[BorrowckResult]>, MirLowerError>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::consteval::const_eval_query)] |     #[salsa::invoke(crate::consteval::const_eval_query)] | ||||||
|     #[salsa::cycle(crate::consteval::const_eval_recover)] |     #[salsa::cycle(cycle_result = crate::consteval::const_eval_cycle_result)] | ||||||
|     fn const_eval( |     fn const_eval( | ||||||
|         &self, |         &self, | ||||||
|         def: GeneralConstId, |         def: GeneralConstId, | ||||||
|  | @ -73,11 +73,11 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     ) -> Result<Const, ConstEvalError>; |     ) -> Result<Const, ConstEvalError>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::consteval::const_eval_static_query)] |     #[salsa::invoke(crate::consteval::const_eval_static_query)] | ||||||
|     #[salsa::cycle(crate::consteval::const_eval_static_recover)] |     #[salsa::cycle(cycle_result = crate::consteval::const_eval_static_cycle_result)] | ||||||
|     fn const_eval_static(&self, def: StaticId) -> Result<Const, ConstEvalError>; |     fn const_eval_static(&self, def: StaticId) -> Result<Const, ConstEvalError>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)] |     #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)] | ||||||
|     #[salsa::cycle(crate::consteval::const_eval_discriminant_recover)] |     #[salsa::cycle(cycle_result = crate::consteval::const_eval_discriminant_cycle_result)] | ||||||
|     fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>; |     fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] |     #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] | ||||||
|  | @ -91,7 +91,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     // endregion:mir
 |     // endregion:mir
 | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::layout::layout_of_adt_query)] |     #[salsa::invoke(crate::layout::layout_of_adt_query)] | ||||||
|     #[salsa::cycle(crate::layout::layout_of_adt_recover)] |     #[salsa::cycle(cycle_result = crate::layout::layout_of_adt_cycle_result)] | ||||||
|     fn layout_of_adt( |     fn layout_of_adt( | ||||||
|         &self, |         &self, | ||||||
|         def: AdtId, |         def: AdtId, | ||||||
|  | @ -100,7 +100,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     ) -> Result<Arc<Layout>, LayoutError>; |     ) -> Result<Arc<Layout>, LayoutError>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::layout::layout_of_ty_query)] |     #[salsa::invoke(crate::layout::layout_of_ty_query)] | ||||||
|     #[salsa::cycle(crate::layout::layout_of_ty_recover)] |     #[salsa::cycle(cycle_result = crate::layout::layout_of_ty_cycle_result)] | ||||||
|     fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>; |     fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::layout::target_data_layout_query)] |     #[salsa::invoke(crate::layout::target_data_layout_query)] | ||||||
|  | @ -113,8 +113,8 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     #[salsa::transparent] |     #[salsa::transparent] | ||||||
|     fn ty(&self, def: TyDefId) -> Binders<Ty>; |     fn ty(&self, def: TyDefId) -> Binders<Ty>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::cycle(crate::lower::type_for_type_alias_with_diagnostics_query_recover)] |  | ||||||
|     #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)] |     #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)] | ||||||
|  |     #[salsa::cycle(cycle_result = crate::lower::type_for_type_alias_with_diagnostics_cycle_result)] | ||||||
|     fn type_for_type_alias_with_diagnostics(&self, def: TypeAliasId) -> (Binders<Ty>, Diagnostics); |     fn type_for_type_alias_with_diagnostics(&self, def: TypeAliasId) -> (Binders<Ty>, Diagnostics); | ||||||
| 
 | 
 | ||||||
|     /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
 |     /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
 | ||||||
|  | @ -123,7 +123,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     fn value_ty(&self, def: ValueTyDefId) -> Option<Binders<Ty>>; |     fn value_ty(&self, def: ValueTyDefId) -> Option<Binders<Ty>>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)] |     #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)] | ||||||
|     #[salsa::cycle(crate::lower::impl_self_ty_with_diagnostics_recover)] |     #[salsa::cycle(cycle_result = crate::lower::impl_self_ty_with_diagnostics_cycle_result)] | ||||||
|     fn impl_self_ty_with_diagnostics(&self, def: ImplId) -> (Binders<Ty>, Diagnostics); |     fn impl_self_ty_with_diagnostics(&self, def: ImplId) -> (Binders<Ty>, Diagnostics); | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::lower::impl_self_ty_query)] |     #[salsa::invoke(crate::lower::impl_self_ty_query)] | ||||||
|  | @ -165,7 +165,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     fn type_alias_impl_traits(&self, def: TypeAliasId) -> Option<Arc<Binders<ImplTraits>>>; |     fn type_alias_impl_traits(&self, def: TypeAliasId) -> Option<Arc<Binders<ImplTraits>>>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] |     #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] | ||||||
|     #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] |     #[salsa::cycle(cycle_result = crate::lower::generic_predicates_for_param_cycle_result)] | ||||||
|     fn generic_predicates_for_param( |     fn generic_predicates_for_param( | ||||||
|         &self, |         &self, | ||||||
|         def: GenericDefId, |         def: GenericDefId, | ||||||
|  | @ -194,7 +194,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     fn trait_environment(&self, def: GenericDefId) -> Arc<TraitEnvironment>; |     fn trait_environment(&self, def: GenericDefId) -> Arc<TraitEnvironment>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] |     #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] | ||||||
|     #[salsa::cycle(crate::lower::generic_defaults_with_diagnostics_recover)] |     #[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)] | ||||||
|     fn generic_defaults_with_diagnostics( |     fn generic_defaults_with_diagnostics( | ||||||
|         &self, |         &self, | ||||||
|         def: GenericDefId, |         def: GenericDefId, | ||||||
|  | @ -282,7 +282,10 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     fn adt_variance(&self, adt_id: AdtId) -> chalk_db::Variances; |     fn adt_variance(&self, adt_id: AdtId) -> chalk_db::Variances; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::variance::variances_of)] |     #[salsa::invoke(crate::variance::variances_of)] | ||||||
|     #[salsa::cycle(crate::variance::variances_of_cycle)] |     #[salsa::cycle(
 | ||||||
|  |         cycle_fn = crate::variance::variances_of_cycle_fn, | ||||||
|  |         cycle_initial = crate::variance::variances_of_cycle_initial, | ||||||
|  |     )] | ||||||
|     fn variances_of(&self, def: GenericDefId) -> Option<Arc<[crate::variance::Variance]>>; |     fn variances_of(&self, def: GenericDefId) -> Option<Arc<[crate::variance::Variance]>>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(chalk_db::associated_ty_value_query)] |     #[salsa::invoke(chalk_db::associated_ty_value_query)] | ||||||
|  | @ -317,7 +320,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | ||||||
|     ) -> chalk_ir::ProgramClauses<Interner>; |     ) -> chalk_ir::ProgramClauses<Interner>; | ||||||
| 
 | 
 | ||||||
|     #[salsa::invoke(crate::drop::has_drop_glue)] |     #[salsa::invoke(crate::drop::has_drop_glue)] | ||||||
|     #[salsa::cycle(crate::drop::has_drop_glue_recover)] |     #[salsa::cycle(cycle_result = crate::drop::has_drop_glue_cycle_result)] | ||||||
|     fn has_drop_glue(&self, ty: Ty, env: Arc<TraitEnvironment>) -> DropGlue; |     fn has_drop_glue(&self, ty: Ty, env: Arc<TraitEnvironment>) -> DropGlue; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -193,9 +193,8 @@ fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment>) -> bool { | ||||||
|     db.trait_solve(env.krate, env.block, goal).is_some() |     db.trait_solve(env.krate, env.block, goal).is_some() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn has_drop_glue_recover( | pub(crate) fn has_drop_glue_cycle_result( | ||||||
|     _db: &dyn HirDatabase, |     _db: &dyn HirDatabase, | ||||||
|     _cycle: &salsa::Cycle, |  | ||||||
|     _ty: Ty, |     _ty: Ty, | ||||||
|     _env: Arc<TraitEnvironment>, |     _env: Arc<TraitEnvironment>, | ||||||
| ) -> DropGlue { | ) -> DropGlue { | ||||||
|  |  | ||||||
|  | @ -13,7 +13,6 @@ use hir_def::{ | ||||||
| use la_arena::{Idx, RawIdx}; | use la_arena::{Idx, RawIdx}; | ||||||
| use rustc_abi::AddressSpace; | use rustc_abi::AddressSpace; | ||||||
| use rustc_index::IndexVec; | use rustc_index::IndexVec; | ||||||
| use salsa::Cycle; |  | ||||||
| 
 | 
 | ||||||
| use triomphe::Arc; | use triomphe::Arc; | ||||||
| 
 | 
 | ||||||
|  | @ -25,7 +24,7 @@ use crate::{ | ||||||
|     utils::ClosureSubst, |     utils::ClosureSubst, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| pub(crate) use self::adt::layout_of_adt_recover; | pub(crate) use self::adt::layout_of_adt_cycle_result; | ||||||
| pub use self::{adt::layout_of_adt_query, target::target_data_layout_query}; | pub use self::{adt::layout_of_adt_query, target::target_data_layout_query}; | ||||||
| 
 | 
 | ||||||
| mod adt; | mod adt; | ||||||
|  | @ -365,9 +364,8 @@ pub fn layout_of_ty_query( | ||||||
|     Ok(Arc::new(result)) |     Ok(Arc::new(result)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn layout_of_ty_recover( | pub(crate) fn layout_of_ty_cycle_result( | ||||||
|     _: &dyn HirDatabase, |     _: &dyn HirDatabase, | ||||||
|     _: &Cycle, |  | ||||||
|     _: Ty, |     _: Ty, | ||||||
|     _: Arc<TraitEnvironment>, |     _: Arc<TraitEnvironment>, | ||||||
| ) -> Result<Arc<Layout>, LayoutError> { | ) -> Result<Arc<Layout>, LayoutError> { | ||||||
|  |  | ||||||
|  | @ -9,7 +9,6 @@ use hir_def::{ | ||||||
| }; | }; | ||||||
| use intern::sym; | use intern::sym; | ||||||
| use rustc_index::IndexVec; | use rustc_index::IndexVec; | ||||||
| use salsa::Cycle; |  | ||||||
| use smallvec::SmallVec; | use smallvec::SmallVec; | ||||||
| use triomphe::Arc; | use triomphe::Arc; | ||||||
| 
 | 
 | ||||||
|  | @ -131,9 +130,8 @@ fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound<u128>, | ||||||
|     (get(sym::rustc_layout_scalar_valid_range_start), get(sym::rustc_layout_scalar_valid_range_end)) |     (get(sym::rustc_layout_scalar_valid_range_start), get(sym::rustc_layout_scalar_valid_range_end)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn layout_of_adt_recover( | pub(crate) fn layout_of_adt_cycle_result( | ||||||
|     _: &dyn HirDatabase, |     _: &dyn HirDatabase, | ||||||
|     _: &Cycle, |  | ||||||
|     _: AdtId, |     _: AdtId, | ||||||
|     _: Substitution, |     _: Substitution, | ||||||
|     _: Arc<TraitEnvironment>, |     _: Arc<TraitEnvironment>, | ||||||
|  |  | ||||||
|  | @ -45,7 +45,6 @@ use hir_expand::name::Name; | ||||||
| use la_arena::{Arena, ArenaMap}; | use la_arena::{Arena, ArenaMap}; | ||||||
| use rustc_hash::FxHashSet; | use rustc_hash::FxHashSet; | ||||||
| use rustc_pattern_analysis::Captures; | use rustc_pattern_analysis::Captures; | ||||||
| use salsa::Cycle; |  | ||||||
| use stdx::{impl_from, never}; | use stdx::{impl_from, never}; | ||||||
| use triomphe::{Arc, ThinArc}; | use triomphe::{Arc, ThinArc}; | ||||||
| 
 | 
 | ||||||
|  | @ -961,9 +960,8 @@ pub(crate) fn generic_predicates_for_param_query( | ||||||
|     GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) |     GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn generic_predicates_for_param_recover( | pub(crate) fn generic_predicates_for_param_cycle_result( | ||||||
|     _db: &dyn HirDatabase, |     _db: &dyn HirDatabase, | ||||||
|     _cycle: &salsa::Cycle, |  | ||||||
|     _def: GenericDefId, |     _def: GenericDefId, | ||||||
|     _param_id: TypeOrConstParamId, |     _param_id: TypeOrConstParamId, | ||||||
|     _assoc_name: Option<Name>, |     _assoc_name: Option<Name>, | ||||||
|  | @ -1264,9 +1262,8 @@ pub(crate) fn generic_defaults_with_diagnostics_query( | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn generic_defaults_with_diagnostics_recover( | pub(crate) fn generic_defaults_with_diagnostics_cycle_result( | ||||||
|     _db: &dyn HirDatabase, |     _db: &dyn HirDatabase, | ||||||
|     _cycle: &Cycle, |  | ||||||
|     _def: GenericDefId, |     _def: GenericDefId, | ||||||
| ) -> (GenericDefaults, Diagnostics) { | ) -> (GenericDefaults, Diagnostics) { | ||||||
|     (GenericDefaults(None), None) |     (GenericDefaults(None), None) | ||||||
|  | @ -1402,16 +1399,12 @@ fn type_for_enum_variant_constructor( | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[salsa::tracked(recovery_fn = type_for_adt_recovery)] | #[salsa::tracked(cycle_result = type_for_adt_cycle_result)] | ||||||
| fn type_for_adt_tracked(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { | fn type_for_adt_tracked(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { | ||||||
|     type_for_adt(db, adt) |     type_for_adt(db, adt) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn type_for_adt_recovery( | fn type_for_adt_cycle_result(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { | ||||||
|     db: &dyn HirDatabase, |  | ||||||
|     _cycle: &salsa::Cycle, |  | ||||||
|     adt: AdtId, |  | ||||||
| ) -> Binders<Ty> { |  | ||||||
|     let generics = generics(db, adt.into()); |     let generics = generics(db, adt.into()); | ||||||
|     make_binders(db, &generics, TyKind::Error.intern(Interner)) |     make_binders(db, &generics, TyKind::Error.intern(Interner)) | ||||||
| } | } | ||||||
|  | @ -1449,9 +1442,8 @@ pub(crate) fn type_for_type_alias_with_diagnostics_query( | ||||||
|     (make_binders(db, &generics, inner), diags) |     (make_binders(db, &generics, inner), diags) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn type_for_type_alias_with_diagnostics_query_recover( | pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result( | ||||||
|     db: &dyn HirDatabase, |     db: &dyn HirDatabase, | ||||||
|     _cycle: &salsa::Cycle, |  | ||||||
|     adt: TypeAliasId, |     adt: TypeAliasId, | ||||||
| ) -> (Binders<Ty>, Diagnostics) { | ) -> (Binders<Ty>, Diagnostics) { | ||||||
|     let generics = generics(db, adt.into()); |     let generics = generics(db, adt.into()); | ||||||
|  | @ -1555,12 +1547,11 @@ pub(crate) fn const_param_ty_with_diagnostics_query( | ||||||
|     (ty, create_diagnostics(ctx.diagnostics)) |     (ty, create_diagnostics(ctx.diagnostics)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn impl_self_ty_with_diagnostics_recover( | pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( | ||||||
|     db: &dyn HirDatabase, |     db: &dyn HirDatabase, | ||||||
|     _cycle: &salsa::Cycle, |  | ||||||
|     impl_id: ImplId, |     impl_id: ImplId, | ||||||
| ) -> (Binders<Ty>, Diagnostics) { | ) -> (Binders<Ty>, Diagnostics) { | ||||||
|     let generics = generics(db, (impl_id).into()); |     let generics = generics(db, impl_id.into()); | ||||||
|     (make_binders(db, &generics, TyKind::Error.intern(Interner)), None) |     (make_binders(db, &generics, TyKind::Error.intern(Interner)), None) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -41,8 +41,8 @@ use rustc_hash::FxHashMap; | ||||||
| use smallvec::{SmallVec, smallvec}; | use smallvec::{SmallVec, smallvec}; | ||||||
| use stdx::{impl_from, never}; | use stdx::{impl_from, never}; | ||||||
| 
 | 
 | ||||||
| pub(crate) use lower::mir_body_recover; | pub(crate) use lower::mir_body_cycle_result; | ||||||
| pub(crate) use monomorphization::monomorphized_mir_body_recover; | pub(crate) use monomorphization::monomorphized_mir_body_cycle_result; | ||||||
| 
 | 
 | ||||||
| use super::consteval::{intern_const_scalar, try_const_usize}; | use super::consteval::{intern_const_scalar, try_const_usize}; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| use std::{fmt::Write, iter, mem}; | use std::{fmt::Write, iter, mem}; | ||||||
| 
 | 
 | ||||||
| use base_db::{Crate, salsa::Cycle}; | use base_db::Crate; | ||||||
| use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; | use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; | ||||||
| use hir_def::{ | use hir_def::{ | ||||||
|     AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId, |     AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId, | ||||||
|  | @ -2145,9 +2145,8 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi | ||||||
|     Ok(Arc::new(result)) |     Ok(Arc::new(result)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn mir_body_recover( | pub(crate) fn mir_body_cycle_result( | ||||||
|     _db: &dyn HirDatabase, |     _db: &dyn HirDatabase, | ||||||
|     _cycle: &Cycle, |  | ||||||
|     _def: DefWithBodyId, |     _def: DefWithBodyId, | ||||||
| ) -> Result<Arc<MirBody>> { | ) -> Result<Arc<MirBody>> { | ||||||
|     Err(MirLowerError::Loop) |     Err(MirLowerError::Loop) | ||||||
|  |  | ||||||
|  | @ -313,9 +313,8 @@ pub fn monomorphized_mir_body_query( | ||||||
|     Ok(Arc::new(body)) |     Ok(Arc::new(body)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn monomorphized_mir_body_recover( | pub(crate) fn monomorphized_mir_body_cycle_result( | ||||||
|     _: &dyn HirDatabase, |     _db: &dyn HirDatabase, | ||||||
|     _: &salsa::Cycle, |  | ||||||
|     _: DefWithBodyId, |     _: DefWithBodyId, | ||||||
|     _: Substitution, |     _: Substitution, | ||||||
|     _: Arc<crate::TraitEnvironment>, |     _: Arc<crate::TraitEnvironment>, | ||||||
|  |  | ||||||
|  | @ -19,10 +19,10 @@ use crate::{ | ||||||
|     AliasTy, Const, ConstScalar, DynTyExt, GenericArg, GenericArgData, Interner, Lifetime, |     AliasTy, Const, ConstScalar, DynTyExt, GenericArg, GenericArgData, Interner, Lifetime, | ||||||
|     LifetimeData, Ty, TyKind, |     LifetimeData, Ty, TyKind, | ||||||
| }; | }; | ||||||
| use base_db::salsa::Cycle; |  | ||||||
| use chalk_ir::Mutability; | use chalk_ir::Mutability; | ||||||
| use hir_def::signatures::StructFlags; | use hir_def::signatures::StructFlags; | ||||||
| use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId}; | use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId}; | ||||||
|  | use salsa::CycleRecoveryAction; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use std::ops::Not; | use std::ops::Not; | ||||||
| use stdx::never; | use stdx::never; | ||||||
|  | @ -55,9 +55,17 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option<Ar | ||||||
|     variances.is_empty().not().then(|| Arc::from_iter(variances)) |     variances.is_empty().not().then(|| Arc::from_iter(variances)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) fn variances_of_cycle( | pub(crate) fn variances_of_cycle_fn( | ||||||
|  |     _db: &dyn HirDatabase, | ||||||
|  |     result: &Option<Arc<[Variance]>>, | ||||||
|  |     _count: u32, | ||||||
|  |     _def: GenericDefId, | ||||||
|  | ) -> CycleRecoveryAction<Option<Arc<[Variance]>>> { | ||||||
|  |     CycleRecoveryAction::Fallback(result.clone()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) fn variances_of_cycle_initial( | ||||||
|     db: &dyn HirDatabase, |     db: &dyn HirDatabase, | ||||||
|     _cycle: &Cycle, |  | ||||||
|     def: GenericDefId, |     def: GenericDefId, | ||||||
| ) -> Option<Arc<[Variance]>> { | ) -> Option<Arc<[Variance]>> { | ||||||
|     let generics = generics(db, def); |     let generics = generics(db, def); | ||||||
|  |  | ||||||
|  | @ -10,10 +10,13 @@ use queries::{ | ||||||
|     Queries, SetterKind, TrackedQuery, Transparent, |     Queries, SetterKind, TrackedQuery, Transparent, | ||||||
| }; | }; | ||||||
| use quote::{ToTokens, format_ident, quote}; | use quote::{ToTokens, format_ident, quote}; | ||||||
|  | use syn::parse::{Parse, ParseStream}; | ||||||
|  | use syn::punctuated::Punctuated; | ||||||
| use syn::spanned::Spanned; | use syn::spanned::Spanned; | ||||||
| use syn::visit_mut::VisitMut; | use syn::visit_mut::VisitMut; | ||||||
| use syn::{ | use syn::{ | ||||||
|     Attribute, FnArg, ItemTrait, Path, TraitItem, TraitItemFn, parse_quote, parse_quote_spanned, |     Attribute, FnArg, ItemTrait, Path, Token, TraitItem, TraitItemFn, parse_quote, | ||||||
|  |     parse_quote_spanned, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| mod queries; | mod queries; | ||||||
|  | @ -106,6 +109,66 @@ enum QueryKind { | ||||||
|     Interned, |     Interned, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Default, Debug, Clone)] | ||||||
|  | struct Cycle { | ||||||
|  |     cycle_fn: Option<(syn::Ident, Path)>, | ||||||
|  |     cycle_initial: Option<(syn::Ident, Path)>, | ||||||
|  |     cycle_result: Option<(syn::Ident, Path)>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Parse for Cycle { | ||||||
|  |     fn parse(input: ParseStream<'_>) -> syn::Result<Self> { | ||||||
|  |         let options = Punctuated::<Option, Token![,]>::parse_terminated(input)?; | ||||||
|  |         let mut cycle_fn = None; | ||||||
|  |         let mut cycle_initial = None; | ||||||
|  |         let mut cycle_result = None; | ||||||
|  |         for option in options { | ||||||
|  |             let name = option.name.to_string(); | ||||||
|  |             match &*name { | ||||||
|  |                 "cycle_fn" => { | ||||||
|  |                     if cycle_fn.is_some() { | ||||||
|  |                         return Err(syn::Error::new_spanned(&option.name, "duplicate option")); | ||||||
|  |                     } | ||||||
|  |                     cycle_fn = Some((option.name, option.value)); | ||||||
|  |                 } | ||||||
|  |                 "cycle_initial" => { | ||||||
|  |                     if cycle_initial.is_some() { | ||||||
|  |                         return Err(syn::Error::new_spanned(&option.name, "duplicate option")); | ||||||
|  |                     } | ||||||
|  |                     cycle_initial = Some((option.name, option.value)); | ||||||
|  |                 } | ||||||
|  |                 "cycle_result" => { | ||||||
|  |                     if cycle_result.is_some() { | ||||||
|  |                         return Err(syn::Error::new_spanned(&option.name, "duplicate option")); | ||||||
|  |                     } | ||||||
|  |                     cycle_result = Some((option.name, option.value)); | ||||||
|  |                 } | ||||||
|  |                 _ => { | ||||||
|  |                     return Err(syn::Error::new_spanned( | ||||||
|  |                         &option.name, | ||||||
|  |                         "unknown cycle option. Accepted values: `cycle_result`, `cycle_fn`, `cycle_initial`", | ||||||
|  |                     )); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return Ok(Self { cycle_fn, cycle_initial, cycle_result }); | ||||||
|  | 
 | ||||||
|  |         struct Option { | ||||||
|  |             name: syn::Ident, | ||||||
|  |             value: Path, | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         impl Parse for Option { | ||||||
|  |             fn parse(input: ParseStream) -> syn::Result<Self> { | ||||||
|  |                 let name = input.parse()?; | ||||||
|  |                 input.parse::<Token![=]>()?; | ||||||
|  |                 let value = input.parse()?; | ||||||
|  |                 Ok(Self { name, value }) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub(crate) fn query_group_impl( | pub(crate) fn query_group_impl( | ||||||
|     _args: proc_macro::TokenStream, |     _args: proc_macro::TokenStream, | ||||||
|     input: proc_macro::TokenStream, |     input: proc_macro::TokenStream, | ||||||
|  | @ -155,8 +218,8 @@ pub(crate) fn query_group_impl( | ||||||
|             for SalsaAttr { name, tts, span } in salsa_attrs { |             for SalsaAttr { name, tts, span } in salsa_attrs { | ||||||
|                 match name.as_str() { |                 match name.as_str() { | ||||||
|                     "cycle" => { |                     "cycle" => { | ||||||
|                         let path = syn::parse::<Parenthesized<Path>>(tts)?; |                         let c = syn::parse::<Parenthesized<Cycle>>(tts)?; | ||||||
|                         cycle = Some(path.0.clone()) |                         cycle = Some(c.0); | ||||||
|                     } |                     } | ||||||
|                     "input" => { |                     "input" => { | ||||||
|                         if !pat_and_tys.is_empty() { |                         if !pat_and_tys.is_empty() { | ||||||
|  | @ -415,7 +478,7 @@ impl<T> syn::parse::Parse for Parenthesized<T> | ||||||
| where | where | ||||||
|     T: syn::parse::Parse, |     T: syn::parse::Parse, | ||||||
| { | { | ||||||
|     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { |     fn parse(input: ParseStream<'_>) -> syn::Result<Self> { | ||||||
|         let content; |         let content; | ||||||
|         syn::parenthesized!(content in input); |         syn::parenthesized!(content in input); | ||||||
|         content.parse::<T>().map(Parenthesized) |         content.parse::<T>().map(Parenthesized) | ||||||
|  |  | ||||||
|  | @ -3,13 +3,15 @@ | ||||||
| use quote::{ToTokens, format_ident, quote, quote_spanned}; | use quote::{ToTokens, format_ident, quote, quote_spanned}; | ||||||
| use syn::{FnArg, Ident, PatType, Path, Receiver, ReturnType, Type, parse_quote, spanned::Spanned}; | use syn::{FnArg, Ident, PatType, Path, Receiver, ReturnType, Type, parse_quote, spanned::Spanned}; | ||||||
| 
 | 
 | ||||||
|  | use crate::Cycle; | ||||||
|  | 
 | ||||||
| pub(crate) struct TrackedQuery { | pub(crate) struct TrackedQuery { | ||||||
|     pub(crate) trait_name: Ident, |     pub(crate) trait_name: Ident, | ||||||
|     pub(crate) signature: syn::Signature, |     pub(crate) signature: syn::Signature, | ||||||
|     pub(crate) pat_and_tys: Vec<PatType>, |     pub(crate) pat_and_tys: Vec<PatType>, | ||||||
|     pub(crate) invoke: Option<Path>, |     pub(crate) invoke: Option<Path>, | ||||||
|     pub(crate) default: Option<syn::Block>, |     pub(crate) default: Option<syn::Block>, | ||||||
|     pub(crate) cycle: Option<Path>, |     pub(crate) cycle: Option<Cycle>, | ||||||
|     pub(crate) lru: Option<u32>, |     pub(crate) lru: Option<u32>, | ||||||
|     pub(crate) generated_struct: Option<GeneratedInputStruct>, |     pub(crate) generated_struct: Option<GeneratedInputStruct>, | ||||||
| } | } | ||||||
|  | @ -34,12 +36,20 @@ impl ToTokens for TrackedQuery { | ||||||
|         let fn_ident = &sig.ident; |         let fn_ident = &sig.ident; | ||||||
|         let shim: Ident = format_ident!("{}_shim", fn_ident); |         let shim: Ident = format_ident!("{}_shim", fn_ident); | ||||||
| 
 | 
 | ||||||
|         let annotation = match (self.cycle.clone(), self.lru) { |         let options = self | ||||||
|             (Some(cycle), Some(lru)) => quote!(#[salsa::tracked(lru = #lru, recovery_fn = #cycle)]), |             .cycle | ||||||
|             (Some(cycle), None) => quote!(#[salsa::tracked(recovery_fn = #cycle)]), |             .as_ref() | ||||||
|             (None, Some(lru)) => quote!(#[salsa::tracked(lru = #lru)]), |             .map(|Cycle { cycle_fn, cycle_initial, cycle_result }| { | ||||||
|             (None, None) => quote!(#[salsa::tracked]), |                 let cycle_fn = cycle_fn.as_ref().map(|(ident, path)| quote!(#ident=#path)); | ||||||
|         }; |                 let cycle_initial = | ||||||
|  |                     cycle_initial.as_ref().map(|(ident, path)| quote!(#ident=#path)); | ||||||
|  |                 let cycle_result = cycle_result.as_ref().map(|(ident, path)| quote!(#ident=#path)); | ||||||
|  |                 let options = cycle_fn.into_iter().chain(cycle_initial).chain(cycle_result); | ||||||
|  |                 quote!(#(#options),*) | ||||||
|  |             }) | ||||||
|  |             .into_iter() | ||||||
|  |             .chain(self.lru.map(|lru| quote!(lru = #lru))); | ||||||
|  |         let annotation = quote!(#[salsa::tracked( #(#options),* )]); | ||||||
| 
 | 
 | ||||||
|         let pat_and_tys = &self.pat_and_tys; |         let pat_and_tys = &self.pat_and_tys; | ||||||
|         let params = self |         let params = self | ||||||
|  |  | ||||||
|  | @ -1,265 +0,0 @@ | ||||||
| use std::panic::UnwindSafe; |  | ||||||
| 
 |  | ||||||
| use expect_test::expect; |  | ||||||
| use query_group_macro::query_group; |  | ||||||
| use salsa::Setter; |  | ||||||
| 
 |  | ||||||
| /// The queries A, B, and C in `Database` can be configured
 |  | ||||||
| /// to invoke one another in arbitrary ways using this
 |  | ||||||
| /// enum.
 |  | ||||||
| #[derive(Debug, Copy, Clone, PartialEq, Eq)] |  | ||||||
| enum CycleQuery { |  | ||||||
|     None, |  | ||||||
|     A, |  | ||||||
|     B, |  | ||||||
|     C, |  | ||||||
|     AthenC, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[salsa::input] |  | ||||||
| struct ABC { |  | ||||||
|     a: CycleQuery, |  | ||||||
|     b: CycleQuery, |  | ||||||
|     c: CycleQuery, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl CycleQuery { |  | ||||||
|     fn invoke(self, db: &dyn CycleDatabase, abc: ABC) -> Result<(), Error> { |  | ||||||
|         match self { |  | ||||||
|             CycleQuery::A => db.cycle_a(abc), |  | ||||||
|             CycleQuery::B => db.cycle_b(abc), |  | ||||||
|             CycleQuery::C => db.cycle_c(abc), |  | ||||||
|             CycleQuery::AthenC => { |  | ||||||
|                 let _ = db.cycle_a(abc); |  | ||||||
|                 db.cycle_c(abc) |  | ||||||
|             } |  | ||||||
|             CycleQuery::None => Ok(()), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[salsa::input] |  | ||||||
| struct MyInput {} |  | ||||||
| 
 |  | ||||||
| #[salsa::tracked] |  | ||||||
| fn memoized_a(db: &dyn CycleDatabase, input: MyInput) { |  | ||||||
|     memoized_b(db, input) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[salsa::tracked] |  | ||||||
| fn memoized_b(db: &dyn CycleDatabase, input: MyInput) { |  | ||||||
|     memoized_a(db, input) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[salsa::tracked] |  | ||||||
| fn volatile_a(db: &dyn CycleDatabase, input: MyInput) { |  | ||||||
|     db.report_untracked_read(); |  | ||||||
|     volatile_b(db, input) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[salsa::tracked] |  | ||||||
| fn volatile_b(db: &dyn CycleDatabase, input: MyInput) { |  | ||||||
|     db.report_untracked_read(); |  | ||||||
|     volatile_a(db, input) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[track_caller] |  | ||||||
| fn extract_cycle(f: impl FnOnce() + UnwindSafe) -> salsa::Cycle { |  | ||||||
|     let v = std::panic::catch_unwind(f); |  | ||||||
|     if let Err(d) = &v { |  | ||||||
|         if let Some(cycle) = d.downcast_ref::<salsa::Cycle>() { |  | ||||||
|             return cycle.clone(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     panic!("unexpected value: {:?}", v) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(PartialEq, Eq, Hash, Clone, Debug)] |  | ||||||
| struct Error { |  | ||||||
|     cycle: Vec<String>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[query_group] |  | ||||||
| trait CycleDatabase: salsa::Database { |  | ||||||
|     #[salsa::cycle(recover_a)] |  | ||||||
|     fn cycle_a(&self, abc: ABC) -> Result<(), Error>; |  | ||||||
| 
 |  | ||||||
|     #[salsa::cycle(recover_b)] |  | ||||||
|     fn cycle_b(&self, abc: ABC) -> Result<(), Error>; |  | ||||||
| 
 |  | ||||||
|     fn cycle_c(&self, abc: ABC) -> Result<(), Error>; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn cycle_a(db: &dyn CycleDatabase, abc: ABC) -> Result<(), Error> { |  | ||||||
|     abc.a(db).invoke(db, abc) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn recover_a(_db: &dyn CycleDatabase, cycle: &salsa::Cycle, _abc: ABC) -> Result<(), Error> { |  | ||||||
|     Err(Error { cycle: cycle.participant_keys().map(|k| format!("{k:?}")).collect() }) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn cycle_b(db: &dyn CycleDatabase, abc: ABC) -> Result<(), Error> { |  | ||||||
|     abc.b(db).invoke(db, abc) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn recover_b(_db: &dyn CycleDatabase, cycle: &salsa::Cycle, _abc: ABC) -> Result<(), Error> { |  | ||||||
|     Err(Error { cycle: cycle.participant_keys().map(|k| format!("{k:?}")).collect() }) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn cycle_c(db: &dyn CycleDatabase, abc: ABC) -> Result<(), Error> { |  | ||||||
|     abc.c(db).invoke(db, abc) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[test] |  | ||||||
| fn cycle_memoized() { |  | ||||||
|     let db = salsa::DatabaseImpl::new(); |  | ||||||
| 
 |  | ||||||
|     let input = MyInput::new(&db); |  | ||||||
|     let cycle = extract_cycle(|| memoized_a(&db, input)); |  | ||||||
|     let expected = expect![[r#" |  | ||||||
|         [ |  | ||||||
|             DatabaseKeyIndex( |  | ||||||
|                 IngredientIndex( |  | ||||||
|                     1, |  | ||||||
|                 ), |  | ||||||
|                 Id(0), |  | ||||||
|             ), |  | ||||||
|             DatabaseKeyIndex( |  | ||||||
|                 IngredientIndex( |  | ||||||
|                     2, |  | ||||||
|                 ), |  | ||||||
|                 Id(0), |  | ||||||
|             ), |  | ||||||
|         ] |  | ||||||
|     "#]];
 |  | ||||||
|     expected.assert_debug_eq(&cycle.all_participants(&db)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[test] |  | ||||||
| fn inner_cycle() { |  | ||||||
|     //     A --> B <-- C
 |  | ||||||
|     //     ^     |
 |  | ||||||
|     //     +-----+
 |  | ||||||
|     let db = salsa::DatabaseImpl::new(); |  | ||||||
| 
 |  | ||||||
|     let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::B); |  | ||||||
|     let err = db.cycle_c(abc); |  | ||||||
|     assert!(err.is_err()); |  | ||||||
|     let expected = expect![[r#" |  | ||||||
|         [ |  | ||||||
|             "cycle_a_shim(Id(0))", |  | ||||||
|             "cycle_b_shim(Id(0))", |  | ||||||
|         ] |  | ||||||
|     "#]];
 |  | ||||||
|     expected.assert_debug_eq(&err.unwrap_err().cycle); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[test] |  | ||||||
| fn cycle_revalidate() { |  | ||||||
|     //     A --> B
 |  | ||||||
|     //     ^     |
 |  | ||||||
|     //     +-----+
 |  | ||||||
|     let mut db = salsa::DatabaseImpl::new(); |  | ||||||
|     let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None); |  | ||||||
|     assert!(db.cycle_a(abc).is_err()); |  | ||||||
|     abc.set_b(&mut db).to(CycleQuery::A); // same value as default
 |  | ||||||
|     assert!(db.cycle_a(abc).is_err()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[test] |  | ||||||
| fn cycle_recovery_unchanged_twice() { |  | ||||||
|     //     A --> B
 |  | ||||||
|     //     ^     |
 |  | ||||||
|     //     +-----+
 |  | ||||||
|     let mut db = salsa::DatabaseImpl::new(); |  | ||||||
|     let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None); |  | ||||||
|     assert!(db.cycle_a(abc).is_err()); |  | ||||||
| 
 |  | ||||||
|     abc.set_c(&mut db).to(CycleQuery::A); // force new revision
 |  | ||||||
|     assert!(db.cycle_a(abc).is_err()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[test] |  | ||||||
| fn cycle_appears() { |  | ||||||
|     let mut db = salsa::DatabaseImpl::new(); |  | ||||||
|     //     A --> B
 |  | ||||||
|     let abc = ABC::new(&db, CycleQuery::B, CycleQuery::None, CycleQuery::None); |  | ||||||
|     assert!(db.cycle_a(abc).is_ok()); |  | ||||||
| 
 |  | ||||||
|     //     A --> B
 |  | ||||||
|     //     ^     |
 |  | ||||||
|     //     +-----+
 |  | ||||||
|     abc.set_b(&mut db).to(CycleQuery::A); |  | ||||||
|     assert!(db.cycle_a(abc).is_err()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[test] |  | ||||||
| fn cycle_disappears() { |  | ||||||
|     let mut db = salsa::DatabaseImpl::new(); |  | ||||||
| 
 |  | ||||||
|     //     A --> B
 |  | ||||||
|     //     ^     |
 |  | ||||||
|     //     +-----+
 |  | ||||||
|     let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None); |  | ||||||
|     assert!(db.cycle_a(abc).is_err()); |  | ||||||
| 
 |  | ||||||
|     //     A --> B
 |  | ||||||
|     abc.set_b(&mut db).to(CycleQuery::None); |  | ||||||
|     assert!(db.cycle_a(abc).is_ok()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[test] |  | ||||||
| fn cycle_multiple() { |  | ||||||
|     // No matter whether we start from A or B, we get the same set of participants:
 |  | ||||||
|     let db = salsa::DatabaseImpl::new(); |  | ||||||
| 
 |  | ||||||
|     // Configuration:
 |  | ||||||
|     //
 |  | ||||||
|     //     A --> B <-- C
 |  | ||||||
|     //     ^     |     ^
 |  | ||||||
|     //     +-----+     |
 |  | ||||||
|     //           |     |
 |  | ||||||
|     //           +-----+
 |  | ||||||
|     //
 |  | ||||||
|     // Here, conceptually, B encounters a cycle with A and then
 |  | ||||||
|     // recovers.
 |  | ||||||
|     let abc = ABC::new(&db, CycleQuery::B, CycleQuery::AthenC, CycleQuery::A); |  | ||||||
| 
 |  | ||||||
|     let c = db.cycle_c(abc); |  | ||||||
|     let b = db.cycle_b(abc); |  | ||||||
|     let a = db.cycle_a(abc); |  | ||||||
|     let expected = expect![[r#" |  | ||||||
|         ( |  | ||||||
|             [ |  | ||||||
|                 "cycle_a_shim(Id(0))", |  | ||||||
|                 "cycle_b_shim(Id(0))", |  | ||||||
|             ], |  | ||||||
|             [ |  | ||||||
|                 "cycle_a_shim(Id(0))", |  | ||||||
|                 "cycle_b_shim(Id(0))", |  | ||||||
|             ], |  | ||||||
|             [ |  | ||||||
|                 "cycle_a_shim(Id(0))", |  | ||||||
|                 "cycle_b_shim(Id(0))", |  | ||||||
|             ], |  | ||||||
|         ) |  | ||||||
|     "#]];
 |  | ||||||
|     expected.assert_debug_eq(&(c.unwrap_err().cycle, b.unwrap_err().cycle, a.unwrap_err().cycle)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[test] |  | ||||||
| fn cycle_mixed_1() { |  | ||||||
|     let db = salsa::DatabaseImpl::new(); |  | ||||||
|     //     A --> B <-- C
 |  | ||||||
|     //           |     ^
 |  | ||||||
|     //           +-----+
 |  | ||||||
|     let abc = ABC::new(&db, CycleQuery::B, CycleQuery::C, CycleQuery::B); |  | ||||||
| 
 |  | ||||||
|     let expected = expect![[r#" |  | ||||||
|         [ |  | ||||||
|             "cycle_b_shim(Id(0))", |  | ||||||
|             "cycle_c_shim(Id(0))", |  | ||||||
|         ] |  | ||||||
|     "#]];
 |  | ||||||
|     expected.assert_debug_eq(&db.cycle_c(abc).unwrap_err().cycle); |  | ||||||
| } |  | ||||||
|  | @ -4,7 +4,7 @@ use std::{ | ||||||
|     panic, thread, |     panic, thread, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use ide_db::base_db::salsa::{self, Cancelled, Cycle}; | use ide_db::base_db::salsa::{self, Cancelled}; | ||||||
| use lsp_server::{ExtractError, Response, ResponseError}; | use lsp_server::{ExtractError, Response, ResponseError}; | ||||||
| use serde::{Serialize, de::DeserializeOwned}; | use serde::{Serialize, de::DeserializeOwned}; | ||||||
| use stdx::thread::ThreadIntent; | use stdx::thread::ThreadIntent; | ||||||
|  | @ -309,14 +309,12 @@ impl RequestDispatcher<'_> { | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| enum HandlerCancelledError { | enum HandlerCancelledError { | ||||||
|     PropagatedPanic, |  | ||||||
|     Inner(salsa::Cancelled), |     Inner(salsa::Cancelled), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl std::error::Error for HandlerCancelledError { | impl std::error::Error for HandlerCancelledError { | ||||||
|     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { | ||||||
|         match self { |         match self { | ||||||
|             HandlerCancelledError::PropagatedPanic => None, |  | ||||||
|             HandlerCancelledError::Inner(cancelled) => Some(cancelled), |             HandlerCancelledError::Inner(cancelled) => Some(cancelled), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -349,9 +347,6 @@ where | ||||||
|             if let Some(panic_message) = panic_message { |             if let Some(panic_message) = panic_message { | ||||||
|                 message.push_str(": "); |                 message.push_str(": "); | ||||||
|                 message.push_str(panic_message) |                 message.push_str(panic_message) | ||||||
|             } else if let Some(cycle) = panic.downcast_ref::<Cycle>() { |  | ||||||
|                 tracing::error!("Cycle propagated out of salsa! This is a bug: {cycle:?}"); |  | ||||||
|                 return Err(HandlerCancelledError::PropagatedPanic); |  | ||||||
|             } else if let Ok(cancelled) = panic.downcast::<Cancelled>() { |             } else if let Ok(cancelled) = panic.downcast::<Cancelled>() { | ||||||
|                 tracing::error!("Cancellation propagated out of salsa! This is a bug"); |                 tracing::error!("Cancellation propagated out of salsa! This is a bug"); | ||||||
|                 return Err(HandlerCancelledError::Inner(*cancelled)); |                 return Err(HandlerCancelledError::Inner(*cancelled)); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Chayim Refael Friedman
						Chayim Refael Friedman