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.rs2664
1 files changed, 1621 insertions, 1043 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 4d5172fd4f..cfd2a06b2a 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -8,31 +8,23 @@
pub(crate) mod diagnostics;
pub(crate) mod path;
-use std::{
- cell::OnceCell,
- iter, mem,
- ops::{self, Not as _},
-};
-
-use base_db::Crate;
-use chalk_ir::{
- Mutability, Safety, TypeOutlives,
- cast::Cast,
- fold::{Shift, TypeFoldable},
- interner::HasInterner,
-};
+use std::{cell::OnceCell, iter, mem};
+use arrayvec::ArrayVec;
use either::Either;
use hir_def::{
AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
- FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId,
- Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId,
+ FunctionId, GeneralConstId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId,
+ LifetimeParamId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId,
+ TypeParamId, UnionId, VariantId,
builtin_type::BuiltinType,
- expr_store::{ExpressionStore, path::Path},
- hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate},
+ expr_store::{ExpressionStore, HygieneId, path::Path},
+ hir::generics::{
+ GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
+ },
item_tree::FieldsShape,
- lang_item::LangItem,
- resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
+ lang_item::LangItems,
+ resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs},
signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
type_ref::{
ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier,
@@ -40,51 +32,71 @@ use hir_def::{
},
};
use hir_expand::name::Name;
-use la_arena::{Arena, ArenaMap};
+use la_arena::{Arena, ArenaMap, Idx};
+use path::{PathDiagnosticCallback, PathLoweringContext};
+use rustc_ast_ir::Mutability;
use rustc_hash::FxHashSet;
+use rustc_pattern_analysis::Captures;
+use rustc_type_ir::{
+ AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate,
+ ExistentialProjection, ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind,
+ TyKind::{self},
+ TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate,
+ inherent::{
+ Clause as _, GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike,
+ Ty as _,
+ },
+};
+use smallvec::{SmallVec, smallvec};
use stdx::{impl_from, never};
+use tracing::debug;
use triomphe::{Arc, ThinArc};
use crate::{
- AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DomainGoal, DynTy, FnAbi,
- FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
- LifetimeData, LifetimeOutlives, PolyFnSig, QuantifiedWhereClause, QuantifiedWhereClauses,
- Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
- all_super_traits,
- consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic},
- db::HirDatabase,
- error_lifetime,
+ FnAbi, ImplTraitId, TraitEnvironment, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
+ consteval::intern_const_ref,
+ db::{HirDatabase, InternedOpaqueTyId},
generics::{Generics, generics, trait_self_param_idx},
- lower::{
- diagnostics::*,
- path::{PathDiagnosticCallback, PathLoweringContext},
+ next_solver::{
+ AliasTy, Binder, BoundExistentialPredicates, Clause, ClauseKind, Clauses, Const,
+ DbInterner, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FxIndexMap, GenericArg,
+ GenericArgs, ParamConst, ParamEnv, PolyFnSig, Predicate, Region, SolverDefId,
+ TraitPredicate, TraitRef, Ty, Tys, UnevaluatedConst, abi::Safety, util::BottomUpFolder,
},
- make_binders,
- mapping::{ToChalk, from_chalk_trait_id, lt_to_placeholder_idx},
- static_lifetime, to_chalk_trait_id, to_placeholder_idx,
- utils::all_super_trait_refs,
- variable_kinds_from_iter,
};
+pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId);
+
+#[derive(PartialEq, Eq, Debug, Hash)]
+pub struct ImplTraits<'db> {
+ pub(crate) impl_traits: Arena<ImplTrait<'db>>,
+}
+
+#[derive(PartialEq, Eq, Debug, Hash)]
+pub struct ImplTrait<'db> {
+ pub(crate) predicates: Box<[Clause<'db>]>,
+}
+
+pub type ImplTraitIdx<'db> = Idx<ImplTrait<'db>>;
+
#[derive(Debug, Default)]
-struct ImplTraitLoweringState {
+struct ImplTraitLoweringState<'db> {
/// When turning `impl Trait` into opaque types, we have to collect the
/// bounds at the same time to get the IDs correct (without becoming too
/// complicated).
mode: ImplTraitLoweringMode,
// This is structured as a struct with fields and not as an enum because it helps with the borrow checker.
- opaque_type_data: Arena<ImplTrait>,
+ opaque_type_data: Arena<ImplTrait<'db>>,
}
-impl ImplTraitLoweringState {
- fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState {
+
+impl<'db> ImplTraitLoweringState<'db> {
+ fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState<'db> {
Self { mode, opaque_type_data: Arena::new() }
}
}
-pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId);
-
#[derive(Debug, Clone)]
-pub enum LifetimeElisionKind {
+pub enum LifetimeElisionKind<'db> {
/// Create a new anonymous lifetime parameter and reference it.
///
/// If `report_in_path`, report an error when encountering lifetime elision in a path:
@@ -102,7 +114,7 @@ pub enum LifetimeElisionKind {
AnonymousCreateParameter { report_in_path: bool },
/// Replace all anonymous lifetimes by provided lifetime.
- Elided(Lifetime),
+ Elided(Region<'db>),
/// Give a hard error when either `&` or `'_` is written. Used to
/// rule out things like `where T: Foo<'_>`. Does not imply an
@@ -121,12 +133,15 @@ pub enum LifetimeElisionKind {
Infer,
}
-impl LifetimeElisionKind {
+impl<'db> LifetimeElisionKind<'db> {
#[inline]
- pub(crate) fn for_const(const_parent: ItemContainerId) -> LifetimeElisionKind {
+ pub(crate) fn for_const(
+ interner: DbInterner<'db>,
+ const_parent: ItemContainerId,
+ ) -> LifetimeElisionKind<'db> {
match const_parent {
ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => {
- LifetimeElisionKind::Elided(static_lifetime())
+ LifetimeElisionKind::Elided(Region::new_static(interner))
}
ItemContainerId::ImplId(_) => {
LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true }
@@ -138,67 +153,74 @@ impl LifetimeElisionKind {
}
#[inline]
- pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind {
+ pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind<'db> {
LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() }
}
#[inline]
- pub(crate) fn for_fn_ret() -> LifetimeElisionKind {
+ pub(crate) fn for_fn_ret(interner: DbInterner<'db>) -> LifetimeElisionKind<'db> {
// FIXME: We should use the elided lifetime here, or `ElisionFailure`.
- LifetimeElisionKind::Elided(error_lifetime())
+ LifetimeElisionKind::Elided(Region::error(interner))
}
}
#[derive(Debug)]
-pub struct TyLoweringContext<'db> {
+pub struct TyLoweringContext<'db, 'a> {
pub db: &'db dyn HirDatabase,
- resolver: &'db Resolver<'db>,
- store: &'db ExpressionStore,
+ interner: DbInterner<'db>,
+ lang_items: &'db LangItems,
+ resolver: &'a Resolver<'db>,
+ store: &'a ExpressionStore,
def: GenericDefId,
generics: OnceCell<Generics>,
in_binders: DebruijnIndex,
- /// Note: Conceptually, it's thinkable that we could be in a location where
- /// some type params should be represented as placeholders, and others
- /// should be converted to variables. I think in practice, this isn't
- /// possible currently, so this should be fine for now.
- pub type_param_mode: ParamLoweringMode,
- impl_trait_mode: ImplTraitLoweringState,
+ impl_trait_mode: ImplTraitLoweringState<'db>,
/// Tracks types with explicit `?Sized` bounds.
- pub(crate) unsized_types: FxHashSet<Ty>,
+ pub(crate) unsized_types: FxHashSet<Ty<'db>>,
pub(crate) diagnostics: Vec<TyLoweringDiagnostic>,
- lifetime_elision: LifetimeElisionKind,
+ lifetime_elision: LifetimeElisionKind<'db>,
+ /// When lowering the defaults for generic params, this contains the index of the currently lowered param.
+ /// We disallow referring to later params, or to ADT's `Self`.
+ lowering_param_default: Option<u32>,
}
-impl<'db> TyLoweringContext<'db> {
+impl<'db, 'a> TyLoweringContext<'db, 'a> {
pub fn new(
db: &'db dyn HirDatabase,
- resolver: &'db Resolver<'db>,
- store: &'db ExpressionStore,
+ resolver: &'a Resolver<'db>,
+ store: &'a ExpressionStore,
def: GenericDefId,
- lifetime_elision: LifetimeElisionKind,
+ lifetime_elision: LifetimeElisionKind<'db>,
) -> Self {
let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed);
- let type_param_mode = ParamLoweringMode::Placeholder;
- let in_binders = DebruijnIndex::INNERMOST;
+ let in_binders = DebruijnIndex::ZERO;
+ let interner = DbInterner::new_with(db, resolver.krate());
Self {
db,
+ // Can provide no block since we don't use it for trait solving.
+ interner,
+ lang_items: interner.lang_items(),
resolver,
def,
generics: Default::default(),
store,
in_binders,
impl_trait_mode,
- type_param_mode,
unsized_types: FxHashSet::default(),
diagnostics: Vec::new(),
lifetime_elision,
+ lowering_param_default: None,
}
}
- pub fn with_debruijn<T>(
+ pub(crate) fn set_lifetime_elision(&mut self, lifetime_elision: LifetimeElisionKind<'db>) {
+ self.lifetime_elision = lifetime_elision;
+ }
+
+ pub(crate) fn with_debruijn<T>(
&mut self,
debruijn: DebruijnIndex,
- f: impl FnOnce(&mut TyLoweringContext<'_>) -> T,
+ f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T,
) -> T {
let old_debruijn = mem::replace(&mut self.in_binders, debruijn);
let result = f(self);
@@ -206,50 +228,34 @@ impl<'db> TyLoweringContext<'db> {
result
}
- pub fn with_shifted_in<T>(
+ pub(crate) fn with_shifted_in<T>(
&mut self,
debruijn: DebruijnIndex,
- f: impl FnOnce(&mut TyLoweringContext<'_>) -> T,
+ f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T,
) -> T {
- self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f)
+ self.with_debruijn(self.in_binders.shifted_in(debruijn.as_u32()), f)
}
- fn with_lifetime_elision<T>(
- &mut self,
- lifetime_elision: LifetimeElisionKind,
- f: impl FnOnce(&mut TyLoweringContext<'_>) -> T,
- ) -> T {
- let old_lifetime_elision = mem::replace(&mut self.lifetime_elision, lifetime_elision);
- let result = f(self);
- self.lifetime_elision = old_lifetime_elision;
- result
- }
-
- pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
+ pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self }
}
- pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
- Self { type_param_mode, ..self }
- }
-
- pub fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
+ pub(crate) fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode);
self
}
- pub fn type_param_mode(&mut self, type_param_mode: ParamLoweringMode) -> &mut Self {
- self.type_param_mode = type_param_mode;
- self
+ pub(crate) fn lowering_param_default(&mut self, index: u32) {
+ self.lowering_param_default = Some(index);
}
- pub fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) {
+ pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) {
self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind });
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
-pub enum ImplTraitLoweringMode {
+pub(crate) enum ImplTraitLoweringMode {
/// `impl Trait` gets lowered into an opaque type that doesn't unify with
/// anything except itself. This is used in places where values flow 'out',
/// i.e. for arguments of the function we're currently checking, and return
@@ -260,30 +266,17 @@ pub enum ImplTraitLoweringMode {
Disallowed,
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum ParamLoweringMode {
- Placeholder,
- Variable,
-}
-
-impl<'a> TyLoweringContext<'a> {
- pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty {
+impl<'db, 'a> TyLoweringContext<'db, 'a> {
+ pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> {
self.lower_ty_ext(type_ref).0
}
- pub fn lower_const(&mut self, const_ref: &ConstRef, const_type: Ty) -> Const {
+ pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> {
let const_ref = &self.store[const_ref.expr];
match const_ref {
- hir_def::hir::Expr::Path(path) => path_to_const(
- self.db,
- self.resolver,
- path,
- self.type_param_mode,
- || self.generics(),
- self.in_binders,
- const_type.clone(),
- )
- .unwrap_or_else(|| unknown_const(const_type)),
+ hir_def::hir::Expr::Path(path) => {
+ self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type))
+ }
hir_def::hir::Expr::Literal(literal) => intern_const_ref(
self.db,
&match *literal {
@@ -326,32 +319,88 @@ impl<'a> TyLoweringContext<'a> {
}
}
- pub fn lower_path_as_const(&mut self, path: &Path, const_type: Ty) -> Const {
- path_to_const(
- self.db,
- self.resolver,
- path,
- self.type_param_mode,
- || self.generics(),
- self.in_binders,
- const_type.clone(),
- )
- .unwrap_or_else(|| unknown_const(const_type))
+ pub(crate) fn path_to_const(&mut self, path: &Path) -> Option<Const<'db>> {
+ match self.resolver.resolve_path_in_value_ns_fully(self.db, path, HygieneId::ROOT) {
+ Some(ValueNs::GenericParam(p)) => {
+ let args = self.generics();
+ match args.type_or_const_param_idx(p.into()) {
+ Some(idx) => Some(self.const_param(p, idx as u32)),
+ None => {
+ never!(
+ "Generic list doesn't contain this param: {:?}, {:?}, {:?}",
+ args,
+ path,
+ p
+ );
+ None
+ }
+ }
+ }
+ Some(ValueNs::ConstId(c)) => {
+ let args = GenericArgs::new_from_iter(self.interner, []);
+ Some(Const::new(
+ self.interner,
+ rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(
+ GeneralConstId::ConstId(c).into(),
+ args,
+ )),
+ ))
+ }
+ _ => None,
+ }
+ }
+
+ pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) -> Const<'db> {
+ self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type))
}
fn generics(&self) -> &Generics {
self.generics.get_or_init(|| generics(self.db, self.def))
}
- pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty, Option<TypeNs>) {
+ fn param_index_is_disallowed(&self, index: u32) -> bool {
+ self.lowering_param_default
+ .is_some_and(|disallow_params_after| index >= disallow_params_after)
+ }
+
+ fn type_param(&mut self, id: TypeParamId, index: u32) -> Ty<'db> {
+ if self.param_index_is_disallowed(index) {
+ // FIXME: Report an error.
+ Ty::new_error(self.interner, ErrorGuaranteed)
+ } else {
+ Ty::new_param(self.interner, id, index)
+ }
+ }
+
+ fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> {
+ if self.param_index_is_disallowed(index) {
+ // FIXME: Report an error.
+ Const::error(self.interner)
+ } else {
+ Const::new_param(self.interner, ParamConst { id, index })
+ }
+ }
+
+ fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> {
+ if self.param_index_is_disallowed(index) {
+ // FIXME: Report an error.
+ Region::error(self.interner)
+ } else {
+ Region::new_early_param(self.interner, EarlyParamRegion { id, index })
+ }
+ }
+
+ #[tracing::instrument(skip(self), ret)]
+ pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option<TypeNs>) {
+ let interner = self.interner;
let mut res = None;
let type_ref = &self.store[type_ref_id];
+ tracing::debug!(?type_ref);
let ty = match type_ref {
- TypeRef::Never => TyKind::Never.intern(Interner),
+ TypeRef::Never => Ty::new(interner, TyKind::Never),
TypeRef::Tuple(inner) => {
let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr));
- TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
- .intern(Interner)
+ Ty::new_tup_from_iter(interner, inner_tys)
}
TypeRef::Path(path) => {
let (ty, res_) =
@@ -361,81 +410,61 @@ impl<'a> TyLoweringContext<'a> {
}
&TypeRef::TypeParam(type_param_id) => {
res = Some(TypeNs::GenericParam(type_param_id));
- match self.type_param_mode {
- ParamLoweringMode::Placeholder => {
- let generics = self.generics();
- let idx = generics.type_or_const_param_idx(type_param_id.into()).unwrap();
- TyKind::Placeholder(to_placeholder_idx(
- self.db,
- type_param_id.into(),
- idx as u32,
- ))
- }
- ParamLoweringMode::Variable => {
- let idx =
- self.generics().type_or_const_param_idx(type_param_id.into()).unwrap();
- TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
- }
- }
- .intern(Interner)
+
+ let generics = self.generics();
+ let (idx, _data) =
+ generics.type_or_const_param(type_param_id.into()).expect("matching generics");
+ self.type_param(type_param_id, idx as u32)
}
&TypeRef::RawPtr(inner, mutability) => {
let inner_ty = self.lower_ty(inner);
- TyKind::Raw(lower_to_chalk_mutability(mutability), inner_ty).intern(Interner)
+ Ty::new(interner, TyKind::RawPtr(inner_ty, lower_mutability(mutability)))
}
TypeRef::Array(array) => {
let inner_ty = self.lower_ty(array.ty);
- let const_len = self.lower_const(&array.len, TyBuilder::usize());
- TyKind::Array(inner_ty, const_len).intern(Interner)
+ let const_len = self.lower_const(array.len, Ty::new_usize(interner));
+ Ty::new_array_with_const_len(interner, inner_ty, const_len)
}
&TypeRef::Slice(inner) => {
let inner_ty = self.lower_ty(inner);
- TyKind::Slice(inner_ty).intern(Interner)
+ Ty::new_slice(interner, inner_ty)
}
TypeRef::Reference(ref_) => {
let inner_ty = self.lower_ty(ref_.ty);
- // FIXME: It should infer the eldided lifetimes instead of stubbing with static
+ // FIXME: It should infer the eldided lifetimes instead of stubbing with error
let lifetime = ref_
.lifetime
- .as_ref()
- .map_or_else(error_lifetime, |&lr| self.lower_lifetime(lr));
- TyKind::Ref(lower_to_chalk_mutability(ref_.mutability), lifetime, inner_ty)
- .intern(Interner)
+ .map_or_else(|| Region::error(interner), |lr| self.lower_lifetime(lr));
+ Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability))
}
- TypeRef::Placeholder => TyKind::Error.intern(Interner),
+ TypeRef::Placeholder => Ty::new_error(interner, ErrorGuaranteed),
TypeRef::Fn(fn_) => {
- let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
- let (params, ret) = fn_.split_params_and_ret();
- let mut subst = Vec::with_capacity(fn_.params.len());
- ctx.with_lifetime_elision(
- LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false },
- |ctx| {
- subst.extend(params.iter().map(|&(_, tr)| ctx.lower_ty(tr)));
- },
- );
- ctx.with_lifetime_elision(LifetimeElisionKind::for_fn_ret(), |ctx| {
- subst.push(ctx.lower_ty(ret));
- });
- Substitution::from_iter(Interner, subst)
- });
- TyKind::Function(FnPointer {
- num_binders: 0, // FIXME lower `for<'a> fn()` correctly
- sig: FnSig {
+ let substs = self.with_shifted_in(
+ DebruijnIndex::from_u32(1),
+ |ctx: &mut TyLoweringContext<'_, '_>| {
+ Tys::new_from_iter(
+ interner,
+ fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)),
+ )
+ },
+ );
+ Ty::new_fn_ptr(
+ interner,
+ Binder::dummy(FnSig {
abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe },
- variadic: fn_.is_varargs,
- },
- substitution: FnSubst(substs),
- })
- .intern(Interner)
+ c_variadic: fn_.is_varargs,
+ inputs_and_output: substs,
+ }),
+ )
}
TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
TypeRef::ImplTrait(bounds) => {
match self.impl_trait_mode.mode {
ImplTraitLoweringMode::Opaque => {
- let origin = match self.def {
- GenericDefId::FunctionId(it) => Either::Left(it),
- GenericDefId::TypeAliasId(it) => Either::Right(it),
+ let origin = match self.resolver.generic_def() {
+ Some(GenericDefId::FunctionId(it)) => Either::Left(it),
+ Some(GenericDefId::TypeAliasId(it)) => Either::Right(it),
_ => panic!(
"opaque impl trait lowering must be in function or type alias"
),
@@ -444,9 +473,18 @@ impl<'a> TyLoweringContext<'a> {
// this dance is to make sure the data is in the right
// place even if we encounter more opaque types while
// lowering the bounds
- let idx = self.impl_trait_mode.opaque_type_data.alloc(ImplTrait {
- bounds: crate::make_single_type_binders(Vec::default()),
- });
+ let idx = self
+ .impl_trait_mode
+ .opaque_type_data
+ .alloc(ImplTrait { predicates: Box::default() });
+
+ let impl_trait_id = origin.either(
+ |f| ImplTraitId::ReturnTypeImplTrait(f, idx),
+ |a| ImplTraitId::TypeAliasImplTrait(a, idx),
+ );
+ let opaque_ty_id: SolverDefId =
+ self.db.intern_impl_trait_id(impl_trait_id).into();
+
// We don't want to lower the bounds inside the binders
// we're currently in, because they don't end up inside
// those binders. E.g. when we have `impl Trait<impl
@@ -457,27 +495,25 @@ impl<'a> TyLoweringContext<'a> {
// parameter of the outer function, it's just one binder
// away instead of two.
let actual_opaque_type_data = self
- .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
- ctx.lower_impl_trait(bounds, self.resolver.krate())
+ .with_debruijn(DebruijnIndex::ZERO, |ctx| {
+ ctx.lower_impl_trait(opaque_ty_id, bounds)
});
self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data;
- let impl_trait_id = origin.either(
- |f| ImplTraitId::ReturnTypeImplTrait(f, idx),
- |a| ImplTraitId::TypeAliasImplTrait(a, idx),
- );
- let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
- let generics = generics(self.db, origin.either(|f| f.into(), |a| a.into()));
- let parameters = generics.bound_vars_subst(self.db, self.in_binders);
- TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
+ let args = GenericArgs::identity_for_item(self.interner, opaque_ty_id);
+ Ty::new_alias(
+ self.interner,
+ AliasTyKind::Opaque,
+ AliasTy::new_from_args(self.interner, opaque_ty_id, args),
+ )
}
ImplTraitLoweringMode::Disallowed => {
// FIXME: report error
- TyKind::Error.intern(Interner)
+ Ty::new_error(self.interner, ErrorGuaranteed)
}
}
}
- TypeRef::Error => TyKind::Error.intern(Interner),
+ TypeRef::Error => Ty::new_error(self.interner, ErrorGuaranteed),
};
(ty, res)
}
@@ -485,8 +521,8 @@ impl<'a> TyLoweringContext<'a> {
/// This is only for `generic_predicates_for_param`, where we can't just
/// lower the self types of the predicates since that could lead to cycles.
/// So we just check here if the `type_ref` resolves to a generic param, and which.
- fn lower_ty_only_param(&mut self, type_ref_id: TypeRefId) -> Option<TypeOrConstParamId> {
- let type_ref = &self.store[type_ref_id];
+ fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
+ let type_ref = &self.store[type_ref];
let path = match type_ref {
TypeRef::Path(path) => path,
&TypeRef::TypeParam(idx) => return Some(idx.into()),
@@ -498,9 +534,8 @@ impl<'a> TyLoweringContext<'a> {
if path.segments().len() > 1 {
return None;
}
- 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,
+ let resolution = match self.resolver.resolve_path_in_type_ns(self.db, path) {
+ Some((it, None, _)) => it,
_ => return None,
};
match resolution {
@@ -510,7 +545,7 @@ impl<'a> TyLoweringContext<'a> {
}
#[inline]
- fn on_path_diagnostic_callback(type_ref: TypeRefId) -> PathDiagnosticCallback<'static> {
+ fn on_path_diagnostic_callback<'b>(type_ref: TypeRefId) -> PathDiagnosticCallback<'b, 'db> {
PathDiagnosticCallback {
data: Either::Left(PathDiagnosticCallbackData(type_ref)),
callback: |data, this, diag| {
@@ -521,7 +556,7 @@ impl<'a> TyLoweringContext<'a> {
}
#[inline]
- fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a> {
+ fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a, 'db> {
PathLoweringContext::new(
self,
Self::on_path_diagnostic_callback(path_id.type_ref()),
@@ -529,7 +564,7 @@ impl<'a> TyLoweringContext<'a> {
)
}
- pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option<TypeNs>) {
+ pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty<'db>, 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);
@@ -540,7 +575,7 @@ impl<'a> TyLoweringContext<'a> {
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),
+ None => return (Ty::new_error(self.interner, ErrorGuaranteed), None),
};
if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
@@ -556,8 +591,8 @@ impl<'a> TyLoweringContext<'a> {
fn lower_trait_ref_from_path(
&mut self,
path_id: PathId,
- explicit_self_ty: Ty,
- ) -> Option<(TraitRef, PathLoweringContext<'_, 'a>)> {
+ explicit_self_ty: Ty<'db>,
+ ) -> Option<(TraitRef<'db>, PathLoweringContext<'_, 'a, 'db>)> {
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.
@@ -570,31 +605,54 @@ impl<'a> TyLoweringContext<'a> {
fn lower_trait_ref(
&mut self,
trait_ref: &HirTraitRef,
- explicit_self_ty: Ty,
- ) -> Option<TraitRef> {
+ explicit_self_ty: Ty<'db>,
+ ) -> Option<TraitRef<'db>> {
self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0)
}
- /// When lowering predicates from parents (impl, traits) for children defs (fns, consts, types), `generics` should
- /// contain the `Generics` for the **child**, while `predicate_owner` should contain the `GenericDefId` of the
- /// **parent**. This is important so we generate the correct bound var/placeholder.
pub(crate) fn lower_where_predicate<'b>(
&'b mut self,
where_predicate: &'b WherePredicate,
ignore_bindings: bool,
- ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'a, 'b> {
+ generics: &Generics,
+ predicate_filter: PredicateFilter,
+ ) -> impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'db> {
match where_predicate {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => {
+ if let PredicateFilter::SelfTrait = predicate_filter {
+ let target_type = &self.store[*target];
+ let self_type = 'is_self: {
+ if let TypeRef::Path(path) = target_type
+ && path.is_self_type()
+ {
+ break 'is_self true;
+ }
+ if let TypeRef::TypeParam(param) = target_type
+ && generics[param.local_id()].is_trait_self()
+ {
+ break 'is_self true;
+ }
+ false
+ };
+ if !self_type {
+ return Either::Left(Either::Left(iter::empty()));
+ }
+ }
let self_ty = self.lower_ty(*target);
- Either::Left(self.lower_type_bound(bound, self_ty, ignore_bindings))
+ Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings)))
+ }
+ &WherePredicate::Lifetime { bound, target } => {
+ Either::Right(iter::once(Clause(Predicate::new(
+ self.interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::RegionOutlives(OutlivesPredicate(
+ self.lower_lifetime(bound),
+ self.lower_lifetime(target),
+ )),
+ )),
+ ))))
}
- &WherePredicate::Lifetime { bound, target } => Either::Right(iter::once(
- crate::wrap_empty_binders(WhereClause::LifetimeOutlives(LifetimeOutlives {
- a: self.lower_lifetime(bound),
- b: self.lower_lifetime(target),
- })),
- )),
}
.into_iter()
}
@@ -602,331 +660,808 @@ impl<'a> TyLoweringContext<'a> {
pub(crate) fn lower_type_bound<'b>(
&'b mut self,
bound: &'b TypeBound,
- self_ty: Ty,
+ self_ty: Ty<'db>,
ignore_bindings: bool,
- ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'a> {
+ ) -> impl Iterator<Item = Clause<'db>> + use<'b, 'a, 'db> {
+ let interner = self.interner;
+ let meta_sized = self.lang_items.MetaSized;
+ let pointee_sized = self.lang_items.PointeeSized;
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, mut ctx)) =
- self.lower_trait_ref_from_path(path, self_ty.clone())
- {
+ if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) {
// FIXME(sized-hierarchy): Remove this bound modifications once we have implemented
// sized-hierarchy correctly.
- let meta_sized = LangItem::MetaSized
- .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
- let pointee_sized = LangItem::PointeeSized
- .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
- let destruct = LangItem::Destruct
- .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
- let hir_trait_id = trait_ref.hir_trait_id();
- if meta_sized.is_some_and(|it| it == hir_trait_id)
- || destruct.is_some_and(|it| it == hir_trait_id)
- {
+ if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) {
// Ignore this bound
- } else if pointee_sized.is_some_and(|it| it == hir_trait_id) {
+ } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) {
// Regard this as `?Sized` bound
ctx.ty_ctx().unsized_types.insert(self_ty);
} else {
if !ignore_bindings {
- assoc_bounds =
- ctx.assoc_type_bindings_from_type_bound(trait_ref.clone());
+ assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref);
}
- clause =
- Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref)));
+ clause = Some(Clause(Predicate::new(
+ interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+ trait_ref,
+ polarity: rustc_type_ir::PredicatePolarity::Positive,
+ }),
+ )),
+ )));
}
}
}
&TypeBound::Path(path, TraitBoundModifier::Maybe) => {
- let sized_trait = LangItem::Sized.resolve_trait(self.db, self.resolver.krate());
+ let sized_trait = self.lang_items.Sized;
// Don't lower associated type bindings as the only possible relaxed trait bound
// `?Sized` has no of them.
// 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());
+ .lower_trait_ref_from_path(path, self_ty)
+ .map(|(trait_ref, _)| trait_ref.def_id.0);
if trait_id == sized_trait {
self.unsized_types.insert(self_ty);
}
}
&TypeBound::Lifetime(l) => {
let lifetime = self.lower_lifetime(l);
- clause = Some(crate::wrap_empty_binders(WhereClause::TypeOutlives(TypeOutlives {
- ty: self_ty,
- lifetime,
- })));
+ clause = Some(Clause(Predicate::new(
+ self.interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::TypeOutlives(OutlivesPredicate(
+ self_ty, lifetime,
+ )),
+ )),
+ )));
}
TypeBound::Use(_) | TypeBound::Error => {}
}
clause.into_iter().chain(assoc_bounds.into_iter().flatten())
}
- fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty {
- let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
+ fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> {
+ let interner = self.interner;
+ let dummy_self_ty = dyn_trait_dummy_self(interner);
+ let mut region = None;
// INVARIANT: The principal trait bound, if present, must come first. Others may be in any
// order but should be in the same order for the same set but possibly different order of
// bounds in the input.
// INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
// These invariants are utilized by `TyExt::dyn_trait()` and chalk.
- let mut lifetime = None;
- let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
- let mut lowered_bounds = Vec::new();
+ let bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
+ let mut principal = None;
+ let mut auto_traits = SmallVec::<[_; 3]>::new();
+ let mut projections = Vec::new();
+ let mut had_error = false;
+
for b in bounds {
- ctx.lower_type_bound(b, self_ty.clone(), false).for_each(|b| {
- let filter = match b.skip_binders() {
- WhereClause::Implemented(_) | WhereClause::AliasEq(_) => true,
- WhereClause::LifetimeOutlives(_) => false,
- WhereClause::TypeOutlives(t) => {
- lifetime = Some(t.lifetime.clone());
- false
+ let db = ctx.db;
+ ctx.lower_type_bound(b, dummy_self_ty, false).for_each(|b| {
+ match b.kind().skip_binder() {
+ rustc_type_ir::ClauseKind::Trait(t) => {
+ let id = t.def_id();
+ let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO);
+ if is_auto {
+ auto_traits.push(t.def_id().0);
+ } else {
+ if principal.is_some() {
+ // FIXME: Report an error.
+ had_error = true;
+ }
+ principal = Some(b.kind().rebind(t.trait_ref));
+ }
}
- };
- if filter {
- lowered_bounds.push(b);
+ rustc_type_ir::ClauseKind::Projection(p) => {
+ projections.push(b.kind().rebind(p));
+ }
+ rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => {
+ if region.is_some() {
+ // FIXME: Report an error.
+ had_error = true;
+ }
+ region = Some(outlives_predicate.1);
+ }
+ rustc_type_ir::ClauseKind::RegionOutlives(_)
+ | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
+ | rustc_type_ir::ClauseKind::WellFormed(_)
+ | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
+ | rustc_type_ir::ClauseKind::HostEffect(_)
+ | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
}
- });
+ })
+ }
+
+ if had_error {
+ return None;
+ }
+
+ if principal.is_none() && auto_traits.is_empty() {
+ // No traits is not allowed.
+ return None;
+ }
+
+ // `Send + Sync` is the same as `Sync + Send`.
+ auto_traits.sort_unstable();
+ // Duplicate auto traits are permitted.
+ auto_traits.dedup();
+
+ // Map the projection bounds onto a key that makes it easy to remove redundant
+ // bounds that are constrained by supertraits of the principal def id.
+ //
+ // Also make sure we detect conflicting bounds from expanding a trait alias and
+ // also specifying it manually, like:
+ // ```
+ // type Alias = Trait<Assoc = i32>;
+ // let _: &dyn Alias<Assoc = u32> = /* ... */;
+ // ```
+ let mut projection_bounds = FxIndexMap::default();
+ for proj in projections {
+ let key = (
+ proj.skip_binder().def_id().expect_type_alias(),
+ interner.anonymize_bound_vars(
+ proj.map_bound(|proj| proj.projection_term.trait_ref(interner)),
+ ),
+ );
+ if let Some(old_proj) = projection_bounds.insert(key, proj)
+ && interner.anonymize_bound_vars(proj)
+ != interner.anonymize_bound_vars(old_proj)
+ {
+ // FIXME: Report "conflicting associated type" error.
+ }
}
- let mut multiple_regular_traits = false;
- let mut multiple_same_projection = false;
- lowered_bounds.sort_unstable_by(|lhs, rhs| {
- use std::cmp::Ordering;
- match (lhs.skip_binders(), rhs.skip_binders()) {
- (WhereClause::Implemented(lhs), WhereClause::Implemented(rhs)) => {
- let lhs_id = lhs.trait_id;
- let lhs_is_auto = ctx
- .db
- .trait_signature(from_chalk_trait_id(lhs_id))
- .flags
- .contains(TraitFlags::AUTO);
- let rhs_id = rhs.trait_id;
- let rhs_is_auto = ctx
- .db
- .trait_signature(from_chalk_trait_id(rhs_id))
- .flags
- .contains(TraitFlags::AUTO);
-
- if !lhs_is_auto && !rhs_is_auto {
- multiple_regular_traits = true;
+ // A stable ordering of associated types from the principal trait and all its
+ // supertraits. We use this to ensure that different substitutions of a trait
+ // don't result in `dyn Trait` types with different projections lists, which
+ // can be unsound: <https://github.com/rust-lang/rust/pull/136458>.
+ // We achieve a stable ordering by walking over the unsubstituted principal
+ // trait ref.
+ let mut ordered_associated_types = vec![];
+
+ if let Some(principal_trait) = principal {
+ for clause in elaborate::elaborate(
+ interner,
+ [Clause::upcast_from(
+ TraitRef::identity(interner, principal_trait.def_id()),
+ interner,
+ )],
+ )
+ .filter_only_self()
+ {
+ let clause = clause.instantiate_supertrait(interner, principal_trait);
+ debug!("observing object predicate `{clause:?}`");
+
+ let bound_predicate = clause.kind();
+ match bound_predicate.skip_binder() {
+ ClauseKind::Trait(pred) => {
+ // FIXME(negative_bounds): Handle this correctly...
+ let trait_ref = interner
+ .anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
+ ordered_associated_types.extend(
+ pred.trait_ref
+ .def_id
+ .0
+ .trait_items(self.db)
+ .associated_types()
+ .map(|item| (item, trait_ref)),
+ );
}
- // Note that the ordering here is important; this ensures the invariant
- // mentioned above.
- (lhs_is_auto, lhs_id).cmp(&(rhs_is_auto, rhs_id))
- }
- (WhereClause::Implemented(_), _) => Ordering::Less,
- (_, WhereClause::Implemented(_)) => Ordering::Greater,
- (WhereClause::AliasEq(lhs), WhereClause::AliasEq(rhs)) => {
- match (&lhs.alias, &rhs.alias) {
- (AliasTy::Projection(lhs_proj), AliasTy::Projection(rhs_proj)) => {
- // We only compare the `associated_ty_id`s. We shouldn't have
- // multiple bounds for an associated type in the correct Rust code,
- // and if we do, we error out.
- if lhs_proj.associated_ty_id == rhs_proj.associated_ty_id {
- multiple_same_projection = true;
+ ClauseKind::Projection(pred) => {
+ let pred = bound_predicate.rebind(pred);
+ // A `Self` within the original bound will be instantiated with a
+ // `trait_object_dummy_self`, so check for that.
+ let references_self = match pred.skip_binder().term.kind() {
+ TermKind::Ty(ty) => {
+ ty.walk().any(|arg| arg == dummy_self_ty.into())
+ }
+ // FIXME(associated_const_equality): We should walk the const instead of not doing anything
+ TermKind::Const(_) => false,
+ };
+
+ // If the projection output contains `Self`, force the user to
+ // elaborate it explicitly to avoid a lot of complexity.
+ //
+ // The "classically useful" case is the following:
+ // ```
+ // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
+ // type MyOutput;
+ // }
+ // ```
+ //
+ // Here, the user could theoretically write `dyn MyTrait<MyOutput = X>`,
+ // but actually supporting that would "expand" to an infinitely-long type
+ // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
+ //
+ // Instead, we force the user to write
+ // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
+ // the discussion in #56288 for alternatives.
+ if !references_self {
+ let key = (
+ pred.skip_binder().projection_term.def_id.expect_type_alias(),
+ interner.anonymize_bound_vars(pred.map_bound(|proj| {
+ proj.projection_term.trait_ref(interner)
+ })),
+ );
+ if !projection_bounds.contains_key(&key) {
+ projection_bounds.insert(key, pred);
}
- lhs_proj.associated_ty_id.cmp(&rhs_proj.associated_ty_id)
}
- // We don't produce `AliasTy::Opaque`s yet.
- _ => unreachable!(),
}
+ _ => (),
}
- // `WhereClause::{TypeOutlives, LifetimeOutlives}` have been filtered out
- _ => unreachable!(),
}
+ }
+
+ // We compute the list of projection bounds taking the ordered associated types,
+ // and check if there was an entry in the collected `projection_bounds`. Those
+ // are computed by first taking the user-written associated types, then elaborating
+ // the principal trait ref, and only using those if there was no user-written.
+ // See note below about how we handle missing associated types with `Self: Sized`,
+ // which are not required to be provided, but are still used if they are provided.
+ let mut projection_bounds: Vec<_> = ordered_associated_types
+ .into_iter()
+ .filter_map(|key| projection_bounds.get(&key).copied())
+ .collect();
+
+ projection_bounds.sort_unstable_by_key(|proj| proj.skip_binder().def_id());
+
+ let principal = principal.map(|principal| {
+ principal.map_bound(|principal| {
+ // Verify that `dummy_self` did not leak inside default type parameters.
+ let args: Vec<_> = principal
+ .args
+ .iter()
+ // Skip `Self`
+ .skip(1)
+ .map(|arg| {
+ if arg.walk().any(|arg| arg == dummy_self_ty.into()) {
+ // FIXME: Report an error.
+ Ty::new_error(interner, ErrorGuaranteed).into()
+ } else {
+ arg
+ }
+ })
+ .collect();
+
+ ExistentialPredicate::Trait(ExistentialTraitRef::new(
+ interner,
+ principal.def_id,
+ args,
+ ))
+ })
});
- if multiple_regular_traits || multiple_same_projection {
- return None;
- }
+ let projections = projection_bounds.into_iter().map(|proj| {
+ proj.map_bound(|mut proj| {
+ // Like for trait refs, verify that `dummy_self` did not leak inside default type
+ // parameters.
+ let references_self = proj.projection_term.args.iter().skip(1).any(|arg| {
+ if arg.walk().any(|arg| arg == dummy_self_ty.into()) {
+ return true;
+ }
+ false
+ });
+ if references_self {
+ proj.projection_term =
+ replace_dummy_self_with_error(interner, proj.projection_term);
+ }
- lowered_bounds.first().and_then(|b| b.trait_id())?;
+ ExistentialPredicate::Projection(ExistentialProjection::erase_self_ty(
+ interner, proj,
+ ))
+ })
+ });
- // As multiple occurrences of the same auto traits *are* permitted, we deduplicate the
- // bounds. We shouldn't have repeated elements besides auto traits at this point.
- lowered_bounds.dedup();
+ let auto_traits = auto_traits.into_iter().map(|auto_trait| {
+ Binder::dummy(ExistentialPredicate::AutoTrait(auto_trait.into()))
+ });
- Some(QuantifiedWhereClauses::from_iter(Interner, lowered_bounds))
+ // N.b. principal, projections, auto traits
+ Some(BoundExistentialPredicates::new_from_iter(
+ interner,
+ principal.into_iter().chain(projections).chain(auto_traits),
+ ))
});
if let Some(bounds) = bounds {
- let bounds = crate::make_single_type_binders(bounds);
- TyKind::Dyn(DynTy {
- bounds,
- lifetime: match lifetime {
- Some(it) => match it.bound_var(Interner) {
- Some(bound_var) => bound_var
- .shifted_out_to(DebruijnIndex::new(2))
- .map(|bound_var| LifetimeData::BoundVar(bound_var).intern(Interner))
- .unwrap_or(it),
- None => it,
- },
- None => error_lifetime(),
+ let region = match region {
+ Some(it) => match it.kind() {
+ rustc_type_ir::RegionKind::ReBound(BoundVarIndexKind::Bound(db), var) => {
+ Region::new_bound(
+ self.interner,
+ db.shifted_out_to_binder(DebruijnIndex::from_u32(2)),
+ var,
+ )
+ }
+ _ => it,
},
- })
- .intern(Interner)
+ None => Region::new_static(self.interner),
+ };
+ Ty::new_dynamic(self.interner, bounds, region)
} else {
// FIXME: report error
// (additional non-auto traits, associated type rebound, or no resolved trait)
- TyKind::Error.intern(Interner)
+ Ty::new_error(self.interner, ErrorGuaranteed)
}
}
- fn lower_impl_trait(&mut self, bounds: &[TypeBound], krate: Crate) -> ImplTrait {
+ fn lower_impl_trait(&mut self, def_id: SolverDefId, bounds: &[TypeBound]) -> ImplTrait<'db> {
+ let interner = self.interner;
cov_mark::hit!(lower_rpit);
- let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
- let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
+ let args = GenericArgs::identity_for_item(interner, def_id);
+ let self_ty = Ty::new_alias(
+ self.interner,
+ rustc_type_ir::AliasTyKind::Opaque,
+ AliasTy::new_from_args(interner, def_id, args),
+ );
+ let predicates = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
let mut predicates = Vec::new();
for b in bounds {
- predicates.extend(ctx.lower_type_bound(b, self_ty.clone(), false));
+ predicates.extend(ctx.lower_type_bound(b, self_ty, false));
}
if !ctx.unsized_types.contains(&self_ty) {
- let sized_trait =
- LangItem::Sized.resolve_trait(ctx.db, krate).map(to_chalk_trait_id);
+ let sized_trait = self.lang_items.Sized;
let sized_clause = sized_trait.map(|trait_id| {
- let clause = WhereClause::Implemented(TraitRef {
- trait_id,
- substitution: Substitution::from1(Interner, self_ty.clone()),
- });
- crate::wrap_empty_binders(clause)
+ let trait_ref = TraitRef::new_from_args(
+ interner,
+ trait_id.into(),
+ GenericArgs::new_from_iter(interner, [self_ty.into()]),
+ );
+ Clause(Predicate::new(
+ interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+ trait_ref,
+ polarity: rustc_type_ir::PredicatePolarity::Positive,
+ }),
+ )),
+ ))
});
predicates.extend(sized_clause);
}
- predicates.shrink_to_fit();
- predicates
+ predicates.into_boxed_slice()
});
- ImplTrait { bounds: crate::make_single_type_binders(predicates) }
+ ImplTrait { predicates }
}
- pub fn lower_lifetime(&self, lifetime: LifetimeRefId) -> Lifetime {
+ pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> {
match self.resolver.resolve_lifetime(&self.store[lifetime]) {
Some(resolution) => match resolution {
- LifetimeNs::Static => static_lifetime(),
- LifetimeNs::LifetimeParam(id) => match self.type_param_mode {
- ParamLoweringMode::Placeholder => {
- let generics = self.generics();
- let idx = generics.lifetime_idx(id).unwrap();
- LifetimeData::Placeholder(lt_to_placeholder_idx(self.db, id, idx as u32))
- }
- ParamLoweringMode::Variable => {
- let idx = match self.generics().lifetime_idx(id) {
- None => return error_lifetime(),
- Some(idx) => idx,
- };
-
- LifetimeData::BoundVar(BoundVar::new(self.in_binders, idx))
- }
+ LifetimeNs::Static => Region::new_static(self.interner),
+ LifetimeNs::LifetimeParam(id) => {
+ let idx = match self.generics().lifetime_idx(id) {
+ None => return Region::error(self.interner),
+ Some(idx) => idx,
+ };
+ self.region_param(id, idx as u32)
}
- .intern(Interner),
},
- None => error_lifetime(),
+ None => Region::error(self.interner),
}
}
}
-/// Build the signature of a callable item (function, struct or enum variant).
-pub(crate) fn callable_item_signature_query(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig {
- match def {
- CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
- CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
- CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
+fn dyn_trait_dummy_self(interner: DbInterner<'_>) -> Ty<'_> {
+ // This type must not appear anywhere except here.
+ Ty::new_fresh(interner, 0)
+}
+
+fn replace_dummy_self_with_error<'db, T: TypeFoldable<DbInterner<'db>>>(
+ interner: DbInterner<'db>,
+ t: T,
+) -> T {
+ let dyn_trait_dummy_self = dyn_trait_dummy_self(interner);
+ t.fold_with(&mut BottomUpFolder {
+ interner,
+ ty_op: |ty| {
+ if ty == dyn_trait_dummy_self { Ty::new_error(interner, ErrorGuaranteed) } else { ty }
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ })
+}
+
+pub(crate) fn lower_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
+ match m {
+ hir_def::type_ref::Mutability::Shared => Mutability::Not,
+ hir_def::type_ref::Mutability::Mut => Mutability::Mut,
}
}
-fn named_associated_type_shorthand_candidates<R>(
- db: &dyn HirDatabase,
- // If the type parameter is defined in an impl and we're in a method, there
- // might be additional where clauses to consider
- def: GenericDefId,
- res: TypeNs,
- assoc_name: Option<Name>,
- // Do NOT let `cb` touch `TraitRef` outside of `TyLoweringContext`. Its substitution contains
- // free `BoundVar`s that need to be shifted and only `TyLoweringContext` knows how to do that
- // properly (see `TyLoweringContext::select_associated_type()`).
- mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
-) -> Option<R> {
- let mut search = |t| {
- all_super_trait_refs(db, t, |t| {
- let data = t.hir_trait_id().trait_items(db);
+fn unknown_const(_ty: Ty<'_>) -> Const<'_> {
+ Const::new(DbInterner::conjure(), ConstKind::Error(ErrorGuaranteed))
+}
- for (name, assoc_id) in &data.items {
- if let AssocItemId::TypeAliasId(alias) = assoc_id
- && let Some(result) = cb(name, &t, *alias)
- {
- return Some(result);
- }
+pub(crate) type Diagnostics = Option<ThinArc<(), TyLoweringDiagnostic>>;
+
+pub(crate) fn create_diagnostics(diagnostics: Vec<TyLoweringDiagnostic>) -> Diagnostics {
+ (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter()))
+}
+
+pub(crate) fn impl_trait_query<'db>(
+ db: &'db dyn HirDatabase,
+ impl_id: ImplId,
+) -> Option<EarlyBinder<'db, TraitRef<'db>>> {
+ db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
+}
+
+pub(crate) fn impl_trait_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
+ impl_id: ImplId,
+) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)> {
+ let impl_data = db.impl_signature(impl_id);
+ let resolver = impl_id.resolver(db);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &impl_data.store,
+ impl_id.into(),
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
+ );
+ let self_ty = db.impl_self_ty(impl_id).skip_binder();
+ let target_trait = impl_data.target_trait.as_ref()?;
+ let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?);
+ Some((trait_ref, create_diagnostics(ctx.diagnostics)))
+}
+
+impl<'db> ImplTraitId<'db> {
+ #[inline]
+ pub fn predicates(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+ let (impl_traits, idx) = match self {
+ ImplTraitId::ReturnTypeImplTrait(owner, idx) => {
+ (ImplTraits::return_type_impl_traits(db, owner), idx)
+ }
+ ImplTraitId::TypeAliasImplTrait(owner, idx) => {
+ (ImplTraits::type_alias_impl_traits(db, owner), idx)
}
+ };
+ impl_traits
+ .as_deref()
+ .expect("owner should have opaque type")
+ .as_ref()
+ .map_bound(|it| &*it.impl_traits[idx].predicates)
+ }
+}
+
+impl InternedOpaqueTyId {
+ #[inline]
+ pub fn predicates<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+ self.loc(db).predicates(db)
+ }
+}
+
+#[salsa::tracked]
+impl<'db> ImplTraits<'db> {
+ #[salsa::tracked(returns(ref), unsafe(non_update_return_type))]
+ pub(crate) fn return_type_impl_traits(
+ db: &'db dyn HirDatabase,
+ def: hir_def::FunctionId,
+ ) -> Option<Box<EarlyBinder<'db, ImplTraits<'db>>>> {
+ // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
+ let data = db.function_signature(def);
+ let resolver = def.resolver(db);
+ let mut ctx_ret = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::Infer,
+ )
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+ if let Some(ret_type) = data.ret_type {
+ let _ret = ctx_ret.lower_ty(ret_type);
+ }
+ let mut return_type_impl_traits =
+ ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data };
+ if return_type_impl_traits.impl_traits.is_empty() {
None
- })
- };
+ } else {
+ return_type_impl_traits.impl_traits.shrink_to_fit();
+ Some(Box::new(EarlyBinder::bind(return_type_impl_traits)))
+ }
+ }
- match res {
- TypeNs::SelfType(impl_id) => {
- // we're _in_ the impl -- the binders get added back later. Correct,
- // but it would be nice to make this more explicit
- let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
-
- let impl_id_as_generic_def: GenericDefId = impl_id.into();
- if impl_id_as_generic_def != def {
- let subst = TyBuilder::subst_for_def(db, impl_id, None)
- .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
- .build();
- let trait_ref = subst.apply(trait_ref, Interner);
- search(trait_ref)
- } else {
- search(trait_ref)
- }
+ #[salsa::tracked(returns(ref), unsafe(non_update_return_type))]
+ pub(crate) fn type_alias_impl_traits(
+ db: &'db dyn HirDatabase,
+ def: hir_def::TypeAliasId,
+ ) -> Option<Box<EarlyBinder<'db, ImplTraits<'db>>>> {
+ let data = db.type_alias_signature(def);
+ let resolver = def.resolver(db);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+ if let Some(type_ref) = data.ty {
+ let _ty = ctx.lower_ty(type_ref);
}
- TypeNs::GenericParam(param_id) => {
- let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
- let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
- // FIXME: how to correctly handle higher-ranked bounds here?
- WhereClause::Implemented(tr) => search(
- tr.clone()
- .shifted_out_to(Interner, DebruijnIndex::ONE)
- .expect("FIXME unexpected higher-ranked trait bound"),
- ),
- _ => None,
- });
- if res.is_some() {
- return res;
- }
- // Handle `Self::Type` referring to own associated type in trait definitions
- if let GenericDefId::TraitId(trait_id) = param_id.parent() {
- let trait_generics = generics(db, trait_id.into());
- if trait_generics[param_id.local_id()].is_trait_self() {
- let trait_ref = TyBuilder::trait_ref(db, trait_id)
- .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
- .build();
- return search(trait_ref);
- }
- }
+ let mut type_alias_impl_traits =
+ ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data };
+ if type_alias_impl_traits.impl_traits.is_empty() {
None
+ } else {
+ type_alias_impl_traits.impl_traits.shrink_to_fit();
+ Some(Box::new(EarlyBinder::bind(type_alias_impl_traits)))
}
- _ => None,
}
}
-pub(crate) type Diagnostics = Option<ThinArc<(), TyLoweringDiagnostic>>;
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum TyDefId {
+ BuiltinType(BuiltinType),
+ AdtId(AdtId),
+ TypeAliasId(TypeAliasId),
+}
+impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId);
-pub(crate) fn create_diagnostics(diagnostics: Vec<TyLoweringDiagnostic>) -> Diagnostics {
- (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter()))
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
+pub enum ValueTyDefId {
+ FunctionId(FunctionId),
+ StructId(StructId),
+ UnionId(UnionId),
+ EnumVariantId(EnumVariantId),
+ ConstId(ConstId),
+ StaticId(StaticId),
+}
+impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
+
+impl ValueTyDefId {
+ pub(crate) fn to_generic_def_id(self, db: &dyn HirDatabase) -> GenericDefId {
+ match self {
+ Self::FunctionId(id) => id.into(),
+ Self::StructId(id) => id.into(),
+ Self::UnionId(id) => id.into(),
+ Self::EnumVariantId(var) => var.lookup(db).parent.into(),
+ Self::ConstId(id) => id.into(),
+ Self::StaticId(id) => id.into(),
+ }
+ }
+}
+
+/// Build the declared type of an item. This depends on the namespace; e.g. for
+/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
+/// the constructor function `(usize) -> Foo` which lives in the values
+/// namespace.
+pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> {
+ let interner = DbInterner::new_no_crate(db);
+ match def {
+ TyDefId::BuiltinType(it) => EarlyBinder::bind(Ty::from_builtin_type(interner, it)),
+ TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt(
+ interner,
+ it,
+ GenericArgs::identity_for_item(interner, it.into()),
+ )),
+ TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
+ }
+}
+
+/// Build the declared type of a function. This should not need to look at the
+/// function body.
+fn type_for_fn<'db>(db: &'db dyn HirDatabase, def: FunctionId) -> EarlyBinder<'db, Ty<'db>> {
+ let interner = DbInterner::new_no_crate(db);
+ EarlyBinder::bind(Ty::new_fn_def(
+ interner,
+ CallableDefId::FunctionId(def).into(),
+ GenericArgs::identity_for_item(interner, def.into()),
+ ))
+}
+
+/// Build the declared type of a const.
+fn type_for_const<'db>(db: &'db dyn HirDatabase, def: ConstId) -> EarlyBinder<'db, Ty<'db>> {
+ let resolver = def.resolver(db);
+ let data = db.const_signature(def);
+ let parent = def.loc(db).container;
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ );
+ ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent));
+ EarlyBinder::bind(ctx.lower_ty(data.type_ref))
+}
+
+/// Build the declared type of a static.
+fn type_for_static<'db>(db: &'db dyn HirDatabase, def: StaticId) -> EarlyBinder<'db, Ty<'db>> {
+ let resolver = def.resolver(db);
+ let data = db.static_signature(def);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ );
+ ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner)));
+ EarlyBinder::bind(ctx.lower_ty(data.type_ref))
}
-pub(crate) fn field_types_query(
+/// Build the type of a tuple struct constructor.
+fn type_for_struct_constructor<'db>(
+ db: &'db dyn HirDatabase,
+ def: StructId,
+) -> Option<EarlyBinder<'db, Ty<'db>>> {
+ let struct_data = def.fields(db);
+ match struct_data.shape {
+ FieldsShape::Record => None,
+ FieldsShape::Unit => Some(type_for_adt(db, def.into())),
+ FieldsShape::Tuple => {
+ let interner = DbInterner::new_no_crate(db);
+ Some(EarlyBinder::bind(Ty::new_fn_def(
+ interner,
+ CallableDefId::StructId(def).into(),
+ GenericArgs::identity_for_item(interner, def.into()),
+ )))
+ }
+ }
+}
+
+/// Build the type of a tuple enum variant constructor.
+fn type_for_enum_variant_constructor<'db>(
+ db: &'db dyn HirDatabase,
+ def: EnumVariantId,
+) -> Option<EarlyBinder<'db, Ty<'db>>> {
+ let struct_data = def.fields(db);
+ match struct_data.shape {
+ FieldsShape::Record => None,
+ FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())),
+ FieldsShape::Tuple => {
+ let interner = DbInterner::new_no_crate(db);
+ Some(EarlyBinder::bind(Ty::new_fn_def(
+ interner,
+ CallableDefId::EnumVariantId(def).into(),
+ GenericArgs::identity_for_item(interner, def.loc(db).parent.into()),
+ )))
+ }
+ }
+}
+
+pub(crate) fn value_ty_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: ValueTyDefId,
+) -> Option<EarlyBinder<'db, Ty<'db>>> {
+ match def {
+ ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)),
+ ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
+ ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())),
+ ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
+ ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)),
+ ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)),
+ }
+}
+
+pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
+ t: TypeAliasId,
+) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
+ let type_alias_data = db.type_alias_signature(t);
+ let mut diags = None;
+ let resolver = t.resolver(db);
+ let interner = DbInterner::new_no_crate(db);
+ let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) {
+ EarlyBinder::bind(Ty::new_foreign(interner, t.into()))
+ } else {
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &type_alias_data.store,
+ t.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+ let res = EarlyBinder::bind(
+ type_alias_data
+ .ty
+ .map(|type_ref| ctx.lower_ty(type_ref))
+ .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)),
+ );
+ diags = create_diagnostics(ctx.diagnostics);
+ res
+ };
+ (inner, diags)
+}
+
+pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>(
+ db: &'db dyn HirDatabase,
+ _adt: TypeAliasId,
+) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
+ (EarlyBinder::bind(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)), None)
+}
+
+pub(crate) fn impl_self_ty_query<'db>(
+ db: &'db dyn HirDatabase,
+ impl_id: ImplId,
+) -> EarlyBinder<'db, Ty<'db>> {
+ db.impl_self_ty_with_diagnostics(impl_id).0
+}
+
+pub(crate) fn impl_self_ty_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
+ impl_id: ImplId,
+) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
+ let resolver = impl_id.resolver(db);
+
+ let impl_data = db.impl_signature(impl_id);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &impl_data.store,
+ impl_id.into(),
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
+ );
+ let ty = ctx.lower_ty(impl_data.self_ty);
+ assert!(!ty.has_escaping_bound_vars());
+ (EarlyBinder::bind(ty), create_diagnostics(ctx.diagnostics))
+}
+
+pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
db: &dyn HirDatabase,
+ _impl_id: ImplId,
+) -> (EarlyBinder<'_, Ty<'_>>, Diagnostics) {
+ (EarlyBinder::bind(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)), None)
+}
+
+pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> {
+ db.const_param_ty_with_diagnostics(def).0
+}
+
+// returns None if def is a type arg
+pub(crate) fn const_param_ty_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: ConstParamId,
+) -> (Ty<'db>, Diagnostics) {
+ let (parent_data, store) = db.generic_params_and_store(def.parent());
+ let data = &parent_data[def.local_id()];
+ let resolver = def.parent().resolver(db);
+ let interner = DbInterner::new_no_crate(db);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &store,
+ def.parent(),
+ LifetimeElisionKind::AnonymousReportError,
+ );
+ let ty = match data {
+ TypeOrConstParamData::TypeParamData(_) => {
+ never!();
+ Ty::new_error(interner, ErrorGuaranteed)
+ }
+ TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
+ };
+ (ty, create_diagnostics(ctx.diagnostics))
+}
+
+pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>(
+ db: &'db dyn HirDatabase,
+ _: crate::db::HirDatabaseData,
+ _def: ConstParamId,
+) -> (Ty<'db>, Diagnostics) {
+ let interner = DbInterner::new_no_crate(db);
+ (Ty::new_error(interner, ErrorGuaranteed), None)
+}
+
+pub(crate) fn field_types_query<'db>(
+ db: &'db dyn HirDatabase,
variant_id: VariantId,
-) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
+) -> Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>> {
db.field_types_with_diagnostics(variant_id).0
}
/// Build the type of all specific fields of a struct or enum variant.
-pub(crate) fn field_types_with_diagnostics_query(
- db: &dyn HirDatabase,
+pub(crate) fn field_types_with_diagnostics_query<'db>(
+ db: &'db dyn HirDatabase,
variant_id: VariantId,
-) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics) {
+) -> (Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>>, Diagnostics) {
let var_data = variant_id.fields(db);
let fields = var_data.fields();
if fields.is_empty() {
@@ -938,7 +1473,6 @@ pub(crate) fn field_types_with_diagnostics_query(
VariantId::UnionId(it) => (it.resolver(db), it.into()),
VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()),
};
- let generics = generics(db, def);
let mut res = ArenaMap::default();
let mut ctx = TyLoweringContext::new(
db,
@@ -946,10 +1480,9 @@ pub(crate) fn field_types_with_diagnostics_query(
&var_data.store,
def,
LifetimeElisionKind::AnonymousReportError,
- )
- .with_type_param_mode(ParamLoweringMode::Variable);
- for (field_id, field_data) in fields.iter() {
- res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
+ );
+ for (field_id, field_data) in var_data.fields().iter() {
+ res.insert(field_id, EarlyBinder::bind(ctx.lower_ty(field_data.type_ref)));
}
(Arc::new(res), create_diagnostics(ctx.diagnostics))
}
@@ -962,17 +1495,16 @@ pub(crate) fn field_types_with_diagnostics_query(
/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
-pub(crate) fn generic_predicates_for_param_query(
- db: &dyn HirDatabase,
+#[tracing::instrument(skip(db), ret)]
+#[salsa::tracked(returns(ref), unsafe(non_update_return_type), cycle_result = generic_predicates_for_param_cycle_result)]
+pub(crate) fn generic_predicates_for_param<'db>(
+ db: &'db dyn HirDatabase,
def: GenericDefId,
param_id: TypeOrConstParamId,
assoc_name: Option<Name>,
-) -> GenericPredicates {
+) -> EarlyBinder<'db, Box<[Clause<'db>]>> {
let generics = generics(db, def);
- if generics.has_no_predicates() && generics.is_empty() {
- return GenericPredicates(None);
- }
-
+ let interner = DbInterner::new_no_crate(db);
let resolver = def.resolver(db);
let mut ctx = TyLoweringContext::new(
db,
@@ -980,11 +1512,10 @@ pub(crate) fn generic_predicates_for_param_query(
generics.store(),
def,
LifetimeElisionKind::AnonymousReportError,
- )
- .with_type_param_mode(ParamLoweringMode::Variable);
+ );
// we have to filter out all other predicates *first*, before attempting to lower them
- let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_>| match pred {
+ let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound, .. } => {
let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
@@ -1000,9 +1531,7 @@ pub(crate) fn generic_predicates_for_param_query(
let TypeRef::Path(path) = &ctx.store[path.type_ref()] else {
return false;
};
- let Some(pointee_sized) =
- LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate())
- else {
+ let Some(pointee_sized) = ctx.lang_items.PointeeSized else {
return false;
};
// Lower the path directly with `Resolver` instead of PathLoweringContext`
@@ -1015,7 +1544,8 @@ pub(crate) fn generic_predicates_for_param_query(
}
}();
if lower {
- ctx.lower_where_predicate(pred, true).for_each(drop);
+ ctx.lower_where_predicate(pred, true, &generics, PredicateFilter::All)
+ .for_each(drop);
}
return false;
}
@@ -1033,8 +1563,8 @@ pub(crate) fn generic_predicates_for_param_query(
return false;
};
- all_super_traits(db, tr).iter().any(|tr| {
- tr.trait_items(db).items.iter().any(|(name, item)| {
+ rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| {
+ tr.0.trait_items(db).items.iter().any(|(name, item)| {
matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
})
})
@@ -1051,261 +1581,448 @@ pub(crate) fn generic_predicates_for_param_query(
ctx.store = maybe_parent_generics.store();
for pred in maybe_parent_generics.where_predicates() {
if predicate(pred, &mut ctx) {
- predicates.extend(
- ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p)),
- );
+ predicates.extend(ctx.lower_where_predicate(
+ pred,
+ true,
+ maybe_parent_generics,
+ PredicateFilter::All,
+ ));
}
}
}
- let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
- if !subst.is_empty(Interner) {
+ let args = GenericArgs::identity_for_item(interner, def.into());
+ if !args.is_empty() {
let explicitly_unsized_tys = ctx.unsized_types;
if let Some(implicitly_sized_predicates) = implicitly_sized_clauses(
db,
+ ctx.lang_items,
param_id.parent,
&explicitly_unsized_tys,
- &subst,
- &resolver,
+ &args,
) {
- predicates.extend(
- implicitly_sized_predicates
- .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
- );
+ predicates.extend(implicitly_sized_predicates);
};
}
- GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
+ EarlyBinder::bind(predicates.into_boxed_slice())
}
-pub(crate) fn generic_predicates_for_param_cycle_result(
- _db: &dyn HirDatabase,
+pub(crate) fn generic_predicates_for_param_cycle_result<'db>(
+ _db: &'db dyn HirDatabase,
_def: GenericDefId,
_param_id: TypeOrConstParamId,
_assoc_name: Option<Name>,
-) -> GenericPredicates {
- GenericPredicates(None)
+) -> EarlyBinder<'db, Box<[Clause<'db>]>> {
+ EarlyBinder::bind(Box::new([]))
}
-pub(crate) fn trait_environment_for_body_query(
- db: &dyn HirDatabase,
- def: DefWithBodyId,
-) -> Arc<TraitEnvironment> {
- let Some(def) = def.as_generic_def_id(db) else {
- let krate = def.module(db).krate();
- return TraitEnvironment::empty(krate);
- };
- db.trait_environment(def)
+#[inline]
+pub(crate) fn type_alias_bounds<'db>(
+ db: &'db dyn HirDatabase,
+ type_alias: TypeAliasId,
+) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+ type_alias_bounds_with_diagnostics(db, type_alias).0.as_ref().map_bound(|it| &**it)
}
-pub(crate) fn trait_environment_query(
- db: &dyn HirDatabase,
- def: GenericDefId,
-) -> Arc<TraitEnvironment> {
- let generics = generics(db, def);
- if generics.has_no_predicates() && generics.is_empty() {
- return TraitEnvironment::empty(def.krate(db));
- }
-
- let resolver = def.resolver(db);
+#[salsa::tracked(returns(ref), unsafe(non_update_return_type))]
+pub fn type_alias_bounds_with_diagnostics<'db>(
+ db: &'db dyn HirDatabase,
+ type_alias: TypeAliasId,
+) -> (EarlyBinder<'db, Box<[Clause<'db>]>>, Diagnostics) {
+ let type_alias_data = db.type_alias_signature(type_alias);
+ let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
let mut ctx = TyLoweringContext::new(
db,
&resolver,
- generics.store(),
- def,
+ &type_alias_data.store,
+ type_alias.into(),
LifetimeElisionKind::AnonymousReportError,
- )
- .with_type_param_mode(ParamLoweringMode::Placeholder);
- let mut traits_in_scope = Vec::new();
- let mut clauses = Vec::new();
- for maybe_parent_generics in
- std::iter::successors(Some(&generics), |generics| generics.parent_generics())
- {
- ctx.store = maybe_parent_generics.store();
- for pred in maybe_parent_generics.where_predicates() {
- for pred in ctx.lower_where_predicate(pred, false) {
- if let WhereClause::Implemented(tr) = pred.skip_binders() {
- traits_in_scope
- .push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
- }
- let program_clause: Binders<DomainGoal> =
- pred.map(|pred| pred.into_from_env_goal(Interner).cast(Interner));
- clauses.push(program_clause);
- }
- }
- }
+ );
+ let interner = ctx.interner;
+ let def_id = type_alias.into();
- if let Some(trait_id) = def.assoc_trait_container(db) {
- // add `Self: Trait<T1, T2, ...>` to the environment in trait
- // function default implementations (and speculative code
- // inside consts or type aliases)
- cov_mark::hit!(trait_self_implements_self);
- let substs = TyBuilder::placeholder_subst(db, trait_id);
- let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
- let pred = WhereClause::Implemented(trait_ref);
- clauses.push(Binders::empty(
- Interner,
- pred.cast::<DomainGoal>(Interner).into_from_env_goal(Interner),
- ));
+ let item_args = GenericArgs::identity_for_item(interner, def_id);
+ let interner_ty = Ty::new_projection_from_args(interner, def_id, item_args);
+
+ let mut bounds = Vec::new();
+ for bound in &type_alias_data.bounds {
+ ctx.lower_type_bound(bound, interner_ty, false).for_each(|pred| {
+ bounds.push(pred);
+ });
}
- let subst = generics.placeholder_subst(db);
- if !subst.is_empty(Interner) {
- let explicitly_unsized_tys = ctx.unsized_types;
- if let Some(implicitly_sized_clauses) =
- implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
- {
- clauses.extend(implicitly_sized_clauses.map(|pred| {
- Binders::empty(
- Interner,
- pred.into_from_env_goal(Interner).cast::<DomainGoal>(Interner),
- )
- }));
+ if !ctx.unsized_types.contains(&interner_ty) {
+ let sized_trait = ctx.lang_items.Sized;
+ if let Some(sized_trait) = sized_trait {
+ let trait_ref = TraitRef::new_from_args(
+ interner,
+ sized_trait.into(),
+ GenericArgs::new_from_iter(interner, [interner_ty.into()]),
+ );
+ bounds.push(trait_ref.upcast(interner));
};
}
- let clauses = chalk_ir::ProgramClauses::from_iter(
- Interner,
- clauses.into_iter().map(|g| {
- chalk_ir::ProgramClause::new(
- Interner,
- chalk_ir::ProgramClauseData(g.map(|g| chalk_ir::ProgramClauseImplication {
- consequence: g,
- conditions: chalk_ir::Goals::empty(Interner),
- constraints: chalk_ir::Constraints::empty(Interner),
- priority: chalk_ir::ClausePriority::High,
- })),
- )
- }),
- );
- let env = chalk_ir::Environment { clauses };
-
- TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
+ (EarlyBinder::bind(bounds.into_boxed_slice()), create_diagnostics(ctx.diagnostics))
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericPredicates(Option<Arc<[Binders<QuantifiedWhereClause>]>>);
+pub struct GenericPredicates<'db> {
+ // The order is the following: first, if `parent_is_trait == true`, comes the implicit trait predicate for the
+ // parent. Then come the explicit predicates for the parent, then the explicit trait predicate for the child,
+ // then the implicit trait predicate for the child, if `is_trait` is `true`.
+ predicates: EarlyBinder<'db, Box<[Clause<'db>]>>,
+ own_predicates_start: u32,
+ is_trait: bool,
+ parent_is_trait: bool,
+}
+
+#[salsa::tracked]
+impl<'db> GenericPredicates<'db> {
+ /// Resolve the where clause(s) of an item with generics.
+ ///
+ /// Diagnostics are computed only for this item's predicates, not for parents.
+ #[salsa::tracked(returns(ref), unsafe(non_update_return_type))]
+ pub fn query_with_diagnostics(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+ ) -> (GenericPredicates<'db>, Diagnostics) {
+ generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true)
+ }
+}
+
+impl<'db> GenericPredicates<'db> {
+ #[inline]
+ pub fn query(db: &'db dyn HirDatabase, def: GenericDefId) -> &'db GenericPredicates<'db> {
+ &Self::query_with_diagnostics(db, def).0
+ }
+
+ #[inline]
+ pub fn query_all(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+ ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+ Self::query(db, def).all_predicates()
+ }
+
+ #[inline]
+ pub fn query_own(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+ ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+ Self::query(db, def).own_predicates()
+ }
-impl ops::Deref for GenericPredicates {
- type Target = [Binders<crate::QuantifiedWhereClause>];
+ #[inline]
+ pub fn query_explicit(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+ ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+ Self::query(db, def).explicit_predicates()
+ }
+
+ #[inline]
+ pub fn all_predicates(&self) -> EarlyBinder<'db, &[Clause<'db>]> {
+ self.predicates.as_ref().map_bound(|it| &**it)
+ }
- fn deref(&self) -> &Self::Target {
- self.0.as_deref().unwrap_or(&[])
+ #[inline]
+ pub fn own_predicates(&self) -> EarlyBinder<'db, &[Clause<'db>]> {
+ self.predicates.as_ref().map_bound(|it| &it[self.own_predicates_start as usize..])
+ }
+
+ /// Returns the predicates, minus the implicit `Self: Trait` predicate for a trait.
+ #[inline]
+ pub fn explicit_predicates(&self) -> EarlyBinder<'db, &[Clause<'db>]> {
+ self.predicates.as_ref().map_bound(|it| {
+ &it[usize::from(self.parent_is_trait)..it.len() - usize::from(self.is_trait)]
+ })
}
}
-/// Resolve the where clause(s) of an item with generics.
-pub(crate) fn generic_predicates_query(
+pub(crate) fn trait_environment_for_body_query(
db: &dyn HirDatabase,
+ def: DefWithBodyId,
+) -> Arc<TraitEnvironment<'_>> {
+ let Some(def) = def.as_generic_def_id(db) else {
+ let krate = def.module(db).krate();
+ return TraitEnvironment::empty(krate);
+ };
+ db.trait_environment(def)
+}
+
+pub(crate) fn trait_environment_query<'db>(
+ db: &'db dyn HirDatabase,
def: GenericDefId,
-) -> GenericPredicates {
- generic_predicates_filtered_by(db, def, |_, _| true).0
+) -> Arc<TraitEnvironment<'db>> {
+ let module = def.module(db);
+ let interner = DbInterner::new_with(db, module.krate());
+ let predicates = GenericPredicates::query_all(db, def);
+ let traits_in_scope = predicates
+ .iter_identity_copied()
+ .filter_map(|pred| match pred.kind().skip_binder() {
+ ClauseKind::Trait(tr) => Some((tr.self_ty(), tr.def_id().0)),
+ _ => None,
+ })
+ .collect();
+ let clauses = rustc_type_ir::elaborate::elaborate(interner, predicates.iter_identity_copied());
+ let clauses = Clauses::new_from_iter(interner, clauses);
+ let env = ParamEnv { clauses };
+
+ // FIXME: We should normalize projections here, like rustc does.
+
+ TraitEnvironment::new(module.krate(), module.containing_block(), traits_in_scope, env)
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(crate) enum PredicateFilter {
+ SelfTrait,
+ All,
}
/// Resolve the where clause(s) of an item with generics,
/// with a given filter
-fn generic_predicates_filtered_by<F>(
- db: &dyn HirDatabase,
+#[tracing::instrument(skip(db, filter), ret)]
+pub(crate) fn generic_predicates_filtered_by<'db, F>(
+ db: &'db dyn HirDatabase,
def: GenericDefId,
+ predicate_filter: PredicateFilter,
filter: F,
-) -> (GenericPredicates, Diagnostics)
+) -> (GenericPredicates<'db>, Diagnostics)
where
- F: Fn(&WherePredicate, GenericDefId) -> bool,
+ F: Fn(GenericDefId) -> bool,
{
let generics = generics(db, def);
- if generics.has_no_predicates() && generics.is_empty() {
- return (GenericPredicates(None), None);
- }
-
let resolver = def.resolver(db);
+ let interner = DbInterner::new_no_crate(db);
let mut ctx = TyLoweringContext::new(
db,
&resolver,
generics.store(),
def,
LifetimeElisionKind::AnonymousReportError,
- )
- .with_type_param_mode(ParamLoweringMode::Variable);
+ );
+ let sized_trait = ctx.lang_items.Sized;
let mut predicates = Vec::new();
- for maybe_parent_generics in
+ let all_generics =
std::iter::successors(Some(&generics), |generics| generics.parent_generics())
- {
- ctx.store = maybe_parent_generics.store();
- for pred in maybe_parent_generics.where_predicates() {
- if filter(pred, maybe_parent_generics.def()) {
- // We deliberately use `generics` and not `maybe_parent_generics` here. This is not a mistake!
- // If we use the parent generics
- predicates.extend(
- ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p)),
+ .collect::<ArrayVec<_, 2>>();
+ let mut is_trait = false;
+ let mut parent_is_trait = false;
+ if all_generics.len() > 1 {
+ add_implicit_trait_predicate(
+ interner,
+ all_generics.last().unwrap().def(),
+ predicate_filter,
+ &mut predicates,
+ &mut parent_is_trait,
+ );
+ }
+ // We need to lower parent predicates first - see the comment below lowering of implicit `Sized` predicates
+ // for why.
+ let mut own_predicates_start = 0;
+ for &maybe_parent_generics in all_generics.iter().rev() {
+ let current_def_predicates_start = predicates.len();
+ // Collect only diagnostics from the child, not including parents.
+ ctx.diagnostics.clear();
+
+ if filter(maybe_parent_generics.def()) {
+ ctx.store = maybe_parent_generics.store();
+ for pred in maybe_parent_generics.where_predicates() {
+ tracing::debug!(?pred);
+ predicates.extend(ctx.lower_where_predicate(
+ pred,
+ false,
+ maybe_parent_generics,
+ predicate_filter,
+ ));
+ }
+
+ push_const_arg_has_type_predicates(db, &mut predicates, maybe_parent_generics);
+
+ if let Some(sized_trait) = sized_trait {
+ let mut add_sized_clause = |param_idx, param_id, param_data| {
+ let (
+ GenericParamId::TypeParamId(param_id),
+ GenericParamDataRef::TypeParamData(param_data),
+ ) = (param_id, param_data)
+ else {
+ return;
+ };
+
+ if param_data.provenance == TypeParamProvenance::TraitSelf {
+ return;
+ }
+
+ let param_ty = Ty::new_param(interner, param_id, param_idx);
+ if ctx.unsized_types.contains(&param_ty) {
+ return;
+ }
+ let trait_ref = TraitRef::new_from_args(
+ interner,
+ sized_trait.into(),
+ GenericArgs::new_from_iter(interner, [param_ty.into()]),
+ );
+ let clause = Clause(Predicate::new(
+ interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+ trait_ref,
+ polarity: rustc_type_ir::PredicatePolarity::Positive,
+ }),
+ )),
+ ));
+ predicates.push(clause);
+ };
+ let parent_params_len = maybe_parent_generics.len_parent();
+ maybe_parent_generics.iter_self().enumerate().for_each(
+ |(param_idx, (param_id, param_data))| {
+ add_sized_clause(
+ (param_idx + parent_params_len) as u32,
+ param_id,
+ param_data,
+ );
+ },
);
}
+
+ // We do not clear `ctx.unsized_types`, as the `?Sized` clause of a child (e.g. an associated type) can
+ // be declared on the parent (e.g. the trait). It is nevertheless fine to register the implicit `Sized`
+ // predicates before lowering the child, as a child cannot define a `?Sized` predicate for its parent.
+ // But we do have to lower the parent first.
+ }
+
+ if maybe_parent_generics.def() == def {
+ own_predicates_start = current_def_predicates_start as u32;
}
}
- if !generics.is_empty() {
- let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
- let explicitly_unsized_tys = ctx.unsized_types;
- if let Some(implicitly_sized_predicates) =
- implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
+ add_implicit_trait_predicate(interner, def, predicate_filter, &mut predicates, &mut is_trait);
+
+ let diagnostics = create_diagnostics(ctx.diagnostics);
+ let predicates = GenericPredicates {
+ own_predicates_start,
+ is_trait,
+ parent_is_trait,
+ predicates: EarlyBinder::bind(predicates.into_boxed_slice()),
+ };
+ return (predicates, diagnostics);
+
+ fn add_implicit_trait_predicate<'db>(
+ interner: DbInterner<'db>,
+ def: GenericDefId,
+ predicate_filter: PredicateFilter,
+ predicates: &mut Vec<Clause<'db>>,
+ set_is_trait: &mut bool,
+ ) {
+ // For traits, add `Self: Trait` predicate. This is
+ // not part of the predicates that a user writes, but it
+ // is something that one must prove in order to invoke a
+ // method or project an associated type.
+ //
+ // In the chalk setup, this predicate is not part of the
+ // "predicates" for a trait item. But it is useful in
+ // rustc because if you directly (e.g.) invoke a trait
+ // method like `Trait::method(...)`, you must naturally
+ // prove that the trait applies to the types that were
+ // used, and adding the predicate into this list ensures
+ // that this is done.
+ if let GenericDefId::TraitId(def_id) = def
+ && predicate_filter == PredicateFilter::All
{
- predicates.extend(
- implicitly_sized_predicates
- .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
- );
- };
+ *set_is_trait = true;
+ predicates.push(TraitRef::identity(interner, def_id.into()).upcast(interner));
+ }
}
+}
- (
- GenericPredicates(predicates.is_empty().not().then(|| predicates.into())),
- create_diagnostics(ctx.diagnostics),
- )
+fn push_const_arg_has_type_predicates<'db>(
+ db: &'db dyn HirDatabase,
+ predicates: &mut Vec<Clause<'db>>,
+ generics: &Generics,
+) {
+ let interner = DbInterner::new_no_crate(db);
+ let const_params_offset = generics.len_parent() + generics.len_lifetimes_self();
+ for (param_index, (param_idx, param_data)) in generics.iter_self_type_or_consts().enumerate() {
+ if !matches!(param_data, TypeOrConstParamData::ConstParamData(_)) {
+ continue;
+ }
+
+ let param_id = ConstParamId::from_unchecked(TypeOrConstParamId {
+ parent: generics.def(),
+ local_id: param_idx,
+ });
+ predicates.push(Clause(
+ ClauseKind::ConstArgHasType(
+ Const::new_param(
+ interner,
+ ParamConst { id: param_id, index: (param_index + const_params_offset) as u32 },
+ ),
+ db.const_param_ty_ns(param_id),
+ )
+ .upcast(interner),
+ ));
+ }
}
/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
/// Exception is Self of a trait def.
-fn implicitly_sized_clauses<'db, 'a, 'subst: 'a>(
+fn implicitly_sized_clauses<'a, 'subst, 'db>(
db: &'db dyn HirDatabase,
+ lang_items: &LangItems,
def: GenericDefId,
- explicitly_unsized_tys: &'a FxHashSet<Ty>,
- substitution: &'subst Substitution,
- resolver: &Resolver<'db>,
-) -> Option<impl Iterator<Item = WhereClause>> {
- let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id)?;
+ explicitly_unsized_tys: &'a FxHashSet<Ty<'db>>,
+ args: &'subst GenericArgs<'db>,
+) -> Option<impl Iterator<Item = Clause<'db>> + Captures<'a> + Captures<'subst>> {
+ let interner = DbInterner::new_no_crate(db);
+ let sized_trait = lang_items.Sized?;
let trait_self_idx = trait_self_param_idx(db, def);
Some(
- substitution
- .iter(Interner)
+ args.iter()
.enumerate()
.filter_map(
move |(idx, generic_arg)| {
if Some(idx) == trait_self_idx { None } else { Some(generic_arg) }
},
)
- .filter_map(|generic_arg| generic_arg.ty(Interner))
- .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty))
+ .filter_map(|generic_arg| generic_arg.as_type())
+ .filter(move |self_ty| !explicitly_unsized_tys.contains(self_ty))
.map(move |self_ty| {
- WhereClause::Implemented(TraitRef {
- trait_id: sized_trait,
- substitution: Substitution::from1(Interner, self_ty.clone()),
- })
+ let trait_ref = TraitRef::new_from_args(
+ interner,
+ sized_trait.into(),
+ GenericArgs::new_from_iter(interner, [self_ty.into()]),
+ );
+ Clause(Predicate::new(
+ interner,
+ Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+ trait_ref,
+ polarity: rustc_type_ir::PredicatePolarity::Positive,
+ }),
+ )),
+ ))
}),
)
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericDefaults(Option<Arc<[Binders<crate::GenericArg>]>>);
-
-impl ops::Deref for GenericDefaults {
- type Target = [Binders<crate::GenericArg>];
+pub struct GenericDefaults<'db>(Option<Arc<[Option<EarlyBinder<'db, GenericArg<'db>>>]>>);
- fn deref(&self) -> &Self::Target {
- self.0.as_deref().unwrap_or(&[])
+impl<'db> GenericDefaults<'db> {
+ #[inline]
+ pub fn get(&self, idx: usize) -> Option<EarlyBinder<'db, GenericArg<'db>>> {
+ self.0.as_ref()?[idx]
}
}
-pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults {
+pub(crate) fn generic_defaults_query(
+ db: &dyn HirDatabase,
+ def: GenericDefId,
+) -> GenericDefaults<'_> {
db.generic_defaults_with_diagnostics(def).0
}
@@ -1315,7 +2032,7 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) ->
pub(crate) fn generic_defaults_with_diagnostics_query(
db: &dyn HirDatabase,
def: GenericDefId,
-) -> (GenericDefaults, Diagnostics) {
+) -> (GenericDefaults<'_>, Diagnostics) {
let generic_params = generics(db, def);
if generic_params.is_empty() {
return (GenericDefaults(None), None);
@@ -1329,23 +2046,22 @@ pub(crate) fn generic_defaults_with_diagnostics_query(
def,
LifetimeElisionKind::AnonymousReportError,
)
- .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
- .with_type_param_mode(ParamLoweringMode::Variable);
+ .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed);
let mut idx = 0;
let mut has_any_default = false;
let mut defaults = generic_params
.iter_parents_with_store()
- .map(|((id, p), store)| {
+ .map(|((_id, p), store)| {
ctx.store = store;
- let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
+ let (result, has_default) = handle_generic_param(&mut ctx, idx, p);
has_any_default |= has_default;
idx += 1;
result
})
.collect::<Vec<_>>();
ctx.diagnostics.clear(); // Don't include diagnostics from the parent.
- defaults.extend(generic_params.iter_self().map(|(id, p)| {
- let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
+ defaults.extend(generic_params.iter_self().map(|(_id, p)| {
+ let (result, has_default) = handle_generic_param(&mut ctx, idx, p);
has_any_default |= has_default;
idx += 1;
result
@@ -1358,47 +2074,26 @@ pub(crate) fn generic_defaults_with_diagnostics_query(
};
return (defaults, diagnostics);
- fn handle_generic_param(
- ctx: &mut TyLoweringContext<'_>,
+ fn handle_generic_param<'db>(
+ ctx: &mut TyLoweringContext<'db, '_>,
idx: usize,
- id: GenericParamId,
p: GenericParamDataRef<'_>,
- generic_params: &Generics,
- ) -> (Binders<crate::GenericArg>, bool) {
- let binders = variable_kinds_from_iter(ctx.db, generic_params.iter_id().take(idx));
+ ) -> (Option<EarlyBinder<'db, GenericArg<'db>>>, bool) {
+ ctx.lowering_param_default(idx as u32);
match p {
GenericParamDataRef::TypeParamData(p) => {
- let ty = p.default.as_ref().map_or_else(
- || TyKind::Error.intern(Interner),
- |ty| {
- // Each default can only refer to previous parameters.
- // Type variable default referring to parameter coming
- // after it is forbidden (FIXME: report diagnostic)
- fallback_bound_vars(ctx.lower_ty(*ty), idx)
- },
- );
- (Binders::new(binders, ty.cast(Interner)), p.default.is_some())
+ let ty = p.default.map(|ty| ctx.lower_ty(ty));
+ (ty.map(|ty| EarlyBinder::bind(ty.into())), p.default.is_some())
}
GenericParamDataRef::ConstParamData(p) => {
- let GenericParamId::ConstParamId(id) = id else {
- unreachable!("Unexpected lifetime or type argument")
- };
-
- let mut val = p.default.as_ref().map_or_else(
- || unknown_const_as_generic(ctx.db.const_param_ty(id)),
- |c| {
- let param_ty = ctx.lower_ty(p.ty);
- let c = ctx.lower_const(c, param_ty);
- c.cast(Interner)
- },
- );
- // Each default can only refer to previous parameters, see above.
- val = fallback_bound_vars(val, idx);
- (Binders::new(binders, val), p.default.is_some())
- }
- GenericParamDataRef::LifetimeParamData(_) => {
- (Binders::new(binders, error_lifetime().cast(Interner)), false)
+ let val = p.default.map(|c| {
+ let param_ty = ctx.lower_ty(p.ty);
+ let c = ctx.lower_const(c, param_ty);
+ c.into()
+ });
+ (val.map(EarlyBinder::bind), p.default.is_some())
}
+ GenericParamDataRef::LifetimeParamData(_) => (None, false),
}
}
}
@@ -1406,21 +2101,36 @@ pub(crate) fn generic_defaults_with_diagnostics_query(
pub(crate) fn generic_defaults_with_diagnostics_cycle_result(
_db: &dyn HirDatabase,
_def: GenericDefId,
-) -> (GenericDefaults, Diagnostics) {
+) -> (GenericDefaults<'_>, Diagnostics) {
(GenericDefaults(None), None)
}
-fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
+/// Build the signature of a callable item (function, struct or enum variant).
+pub(crate) fn callable_item_signature_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: CallableDefId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
+ match def {
+ CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
+ CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
+ CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
+ }
+}
+
+fn fn_sig_for_fn<'db>(
+ db: &'db dyn HirDatabase,
+ def: FunctionId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
let data = db.function_signature(def);
let resolver = def.resolver(db);
+ let interner = DbInterner::new_no_crate(db);
let mut ctx_params = TyLoweringContext::new(
db,
&resolver,
&data.store,
def.into(),
LifetimeElisionKind::for_fn_params(&data),
- )
- .with_type_param_mode(ParamLoweringMode::Variable);
+ );
let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
let ret = match data.ret_type {
@@ -1430,419 +2140,287 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
&resolver,
&data.store,
def.into(),
- LifetimeElisionKind::for_fn_ret(),
+ LifetimeElisionKind::for_fn_ret(interner),
)
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
- .with_type_param_mode(ParamLoweringMode::Variable);
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
ctx_ret.lower_ty(ret_type)
}
- None => TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
+ None => Ty::new_tup(interner, &[]),
};
- let generics = generics(db, def.into());
- let sig = CallableSig::from_params_and_return(
- params,
- ret,
- data.is_varargs(),
- if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
- data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
- );
- make_binders(db, &generics, sig)
-}
-/// Build the declared type of a function. This should not need to look at the
-/// function body.
-fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
- let generics = generics(db, def.into());
- let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
- make_binders(
- db,
- &generics,
- TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(Interner),
- )
+ let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret)));
+ // If/when we track late bound vars, we need to switch this to not be `dummy`
+ EarlyBinder::bind(rustc_type_ir::Binder::dummy(FnSig {
+ abi: data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
+ c_variadic: data.is_varargs(),
+ safety: if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
+ inputs_and_output,
+ }))
}
-/// Build the declared type of a const.
-fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
- let data = db.const_signature(def);
- let generics = generics(db, def.into());
- let resolver = def.resolver(db);
- let parent = def.loc(db).container;
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &data.store,
- def.into(),
- LifetimeElisionKind::for_const(parent),
- )
- .with_type_param_mode(ParamLoweringMode::Variable);
-
- make_binders(db, &generics, ctx.lower_ty(data.type_ref))
+fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> {
+ let interner = DbInterner::new_no_crate(db);
+ let args = GenericArgs::identity_for_item(interner, adt.into());
+ let ty = Ty::new_adt(interner, adt, args);
+ EarlyBinder::bind(ty)
}
-/// Build the declared type of a static.
-fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
- let data = db.static_signature(def);
- let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &data.store,
- def.into(),
- LifetimeElisionKind::Elided(static_lifetime()),
- );
-
- Binders::empty(Interner, ctx.lower_ty(data.type_ref))
-}
-
-fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
+fn fn_sig_for_struct_constructor<'db>(
+ db: &'db dyn HirDatabase,
+ def: StructId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
let field_tys = db.field_types(def.into());
- let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone());
- let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
- Binders::new(
- binders,
- CallableSig::from_params_and_return(params, ret, false, Safety::Safe, FnAbi::RustCall),
- )
+ let params = field_tys.iter().map(|(_, ty)| ty.skip_binder());
+ let ret = type_for_adt(db, def.into()).skip_binder();
+
+ let inputs_and_output =
+ Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret)));
+ EarlyBinder::bind(Binder::dummy(FnSig {
+ abi: FnAbi::RustCall,
+ c_variadic: false,
+ safety: Safety::Safe,
+ inputs_and_output,
+ }))
}
-/// Build the type of a tuple struct constructor.
-fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Option<Binders<Ty>> {
- let struct_data = def.fields(db);
- match struct_data.shape {
- FieldsShape::Record => None,
- FieldsShape::Unit => Some(type_for_adt(db, def.into())),
- FieldsShape::Tuple => {
- let generics = generics(db, AdtId::from(def).into());
- let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
- Some(make_binders(
- db,
- &generics,
- TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner),
- ))
- }
- }
-}
-
-fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig {
+fn fn_sig_for_enum_variant_constructor<'db>(
+ db: &'db dyn HirDatabase,
+ def: EnumVariantId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
let field_tys = db.field_types(def.into());
- let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone());
+ let params = field_tys.iter().map(|(_, ty)| ty.skip_binder());
let parent = def.lookup(db).parent;
- let (ret, binders) = type_for_adt(db, parent.into()).into_value_and_skipped_binders();
- Binders::new(
- binders,
- CallableSig::from_params_and_return(params, ret, false, Safety::Safe, FnAbi::RustCall),
- )
-}
-
-/// Build the type of a tuple enum variant constructor.
-fn type_for_enum_variant_constructor(
- db: &dyn HirDatabase,
- def: EnumVariantId,
-) -> Option<Binders<Ty>> {
- let e = def.lookup(db).parent;
- match def.fields(db).shape {
- FieldsShape::Record => None,
- FieldsShape::Unit => Some(type_for_adt(db, e.into())),
- FieldsShape::Tuple => {
- let generics = generics(db, e.into());
- let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
- Some(make_binders(
- db,
- &generics,
- TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs)
- .intern(Interner),
- ))
- }
- }
-}
-
-#[salsa_macros::tracked(cycle_result = type_for_adt_cycle_result)]
-fn type_for_adt_tracked(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
- type_for_adt(db, adt)
-}
-
-fn type_for_adt_cycle_result(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
- let generics = generics(db, adt.into());
- make_binders(db, &generics, TyKind::Error.intern(Interner))
+ let ret = type_for_adt(db, parent.into()).skip_binder();
+
+ let inputs_and_output =
+ Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret)));
+ EarlyBinder::bind(Binder::dummy(FnSig {
+ abi: FnAbi::RustCall,
+ c_variadic: false,
+ safety: Safety::Safe,
+ inputs_and_output,
+ }))
}
-fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
- let generics = generics(db, adt.into());
- let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
- let ty = TyKind::Adt(crate::AdtId(adt), subst).intern(Interner);
- make_binders(db, &generics, ty)
-}
-
-pub(crate) fn type_for_type_alias_with_diagnostics_query(
- db: &dyn HirDatabase,
- t: TypeAliasId,
-) -> (Binders<Ty>, Diagnostics) {
- let generics = generics(db, t.into());
- let type_alias_data = db.type_alias_signature(t);
- let mut diags = None;
- let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) {
- TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)
- } else {
- let resolver = t.resolver(db);
- let alias = db.type_alias_signature(t);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &alias.store,
- t.into(),
- LifetimeElisionKind::AnonymousReportError,
- )
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
- .with_type_param_mode(ParamLoweringMode::Variable);
- let res = alias
- .ty
- .map(|type_ref| ctx.lower_ty(type_ref))
- .unwrap_or_else(|| TyKind::Error.intern(Interner));
- diags = create_diagnostics(ctx.diagnostics);
- res
- };
-
- (make_binders(db, &generics, inner), diags)
-}
-
-pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result(
- db: &dyn HirDatabase,
- adt: TypeAliasId,
-) -> (Binders<Ty>, Diagnostics) {
- let generics = generics(db, adt.into());
- (make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum TyDefId {
- BuiltinType(BuiltinType),
- AdtId(AdtId),
- TypeAliasId(TypeAliasId),
-}
-impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId);
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
-pub enum ValueTyDefId {
- FunctionId(FunctionId),
- StructId(StructId),
- UnionId(UnionId),
- EnumVariantId(EnumVariantId),
- ConstId(ConstId),
- StaticId(StaticId),
-}
-impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
-
-impl ValueTyDefId {
- pub(crate) fn to_generic_def_id(self, db: &dyn HirDatabase) -> GenericDefId {
- match self {
- Self::FunctionId(id) => id.into(),
- Self::StructId(id) => id.into(),
- Self::UnionId(id) => id.into(),
- Self::EnumVariantId(var) => var.lookup(db).parent.into(),
- Self::ConstId(id) => id.into(),
- Self::StaticId(id) => id.into(),
- }
- }
-}
-
-/// Build the declared type of an item. This depends on the namespace; e.g. for
-/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
-/// the constructor function `(usize) -> Foo` which lives in the values
-/// namespace.
-pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> {
- match def {
- TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)),
- TyDefId::AdtId(it) => type_for_adt_tracked(db, it),
- TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
+// FIXME(next-solver): should merge this with `explicit_item_bounds` in some way
+pub(crate) fn associated_ty_item_bounds<'db>(
+ db: &'db dyn HirDatabase,
+ type_alias: TypeAliasId,
+) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> {
+ let type_alias_data = db.type_alias_signature(type_alias);
+ let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
+ let interner = DbInterner::new_no_crate(db);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &type_alias_data.store,
+ type_alias.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ );
+ // FIXME: we should never create non-existential predicates in the first place
+ // For now, use an error type so we don't run into dummy binder issues
+ let self_ty = Ty::new_error(interner, ErrorGuaranteed);
+
+ let mut bounds = Vec::new();
+ for bound in &type_alias_data.bounds {
+ ctx.lower_type_bound(bound, self_ty, false).for_each(|pred| {
+ if let Some(bound) = pred
+ .kind()
+ .map_bound(|c| match c {
+ rustc_type_ir::ClauseKind::Trait(t) => {
+ let id = t.def_id();
+ let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO);
+ if is_auto {
+ Some(ExistentialPredicate::AutoTrait(t.def_id()))
+ } else {
+ Some(ExistentialPredicate::Trait(ExistentialTraitRef::new_from_args(
+ interner,
+ t.def_id(),
+ GenericArgs::new_from_iter(
+ interner,
+ t.trait_ref.args.iter().skip(1),
+ ),
+ )))
+ }
+ }
+ rustc_type_ir::ClauseKind::Projection(p) => Some(
+ ExistentialPredicate::Projection(ExistentialProjection::new_from_args(
+ interner,
+ p.def_id(),
+ GenericArgs::new_from_iter(
+ interner,
+ p.projection_term.args.iter().skip(1),
+ ),
+ p.term,
+ )),
+ ),
+ rustc_type_ir::ClauseKind::TypeOutlives(_) => None,
+ rustc_type_ir::ClauseKind::RegionOutlives(_)
+ | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
+ | rustc_type_ir::ClauseKind::WellFormed(_)
+ | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
+ | rustc_type_ir::ClauseKind::HostEffect(_)
+ | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
+ })
+ .transpose()
+ {
+ bounds.push(bound);
+ }
+ });
}
-}
-pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Option<Binders<Ty>> {
- match def {
- ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)),
- ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
- ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())),
- ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
- ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)),
- ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)),
+ if !ctx.unsized_types.contains(&self_ty)
+ && let Some(sized_trait) = ctx.lang_items.Sized
+ {
+ let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new(
+ interner,
+ sized_trait.into(),
+ [] as [GenericArg<'_>; 0],
+ )));
+ bounds.push(sized_clause);
}
-}
-pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> {
- db.impl_self_ty_with_diagnostics(impl_id).0
+ EarlyBinder::bind(BoundExistentialPredicates::new_from_iter(interner, bounds))
}
-pub(crate) fn impl_self_ty_with_diagnostics_query(
- db: &dyn HirDatabase,
- impl_id: ImplId,
-) -> (Binders<Ty>, Diagnostics) {
- let impl_data = db.impl_signature(impl_id);
- let resolver = impl_id.resolver(db);
- let generics = generics(db, impl_id.into());
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &impl_data.store,
- impl_id.into(),
- LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
- )
- .with_type_param_mode(ParamLoweringMode::Variable);
- (
- make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)),
- create_diagnostics(ctx.diagnostics),
- )
+pub(crate) fn associated_type_by_name_including_super_traits<'db>(
+ db: &'db dyn HirDatabase,
+ trait_ref: TraitRef<'db>,
+ name: &Name,
+) -> Option<(TraitRef<'db>, TypeAliasId)> {
+ let module = trait_ref.def_id.0.module(db);
+ let interner = DbInterner::new_with(db, module.krate());
+ rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| {
+ let trait_id = t.as_ref().skip_binder().def_id.0;
+ let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?;
+ Some((t.skip_binder(), assoc_type))
+ })
}
-pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
+pub fn associated_type_shorthand_candidates(
db: &dyn HirDatabase,
- impl_id: ImplId,
-) -> (Binders<Ty>, Diagnostics) {
- let generics = generics(db, impl_id.into());
- (make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
+ def: GenericDefId,
+ res: TypeNs,
+ mut cb: impl FnMut(&Name, TypeAliasId) -> bool,
+) -> Option<TypeAliasId> {
+ let interner = DbInterner::new_no_crate(db);
+ named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| {
+ cb(name, id).then_some(id)
+ })
}
-pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
- db.const_param_ty_with_diagnostics(def).0
-}
+#[tracing::instrument(skip(interner, check_alias))]
+fn named_associated_type_shorthand_candidates<'db, R>(
+ interner: DbInterner<'db>,
+ // If the type parameter is defined in an impl and we're in a method, there
+ // might be additional where clauses to consider
+ def: GenericDefId,
+ res: TypeNs,
+ assoc_name: Option<Name>,
+ mut check_alias: impl FnMut(&Name, TraitRef<'db>, TypeAliasId) -> Option<R>,
+) -> Option<R> {
+ let db = interner.db;
+ let mut search = |t: TraitRef<'db>| -> Option<R> {
+ let mut checked_traits = FxHashSet::default();
+ let mut check_trait = |trait_ref: TraitRef<'db>| {
+ let trait_id = trait_ref.def_id.0;
+ let name = &db.trait_signature(trait_id).name;
+ tracing::debug!(?trait_id, ?name);
+ if !checked_traits.insert(trait_id) {
+ return None;
+ }
+ let data = trait_id.trait_items(db);
-// returns None if def is a type arg
-pub(crate) fn const_param_ty_with_diagnostics_query(
- db: &dyn HirDatabase,
- def: ConstParamId,
-) -> (Ty, Diagnostics) {
- let (parent_data, store) = db.generic_params_and_store(def.parent());
- let data = &parent_data[def.local_id()];
- let resolver = def.parent().resolver(db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &store,
- def.parent(),
- LifetimeElisionKind::AnonymousReportError,
- );
- let ty = match data {
- TypeOrConstParamData::TypeParamData(_) => {
- never!();
- Ty::new(Interner, TyKind::Error)
+ tracing::debug!(?data.items);
+ for (name, assoc_id) in &data.items {
+ if let &AssocItemId::TypeAliasId(alias) = assoc_id
+ && let Some(ty) = check_alias(name, trait_ref, alias)
+ {
+ return Some(ty);
+ }
+ }
+ None
+ };
+ let mut stack: SmallVec<[_; 4]> = smallvec![t];
+ while let Some(trait_ref) = stack.pop() {
+ if let Some(alias) = check_trait(trait_ref) {
+ return Some(alias);
+ }
+ for pred in generic_predicates_filtered_by(
+ db,
+ GenericDefId::TraitId(trait_ref.def_id.0),
+ PredicateFilter::SelfTrait,
+ // We are likely in the midst of lowering generic predicates of `def`.
+ // So, if we allow `pred == def` we might fall into an infinite recursion.
+ // Actually, we have already checked for the case `pred == def` above as we started
+ // with a stack including `trait_id`
+ |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0),
+ )
+ .0
+ .predicates
+ .instantiate_identity()
+ {
+ tracing::debug!(?pred);
+ let sup_trait_ref = match pred.kind().skip_binder() {
+ rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref,
+ _ => continue,
+ };
+ let sup_trait_ref =
+ EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args);
+ stack.push(sup_trait_ref);
+ }
+ tracing::debug!(?stack);
}
- TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
- };
- (ty, create_diagnostics(ctx.diagnostics))
-}
-
-pub(crate) fn const_param_ty_with_diagnostics_cycle_result(
- _: &dyn HirDatabase,
- _: crate::db::HirDatabaseData,
- _: ConstParamId,
-) -> (Ty, Diagnostics) {
- (TyKind::Error.intern(Interner), None)
-}
-
-pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
- db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
-}
-pub(crate) fn impl_trait_with_diagnostics_query(
- db: &dyn HirDatabase,
- impl_id: ImplId,
-) -> Option<(Binders<TraitRef>, Diagnostics)> {
- let impl_data = db.impl_signature(impl_id);
- let resolver = impl_id.resolver(db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &impl_data.store,
- impl_id.into(),
- LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
- )
- .with_type_param_mode(ParamLoweringMode::Variable);
- let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
- let target_trait = impl_data.target_trait.as_ref()?;
- let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?);
- Some((trait_ref, create_diagnostics(ctx.diagnostics)))
-}
-
-pub(crate) fn return_type_impl_traits(
- db: &dyn HirDatabase,
- def: hir_def::FunctionId,
-) -> Option<Arc<Binders<ImplTraits>>> {
- // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
- let data = db.function_signature(def);
- let resolver = def.resolver(db);
- let mut ctx_ret =
- TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer)
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
- .with_type_param_mode(ParamLoweringMode::Variable);
- if let Some(ret_type) = data.ret_type {
- let _ret = ctx_ret.lower_ty(ret_type);
- }
- let generics = generics(db, def.into());
- let return_type_impl_traits =
- ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data };
- if return_type_impl_traits.impl_traits.is_empty() {
None
- } else {
- Some(Arc::new(make_binders(db, &generics, return_type_impl_traits)))
- }
-}
+ };
-pub(crate) fn type_alias_impl_traits(
- db: &dyn HirDatabase,
- def: hir_def::TypeAliasId,
-) -> Option<Arc<Binders<ImplTraits>>> {
- let data = db.type_alias_signature(def);
- let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &data.store,
- def.into(),
- LifetimeElisionKind::AnonymousReportError,
- )
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
- .with_type_param_mode(ParamLoweringMode::Variable);
- if let Some(type_ref) = data.ty {
- let _ty = ctx.lower_ty(type_ref);
- }
- let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data };
- if type_alias_impl_traits.impl_traits.is_empty() {
- None
- } else {
- let generics = generics(db, def.into());
- Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits)))
- }
-}
+ match res {
+ TypeNs::SelfType(impl_id) => {
+ let trait_ref = db.impl_trait(impl_id)?;
-pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
- match m {
- hir_def::type_ref::Mutability::Shared => Mutability::Not,
- hir_def::type_ref::Mutability::Mut => Mutability::Mut,
- }
-}
+ // FIXME(next-solver): same method in `lower` checks for impl or not
+ // Is that needed here?
-/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
-/// parameter whose index is `param_index`. A `BoundVar` is free when it appears after the
-/// generic parameter of `param_index`.
-fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
- s: T,
- param_index: usize,
-) -> T {
- let is_allowed = |index| (0..param_index).contains(&index);
-
- crate::fold_free_vars(
- s,
- |bound, binders| {
- if bound.index_if_innermost().is_none_or(is_allowed) {
- bound.shifted_in_from(binders).to_ty(Interner)
- } else {
- TyKind::Error.intern(Interner)
- }
- },
- |ty, bound, binders| {
- if bound.index_if_innermost().is_none_or(is_allowed) {
- bound.shifted_in_from(binders).to_const(Interner, ty)
- } else {
- unknown_const(ty)
+ // we're _in_ the impl -- the binders get added back later. Correct,
+ // but it would be nice to make this more explicit
+ search(trait_ref.skip_binder())
+ }
+ TypeNs::GenericParam(param_id) => {
+ // Handle `Self::Type` referring to own associated type in trait definitions
+ // This *must* be done first to avoid cycles with
+ // `generic_predicates_for_param`, but not sure that it's sufficient,
+ if let GenericDefId::TraitId(trait_id) = param_id.parent() {
+ let trait_name = &db.trait_signature(trait_id).name;
+ tracing::debug!(?trait_name);
+ let trait_generics = generics(db, trait_id.into());
+ tracing::debug!(?trait_generics);
+ if trait_generics[param_id.local_id()].is_trait_self() {
+ let args = GenericArgs::identity_for_item(interner, trait_id.into());
+ let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args);
+ tracing::debug!(?args, ?trait_ref);
+ return search(trait_ref);
+ }
}
- },
- )
+
+ let predicates =
+ generic_predicates_for_param(db, def, param_id.into(), assoc_name.clone());
+ predicates
+ .as_ref()
+ .iter_identity_copied()
+ .find_map(|pred| match pred.kind().skip_binder() {
+ rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate),
+ _ => None,
+ })
+ .and_then(|trait_predicate| {
+ let trait_ref = trait_predicate.trait_ref;
+ assert!(
+ !trait_ref.has_escaping_bound_vars(),
+ "FIXME unexpected higher-ranked trait bound"
+ );
+ search(trait_ref)
+ })
+ }
+ _ => None,
+ }
}