Skip to content

Commit 42c95f8

Browse files
committed
Auto merge of rust-lang#111773 - Jules-Bertholet:await-autoref, r=<try>
Perform autoref/autoderef on `.await` This PR adds support for autoref/autoderef of the reciever of an `.await` (before calling `IntoFuture::into_future()`). This PR is not ready to merge yet—the feature works, but diagnostics are regressed and clippy is broken. I would like to get some feedback on my current approach, before investing more effort into it. Fixes rust-lang#111546.
2 parents 1db4b12 + b6a85d4 commit 42c95f8

File tree

33 files changed

+315
-146
lines changed

33 files changed

+315
-146
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
106106
let receiver = self.lower_expr(receiver);
107107
let args =
108108
self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x)));
109-
hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(*span))
109+
hir::ExprKind::MethodCall(
110+
hir::MethodCallPath::Segment(hir_seg),
111+
receiver,
112+
args,
113+
self.lower_span(*span),
114+
)
110115
}
111116
ExprKind::Binary(binop, lhs, rhs) => {
112117
let binop = self.lower_binop(*binop);
@@ -755,7 +760,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
755760

756761
/// Desugar `<expr>.await` into:
757762
/// ```ignore (pseudo-rust)
758-
/// match ::std::future::IntoFuture::into_future(<expr>) {
763+
/// match <expr>.<::core::future::IntoFuture::into_future>() {
759764
/// mut __awaitee => loop {
760765
/// match unsafe { ::std::future::Future::poll(
761766
/// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
@@ -915,13 +920,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
915920
// mut __awaitee => loop { ... }
916921
let awaitee_arm = self.arm(awaitee_pat, loop_expr);
917922

918-
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
919-
let into_future_expr = self.expr_call_lang_item_fn(
923+
// `<expr>.<::core::future::IntoFuture::into_future>()`
924+
// This is special; it does auto(de)ref like a method call,
925+
// but name-resolves only to the `into_future_into_future`
926+
// lang item.
927+
let into_future_expr = self.arena.alloc(self.expr(
920928
span,
921-
hir::LangItem::IntoFutureIntoFuture,
922-
arena_vec![self; expr],
923-
Some(expr_hir_id),
924-
);
929+
hir::ExprKind::MethodCall(
930+
hir::MethodCallPath::AwaitIntoFuture(await_kw_span),
931+
self.arena.alloc(expr),
932+
&[],
933+
await_kw_span,
934+
),
935+
));
925936

926937
// match <into_future_expr> {
927938
// mut __awaitee => loop { .. }

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1388,7 +1388,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
13881388
}
13891389

