Skip to content

Commit 62df79d

Browse files
Autoref/deref for .await
1 parent 60b5ca6 commit 62df79d

File tree

4 files changed

+130
-44
lines changed

4 files changed

+130
-44
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+27-7
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
730730

731731
/// Desugar `<expr>.await` into:
732732
/// ```ignore (pseudo-rust)
733-
/// match ::std::future::IntoFuture::into_future(<expr>) {
733+
/// match (<expr>).<::std::future::IntoFuture::into_future>() {
734734
/// mut __awaitee => loop {
735735
/// match unsafe { ::std::future::Future::poll(
736736
/// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
@@ -930,13 +930,33 @@ impl<'hir> LoweringContext<'_, 'hir> {
930930
// mut __awaitee => loop { ... }
931931
let awaitee_arm = self.arm(awaitee_pat, loop_expr);
932932

933-
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
934933
let into_future_expr = match await_kind {
935-
FutureKind::Future => self.expr_call_lang_item_fn(
936-
span,
937-
hir::LangItem::IntoFutureIntoFuture,
938-
arena_vec![self; *expr],
939-
),
934+
// `match (<expr>).<::std::future::IntoFuture::into_future>() { ... }`
935+
// The `into_future` call is a little special,
936+
// it resolves directly to the `into_future` lang item
937+
// but goes through autoref/autoderef like any method call.
938+
FutureKind::Future => {
939+
let into_future_id = self
940+
.tcx
941+
.require_lang_item(hir::LangItem::IntoFutureIntoFuture, Some(await_kw_span));
942+
943+
let segment_hid = self.next_id();
944+
945+
self.arena.alloc(self.expr(
946+
span,
947+
hir::ExprKind::MethodCall(
948+
self.arena.alloc(hir::PathSegment::new(
949+
Ident::new(sym::into_future, await_kw_span),
950+
segment_hid,
951+
Res::Def(DefKind::AssocFn, into_future_id),
952+
)),
953+
self.arena.alloc(expr),
954+
&[],
955+
span,
956+
),
957+
))
958+
}
959+
940960
// Not needed for `for await` because we expect to have already called
941961
// `IntoAsyncIterator::into_async_iter` on it.
942962
FutureKind::AsyncIterator => expr,

compiler/rustc_hir_typeck/src/method/mod.rs

+35-37
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
182182
self_expr: &'tcx hir::Expr<'tcx>,
183183
args: &'tcx [hir::Expr<'tcx>],
184184
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
185-
let pick =
186-
self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
185+
let probe_scope =
186+
segment.res.opt_def_id().map_or(ProbeScope::TraitsInScope, ProbeScope::DefId);
187+
let pick = self.lookup_probe(segment.ident, self_ty, call_expr, probe_scope)?;
187188

188189
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
189190

