diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index 0d95d916ff9..f5324f052e5 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -222,11 +222,10 @@ impl GenericParams { let module = loc.container.module(db); let func_data = db.function_data(id); - // Don't create an `Expander` nor call `loc.source(db)` if not needed since this - // causes a reparse after the `ItemTree` has been created. - let mut expander = Lazy::new(|| { - (module.def_map(db), Expander::new(db, loc.source(db).file_id, module)) - }); + // Don't create an `Expander` if not needed since this + // could cause a reparse after the `ItemTree` has been created due to the spanmap. + let mut expander = + Lazy::new(|| (module.def_map(db), Expander::new(db, loc.id.file_id(), module))); for param in func_data.params.iter() { generic_params.fill_implicit_impl_trait_args(db, &mut expander, param); } diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 16144394e3b..3d2cddffa3b 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -106,11 +106,6 @@ impl ItemTree { pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { let _p = profile::span("file_item_tree_query").detail(|| format!("{file_id:?}")); let syntax = db.parse_or_expand(file_id); - if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) - { - // FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic - return Default::default(); - } let ctx = lower::Ctx::new(db, file_id); let mut top_attrs = None; @@ -129,6 +124,9 @@ impl ItemTree { ctx.lower_macro_stmts(stmts) }, _ => { + if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) { + return Default::default(); + } panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}"); }, } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 7cf13a202e0..b5333861cc8 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -569,6 +569,8 @@ pub struct ConstBlockLoc { pub root: hir::ExprId, } +/// Something that holds types, required for the current const arg lowering implementation as they +/// need to be able to query where they are defined. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum TypeOwnerId { FunctionId(FunctionId), @@ -581,9 +583,6 @@ pub enum TypeOwnerId { TypeAliasId(TypeAliasId), ImplId(ImplId), EnumVariantId(EnumVariantId), - // FIXME(const-generic-body): ModuleId should not be a type owner. This needs to be fixed to make `TypeOwnerId` actually - // useful for assigning ids to in type consts. - ModuleId(ModuleId), } impl TypeOwnerId { @@ -597,9 +596,7 @@ impl TypeOwnerId { TypeOwnerId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), TypeOwnerId::ImplId(it) => GenericDefId::ImplId(it), TypeOwnerId::EnumVariantId(it) => GenericDefId::EnumVariantId(it), - TypeOwnerId::InTypeConstId(_) | TypeOwnerId::ModuleId(_) | TypeOwnerId::StaticId(_) => { - return None - } + TypeOwnerId::InTypeConstId(_) | TypeOwnerId::StaticId(_) => return None, }) } } @@ -614,8 +611,7 @@ impl_from!( TraitAliasId, TypeAliasId, ImplId, - EnumVariantId, - ModuleId + EnumVariantId for TypeOwnerId ); @@ -713,12 +709,15 @@ pub struct InTypeConstLoc { pub id: AstId, /// The thing this const arg appears in pub owner: TypeOwnerId, - pub thing: Box, + // FIXME(const-generic-body): The expected type should not be + pub expected_ty: Box, } impl PartialEq for InTypeConstLoc { fn eq(&self, other: &Self) -> bool { - self.id == other.id && self.owner == other.owner && &*self.thing == &*other.thing + self.id == other.id + && self.owner == other.owner + && &*self.expected_ty == &*other.expected_ty } } @@ -1041,7 +1040,6 @@ impl HasModule for TypeOwnerId { TypeOwnerId::TypeAliasId(it) => it.lookup(db).module(db), TypeOwnerId::ImplId(it) => it.lookup(db).container, TypeOwnerId::EnumVariantId(it) => it.parent.lookup(db).container, - TypeOwnerId::ModuleId(it) => *it, } } } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index ba0a2c0224a..2ac1516ec07 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -589,6 +589,16 @@ impl Resolver { }) } + pub fn type_owner(&self) -> Option { + self.scopes().find_map(|scope| match scope { + Scope::BlockScope(_) => None, + &Scope::GenericParams { def, .. } => Some(def.into()), + &Scope::ImplDefScope(id) => Some(id.into()), + &Scope::AdtScope(adt) => Some(adt.into()), + Scope::ExprScope(it) => Some(it.owner.into()), + }) + } + pub fn impl_def(&self) -> Option { self.scopes().find_map(|scope| match scope { Scope::ImplDefScope(def) => Some(*def), @@ -1079,7 +1089,6 @@ impl HasResolver for TypeOwnerId { TypeOwnerId::TypeAliasId(it) => it.resolver(db), TypeOwnerId::ImplId(it) => it.resolver(db), TypeOwnerId::EnumVariantId(it) => it.resolver(db), - TypeOwnerId::ModuleId(it) => it.resolver(db), } } } diff --git a/crates/hir-expand/src/eager.rs b/crates/hir-expand/src/eager.rs index 1e2722e8464..8d55240aef5 100644 --- a/crates/hir-expand/src/eager.rs +++ b/crates/hir-expand/src/eager.rs @@ -88,7 +88,7 @@ pub fn expand_eager_macro_input( let loc = MacroCallLoc { def, krate, - eager: Some(Box::new(EagerCallInfo { arg: Arc::new(subtree), arg_id, error: err.clone() })), + eager: Some(Arc::new(EagerCallInfo { arg: Arc::new(subtree), arg_id, error: err.clone() })), kind: MacroCallKind::FnLike { ast_id: call_id, expand_to }, call_site, }; diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index f5e9cd33f2b..d7819b315c4 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -117,7 +117,7 @@ pub struct MacroCallLoc { pub krate: CrateId, /// Some if this is a macro call for an eager macro. Note that this is `None` /// for the eager input macro file. - eager: Option>, + eager: Option>, pub kind: MacroCallKind, pub call_site: SyntaxContextId, } diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 8262edec22c..6f724e45874 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -113,7 +113,7 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc() .unwrap() diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index c86fe9adff8..97c4a741ff2 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -113,7 +113,9 @@ pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, resolver: &'a Resolver, in_binders: DebruijnIndex, - owner: TypeOwnerId, + // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases + // where expected + owner: Option, /// Note: Conceptually, it's thinkable that we could be in a location where /// some type params should be represented as placeholders, and others /// should be converted to variables. I think in practice, this isn't @@ -127,6 +129,14 @@ pub struct TyLoweringContext<'a> { impl<'a> TyLoweringContext<'a> { pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self { + Self::new_maybe_unowned(db, resolver, Some(owner)) + } + + pub fn new_maybe_unowned( + db: &'a dyn HirDatabase, + resolver: &'a Resolver, + owner: Option, + ) -> Self { let impl_trait_mode = ImplTraitLoweringState::Disallowed; let type_param_mode = ParamLoweringMode::Placeholder; let in_binders = DebruijnIndex::INNERMOST; @@ -213,10 +223,11 @@ impl<'a> TyLoweringContext<'a> { } pub fn lower_const(&self, const_ref: &ConstRef, const_type: Ty) -> Const { + let Some(owner) = self.owner else { return unknown_const(const_type) }; const_or_path_to_chalk( self.db, self.resolver, - self.owner, + owner, const_type, const_ref, self.type_param_mode, @@ -1768,10 +1779,11 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders { let resolver = t.resolver(db.upcast()); let ctx = TyLoweringContext::new(db, &resolver, t.into()) .with_type_param_mode(ParamLoweringMode::Variable); - if db.type_alias_data(t).is_extern { + let type_alias_data = db.type_alias_data(t); + if type_alias_data.is_extern { Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)) } else { - let type_ref = &db.type_alias_data(t).type_ref; + let type_ref = &type_alias_data.type_ref; let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error)); make_binders(db, &generics, inner) } @@ -2042,7 +2054,7 @@ pub(crate) fn const_or_path_to_chalk( .intern_in_type_const(InTypeConstLoc { id: it, owner, - thing: Box::new(InTypeConstIdMetadata(expected_ty.clone())), + expected_ty: Box::new(InTypeConstIdMetadata(expected_ty.clone())), }) .into(); intern_const_scalar( diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index bb15ca8c436..28e84e480d7 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -9,11 +9,10 @@ use super::visit_module; fn typing_whitespace_inside_a_function_should_not_invalidate_types() { let (mut db, pos) = TestDB::with_position( " - //- /lib.rs - fn foo() -> i32 { - $01 + 1 - } - ", +//- /lib.rs +fn foo() -> i32 { + $01 + 1 +}", ); { let events = db.log_executed(|| { @@ -27,12 +26,11 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { } let new_text = " - fn foo() -> i32 { - 1 - + - 1 - } - "; +fn foo() -> i32 { + 1 + + + 1 +}"; db.set_file_text(pos.file_id, Arc::from(new_text)); @@ -47,3 +45,55 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { assert!(!format!("{events:?}").contains("infer"), "{events:#?}") } } + +#[test] +fn typing_inside_a_function_should_not_invalidate_types_in_another() { + let (mut db, pos) = TestDB::with_position( + " +//- /lib.rs +fn foo() -> f32 { + 1.0 + 2.0 +} +fn bar() -> i32 { + $01 + 1 +} +fn baz() -> i32 { + 1 + 1 +}", + ); + { + let events = db.log_executed(|| { + let module = db.module_for_file(pos.file_id); + let crate_def_map = module.def_map(&db); + visit_module(&db, &crate_def_map, module.local_id, &mut |def| { + db.infer(def); + }); + }); + assert!(format!("{events:?}").contains("infer")) + } + + let new_text = " +fn foo() -> f32 { + 1.0 + 2.0 +} +fn bar() -> i32 { + 53 +} +fn baz() -> i32 { + 1 + 1 +} +"; + + db.set_file_text(pos.file_id, Arc::from(new_text)); + + { + let events = db.log_executed(|| { + let module = db.module_for_file(pos.file_id); + let crate_def_map = module.def_map(&db); + visit_module(&db, &crate_def_map, module.local_id, &mut |def| { + db.infer(def); + }); + }); + assert!(format!("{events:?}").matches("infer").count() == 1, "{events:#?}") + } +} diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index dcf8ba27a68..a03ff220745 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -948,10 +948,10 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_type(&self, ty: &ast::Type) -> Option { let analyze = self.analyze(ty.syntax())?; let ctx = LowerCtx::with_file_id(self.db.upcast(), analyze.file_id); - let ty = hir_ty::TyLoweringContext::new( + let ty = hir_ty::TyLoweringContext::new_maybe_unowned( self.db, &analyze.resolver, - analyze.resolver.module().into(), + analyze.resolver.type_owner(), ) .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); Some(Type::new_with_resolver(self.db, &analyze.resolver, ty)) diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 73db6f8f0b8..d05118bbc28 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -1040,8 +1040,9 @@ fn resolve_hir_path_( let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => { - let (_, res) = TyLoweringContext::new(db, resolver, resolver.module().into()) - .lower_ty_ext(type_ref); + let (_, res) = + TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner()) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) } None => {