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.rs | 168 |
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, |