use std::iter;
use chalk_ir::{BoundVar, cast::Cast, fold::Shift};
use either::Either;
use hir_def::{
GenericDefId, GenericParamId, ItemContainerId, Lookup, TraitId,
data::TraitFlags,
expr_store::HygieneId,
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments},
resolver::{ResolveValueResult, TypeNs, ValueNs},
type_ref::{TypeBound, TypeRef, TypesMap},
};
use smallvec::SmallVec;
use stdx::never;
use crate::{
AliasEq, AliasTy, GenericArgsProhibitedReason, ImplTraitLoweringMode, Interner,
ParamLoweringMode, PathLoweringDiagnostic, ProjectionTy, QuantifiedWhereClause, Substitution,
TraitRef, Ty, TyBuilder, TyDefId, TyKind, TyLoweringContext, ValueTyDefId, WhereClause,
consteval::unknown_const_as_generic,
error_lifetime,
generics::generics,
lower::{
ImplTraitLoweringState, generic_arg_to_chalk, named_associated_type_shorthand_candidates,
},
to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
utils::associated_type_by_name_including_super_traits,
};
type CallbackData<'a> = Either<
super::PathDiagnosticCallbackData,
crate::infer::diagnostics::PathDiagnosticCallbackData<'a>,
>;
pub(crate) struct PathDiagnosticCallback<'a> {
pub(crate) data: CallbackData<'a>,
pub(crate) callback: fn(&CallbackData<'_>, &mut TyLoweringContext<'_>, PathLoweringDiagnostic),
}
pub(crate) struct PathLoweringContext<'a, 'b> {
ctx: &'a mut TyLoweringContext<'b>,
on_diagnostic: PathDiagnosticCallback<'a>,
path: &'a Path,
segments: PathSegments<'a>,
current_segment_idx: usize,
current_or_prev_segment: PathSegment<'a>,
}
impl<'a, 'b> PathLoweringContext<'a, 'b> {
#[inline]
pub(crate) fn new(
ctx: &'a mut TyLoweringContext<'b>,
on_diagnostic: PathDiagnosticCallback<'a>,
path: &'a Path,
) -> Self {
let segments = path.segments();
let first_segment = segments.first().unwrap_or(PathSegment::MISSING);
Self {
ctx,
on_diagnostic,
path,
segments,
current_segment_idx: 0,
current_or_prev_segment: first_segment,
}
}
#[inline]
#[cold]
fn on_diagnostic(&mut self, diag: PathLoweringDiagnostic) {
(self.on_diagnostic.callback)(&self.on_diagnostic.data, self.ctx, diag);
}
#[inline]
pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'b> {
self.ctx
}
#[inline]
fn current_segment_u32(&self) -> u32 {
self.current_segment_idx as u32
}
#[inline]
fn skip_resolved_segment(&mut self) {
if !matches!(self.path, Path::LangItem(..)) {
self.current_segment_idx += 1;
}
self.update_current_segment();
}
#[inline]
fn update_current_segment(&mut self) {
self.current_or_prev_segment =
self.segments.get(self.current_segment_idx).unwrap_or(self.current_or_prev_segment);
}
#[inline]
pub(crate) fn ignore_last_segment(&mut self) {
self.segments = self.segments.strip_last();
}
#[inline]
pub(crate) fn set_current_segment(&mut self, segment: usize) {
self.current_segment_idx = segment;
self.current_or_prev_segment = self
.segments
.get(segment)
.expect("invalid segment passed to PathLoweringContext::set_current_segment()");
}
pub(crate) fn lower_ty_relative_path(
&mut self,
ty: Ty,
res: Option<TypeNs>,
) -> (Ty, Option<TypeNs>) {
match self.segments.len() - self.current_segment_idx {
0 => (ty, res),
1 => {
(self.select_associated_type(res), None)
}
_ => {
(TyKind::Error.intern(Interner), None)
}
}
}
fn prohibit_parenthesized_generic_args(&mut self) -> bool {
if let Some(generic_args) = self.current_or_prev_segment.args_and_bindings {
match generic_args.parenthesized {
GenericArgsParentheses::No => {}
GenericArgsParentheses::ReturnTypeNotation | GenericArgsParentheses::ParenSugar => {
let segment = self.current_segment_u32();
self.on_diagnostic(
PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
);
return true;
}
}
}
false
}
pub(crate) fn lower_partly_resolved_path(
&mut self,
resolution: TypeNs,
infer_args: bool,
) -> (Ty, Option<TypeNs>) {
let remaining_segments = self.segments.skip(self.current_segment_idx + 1);
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_,
TyKind::Error.intern(Interner),
);
self.skip_resolved_segment();
let segment = self.current_or_prev_segment;
let found =
self.ctx.db.trait_items(trait_).associated_type_by_name(segment.name);
match found {
Some(associated_ty) => {
let substitution = self.substs_from_path_segment(
associated_ty.into(),
false,
None,
);
let len_self =
generics(self.ctx.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 => {
TyKind::Error.intern(Interner)
}
}
}
0 => {
stdx::never!("unexpected fully resolved trait path");
TyKind::Error.intern(Interner)
}
_ => {
TyKind::Error.intern(Interner)
}
};
return (ty, None);
}
TypeNs::TraitAliasId(_) => {
return (TyKind::Error.intern(Interner), None);
}
TypeNs::GenericParam(param_id) => match self.ctx.type_param_mode {
ParamLoweringMode::Placeholder => {
TyKind::Placeholder(to_placeholder_idx(self.ctx.db, param_id.into()))
}
ParamLoweringMode::Variable => {
let idx = match self
.ctx
.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.ctx.in_binders, idx))
}
}
.intern(Interner),
TypeNs::SelfType(impl_id) => {
let generics = self.ctx.generics().expect("impl should have generic param scope");
match self.ctx.type_param_mode {
ParamLoweringMode::Placeholder => {
let generics = generics.parent_or_self();
let subst = generics.placeholder_subst(self.ctx.db);
self.ctx.db.impl_self_ty(impl_id).substitute(Interner, &subst)
}
ParamLoweringMode::Variable => {
let starting_from = match generics.def() {
GenericDefId::ImplId(_) => 0,
_ => generics.len_self(),
};
TyBuilder::impl_self_ty(self.ctx.db, impl_id)
.fill_with_bound_vars(self.ctx.in_binders, starting_from)
.build()
}
}
}
TypeNs::AdtSelfType(adt) => {
let generics = generics(self.ctx.db.upcast(), adt.into());
let substs = match self.ctx.type_param_mode {
ParamLoweringMode::Placeholder => generics.placeholder_subst(self.ctx.db),
ParamLoweringMode::Variable => {
generics.bound_vars_subst(self.ctx.db, self.ctx.in_binders)
}
};
self.ctx.db.ty(adt.into()).substitute(Interner, &substs)
}
TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args),
TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args),
TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args),
TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(Interner), None),
};
self.skip_resolved_segment();
self.lower_ty_relative_path(ty, Some(resolution))
}
fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) {
let mut prohibit_generics_on_resolved = |reason| {
if self.current_or_prev_segment.args_and_bindings.is_some() {
let segment = self.current_segment_u32();
self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
segment,
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) -> Option<TypeNs> {
let (res, unresolved) = self.resolve_path_in_type_ns()?;
if unresolved.is_some() {
return None;
}
Some(res)
}
pub(crate) fn resolve_path_in_type_ns(&mut self) -> Option<(TypeNs, Option<usize>)> {
let (resolution, remaining_index, _, prefix_info) = self
.ctx
.resolver
.resolve_path_in_type_ns_with_prefix_info(self.ctx.db.upcast(), self.path)?;
let segments = self.segments;
if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
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),
};
self.current_segment_idx = resolved_segment_idx;
self.current_or_prev_segment =
segments.get(resolved_segment_idx).expect("should have resolved segment");
if matches!(self.path, Path::BarePath(..)) {
return Some((resolution, remaining_index));
}
for (i, mod_segment) in module_segments.iter().enumerate() {
if mod_segment.args_and_bindings.is_some() {
self.on_diagnostic(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())
{
self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
segment: (enum_segment + 1) as u32,
reason: GenericArgsProhibitedReason::EnumVariant,
});
}
}
self.handle_type_ns_resolution(&resolution);
Some((resolution, remaining_index))
}
pub(crate) fn resolve_path_in_value_ns(
&mut self,
hygiene_id: HygieneId,
) -> Option<ResolveValueResult> {
let (res, prefix_info) = self.ctx.resolver.resolve_path_in_value_ns_with_prefix_info(
self.ctx.db.upcast(),
self.path,
hygiene_id,
)?;
let segments = self.segments;
if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
return Some(res);
}
let (mod_segments, enum_segment, resolved_segment_idx) = match res {
ResolveValueResult::Partial(_, unresolved_segment, _) => {
(segments.take(unresolved_segment - 1), None, unresolved_segment - 1)
}
ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
if prefix_info.enum_variant =>
{
(segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1)
}
ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1),
};
self.current_segment_idx = resolved_segment_idx;
self.current_or_prev_segment =
segments.get(resolved_segment_idx).expect("should have resolved segment");
for (i, mod_segment) in mod_segments.iter().enumerate() {
if mod_segment.args_and_bindings.is_some() {
self.on_diagnostic(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())
{
self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
segment: (enum_segment + 1) as u32,
reason: GenericArgsProhibitedReason::EnumVariant,
});
}
}
match &res {
ResolveValueResult::ValueNs(resolution, _) => {
let resolved_segment_idx = self.current_segment_u32();
let resolved_segment = self.current_or_prev_segment;
let mut prohibit_generics_on_resolved = |reason| {
if resolved_segment.args_and_bindings.is_some() {
self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
segment: resolved_segment_idx,
reason,
});
}
};
match resolution {
ValueNs::ImplSelf(_) => {
prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
}
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, _, _) => {
self.handle_type_ns_resolution(resolution);
}
};
Some(res)
}
fn select_associated_type(&mut self, res: Option<TypeNs>) -> Ty {
let Some((generics, res)) = self.ctx.generics().zip(res) else {
return TyKind::Error.intern(Interner);
};
let segment = self.current_or_prev_segment;
let ty = named_associated_type_shorthand_candidates(
self.ctx.db,
generics.def(),
res,
Some(segment.name.clone()),
move |name, t, associated_ty| {
let generics = self.ctx.generics().unwrap();
if name != segment.name {
return None;
}
let parent_subst = t.substitution.clone();
let parent_subst = match self.ctx.type_param_mode {
ParamLoweringMode::Placeholder => {
let s = generics.placeholder_subst(self.ctx.db);
s.apply(parent_subst, Interner)
}
ParamLoweringMode::Variable => {
parent_subst.shifted_in_from(Interner, self.ctx.in_binders)
}
};
let substs = self.substs_from_path_segment(associated_ty.into(), false, None);
let len_self =
crate::generics::generics(self.ctx.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, typeable: TyDefId, infer_args: bool) -> Ty {
let generic_def = match typeable {
TyDefId::BuiltinType(builtin) => return TyBuilder::builtin(builtin),
TyDefId::AdtId(it) => it.into(),
TyDefId::TypeAliasId(it) => it.into(),
};
let substs = self.substs_from_path_segment(generic_def, infer_args, None);
self.ctx.db.ty(typeable).substitute(Interner, &substs)
}
pub(crate) fn substs_from_path(
&mut self,
resolved: ValueTyDefId,
infer_args: bool,
) -> Substitution {
let prev_current_segment_idx = self.current_segment_idx;
let prev_current_segment = self.current_or_prev_segment;
let generic_def = match resolved {
ValueTyDefId::FunctionId(it) => it.into(),
ValueTyDefId::StructId(it) => it.into(),
ValueTyDefId::UnionId(it) => it.into(),
ValueTyDefId::ConstId(it) => it.into(),
ValueTyDefId::StaticId(_) => return Substitution::empty(Interner),
ValueTyDefId::EnumVariantId(var) => {
let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
let penultimate = self.segments.get(penultimate_idx);
if let Some(penultimate) = penultimate {
if self.current_or_prev_segment.args_and_bindings.is_none()
&& penultimate.args_and_bindings.is_some()
{
self.current_segment_idx = penultimate_idx;
self.current_or_prev_segment = penultimate;
}
}
var.lookup(self.ctx.db.upcast()).parent.into()
}
};
let result = self.substs_from_path_segment(generic_def, infer_args, None);
self.current_segment_idx = prev_current_segment_idx;
self.current_or_prev_segment = prev_current_segment;
result
}
pub(crate) fn substs_from_path_segment(
&mut self,
def: GenericDefId,
infer_args: bool,
explicit_self_ty: Option<Ty>,
) -> Substitution {
let prohibit_parens = match def {
GenericDefId::TraitId(trait_) => {
let is_rtn =
self.current_or_prev_segment.args_and_bindings.is_some_and(|generics| {
generics.parenthesized == GenericArgsParentheses::ReturnTypeNotation
});
let is_fn_trait =
!self.ctx.db.trait_data(trait_).flags.contains(TraitFlags::RUSTC_PAREN_SUGAR);
is_rtn || is_fn_trait
}
_ => true,
};
if prohibit_parens && self.prohibit_parenthesized_generic_args() {
return TyBuilder::unknown_subst(self.ctx.db, def);
}
self.substs_from_args_and_bindings(
self.current_or_prev_segment.args_and_bindings,
def,
infer_args,
explicit_self_ty,
)
}
pub(super) fn substs_from_args_and_bindings(
&mut self,
args_and_bindings: Option<&GenericArgs>,
def: GenericDefId,
infer_args: bool,
explicit_self_ty: Option<Ty>,
) -> Substitution {
let def_generics = generics(self.ctx.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();
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 {
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.ctx.lower_ty(*ty).cast(Interner));
}
}
} else {
fill_self_param()
};
for arg in args
.iter()
.filter_map(|arg| match arg {
GenericArg::Lifetime(arg) => Some(self.ctx.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 };
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.ctx.db,
id,
arg,
self.ctx,
self.ctx.types_map,
|ctx, type_ref| ctx.lower_ty(type_ref),
|ctx, const_ref, ty| ctx.lower_const(const_ref, ty),
|ctx, lifetime_ref| ctx.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.ctx.db.const_param_ty(x))
}
GenericParamId::TypeParamId(_) => ty_error(),
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
};
let is_assoc_ty = || match def {
GenericDefId::TypeAliasId(id) => {
matches!(id.lookup(self.ctx.db.upcast()).container, ItemContainerId::TraitId(_))
}
_ => false,
};
let fill_defaults = (!infer_args || had_explicit_args) && !is_assoc_ty();
if fill_defaults {
let defaults = &*self.ctx.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<_>>();
for (idx, default_ty) in item[substs.len()..].iter().enumerate() {
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));
}
substs.extend(rem.drain(parent_from..));
} else {
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,
explicit_self_ty: Ty,
) -> TraitRef {
let substs = self.trait_ref_substs_from_path(resolved, explicit_self_ty);
TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
}
fn trait_ref_substs_from_path(
&mut self,
resolved: TraitId,
explicit_self_ty: Ty,
) -> Substitution {
self.substs_from_path_segment(resolved.into(), false, Some(explicit_self_ty))
}
pub(super) fn assoc_type_bindings_from_type_bound<'c>(
mut self,
bound: &'c TypeBound,
trait_ref: TraitRef,
) -> Option<impl Iterator<Item = QuantifiedWhereClause> + use<'a, 'b, 'c>> {
self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
args_and_bindings.bindings.iter().flat_map(move |binding| {
let found = associated_type_by_name_including_super_traits(
self.ctx.db,
trait_ref.clone(),
&binding.name,
);
let (super_trait_ref, associated_ty) = match found {
None => return SmallVec::new(),
Some(t) => t,
};
let substitution = self.substs_from_args_and_bindings(
binding.args.as_ref(),
associated_ty.into(),
false, Some(super_trait_ref.self_type_parameter(Interner)),
);
let self_params = generics(self.ctx.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.ctx.types_map[type_ref], self.ctx.impl_trait_mode.mode) {
(TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
(_, ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque) => {
let ty = self.ctx.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) => {
let target_param_idx =
self.ctx.resolver.where_predicates_in_scope().find_map(
|(p, (_, types_map))| match p {
WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(idx),
bound: b,
} if std::ptr::eq::<TypesMap>(
self.ctx.types_map,
types_map,
) && bound == b =>
{
Some(idx)
}
_ => None,
},
);
let ty = if let Some(target_param_idx) = target_param_idx {
let mut counter = 0;
let generics = self.ctx.generics().expect("generics in scope");
for (idx, data) in generics.iter_self_type_or_consts() {
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.ctx.db,
self.ctx.resolver,
self.ctx.types_map,
self.ctx.types_source_map,
self.ctx.owner,
)
.with_type_param_mode(self.ctx.type_param_mode);
match self.ctx.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.ctx.diagnostics.extend(ext.diagnostics);
ty
} else {
self.ctx.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.ctx.lower_type_bound(
bound,
TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner),
false,
));
}
predicates
})
})
}
}