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.rs168
1 files changed, 71 insertions, 97 deletions
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 36ec60a7a2..6254bc1239 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -7,7 +7,6 @@ use hir_def::{
AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup,
};
use hir_expand::name::Name;
-use intern::sym;
use stdx::never;
use crate::{
@@ -41,7 +40,7 @@ impl InferenceContext<'_> {
}
fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
- let (value, self_subst) = self.resolve_value_path_inner(path, id)?;
+ let (value, self_subst) = self.resolve_value_path_inner(path, id, false)?;
let value_def: ValueTyDefId = match value {
ValueNs::FunctionId(it) => it.into(),
@@ -94,7 +93,14 @@ impl InferenceContext<'_> {
return Some(ValuePathResolution::NonGeneric(ty));
};
- let substs = self.with_body_ty_lowering(|ctx| ctx.substs_from_path(path, value_def, true));
+ 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)
+ });
let substs = substs.as_slice(Interner);
if let ValueNs::EnumVariantId(_) = value {
@@ -146,6 +152,7 @@ impl InferenceContext<'_> {
&mut self,
path: &Path,
id: ExprOrPatId,
+ no_diagnostics: bool,
) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
// Don't use `self.make_ty()` here as we need `orig_ns`.
let mut ctx = TyLoweringContext::new(
@@ -156,33 +163,83 @@ impl InferenceContext<'_> {
&self.diagnostics,
InferenceTyDiagnosticSource::Body,
);
+ let mut path_ctx = if no_diagnostics {
+ ctx.at_path_forget_diagnostics(path)
+ } else {
+ ctx.at_path(path, id)
+ };
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
let last = path.segments().last()?;
- let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
+ let (ty, orig_ns) = path_ctx.ty_ctx().lower_ty_ext(type_ref);
let ty = self.table.insert_type_vars(ty);
let ty = self.table.normalize_associated_types_in(ty);
- let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
- let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
- drop(ctx);
+ path_ctx.ignore_last_segment();
+ let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns);
+ drop_ctx(ctx, no_diagnostics);
let ty = self.table.insert_type_vars(ty);
let ty = self.table.normalize_associated_types_in(ty);
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
} else {
let hygiene = self.body.expr_or_pat_path_hygiene(id);
// FIXME: report error, unresolved first path segment
- let value_or_partial = ctx.resolve_path_in_value_ns(path, id, hygiene)?;
- drop(ctx);
+ let value_or_partial = path_ctx.resolve_path_in_value_ns(hygiene)?;
match value_or_partial {
- ResolveValueResult::ValueNs(it, _) => (it, None),
- ResolveValueResult::Partial(def, remaining_index, _) => self
- .resolve_assoc_item(id, def, path, remaining_index, id)
- .map(|(it, substs)| (it, Some(substs)))?,
+ ResolveValueResult::ValueNs(it, _) => {
+ drop_ctx(ctx, no_diagnostics);
+ (it, None)
+ }
+ ResolveValueResult::Partial(def, remaining_index, _) => {
+ // there may be more intermediate segments between the resolved one and
+ // the end. Only the last segment needs to be resolved to a value; from
+ // the segments before that, we need to get either a type or a trait ref.
+
+ let remaining_segments = path.segments().skip(remaining_index);
+ let is_before_last = remaining_segments.len() == 1;
+ let last_segment = remaining_segments
+ .last()
+ .expect("there should be at least one segment here");
+
+ let (resolution, substs) = match (def, is_before_last) {
+ (TypeNs::TraitId(trait_), true) => {
+ let self_ty = self.table.new_type_var();
+ let trait_ref =
+ path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty);
+ drop_ctx(ctx, no_diagnostics);
+ self.resolve_trait_assoc_item(trait_ref, last_segment, id)
+ }
+ (def, _) => {
+ // Either we already have a type (e.g. `Vec::new`), or we have a
+ // trait but it's not the last segment, so the next segment
+ // should resolve to an associated type of that trait (e.g. `<T
+ // as Iterator>::Item::default`)
+ path_ctx.ignore_last_segment();
+ let (ty, _) = path_ctx.lower_partly_resolved_path(def, true);
+ drop_ctx(ctx, no_diagnostics);
+ if ty.is_unknown() {
+ return None;
+ }
+
+ let ty = self.insert_type_vars(ty);
+ let ty = self.normalize_associated_types_in(ty);
+
+ self.resolve_ty_assoc_item(ty, last_segment.name, id)
+ }
+ }?;
+ (resolution, Some(substs))
+ }
}
};
- Some((value, self_subst))
+ return Some((value, self_subst));
+
+ #[inline]
+ 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) {
@@ -212,89 +269,6 @@ impl InferenceContext<'_> {
}
}
- fn resolve_assoc_item(
- &mut self,
- node: ExprOrPatId,
- def: TypeNs,
- path: &Path,
- remaining_index: usize,
- id: ExprOrPatId,
- ) -> Option<(ValueNs, Substitution)> {
- // there may be more intermediate segments between the resolved one and
- // the end. Only the last segment needs to be resolved to a value; from
- // the segments before that, we need to get either a type or a trait ref.
-
- let _d;
- let (resolved_segment, remaining_segments) = match path {
- Path::Normal { .. } | Path::BarePath(_) => {
- assert!(remaining_index < path.segments().len());
- (
- path.segments().get(remaining_index - 1).unwrap(),
- path.segments().skip(remaining_index),
- )
- }
- Path::LangItem(..) => (
- PathSegment {
- name: {
- _d = Name::new_symbol_root(sym::Unknown.clone());
- &_d
- },
- args_and_bindings: None,
- },
- path.segments(),
- ),
- };
- let is_before_last = remaining_segments.len() == 1;
-
- match (def, is_before_last) {
- (TypeNs::TraitId(trait_), true) => {
- let segment =
- remaining_segments.last().expect("there should be at least one segment here");
- let self_ty = self.table.new_type_var();
- let trait_ref = self.with_body_ty_lowering(|ctx| {
- ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty)
- });
- self.resolve_trait_assoc_item(trait_ref, segment, id)
- }
- (def, _) => {
- // Either we already have a type (e.g. `Vec::new`), or we have a
- // trait but it's not the last segment, so the next segment
- // should resolve to an associated type of that trait (e.g. `<T
- // as Iterator>::Item::default`)
- let remaining_segments_for_ty =
- remaining_segments.take(remaining_segments.len() - 1);
- let mut ctx = TyLoweringContext::new(
- self.db,
- &self.resolver,
- &self.body.types,
- self.owner.into(),
- &self.diagnostics,
- InferenceTyDiagnosticSource::Body,
- );
- let (ty, _) = ctx.lower_partly_resolved_path(
- node,
- def,
- resolved_segment,
- remaining_segments_for_ty,
- (remaining_index - 1) as u32,
- true,
- );
- drop(ctx);
- if ty.is_unknown() {
- return None;
- }
-
- let ty = self.insert_type_vars(ty);
- let ty = self.normalize_associated_types_in(ty);
-
- let segment =
- remaining_segments.last().expect("there should be at least one segment here");
-
- self.resolve_ty_assoc_item(ty, segment.name, id)
- }
- }
- }
-
fn resolve_trait_assoc_item(
&mut self,
trait_ref: TraitRef,