use arrayvec::ArrayVec;
use base_db::{CrateId, Edition};
-use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
+use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, Mutability, UniverseIndex};
use hir_def::{
item_scope::ItemScope, lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId,
ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
use stdx::never;
use crate::{
- autoderef,
+ autoderef::{self, AutoderefKind},
consteval::{self, ConstExt},
db::HirDatabase,
from_foreign_def_id,
+ infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
primitive::{self, FloatTy, IntTy, UintTy},
static_lifetime,
utils::all_super_traits,
- AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
- Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
+ AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, GenericArgData,
+ InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder,
+ TyExt, TyKind,
};
/// This is used as a key for indexing impls.
/// an `impl S`, but not `impl &S`. Hence, this will return `None` for
/// reference types and such.
pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> {
- let fp = match ty.kind(&Interner) {
+ let fp = match ty.kind(Interner) {
TyKind::Str => TyFingerprint::Str,
TyKind::Never => TyFingerprint::Never,
TyKind::Slice(..) => TyFingerprint::Slice,
/// Creates a TyFingerprint for looking up a trait impl.
pub fn for_trait_impl(ty: &Ty) -> Option<TyFingerprint> {
- let fp = match ty.kind(&Interner) {
+ let fp = match ty.kind(Interner) {
TyKind::Str => TyFingerprint::Str,
TyKind::Never => TyFingerprint::Never,
TyKind::Slice(..) => TyFingerprint::Slice,
TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty),
TyKind::Tuple(_, subst) => {
- let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(&Interner));
+ let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(Interner));
match first_ty {
Some(ty) => return TyFingerprint::for_trait_impl(ty),
None => TyFingerprint::Unit,
| TyKind::Generator(..)
| TyKind::GeneratorWitness(..) => TyFingerprint::Unnameable,
TyKind::Function(fn_ptr) => {
- TyFingerprint::Function(fn_ptr.substitution.0.len(&Interner) as u32)
+ TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32)
}
TyKind::Alias(_)
| TyKind::Placeholder(_)
impls.collect_def_map(db, &crate_def_map);
impls.shrink_to_fit();
- return Arc::new(impls);
+ Arc::new(impls)
}
pub(crate) fn inherent_impls_in_block_query(
impls.shrink_to_fit();
return Some(Arc::new(impls));
}
- return None;
+ None
}
fn shrink_to_fit(&mut self) {
let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect());
- let lang_item_targets = match ty.kind(&Interner) {
+ let lang_item_targets = match ty.kind(Interner) {
TyKind::Adt(AdtId(def_id), _) => {
return mod_to_crate_ids(def_id.module(db.upcast()));
}
Some(res)
}
-/// Look up the method with the given name, returning the actual autoderefed
-/// receiver type (but without autoref applied yet).
+/// Look up the method with the given name.
pub(crate) fn lookup_method(
ty: &Canonical<Ty>,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- krate: CrateId,
traits_in_scope: &FxHashSet<TraitId>,
- visible_from_module: Option<ModuleId>,
+ visible_from_module: VisibleFromModule,
name: &Name,
-) -> Option<(Canonical<Ty>, FunctionId)> {
+) -> Option<(ReceiverAdjustments, FunctionId)> {
iterate_method_candidates(
ty,
db,
env,
- krate,
traits_in_scope,
visible_from_module,
Some(name),
LookupMode::MethodCall,
- |ty, f| match f {
- AssocItemId::FunctionId(f) => Some((ty.clone(), f)),
+ |adjustments, f| match f {
+ AssocItemId::FunctionId(f) => Some((adjustments, f)),
_ => None,
},
)
Path,
}
+#[derive(Clone, Copy)]
+pub enum VisibleFromModule {
+ /// Filter for results that are visible from the given module
+ Filter(ModuleId),
+ /// Include impls from the given block.
+ IncludeBlock(BlockId),
+ /// Do nothing special in regards visibility
+ None,
+}
+
+impl From<Option<ModuleId>> for VisibleFromModule {
+ fn from(module: Option<ModuleId>) -> Self {
+ match module {
+ Some(module) => Self::Filter(module),
+ None => Self::None,
+ }
+ }
+}
+
+impl From<Option<BlockId>> for VisibleFromModule {
+ fn from(block: Option<BlockId>) -> Self {
+ match block {
+ Some(block) => Self::IncludeBlock(block),
+ None => Self::None,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Default)]
+pub struct ReceiverAdjustments {
+ autoref: Option<Mutability>,
+ autoderefs: usize,
+ unsize_array: bool,
+}
+
+impl ReceiverAdjustments {
+ pub(crate) fn apply(&self, table: &mut InferenceTable, ty: Ty) -> (Ty, Vec<Adjustment>) {
+ let mut ty = ty;
+ let mut adjust = Vec::new();
+ for _ in 0..self.autoderefs {
+ match autoderef::autoderef_step(table, ty.clone()) {
+ None => {
+ never!("autoderef not possible for {:?}", ty);
+ ty = TyKind::Error.intern(Interner);
+ break;
+ }
+ Some((kind, new_ty)) => {
+ ty = new_ty.clone();
+ adjust.push(Adjustment {
+ kind: Adjust::Deref(match kind {
+ // FIXME should we know the mutability here?
+ AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)),
+ AutoderefKind::Builtin => None,
+ }),
+ target: new_ty,
+ });
+ }
+ }
+ }
+ if self.unsize_array {
+ ty = match ty.kind(Interner) {
+ TyKind::Array(inner, _) => TyKind::Slice(inner.clone()).intern(Interner),
+ _ => {
+ never!("unsize_array with non-array {:?}", ty);
+ ty
+ }
+ };
+ // FIXME this is kind of wrong since the unsize needs to happen to a pointer/reference
+ adjust.push(Adjustment {
+ kind: Adjust::Pointer(PointerCast::Unsize),
+ target: ty.clone(),
+ });
+ }
+ if let Some(m) = self.autoref {
+ ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner);
+ adjust
+ .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() });
+ }
+ (ty, adjust)
+ }
+
+ fn with_autoref(&self, m: Mutability) -> ReceiverAdjustments {
+ Self { autoref: Some(m), ..*self }
+ }
+}
+
// This would be nicer if it just returned an iterator, but that runs into
// lifetime problems, because we need to borrow temp `CrateImplDefs`.
// FIXME add a context type here?
-pub fn iterate_method_candidates<T>(
+pub(crate) fn iterate_method_candidates<T>(
ty: &Canonical<Ty>,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- krate: CrateId,
traits_in_scope: &FxHashSet<TraitId>,
- visible_from_module: Option<ModuleId>,
+ visible_from_module: VisibleFromModule,
name: Option<&Name>,
mode: LookupMode,
- mut callback: impl FnMut(&Canonical<Ty>, AssocItemId) -> Option<T>,
+ mut callback: impl FnMut(ReceiverAdjustments, AssocItemId) -> Option<T>,
) -> Option<T> {
let mut slot = None;
iterate_method_candidates_dyn(
ty,
db,
env,
- krate,
traits_in_scope,
visible_from_module,
name,
mode,
- &mut |ty, item| {
+ &mut |adj, item| {
assert!(slot.is_none());
- if let Some(it) = callback(ty, item) {
+ if let Some(it) = callback(adj, item) {
slot = Some(it);
return ControlFlow::Break(());
}
slot
}
+pub fn iterate_path_candidates(
+ ty: &Canonical<Ty>,
+ db: &dyn HirDatabase,
+ env: Arc<TraitEnvironment>,
+ traits_in_scope: &FxHashSet<TraitId>,
+ visible_from_module: VisibleFromModule,
+ name: Option<&Name>,
+ callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
+) -> ControlFlow<()> {
+ iterate_method_candidates_dyn(
+ ty,
+ db,
+ env,
+ traits_in_scope,
+ visible_from_module,
+ name,
+ LookupMode::Path,
+ // the adjustments are not relevant for path lookup
+ &mut |_, id| callback(id),
+ )
+}
+
pub fn iterate_method_candidates_dyn(
ty: &Canonical<Ty>,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- krate: CrateId,
traits_in_scope: &FxHashSet<TraitId>,
- visible_from_module: Option<ModuleId>,
+ visible_from_module: VisibleFromModule,
name: Option<&Name>,
mode: LookupMode,
- callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
+ callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
match mode {
LookupMode::MethodCall => {
- // For method calls, rust first does any number of autoderef, and then one
- // autoref (i.e. when the method takes &self or &mut self). We just ignore
- // the autoref currently -- when we find a method matching the given name,
- // we assume it fits.
-
- // Also note that when we've got a receiver like &S, even if the method we
- // find in the end takes &self, we still do the autoderef step (just as
- // rustc does an autoderef and then autoref again).
- let ty = InEnvironment { goal: ty.clone(), environment: env.env.clone() };
+ // For method calls, rust first does any number of autoderef, and
+ // then one autoref (i.e. when the method takes &self or &mut self).
+ // Note that when we've got a receiver like &S, even if the method
+ // we find in the end takes &self, we still do the autoderef step
+ // (just as rustc does an autoderef and then autoref again).
// We have to be careful about the order we're looking at candidates
// in here. Consider the case where we're resolving `x.clone()`
// the methods by autoderef order of *receiver types*, not *self
// types*.
- let deref_chain = autoderef_method_receiver(db, krate, ty);
- let mut deref_chains = stdx::slice_tails(&deref_chain);
- deref_chains.try_for_each(|deref_chain| {
+ let mut table = InferenceTable::new(db, env.clone());
+ let ty = table.instantiate_canonical(ty.clone());
+ let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
+ let deref_chains = stdx::slice_tails(&deref_chain);
+
+ let result = deref_chains.zip(adj).try_for_each(|(deref_chain, adj)| {
iterate_method_candidates_with_autoref(
deref_chain,
+ adj,
db,
env.clone(),
- krate,
traits_in_scope,
visible_from_module,
name,
callback,
)
- })
+ });
+ result
}
LookupMode::Path => {
// No autoderef for path lookups
ty,
db,
env,
- krate,
traits_in_scope,
visible_from_module,
name,
fn iterate_method_candidates_with_autoref(
deref_chain: &[Canonical<Ty>],
+ first_adjustment: ReceiverAdjustments,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- krate: CrateId,
traits_in_scope: &FxHashSet<TraitId>,
- visible_from_module: Option<ModuleId>,
+ visible_from_module: VisibleFromModule,
name: Option<&Name>,
- mut callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
+ mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
let (receiver_ty, rest) = match deref_chain.split_first() {
- Some((rec, rest)) => (rec.clone(), rest),
+ Some((rec, rest)) => (rec, rest),
None => {
never!("received empty deref-chain");
return ControlFlow::Break(());
}
};
iterate_method_candidates_by_receiver(
- &receiver_ty,
- &rest,
+ receiver_ty,
+ first_adjustment.clone(),
+ rest,
db,
env.clone(),
- krate,
traits_in_scope,
visible_from_module,
name,
)?;
let refed = Canonical {
- binders: receiver_ty.binders.clone(),
value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone())
- .intern(&Interner),
+ .intern(Interner),
+ binders: receiver_ty.binders.clone(),
};
iterate_method_candidates_by_receiver(
&refed,
+ first_adjustment.with_autoref(Mutability::Not),
deref_chain,
db,
env.clone(),
- krate,
traits_in_scope,
visible_from_module,
name,
)?;
let ref_muted = Canonical {
- binders: receiver_ty.binders,
- value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value).intern(&Interner),
+ value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone())
+ .intern(Interner),
+ binders: receiver_ty.binders.clone(),
};
iterate_method_candidates_by_receiver(
&ref_muted,
+ first_adjustment.with_autoref(Mutability::Mut),
deref_chain,
db,
env,
- krate,
traits_in_scope,
visible_from_module,
name,
fn iterate_method_candidates_by_receiver(
receiver_ty: &Canonical<Ty>,
+ receiver_adjustments: ReceiverAdjustments,
rest_of_deref_chain: &[Canonical<Ty>],
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- krate: CrateId,
traits_in_scope: &FxHashSet<TraitId>,
- visible_from_module: Option<ModuleId>,
+ visible_from_module: VisibleFromModule,
name: Option<&Name>,
- mut callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
+ mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
// We're looking for methods with *receiver* type receiver_ty. These could
// be found in any of the derefs of receiver_ty, so we have to go through
env.clone(),
name,
Some(receiver_ty),
- krate,
+ Some(receiver_adjustments.clone()),
visible_from_module,
&mut callback,
)?
self_ty,
db,
env.clone(),
- krate,
traits_in_scope,
name,
Some(receiver_ty),
+ Some(receiver_adjustments.clone()),
&mut callback,
)?
}
self_ty: &Canonical<Ty>,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- krate: CrateId,
traits_in_scope: &FxHashSet<TraitId>,
- visible_from_module: Option<ModuleId>,
+ visible_from_module: VisibleFromModule,
name: Option<&Name>,
- mut callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
+ mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
iterate_inherent_methods(
self_ty,
env.clone(),
name,
None,
- krate,
+ None,
visible_from_module,
&mut callback,
)?;
- iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback)
+ iterate_trait_method_candidates(self_ty, db, env, traits_in_scope, name, None, None, callback)
}
fn iterate_trait_method_candidates(
self_ty: &Canonical<Ty>,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- krate: CrateId,
traits_in_scope: &FxHashSet<TraitId>,
name: Option<&Name>,
receiver_ty: Option<&Canonical<Ty>>,
- callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
+ receiver_adjustments: Option<ReceiverAdjustments>,
+ callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
- let receiver_is_array = matches!(self_ty.value.kind(&Interner), chalk_ir::TyKind::Array(..));
+ let self_is_array = matches!(self_ty.value.kind(Interner), chalk_ir::TyKind::Array(..));
// if ty is `dyn Trait`, the trait doesn't need to be in scope
let inherent_trait =
self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
- let env_traits = matches!(self_ty.value.kind(&Interner), TyKind::Placeholder(_))
+ let env_traits = matches!(self_ty.value.kind(Interner), TyKind::Placeholder(_))
// if we have `T: Trait` in the param env, the trait doesn't need to be in scope
.then(|| {
env.traits_in_scope_from_clauses(self_ty.value.clone())
// 2021.
// This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
// arrays.
- if data.skip_array_during_method_dispatch && receiver_is_array {
+ if data.skip_array_during_method_dispatch && self_is_array {
// FIXME: this should really be using the edition of the method name's span, in case it
// comes from a macro
- if db.crate_graph()[krate].edition < Edition::Edition2021 {
+ if db.crate_graph()[env.krate].edition < Edition::Edition2021 {
continue;
}
}
continue;
}
if !known_implemented {
- let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone());
- if db.trait_solve(krate, goal.cast(&Interner)).is_none() {
+ let goal = generic_implements_goal(db, env.clone(), t, self_ty);
+ if db.trait_solve(env.krate, goal.cast(Interner)).is_none() {
continue 'traits;
}
}
known_implemented = true;
- // FIXME: we shouldn't be ignoring the binders here
- callback(self_ty, item)?
+ callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
}
}
ControlFlow::Continue(())
// inherent methods on arrays are fingerprinted as [T; {unknown}], so we must also consider them when
// resolving a method call on an array with a known len
let array_impls = {
- match self_ty.kind(&Interner) {
+ match self_ty.kind(Interner) {
TyKind::Array(parameters, array_len) if !array_len.is_unknown() => {
let unknown_array_len_ty =
TyKind::Array(parameters.clone(), consteval::usize_const(None));
- Some(impls.for_self_ty(&unknown_array_len_ty.intern(&Interner)))
+ Some(impls.for_self_ty(&unknown_array_len_ty.intern(Interner)))
}
_ => None,
}
env: Arc<TraitEnvironment>,
name: Option<&Name>,
receiver_ty: Option<&Canonical<Ty>>,
- krate: CrateId,
- visible_from_module: Option<ModuleId>,
- callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
+ receiver_adjustments: Option<ReceiverAdjustments>,
+ visible_from_module: VisibleFromModule,
+ callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
- let def_crates = match def_crates(db, &self_ty.value, krate) {
+ let def_crates = match def_crates(db, &self_ty.value, env.krate) {
Some(k) => k,
None => return ControlFlow::Continue(()),
};
- if let Some(module_id) = visible_from_module {
- if let Some(block_id) = module_id.containing_block() {
- if let Some(impls) = db.inherent_impls_in_block(block_id) {
- impls_for_self_ty(
- &impls,
- self_ty,
- db,
- env.clone(),
- name,
- receiver_ty,
- visible_from_module,
- callback,
- )?;
- }
+ let (module, block) = match visible_from_module {
+ VisibleFromModule::Filter(module) => (Some(module), module.containing_block()),
+ VisibleFromModule::IncludeBlock(block) => (None, Some(block)),
+ VisibleFromModule::None => (None, None),
+ };
+
+ if let Some(block_id) = block {
+ if let Some(impls) = db.inherent_impls_in_block(block_id) {
+ impls_for_self_ty(
+ &impls,
+ self_ty,
+ db,
+ env.clone(),
+ name,
+ receiver_ty,
+ receiver_adjustments.clone(),
+ module,
+ callback,
+ )?;
}
}
env.clone(),
name,
receiver_ty,
- visible_from_module,
+ receiver_adjustments.clone(),
+ module,
callback,
)?;
}
env: Arc<TraitEnvironment>,
name: Option<&Name>,
receiver_ty: Option<&Canonical<Ty>>,
+ receiver_adjustments: Option<ReceiverAdjustments>,
visible_from_module: Option<ModuleId>,
- callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
+ callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
let impls_for_self_ty = filter_inherent_impls_for_self_ty(impls, &self_ty.value);
for &impl_def in impls_for_self_ty {
cov_mark::hit!(impl_self_type_match_without_receiver);
continue;
}
- let receiver_ty = receiver_ty.unwrap_or(self_ty);
- callback(receiver_ty, item)?;
+ callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
}
}
ControlFlow::Continue(())
}
}
-/// Returns the self type for the index trait call.
+/// Returns the receiver type for the index trait call.
pub fn resolve_indexing_op(
db: &dyn HirDatabase,
- ty: &Canonical<Ty>,
env: Arc<TraitEnvironment>,
- krate: CrateId,
+ ty: Canonical<Ty>,
index_trait: TraitId,
-) -> Option<Canonical<Ty>> {
- let ty = InEnvironment { goal: ty.clone(), environment: env.env.clone() };
- let deref_chain = autoderef_method_receiver(db, krate, ty);
- for ty in deref_chain {
- let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone());
- if db.trait_solve(krate, goal.cast(&Interner)).is_some() {
- return Some(ty);
+) -> Option<ReceiverAdjustments> {
+ let mut table = InferenceTable::new(db, env.clone());
+ let ty = table.instantiate_canonical(ty);
+ let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
+ for (ty, adj) in deref_chain.into_iter().zip(adj) {
+ let goal = generic_implements_goal(db, env.clone(), index_trait, &ty);
+ if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
+ return Some(adj);
}
}
None
// a transformed receiver may be considered equal (and a valid method call candidate) if it is an array
// with an unknown (i.e. generic) length, and the receiver is an array with the same item type but a known len,
// this allows inherent methods on arrays to be considered valid resolution candidates
- match (transformed_receiver_ty.kind(&Interner), receiver_ty.kind(&Interner)) {
+ match (transformed_receiver_ty.kind(Interner), receiver_ty.kind(Interner)) {
(
TyKind::Array(transformed_array_ty, transformed_array_len),
TyKind::Array(receiver_array_ty, receiver_array_len),
) -> Option<Substitution> {
// we create a var for each type parameter of the impl; we need to keep in
// mind here that `self_ty` might have vars of its own
- let self_ty_vars = self_ty.binders.len(&Interner);
+ let self_ty_vars = self_ty.binders.len(Interner);
let vars = TyBuilder::subst_for_def(db, impl_id)
.fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty_vars)
.build();
- let self_ty_with_vars = db.impl_self_ty(impl_id).substitute(&Interner, &vars);
+ let self_ty_with_vars = db.impl_self_ty(impl_id).substitute(Interner, &vars);
let mut kinds = self_ty.binders.interned().to_vec();
- kinds.extend(
- iter::repeat(chalk_ir::WithKind::new(
- chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
- UniverseIndex::ROOT,
- ))
- .take(vars.len(&Interner)),
- );
+ kinds.extend(vars.iter(Interner).map(|x| {
+ let kind = match x.data(Interner) {
+ GenericArgData::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
+ GenericArgData::Const(c) => chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()),
+ GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
+ };
+ chalk_ir::WithKind::new(kind, UniverseIndex::ROOT)
+ }));
let tys = Canonical {
- binders: CanonicalVarKinds::from_iter(&Interner, kinds),
+ binders: CanonicalVarKinds::from_iter(Interner, kinds),
value: (self_ty_with_vars, self_ty.value.clone()),
};
let substs = super::infer::unify(db, env, &tys)?;
// Unknown, and in that case we want the result to contain Unknown in those
// places again.
let suffix =
- Substitution::from_iter(&Interner, substs.iter(&Interner).cloned().skip(self_ty_vars));
+ Substitution::from_iter(Interner, substs.iter(Interner).skip(self_ty_vars).cloned());
Some(fallback_bound_vars(suffix, self_ty_vars))
}
/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
/// num_vars_to_keep) by `TyKind::Unknown`.
-fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution {
- crate::fold_free_vars(s, |bound, binders| {
- if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
- TyKind::Error.intern(&Interner)
- } else {
- bound.shifted_in_from(binders).to_ty(&Interner)
- }
- })
+pub(crate) fn fallback_bound_vars<T: Fold<Interner> + HasInterner<Interner = Interner>>(
+ s: T,
+ num_vars_to_keep: usize,
+) -> T::Result {
+ crate::fold_free_vars(
+ s,
+ |bound, binders| {
+ if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
+ TyKind::Error.intern(Interner)
+ } else {
+ bound.shifted_in_from(binders).to_ty(Interner)
+ }
+ },
+ |ty, bound, binders| {
+ if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
+ consteval::usize_const(None)
+ } else {
+ bound.shifted_in_from(binders).to_const(Interner, ty)
+ }
+ },
+ )
}
fn transform_receiver_ty(
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => unreachable!(),
};
let sig = db.callable_item_signature(function_id.into());
- Some(sig.map(|s| s.params()[0].clone()).substitute(&Interner, &substs))
+ Some(sig.map(|s| s.params()[0].clone()).substitute(Interner, &substs))
}
pub fn implements_trait(
ty: &Canonical<Ty>,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- krate: CrateId,
trait_: TraitId,
) -> bool {
- let goal = generic_implements_goal(db, env, trait_, ty.clone());
- let solution = db.trait_solve(krate, goal.cast(&Interner));
+ let goal = generic_implements_goal(db, env.clone(), trait_, ty);
+ let solution = db.trait_solve(env.krate, goal.cast(Interner));
solution.is_some()
}
ty: &Canonical<Ty>,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- krate: CrateId,
trait_: TraitId,
) -> bool {
- let goal = generic_implements_goal(db, env, trait_, ty.clone());
- let solution = db.trait_solve(krate, goal.cast(&Interner));
+ let goal = generic_implements_goal(db, env.clone(), trait_, ty);
+ let solution = db.trait_solve(env.krate, goal.cast(Interner));
matches!(solution, Some(crate::Solution::Unique(_)))
}
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
trait_: TraitId,
- self_ty: Canonical<Ty>,
+ self_ty: &Canonical<Ty>,
) -> Canonical<InEnvironment<super::DomainGoal>> {
let mut kinds = self_ty.binders.interned().to_vec();
let trait_ref = TyBuilder::trait_ref(db, trait_)
- .push(self_ty.value)
+ .push(self_ty.value.clone())
.fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
.build();
- kinds.extend(
- iter::repeat(chalk_ir::WithKind::new(
- chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
- UniverseIndex::ROOT,
- ))
- .take(trait_ref.substitution.len(&Interner) - 1),
- );
- let obligation = trait_ref.cast(&Interner);
+ kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|x| {
+ let vk = match x.data(Interner) {
+ chalk_ir::GenericArgData::Ty(_) => {
+ chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
+ }
+ chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
+ chalk_ir::GenericArgData::Const(c) => {
+ chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
+ }
+ };
+ chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
+ }));
+ let obligation = trait_ref.cast(Interner);
Canonical {
- binders: CanonicalVarKinds::from_iter(&Interner, kinds),
+ binders: CanonicalVarKinds::from_iter(Interner, kinds),
value: InEnvironment::new(&env.env, obligation),
}
}
fn autoderef_method_receiver(
- db: &dyn HirDatabase,
- krate: CrateId,
- ty: InEnvironment<Canonical<Ty>>,
-) -> Vec<Canonical<Ty>> {
- let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect();
+ table: &mut InferenceTable,
+ ty: Ty,
+) -> (Vec<Canonical<Ty>>, Vec<ReceiverAdjustments>) {
+ let (mut deref_chain, mut adjustments): (Vec<_>, Vec<_>) = (Vec::new(), Vec::new());
+ let mut autoderef = autoderef::Autoderef::new(table, ty);
+ while let Some((ty, derefs)) = autoderef.next() {
+ deref_chain.push(autoderef.table.canonicalize(ty).value);
+ adjustments.push(ReceiverAdjustments {
+ autoref: None,
+ autoderefs: derefs,
+ unsize_array: false,
+ });
+ }
// As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
- if let Some(TyKind::Array(parameters, _)) =
- deref_chain.last().map(|ty| ty.value.kind(&Interner))
- {
- let kinds = deref_chain.last().unwrap().binders.clone();
- let unsized_ty = TyKind::Slice(parameters.clone()).intern(&Interner);
- deref_chain.push(Canonical { value: unsized_ty, binders: kinds })
+ if let (Some((TyKind::Array(parameters, _), binders)), Some(adj)) = (
+ deref_chain.last().map(|ty| (ty.value.kind(Interner), ty.binders.clone())),
+ adjustments.last().cloned(),
+ ) {
+ let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner);
+ deref_chain.push(Canonical { value: unsized_ty, binders });
+ adjustments.push(ReceiverAdjustments { unsize_array: true, ..adj });
}
- deref_chain
+ (deref_chain, adjustments)
}