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.
Chayim Refael Friedman 4 weeks ago
parent 343744e · commit b53541f
-rw-r--r--crates/hir-def/src/lang_item.rs35
-rw-r--r--crates/hir-ty/src/infer.rs54
-rw-r--r--crates/hir-ty/src/infer/expr.rs17
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,