@@ -202,12 +203,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
202203
if let ty::Ref(region, t_type, mutability) = self_ty.kind() {
203204
let trait_type = Ty::new_ref(self.tcx, *region, *t_type, mutability.invert());
204205
// We probe again to see if there might be a borrow mutability discrepancy.
205-
match self.lookup_probe(
206-
segment.ident,
207-
trait_type,
208-
call_expr,
209-
ProbeScope::TraitsInScope,
210-
) {
206+
match self.lookup_probe(segment.ident, trait_type, call_expr, probe_scope) {
211207
Ok(ref new_pick) if pick.differs_from(new_pick) => {
212208
needs_mut = new_pick.self_ty.ref_mutability() != self_ty.ref_mutability();
213209
}
@@ -216,29 +212,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
216212
}
217213

218214
// We probe again, taking all traits into account (not only those in scope).
219-
let candidates = match self.lookup_probe_for_diagnostic(
220-
segment.ident,
221-
self_ty,
222-
call_expr,
223-
ProbeScope::AllTraits,
224-
None,
225-
) {
226-
// If we find a different result the caller probably forgot to import a trait.
227-
Ok(ref new_pick) if pick.differs_from(new_pick) => {
228-
vec![new_pick.item.container_id(self.tcx)]
215+
let candidates = if probe_scope == ProbeScope::TraitsInScope {
216+
match self.lookup_probe_for_diagnostic(
217+
segment.ident,
218+
self_ty,
219+
call_expr,
220+
ProbeScope::AllTraits,
221+
None,
222+
) {
223+
// If we find a different result the caller probably forgot to import a trait.
224+
Ok(ref new_pick) if pick.differs_from(new_pick) => {
225+
vec![new_pick.item.container_id(self.tcx)]
226+
}
227+
Err(Ambiguity(ref sources)) => sources
228+
.iter()
229+
.filter_map(|source| {
230+
match *source {
231+
// Note: this cannot come from an inherent impl,
232+
// because the first probing succeeded.
233+
CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def),
234+
CandidateSource::Trait(_) => None,
235+
}
236+
})
237+
.collect(),
238+
_ => Vec::new(),
229239
}
230-
Err(Ambiguity(ref sources)) => sources
231-
.iter()
232-
.filter_map(|source| {
233-
match *source {
234-
// Note: this cannot come from an inherent impl,
235-
// because the first probing succeeded.
236-
CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def),
237-
CandidateSource::Trait(_) => None,
238-
}
239-
})
240-
.collect(),
241-
_ => Vec::new(),
240+
} else {
241+
Vec::new()
242242
};
243243

244244
return Err(IllegalSizedBound { candidates, needs_mut, bound_span: span, self_expr });
@@ -255,13 +255,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
255255
call_expr: &'tcx hir::Expr<'tcx>,
256256
self_expr: &'tcx hir::Expr<'tcx>,
257257
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
258-
let pick = self.lookup_probe_for_diagnostic(
259-
segment.ident,
260-
self_ty,
261-
call_expr,
262-
ProbeScope::TraitsInScope,
263-
None,
264-
)?;
258+
let probe_scope =
259+
segment.res.opt_def_id().map_or(ProbeScope::TraitsInScope, ProbeScope::DefId);
260+
261+
let pick =
262+
self.lookup_probe_for_diagnostic(segment.ident, self_ty, call_expr, probe_scope, None)?;
265263

266264
Ok(self
267265
.confirm_method_for_diagnostic(span, self_expr, call_expr, self_ty, &pick, segment)

compiler/rustc_hir_typeck/src/method/probe.rs

+24
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ pub enum ProbeScope {
248248

249249
// Assemble candidates coming from all traits.
250250
AllTraits,
251+
252+
// Consider only the given `DefId`.
253+
DefId(DefId),
251254
}
252255

253256
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -495,6 +498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495498
probe_cx.assemble_extension_candidates_for_traits_in_scope()
496499
}
497500
ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(),
501+
ProbeScope::DefId(id) => probe_cx.assemble_extension_candidate_for_def_id(id),
498502
};
499503
op(probe_cx)
500504
})
@@ -919,6 +923,26 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
919923
}
920924
}
921925

926+
fn assemble_extension_candidate_for_def_id(&mut self, fn_id: DefId) {
927+
let item: AssocItem = self.tcx.associated_item(fn_id);
928+
let trait_def_id = item.trait_container(self.tcx).expect("method should have a trait");
929+
let trait_args = self.fresh_args_for_item(self.span, trait_def_id);
930+
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_args);
931+
let (xform_self_ty, xform_ret_ty) =
932+
self.xform_self_ty(item, trait_ref.self_ty(), trait_args);
933+
934+
self.push_candidate(
935+
Candidate {
936+
xform_self_ty,
937+
xform_ret_ty,
938+
item,
939+
import_ids: smallvec![],
940+
kind: TraitCandidate(trait_ref),
941+
},
942+
false,
943+
);
944+
}
945+
922946
fn matches_return_type(
923947
&self,
924948
method: ty::AssocItem,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// run-pass
2+
// aux-build: issue-72470-lib.rs
3+
// edition:2021
4+
extern crate issue_72470_lib;
5+
use std::{future::{Future, IntoFuture}, pin::Pin};
6+
7+
struct AwaitMe;
8+
9+
impl IntoFuture for &AwaitMe {
10+
type Output = i32;
11+
type IntoFuture = Pin<Box<dyn Future<Output = i32>>>;
12+
13+
fn into_future(self) -> Self::IntoFuture {
14+
Box::pin(me())
15+
}
16+
}
17+
18+
async fn me() -> i32 {
19+
41
20+
}
21+
22+
async fn run() {
23+
assert_eq!(AwaitMe.await, 41);
24+
}
25+
26+
struct AwaitMeToo;
27+
28+
impl IntoFuture for &mut AwaitMeToo {
29+
type Output = i32;
30+
type IntoFuture = Pin<Box<dyn Future<Output = i32>>>;
31+
32+
fn into_future(self) -> Self::IntoFuture {
33+
Box::pin(me())
34+
}
35+
}
36+
37+
async fn run_too() {
38+
assert_eq!(AwaitMeToo.await, 41);
39+
}
40+
41+
fn main() {
42+
issue_72470_lib::run(run());
43+
issue_72470_lib::run(run_too());
44+
}

0 commit comments

Comments
 (0)