Skip to content

Commit ab896e3

Browse files
Merge #11550
11550: Refactor autoderef/method resolution r=flodiebold a=flodiebold - 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. Co-authored-by: Florian Diebold <[email protected]>
2 parents c825748 + 6fc3d3a commit ab896e3

22 files changed

+775
-663
lines changed

crates/hir/src/lib.rs

+45-47
Original file line numberDiff line numberDiff line change
@@ -2440,7 +2440,7 @@ impl Impl {
24402440

24412441
#[derive(Clone, PartialEq, Eq, Debug)]
24422442
pub struct Type {
2443-
krate: CrateId,
2443+
krate: CrateId, // FIXME this is probably redundant with the TraitEnvironment
24442444
env: Arc<TraitEnvironment>,
24452445
ty: Ty,
24462446
}
@@ -2533,36 +2533,25 @@ impl Type {
25332533
/// Checks that particular type `ty` implements `std::future::Future`.
25342534
/// This function is used in `.await` syntax completion.
25352535
pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
2536-
// No special case for the type of async block, since Chalk can figure it out.
2537-
2538-
let krate = self.krate;
2539-
2540-
let std_future_trait =
2541-
db.lang_item(krate, SmolStr::new_inline("future_trait")).and_then(|it| it.as_trait());
2536+
let std_future_trait = db
2537+
.lang_item(self.krate, SmolStr::new_inline("future_trait"))
2538+
.and_then(|it| it.as_trait());
25422539
let std_future_trait = match std_future_trait {
25432540
Some(it) => it,
25442541
None => return false,
25452542
};
25462543

25472544
let canonical_ty =
25482545
Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
2549-
method_resolution::implements_trait(
2550-
&canonical_ty,
2551-
db,
2552-
self.env.clone(),
2553-
krate,
2554-
std_future_trait,
2555-
)
2546+
method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), std_future_trait)
25562547
}
25572548

25582549
/// Checks that particular type `ty` implements `std::ops::FnOnce`.
25592550
///
25602551
/// This function can be used to check if a particular type is callable, since FnOnce is a
25612552
/// supertrait of Fn and FnMut, so all callable types implements at least FnOnce.
25622553
pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
2563-
let krate = self.krate;
2564-
2565-
let fnonce_trait = match FnTrait::FnOnce.get_id(db, krate) {
2554+
let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.krate) {
25662555
Some(it) => it,
25672556
None => return false,
25682557
};
@@ -2573,7 +2562,6 @@ impl Type {
25732562
&canonical_ty,
25742563
db,
25752564
self.env.clone(),
2576-
krate,
25772565
fnonce_trait,
25782566
)
25792567
}
@@ -2744,9 +2732,8 @@ impl Type {
27442732
pub fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
27452733
// There should be no inference vars in types passed here
27462734
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
2747-
let environment = self.env.env.clone();
2748-
let ty = InEnvironment { goal: canonical, environment };
2749-
autoderef(db, Some(self.krate), ty).map(|canonical| canonical.value)
2735+
let environment = self.env.clone();
2736+
autoderef(db, environment, canonical).map(|canonical| canonical.value)
27502737
}
27512738

