Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower.rs')
-rw-r--r--crates/hir-ty/src/lower.rs983
1 files changed, 63 insertions, 920 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index db13e1fd35..af73b5ed9a 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -6,6 +6,7 @@
//!
//! This usually involves resolving names, collecting generic arguments etc.
pub(crate) mod diagnostics;
+pub(crate) mod path;
use std::{
cell::OnceCell,
@@ -26,29 +27,26 @@ use hir_def::{
builtin_type::BuiltinType,
data::{adt::StructKind, TraitFlags},
expander::Expander,
- expr_store::HygieneId,
generics::{
GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
WherePredicateTypeTarget,
},
lang_item::LangItem,
nameres::MacroSubNs,
- path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
- resolver::{HasResolver, LifetimeNs, ResolveValueResult, Resolver, TypeNs, ValueNs},
+ path::{GenericArg, ModPath, Path, PathKind},
+ resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
type_ref::{
ConstRef, LifetimeRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound,
TypeRef, TypeRefId, TypesMap, TypesSourceMap,
},
AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
- FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId,
- LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId,
- TypeOwnerId, UnionId, VariantId,
+ FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, LocalFieldId,
+ Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, UnionId, VariantId,
};
use hir_expand::{name::Name, ExpandResult};
use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashSet;
use rustc_pattern_analysis::Captures;
-use smallvec::SmallVec;
use stdx::{impl_from, never};
use syntax::ast;
use triomphe::{Arc, ThinArc};
@@ -62,18 +60,19 @@ use crate::{
db::HirDatabase,
error_lifetime,
generics::{generics, trait_self_param_idx, Generics},
- lower::diagnostics::*,
+ lower::{
+ diagnostics::*,
+ path::{PathDiagnosticCallback, PathLoweringContext},
+ },
make_binders,
mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk},
- static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
- utils::{
- all_super_trait_refs, associated_type_by_name_including_super_traits, InTypeConstIdMetadata,
- },
- AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy,
- FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
- LifetimeData, LifetimeOutlives, ParamKind, PolyFnSig, ProgramClause, ProjectionTy,
- QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef,
- TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
+ static_lifetime, to_chalk_trait_id, to_placeholder_idx,
+ utils::{all_super_trait_refs, InTypeConstIdMetadata},
+ AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy, FnAbi,
+ FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
+ LifetimeData, LifetimeOutlives, ParamKind, PolyFnSig, ProgramClause, QuantifiedWhereClause,
+ QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder,
+ TyKind, WhereClause,
};
#[derive(Debug, Default)]
@@ -106,6 +105,8 @@ impl ImplTraitLoweringState {
}
}
+pub(crate) struct PathDiagnosticCallbackData(TypeRefId);
+
#[derive(Debug)]
pub struct TyLoweringContext<'a> {
pub db: &'a dyn HirDatabase,
@@ -527,9 +528,8 @@ impl<'a> TyLoweringContext<'a> {
if path.segments().len() > 1 {
return None;
}
- let resolution = match self
- .resolve_path_in_type_ns(path, &mut Self::on_path_diagnostic_callback(type_ref_id))
- {
+ let mut ctx = self.at_path(PathId::from_type_ref_unchecked(type_ref_id));
+ let resolution = match ctx.resolve_path_in_type_ns() {
Some((it, None)) => it,
_ => return None,
};
@@ -539,409 +539,36 @@ impl<'a> TyLoweringContext<'a> {
}
}
- pub(crate) fn lower_ty_relative_path(
- &mut self,
- ty: Ty,
- // We need the original resolution to lower `Self::AssocTy` correctly
- res: Option<TypeNs>,
- remaining_segments: PathSegments<'_>,
- ) -> (Ty, Option<TypeNs>) {
- match remaining_segments.len() {
- 0 => (ty, res),
- 1 => {
- // resolve unselected assoc types
- let segment = remaining_segments.first().unwrap();
- (self.select_associated_type(res, segment), None)
- }
- _ => {
- // FIXME report error (ambiguous associated type)
- (TyKind::Error.intern(Interner), None)
- }
- }
- }
-
- pub(crate) fn lower_partly_resolved_path(
- &mut self,
- resolution: TypeNs,
- resolved_segment: PathSegment<'_>,
- remaining_segments: PathSegments<'_>,
- _resolved_segment_idx: u32,
- infer_args: bool,
- _on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
- ) -> (Ty, Option<TypeNs>) {
- let ty = match resolution {
- TypeNs::TraitId(trait_) => {
- let ty = match remaining_segments.len() {
- 1 => {
- let trait_ref = self.lower_trait_ref_from_resolved_path(
- trait_,
- resolved_segment,
- TyKind::Error.intern(Interner),
- );
- let segment = remaining_segments.first().unwrap();
- let found = self
- .db
- .trait_data(trait_ref.hir_trait_id())
- .associated_type_by_name(segment.name);
-
- match found {
- Some(associated_ty) => {
- // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
- // generic params. It's inefficient to splice the `Substitution`s, so we may want
- // that method to optionally take parent `Substitution` as we already know them at
- // this point (`trait_ref.substitution`).
- let substitution = self.substs_from_path_segment(
- segment,
- Some(associated_ty.into()),
- false,
- None,
- );
- let len_self =
- generics(self.db.upcast(), associated_ty.into()).len_self();
- let substitution = Substitution::from_iter(
- Interner,
- substitution
- .iter(Interner)
- .take(len_self)
- .chain(trait_ref.substitution.iter(Interner)),
- );
- TyKind::Alias(AliasTy::Projection(ProjectionTy {
- associated_ty_id: to_assoc_type_id(associated_ty),
- substitution,
- }))
- .intern(Interner)
- }
- None => {
- // FIXME: report error (associated type not found)
- TyKind::Error.intern(Interner)
- }
- }
- }
- 0 => {
- // Trait object type without dyn; this should be handled in upstream. See
- // `lower_path()`.
- stdx::never!("unexpected fully resolved trait path");
- TyKind::Error.intern(Interner)
- }
- _ => {
- // FIXME report error (ambiguous associated type)
- TyKind::Error.intern(Interner)
- }
- };
- return (ty, None);
- }
- TypeNs::TraitAliasId(_) => {
- // FIXME(trait_alias): Implement trait alias.
- return (TyKind::Error.intern(Interner), None);
- }
- TypeNs::GenericParam(param_id) => match self.type_param_mode {
- ParamLoweringMode::Placeholder => {
- TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
- }
- ParamLoweringMode::Variable => {
- let idx = match self
- .generics()
- .expect("generics in scope")
- .type_or_const_param_idx(param_id.into())
- {
- None => {
- never!("no matching generics");
- return (TyKind::Error.intern(Interner), None);
- }
- Some(idx) => idx,
- };
-
- TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
- }
- }
- .intern(Interner),
- TypeNs::SelfType(impl_id) => {
- let generics = self.generics().expect("impl should have generic param scope");
-
- match self.type_param_mode {
- ParamLoweringMode::Placeholder => {
- // `def` can be either impl itself or item within, and we need impl itself
- // now.
- let generics = generics.parent_or_self();
- let subst = generics.placeholder_subst(self.db);
- self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
- }
- ParamLoweringMode::Variable => {
- let starting_from = match generics.def() {
- GenericDefId::ImplId(_) => 0,
- // `def` is an item within impl. We need to substitute `BoundVar`s but
- // remember that they are for parent (i.e. impl) generic params so they
- // come after our own params.
- _ => generics.len_self(),
- };
- TyBuilder::impl_self_ty(self.db, impl_id)
- .fill_with_bound_vars(self.in_binders, starting_from)
- .build()
- }
- }
- }
- TypeNs::AdtSelfType(adt) => {
- let generics = generics(self.db.upcast(), adt.into());
- let substs = match self.type_param_mode {
- ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
- ParamLoweringMode::Variable => {
- generics.bound_vars_subst(self.db, self.in_binders)
- }
- };
- self.db.ty(adt.into()).substitute(Interner, &substs)
- }
-
- TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args),
- TypeNs::BuiltinType(it) => {
- self.lower_path_inner(resolved_segment, it.into(), infer_args)
- }
- TypeNs::TypeAliasId(it) => {
- self.lower_path_inner(resolved_segment, it.into(), infer_args)
- }
- // FIXME: report error
- TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(Interner), None),
- };
- self.lower_ty_relative_path(ty, Some(resolution), remaining_segments)
- }
-
- fn handle_type_ns_resolution(
- &mut self,
- resolution: &TypeNs,
- resolved_segment: PathSegment<'_>,
- resolved_segment_idx: usize,
- on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
- ) {
- let mut prohibit_generics_on_resolved = |reason| {
- if resolved_segment.args_and_bindings.is_some() {
- on_diagnostic(
- self,
- PathLoweringDiagnostic::GenericArgsProhibited {
- segment: resolved_segment_idx as u32,
- reason,
- },
- );
- }
- };
-
- match resolution {
- TypeNs::SelfType(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
- }
- TypeNs::GenericParam(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
- }
- TypeNs::AdtSelfType(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
- }
- TypeNs::BuiltinType(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
- }
- TypeNs::AdtId(_)
- | TypeNs::EnumVariantId(_)
- | TypeNs::TypeAliasId(_)
- | TypeNs::TraitId(_)
- | TypeNs::TraitAliasId(_) => {}
- }
- }
-
- pub(crate) fn resolve_path_in_type_ns_fully(
- &mut self,
- path: &Path,
- on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
- ) -> Option<TypeNs> {
- let (res, unresolved) = self.resolve_path_in_type_ns(path, on_diagnostic)?;
- if unresolved.is_some() {
- return None;
- }
- Some(res)
- }
-
- pub(crate) fn resolve_path_in_type_ns(
- &mut self,
- path: &Path,
- on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
- ) -> Option<(TypeNs, Option<usize>)> {
- let (resolution, remaining_index, _, prefix_info) =
- self.resolver.resolve_path_in_type_ns_with_prefix_info(self.db.upcast(), path)?;
- let segments = path.segments();
-
- match path {
- // `segments.is_empty()` can occur with `self`.
- Path::Normal(..) if !segments.is_empty() => (),
- _ => return Some((resolution, remaining_index)),
- };
-
- let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index {
- None if prefix_info.enum_variant => {
- (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2))
- }
- None => (segments.strip_last(), segments.len() - 1, None),
- Some(i) => (segments.take(i - 1), i - 1, None),
- };
-
- for (i, mod_segment) in module_segments.iter().enumerate() {
- if mod_segment.args_and_bindings.is_some() {
- on_diagnostic(
- self,
- PathLoweringDiagnostic::GenericArgsProhibited {
- segment: i as u32,
- reason: GenericArgsProhibitedReason::Module,
- },
- );
- }
- }
-
- if let Some(enum_segment) = enum_segment {
- if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
- && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
- {
- on_diagnostic(
- self,
- PathLoweringDiagnostic::GenericArgsProhibited {
- segment: (enum_segment + 1) as u32,
- reason: GenericArgsProhibitedReason::EnumVariant,
- },
- );
- }
- }
-
- self.handle_type_ns_resolution(
- &resolution,
- segments.get(resolved_segment_idx).expect("should have resolved segment"),
- resolved_segment_idx,
- on_diagnostic,
- );
-
- Some((resolution, remaining_index))
- }
-
- pub(crate) fn resolve_path_in_value_ns(
- &mut self,
- path: &Path,
- hygiene_id: HygieneId,
- on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
- ) -> Option<ResolveValueResult> {
- let (res, prefix_info) = self.resolver.resolve_path_in_value_ns_with_prefix_info(
- self.db.upcast(),
- path,
- hygiene_id,
- )?;
-
- let segments = path.segments();
- match path {
- // `segments.is_empty()` can occur with `self`.
- Path::Normal(..) if !segments.is_empty() => (),
- _ => return Some(res),
- };
-
- let (mod_segments, enum_segment) = match res {
- ResolveValueResult::Partial(_, unresolved_segment, _) => {
- (segments.take(unresolved_segment - 1), None)
- }
- ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
- if prefix_info.enum_variant =>
- {
- (segments.strip_last_two(), segments.len().checked_sub(2))
- }
- ResolveValueResult::ValueNs(..) => (segments.strip_last(), None),
- };
- for (i, mod_segment) in mod_segments.iter().enumerate() {
- if mod_segment.args_and_bindings.is_some() {
- on_diagnostic(
- self,
- PathLoweringDiagnostic::GenericArgsProhibited {
- segment: i as u32,
- reason: GenericArgsProhibitedReason::Module,
- },
- );
- }
- }
-
- if let Some(enum_segment) = enum_segment {
- if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
- && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
- {
- on_diagnostic(
- self,
- PathLoweringDiagnostic::GenericArgsProhibited {
- segment: (enum_segment + 1) as u32,
- reason: GenericArgsProhibitedReason::EnumVariant,
- },
- );
- }
+ #[inline]
+ fn on_path_diagnostic_callback(type_ref: TypeRefId) -> PathDiagnosticCallback<'static> {
+ PathDiagnosticCallback {
+ data: Either::Left(PathDiagnosticCallbackData(type_ref)),
+ callback: |data, this, diag| {
+ let type_ref = data.as_ref().left().unwrap().0;
+ this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag))
+ },
}
-
- match &res {
- ResolveValueResult::ValueNs(resolution, _) => {
- let resolved_segment_idx =
- segments.len().checked_sub(1).unwrap_or_else(|| panic!("{path:?}"));
- let resolved_segment = segments.last().unwrap();
-
- let mut prohibit_generics_on_resolved = |reason| {
- if resolved_segment.args_and_bindings.is_some() {
- on_diagnostic(
- self,
- PathLoweringDiagnostic::GenericArgsProhibited {
- segment: resolved_segment_idx as u32,
- reason,
- },
- );
- }
- };
-
- match resolution {
- ValueNs::ImplSelf(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
- }
- // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not
- // E0109 (generic arguments provided for a type that doesn't accept them) for
- // consts and statics, presumably as a defense against future in which consts
- // and statics can be generic, or just because it was easier for rustc implementors.
- // That means we'll show the wrong error code. Because of us it's easier to do it
- // this way :)
- ValueNs::GenericParam(_) | ValueNs::ConstId(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
- }
- ValueNs::StaticId(_) => {
- prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
- }
- ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::EnumVariantId(_) => {}
- ValueNs::LocalBinding(_) => {}
- }
- }
- ResolveValueResult::Partial(resolution, unresolved_idx, _) => {
- let resolved_segment_idx = unresolved_idx - 1;
- let resolved_segment = segments.get(resolved_segment_idx).unwrap();
- self.handle_type_ns_resolution(
- resolution,
- resolved_segment,
- resolved_segment_idx,
- on_diagnostic,
- );
- }
- };
- Some(res)
}
- fn on_path_diagnostic_callback(
- type_ref: TypeRefId,
- ) -> impl FnMut(&mut Self, PathLoweringDiagnostic) {
- move |this, diag| {
- this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag))
- }
+ #[inline]
+ fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a> {
+ PathLoweringContext::new(
+ self,
+ Self::on_path_diagnostic_callback(path_id.type_ref()),
+ &self.types_map[path_id],
+ )
}
pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option<TypeNs>) {
// Resolve the path (in type namespace)
if let Some(type_ref) = path.type_anchor() {
let (ty, res) = self.lower_ty_ext(type_ref);
- return self.lower_ty_relative_path(ty, res, path.segments());
+ let mut ctx = self.at_path(path_id);
+ return ctx.lower_ty_relative_path(ty, res);
}
- let (resolution, remaining_index) = match self.resolve_path_in_type_ns(
- path,
- &mut Self::on_path_diagnostic_callback(path_id.type_ref()),
- ) {
+ let mut ctx = self.at_path(path_id);
+ let (resolution, remaining_index) = match ctx.resolve_path_in_type_ns() {
Some(it) => it,
None => return (TyKind::Error.intern(Interner), None),
};
@@ -953,354 +580,21 @@ impl<'a> TyLoweringContext<'a> {
return (ty, None);
}
- let (resolved_segment_idx, resolved_segment, remaining_segments) = match remaining_index {
- None => (
- path.segments().len() - 1,
- path.segments().last().expect("resolved path has at least one element"),
- PathSegments::EMPTY,
- ),
- Some(i) => (i - 1, path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
- };
-
- self.lower_partly_resolved_path(
- resolution,
- resolved_segment,
- remaining_segments,
- resolved_segment_idx as u32,
- false,
- &mut Self::on_path_diagnostic_callback(path_id.type_ref()),
- )
- }
-
- fn select_associated_type(&mut self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
- let Some((generics, res)) = self.generics().zip(res) else {
- return TyKind::Error.intern(Interner);
- };
- let ty = named_associated_type_shorthand_candidates(
- self.db,
- generics.def(),
- res,
- Some(segment.name.clone()),
- move |name, t, associated_ty| {
- let generics = self.generics().unwrap();
-
- if name != segment.name {
- return None;
- }
-
- let parent_subst = t.substitution.clone();
- let parent_subst = match self.type_param_mode {
- ParamLoweringMode::Placeholder => {
- // if we're lowering to placeholders, we have to put them in now.
- let s = generics.placeholder_subst(self.db);
- s.apply(parent_subst, Interner)
- }
- ParamLoweringMode::Variable => {
- // We need to shift in the bound vars, since
- // `named_associated_type_shorthand_candidates` does not do that.
- parent_subst.shifted_in_from(Interner, self.in_binders)
- }
- };
-
- // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
- // generic params. It's inefficient to splice the `Substitution`s, so we may want
- // that method to optionally take parent `Substitution` as we already know them at
- // this point (`t.substitution`).
- let substs =
- self.substs_from_path_segment(segment, Some(associated_ty.into()), false, None);
-
- let len_self =
- crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self();
-
- let substs = Substitution::from_iter(
- Interner,
- substs.iter(Interner).take(len_self).chain(parent_subst.iter(Interner)),
- );
-
- Some(
- TyKind::Alias(AliasTy::Projection(ProjectionTy {
- associated_ty_id: to_assoc_type_id(associated_ty),
- substitution: substs,
- }))
- .intern(Interner),
- )
- },
- );
-
- ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
- }
-
- fn lower_path_inner(
- &mut self,
- segment: PathSegment<'_>,
- typeable: TyDefId,
- infer_args: bool,
- ) -> Ty {
- let generic_def = match typeable {
- TyDefId::BuiltinType(_) => None,
- TyDefId::AdtId(it) => Some(it.into()),
- TyDefId::TypeAliasId(it) => Some(it.into()),
- };
- let substs = self.substs_from_path_segment(segment, generic_def, infer_args, None);
- self.db.ty(typeable).substitute(Interner, &substs)
- }
-
- /// Collect generic arguments from a path into a `Substs`. See also
- /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
- pub(super) fn substs_from_path(
- &mut self,
- path: &Path,
- // Note that we don't call `db.value_type(resolved)` here,
- // `ValueTyDefId` is just a convenient way to pass generics and
- // special-case enum variants
- resolved: ValueTyDefId,
- infer_args: bool,
- ) -> Substitution {
- let last = path.segments().last();
- let (segment, generic_def) = match resolved {
- ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
- ValueTyDefId::StructId(it) => (last, Some(it.into())),
- ValueTyDefId::UnionId(it) => (last, Some(it.into())),
- ValueTyDefId::ConstId(it) => (last, Some(it.into())),
- ValueTyDefId::StaticId(_) => (last, None),
- ValueTyDefId::EnumVariantId(var) => {
- // the generic args for an enum variant may be either specified
- // on the segment referring to the enum, or on the segment
- // referring to the variant. So `Option::<T>::None` and
- // `Option::None::<T>` are both allowed (though the former is
- // preferred). See also `def_ids_for_path_segments` in rustc.
- let len = path.segments().len();
- let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
- let segment = match penultimate {
- Some(segment) if segment.args_and_bindings.is_some() => Some(segment),
- _ => last,
- };
- (segment, Some(var.lookup(self.db.upcast()).parent.into()))
- }
- };
- if let Some(segment) = segment {
- self.substs_from_path_segment(segment, generic_def, infer_args, None)
- } else if let Some(generic_def) = generic_def {
- // lang item
- self.substs_from_args_and_bindings(None, Some(generic_def), infer_args, None)
- } else {
- Substitution::empty(Interner)
- }
- }
-
- pub(super) fn substs_from_path_segment(
- &mut self,
- segment: PathSegment<'_>,
- def: Option<GenericDefId>,
- infer_args: bool,
- explicit_self_ty: Option<Ty>,
- ) -> Substitution {
- self.substs_from_args_and_bindings(
- segment.args_and_bindings,
- def,
- infer_args,
- explicit_self_ty,
- )
- }
-
- fn substs_from_args_and_bindings(
- &mut self,
- args_and_bindings: Option<&GenericArgs>,
- def: Option<GenericDefId>,
- infer_args: bool,
- explicit_self_ty: Option<Ty>,
- ) -> Substitution {
- let Some(def) = def else { return Substitution::empty(Interner) };
-
- // Order is
- // - Optional Self parameter
- // - Lifetime parameters
- // - Type or Const parameters
- // - Parent parameters
- let def_generics = generics(self.db.upcast(), def);
- let (
- parent_params,
- self_param,
- type_params,
- const_params,
- impl_trait_params,
- lifetime_params,
- ) = def_generics.provenance_split();
- let item_len =
- self_param as usize + type_params + const_params + impl_trait_params + lifetime_params;
- let total_len = parent_params + item_len;
-
- let mut substs = Vec::new();
-
- // we need to iterate the lifetime and type/const params separately as our order of them
- // differs from the supplied syntax
-
- let ty_error = || TyKind::Error.intern(Interner).cast(Interner);
- let mut def_toc_iter = def_generics.iter_self_type_or_consts_id();
- let fill_self_param = || {
- if self_param {
- let self_ty = explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(ty_error);
-
- if let Some(id) = def_toc_iter.next() {
- assert!(matches!(id, GenericParamId::TypeParamId(_)));
- substs.push(self_ty);
- }
- }
- };
- let mut had_explicit_args = false;
-
- if let Some(&GenericArgs { ref args, has_self_type, .. }) = args_and_bindings {
- // Fill in the self param first
- if has_self_type && self_param {
- had_explicit_args = true;
- if let Some(id) = def_toc_iter.next() {
- assert!(matches!(id, GenericParamId::TypeParamId(_)));
- had_explicit_args = true;
- if let GenericArg::Type(ty) = &args[0] {
- substs.push(self.lower_ty(*ty).cast(Interner));
- }
- }
- } else {
- fill_self_param()
- };
-
- // Then fill in the supplied lifetime args, or error lifetimes if there are too few
- // (default lifetimes aren't a thing)
- for arg in args
- .iter()
- .filter_map(|arg| match arg {
- GenericArg::Lifetime(arg) => Some(self.lower_lifetime(arg)),
- _ => None,
- })
- .chain(iter::repeat(error_lifetime()))
- .take(lifetime_params)
- {
- substs.push(arg.cast(Interner));
- }
-
- let skip = if has_self_type { 1 } else { 0 };
- // Fill in supplied type and const args
- // Note if non-lifetime args are provided, it should be all of them, but we can't rely on that
- for (arg, id) in args
- .iter()
- .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
- .skip(skip)
- .take(type_params + const_params)
- .zip(def_toc_iter)
- {
- had_explicit_args = true;
- let arg = generic_arg_to_chalk(
- self.db,
- id,
- arg,
- self,
- self.types_map,
- |this, type_ref| this.lower_ty(type_ref),
- |this, const_ref, ty| this.lower_const(const_ref, ty),
- |this, lifetime_ref| this.lower_lifetime(lifetime_ref),
- );
- substs.push(arg);
- }
- } else {
- fill_self_param();
- }
-
- let param_to_err = |id| match id {
- GenericParamId::ConstParamId(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
- GenericParamId::TypeParamId(_) => ty_error(),
- GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
- };
- // handle defaults. In expression or pattern path segments without
- // explicitly specified type arguments, missing type arguments are inferred
- // (i.e. defaults aren't used).
- // Generic parameters for associated types are not supposed to have defaults, so we just
- // ignore them.
- let is_assoc_ty = || match def {
- GenericDefId::TypeAliasId(id) => {
- matches!(id.lookup(self.db.upcast()).container, ItemContainerId::TraitId(_))
- }
- _ => false,
- };
- let fill_defaults = (!infer_args || had_explicit_args) && !is_assoc_ty();
- if fill_defaults {
- let defaults = &*self.db.generic_defaults(def);
- let (item, _parent) = defaults.split_at(item_len);
- let parent_from = item_len - substs.len();
-
- let mut rem =
- def_generics.iter_id().skip(substs.len()).map(param_to_err).collect::<Vec<_>>();
- // Fill in defaults for type/const params
- for (idx, default_ty) in item[substs.len()..].iter().enumerate() {
- // each default can depend on the previous parameters
- let substs_so_far = Substitution::from_iter(
- Interner,
- substs.iter().cloned().chain(rem[idx..].iter().cloned()),
- );
- substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
- }
- // Fill in remaining parent params
- substs.extend(rem.drain(parent_from..));
- } else {
- // Fill in remaining def params and parent params
- substs.extend(def_generics.iter_id().skip(substs.len()).map(param_to_err));
- }
-
- assert_eq!(substs.len(), total_len, "expected {} substs, got {}", total_len, substs.len());
- Substitution::from_iter(Interner, substs)
- }
-
- pub(crate) fn lower_trait_ref_from_resolved_path(
- &mut self,
- resolved: TraitId,
- segment: PathSegment<'_>,
- explicit_self_ty: Ty,
- ) -> TraitRef {
- let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
- TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
- }
-
- fn prohibit_generics(
- &mut self,
- path_id: PathId,
- idx: u32,
- segments: PathSegments<'_>,
- reason: GenericArgsProhibitedReason,
- ) {
- segments.iter().zip(idx..).for_each(|(segment, idx)| {
- if segment.args_and_bindings.is_some() {
- self.push_diagnostic(
- path_id.type_ref(),
- TyLoweringDiagnosticKind::PathDiagnostic(
- PathLoweringDiagnostic::GenericArgsProhibited { segment: idx, reason },
- ),
- );
- }
- });
+ ctx.lower_partly_resolved_path(resolution, false)
}
fn lower_trait_ref_from_path(
&mut self,
path_id: PathId,
explicit_self_ty: Ty,
- ) -> Option<TraitRef> {
- let path = &self.types_map[path_id];
- let resolved = match self.resolve_path_in_type_ns_fully(
- path,
- &mut Self::on_path_diagnostic_callback(path_id.type_ref()),
- )? {
+ ) -> Option<(TraitRef, PathLoweringContext<'_, 'a>)> {
+ let mut ctx = self.at_path(path_id);
+ let resolved = match ctx.resolve_path_in_type_ns_fully()? {
// FIXME(trait_alias): We need to handle trait alias here.
TypeNs::TraitId(tr) => tr,
_ => return None,
};
- // Do this after we verify it's indeed a trait to not confuse the user if they're not modules.
- self.prohibit_generics(
- path_id,
- 0,
- path.segments().strip_last(),
- GenericArgsProhibitedReason::Module,
- );
- let segment = path.segments().last().expect("path should have at least one segment");
- Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty))
+ Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty), ctx))
}
fn lower_trait_ref(
@@ -1308,16 +602,7 @@ impl<'a> TyLoweringContext<'a> {
trait_ref: &HirTraitRef,
explicit_self_ty: Ty,
) -> Option<TraitRef> {
- self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty)
- }
-
- fn trait_ref_substs_from_path(
- &mut self,
- segment: PathSegment<'_>,
- resolved: TraitId,
- explicit_self_ty: Ty,
- ) -> Substitution {
- self.substs_from_path_segment(segment, Some(resolved.into()), false, Some(explicit_self_ty))
+ self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0)
}
pub(crate) fn lower_where_predicate<'b>(
@@ -1365,11 +650,18 @@ impl<'a> TyLoweringContext<'a> {
self_ty: Ty,
ignore_bindings: bool,
) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'a> {
- let mut trait_ref = None;
- let clause = match bound {
- &TypeBound::Path(path, TraitBoundModifier::None) => {
- trait_ref = self.lower_trait_ref_from_path(path, self_ty);
- trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
+ let mut assoc_bounds = None;
+ let mut clause = None;
+ match bound {
+ &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
+ // FIXME Don't silently drop the hrtb lifetimes here
+ if let Some((trait_ref, ctx)) = self.lower_trait_ref_from_path(path, self_ty) {
+ if !ignore_bindings {
+ assoc_bounds =
+ ctx.assoc_type_bindings_from_type_bound(bound, trait_ref.clone());
+ }
+ clause = Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref)));
+ }
}
&TypeBound::Path(path, TraitBoundModifier::Maybe) => {
let sized_trait = self
@@ -1381,170 +673,21 @@ impl<'a> TyLoweringContext<'a> {
// If we got another trait here ignore the bound completely.
let trait_id = self
.lower_trait_ref_from_path(path, self_ty.clone())
- .map(|trait_ref| trait_ref.hir_trait_id());
+ .map(|(trait_ref, _)| trait_ref.hir_trait_id());
if trait_id == sized_trait {
self.unsized_types.insert(self_ty);
}
- None
- }
- &TypeBound::ForLifetime(_, path) => {
- // FIXME Don't silently drop the hrtb lifetimes here
- trait_ref = self.lower_trait_ref_from_path(path, self_ty);
- trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
}
TypeBound::Lifetime(l) => {
let lifetime = self.lower_lifetime(l);
- Some(crate::wrap_empty_binders(WhereClause::TypeOutlives(TypeOutlives {
+ clause = Some(crate::wrap_empty_binders(WhereClause::TypeOutlives(TypeOutlives {
ty: self_ty,
lifetime,
- })))
+ })));
}
- TypeBound::Use(_) | TypeBound::Error => None,
- };
- clause.into_iter().chain(
- trait_ref
- .filter(move |_| !ignore_bindings)
- .map(move |tr| self.assoc_type_bindings_from_type_bound(bound, tr))
- .into_iter()
- .flatten(),
- )
- }
-
- fn assoc_type_bindings_from_type_bound<'b>(
- &'b mut self,
- bound: &'b TypeBound,
- trait_ref: TraitRef,
- ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'a> {
- let last_segment = match bound {
- &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
- self.types_map[path].segments().last()
- }
- TypeBound::Path(_, TraitBoundModifier::Maybe)
- | TypeBound::Use(_)
- | TypeBound::Error
- | TypeBound::Lifetime(_) => None,
- };
- last_segment
- .into_iter()
- .filter_map(|segment| segment.args_and_bindings)
- .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
- .flat_map(move |binding| {
- let found = associated_type_by_name_including_super_traits(
- self.db,
- trait_ref.clone(),
- &binding.name,
- );
- let (super_trait_ref, associated_ty) = match found {
- None => return SmallVec::new(),
- Some(t) => t,
- };
- // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
- // generic params. It's inefficient to splice the `Substitution`s, so we may want
- // that method to optionally take parent `Substitution` as we already know them at
- // this point (`super_trait_ref.substitution`).
- let substitution = self.substs_from_path_segment(
- // FIXME: This is hack. We shouldn't really build `PathSegment` directly.
- PathSegment { name: &binding.name, args_and_bindings: binding.args.as_ref() },
- Some(associated_ty.into()),
- false, // this is not relevant
- Some(super_trait_ref.self_type_parameter(Interner)),
- );
- let self_params = generics(self.db.upcast(), associated_ty.into()).len_self();
- let substitution = Substitution::from_iter(
- Interner,
- substitution
- .iter(Interner)
- .take(self_params)
- .chain(super_trait_ref.substitution.iter(Interner)),
- );
- let projection_ty = ProjectionTy {
- associated_ty_id: to_assoc_type_id(associated_ty),
- substitution,
- };
- let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
- binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
- );
- if let Some(type_ref) = binding.type_ref {
- match (&self.types_map[type_ref], self.impl_trait_mode.mode) {
- (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
- (_, ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque) => {
- let ty = self.lower_ty(type_ref);
- let alias_eq =
- AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
- predicates
- .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
- }
- (_, ImplTraitLoweringMode::Param | ImplTraitLoweringMode::Variable) => {
- // Find the generic index for the target of our `bound`
- let target_param_idx = self
- .resolver
- .where_predicates_in_scope()
- .find_map(|(p, _)| match p {
- WherePredicate::TypeBound {
- target: WherePredicateTypeTarget::TypeOrConstParam(idx),
- bound: b,
- } if b == bound => Some(idx),
- _ => None,
- });
- let ty = if let Some(target_param_idx) = target_param_idx {
- let mut counter = 0;
- let generics = self.generics().expect("generics in scope");
- for (idx, data) in generics.iter_self_type_or_consts() {
- // Count the number of `impl Trait` things that appear before
- // the target of our `bound`.
- // Our counter within `impl_trait_mode` should be that number
- // to properly lower each types within `type_ref`
- if data.type_param().is_some_and(|p| {
- p.provenance == TypeParamProvenance::ArgumentImplTrait
- }) {
- counter += 1;
- }
- if idx == *target_param_idx {
- break;
- }
- }
- let mut ext = TyLoweringContext::new_maybe_unowned(
- self.db,
- self.resolver,
- self.types_map,
- self.types_source_map,
- self.owner,
- )
- .with_type_param_mode(self.type_param_mode);
- match self.impl_trait_mode.mode {
- ImplTraitLoweringMode::Param => {
- ext.impl_trait_mode =
- ImplTraitLoweringState::param(counter);
- }
- ImplTraitLoweringMode::Variable => {
- ext.impl_trait_mode =
- ImplTraitLoweringState::variable(counter);
- }
- _ => unreachable!(),
- }
- let ty = ext.lower_ty(type_ref);
- self.diagnostics.extend(ext.diagnostics);
- ty
- } else {
- self.lower_ty(type_ref)
- };
-
- let alias_eq =
- AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
- predicates
- .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
- }
- }
- }
- for bound in binding.bounds.iter() {
- predicates.extend(self.lower_type_bound(
- bound,
- TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner),
- false,
- ));
- }
- predicates
- })
+ TypeBound::Use(_) | TypeBound::Error => {}
+ }
+ clause.into_iter().chain(assoc_bounds.into_iter().flatten())
}
fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty {