Unnamed repository; edit this file 'description' to name the repository.
Rewrite `await` inference
- Do not eagerly normalize the `IntoFuture::Output` projection
- Store `IntoFuture` and `IntoFuture::Output` in `LangItems`, to save computing them every time. They are not really lang items, but are similar in nature.
| -rw-r--r-- | crates/hir-def/src/lang_item.rs | 35 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 54 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 17 |
3 files changed, 50 insertions, 56 deletions
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 6071ed2981..adc445c2a8 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -7,8 +7,8 @@ use intern::{Symbol, sym}; use stdx::impl_from; use crate::{ - AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, MacroId, - ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId, + AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, + ItemContainerId, MacroId, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId, attrs::AttrFlags, db::DefDatabase, nameres::{DefMap, assoc::TraitItems, crate_def_map, crate_local_def_map}, @@ -102,6 +102,8 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt lang_items.fill_non_lang_core_items(db, crate_def_map); } + lang_items.resolve_manually(db); + if lang_items.is_empty() { None } else { Some(Box::new(lang_items)) } } @@ -190,6 +192,23 @@ fn resolve_core_macro( current.scope.makro(&Name::new_symbol_root(name)) } +impl LangItems { + fn resolve_manually(&mut self, db: &dyn DefDatabase) { + (|| { + let into_future_into_future = self.IntoFutureIntoFuture?; + let ItemContainerId::TraitId(into_future) = into_future_into_future.loc(db).container + else { + return None; + }; + self.IntoFuture = Some(into_future); + self.IntoFutureOutput = into_future + .trait_items(db) + .associated_type_by_name(&Name::new_symbol_root(sym::Output)); + Some(()) + })(); + } +} + #[salsa::tracked(returns(as_deref))] pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option<Box<[TraitId]>> { let mut traits = Vec::new(); @@ -221,6 +240,10 @@ macro_rules! language_item_table { @non_lang_core_macros: $( core::$($non_lang_macro_module:ident)::*, $non_lang_macro:ident, $non_lang_macro_field:ident; )* + + @resolve_manually: + + $( $resolve_manually:ident, $resolve_manually_type:ident; )* ) => { #[allow(non_snake_case)] // FIXME: Should we remove this? #[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] @@ -235,6 +258,9 @@ macro_rules! language_item_table { $( pub $non_lang_macro_field: Option<MacroId>, )* + $( + pub $resolve_manually: Option<$resolve_manually_type>, + )* } impl LangItems { @@ -247,6 +273,7 @@ macro_rules! language_item_table { $( self.$lang_item = self.$lang_item.or(other.$lang_item); )* $( self.$non_lang_trait = self.$non_lang_trait.or(other.$non_lang_trait); )* $( self.$non_lang_macro_field = self.$non_lang_macro_field.or(other.$non_lang_macro_field); )* + $( self.$resolve_manually = self.$resolve_manually.or(other.$resolve_manually); )* } fn assign_lang_item(&mut self, name: Symbol, target: LangItemTarget) { @@ -538,4 +565,8 @@ language_item_table! { LangItems => core::marker, CoercePointee, CoercePointeeDerive; core::marker, Copy, CopyDerive; core::clone, Clone, CloneDerive; + + @resolve_manually: + IntoFuture, TraitId; + IntoFutureOutput, TypeAliasId; } diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 467a1a92dd..fd0612e066 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -35,8 +35,8 @@ use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ AdtId, AssocItemId, AttrDefId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwnerId, - FieldId, FunctionId, GenericDefId, GenericParamId, HasModule, ItemContainerId, LocalFieldId, - Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId, + FieldId, FunctionId, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, TraitId, + TupleFieldId, TupleId, TypeOrConstParamId, VariantId, attrs::AttrFlags, expr_store::{Body, ExpressionStore, HygieneId, RootExprOrigin, path::Path}, hir::{BindingId, ExprId, ExprOrPatId, LabelId, PatId}, @@ -49,7 +49,6 @@ use hir_def::{ }; use hir_expand::{mod_path::ModPath, name::Name}; use indexmap::IndexSet; -use intern::sym; use la_arena::ArenaMap; use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; @@ -83,8 +82,8 @@ use crate::{ }, method_resolution::CandidateId, next_solver::{ - AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Region, - StoredGenericArgs, StoredTy, StoredTys, Ty, TyKind, Tys, + AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArgs, Region, StoredGenericArgs, + StoredTy, StoredTys, Ty, TyKind, Tys, abi::Safety, infer::{InferCtxt, ObligationInspector, traits::ObligationCause}, }, @@ -1871,14 +1870,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.table.resolve_vars_if_possible(t) } - fn resolve_associated_type( - &mut self, - inner_ty: Ty<'db>, - assoc_ty: Option<TypeAliasId>, - ) -> Ty<'db> { - self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[]) - } - fn demand_eqtype( &mut self, id: ExprOrPatId, @@ -1974,30 +1965,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> { ty.unwrap_or_else(|| self.expr_ty(e)) } - fn resolve_associated_type_with_params( - &mut self, - inner_ty: Ty<'db>, - assoc_ty: Option<TypeAliasId>, - // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be - // handled when we support them. - params: &[GenericArg<'db>], - ) -> Ty<'db> { - match assoc_ty { - Some(res_assoc_ty) => { - let alias = Ty::new_alias( - self.interner(), - AliasTy::new( - self.interner(), - AliasTyKind::Projection { def_id: res_assoc_ty.into() }, - iter::once(inner_ty.into()).chain(params.iter().copied()), - ), - ); - self.table.try_structurally_resolve_type(alias) - } - None => self.err_ty(), - } - } - fn resolve_variant( &mut self, node: ExprOrPatId, @@ -2323,19 +2290,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } } - fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> { - trait_.trait_items(self.db).associated_type_by_name(&Name::new_symbol_root(sym::Output)) - } - - fn resolve_future_future_output(&self) -> Option<TypeAliasId> { - let ItemContainerId::TraitId(trait_) = - self.lang_items.IntoFutureIntoFuture?.lookup(self.db).container - else { - return None; - }; - self.resolve_output_on(trait_) - } - fn resolve_boxed_box(&self) -> Option<AdtId> { let struct_ = self.lang_items.OwnedBox?; Some(struct_.into()) diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index f35dd8ae0b..73d81ad16e 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -601,10 +601,7 @@ impl<'db> InferenceContext<'_, 'db> { self.infer_record_expr(tgt_expr, expected, path, fields, *spread) } Expr::Field { expr, name } => self.infer_field_access(tgt_expr, *expr, name, expected), - Expr::Await { expr } => { - let inner_ty = self.infer_expr_inner(*expr, &Expectation::none(), ExprIsRead::Yes); - self.resolve_associated_type(inner_ty, self.resolve_future_future_output()) - } + Expr::Await { expr } => self.infer_await_expr(*expr), Expr::Cast { expr, type_ref } => { let cast_ty = self.make_body_ty(*type_ref); let expr_ty = @@ -971,6 +968,18 @@ impl<'db> InferenceContext<'_, 'db> { ty } + fn infer_await_expr(&mut self, awaitee: ExprId) -> Ty<'db> { + let awaitee_ty = self.infer_expr_no_expect(awaitee, ExprIsRead::Yes); + let (Some(into_future), Some(into_future_output)) = + (self.lang_items.IntoFuture, self.lang_items.IntoFutureOutput) + else { + return self.types.types.error; + }; + self.table.register_bound(awaitee_ty, into_future, ObligationCause::new()); + // Do not eagerly normalize. + Ty::new_projection(self.interner(), into_future_output.into(), [awaitee_ty]) + } + fn infer_record_expr( &mut self, expr: ExprId, |