Skip to content

Commit 267fe19

Browse files
Autoref/deref for .await
1 parent 4451777 commit 267fe19

File tree

4 files changed

+125
-43
lines changed

4 files changed

+125
-43
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+22-6
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
860860

861861
/// Desugar `<expr>.await` into:
862862
/// ```ignore (pseudo-rust)
863-
/// match ::std::future::IntoFuture::into_future(<expr>) {
863+
/// match (<expr>).<::std::future::IntoFuture::into_future>() {
864864
/// mut __awaitee => loop {
865865
/// match unsafe { ::std::future::Future::poll(
866866
/// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
@@ -1020,12 +1020,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
10201020
// mut __awaitee => loop { ... }
10211021
let awaitee_arm = self.arm(awaitee_pat, loop_expr);
10221022

1023-
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
1024-
let into_future_expr = self.expr_call_lang_item_fn(
1023+
// `match (<expr>).<::std::future::IntoFuture::into_future>() { ... }`
1024+
// The `into_future` call is a little special,
1025+
// it resolves directly to the `into_future` lang item
1026+
// but goes through autoref/autoderef like any method call.
1027+
let into_future_id =
1028+
self.tcx.require_lang_item(hir::LangItem::IntoFutureIntoFuture, Some(await_kw_span));
1029+
1030+
let segment_hid = self.next_id();
1031+
1032+
let into_future_expr = self.arena.alloc(self.expr(
10251033
span,
1026-
hir::LangItem::IntoFutureIntoFuture,
1027-
arena_vec![self; expr],
1028-
);
1034+
hir::ExprKind::MethodCall(
1035+
self.arena.alloc(hir::PathSegment::new(
1036+
Ident::new(sym::into_future, await_kw_span),
1037+
segment_hid,
1038+
Res::Def(DefKind::AssocFn, into_future_id),
1039+
)),
1040+
self.arena.alloc(expr),
1041+
&[],
1042+
await_kw_span,
1043+
),
1044+
));
10291045

10301046
// match <into_future_expr> {
10311047
// mut __awaitee => loop { .. }

compiler/rustc_hir_typeck/src/method/mod.rs

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

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

@@ -207,12 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
207208
ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
208209
);
209210
// We probe again to see if there might be a borrow mutability discrepancy.
210-
match self.lookup_probe(
211-
segment.ident,
212-
trait_type,
213-
call_expr,
214-
ProbeScope::TraitsInScope,
215-
) {
211+
match self.lookup_probe(segment.ident, trait_type, call_expr, probe_scope) {
216212
Ok(ref new_pick) if pick.differs_from(new_pick) => {
217213
needs_mut = new_pick.self_ty.ref_mutability() != self_ty.ref_mutability();
218214
}
@@ -221,29 +217,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
221217
}
222218

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

249249
return Err(IllegalSizedBound { candidates, needs_mut, bound_span: span, self_expr });
@@ -260,13 +260,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
260260
call_expr: &'tcx hir::Expr<'tcx>,
261261
self_expr: &'tcx hir::Expr<'tcx>,
262262
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
263-
let pick = self.lookup_probe_for_diagnostic(
264-
segment.ident,
265-
self_ty,
266-
call_expr,
267-
ProbeScope::TraitsInScope,
268-
None,
269-
)?;
263+
let probe_scope =
264+
segment.res.opt_def_id().map_or(ProbeScope::TraitsInScope, ProbeScope::DefId);
265+
266+
let pick =
267+
self.lookup_probe_for_diagnostic(segment.ident, self_ty, call_expr, probe_scope, None)?;
270268

271269
Ok(self
272270
.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> {
@@ -498,6 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
498501
probe_cx.assemble_extension_candidates_for_traits_in_scope()
499502
}
500503
ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(),
504+
ProbeScope::DefId(id) => probe_cx.assemble_extension_candidate_for_def_id(id),
501505
};
502506
op(probe_cx)
503507
})
@@ -920,6 +924,26 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
920924
}
921925
}
922926

927+
fn assemble_extension_candidate_for_def_id(&mut self, fn_id: DefId) {
928+
let item: AssocItem = self.tcx.associated_item(fn_id);
929+
let trait_def_id = item.trait_container(self.tcx).expect("method should have a trait");
930+
let trait_args = self.fresh_args_for_item(self.span, trait_def_id);
931+
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_args);
932+
let (xform_self_ty, xform_ret_ty) =
933+
self.xform_self_ty(item, trait_ref.self_ty(), trait_args);
934+
935+
self.push_candidate(
936+
Candidate {
937+
xform_self_ty,
938+
xform_ret_ty,
939+
item,
940+
import_ids: smallvec![],
941+
kind: TraitCandidate(trait_ref),
942+
},
943+
false,
944+
);
945+
}
946+
923947
fn matches_return_type(
924948
&self,
925949
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)