Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/path.rs')
-rw-r--r--crates/hir-ty/src/infer/path.rs230
1 files changed, 106 insertions, 124 deletions
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 733f3c2788..f70ed90b95 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -1,52 +1,50 @@
//! Path expression resolution.
-use chalk_ir::cast::Cast;
use hir_def::{
AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup,
expr_store::path::{Path, PathSegment},
resolver::{ResolveValueResult, TypeNs, ValueNs},
};
use hir_expand::name::Name;
+use rustc_type_ir::inherent::{SliceLike, Ty as _};
use stdx::never;
use crate::{
- InferenceDiagnostic, Interner, LifetimeElisionKind, Substitution, TraitRef, TraitRefExt, Ty,
- TyBuilder, TyExt, TyKind, ValueTyDefId,
- builder::ParamKind,
- consteval, error_lifetime,
+ InferenceDiagnostic, ValueTyDefId,
generics::generics,
infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
+ lower_nextsolver::LifetimeElisionKind,
method_resolution::{self, VisibleFromModule},
next_solver::{
- DbInterner,
- mapping::{ChalkToNextSolver, NextSolverToChalk},
+ GenericArg, GenericArgs, TraitRef, Ty,
+ infer::traits::{Obligation, ObligationCause},
},
- to_chalk_trait_id,
};
use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource};
-impl<'db> InferenceContext<'db> {
- pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> {
+impl<'db> InferenceContext<'_, 'db> {
+ pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty<'db>> {
let (value_def, generic_def, substs) = match self.resolve_value_path(path, id)? {
ValuePathResolution::GenericDef(value_def, generic_def, substs) => {
(value_def, generic_def, substs)
}
ValuePathResolution::NonGeneric(ty) => return Some(ty),
};
- let substs =
- self.process_remote_user_written_ty::<_, crate::next_solver::GenericArgs<'db>>(substs);
+ let args = self.process_remote_user_written_ty(substs);
- self.add_required_obligations_for_value_path(generic_def, &substs);
+ self.add_required_obligations_for_value_path(generic_def, args);
- let interner = DbInterner::new_with(self.db, None, None);
- let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
- let ty = self.db.value_ty(value_def)?.instantiate(interner, args).to_chalk(interner);
+ let ty = self.db.value_ty(value_def)?.instantiate(self.interner(), args);
let ty = self.process_remote_user_written_ty(ty);
Some(ty)
}
- fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
+ fn resolve_value_path(
+ &mut self,
+ path: &Path,
+ id: ExprOrPatId,
+ ) -> Option<ValuePathResolution<'db>> {
let (value, self_subst) = self.resolve_value_path_inner(path, id, false)?;
let value_def: ValueTyDefId = match value {
@@ -65,7 +63,7 @@ impl<'db> InferenceContext<'db> {
}
ValueNs::LocalBinding(pat) => {
return match self.result.type_of_binding.get(pat) {
- Some(ty) => Some(ValuePathResolution::NonGeneric(ty.clone())),
+ Some(ty) => Some(ValuePathResolution::NonGeneric(*ty)),
None => {
never!("uninferred pattern?");
None
@@ -73,17 +71,12 @@ impl<'db> InferenceContext<'db> {
};
}
ValueNs::ImplSelf(impl_id) => {
- let generics = crate::generics::generics(self.db, impl_id.into());
- let interner = DbInterner::new_with(self.db, None, None);
- let substs = generics.placeholder_subst(self.db);
- let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
- let ty =
- self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner);
+ let ty = self.db.impl_self_ty(impl_id).instantiate_identity();
return if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
Some(ValuePathResolution::GenericDef(
struct_id.into(),
struct_id.into(),
- substs.clone(),
+ substs,
))
} else {
// FIXME: report error, invalid Self reference
@@ -91,67 +84,42 @@ impl<'db> InferenceContext<'db> {
};
}
ValueNs::GenericParam(it) => {
- return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty(it)));
+ return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty_ns(it)));
}
};
let generic_def = value_def.to_generic_def_id(self.db);
if let GenericDefId::StaticId(_) = generic_def {
- let interner = DbInterner::new_with(self.db, None, None);
// `Static` is the kind of item that can never be generic currently. We can just skip the binders to get its type.
- let ty = self.db.value_ty(value_def)?.skip_binder().to_chalk(interner);
+ let ty = self.db.value_ty(value_def)?.skip_binder();
return Some(ValuePathResolution::NonGeneric(ty));
};
- let substs = self.with_body_ty_lowering(|ctx| {
- let mut path_ctx = ctx.at_path(path, id);
- let last_segment = path.segments().len().checked_sub(1);
- if let Some(last_segment) = last_segment {
- path_ctx.set_current_segment(last_segment)
- }
- path_ctx.substs_from_path(value_def, true, false)
- });
- let substs = substs.as_slice(Interner);
-
- if let ValueNs::EnumVariantId(_) = value {
- let mut it = substs
- .iter()
- .chain(self_subst.as_ref().map_or(&[][..], |s| s.as_slice(Interner)))
- .cloned();
- let builder = TyBuilder::subst_for_def(self.db, generic_def, None);
- let substs = builder
- .fill(|x| {
- it.next().unwrap_or_else(|| match x {
- ParamKind::Type => {
- self.result.standard_types.unknown.clone().cast(Interner)
- }
- ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
- ParamKind::Lifetime => error_lifetime().cast(Interner),
- })
- })
- .build();
-
- return Some(ValuePathResolution::GenericDef(value_def, generic_def, substs));
- }
-
- let parent_substs = self_subst.or_else(|| {
- let generics = generics(self.db, generic_def);
- let parent_params_len = generics.parent_generics()?.len();
- let parent_args = &substs[..parent_params_len];
- Some(Substitution::from_iter(Interner, parent_args))
- });
- let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
- let mut it = substs.iter().skip(parent_substs_len).cloned();
- let builder = TyBuilder::subst_for_def(self.db, generic_def, parent_substs);
- let substs = builder
- .fill(|x| {
- it.next().unwrap_or_else(|| match x {
- ParamKind::Type => self.result.standard_types.unknown.clone().cast(Interner),
- ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
- ParamKind::Lifetime => error_lifetime().cast(Interner),
- })
+ let substs = if self_subst.is_some_and(|it| !it.is_empty())
+ && matches!(value_def, ValueTyDefId::EnumVariantId(_))
+ {
+ // This is something like `TypeAlias::<Args>::EnumVariant`. Do not call `substs_from_path()`,
+ // as it'll try to re-lower the previous segment assuming it refers to the enum, but it refers
+ // to the type alias and they may have different generics.
+ self.types.empty_args
+ } else {
+ self.with_body_ty_lowering(|ctx| {
+ let mut path_ctx = ctx.at_path(path, id);
+ let last_segment = path.segments().len().checked_sub(1);
+ if let Some(last_segment) = last_segment {
+ path_ctx.set_current_segment(last_segment)
+ }
+ path_ctx.substs_from_path(value_def, true, false)
})
- .build();
+ };
+
+ let parent_substs_len = self_subst.map_or(0, |it| it.len());
+ let substs = GenericArgs::fill_rest(
+ self.interner(),
+ generic_def.into(),
+ self_subst.iter().flat_map(|it| it.iter()).chain(substs.iter().skip(parent_substs_len)),
+ |_, _, id, _| GenericArg::error_from_id(self.interner(), id),
+ );
Some(ValuePathResolution::GenericDef(value_def, generic_def, substs))
}
@@ -161,7 +129,7 @@ impl<'db> InferenceContext<'db> {
path: &Path,
id: ExprOrPatId,
no_diagnostics: bool,
- ) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
+ ) -> Option<(ValueNs, Option<GenericArgs<'db>>)> {
// Don't use `self.make_ty()` here as we need `orig_ns`.
let mut ctx = TyLoweringContext::new(
self.db,
@@ -211,7 +179,7 @@ impl<'db> InferenceContext<'db> {
let (resolution, substs) = match (def, is_before_last) {
(TypeNs::TraitId(trait_), true) => {
- let self_ty = self.table.new_type_var();
+ let self_ty = self.table.next_ty_var();
let trait_ref =
path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty, true);
drop_ctx(ctx, no_diagnostics);
@@ -225,7 +193,7 @@ impl<'db> InferenceContext<'db> {
path_ctx.ignore_last_segment();
let (ty, _) = path_ctx.lower_partly_resolved_path(def, true);
drop_ctx(ctx, no_diagnostics);
- if ty.is_unknown() {
+ if ty.is_ty_error() {
return None;
}
@@ -241,21 +209,25 @@ impl<'db> InferenceContext<'db> {
return Some((value, self_subst));
#[inline]
- fn drop_ctx(mut ctx: TyLoweringContext<'_>, no_diagnostics: bool) {
+ fn drop_ctx(mut ctx: TyLoweringContext<'_, '_>, no_diagnostics: bool) {
if no_diagnostics {
ctx.forget_diagnostics();
}
}
}
- fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) {
- let predicates = self.db.generic_predicates(def);
- for predicate in predicates.iter() {
- let (predicate, binders) =
- predicate.clone().substitute(Interner, &subst).into_value_and_skipped_binders();
- // Quantified where clauses are not yet handled.
- stdx::always!(binders.is_empty(Interner));
- self.push_obligation(predicate.cast(Interner));
+ fn add_required_obligations_for_value_path(
+ &mut self,
+ def: GenericDefId,
+ subst: GenericArgs<'db>,
+ ) {
+ let predicates = self.db.generic_predicates_ns(def);
+ let interner = self.interner();
+ let param_env = self.table.trait_env.env;
+ if let Some(predicates) = predicates.instantiate(self.interner(), subst) {
+ self.table.register_predicates(predicates.map(|predicate| {
+ Obligation::new(interner, ObligationCause::new(), param_env, predicate)
+ }));
}
// We need to add `Self: Trait` obligation when `def` is a trait assoc item.
@@ -267,21 +239,27 @@ impl<'db> InferenceContext<'db> {
if let ItemContainerId::TraitId(trait_) = container {
let parent_len = generics(self.db, def).parent_generics().map_or(0, |g| g.len_self());
- let parent_subst =
- Substitution::from_iter(Interner, subst.iter(Interner).take(parent_len));
- let trait_ref =
- TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: parent_subst };
- self.push_obligation(trait_ref.cast(Interner));
+ let parent_subst = GenericArgs::new_from_iter(
+ interner,
+ subst.as_slice()[..parent_len].iter().copied(),
+ );
+ let trait_ref = TraitRef::new(interner, trait_.into(), parent_subst);
+ self.table.register_predicate(Obligation::new(
+ interner,
+ ObligationCause::new(),
+ param_env,
+ trait_ref,
+ ));
}
}
fn resolve_trait_assoc_item(
&mut self,
- trait_ref: TraitRef,
+ trait_ref: TraitRef<'db>,
segment: PathSegment<'_>,
id: ExprOrPatId,
- ) -> Option<(ValueNs, Substitution)> {
- let trait_ = trait_ref.hir_trait_id();
+ ) -> Option<(ValueNs, GenericArgs<'db>)> {
+ let trait_ = trait_ref.def_id.0;
let item =
trait_.trait_items(self.db).items.iter().map(|(_name, id)| *id).find_map(|item| {
match item {
@@ -309,25 +287,25 @@ impl<'db> InferenceContext<'db> {
AssocItemId::TypeAliasId(_) => unreachable!(),
};
- self.write_assoc_resolution(id, item, trait_ref.substitution.clone());
- Some((def, trait_ref.substitution))
+ self.write_assoc_resolution(id, item, trait_ref.args);
+ Some((def, trait_ref.args))
}
fn resolve_ty_assoc_item(
&mut self,
- ty: Ty,
+ ty: Ty<'db>,
name: &Name,
id: ExprOrPatId,
- ) -> Option<(ValueNs, Substitution)> {
- if let TyKind::Error = ty.kind(Interner) {
+ ) -> Option<(ValueNs, GenericArgs<'db>)> {
+ if ty.is_ty_error() {
return None;
}
- if let Some(result) = self.resolve_enum_variant_on_ty(&ty, name, id) {
+ if let Some(result) = self.resolve_enum_variant_on_ty(ty, name, id) {
return Some(result);
}
- let canonical_ty = self.canonicalize(ty.clone().to_nextsolver(self.table.interner));
+ let canonical_ty = self.canonicalize(ty);
let mut not_visible = None;
let res = method_resolution::iterate_method_candidates(
@@ -362,24 +340,28 @@ impl<'db> InferenceContext<'db> {
};
let substs = match container {
ItemContainerId::ImplId(impl_id) => {
- let interner = DbInterner::new_with(self.db, None, None);
- let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
- .fill_with_inference_vars(&mut self.table)
- .build();
- let args: crate::next_solver::GenericArgs<'_> = impl_substs.to_nextsolver(interner);
+ let impl_substs = self.table.fresh_args_for_item(impl_id.into());
let impl_self_ty =
- self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner);
- self.unify(&impl_self_ty, &ty);
+ self.db.impl_self_ty(impl_id).instantiate(self.interner(), impl_substs);
+ self.unify(impl_self_ty, ty);
impl_substs
}
ItemContainerId::TraitId(trait_) => {
// we're picking this method
- let trait_ref = TyBuilder::trait_ref(self.db, trait_)
- .push(ty.clone())
- .fill_with_inference_vars(&mut self.table)
- .build();
- self.push_obligation(trait_ref.clone().cast(Interner));
- trait_ref.substitution
+ let args = GenericArgs::fill_rest(
+ self.interner(),
+ trait_.into(),
+ [ty.into()],
+ |_, _, id, _| self.table.next_var_for_param(id),
+ );
+ let trait_ref = TraitRef::new(self.interner(), trait_.into(), args);
+ self.table.register_predicate(Obligation::new(
+ self.interner(),
+ ObligationCause::new(),
+ self.table.trait_env.env,
+ trait_ref,
+ ));
+ args
}
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
never!("assoc item contained in module/extern block");
@@ -387,7 +369,7 @@ impl<'db> InferenceContext<'db> {
}
};
- self.write_assoc_resolution(id, item, substs.clone());
+ self.write_assoc_resolution(id, item, substs);
if !visible {
self.push_diagnostic(InferenceDiagnostic::PrivateAssocItem { id, item });
}
@@ -396,11 +378,11 @@ impl<'db> InferenceContext<'db> {
fn resolve_enum_variant_on_ty(
&mut self,
- ty: &Ty,
+ ty: Ty<'db>,
name: &Name,
id: ExprOrPatId,
- ) -> Option<(ValueNs, Substitution)> {
- let ty = self.table.structurally_resolve_type(ty);
+ ) -> Option<(ValueNs, GenericArgs<'db>)> {
+ let ty = self.table.try_structurally_resolve_type(ty);
let (enum_id, subst) = match ty.as_adt() {
Some((AdtId::EnumId(e), subst)) => (e, subst),
_ => return None,
@@ -408,14 +390,14 @@ impl<'db> InferenceContext<'db> {
let enum_data = enum_id.enum_variants(self.db);
let variant = enum_data.variant(name)?;
self.write_variant_resolution(id, variant.into());
- Some((ValueNs::EnumVariantId(variant), subst.clone()))
+ Some((ValueNs::EnumVariantId(variant), subst))
}
}
#[derive(Debug)]
-enum ValuePathResolution {
+enum ValuePathResolution<'db> {
// It's awkward to wrap a single ID in two enums, but we need both and this saves fallible
// conversion between them + `unwrap()`.
- GenericDef(ValueTyDefId, GenericDefId, Substitution),
- NonGeneric(Ty),
+ GenericDef(ValueTyDefId, GenericDefId, GenericArgs<'db>),
+ NonGeneric(Ty<'db>),
}