• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Common logic for borrowck use-after-move errors when moved into a `fn(self)`,
2 //! as well as errors when attempting to call a non-const function in a const
3 //! context.
4 
5 use crate::ty::subst::SubstsRef;
6 use crate::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt};
7 use rustc_hir::def_id::DefId;
8 use rustc_hir::{lang_items, LangItem};
9 use rustc_span::symbol::Ident;
10 use rustc_span::{sym, DesugaringKind, Span};
11 
12 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
13 pub enum CallDesugaringKind {
14     /// for _ in x {} calls x.into_iter()
15     ForLoopIntoIter,
16     /// x? calls x.branch()
17     QuestionBranch,
18     /// x? calls type_of(x)::from_residual()
19     QuestionFromResidual,
20     /// try { ..; x } calls type_of(x)::from_output(x)
21     TryBlockFromOutput,
22     /// `.await` calls `IntoFuture::into_future`
23     Await,
24 }
25 
26 impl CallDesugaringKind {
trait_def_id(self, tcx: TyCtxt<'_>) -> DefId27     pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId {
28         match self {
29             Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(),
30             Self::QuestionBranch | Self::TryBlockFromOutput => {
31                 tcx.require_lang_item(LangItem::Try, None)
32             }
33             Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
34             Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(),
35         }
36     }
37 }
38 
39 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
40 pub enum CallKind<'tcx> {
41     /// A normal method call of the form `receiver.foo(a, b, c)`
42     Normal {
43         self_arg: Option<Ident>,
44         desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>,
45         method_did: DefId,
46         method_substs: SubstsRef<'tcx>,
47     },
48     /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
49     FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> },
50     /// A call to an operator trait, desugared from operator syntax (e.g. `a << b`)
51     Operator { self_arg: Option<Ident>, trait_id: DefId, self_ty: Ty<'tcx> },
52     DerefCoercion {
53         /// The `Span` of the `Target` associated type
54         /// in the `Deref` impl we are using.
55         deref_target: Span,
56         /// The type `T::Deref` we are dereferencing to
57         deref_target_ty: Ty<'tcx>,
58         self_ty: Ty<'tcx>,
59     },
60 }
61 
call_kind<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, method_did: DefId, method_substs: SubstsRef<'tcx>, fn_call_span: Span, from_hir_call: bool, self_arg: Option<Ident>, ) -> CallKind<'tcx>62 pub fn call_kind<'tcx>(
63     tcx: TyCtxt<'tcx>,
64     param_env: ParamEnv<'tcx>,
65     method_did: DefId,
66     method_substs: SubstsRef<'tcx>,
67     fn_call_span: Span,
68     from_hir_call: bool,
69     self_arg: Option<Ident>,
70 ) -> CallKind<'tcx> {
71     let parent = tcx.opt_associated_item(method_did).and_then(|assoc| {
72         let container_id = assoc.container_id(tcx);
73         match assoc.container {
74             AssocItemContainer::ImplContainer => tcx.trait_id_of_impl(container_id),
75             AssocItemContainer::TraitContainer => Some(container_id),
76         }
77     });
78 
79     let fn_call = parent.and_then(|p| {
80         lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
81     });
82 
83     let operator = if !from_hir_call && let Some(p) = parent {
84         lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
85     } else {
86         None
87     };
88 
89     let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
90 
91     // Check for a 'special' use of 'self' -
92     // an FnOnce call, an operator (e.g. `<<`), or a
93     // deref coercion.
94     let kind = if let Some(trait_id) = fn_call {
95         Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) })
96     } else if let Some(trait_id) = operator {
97         Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) })
98     } else if is_deref {
99         let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
100             Instance::resolve(tcx, param_env, deref_target, method_substs).transpose()
101         });
102         if let Some(Ok(instance)) = deref_target {
103             let deref_target_ty = instance.ty(tcx, param_env);
104             Some(CallKind::DerefCoercion {
105                 deref_target: tcx.def_span(instance.def_id()),
106                 deref_target_ty,
107                 self_ty: method_substs.type_at(0),
108             })
109         } else {
110             None
111         }
112     } else {
113         None
114     };
115 
116     kind.unwrap_or_else(|| {
117         // This isn't a 'special' use of `self`
118         debug!(?method_did, ?fn_call_span);
119         let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn()
120             && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop)
121         {
122             Some((CallDesugaringKind::ForLoopIntoIter, method_substs.type_at(0)))
123         } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) {
124             if Some(method_did) == tcx.lang_items().branch_fn() {
125                 Some((CallDesugaringKind::QuestionBranch, method_substs.type_at(0)))
126             } else if Some(method_did) == tcx.lang_items().from_residual_fn() {
127                 Some((CallDesugaringKind::QuestionFromResidual, method_substs.type_at(0)))
128             } else {
129                 None
130             }
131         } else if Some(method_did) == tcx.lang_items().from_output_fn()
132             && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock)
133         {
134             Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0)))
135         } else if fn_call_span.is_desugaring(DesugaringKind::Await) {
136             Some((CallDesugaringKind::Await, method_substs.type_at(0)))
137         } else {
138             None
139         };
140         CallKind::Normal { self_arg, desugaring, method_did, method_substs }
141     })
142 }
143