27522739
// This would be nicer if it just returned an iterator, but that runs into
@@ -2801,24 +2788,26 @@ impl Type {
28012788
pub fn iterate_method_candidates<T>(
28022789
&self,
28032790
db: &dyn HirDatabase,
2804-
krate: Crate,
2791+
scope: &SemanticsScope,
2792+
// FIXME this can be retrieved from `scope`, except autoimport uses this
2793+
// to specify a different set, so the method needs to be split
28052794
traits_in_scope: &FxHashSet<TraitId>,
28062795
with_local_impls: Option<Module>,
28072796
name: Option<&Name>,
2808-
mut callback: impl FnMut(Type, Function) -> Option<T>,
2797+
mut callback: impl FnMut(Function) -> Option<T>,
28092798
) -> Option<T> {
28102799
let _p = profile::span("iterate_method_candidates");
28112800
let mut slot = None;
28122801

28132802
self.iterate_method_candidates_dyn(
28142803
db,
2815-
krate,
2804+
scope,
28162805
traits_in_scope,
28172806
with_local_impls,
28182807
name,
2819-
&mut |ty, assoc_item_id| {
2808+
&mut |assoc_item_id| {
28202809
if let AssocItemId::FunctionId(func) = assoc_item_id {
2821-
if let Some(res) = callback(self.derived(ty.clone()), func.into()) {
2810+
if let Some(res) = callback(func.into()) {
28222811
slot = Some(res);
28232812
return ControlFlow::Break(());
28242813
}
@@ -2832,50 +2821,55 @@ impl Type {
28322821
fn iterate_method_candidates_dyn(
28332822
&self,
28342823
db: &dyn HirDatabase,
2835-
krate: Crate,
2824+
scope: &SemanticsScope,
28362825
traits_in_scope: &FxHashSet<TraitId>,
28372826
with_local_impls: Option<Module>,
28382827
name: Option<&Name>,
2839-
callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
2828+
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
28402829
) {
28412830
// There should be no inference vars in types passed here
28422831
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
28432832

2844-
let env = self.env.clone();
2845-
let krate = krate.id;
2833+
let krate = match scope.krate() {
2834+
Some(k) => k,
2835+
None => return,
2836+
};
2837+
let environment = scope.resolver().generic_def().map_or_else(
2838+
|| Arc::new(TraitEnvironment::empty(krate.id)),
2839+
|d| db.trait_environment(d),
2840+
);
28462841

28472842
method_resolution::iterate_method_candidates_dyn(
28482843
&canonical,
28492844
db,
2850-
env,
2851-
krate,
2845+
environment,
28522846
traits_in_scope,
28532847
with_local_impls.and_then(|b| b.id.containing_block()).into(),
28542848
name,
28552849
method_resolution::LookupMode::MethodCall,
2856-
&mut |ty, id| callback(&ty.value, id),
2850+
&mut |_adj, id| callback(id),
28572851
);
28582852
}
28592853

28602854
pub fn iterate_path_candidates<T>(
28612855
&self,
28622856
db: &dyn HirDatabase,
2863-
krate: Crate,
2857+
scope: &SemanticsScope,
28642858
traits_in_scope: &FxHashSet<TraitId>,
28652859
with_local_impls: Option<Module>,
28662860
name: Option<&Name>,
2867-
mut callback: impl FnMut(Type, AssocItem) -> Option<T>,
2861+
mut callback: impl FnMut(AssocItem) -> Option<T>,
28682862
) -> Option<T> {
28692863
let _p = profile::span("iterate_path_candidates");
28702864
let mut slot = None;
28712865
self.iterate_path_candidates_dyn(
28722866
db,
2873-
krate,
2867+
scope,
28742868
traits_in_scope,
28752869
with_local_impls,
28762870
name,
2877-
&mut |ty, assoc_item_id| {
2878-
if let Some(res) = callback(self.derived(ty.clone()), assoc_item_id.into()) {
2871+
&mut |assoc_item_id| {
2872+
if let Some(res) = callback(assoc_item_id.into()) {
28792873
slot = Some(res);
28802874
return ControlFlow::Break(());
28812875
}
@@ -2888,27 +2882,31 @@ impl Type {
28882882
fn iterate_path_candidates_dyn(
28892883
&self,
28902884
db: &dyn HirDatabase,
2891-
krate: Crate,
2885+
scope: &SemanticsScope,
28922886
traits_in_scope: &FxHashSet<TraitId>,
28932887
with_local_impls: Option<Module>,
28942888
name: Option<&Name>,
2895-
callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
2889+
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
28962890
) {
28972891
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
28982892

2899-
let env = self.env.clone();
2900-
let krate = krate.id;
2893+
let krate = match scope.krate() {
2894+
Some(k) => k,
2895+
None => return,
2896+
};
2897+
let environment = scope.resolver().generic_def().map_or_else(
2898+
|| Arc::new(TraitEnvironment::empty(krate.id)),
2899+
|d| db.trait_environment(d),
2900+
);
29012901

2902-
method_resolution::iterate_method_candidates_dyn(
2902+
method_resolution::iterate_path_candidates(
29032903
&canonical,
29042904
db,
2905-
env,
2906-
krate,
2905+
environment,
29072906
traits_in_scope,
29082907
with_local_impls.and_then(|b| b.id.containing_block()).into(),
29092908
name,
2910-
method_resolution::LookupMode::Path,
2911-
&mut |ty, id| callback(&ty.value, id),
2909+
&mut |id| callback(id),
29122910
);
29132911
}
29142912

crates/hir/src/semantics.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,10 @@ impl<'a> SemanticsScope<'a> {
12301230
Some(Crate { id: self.resolver.krate()? })
12311231
}
12321232

1233+
pub(crate) fn resolver(&self) -> &Resolver {
1234+
&self.resolver
1235+
}
1236+
12331237
/// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
12341238
pub fn visible_traits(&self) -> FxHashSet<TraitId> {
12351239
let resolver = &self.resolver;

0 commit comments

Comments
 (0)