Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower_nextsolver/path.rs')
-rw-r--r--crates/hir-ty/src/lower_nextsolver/path.rs1360
1 files changed, 1360 insertions, 0 deletions
diff --git a/crates/hir-ty/src/lower_nextsolver/path.rs b/crates/hir-ty/src/lower_nextsolver/path.rs
new file mode 100644
index 0000000000..7d6734303c
--- /dev/null
+++ b/crates/hir-ty/src/lower_nextsolver/path.rs
@@ -0,0 +1,1360 @@
+//! A wrapper around [`TyLoweringContext`] specifically for lowering paths.
+
+use std::ops::Deref;
+
+use either::Either;
+use hir_def::{
+ AssocItemId, GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId,
+ builtin_type::BuiltinType,
+ expr_store::{
+ ExpressionStore, HygieneId,
+ path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments},
+ },
+ hir::generics::{
+ GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance,
+ },
+ resolver::{ResolveValueResult, TypeNs, ValueNs},
+ signatures::TraitFlags,
+ type_ref::{TypeRef, TypeRefId},
+};
+use hir_expand::name::Name;
+use intern::sym;
+use rustc_hash::FxHashSet;
+use rustc_type_ir::{
+ AliasTerm, AliasTy, AliasTyKind, TypeVisitableExt,
+ inherent::{GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _},
+};
+use smallvec::{SmallVec, smallvec};
+use stdx::never;
+
+use crate::{
+ GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource,
+ PathLoweringDiagnostic, TyDefId, ValueTyDefId,
+ consteval_nextsolver::{unknown_const, unknown_const_as_generic},
+ db::HirDatabase,
+ generics::{Generics, generics},
+ lower::PathDiagnosticCallbackData,
+ lower_nextsolver::{
+ LifetimeElisionKind, PredicateFilter, generic_predicates_filtered_by,
+ named_associated_type_shorthand_candidates,
+ },
+ next_solver::{
+ AdtDef, Binder, Clause, Const, DbInterner, ErrorGuaranteed, Predicate, ProjectionPredicate,
+ Region, SolverDefId, TraitRef, Ty,
+ mapping::{ChalkToNextSolver, convert_binder_to_early_binder},
+ },
+ primitive,
+};
+
+use super::{
+ ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits,
+ const_param_ty_query, ty_query,
+};
+
+type CallbackData<'a> =
+ Either<PathDiagnosticCallbackData, crate::infer::diagnostics::PathDiagnosticCallbackData<'a>>;
+
+// We cannot use `&mut dyn FnMut()` because of lifetime issues, and we don't want to use `Box<dyn FnMut()>`
+// because of the allocation, so we create a lifetime-less callback, tailored for our needs.
+pub(crate) struct PathDiagnosticCallback<'a, 'db> {
+ pub(crate) data: CallbackData<'a>,
+ pub(crate) callback:
+ fn(&CallbackData<'_>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic),
+}
+
+pub(crate) struct PathLoweringContext<'a, 'b, 'db> {
+ ctx: &'a mut TyLoweringContext<'db, 'b>,
+ on_diagnostic: PathDiagnosticCallback<'a, 'db>,
+ path: &'a Path,
+ segments: PathSegments<'a>,
+ current_segment_idx: usize,
+ /// Contains the previous segment if `current_segment_idx == segments.len()`
+ current_or_prev_segment: PathSegment<'a>,
+}
+
+impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
+ #[inline]
+ pub(crate) fn new(
+ ctx: &'a mut TyLoweringContext<'db, 'b>,
+ on_diagnostic: PathDiagnosticCallback<'a, 'db>,
+ 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<'db, '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(..)) {
+ // In lang items, the resolved "segment" is not one of the segments. Perhaps we should've put it
+ // point at -1, but I don't feel this is clearer.
+ 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()");
+ }
+
+ #[inline]
+ fn with_lifetime_elision<T>(
+ &mut self,
+ lifetime_elision: LifetimeElisionKind<'db>,
+ f: impl FnOnce(&mut PathLoweringContext<'_, '_, 'db>) -> T,
+ ) -> T {
+ let old_lifetime_elision =
+ std::mem::replace(&mut self.ctx.lifetime_elision, lifetime_elision);
+ let result = f(self);
+ self.ctx.lifetime_elision = old_lifetime_elision;
+ result
+ }
+
+ pub(crate) fn lower_ty_relative_path(
+ &mut self,
+ ty: Ty<'db>,
+ // We need the original resolution to lower `Self::AssocTy` correctly
+ res: Option<TypeNs>,
+ ) -> (Ty<'db>, Option<TypeNs>) {
+ let remaining_segments = self.segments.len() - self.current_segment_idx;
+ match remaining_segments {
+ 0 => (ty, res),
+ 1 => {
+ // resolve unselected assoc types
+ (self.select_associated_type(res), None)
+ }
+ _ => {
+ // FIXME report error (ambiguous associated type)
+ (Ty::new_error(self.ctx.interner, ErrorGuaranteed), 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
+ }
+
+ // When calling this, the current segment is the resolved segment (we don't advance it yet).
+ pub(crate) fn lower_partly_resolved_path(
+ &mut self,
+ resolution: TypeNs,
+ infer_args: bool,
+ ) -> (Ty<'db>, Option<TypeNs>) {
+ let remaining_segments = self.segments.skip(self.current_segment_idx + 1);
+ tracing::debug!(?remaining_segments);
+ let rem_seg_len = remaining_segments.len();
+ tracing::debug!(?rem_seg_len);
+
+ 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_,
+ Ty::new_error(self.ctx.interner, ErrorGuaranteed),
+ );
+ tracing::debug!(?trait_ref);
+ self.skip_resolved_segment();
+ let segment = self.current_or_prev_segment;
+ let trait_id = trait_ref.def_id.0;
+ let found =
+ trait_id.trait_items(self.ctx.db).associated_type_by_name(segment.name);
+
+ tracing::debug!(?found);
+ 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(
+ associated_ty.into(),
+ false,
+ None,
+ true,
+ );
+ let args = crate::next_solver::GenericArgs::new_from_iter(
+ self.ctx.interner,
+ trait_ref
+ .args
+ .iter()
+ .chain(substitution.iter().skip(trait_ref.args.len())),
+ );
+ Ty::new_alias(
+ self.ctx.interner,
+ AliasTyKind::Projection,
+ AliasTy::new_from_args(
+ self.ctx.interner,
+ associated_ty.into(),
+ args,
+ ),
+ )
+ }
+ None => {
+ // FIXME: report error (associated type not found)
+ Ty::new_error(self.ctx.interner, ErrorGuaranteed)
+ }
+ }
+ }
+ 0 => {
+ // Trait object type without dyn; this should be handled in upstream. See
+ // `lower_path()`.
+ stdx::never!("unexpected fully resolved trait path");
+ Ty::new_error(self.ctx.interner, ErrorGuaranteed)
+ }
+ _ => {
+ // FIXME report error (ambiguous associated type)
+ Ty::new_error(self.ctx.interner, ErrorGuaranteed)
+ }
+ };
+ return (ty, None);
+ }
+ TypeNs::GenericParam(param_id) => {
+ let generics = self.ctx.generics();
+ let idx = generics.type_or_const_param_idx(param_id.into());
+ match idx {
+ None => {
+ never!("no matching generics");
+ Ty::new_error(self.ctx.interner, ErrorGuaranteed)
+ }
+ Some(idx) => {
+ let (pidx, param) = generics.iter().nth(idx).unwrap();
+ assert_eq!(pidx, param_id.into());
+ let p = match param {
+ GenericParamDataRef::TypeParamData(p) => p,
+ _ => unreachable!(),
+ };
+ Ty::new_param(
+ self.ctx.interner,
+ param_id,
+ idx as u32,
+ p.name
+ .as_ref()
+ .map_or_else(|| sym::MISSING_NAME.clone(), |p| p.symbol().clone()),
+ )
+ }
+ }
+ }
+ TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty_ns(impl_id).skip_binder(),
+ TypeNs::AdtSelfType(adt) => {
+ let args = crate::next_solver::GenericArgs::identity_for_item(
+ self.ctx.interner,
+ adt.into(),
+ );
+ Ty::new_adt(self.ctx.interner, AdtDef::new(adt, self.ctx.interner), args)
+ }
+
+ 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),
+ // FIXME: report error
+ TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => {
+ return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None);
+ }
+ };
+
+ tracing::debug!(?ty);
+
+ 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::ModuleId(_) => {
+ prohibit_generics_on_resolved(GenericArgsProhibitedReason::Module)
+ }
+ TypeNs::AdtId(_)
+ | TypeNs::EnumVariantId(_)
+ | TypeNs::TypeAliasId(_)
+ | TypeNs::TraitId(_) => {}
+ }
+ }
+
+ 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)
+ }
+
+ #[tracing::instrument(skip(self), ret)]
+ 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, self.path)?;
+
+ let segments = self.segments;
+ if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
+ // `segments.is_empty()` can occur with `self`.
+ 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(..)) {
+ // Bare paths cannot have generics, so skip them as an optimization.
+ 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
+ && 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,
+ self.path,
+ hygiene_id,
+ )?;
+
+ let segments = self.segments;
+ if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
+ // `segments.is_empty()` can occur with `self`.
+ 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
+ && 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)
+ }
+ // 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, _, _) => {
+ self.handle_type_ns_resolution(resolution);
+ }
+ };
+ Some(res)
+ }
+
+ #[tracing::instrument(skip(self), ret)]
+ fn select_associated_type(&mut self, res: Option<TypeNs>) -> Ty<'db> {
+ let interner = self.ctx.interner;
+ let Some(res) = res else {
+ return Ty::new_error(self.ctx.interner, ErrorGuaranteed);
+ };
+ let db = self.ctx.db;
+ let def = self.ctx.def;
+ let segment = self.current_or_prev_segment;
+ let assoc_name = segment.name;
+ let mut check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| {
+ if name != assoc_name {
+ return None;
+ }
+
+ // 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(associated_ty.into(), false, None, true);
+
+ let substs = crate::next_solver::GenericArgs::new_from_iter(
+ interner,
+ t.args.iter().chain(substs.iter().skip(t.args.len())),
+ );
+
+ Some(Ty::new_alias(
+ interner,
+ AliasTyKind::Projection,
+ AliasTy::new(interner, associated_ty.into(), substs),
+ ))
+ };
+ named_associated_type_shorthand_candidates(
+ interner,
+ def,
+ res,
+ Some(assoc_name.clone()),
+ check_alias,
+ )
+ .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed))
+ }
+
+ fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> {
+ let generic_def = match typeable {
+ TyDefId::BuiltinType(builtinty) => return builtin(self.ctx.interner, builtinty),
+ TyDefId::AdtId(it) => it.into(),
+ TyDefId::TypeAliasId(it) => it.into(),
+ };
+ let args = self.substs_from_path_segment(generic_def, infer_args, None, false);
+ let ty = ty_query(self.ctx.db, typeable);
+ ty.instantiate(self.ctx.interner, args)
+ }
+
+ /// Collect generic arguments from a path into a `Substs`. See also
+ /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
+ pub(crate) fn substs_from_path(
+ &mut self,
+ // 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,
+ lowering_assoc_type_generics: bool,
+ ) -> crate::next_solver::GenericArgs<'db> {
+ let interner = self.ctx.interner;
+ 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 crate::next_solver::GenericArgs::new_from_iter(interner, []);
+ }
+ 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
+ // FIXME: This isn't strictly correct, enum variants may be used not through the enum
+ // (via `use Enum::Variant`). The resolver returns whether they were, but we don't have its result
+ // available here. The worst that can happen is that we will show some confusing diagnostics to the user,
+ // if generics exist on the module and they don't match with the variant.
+ // preferred). See also `def_ids_for_path_segments` in rustc.
+ //
+ // `wrapping_sub(1)` will return a number which `get` will return None for if current_segment_idx<2.
+ // This simplifies the code a bit.
+ let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
+ let penultimate = self.segments.get(penultimate_idx);
+ if let Some(penultimate) = penultimate
+ && 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).parent.into()
+ }
+ };
+ let result = self.substs_from_path_segment(
+ generic_def,
+ infer_args,
+ None,
+ lowering_assoc_type_generics,
+ );
+ 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<'db>>,
+ lowering_assoc_type_generics: bool,
+ ) -> crate::next_solver::GenericArgs<'db> {
+ let mut lifetime_elision = self.ctx.lifetime_elision.clone();
+
+ if let Some(args) = self.current_or_prev_segment.args_and_bindings
+ && args.parenthesized != GenericArgsParentheses::No
+ {
+ let prohibit_parens = match def {
+ GenericDefId::TraitId(trait_) => {
+ // RTN is prohibited anyways if we got here.
+ let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation;
+ let is_fn_trait = self
+ .ctx
+ .db
+ .trait_signature(trait_)
+ .flags
+ .contains(TraitFlags::RUSTC_PAREN_SUGAR);
+ is_rtn || !is_fn_trait
+ }
+ _ => true,
+ };
+
+ if prohibit_parens {
+ let segment = self.current_segment_u32();
+ self.on_diagnostic(
+ PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
+ );
+
+ return unknown_subst(self.ctx.interner, def);
+ }
+
+ // `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
+ lifetime_elision =
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
+ }
+
+ self.substs_from_args_and_bindings(
+ self.current_or_prev_segment.args_and_bindings,
+ def,
+ infer_args,
+ explicit_self_ty,
+ PathGenericsSource::Segment(self.current_segment_u32()),
+ lowering_assoc_type_generics,
+ lifetime_elision,
+ )
+ }
+
+ 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<'db>>,
+ generics_source: PathGenericsSource,
+ lowering_assoc_type_generics: bool,
+ lifetime_elision: LifetimeElisionKind<'db>,
+ ) -> crate::next_solver::GenericArgs<'db> {
+ struct LowererCtx<'a, 'b, 'c, 'db> {
+ ctx: &'a mut PathLoweringContext<'b, 'c, 'db>,
+ generics_source: PathGenericsSource,
+ }
+
+ impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> {
+ fn report_len_mismatch(
+ &mut self,
+ def: GenericDefId,
+ provided_count: u32,
+ expected_count: u32,
+ kind: IncorrectGenericsLenKind,
+ ) {
+ self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsLen {
+ generics_source: self.generics_source,
+ provided_count,
+ expected_count,
+ kind,
+ def,
+ });
+ }
+
+ fn report_arg_mismatch(
+ &mut self,
+ param_id: GenericParamId,
+ arg_idx: u32,
+ has_self_arg: bool,
+ ) {
+ self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsOrder {
+ generics_source: self.generics_source,
+ param_id,
+ arg_idx,
+ has_self_arg,
+ });
+ }
+
+ fn provided_kind(
+ &mut self,
+ param_id: GenericParamId,
+ param: GenericParamDataRef<'_>,
+ arg: &GenericArg,
+ ) -> crate::next_solver::GenericArg<'db> {
+ match (param, arg) {
+ (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => {
+ self.ctx.ctx.lower_lifetime(*lifetime).into()
+ }
+ (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => {
+ self.ctx.ctx.lower_ty(*type_ref).into()
+ }
+ (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => {
+ let GenericParamId::ConstParamId(const_id) = param_id else {
+ unreachable!("non-const param ID for const param");
+ };
+ self.ctx
+ .ctx
+ .lower_const(konst, const_param_ty_query(self.ctx.ctx.db, const_id))
+ .into()
+ }
+ _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
+ }
+ }
+
+ fn provided_type_like_const(
+ &mut self,
+ const_ty: Ty<'db>,
+ arg: TypeLikeConst<'_>,
+ ) -> crate::next_solver::Const<'db> {
+ match arg {
+ TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty),
+ TypeLikeConst::Infer => unknown_const(const_ty),
+ }
+ }
+
+ fn inferred_kind(
+ &mut self,
+ def: GenericDefId,
+ param_id: GenericParamId,
+ param: GenericParamDataRef<'_>,
+ infer_args: bool,
+ preceding_args: &[crate::next_solver::GenericArg<'db>],
+ ) -> crate::next_solver::GenericArg<'db> {
+ let default = || {
+ self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(|default| {
+ convert_binder_to_early_binder(
+ self.ctx.ctx.interner,
+ def,
+ default.to_nextsolver(self.ctx.ctx.interner),
+ )
+ .instantiate(self.ctx.ctx.interner, preceding_args)
+ })
+ };
+ match param {
+ GenericParamDataRef::LifetimeParamData(_) => {
+ Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
+ .into()
+ }
+ GenericParamDataRef::TypeParamData(param) => {
+ if !infer_args
+ && param.default.is_some()
+ && let Some(default) = default()
+ {
+ return default;
+ }
+ Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
+ }
+ GenericParamDataRef::ConstParamData(param) => {
+ if !infer_args
+ && param.default.is_some()
+ && let Some(default) = default()
+ {
+ return default;
+ }
+ let GenericParamId::ConstParamId(const_id) = param_id else {
+ unreachable!("non-const param ID for const param");
+ };
+ unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
+ }
+ }
+ }
+
+ fn parent_arg(
+ &mut self,
+ param_id: GenericParamId,
+ ) -> crate::next_solver::GenericArg<'db> {
+ match param_id {
+ GenericParamId::TypeParamId(_) => {
+ Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
+ }
+ GenericParamId::ConstParamId(const_id) => {
+ unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
+ }
+ GenericParamId::LifetimeParamId(_) => {
+ Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
+ .into()
+ }
+ }
+ }
+
+ fn report_elided_lifetimes_in_path(
+ &mut self,
+ def: GenericDefId,
+ expected_count: u32,
+ hard_error: bool,
+ ) {
+ self.ctx.on_diagnostic(PathLoweringDiagnostic::ElidedLifetimesInPath {
+ generics_source: self.generics_source,
+ def,
+ expected_count,
+ hard_error,
+ });
+ }
+
+ fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) {
+ self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure {
+ generics_source: self.generics_source,
+ def,
+ expected_count,
+ });
+ }
+
+ fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) {
+ self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime {
+ generics_source: self.generics_source,
+ def,
+ expected_count,
+ });
+ }
+ }
+
+ substs_from_args_and_bindings(
+ self.ctx.db,
+ self.ctx.store,
+ args_and_bindings,
+ def,
+ infer_args,
+ lifetime_elision,
+ lowering_assoc_type_generics,
+ explicit_self_ty,
+ &mut LowererCtx { ctx: self, generics_source },
+ )
+ }
+
+ pub(crate) fn lower_trait_ref_from_resolved_path(
+ &mut self,
+ resolved: TraitId,
+ explicit_self_ty: Ty<'db>,
+ ) -> TraitRef<'db> {
+ let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty);
+ TraitRef::new_from_args(self.ctx.interner, resolved.into(), args)
+ }
+
+ fn trait_ref_substs_from_path(
+ &mut self,
+ resolved: TraitId,
+ explicit_self_ty: Ty<'db>,
+ ) -> crate::next_solver::GenericArgs<'db> {
+ self.substs_from_path_segment(resolved.into(), false, Some(explicit_self_ty), false)
+ }
+
+ pub(super) fn assoc_type_bindings_from_type_bound<'c>(
+ mut self,
+ trait_ref: TraitRef<'db>,
+ ) -> Option<impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'c, 'db>> {
+ let interner = self.ctx.interner;
+ self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
+ args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| {
+ let found = associated_type_by_name_including_super_traits(
+ self.ctx.db,
+ trait_ref,
+ &binding.name,
+ );
+ let (super_trait_ref, associated_ty) = match found {
+ None => return SmallVec::new(),
+ Some(t) => t,
+ };
+ let args =
+ self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
+ // 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`).
+ this.substs_from_args_and_bindings(
+ binding.args.as_ref(),
+ associated_ty.into(),
+ false, // this is not relevant
+ Some(super_trait_ref.self_ty()),
+ PathGenericsSource::AssocType {
+ segment: this.current_segment_u32(),
+ assoc_type: binding_idx as u32,
+ },
+ false,
+ this.ctx.lifetime_elision.clone(),
+ )
+ });
+ let args = crate::next_solver::GenericArgs::new_from_iter(
+ interner,
+ super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())),
+ );
+ let projection_term =
+ AliasTerm::new_from_args(interner, associated_ty.into(), args);
+ 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.store[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 pred = Clause(Predicate::new(
+ interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Projection(ProjectionPredicate {
+ projection_term,
+ term: ty.into(),
+ }),
+ )),
+ ));
+ predicates.push(pred);
+ }
+ }
+ }
+ for bound in binding.bounds.iter() {
+ predicates.extend(self.ctx.lower_type_bound(
+ bound,
+ Ty::new_alias(
+ self.ctx.interner,
+ AliasTyKind::Projection,
+ AliasTy::new_from_args(self.ctx.interner, associated_ty.into(), args),
+ ),
+ false,
+ ));
+ }
+ predicates
+ })
+ })
+ }
+}
+
+/// A const that were parsed like a type.
+pub(crate) enum TypeLikeConst<'a> {
+ Infer,
+ Path(&'a Path),
+}
+
+pub(crate) trait GenericArgsLowerer<'db> {
+ fn report_elided_lifetimes_in_path(
+ &mut self,
+ def: GenericDefId,
+ expected_count: u32,
+ hard_error: bool,
+ );
+
+ fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32);
+
+ fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32);
+
+ fn report_len_mismatch(
+ &mut self,
+ def: GenericDefId,
+ provided_count: u32,
+ expected_count: u32,
+ kind: IncorrectGenericsLenKind,
+ );
+
+ fn report_arg_mismatch(&mut self, param_id: GenericParamId, arg_idx: u32, has_self_arg: bool);
+
+ fn provided_kind(
+ &mut self,
+ param_id: GenericParamId,
+ param: GenericParamDataRef<'_>,
+ arg: &GenericArg,
+ ) -> crate::next_solver::GenericArg<'db>;
+
+ fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>)
+ -> Const<'db>;
+
+ fn inferred_kind(
+ &mut self,
+ def: GenericDefId,
+ param_id: GenericParamId,
+ param: GenericParamDataRef<'_>,
+ infer_args: bool,
+ preceding_args: &[crate::next_solver::GenericArg<'db>],
+ ) -> crate::next_solver::GenericArg<'db>;
+
+ fn parent_arg(&mut self, param_id: GenericParamId) -> crate::next_solver::GenericArg<'db>;
+}
+
+/// Returns true if there was an error.
+fn check_generic_args_len<'db>(
+ args_and_bindings: Option<&GenericArgs>,
+ def: GenericDefId,
+ def_generics: &Generics,
+ infer_args: bool,
+ lifetime_elision: &LifetimeElisionKind<'db>,
+ lowering_assoc_type_generics: bool,
+ ctx: &mut impl GenericArgsLowerer<'db>,
+) -> bool {
+ let mut had_error = false;
+
+ let (mut provided_lifetimes_count, mut provided_types_and_consts_count) = (0usize, 0usize);
+ if let Some(args_and_bindings) = args_and_bindings {
+ let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..];
+ for arg in args_no_self {
+ match arg {
+ GenericArg::Lifetime(_) => provided_lifetimes_count += 1,
+ GenericArg::Type(_) | GenericArg::Const(_) => provided_types_and_consts_count += 1,
+ }
+ }
+ }
+
+ let lifetime_args_len = def_generics.len_lifetimes_self();
+ if provided_lifetimes_count == 0 && lifetime_args_len > 0 && !lowering_assoc_type_generics {
+ // In generic associated types, we never allow inferring the lifetimes.
+ match lifetime_elision {
+ &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => {
+ ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path);
+ had_error |= report_in_path;
+ }
+ LifetimeElisionKind::AnonymousReportError => {
+ ctx.report_missing_lifetime(def, lifetime_args_len as u32);
+ had_error = true
+ }
+ LifetimeElisionKind::ElisionFailure => {
+ ctx.report_elision_failure(def, lifetime_args_len as u32);
+ had_error = true;
+ }
+ LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
+ // FIXME: Check there are other lifetimes in scope, and error/lint.
+ }
+ LifetimeElisionKind::Elided(_) => {
+ ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false);
+ }
+ LifetimeElisionKind::Infer => {
+ // Allow eliding lifetimes.
+ }
+ }
+ } else if lifetime_args_len != provided_lifetimes_count {
+ ctx.report_len_mismatch(
+ def,
+ provided_lifetimes_count as u32,
+ lifetime_args_len as u32,
+ IncorrectGenericsLenKind::Lifetimes,
+ );
+ had_error = true;
+ }
+
+ let defaults_count =
+ def_generics.iter_self_type_or_consts().filter(|(_, param)| param.has_default()).count();
+ let named_type_and_const_params_count = def_generics
+ .iter_self_type_or_consts()
+ .filter(|(_, param)| match param {
+ TypeOrConstParamData::TypeParamData(param) => {
+ param.provenance == TypeParamProvenance::TypeParamList
+ }
+ TypeOrConstParamData::ConstParamData(_) => true,
+ })
+ .count();
+ let expected_max = named_type_and_const_params_count;
+ let expected_min =
+ if infer_args { 0 } else { named_type_and_const_params_count - defaults_count };
+ if provided_types_and_consts_count < expected_min
+ || expected_max < provided_types_and_consts_count
+ {
+ ctx.report_len_mismatch(
+ def,
+ provided_types_and_consts_count as u32,
+ named_type_and_const_params_count as u32,
+ IncorrectGenericsLenKind::TypesAndConsts,
+ );
+ had_error = true;
+ }
+
+ had_error
+}
+
+pub(crate) fn substs_from_args_and_bindings<'db>(
+ db: &'db dyn HirDatabase,
+ store: &ExpressionStore,
+ args_and_bindings: Option<&GenericArgs>,
+ def: GenericDefId,
+ mut infer_args: bool,
+ lifetime_elision: LifetimeElisionKind<'db>,
+ lowering_assoc_type_generics: bool,
+ explicit_self_ty: Option<Ty<'db>>,
+ ctx: &mut impl GenericArgsLowerer<'db>,
+) -> crate::next_solver::GenericArgs<'db> {
+ let interner = DbInterner::new_with(db, None, None);
+
+ tracing::debug!(?args_and_bindings);
+
+ // Order is
+ // - Parent parameters
+ // - Optional Self parameter
+ // - Lifetime parameters
+ // - Type or Const parameters
+ let def_generics = generics(db, def);
+ let args_slice = args_and_bindings.map(|it| &*it.args).unwrap_or_default();
+
+ // We do not allow inference if there are specified args, i.e. we do not allow partial inference.
+ let has_non_lifetime_args =
+ args_slice.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_)));
+ infer_args &= !has_non_lifetime_args;
+
+ let had_count_error = check_generic_args_len(
+ args_and_bindings,
+ def,
+ &def_generics,
+ infer_args,
+ &lifetime_elision,
+ lowering_assoc_type_generics,
+ ctx,
+ );
+
+ let mut substs = Vec::with_capacity(def_generics.len());
+
+ substs.extend(def_generics.iter_parent_id().map(|id| ctx.parent_arg(id)));
+
+ let mut args = args_slice.iter().enumerate().peekable();
+ let mut params = def_generics.iter_self().peekable();
+
+ // If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
+ // If we later encounter a lifetime, we know that the arguments were provided in the
+ // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be
+ // inferred, so we can use it for diagnostics later.
+ let mut force_infer_lt = None;
+
+ let has_self_arg = args_and_bindings.is_some_and(|it| it.has_self_type);
+ // First, handle `Self` parameter. Consume it from the args if provided, otherwise from `explicit_self_ty`,
+ // and lastly infer it.
+ if let Some(&(
+ self_param_id,
+ self_param @ GenericParamDataRef::TypeParamData(TypeParamData {
+ provenance: TypeParamProvenance::TraitSelf,
+ ..
+ }),
+ )) = params.peek()
+ {
+ let self_ty = if has_self_arg {
+ let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type");
+ ctx.provided_kind(self_param_id, self_param, self_ty)
+ } else {
+ explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| {
+ ctx.inferred_kind(def, self_param_id, self_param, infer_args, &substs)
+ })
+ };
+ params.next();
+ substs.push(self_ty);
+ }
+
+ loop {
+ // We're going to iterate through the generic arguments that the user
+ // provided, matching them with the generic parameters we expect.
+ // Mismatches can occur as a result of elided lifetimes, or for malformed
+ // input. We try to handle both sensibly.
+ match (args.peek(), params.peek()) {
+ (Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) {
+ (GenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param))
+ if type_param.provenance == TypeParamProvenance::ArgumentImplTrait =>
+ {
+ // Do not allow specifying `impl Trait` explicitly. We already err at that, but if we won't handle it here
+ // we will handle it as if it was specified, instead of inferring it.
+ substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
+ params.next();
+ }
+ (GenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
+ | (GenericArg::Type(_), GenericParamDataRef::TypeParamData(_))
+ | (GenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => {
+ substs.push(ctx.provided_kind(param_id, param, arg));
+ args.next();
+ params.next();
+ }
+ (
+ GenericArg::Type(_) | GenericArg::Const(_),
+ GenericParamDataRef::LifetimeParamData(_),
+ ) => {
+ // We expected a lifetime argument, but got a type or const
+ // argument. That means we're inferring the lifetime.
+ substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
+ params.next();
+ force_infer_lt = Some((arg_idx as u32, param_id));
+ }
+ (GenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => {
+ if let Some(konst) = type_looks_like_const(store, *type_ref) {
+ let GenericParamId::ConstParamId(param_id) = param_id else {
+ panic!("unmatching param kinds");
+ };
+ let const_ty = const_param_ty_query(db, param_id);
+ substs.push(ctx.provided_type_like_const(const_ty, konst).into());
+ args.next();
+ params.next();
+ } else {
+ // See the `_ => { ... }` branch.
+ if !had_count_error {
+ ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
+ }
+ while args.next().is_some() {}
+ }
+ }
+ _ => {
+ // We expected one kind of parameter, but the user provided
+ // another. This is an error. However, if we already know that
+ // the arguments don't match up with the parameters, we won't issue
+ // an additional error, as the user already knows what's wrong.
+ if !had_count_error {
+ ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
+ }
+
+ // We've reported the error, but we want to make sure that this
+ // problem doesn't bubble down and create additional, irrelevant
+ // errors. In this case, we're simply going to ignore the argument
+ // and any following arguments. The rest of the parameters will be
+ // inferred.
+ while args.next().is_some() {}
+ }
+ },
+
+ (Some(&(_, arg)), None) => {
+ // We should never be able to reach this point with well-formed input.
+ // There are two situations in which we can encounter this issue.
+ //
+ // 1. The number of arguments is incorrect. In this case, an error
+ // will already have been emitted, and we can ignore it.
+ // 2. We've inferred some lifetimes, which have been provided later (i.e.
+ // after a type or const). We want to throw an error in this case.
+ if !had_count_error {
+ assert!(
+ matches!(arg, GenericArg::Lifetime(_)),
+ "the only possible situation here is incorrect lifetime order"
+ );
+ let (provided_arg_idx, param_id) =
+ force_infer_lt.expect("lifetimes ought to have been inferred");
+ ctx.report_arg_mismatch(param_id, provided_arg_idx, has_self_arg);
+ }
+
+ break;
+ }
+
+ (None, Some(&(param_id, param))) => {
+ // If there are fewer arguments than parameters, it means we're inferring the remaining arguments.
+ let param = if let GenericParamId::LifetimeParamId(_) = param_id {
+ match &lifetime_elision {
+ LifetimeElisionKind::ElisionFailure
+ | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
+ | LifetimeElisionKind::AnonymousReportError => {
+ assert!(had_count_error);
+ ctx.inferred_kind(def, param_id, param, infer_args, &substs)
+ }
+ LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
+ Region::new_static(interner).into()
+ }
+ LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(),
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }
+ | LifetimeElisionKind::Infer => {
+ // FIXME: With `AnonymousCreateParameter`, we need to create a new lifetime parameter here
+ // (but this will probably be done in hir-def lowering instead).
+ ctx.inferred_kind(def, param_id, param, infer_args, &substs)
+ }
+ }
+ } else {
+ ctx.inferred_kind(def, param_id, param, infer_args, &substs)
+ };
+ substs.push(param);
+ params.next();
+ }
+
+ (None, None) => break,
+ }
+ }
+
+ crate::next_solver::GenericArgs::new_from_iter(interner, substs)
+}
+
+fn type_looks_like_const(
+ store: &ExpressionStore,
+ type_ref: TypeRefId,
+) -> Option<TypeLikeConst<'_>> {
+ // A path/`_` const will be parsed as a type, instead of a const, because when parsing/lowering
+ // in hir-def we don't yet know the expected argument kind. rustc does this a bit differently,
+ // when lowering to HIR it resolves the path, and if it doesn't resolve to the type namespace
+ // it is lowered as a const. Our behavior could deviate from rustc when the value is resolvable
+ // in both the type and value namespaces, but I believe we only allow more code.
+ let type_ref = &store[type_ref];
+ match type_ref {
+ TypeRef::Path(path) => Some(TypeLikeConst::Path(path)),
+ TypeRef::Placeholder => Some(TypeLikeConst::Infer),
+ _ => None,
+ }
+}
+
+fn unknown_subst<'db>(
+ interner: DbInterner<'db>,
+ def: impl Into<GenericDefId>,
+) -> crate::next_solver::GenericArgs<'db> {
+ let params = generics(interner.db(), def.into());
+ crate::next_solver::GenericArgs::new_from_iter(
+ interner,
+ params.iter_id().map(|id| match id {
+ GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(),
+ GenericParamId::ConstParamId(id) => {
+ unknown_const_as_generic(const_param_ty_query(interner.db(), id))
+ }
+ GenericParamId::LifetimeParamId(_) => {
+ crate::next_solver::Region::error(interner).into()
+ }
+ }),
+ )
+}
+
+pub(crate) fn builtin<'db>(interner: DbInterner<'db>, builtin: BuiltinType) -> Ty<'db> {
+ match builtin {
+ BuiltinType::Char => Ty::new(interner, rustc_type_ir::TyKind::Char),
+ BuiltinType::Bool => Ty::new_bool(interner),
+ BuiltinType::Str => Ty::new(interner, rustc_type_ir::TyKind::Str),
+ BuiltinType::Int(t) => {
+ let int_ty = match primitive::int_ty_from_builtin(t) {
+ chalk_ir::IntTy::Isize => rustc_type_ir::IntTy::Isize,
+ chalk_ir::IntTy::I8 => rustc_type_ir::IntTy::I8,
+ chalk_ir::IntTy::I16 => rustc_type_ir::IntTy::I16,
+ chalk_ir::IntTy::I32 => rustc_type_ir::IntTy::I32,
+ chalk_ir::IntTy::I64 => rustc_type_ir::IntTy::I64,
+ chalk_ir::IntTy::I128 => rustc_type_ir::IntTy::I128,
+ };
+ Ty::new_int(interner, int_ty)
+ }
+ BuiltinType::Uint(t) => {
+ let uint_ty = match primitive::uint_ty_from_builtin(t) {
+ chalk_ir::UintTy::Usize => rustc_type_ir::UintTy::Usize,
+ chalk_ir::UintTy::U8 => rustc_type_ir::UintTy::U8,
+ chalk_ir::UintTy::U16 => rustc_type_ir::UintTy::U16,
+ chalk_ir::UintTy::U32 => rustc_type_ir::UintTy::U32,
+ chalk_ir::UintTy::U64 => rustc_type_ir::UintTy::U64,
+ chalk_ir::UintTy::U128 => rustc_type_ir::UintTy::U128,
+ };
+ Ty::new_uint(interner, uint_ty)
+ }
+ BuiltinType::Float(t) => {
+ let float_ty = match primitive::float_ty_from_builtin(t) {
+ chalk_ir::FloatTy::F16 => rustc_type_ir::FloatTy::F16,
+ chalk_ir::FloatTy::F32 => rustc_type_ir::FloatTy::F32,
+ chalk_ir::FloatTy::F64 => rustc_type_ir::FloatTy::F64,
+ chalk_ir::FloatTy::F128 => rustc_type_ir::FloatTy::F128,
+ };
+ Ty::new_float(interner, float_ty)
+ }
+ }
+}