13901390
if let hir::ExprKind::MethodCall(body_call, recv, ..) = ex.kind
1391-
&& body_call.ident.name == sym::next
1391+
&& body_call.ident().name == sym::next
13921392
&& recv.span.source_equal(self.expr_span)
13931393
{
13941394
self.body_expr = Some(ex);
@@ -2324,11 +2324,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
23242324
{
23252325
if let Some(call) = visitor.call
23262326
&& let hir::ExprKind::MethodCall(path, _, [], _) = call.kind
2327-
&& path.ident.name == sym::iter
2327+
&& path.ident().name == sym::iter
23282328
&& let Some(ty) = expr_ty
23292329
{
23302330
err.span_suggestion_verbose(
2331-
path.ident.span,
2331+
path.ident().span,
23322332
format!(
23332333
"consider consuming the `{ty}` when turning it into an \
23342334
`Iterator`",

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
881881
&& let Call(_, [expr]) = expr.kind
882882
{
883883
match expr.kind {
884-
MethodCall(path_segment, _, _, span) => {
884+
MethodCall(hir::MethodCallPath::Segment(path_segment), _, _, span) => {
885885
// We have `for _ in iter.read_only_iter()`, try to
886886
// suggest `for _ in iter.mutable_iter()` instead.
887887
let opt_suggestions = self
@@ -1033,7 +1033,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
10331033
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
10341034
{
10351035
let mut cur_expr = expr;
1036-
while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
1036+
while let ExprKind::MethodCall(hir::MethodCallPath::Segment(path_segment), recv, _, _) = cur_expr.kind {
10371037
if path_segment.ident.name == sym::iter {
10381038
// check `_ty` has `iter_mut` method
10391039
let res = self

compiler/rustc_hir/src/hir.rs

+51-4
Original file line numberDiff line numberDiff line change
@@ -1910,7 +1910,7 @@ impl Expr<'_> {
19101910

19111911
pub fn method_ident(&self) -> Option<Ident> {
19121912
match self.kind {
1913-
ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident),
1913+
ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident()),
19141914
ExprKind::Unary(_, expr) | ExprKind::AddrOf(.., expr) => expr.method_ident(),
19151915
_ => None,
19161916
}
@@ -1943,6 +1943,48 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
19431943
}
19441944
}
19451945

1946+
#[derive(Debug, Clone, Copy, HashStable_Generic)]
1947+
pub enum MethodCallPath<'hir> {
1948+
Segment(&'hir PathSegment<'hir>),
1949+
// Used in the `.await` desugaring.
1950+
AwaitIntoFuture(Span),
1951+
}
1952+
1953+
impl<'hir> MethodCallPath<'hir> {
1954+
#[inline]
1955+
pub fn ident(self) -> Ident {
1956+
match self {
1957+
MethodCallPath::Segment(segment) => segment.ident,
1958+
MethodCallPath::AwaitIntoFuture(span) => Ident::new(sym::into_future, span),
1959+
}
1960+
}
1961+
1962+
#[inline]
1963+
pub fn span(self) -> Span {
1964+
match self {
1965+
MethodCallPath::Segment(segment) => segment.ident.span,
1966+
MethodCallPath::AwaitIntoFuture(span) => span,
1967+
}
1968+
}
1969+
1970+
#[inline]
1971+
pub fn opt_args<'a>(self) -> Option<&'a GenericArgs<'hir>> {
1972+
match self {
1973+
MethodCallPath::Segment(segment) => segment.args,
1974+
MethodCallPath::AwaitIntoFuture(_) => None,
1975+
}
1976+
}
1977+
1978+
#[inline]
1979+
pub fn args<'a>(self) -> &'a GenericArgs<'hir> {
1980+
const EMPTY: GenericArgs<'_> = GenericArgs::none();
1981+
match self {
1982+
MethodCallPath::Segment(segment) => segment.args(),
1983+
MethodCallPath::AwaitIntoFuture(_) => &EMPTY,
1984+
}
1985+
}
1986+
}
1987+
19461988
#[derive(Debug, Clone, Copy, HashStable_Generic)]
19471989
pub enum ExprKind<'hir> {
19481990
/// Allow anonymous constants from an inline `const` block
@@ -1958,8 +2000,13 @@ pub enum ExprKind<'hir> {
19582000
Call(&'hir Expr<'hir>, &'hir [Expr<'hir>]),
19592001
/// A method call (e.g., `x.foo::<'static, Bar, Baz>(a, b, c, d)`).
19602002
///
1961-
/// The `PathSegment` represents the method name and its generic arguments
1962-
/// (within the angle brackets).
2003+
/// The [`MethodCallPath`] is either:
2004+
///
2005+
/// - a [`PathSegment`] that represents the method name and its generic arguments
2006+
/// (within the angle brackets), or
2007+
/// - `IntoFutureFn` that represents a call to `IntoFuture::into_future()`
2008+
/// from the `.await` desugaring.
2009+
///
19632010
/// The `&Expr` is the expression that evaluates
19642011
/// to the object on which the method is being called on (the receiver),
19652012
/// and the `&[Expr]` is the rest of the arguments.
@@ -1972,7 +2019,7 @@ pub enum ExprKind<'hir> {
19722019
/// the `hir_id` of the `MethodCall` node itself.
19732020
///
19742021
/// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
1975-
MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span),
2022+
MethodCall(MethodCallPath<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span),
19762023
/// A tuple (e.g., `(a, b, c, d)`).
19772024
Tup(&'hir [Expr<'hir>]),
19782025
/// A binary operation (e.g., `a + b`, `a * b`).

compiler/rustc_hir/src/intravisit.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -715,8 +715,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
715715
visitor.visit_expr(callee_expression);
716716
walk_list!(visitor, visit_expr, arguments);
717717
}
718-
ExprKind::MethodCall(ref segment, receiver, arguments, _) => {
719-
visitor.visit_path_segment(segment);
718+
ExprKind::MethodCall(ref call_path, receiver, arguments, _) => {
719+
if let &MethodCallPath::Segment(segment) = call_path {
720+
visitor.visit_path_segment(segment);
721+
}
720722
visitor.visit_expr(receiver);
721723
walk_list!(visitor, visit_expr, arguments);
722724
}

compiler/rustc_hir_analysis/src/collect/type_of.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
154154
}
155155
Node::Expr(&Expr {
156156
kind:
157-
ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
157+
ExprKind::MethodCall(hir::MethodCallPath::Segment(segment), ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
158158
..
159159
}) => {
160160
let body_owner = tcx.hir().enclosing_body_owner(hir_id);

compiler/rustc_hir_pretty/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1126,14 +1126,14 @@ impl<'a> State<'a> {
11261126

11271127
fn print_expr_method_call(
11281128
&mut self,
1129-
segment: &hir::PathSegment<'_>,
1129+
segment: hir::MethodCallPath<'_>,
11301130
receiver: &hir::Expr<'_>,
11311131
args: &[hir::Expr<'_>],
11321132
) {
11331133
let base_args = args;
11341134
self.print_expr_maybe_paren(&receiver, parser::PREC_POSTFIX);
11351135
self.word(".");
1136-
self.print_ident(segment.ident);
1136+
self.print_ident(segment.ident());
11371137

11381138
let generic_args = segment.args();
11391139
if !generic_args.args.is_empty() || !generic_args.bindings.is_empty() {

compiler/rustc_hir_typeck/src/callee.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
511511
call_expr,
512512
callee_ty,
513513
&pick,
514-
segment,
514+
hir::MethodCallPath::Segment(segment),
515515
);
516516
if pick.illegal_sized_bound.is_some() {
517517
return;

compiler/rustc_hir_typeck/src/demand.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
807807
};
808808

809809
let Ok(pick) = self.lookup_probe_for_diagnostic(
810-
path.ident,
810+
path.ident(),
811811
self_ty,
812812
deref,
813813
probe::ProbeScope::TraitsInScope,
@@ -817,7 +817,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
817817
};
818818
let in_scope_methods = self.probe_for_name_many(
819819
probe::Mode::MethodCall,
820-
path.ident,
820+
path.ident(),
821821
Some(expected),
822822
probe::IsSuggestion(true),
823823
self_ty,
@@ -829,7 +829,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
829829

830830
let all_methods = self.probe_for_name_many(
831831
probe::Mode::MethodCall,
832-
path.ident,
832+
path.ident(),
833833
Some(expected),
834834
probe::IsSuggestion(true),
835835
self_ty,
@@ -871,9 +871,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
871871
if suggestions.is_empty() {
872872
return;
873873
}
874-
let mut path_span: MultiSpan = path.ident.span.into();
874+
let mut path_span: MultiSpan = path.ident().span.into();
875875
path_span.push_span_label(
876-
path.ident.span,
876+
path.ident().span,
877877
with_no_trimmed_paths!(format!(
878878
"refers to `{}`",
879879
self.tcx.def_path_str(pick.item.def_id),
@@ -921,7 +921,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
921921
path_span,
922922
format!(
923923
"the `{}` call is resolved to the method in `{container}`, shadowing {tail}",
924-
path.ident,
924+
path.ident(),
925925
),
926926
);
927927
if suggestions.len() > other_methods_in_scope.len() {
@@ -1109,7 +1109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11091109
else {
11101110
return;
11111111
};
1112-
maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
1112+
maybe_emit_help(def_id, method.ident(), args, CallableKind::Method)
11131113
}
11141114
_ => return,
11151115
}

compiler/rustc_hir_typeck/src/expr.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
243243
ExprKind::Call(..) if expr.span.is_desugaring(DesugaringKind::TryBlock) => {}
244244
ExprKind::Call(callee, _) => self.warn_if_unreachable(expr.hir_id, callee.span, "call"),
245245
ExprKind::MethodCall(segment, ..) => {
246-
self.warn_if_unreachable(expr.hir_id, segment.ident.span, "call")
246+
self.warn_if_unreachable(expr.hir_id, segment.ident().span, "call")
247247
}
248248
_ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"),
249249
}
@@ -1305,15 +1305,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13051305
fn check_method_call(
13061306
&self,
13071307
expr: &'tcx hir::Expr<'tcx>,
1308-
segment: &hir::PathSegment<'_>,
1308+
segment: hir::MethodCallPath<'_>,
13091309
rcvr: &'tcx hir::Expr<'tcx>,
13101310
args: &'tcx [hir::Expr<'tcx>],
13111311
expected: Expectation<'tcx>,
13121312
) -> Ty<'tcx> {
13131313
let rcvr_t = self.check_expr(&rcvr);
13141314
// no need to check for bot/err -- callee does that
13151315
let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t);
1316-
let span = segment.ident.span;
1316+
let span = segment.ident().span;
13171317

13181318
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
13191319
Ok(method) => {
@@ -1325,11 +1325,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13251325
Ok(method)
13261326
}
13271327
Err(error) => {
1328-
if segment.ident.name != kw::Empty {
1328+
if segment.ident().name != kw::Empty {
13291329
if let Some(mut err) = self.report_method_error(
13301330
span,
13311331
rcvr_t,
1332-
segment.ident,
1332+
segment.ident(),
13331333
SelfSource::MethodCall(rcvr),
13341334
error,
13351335
Some(args),

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1038,9 +1038,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10381038
return;
10391039
}
10401040

1041-
let mut sp = MultiSpan::from_span(path_segment.ident.span);
1041+
let mut sp = MultiSpan::from_span(path_segment.ident().span);
10421042
sp.push_span_label(
1043-
path_segment.ident.span,
1043+
path_segment.ident().span,
10441044
format!(
10451045
"this call modifies {} in-place",
10461046
match rcvr.kind {
@@ -1054,14 +1054,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10541054
);
10551055

10561056
let modifies_rcvr_note =
1057-
format!("method `{}` modifies its receiver in-place", path_segment.ident);
1057+
format!("method `{}` modifies its receiver in-place", path_segment.ident());
10581058
if rcvr_has_the_expected_type {
10591059
sp.push_span_label(
10601060
rcvr.span,
10611061
"you probably want to use this value after calling the method...",
10621062
);
10631063
err.span_note(sp, modifies_rcvr_note);
1064-
err.note(format!("...instead of the `()` output of method `{}`", path_segment.ident));
1064+
err.note(format!("...instead of the `()` output of method `{}`", path_segment.ident()));
10651065
} else if let ExprKind::MethodCall(..) = rcvr.kind {
10661066
err.span_note(
10671067
sp,

0 commit comments

Comments
 (0)