From c859e76f57711b689aef85faec746d665057b93e Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 23 Oct 2025 22:04:37 +0300 Subject: [PATCH] Represent async blocks as `TyKind::Coroutine`, not as opaques --- .../crates/hir-ty/src/display.rs | 88 +++++++++-------- .../rust-analyzer/crates/hir-ty/src/infer.rs | 1 - .../crates/hir-ty/src/infer/expr.rs | 33 ++++--- .../rust-analyzer/crates/hir-ty/src/lib.rs | 3 +- .../hir-ty/src/next_solver/generic_arg.rs | 1 - .../crates/hir-ty/src/next_solver/generics.rs | 26 +---- .../crates/hir-ty/src/next_solver/interner.rs | 3 +- .../crates/hir-ty/src/next_solver/ty.rs | 37 +++---- .../crates/hir-ty/src/next_solver/util.rs | 99 +------------------ 9 files changed, 94 insertions(+), 197 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index f8d9add42a8b..c749a3d24a25 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -48,7 +48,7 @@ use triomphe::Arc; use crate::{ CallableDefId, FnAbi, ImplTraitId, MemoryMap, TraitEnvironment, consteval, - db::{HirDatabase, InternedClosure}, + db::{HirDatabase, InternedClosure, InternedCoroutine}, generics::generics, layout::Layout, mir::pad16, @@ -1389,33 +1389,6 @@ impl<'db> HirDisplay<'db> for Ty<'db> { SizedByDefault::Sized { anchor: krate }, )?; } - ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => { - let future_trait = - LangItem::Future.resolve_trait(db, body.module(db).krate()); - let output = future_trait.and_then(|t| { - t.trait_items(db) - .associated_type_by_name(&Name::new_symbol_root(sym::Output)) - }); - write!(f, "impl ")?; - if let Some(t) = future_trait { - f.start_location_link(t.into()); - } - write!(f, "Future")?; - if future_trait.is_some() { - f.end_location_link(); - } - write!(f, "<")?; - if let Some(t) = output { - f.start_location_link(t.into()); - } - write!(f, "Output")?; - if output.is_some() { - f.end_location_link(); - } - write!(f, " = ")?; - alias_ty.args.type_at(0).hir_fmt(f)?; - write!(f, ">")?; - } } } TyKind::Closure(id, substs) => { @@ -1567,23 +1540,56 @@ impl<'db> HirDisplay<'db> for Ty<'db> { } } TyKind::Infer(..) => write!(f, "_")?, - TyKind::Coroutine(_, subst) => { - if f.display_kind.is_source_code() { - return Err(HirDisplayError::DisplaySourceCodeError( - DisplaySourceCodeError::Coroutine, - )); - } + TyKind::Coroutine(coroutine_id, subst) => { + let InternedCoroutine(owner, expr_id) = coroutine_id.0.loc(db); let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } = subst.split_coroutine_args(); - write!(f, "|")?; - resume_ty.hir_fmt(f)?; - write!(f, "|")?; + let body = db.body(owner); + match &body[expr_id] { + hir_def::hir::Expr::Async { .. } => { + let future_trait = + LangItem::Future.resolve_trait(db, owner.module(db).krate()); + let output = future_trait.and_then(|t| { + t.trait_items(db) + .associated_type_by_name(&Name::new_symbol_root(sym::Output)) + }); + write!(f, "impl ")?; + if let Some(t) = future_trait { + f.start_location_link(t.into()); + } + write!(f, "Future")?; + if future_trait.is_some() { + f.end_location_link(); + } + write!(f, "<")?; + if let Some(t) = output { + f.start_location_link(t.into()); + } + write!(f, "Output")?; + if output.is_some() { + f.end_location_link(); + } + write!(f, " = ")?; + return_ty.hir_fmt(f)?; + write!(f, ">")?; + } + _ => { + if f.display_kind.is_source_code() { + return Err(HirDisplayError::DisplaySourceCodeError( + DisplaySourceCodeError::Coroutine, + )); + } + write!(f, "|")?; + resume_ty.hir_fmt(f)?; + write!(f, "|")?; - write!(f, " yields ")?; - yield_ty.hir_fmt(f)?; + write!(f, " yields ")?; + yield_ty.hir_fmt(f)?; - write!(f, " -> ")?; - return_ty.hir_fmt(f)?; + write!(f, " -> ")?; + return_ty.hir_fmt(f)?; + } + } } TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?, TyKind::Pat(_, _) => write!(f, "{{pat}}")?, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 21b6e053cc3b..361e66522df6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -1243,7 +1243,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } (self.db.type_alias_impl_traits(def), idx) } - _ => unreachable!(), }; let Some(impl_traits) = impl_traits else { return ty; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index efb7244ff637..fd4e374d9c89 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -18,7 +18,7 @@ use hir_expand::name::Name; use intern::sym; use rustc_ast_ir::Mutability; use rustc_type_ir::{ - AliasTyKind, InferTy, Interner, + CoroutineArgs, CoroutineArgsParts, InferTy, Interner, inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Ty as _}, }; use syntax::ast::RangeOp; @@ -29,6 +29,7 @@ use crate::{ IncorrectGenericsLenKind, Rawness, TraitEnvironment, autoderef::overloaded_deref_ty, consteval, + db::InternedCoroutine, generics::generics, infer::{ AllowTwoPhase, BreakableKind, @@ -43,7 +44,7 @@ use crate::{ }, method_resolution::{self, VisibleFromModule}, next_solver::{ - AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, TraitRef, Ty, TyKind, + Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, TraitRef, Ty, TyKind, TypeError, infer::{ InferOk, @@ -1132,18 +1133,26 @@ impl<'db> InferenceContext<'_, 'db> { inner_ty: Ty<'db>, tgt_expr: ExprId, ) -> Ty<'db> { - // Use the first type parameter as the output type of future. - // existential type AsyncBlockImplTrait: Future - let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr); - let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); - Ty::new_alias( + let coroutine_id = InternedCoroutine(self.owner, tgt_expr); + let coroutine_id = self.db.intern_coroutine(coroutine_id).into(); + let parent_args = GenericArgs::identity_for_item(self.interner(), self.generic_def.into()); + Ty::new_coroutine( self.interner(), - AliasTyKind::Opaque, - AliasTy::new( + coroutine_id, + CoroutineArgs::new( self.interner(), - opaque_ty_id, - GenericArgs::new_from_iter(self.interner(), [inner_ty.into()]), - ), + CoroutineArgsParts { + parent_args, + kind_ty: self.types.unit, + // rustc uses a special lang item type for the resume ty. I don't believe this can cause us problems. + resume_ty: self.types.unit, + yield_ty: self.types.unit, + return_ty: inner_ty, + // FIXME: Infer upvars. + tupled_upvars_ty: self.types.unit, + }, + ) + .args, ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index ecca1ef04da5..2942c0f7a9d3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -53,7 +53,7 @@ mod variance; use std::hash::Hash; -use hir_def::{CallableDefId, TypeOrConstParamId, hir::ExprId, type_ref::Rawness}; +use hir_def::{CallableDefId, TypeOrConstParamId, type_ref::Rawness}; use hir_expand::name::Name; use indexmap::{IndexMap, map::Entry}; use intern::{Symbol, sym}; @@ -334,7 +334,6 @@ impl FnAbi { pub enum ImplTraitId<'db> { ReturnTypeImplTrait(hir_def::FunctionId, next_solver::ImplTraitIdx<'db>), TypeAliasImplTrait(hir_def::TypeAliasId, next_solver::ImplTraitIdx<'db>), - AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), } /// 'Canonicalizes' the `t` by replacing any errors with new variables. Also diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs index 24f22bcb0c3e..90bd44aee86f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs @@ -446,7 +446,6 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< signature_parts_ty, tupled_upvars_ty, coroutine_captures_by_ref_ty, - _coroutine_witness_ty, ] => rustc_type_ir::CoroutineClosureArgsParts { parent_args: GenericArgs::new_from_iter( DbInterner::conjure(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs index d5a9a6f527bb..4d164a7e3bc5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs @@ -2,10 +2,7 @@ use hir_def::{ ConstParamId, GenericDefId, GenericParamId, LifetimeParamId, TypeOrConstParamId, TypeParamId, - hir::generics::{ - GenericParams, LocalTypeOrConstParamId, TypeOrConstParamData, TypeParamData, - TypeParamProvenance, - }, + hir::generics::{GenericParams, TypeOrConstParamData}, }; use crate::{db::HirDatabase, generics::parent_generic_def}; @@ -67,27 +64,6 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => { (Some(type_alias_id.into()), Vec::new()) } - crate::ImplTraitId::AsyncBlockTypeImplTrait(_def, _) => { - let param = TypeOrConstParamData::TypeParamData(TypeParamData { - name: None, - default: None, - provenance: TypeParamProvenance::TypeParamList, - }); - // Yes, there is a parent but we don't include it in the generics - // FIXME: It seems utterly sensitive to fake a generic param here. - // Also, what a horrible mess! - ( - None, - vec![mk_ty( - GenericDefId::FunctionId(salsa::plumbing::FromId::from_id(unsafe { - salsa::Id::from_index(salsa::Id::MAX_U32 - 1) - })), - 0, - LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)), - ¶m, - )], - ) - } } } _ => panic!("No generics for {def:?}"), 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 06d35ba93d95..e3c65689d3fd 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 @@ -1884,8 +1884,7 @@ impl<'db> Interner for DbInterner<'db> { let infer = self.db().infer(func.into()); EarlyBinder::bind(infer.type_of_rpit[idx]) } - crate::ImplTraitId::TypeAliasImplTrait(..) - | crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { + crate::ImplTraitId::TypeAliasImplTrait(..) => { // FIXME(next-solver) EarlyBinder::bind(Ty::new_error(self, ErrorGuaranteed)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 95ee00d2754b..1443e2f0b312 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -26,7 +26,7 @@ use rustc_type_ir::{ use crate::{ ImplTraitId, - db::HirDatabase, + db::{HirDatabase, InternedCoroutine}, next_solver::{ AdtDef, AliasTy, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const, CoroutineIdWrapper, FnSig, GenericArg, PolyFnSig, Region, TraitRef, TypeAliasIdWrapper, @@ -546,23 +546,6 @@ impl<'db> Ty<'db> { .collect() }) } - ImplTraitId::AsyncBlockTypeImplTrait(def, _) => { - let krate = def.module(db).krate(); - if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) { - // This is only used by type walking. - // Parameters will be walked outside, and projection predicate is not used. - // So just provide the Future trait. - let impl_bound = TraitRef::new( - interner, - future_trait.into(), - GenericArgs::new_from_iter(interner, []), - ) - .upcast(interner); - Some(vec![impl_bound]) - } else { - None - } - } } } TyKind::Param(param) => { @@ -592,6 +575,24 @@ impl<'db> Ty<'db> { _ => None, } } + TyKind::Coroutine(coroutine_id, _args) => { + let InternedCoroutine(owner, _) = coroutine_id.0.loc(db); + let krate = owner.module(db).krate(); + if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) { + // This is only used by type walking. + // Parameters will be walked outside, and projection predicate is not used. + // So just provide the Future trait. + let impl_bound = TraitRef::new( + interner, + future_trait.into(), + GenericArgs::new_from_iter(interner, []), + ) + .upcast(interner); + Some(vec![impl_bound]) + } else { + None + } + } _ => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs index bb0d0552c710..d113f76a327d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs @@ -7,11 +7,10 @@ use std::{ use base_db::Crate; use hir_def::{BlockId, HasModule, lang_item::LangItem}; -use intern::sym; use la_arena::Idx; use rustc_abi::{Float, HasDataLayout, Integer, IntegerType, Primitive, ReprOptions}; use rustc_type_ir::{ - ConstKind, CoroutineArgs, DebruijnIndex, FloatTy, GenericArgKind, INNERMOST, IntTy, Interner, + ConstKind, CoroutineArgs, DebruijnIndex, FloatTy, INNERMOST, IntTy, Interner, PredicatePolarity, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, UintTy, UniverseIndex, inherent::{ @@ -32,9 +31,8 @@ use crate::{ }; use super::{ - AliasTerm, AliasTy, Binder, BoundRegion, BoundTy, BoundTyKind, BoundVarKind, BoundVarKinds, - Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder, GenericArgs, Predicate, - PredicateKind, ProjectionPredicate, Region, SolverDefId, Term, TraitPredicate, TraitRef, Ty, + Binder, BoundRegion, BoundTy, Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder, + GenericArgs, Predicate, PredicateKind, Region, SolverDefId, TraitPredicate, TraitRef, Ty, TyKind, fold::{BoundVarReplacer, FnMutDelegate}, }; @@ -578,98 +576,9 @@ pub fn explicit_item_bounds<'db>( let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())]; EarlyBinder::bind(Clauses::new_from_iter(interner, data.predicates.clone())) } - crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { - if let Some((future_trait, future_output)) = LangItem::Future - .resolve_trait(db, interner.krate.expect("Must have interner.krate")) - .and_then(|trait_| { - let alias = trait_.trait_items(db).associated_type_by_name( - &hir_expand::name::Name::new_symbol_root(sym::Output.clone()), - )?; - Some((trait_, alias)) - }) - { - let args = GenericArgs::identity_for_item(interner, def_id); - let out = args.as_slice()[0]; - let mut predicates = vec![]; - - let item_ty = Ty::new_alias( - interner, - rustc_type_ir::AliasTyKind::Opaque, - AliasTy::new_from_args(interner, def_id, args), - ); - - let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { - polarity: rustc_type_ir::PredicatePolarity::Positive, - trait_ref: TraitRef::new_from_args( - interner, - future_trait.into(), - GenericArgs::new_from_iter(interner, [item_ty.into()]), - ), - })); - predicates.push(Clause(Predicate::new( - interner, - Binder::bind_with_vars( - kind, - BoundVarKinds::new_from_iter( - interner, - [BoundVarKind::Ty(BoundTyKind::Anon)], - ), - ), - ))); - let sized_trait = LangItem::Sized - .resolve_trait(db, interner.krate.expect("Must have interner.krate")); - if let Some(sized_trait_) = sized_trait { - let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { - polarity: rustc_type_ir::PredicatePolarity::Positive, - trait_ref: TraitRef::new_from_args( - interner, - sized_trait_.into(), - GenericArgs::new_from_iter(interner, [item_ty.into()]), - ), - })); - predicates.push(Clause(Predicate::new( - interner, - Binder::bind_with_vars( - kind, - BoundVarKinds::new_from_iter( - interner, - [BoundVarKind::Ty(BoundTyKind::Anon)], - ), - ), - ))); - } - let kind = - PredicateKind::Clause(ClauseKind::Projection(ProjectionPredicate { - projection_term: AliasTerm::new_from_args( - interner, - future_output.into(), - GenericArgs::new_from_iter(interner, [item_ty.into()]), - ), - term: match out.kind() { - GenericArgKind::Lifetime(_lt) => panic!(), - GenericArgKind::Type(ty) => Term::Ty(ty), - GenericArgKind::Const(const_) => Term::Const(const_), - }, - })); - predicates.push(Clause(Predicate::new( - interner, - Binder::bind_with_vars( - kind, - BoundVarKinds::new_from_iter( - interner, - [BoundVarKind::Ty(BoundTyKind::Anon)], - ), - ), - ))); - EarlyBinder::bind(Clauses::new_from_iter(interner, predicates)) - } else { - // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback. - EarlyBinder::bind(Clauses::new_from_iter(interner, [])) - } - } } } - _ => panic!("Unexpected GeneridDefId"), + _ => panic!("Unexpected GenericDefId"), } }