From 00941b3142bf7b50a39b1a2dfa167d3642b5f3db Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 13 Aug 2025 10:07:12 +0200 Subject: [PATCH] implement `type_of_opaque` --- .../rust-analyzer/crates/hir-ty/src/layout.rs | 23 +--- .../crates/hir-ty/src/next_solver/interner.rs | 100 +++++++++--------- .../rust-analyzer/crates/hir-ty/src/tests.rs | 2 +- ...e_alias_impl_traits.rs => opaque_types.rs} | 16 +++ 4 files changed, 69 insertions(+), 72 deletions(-) rename src/tools/rust-analyzer/crates/hir-ty/src/tests/{type_alias_impl_traits.rs => opaque_types.rs} (92%) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 819bd583deae..e7bb529ad8f2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -335,27 +335,6 @@ pub fn layout_of_ty_ns_query<'db>( ptr.valid_range_mut().start = 1; Layout::scalar(dl, ptr) } - TyKind::Alias(_, ty) => match ty.def_id { - SolverDefId::TypeAliasId(_) => { - return Err(LayoutError::HasPlaceholder); - } - SolverDefId::InternedOpaqueTyId(opaque) => { - let impl_trait_id = db.lookup_intern_impl_trait_id(opaque); - match impl_trait_id { - crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { - let infer = db.infer(func.into()); - return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env); - } - crate::ImplTraitId::TypeAliasImplTrait(..) => { - return Err(LayoutError::NotImplemented); - } - crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { - return Err(LayoutError::NotImplemented); - } - } - } - _ => unreachable!(), - }, TyKind::Closure(c, args) => { let id = match c { SolverDefId::InternedClosureId(id) => id, @@ -389,7 +368,7 @@ pub fn layout_of_ty_ns_query<'db>( } TyKind::Error(_) => return Err(LayoutError::HasErrorType), - TyKind::Placeholder(_) | TyKind::Bound(..) | TyKind::Infer(..) | TyKind::Param(..) => { + TyKind::Placeholder(_) | TyKind::Bound(..) | TyKind::Infer(..) | TyKind::Param(..) | TyKind::Alias(..) => { return Err(LayoutError::HasPlaceholder); } }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 402c73bb8822..294d071f58ae 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -626,12 +626,8 @@ impl<'db> inherent::AdtDef> for AdtDef { fn struct_tail_ty( self, interner: DbInterner<'db>, - ) -> Option< - rustc_type_ir::EarlyBinder< - DbInterner<'db>, - as rustc_type_ir::Interner>::Ty, - >, - > { + ) -> Option, as rustc_type_ir::Interner>::Ty>> + { let db = interner.db(); let hir_def::AdtId::StructId(struct_id) = self.inner().id else { return None; @@ -645,7 +641,7 @@ impl<'db> inherent::AdtDef> for AdtDef { fn all_field_tys( self, interner: DbInterner<'db>, - ) -> rustc_type_ir::EarlyBinder< + ) -> EarlyBinder< DbInterner<'db>, impl IntoIterator as rustc_type_ir::Interner>::Ty>, > { @@ -679,19 +675,15 @@ impl<'db> inherent::AdtDef> for AdtDef { .collect(), }; - rustc_type_ir::EarlyBinder::bind(tys) + EarlyBinder::bind(tys) } fn sizedness_constraint( self, interner: DbInterner<'db>, sizedness: SizedTraitKind, - ) -> Option< - rustc_type_ir::EarlyBinder< - DbInterner<'db>, - as rustc_type_ir::Interner>::Ty, - >, - > { + ) -> Option, as rustc_type_ir::Interner>::Ty>> + { if self.is_struct() { let tail_ty = self.all_field_tys(interner).skip_binder().into_iter().last()?; @@ -1066,7 +1058,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } } - fn type_of(self, def_id: Self::DefId) -> rustc_type_ir::EarlyBinder { + fn type_of(self, def_id: Self::DefId) -> EarlyBinder { let def_id = match def_id { SolverDefId::TypeAliasId(id) => { use hir_def::Lookup; @@ -1077,9 +1069,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { crate::TyDefId::TypeAliasId(id) } SolverDefId::AdtId(id) => crate::TyDefId::AdtId(id), - // FIXME(next-solver): need to support opaque types. This uses the types of - // `query mir_borrowck` in rustc. If we're ignoring regions, we could simply - // use the type inferred by general type inference here. + // FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc. + // + // We currently always use the type from HIR typeck which ignores regions. This + // should be fine. + SolverDefId::InternedOpaqueTyId(_) => { + return self.type_of_opaque_hir_typeck(def_id); + } _ => panic!("Unexpected def_id `{def_id:?}` provided for `type_of`"), }; self.db().ty_ns(def_id) @@ -1109,7 +1105,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { SolverDefId::InternedOpaqueTyId(_) => AliasTermKind::OpaqueTy, SolverDefId::TypeAliasId(_) => AliasTermKind::ProjectionTy, SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst, - _ => todo!("Unexpected alias: {:?}", alias.def_id), + _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), } } @@ -1204,8 +1200,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn fn_sig( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder>> - { + ) -> EarlyBinder>> { let id = match def_id { SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), SolverDefId::Ctor(ctor) => match ctor { @@ -1258,7 +1253,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn item_bounds( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { explicit_item_bounds(self, def_id).map_bound(|bounds| { Clauses::new_from_iter(self, elaborate(self, bounds).collect::>()) }) @@ -1268,7 +1263,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn item_self_bounds( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { explicit_item_bounds(self, def_id).map_bound(|bounds| { Clauses::new_from_iter( self, @@ -1280,7 +1275,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn item_non_self_bounds( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { let all_bounds: FxHashSet<_> = self.item_bounds(def_id).skip_binder().into_iter().collect(); let own_bounds: FxHashSet<_> = self.item_self_bounds(def_id).skip_binder().into_iter().collect(); @@ -1298,7 +1293,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn predicates_of( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { let predicates = self.db().generic_predicates_ns(def_id.try_into().unwrap()); let predicates: Vec<_> = predicates.iter().cloned().collect(); EarlyBinder::bind(predicates.into_iter()) @@ -1308,7 +1303,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn own_predicates_of( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { let predicates = self.db().generic_predicates_without_parent_ns(def_id.try_into().unwrap()); let predicates: Vec<_> = predicates.iter().cloned().collect(); EarlyBinder::bind(predicates.into_iter()) @@ -1318,8 +1313,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn explicit_super_predicates_of( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> - { + ) -> EarlyBinder> { let predicates: Vec<(Clause<'db>, Span)> = self .db() .generic_predicates_ns(def_id.try_into().unwrap()) @@ -1327,15 +1321,14 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { .cloned() .map(|p| (p, Span::dummy())) .collect(); - rustc_type_ir::EarlyBinder::bind(predicates) + EarlyBinder::bind(predicates) } #[tracing::instrument(skip(self), ret)] fn explicit_implied_predicates_of( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> - { + ) -> EarlyBinder> { let predicates: Vec<(Clause<'db>, Span)> = self .db() .generic_predicates_ns(def_id.try_into().unwrap()) @@ -1343,13 +1336,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { .cloned() .map(|p| (p, Span::dummy())) .collect(); - rustc_type_ir::EarlyBinder::bind(predicates) + EarlyBinder::bind(predicates) } fn impl_super_outlives( self, impl_def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { let impl_id = match impl_def_id { SolverDefId::ImplId(id) => id, _ => unreachable!(), @@ -1372,11 +1365,11 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn const_conditions( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder< + ) -> EarlyBinder< Self, impl IntoIterator>>, > { - rustc_type_ir::EarlyBinder::bind([unimplemented!()]) + EarlyBinder::bind([unimplemented!()]) } fn has_target_features(self, def_id: Self::DefId) -> bool { @@ -1763,7 +1756,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn impl_trait_ref( self, impl_def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { let impl_id = match impl_def_id { SolverDefId::ImplId(id) => id, _ => panic!("Unexpected SolverDefId in impl_trait_ref"), @@ -1960,12 +1953,12 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn explicit_implied_const_bounds( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder< + ) -> EarlyBinder< Self, impl IntoIterator>>, > { // FIXME(next-solver) - rustc_type_ir::EarlyBinder::bind([]) + EarlyBinder::bind([]) } fn fn_is_const(self, def_id: Self::DefId) -> bool { @@ -1988,22 +1981,31 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { None } - fn type_of_opaque_hir_typeck( - self, - def_id: Self::LocalDefId, - ) -> rustc_type_ir::EarlyBinder { - // FIXME(next-solver): This should look at the type computed for the - // opaque by HIR typeck. - unimplemented!() + fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId) -> EarlyBinder { + match def_id { + SolverDefId::InternedOpaqueTyId(opaque) => { + let impl_trait_id = self.db().lookup_intern_impl_trait_id(opaque); + match impl_trait_id { + crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { + let infer = self.db().infer(func.into()); + EarlyBinder::bind(infer.type_of_rpit[idx].to_nextsolver(self)) + } + crate::ImplTraitId::TypeAliasImplTrait(..) + | crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { + // FIXME(next-solver) + EarlyBinder::bind(Ty::new_error(self, ErrorGuaranteed)) + } + } + } + _ => panic!("Unexpected SolverDefId in type_of_opaque_hir_typeck"), + } } fn coroutine_hidden_types( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder< - Self, - rustc_type_ir::Binder>, - > { + ) -> EarlyBinder>> + { // FIXME(next-solver) unimplemented!() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index fc31973022bd..d89cf4bcd45c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -6,11 +6,11 @@ mod incremental; mod macros; mod method_resolution; mod never_type; +mod opaque_types; mod patterns; mod regression; mod simple; mod traits; -mod type_alias_impl_traits; use base_db::{Crate, SourceDatabase}; use expect_test::Expect; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/type_alias_impl_traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs similarity index 92% rename from src/tools/rust-analyzer/crates/hir-ty/src/tests/type_alias_impl_traits.rs rename to src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs index e2b7bf379cc3..36578545a9f4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/type_alias_impl_traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs @@ -159,3 +159,19 @@ static ALIAS: i32 = { "#]], ) } + +#[test] +fn leak_auto_traits() { + check_no_mismatches( + r#" +//- minicore: send +fn foo() -> impl Sized {} + +fn is_send(_: T) {} + +fn main() { + is_send(foo()); +} + "#, + ); +}