mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
Refactor autoderef and method resolution
- don't return the receiver type from method resolution; instead just return the autorefs/autoderefs that happened and repeat them. This ensures all the effects like trait obligations and whatever we learned about type variables from derefing them are actually applied. Also, it allows us to get rid of `decanonicalize_ty`, which was just wrong in principle. - Autoderef itself now directly works with an inference table. Sadly this has the effect of making it harder to use as an iterator, often requiring manual `while let` loops. (rustc works around this by using inner mutability in the inference context, so that things like unifying types don't require a unique reference.) - We now record the adjustments (autoref/deref) for method receivers and index expressions, which we didn't before. - Removed the redundant crate parameter from method resolution, since the trait_env contains the crate as well. - in the HIR API, the methods now take a scope to determine the trait env. `Type` carries a trait env, but I think that's probably a bad decision because it's easy to create it with the wrong env, e.g. by using `Adt::ty`. This mostly didn't matter so far because `iterate_method_candidates` took a crate parameter and ignored `self.krate`, but the trait env would still have been wrong in those cases, which I think would give some wrong results in some edge cases. Fixes #10058.
This commit is contained in:
parent
6858694001
commit
6fb5abbc03
21 changed files with 655 additions and 667 deletions
|
@ -2440,7 +2440,7 @@ impl Impl {
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Type {
|
||||
krate: CrateId,
|
||||
krate: CrateId, // FIXME this is probably redundant with the TraitEnvironment
|
||||
env: Arc<TraitEnvironment>,
|
||||
ty: Ty,
|
||||
}
|
||||
|
@ -2533,12 +2533,9 @@ impl Type {
|
|||
/// Checks that particular type `ty` implements `std::future::Future`.
|
||||
/// This function is used in `.await` syntax completion.
|
||||
pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
|
||||
// No special case for the type of async block, since Chalk can figure it out.
|
||||
|
||||
let krate = self.krate;
|
||||
|
||||
let std_future_trait =
|
||||
db.lang_item(krate, SmolStr::new_inline("future_trait")).and_then(|it| it.as_trait());
|
||||
let std_future_trait = db
|
||||
.lang_item(self.krate, SmolStr::new_inline("future_trait"))
|
||||
.and_then(|it| it.as_trait());
|
||||
let std_future_trait = match std_future_trait {
|
||||
Some(it) => it,
|
||||
None => return false,
|
||||
|
@ -2546,13 +2543,7 @@ impl Type {
|
|||
|
||||
let canonical_ty =
|
||||
Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
|
||||
method_resolution::implements_trait(
|
||||
&canonical_ty,
|
||||
db,
|
||||
self.env.clone(),
|
||||
krate,
|
||||
std_future_trait,
|
||||
)
|
||||
method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), std_future_trait)
|
||||
}
|
||||
|
||||
/// Checks that particular type `ty` implements `std::ops::FnOnce`.
|
||||
|
@ -2560,9 +2551,7 @@ impl Type {
|
|||
/// This function can be used to check if a particular type is callable, since FnOnce is a
|
||||
/// supertrait of Fn and FnMut, so all callable types implements at least FnOnce.
|
||||
pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
|
||||
let krate = self.krate;
|
||||
|
||||
let fnonce_trait = match FnTrait::FnOnce.get_id(db, krate) {
|
||||
let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.krate) {
|
||||
Some(it) => it,
|
||||
None => return false,
|
||||
};
|
||||
|
@ -2573,7 +2562,6 @@ impl Type {
|
|||
&canonical_ty,
|
||||
db,
|
||||
self.env.clone(),
|
||||
krate,
|
||||
fnonce_trait,
|
||||
)
|
||||
}
|
||||
|
@ -2744,9 +2732,8 @@ impl Type {
|
|||
pub fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
|
||||
// There should be no inference vars in types passed here
|
||||
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
|
||||
let environment = self.env.env.clone();
|
||||
let ty = InEnvironment { goal: canonical, environment };
|
||||
autoderef(db, Some(self.krate), ty).map(|canonical| canonical.value)
|
||||
let environment = self.env.clone();
|
||||
autoderef(db, environment, canonical).map(|canonical| canonical.value)
|
||||
}
|
||||
|
||||
// This would be nicer if it just returned an iterator, but that runs into
|
||||
|
@ -2801,24 +2788,26 @@ impl Type {
|
|||
pub fn iterate_method_candidates<T>(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
krate: Crate,
|
||||
scope: &SemanticsScope,
|
||||
// FIXME this can be retrieved from `scope`, except autoimport uses this
|
||||
// to specify a different set, so the method needs to be split
|
||||
traits_in_scope: &FxHashSet<TraitId>,
|
||||
with_local_impls: Option<Module>,
|
||||
name: Option<&Name>,
|
||||
mut callback: impl FnMut(Type, Function) -> Option<T>,
|
||||
mut callback: impl FnMut(Function) -> Option<T>,
|
||||
) -> Option<T> {
|
||||
let _p = profile::span("iterate_method_candidates");
|
||||
let mut slot = None;
|
||||
|
||||
self.iterate_method_candidates_dyn(
|
||||
db,
|
||||
krate,
|
||||
scope,
|
||||
traits_in_scope,
|
||||
with_local_impls,
|
||||
name,
|
||||
&mut |ty, assoc_item_id| {
|
||||
&mut |assoc_item_id| {
|
||||
if let AssocItemId::FunctionId(func) = assoc_item_id {
|
||||
if let Some(res) = callback(self.derived(ty.clone()), func.into()) {
|
||||
if let Some(res) = callback(func.into()) {
|
||||
slot = Some(res);
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
|
@ -2832,50 +2821,55 @@ impl Type {
|
|||
fn iterate_method_candidates_dyn(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
krate: Crate,
|
||||
scope: &SemanticsScope,
|
||||
traits_in_scope: &FxHashSet<TraitId>,
|
||||
with_local_impls: Option<Module>,
|
||||
name: Option<&Name>,
|
||||
callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
|
||||
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
|
||||
) {
|
||||
// There should be no inference vars in types passed here
|
||||
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
|
||||
|
||||
let env = self.env.clone();
|
||||
let krate = krate.id;
|
||||
let krate = match scope.krate() {
|
||||
Some(k) => k,
|
||||
None => return,
|
||||
};
|
||||
let environment = scope.resolver().generic_def().map_or_else(
|
||||
|| Arc::new(TraitEnvironment::empty(krate.id)),
|
||||
|d| db.trait_environment(d),
|
||||
);
|
||||
|
||||
method_resolution::iterate_method_candidates_dyn(
|
||||
&canonical,
|
||||
db,
|
||||
env,
|
||||
krate,
|
||||
environment,
|
||||
traits_in_scope,
|
||||
with_local_impls.and_then(|b| b.id.containing_block()).into(),
|
||||
name,
|
||||
method_resolution::LookupMode::MethodCall,
|
||||
&mut |ty, id| callback(&ty.value, id),
|
||||
&mut |_adj, id| callback(id),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn iterate_path_candidates<T>(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
krate: Crate,
|
||||
scope: &SemanticsScope,
|
||||
traits_in_scope: &FxHashSet<TraitId>,
|
||||
with_local_impls: Option<Module>,
|
||||
name: Option<&Name>,
|
||||
mut callback: impl FnMut(Type, AssocItem) -> Option<T>,
|
||||
mut callback: impl FnMut(AssocItem) -> Option<T>,
|
||||
) -> Option<T> {
|
||||
let _p = profile::span("iterate_path_candidates");
|
||||
let mut slot = None;
|
||||
self.iterate_path_candidates_dyn(
|
||||
db,
|
||||
krate,
|
||||
scope,
|
||||
traits_in_scope,
|
||||
with_local_impls,
|
||||
name,
|
||||
&mut |ty, assoc_item_id| {
|
||||
if let Some(res) = callback(self.derived(ty.clone()), assoc_item_id.into()) {
|
||||
&mut |assoc_item_id| {
|
||||
if let Some(res) = callback(assoc_item_id.into()) {
|
||||
slot = Some(res);
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
|
@ -2888,27 +2882,31 @@ impl Type {
|
|||
fn iterate_path_candidates_dyn(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
krate: Crate,
|
||||
scope: &SemanticsScope,
|
||||
traits_in_scope: &FxHashSet<TraitId>,
|
||||
with_local_impls: Option<Module>,
|
||||
name: Option<&Name>,
|
||||
callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
|
||||
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
|
||||
) {
|
||||
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
|
||||
|
||||
let env = self.env.clone();
|
||||
let krate = krate.id;
|
||||
let krate = match scope.krate() {
|
||||
Some(k) => k,
|
||||
None => return,
|
||||
};
|
||||
let environment = scope.resolver().generic_def().map_or_else(
|
||||
|| Arc::new(TraitEnvironment::empty(krate.id)),
|
||||
|d| db.trait_environment(d),
|
||||
);
|
||||
|
||||
method_resolution::iterate_method_candidates_dyn(
|
||||
method_resolution::iterate_path_candidates(
|
||||
&canonical,
|
||||
db,
|
||||
env,
|
||||
krate,
|
||||
environment,
|
||||
traits_in_scope,
|
||||
with_local_impls.and_then(|b| b.id.containing_block()).into(),
|
||||
name,
|
||||
method_resolution::LookupMode::Path,
|
||||
&mut |ty, id| callback(&ty.value, id),
|
||||
&mut |id| callback(id),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue