|
2 | 2 | //! as well as errors when attempting to call a non-const function in a const
|
3 | 3 | //! context.
|
4 | 4 |
|
| 5 | +use rustc_hir::def::DefKind; |
5 | 6 | use rustc_hir::def_id::DefId;
|
6 | 7 | use rustc_hir::{LangItem, lang_items};
|
| 8 | +use rustc_middle::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv}; |
7 | 9 | use rustc_span::{DesugaringKind, Ident, Span, sym};
|
8 | 10 | use tracing::debug;
|
9 | 11 |
|
10 |
| -use crate::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv}; |
| 12 | +use crate::traits::specialization_graph; |
11 | 13 |
|
12 | 14 | #[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
13 | 15 | pub enum CallDesugaringKind {
|
@@ -55,7 +57,7 @@ pub enum CallKind<'tcx> {
|
55 | 57 | DerefCoercion {
|
56 | 58 | /// The `Span` of the `Target` associated type
|
57 | 59 | /// in the `Deref` impl we are using.
|
58 |
| - deref_target: Span, |
| 60 | + deref_target_span: Option<Span>, |
59 | 61 | /// The type `T::Deref` we are dereferencing to
|
60 | 62 | deref_target_ty: Ty<'tcx>,
|
61 | 63 | self_ty: Ty<'tcx>,
|
@@ -89,61 +91,65 @@ pub fn call_kind<'tcx>(
|
89 | 91 | None
|
90 | 92 | };
|
91 | 93 |
|
92 |
| - let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); |
93 |
| - |
94 | 94 | // Check for a 'special' use of 'self' -
|
95 | 95 | // an FnOnce call, an operator (e.g. `<<`), or a
|
96 | 96 | // deref coercion.
|
97 |
| - let kind = if let Some(trait_id) = fn_call { |
98 |
| - Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_args.type_at(0) }) |
| 97 | + if let Some(trait_id) = fn_call { |
| 98 | + return CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_args.type_at(0) }; |
99 | 99 | } else if let Some(trait_id) = operator {
|
100 |
| - Some(CallKind::Operator { self_arg, trait_id, self_ty: method_args.type_at(0) }) |
101 |
| - } else if is_deref { |
102 |
| - let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { |
103 |
| - Instance::try_resolve(tcx, typing_env, deref_target, method_args).transpose() |
104 |
| - }); |
105 |
| - if let Some(Ok(instance)) = deref_target { |
106 |
| - let deref_target_ty = instance.ty(tcx, typing_env); |
107 |
| - Some(CallKind::DerefCoercion { |
108 |
| - deref_target: tcx.def_span(instance.def_id()), |
109 |
| - deref_target_ty, |
110 |
| - self_ty: method_args.type_at(0), |
111 |
| - }) |
| 100 | + return CallKind::Operator { self_arg, trait_id, self_ty: method_args.type_at(0) }; |
| 101 | + } else if !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did) { |
| 102 | + let deref_target_def_id = |
| 103 | + tcx.get_diagnostic_item(sym::deref_target).expect("deref method but no deref target"); |
| 104 | + let deref_target_ty = tcx.normalize_erasing_regions( |
| 105 | + typing_env, |
| 106 | + Ty::new_projection(tcx, deref_target_def_id, method_args), |
| 107 | + ); |
| 108 | + let deref_target_span = if let Ok(Some(instance)) = |
| 109 | + Instance::try_resolve(tcx, typing_env, method_did, method_args) |
| 110 | + && let instance_parent_def_id = tcx.parent(instance.def_id()) |
| 111 | + && matches!(tcx.def_kind(instance_parent_def_id), DefKind::Impl { .. }) |
| 112 | + && let Ok(instance) = |
| 113 | + specialization_graph::assoc_def(tcx, instance_parent_def_id, deref_target_def_id) |
| 114 | + && instance.is_final() |
| 115 | + { |
| 116 | + Some(tcx.def_span(instance.item.def_id)) |
| 117 | + } else { |
| 118 | + None |
| 119 | + }; |
| 120 | + return CallKind::DerefCoercion { |
| 121 | + deref_target_ty, |
| 122 | + deref_target_span, |
| 123 | + self_ty: method_args.type_at(0), |
| 124 | + }; |
| 125 | + } |
| 126 | + |
| 127 | + // This isn't a 'special' use of `self` |
| 128 | + debug!(?method_did, ?fn_call_span); |
| 129 | + let desugaring = if tcx.is_lang_item(method_did, LangItem::IntoIterIntoIter) |
| 130 | + && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop) |
| 131 | + { |
| 132 | + Some((CallDesugaringKind::ForLoopIntoIter, method_args.type_at(0))) |
| 133 | + } else if tcx.is_lang_item(method_did, LangItem::IteratorNext) |
| 134 | + && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop) |
| 135 | + { |
| 136 | + Some((CallDesugaringKind::ForLoopNext, method_args.type_at(0))) |
| 137 | + } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) { |
| 138 | + if tcx.is_lang_item(method_did, LangItem::TryTraitBranch) { |
| 139 | + Some((CallDesugaringKind::QuestionBranch, method_args.type_at(0))) |
| 140 | + } else if tcx.is_lang_item(method_did, LangItem::TryTraitFromResidual) { |
| 141 | + Some((CallDesugaringKind::QuestionFromResidual, method_args.type_at(0))) |
112 | 142 | } else {
|
113 | 143 | None
|
114 | 144 | }
|
| 145 | + } else if tcx.is_lang_item(method_did, LangItem::TryTraitFromOutput) |
| 146 | + && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock) |
| 147 | + { |
| 148 | + Some((CallDesugaringKind::TryBlockFromOutput, method_args.type_at(0))) |
| 149 | + } else if fn_call_span.is_desugaring(DesugaringKind::Await) { |
| 150 | + Some((CallDesugaringKind::Await, method_args.type_at(0))) |
115 | 151 | } else {
|
116 | 152 | None
|
117 | 153 | };
|
118 |
| - |
119 |
| - kind.unwrap_or_else(|| { |
120 |
| - // This isn't a 'special' use of `self` |
121 |
| - debug!(?method_did, ?fn_call_span); |
122 |
| - let desugaring = if tcx.is_lang_item(method_did, LangItem::IntoIterIntoIter) |
123 |
| - && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop) |
124 |
| - { |
125 |
| - Some((CallDesugaringKind::ForLoopIntoIter, method_args.type_at(0))) |
126 |
| - } else if tcx.is_lang_item(method_did, LangItem::IteratorNext) |
127 |
| - && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop) |
128 |
| - { |
129 |
| - Some((CallDesugaringKind::ForLoopNext, method_args.type_at(0))) |
130 |
| - } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) { |
131 |
| - if tcx.is_lang_item(method_did, LangItem::TryTraitBranch) { |
132 |
| - Some((CallDesugaringKind::QuestionBranch, method_args.type_at(0))) |
133 |
| - } else if tcx.is_lang_item(method_did, LangItem::TryTraitFromResidual) { |
134 |
| - Some((CallDesugaringKind::QuestionFromResidual, method_args.type_at(0))) |
135 |
| - } else { |
136 |
| - None |
137 |
| - } |
138 |
| - } else if tcx.is_lang_item(method_did, LangItem::TryTraitFromOutput) |
139 |
| - && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock) |
140 |
| - { |
141 |
| - Some((CallDesugaringKind::TryBlockFromOutput, method_args.type_at(0))) |
142 |
| - } else if fn_call_span.is_desugaring(DesugaringKind::Await) { |
143 |
| - Some((CallDesugaringKind::Await, method_args.type_at(0))) |
144 |
| - } else { |
145 |
| - None |
146 |
| - }; |
147 |
| - CallKind::Normal { self_arg, desugaring, method_did, method_args } |
148 |
| - }) |
| 154 | + CallKind::Normal { self_arg, desugaring, method_did, method_args } |
149 | 155 | }
|
0 commit comments