Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/source_analyzer.rs')
-rw-r--r--crates/hir/src/source_analyzer.rs363
1 files changed, 206 insertions, 157 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 6c43f80ce8..06182620c8 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -5,12 +5,15 @@
//!
//! So, this modules should not be used during hir construction, it exists
//! purely for "IDE needs".
-use std::iter::{self, once};
+use std::{
+ cell::OnceCell,
+ iter::{self, once},
+};
use either::Either;
use hir_def::{
AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, ExpressionStoreOwnerId, FieldId,
- FunctionId, GenericDefId, LocalFieldId, ModuleDefId, StructId, TraitId, VariantId,
+ FunctionId, GenericDefId, LocalFieldId, ModuleDefId, StructId, VariantId,
expr_store::{
Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, HygieneId,
lower::ExprCollector,
@@ -21,7 +24,7 @@ use hir_def::{
lang_item::LangItems,
nameres::MacroSubNs,
resolver::{Resolver, TypeNs, ValueNs, resolver_for_scope},
- type_ref::{Mutability, TypeRef, TypeRefId},
+ type_ref::{Mutability, TypeRefId},
};
use hir_expand::{
HirFileId, InFile,
@@ -29,7 +32,8 @@ use hir_expand::{
name::{AsName, Name},
};
use hir_ty::{
- Adjustment, InferenceResult, LifetimeElisionKind, ParamEnvAndCrate, TyLoweringContext,
+ Adjustment, InferBodyId, InferenceResult, LifetimeElisionKind, ParamEnvAndCrate,
+ TyLoweringContext, TyLoweringInferVarsCtx,
diagnostics::{
InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields,
unsafe_operations,
@@ -37,8 +41,8 @@ use hir_ty::{
lang_items::lang_items_for_bin_op,
method_resolution::{self, CandidateId},
next_solver::{
- AliasTy, DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, Ty, TyKind, TypingMode,
- infer::DbInternerInferExt,
+ AliasTy, DbInterner, DefaultAny, ErrorGuaranteed, GenericArgs, ParamEnv, Region, Ty,
+ TyKind, TypingMode, infer::DbInternerInferExt,
},
traits::structurally_normalize_ty,
};
@@ -47,7 +51,7 @@ use itertools::Itertools;
use rustc_hash::FxHashSet;
use rustc_type_ir::{
AliasTyKind,
- inherent::{AdtDef, IntoKind, Ty as _},
+ inherent::{IntoKind, Ty as _},
};
use smallvec::SmallVec;
use stdx::never;
@@ -59,7 +63,7 @@ use syntax::{
use crate::{
Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const,
DeriveHelper, EnumVariant, Field, Function, GenericSubstitution, Local, Macro, ModuleDef,
- Static, Struct, ToolModule, Trait, TupleField, Type, TypeAlias,
+ SemanticsImpl, Static, Struct, ToolModule, Trait, TupleField, Type, TypeAlias,
db::HirDatabase,
semantics::{PathResolution, PathResolutionPerNs},
};
@@ -71,6 +75,7 @@ pub(crate) struct SourceAnalyzer<'db> {
pub(crate) file_id: HirFileId,
pub(crate) resolver: Resolver<'db>,
pub(crate) body_or_sig: Option<BodyOrSig<'db>>,
+ pub(crate) infer_body: Option<InferBodyId>,
}
#[derive(Debug)]
@@ -137,34 +142,39 @@ impl<'db> SourceAnalyzer<'db> {
scope_for_offset(db, scopes, source_map, node.file_id, offset)
}
};
+ let (scope, _expr) = scope.unzip();
let resolver = resolver_for_scope(db, def, scope);
SourceAnalyzer {
resolver,
body_or_sig: Some(BodyOrSig::Body { def, body, source_map, infer }),
file_id,
+ infer_body: Some(def.into()),
}
}
pub(crate) fn new_generic_def(
db: &'db dyn HirDatabase,
+ sema: &SemanticsImpl<'db>,
def: GenericDefId,
node: InFile<&SyntaxNode>,
offset: Option<TextSize>,
) -> SourceAnalyzer<'db> {
- Self::new_generic_def_(db, def, node, offset, true)
+ Self::new_generic_def_(db, sema, def, node, offset, true)
}
pub(crate) fn new_generic_def_no_infer(
db: &'db dyn HirDatabase,
+ sema: &SemanticsImpl<'db>,
def: GenericDefId,
node: InFile<&SyntaxNode>,
offset: Option<TextSize>,
) -> SourceAnalyzer<'db> {
- Self::new_generic_def_(db, def, node, offset, false)
+ Self::new_generic_def_(db, sema, def, node, offset, false)
}
pub(crate) fn new_generic_def_(
db: &'db dyn HirDatabase,
+ sema: &SemanticsImpl<'db>,
def: GenericDefId,
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
offset: Option<TextSize>,
@@ -184,17 +194,31 @@ impl<'db> SourceAnalyzer<'db> {
scope_for_offset(db, scopes, source_map, node.file_id, offset)
}
};
+ let (scope, expr) = scope.unzip();
let resolver = resolver_for_scope(db, def, scope);
- let infer = if infer { Some(InferenceResult::of(db, def)) } else { None };
+ let infer_body = expr.and_then(|expr| {
+ sema.infer_body_for_expr_or_pat(
+ ExpressionStoreOwnerId::Signature(def),
+ store,
+ expr.into(),
+ )
+ });
+ let infer = if infer && let Some(infer_body) = infer_body {
+ Some(InferenceResult::of(db, infer_body))
+ } else {
+ None
+ };
SourceAnalyzer {
resolver,
body_or_sig: Some(BodyOrSig::Sig { def, store, source_map, generics, infer }),
file_id,
+ infer_body,
}
}
pub(crate) fn new_variant_body(
db: &'db dyn HirDatabase,
+ sema: &SemanticsImpl<'db>,
def: VariantId,
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
offset: Option<TextSize>,
@@ -214,8 +238,20 @@ impl<'db> SourceAnalyzer<'db> {
scope_for_offset(db, scopes, source_map, node.file_id, offset)
}
};
+ let (scope, expr) = scope.unzip();
let resolver = resolver_for_scope(db, def, scope);
- let infer = if infer { Some(InferenceResult::of(db, def)) } else { None };
+ let infer_body = expr.and_then(|expr| {
+ sema.infer_body_for_expr_or_pat(
+ ExpressionStoreOwnerId::VariantFields(def),
+ &fields.store,
+ expr.into(),
+ )
+ });
+ let infer = if infer && let Some(infer_body) = infer_body {
+ Some(InferenceResult::of(db, infer_body))
+ } else {
+ None
+ };
SourceAnalyzer {
resolver,
body_or_sig: Some(BodyOrSig::VariantFields {
@@ -225,6 +261,7 @@ impl<'db> SourceAnalyzer<'db> {
infer,
}),
file_id,
+ infer_body,
}
}
@@ -232,7 +269,7 @@ impl<'db> SourceAnalyzer<'db> {
resolver: Resolver<'db>,
node: InFile<&SyntaxNode>,
) -> SourceAnalyzer<'db> {
- SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id }
+ SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id, infer_body: None }
}
fn owner(&self) -> Option<ExpressionStoreOwnerId> {
@@ -339,39 +376,45 @@ impl<'db> SourceAnalyzer<'db> {
let type_ref = self.type_id(ty)?;
- let mut ty = TyLoweringContext::new(
+ let generic_def = self.resolver.generic_def()?;
+ let generics = OnceCell::new();
+ let mut vars_cts = VarsCtx { types: interner.default_types(), infer: self.infer() };
+ let ty = TyLoweringContext::new(
db,
&self.resolver,
self.store()?,
- self.resolver.generic_def()?,
+ generic_def.into(),
+ generic_def,
+ &generics,
// FIXME: Is this correct here? Anyway that should impact mostly diagnostics, which we don't emit here
// (this can impact the lifetimes generated, e.g. in `const` they won't be `'static`, but this seems like a
// small problem).
LifetimeElisionKind::Infer,
)
+ .with_infer_vars_behavior(Some(&mut vars_cts))
.lower_ty(type_ref);
- // Try and substitute unknown types using InferenceResult
- if let Some(infer) = self.infer()
- && let Some(store) = self.store()
- {
- let mut inferred_types = vec![];
- TypeRef::walk(type_ref, store, &mut |type_ref_id, type_ref| {
- if matches!(type_ref, TypeRef::Placeholder) {
- inferred_types.push(infer.type_of_type_placeholder(type_ref_id));
+ struct VarsCtx<'a, 'db> {
+ types: &'db DefaultAny<'db>,
+ infer: Option<&'a InferenceResult>,
+ }
+
+ impl<'db> TyLoweringInferVarsCtx<'db> for VarsCtx<'_, 'db> {
+ fn next_ty_var(&mut self, span: hir_ty::Span) -> Ty<'db> {
+ if let hir_ty::Span::TypeRefId(type_ref) = span
+ && let Some(ty) =
+ self.infer.and_then(|infer| infer.type_of_type_placeholder(type_ref))
+ {
+ ty
+ } else {
+ self.types.types.error
}
- });
- let mut inferred_types = inferred_types.into_iter();
-
- let substituted_ty = hir_ty::next_solver::fold::fold_tys(interner, ty, |ty| {
- if ty.is_ty_error() { inferred_types.next().flatten().unwrap_or(ty) } else { ty }
- });
-
- // Only used the result if the placeholder and unknown type counts matched
- let success =
- inferred_types.next().is_none() && !substituted_ty.references_non_lt_error();
- if success {
- ty = substituted_ty;
+ }
+ fn next_const_var(&mut self, _span: hir_ty::Span) -> hir_ty::next_solver::Const<'db> {
+ self.types.consts.error
+ }
+ fn next_region_var(&mut self, _span: hir_ty::Span) -> Region<'db> {
+ self.types.regions.error
}
}
@@ -409,7 +452,7 @@ impl<'db> SourceAnalyzer<'db> {
ExprOrPatId::PatId(idx) => infer
.pat_adjustment(idx)
.and_then(|adjusts| adjusts.last())
- .map(|adjust| adjust.as_ref()),
+ .map(|adjust| adjust.source.as_ref()),
};
let ty = infer.expr_or_pat_ty(expr_or_pat_id);
@@ -436,7 +479,7 @@ impl<'db> SourceAnalyzer<'db> {
) -> Option<Type<'db>> {
let binding = match self.body_or_sig.as_ref()? {
BodyOrSig::Sig { .. } | BodyOrSig::VariantFields { .. } => return None,
- BodyOrSig::Body { body, .. } => body.self_param?,
+ BodyOrSig::Body { body, .. } => body.self_param()?,
};
let ty = self.infer()?.binding_ty(binding);
Some(Type::new_with_resolver(db, &self.resolver, ty))
@@ -449,12 +492,12 @@ impl<'db> SourceAnalyzer<'db> {
) -> Option<BindingMode> {
let id = self.pat_id(&pat.clone().into())?;
let infer = self.infer()?;
- infer.binding_mode(id.as_pat()?).map(|bm| match bm {
- hir_ty::BindingMode::Move => BindingMode::Move,
- hir_ty::BindingMode::Ref(hir_ty::next_solver::Mutability::Mut) => {
+ Some(match infer.binding_mode(id.as_pat()?)? {
+ hir_ty::BindingMode(hir_ty::ByRef::No, _) => BindingMode::Move,
+ hir_ty::BindingMode(hir_ty::ByRef::Yes(hir_ty::next_solver::Mutability::Mut), _) => {
BindingMode::Ref(Mutability::Mut)
}
- hir_ty::BindingMode::Ref(hir_ty::next_solver::Mutability::Not) => {
+ hir_ty::BindingMode(hir_ty::ByRef::Yes(hir_ty::next_solver::Mutability::Not), _) => {
BindingMode::Ref(Mutability::Shared)
}
})
@@ -470,7 +513,7 @@ impl<'db> SourceAnalyzer<'db> {
infer
.pat_adjustment(pat_id.as_pat()?)?
.iter()
- .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.as_ref()))
+ .map(|adjust| Type::new_with_resolver(db, &self.resolver, adjust.source.as_ref()))
.collect(),
)
}
@@ -483,7 +526,7 @@ impl<'db> SourceAnalyzer<'db> {
let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
let (func, args) = self.infer()?.method_resolution(expr_id)?;
let interner = DbInterner::new_no_crate(db);
- let ty = db.value_ty(func.into())?.instantiate(interner, args);
+ let ty = db.value_ty(func.into())?.instantiate(interner, args).skip_norm_wip();
let ty = Type::new_with_resolver(db, &self.resolver, ty);
let mut res = ty.as_callable(db)?;
res.is_bound_method = true;
@@ -538,7 +581,7 @@ impl<'db> SourceAnalyzer<'db> {
&self,
field: &ast::FieldExpr,
) -> Option<Either<Field, TupleField>> {
- let def = self.owner()?;
+ let def = self.infer_body?;
let expr_id = self.expr_id(field.clone().into())?.as_expr()?;
self.infer()?.field_resolution(expr_id).map(|it| {
it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index })
@@ -565,7 +608,7 @@ impl<'db> SourceAnalyzer<'db> {
field: &ast::FieldExpr,
) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution<'db>>)>
{
- let def = self.owner()?;
+ let def = self.infer_body?;
let expr_id = self.expr_id(field.clone().into())?.as_expr()?;
let inference_result = self.infer()?;
match inference_result.field_resolution(expr_id) {
@@ -626,8 +669,7 @@ impl<'db> SourceAnalyzer<'db> {
has_start: bool,
has_end: bool,
) -> Option<StructId> {
- let has_new_range =
- self.resolver.top_level_def_map().is_unstable_feature_enabled(&sym::new_range);
+ let has_new_range = self.resolver.top_level_def_map().features().new_range;
let lang_items = self.lang_items(db);
match (op_kind, has_start, has_end) {
(RangeOp::Exclusive, false, false) => lang_items.RangeFull,
@@ -707,35 +749,25 @@ impl<'db> SourceAnalyzer<'db> {
db: &'db dyn HirDatabase,
prefix_expr: &ast::PrefixExpr,
) -> Option<Function> {
+ let lang_items = self.lang_items(db);
let (_op_trait, op_fn) = match prefix_expr.op_kind()? {
ast::UnaryOp::Deref => {
// This can be either `Deref::deref` or `DerefMut::deref_mut`.
// Since deref kind is inferenced and stored in `InferenceResult.method_resolution`,
// use that result to find out which one it is.
- let (deref_trait, deref) = self.lang_trait_fn(
- db,
- self.lang_items(db).Deref,
- &Name::new_symbol_root(sym::deref),
- )?;
+ let (deref_trait, deref) = (lang_items.Deref?, lang_items.Deref_deref?);
self.infer()
.and_then(|infer| {
let expr = self.expr_id(prefix_expr.clone().into())?.as_expr()?;
let (func, _) = infer.method_resolution(expr)?;
- let (deref_mut_trait, deref_mut) = self.lang_trait_fn(
- db,
- self.lang_items(db).DerefMut,
- &Name::new_symbol_root(sym::deref_mut),
- )?;
+ let (deref_mut_trait, deref_mut) =
+ (lang_items.DerefMut?, lang_items.DerefMut_deref_mut?);
if func == deref_mut { Some((deref_mut_trait, deref_mut)) } else { None }
})
.unwrap_or((deref_trait, deref))
}
- ast::UnaryOp::Not => {
- self.lang_trait_fn(db, self.lang_items(db).Not, &Name::new_symbol_root(sym::not))?
- }
- ast::UnaryOp::Neg => {
- self.lang_trait_fn(db, self.lang_items(db).Neg, &Name::new_symbol_root(sym::neg))?
- }
+ ast::UnaryOp::Not => (lang_items.Not?, lang_items.Not_not?),
+ ast::UnaryOp::Neg => (lang_items.Neg?, lang_items.Neg_neg?),
};
let ty = self.ty_of_expr(prefix_expr.expr()?)?;
@@ -754,19 +786,16 @@ impl<'db> SourceAnalyzer<'db> {
) -> Option<Function> {
let base_ty = self.ty_of_expr(index_expr.base()?)?;
let index_ty = self.ty_of_expr(index_expr.index()?)?;
+ let lang_items = self.lang_items(db);
- let (_index_trait, index_fn) =
- self.lang_trait_fn(db, self.lang_items(db).Index, &Name::new_symbol_root(sym::index))?;
+ let (_index_trait, index_fn) = (lang_items.Index?, lang_items.Index_index?);
let op_fn = self
.infer()
.and_then(|infer| {
let expr = self.expr_id(index_expr.clone().into())?.as_expr()?;
let (func, _) = infer.method_resolution(expr)?;
- let (_index_mut_trait, index_mut_fn) = self.lang_trait_fn(
- db,
- self.lang_items(db).IndexMut,
- &Name::new_symbol_root(sym::index_mut),
- )?;
+ let (_index_mut_trait, index_mut_fn) =
+ (lang_items.IndexMut_index_mut?, lang_items.IndexMut_index_mut?);
if func == index_mut_fn { Some(index_mut_fn) } else { None }
})
.unwrap_or(index_fn);
@@ -785,10 +814,8 @@ impl<'db> SourceAnalyzer<'db> {
let lhs = self.ty_of_expr(binop_expr.lhs()?)?;
let rhs = self.ty_of_expr(binop_expr.rhs()?)?;
- let (_op_trait, op_fn) =
- lang_items_for_bin_op(self.lang_items(db), op).and_then(|(name, lang_item)| {
- self.lang_trait_fn(db, lang_item, &Name::new_symbol_root(name))
- })?;
+ let (op_fn, _op_trait) = lang_items_for_bin_op(self.lang_items(db), op)
+ .and_then(|(method, trait_)| method.zip(trait_))?;
// HACK: subst for `index()` coincides with that for `Index` because `index()` itself
// doesn't have any generic parameters, so we skip building another subst for `index()`.
let substs = GenericArgs::new_from_slice(&[lhs.into(), rhs.into()]);
@@ -836,9 +863,11 @@ impl<'db> SourceAnalyzer<'db> {
&path,
name_hygiene(db, InFile::new(self.file_id, ast_name.syntax())),
) {
- Some(ValueNs::LocalBinding(binding_id)) => {
- Some(Local { binding_id, parent: self.resolver.expression_store_owner()? })
- }
+ Some(ValueNs::LocalBinding(binding_id)) => Some(Local {
+ binding_id,
+ parent: self.owner()?,
+ parent_infer: self.infer_body?,
+ }),
_ => None,
}
};
@@ -846,8 +875,10 @@ impl<'db> SourceAnalyzer<'db> {
let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?;
let variant_data = variant.fields(db);
let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
- let field_ty =
- (*db.field_types(variant).get(field.local_id)?).get().instantiate(interner, subst);
+ let field_ty = (*db.field_types(variant).get(field.local_id)?)
+ .get()
+ .instantiate(interner, subst)
+ .skip_norm_wip();
Some((
field.into(),
local,
@@ -869,8 +900,10 @@ impl<'db> SourceAnalyzer<'db> {
let variant_data = variant.fields(db);
let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
let (adt, subst) = self.infer()?.pat_ty(pat_id.as_pat()?).as_adt()?;
- let field_ty =
- (*db.field_types(variant).get(field.local_id)?).get().instantiate(interner, subst);
+ let field_ty = (*db.field_types(variant).get(field.local_id)?)
+ .get()
+ .instantiate(interner, subst)
+ .skip_norm_wip();
Some((
field.into(),
Type::new_with_resolver(db, &self.resolver, field_ty),
@@ -898,7 +931,14 @@ impl<'db> SourceAnalyzer<'db> {
};
let store_owner = self.resolver.expression_store_owner();
- let res = resolve_hir_value_path(db, &self.resolver, store_owner, path, HygieneId::ROOT)?;
+ let res = resolve_hir_value_path(
+ db,
+ &self.resolver,
+ store_owner,
+ self.infer_body,
+ path,
+ HygieneId::ROOT,
+ )?;
match res {
PathResolution::Def(def) => Some(def),
_ => None,
@@ -932,24 +972,25 @@ impl<'db> SourceAnalyzer<'db> {
if let Either::Right(container) = &mut container {
*container = structurally_normalize_ty(&infcx, *container, trait_env.param_env);
}
- let handle_variants = |variant: VariantId,
- subst: GenericArgs<'db>,
- container: &mut _| {
- let fields = variant.fields(db);
- let field = fields.field(&field_name.as_name())?;
- let field_types = db.field_types(variant);
- *container = Either::Right(field_types[field].get().instantiate(interner, subst));
- let generic_def = match variant {
- VariantId::EnumVariantId(it) => it.loc(db).parent.into(),
- VariantId::StructId(it) => it.into(),
- VariantId::UnionId(it) => it.into(),
+ let handle_variants =
+ |variant: VariantId, subst: GenericArgs<'db>, container: &mut _| {
+ let fields = variant.fields(db);
+ let field = fields.field(&field_name.as_name())?;
+ let field_types = db.field_types(variant);
+ *container = Either::Right(
+ field_types[field].get().instantiate(interner, subst).skip_norm_wip(),
+ );
+ let generic_def = match variant {
+ VariantId::EnumVariantId(it) => it.loc(db).parent.into(),
+ VariantId::StructId(it) => it.into(),
+ VariantId::UnionId(it) => it.into(),
+ };
+ Some((
+ Either::Right(Field { parent: variant.into(), id: field }),
+ generic_def,
+ subst,
+ ))
};
- Some((
- Either::Right(Field { parent: variant.into(), id: field }),
- generic_def,
- subst,
- ))
- };
let temp_ty = Ty::new_error(interner, ErrorGuaranteed);
let (field_def, generic_def, subst) =
match std::mem::replace(&mut container, Either::Right(temp_ty)) {
@@ -957,7 +998,7 @@ impl<'db> SourceAnalyzer<'db> {
handle_variants(VariantId::from(variant_id), subst, &mut container)?
}
Either::Right(container_ty) => match container_ty.kind() {
- TyKind::Adt(adt_def, subst) => match adt_def.def_id().0 {
+ TyKind::Adt(adt_def, subst) => match adt_def.def_id() {
AdtId::StructId(id) => {
handle_variants(id.into(), subst, &mut container)?
}
@@ -1120,7 +1161,7 @@ impl<'db> SourceAnalyzer<'db> {
}
// FIXME: collectiong here shouldnt be necessary?
- let mut collector = ExprCollector::body(db, self.resolver.module(), self.file_id);
+ let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);
let hir_path =
collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;
let parent_hir_path = path
@@ -1202,21 +1243,15 @@ impl<'db> SourceAnalyzer<'db> {
}
if let Some(attr) = meta_path.parent_attr() {
- let adt = if let Some(field) =
- attr.syntax().parent().and_then(ast::RecordField::cast)
- {
- field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
- } else if let Some(field) =
- attr.syntax().parent().and_then(ast::TupleField::cast)
- {
- field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
- } else if let Some(variant) =
- attr.syntax().parent().and_then(ast::Variant::cast)
- {
- variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast)
- } else {
- None
- };
+ let adt =
+ attr.syntax().ancestors().find_map(ast::Item::cast).and_then(
+ |it| match it {
+ ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
+ ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
+ ast::Item::Union(it) => Some(ast::Adt::Union(it)),
+ _ => None,
+ },
+ );
if let Some(adt) = adt {
let ast_id = db.ast_id_map(self.file_id).ast_id(&adt);
if let Some(helpers) = self
@@ -1266,6 +1301,7 @@ impl<'db> SourceAnalyzer<'db> {
let res = resolve_hir_path_(
db,
&self.resolver,
+ self.infer_body,
&hir_path,
prefer_value_ns,
name_hygiene(db, InFile::new(self.file_id, path.syntax())),
@@ -1287,7 +1323,7 @@ impl<'db> SourceAnalyzer<'db> {
let env = self.trait_environment(db);
let (subst, expected_resolution) = match ty.kind() {
TyKind::Adt(adt_def, subst) => {
- let adt_id = adt_def.def_id().0;
+ let adt_id = adt_def.def_id();
(
GenericSubstitution::new(adt_id.into(), subst, env),
PathResolution::Def(ModuleDef::Adt(adt_id.into())),
@@ -1298,7 +1334,7 @@ impl<'db> SourceAnalyzer<'db> {
args,
..
}) => {
- let assoc_id = def_id.expect_type_alias();
+ let assoc_id = def_id.0;
(
GenericSubstitution::new(assoc_id.into(), args, env),
PathResolution::Def(ModuleDef::TypeAlias(assoc_id.into())),
@@ -1332,13 +1368,14 @@ impl<'db> SourceAnalyzer<'db> {
db: &dyn HirDatabase,
path: &ast::Path,
) -> Option<PathResolutionPerNs> {
- let mut collector = ExprCollector::body(db, self.resolver.module(), self.file_id);
+ let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);
let hir_path =
collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;
let (store, _) = collector.store.finish();
Some(resolve_hir_path_(
db,
&self.resolver,
+ self.infer_body,
&hir_path,
false,
name_hygiene(db, InFile::new(self.file_id, path.syntax())),
@@ -1428,7 +1465,7 @@ impl<'db> SourceAnalyzer<'db> {
.into_iter()
.map(|local_id| {
let field = FieldId { parent: variant, local_id };
- let ty = field_types[local_id].get().instantiate(interner, substs);
+ let ty = field_types[local_id].get().instantiate(interner, substs).skip_norm_wip();
(field.into(), Type::new_with_resolver_inner(db, &self.resolver, ty))
})
.collect()
@@ -1456,9 +1493,7 @@ impl<'db> SourceAnalyzer<'db> {
};
match expanded_expr {
ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr),
- ExprOrPatId::PatId(expanded_pat) => {
- body.walk_exprs_in_pat(expanded_pat, &mut walk_expr)
- }
+ ExprOrPatId::PatId(expanded_pat) => body.walk_exprs_in_pat(expanded_pat, walk_expr),
}
return is_unsafe;
}
@@ -1480,6 +1515,7 @@ impl<'db> SourceAnalyzer<'db> {
db,
&self.resolver,
self.resolver.expression_store_owner(),
+ self.infer_body,
&Path::from_known_path_with_no_generic(ModPath::from_segments(
PathKind::Plain,
Some(name.clone()),
@@ -1519,6 +1555,7 @@ impl<'db> SourceAnalyzer<'db> {
db,
&self.resolver,
self.resolver.expression_store_owner(),
+ self.infer_body,
&Path::from_known_path_with_no_generic(ModPath::from_segments(
PathKind::Plain,
Some(name.clone()),
@@ -1586,28 +1623,19 @@ impl<'db> SourceAnalyzer<'db> {
hir_def::lang_item::lang_items(db, self.resolver.krate())
}
- fn lang_trait_fn(
- &self,
- db: &'db dyn HirDatabase,
- lang_trait: Option<TraitId>,
- method_name: &Name,
- ) -> Option<(TraitId, FunctionId)> {
- let trait_id = lang_trait?;
- let fn_id = trait_id.trait_items(db).method_by_name(method_name)?;
- Some((trait_id, fn_id))
- }
-
fn ty_of_expr(&self, expr: ast::Expr) -> Option<Ty<'db>> {
self.infer()?.type_of_expr_or_pat(self.expr_id(expr)?)
}
}
+// Note: the `ExprId` here does not need to be accurate, what's important is that it points at the same
+// inference root.
fn scope_for(
db: &dyn HirDatabase,
scopes: &ExprScopes,
source_map: &ExpressionStoreSourceMap,
node: InFile<&SyntaxNode>,
-) -> Option<ScopeId> {
+) -> Option<(ScopeId, ExprId)> {
node.ancestors_with_macros(db)
.take_while(|it| {
let kind = it.kind();
@@ -1618,7 +1646,7 @@ fn scope_for(
})
.filter_map(|it| it.map(ast::Expr::cast).transpose())
.filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr())
- .find_map(|it| scopes.scope_for(it))
+ .find_map(|expr| scopes.scope_for(expr).map(|scope| (scope, expr)))
}
fn scope_for_offset(
@@ -1627,14 +1655,14 @@ fn scope_for_offset(
source_map: &ExpressionStoreSourceMap,
from_file: HirFileId,
offset: TextSize,
-) -> Option<ScopeId> {
+) -> Option<(ScopeId, ExprId)> {
scopes
.scope_by_expr()
.iter()
.filter_map(|(id, scope)| {
let InFile { file_id, value } = source_map.expr_syntax(id).ok()?;
if from_file == file_id {
- return Some((value.text_range(), scope));
+ return Some((value.text_range(), scope, id));
}
// FIXME handle attribute expansion
@@ -1643,13 +1671,15 @@ fn scope_for_offset(
})
.find(|it| it.file_id == from_file)
.filter(|it| it.kind() == SyntaxKind::MACRO_CALL)?;
- Some((source.text_range(), scope))
+ Some((source.text_range(), scope, id))
+ })
+ .filter(|(expr_range, _scope, _expr)| {
+ expr_range.start() <= offset && offset <= expr_range.end()
})
- .filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end())
// find containing scope
- .min_by_key(|(expr_range, _scope)| expr_range.len())
- .map(|(expr_range, scope)| {
- adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or(*scope)
+ .min_by_key(|(expr_range, _scope, _expr)| expr_range.len())
+ .map(|(expr_range, scope, expr)| {
+ adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or((*scope, expr))
})
}
@@ -1662,7 +1692,7 @@ fn adjust(
expr_range: TextRange,
from_file: HirFileId,
offset: TextSize,
-) -> Option<ScopeId> {
+) -> Option<(ScopeId, ExprId)> {
let child_scopes = scopes
.scope_by_expr()
.iter()
@@ -1674,14 +1704,14 @@ fn adjust(
}
let root = source.file_syntax(db);
let node = source.value.to_node(&root);
- Some((node.syntax().text_range(), scope))
+ Some((node.syntax().text_range(), scope, id))
})
- .filter(|&(range, _)| {
+ .filter(|&(range, _, _)| {
range.start() <= offset && expr_range.contains_range(range) && range != expr_range
});
child_scopes
- .max_by(|&(r1, _), &(r2, _)| {
+ .max_by(|&(r1, _, _), &(r2, _, _)| {
if r1.contains_range(r2) {
std::cmp::Ordering::Greater
} else if r2.contains_range(r1) {
@@ -1690,18 +1720,19 @@ fn adjust(
r1.start().cmp(&r2.start())
}
})
- .map(|(_ptr, scope)| *scope)
+ .map(|(_ptr, scope, expr)| (*scope, expr))
}
#[inline]
pub(crate) fn resolve_hir_path(
db: &dyn HirDatabase,
resolver: &Resolver<'_>,
+ infer_body: Option<InferBodyId>,
path: &Path,
hygiene: HygieneId,
store: Option<&ExpressionStore>,
) -> Option<PathResolution> {
- resolve_hir_path_(db, resolver, path, false, hygiene, store, false).any()
+ resolve_hir_path_(db, resolver, infer_body, path, false, hygiene, store, false).any()
}
#[inline]
@@ -1719,6 +1750,7 @@ pub(crate) fn resolve_hir_path_as_attr_macro(
fn resolve_hir_path_(
db: &dyn HirDatabase,
resolver: &Resolver<'_>,
+ infer_body: Option<InferBodyId>,
path: &Path,
prefer_value_ns: bool,
hygiene: HygieneId,
@@ -1728,9 +1760,17 @@ fn resolve_hir_path_(
let types = || {
let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => resolver.generic_def().and_then(|def| {
- let (_, res) =
- TyLoweringContext::new(db, resolver, store?, def, LifetimeElisionKind::Infer)
- .lower_ty_ext(type_ref);
+ let generics = OnceCell::new();
+ let (_, res) = TyLoweringContext::new(
+ db,
+ resolver,
+ store?,
+ def.into(),
+ def,
+ &generics,
+ LifetimeElisionKind::Infer,
+ )
+ .lower_ty_ext(type_ref);
res.map(|ty_ns| (ty_ns, path.segments().first()))
}),
None => {
@@ -1788,7 +1828,7 @@ fn resolve_hir_path_(
};
let body_owner = resolver.expression_store_owner();
- let values = || resolve_hir_value_path(db, resolver, body_owner, path, hygiene);
+ let values = || resolve_hir_value_path(db, resolver, body_owner, infer_body, path, hygiene);
let items = || {
resolver
@@ -1834,13 +1874,14 @@ fn resolve_hir_value_path(
db: &dyn HirDatabase,
resolver: &Resolver<'_>,
store_owner: Option<ExpressionStoreOwnerId>,
+ infer_body: Option<InferBodyId>,
path: &Path,
hygiene: HygieneId,
) -> Option<PathResolution> {
resolver.resolve_path_in_value_ns_fully(db, path, hygiene).and_then(|val| {
let res = match val {
ValueNs::LocalBinding(binding_id) => {
- let var = Local { parent: store_owner?, binding_id };
+ let var = Local { parent: store_owner?, parent_infer: infer_body?, binding_id };
PathResolution::Local(var)
}
ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
@@ -1877,9 +1918,17 @@ fn resolve_hir_path_qualifier(
(|| {
let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => resolver.generic_def().and_then(|def| {
- let (_, res) =
- TyLoweringContext::new(db, resolver, store, def, LifetimeElisionKind::Infer)
- .lower_ty_ext(type_ref);
+ let generics = OnceCell::new();
+ let (_, res) = TyLoweringContext::new(
+ db,
+ resolver,
+ store,
+ def.into(),
+ def,
+ &generics,
+ LifetimeElisionKind::Infer,
+ )
+ .lower_ty_ext(type_ref);
res.map(|ty_ns| (ty_ns, path.segments().first()))
}),
None => {