Skip to content

Commit 40f5861

Browse files
authored
Rollup merge of rust-lang#135426 - compiler-errors:no-resolve-assoc-ty, r=lcnr
Assert that `Instance::try_resolve` is only used on body-like things `Instance::resolve` is not set up to resolve items that are not body-like things. The logic in `resolve_associated_item` very much encodes this assumption: https://github.com/rust-lang/rust/blob/e7ad3ae331bf2716389c10e01612e201a7f98c8d/compiler/rustc_ty_utils/src/instance.rs#L96-L386 However, some diagnostics were using `Instance::resolve` on an associated type, and it was simply a lucky coicidence that nothing went wrong. This PR adds an assertion to make sure we won't do this again in the future, and fixes two callsites: 1. `call_kind` which returns a `CallKind` enum to categorize what a call in MIR comes from, and was using `Instance::resolve` to point at the associated type `Deref::Target` for a specific self ty. 2. `MirBorrowckCtxt::explain_deref_coercion`, which was doing the same thing. The logic was replaced with `specialization_graph::assoc_def`, which is the proper way of fetching the right `AssocItem` for a given impl. r? `@lcnr` or re-roll :)
2 parents b8dab0e + 9bf9f5d commit 40f5861

File tree

10 files changed

+116
-97
lines changed

10 files changed

+116
-97
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+25-34
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_middle::bug;
2020
use rustc_middle::hir::nested_filter::OnlyBodies;
2121
use rustc_middle::mir::tcx::PlaceTy;
2222
use rustc_middle::mir::{
23-
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
23+
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
2424
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
2525
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
2626
TerminatorKind, VarBindingForm, VarDebugInfoContents,
@@ -30,13 +30,13 @@ use rustc_middle::ty::{
3030
self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
3131
suggest_constraining_type_params,
3232
};
33-
use rustc_middle::util::CallKind;
3433
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
3534
use rustc_span::def_id::{DefId, LocalDefId};
3635
use rustc_span::hygiene::DesugaringKind;
3736
use rustc_span::{BytePos, Ident, Span, Symbol, kw, sym};
3837
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
3938
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
39+
use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;
4040
use rustc_trait_selection::infer::InferCtxtExt;
4141
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
4242
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
@@ -46,7 +46,7 @@ use super::explain_borrow::{BorrowExplanation, LaterUseKind};
4646
use super::{DescribePlaceOpt, RegionName, RegionNameSource, UseSpans};
4747
use crate::borrow_set::{BorrowData, TwoPhaseActivation};
4848
use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
49-
use crate::diagnostics::{CapturedMessageOpt, Instance, find_all_local_uses};
49+
use crate::diagnostics::{CapturedMessageOpt, call_kind, find_all_local_uses};
5050
use crate::prefixes::IsPrefixOf;
5151
use crate::{InitializationRequiringAction, MirBorrowckCtxt, WriteKind, borrowck_errors};
5252

@@ -305,7 +305,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
305305
}
306306

307307
if let UseSpans::FnSelfUse {
308-
kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. },
308+
kind: CallKind::DerefCoercion { deref_target_span, deref_target_ty, .. },
309309
..
310310
} = use_spans
311311
{
@@ -315,8 +315,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
315315
));
316316

317317
// Check first whether the source is accessible (issue #87060)
318-
if self.infcx.tcx.sess.source_map().is_span_accessible(deref_target) {
319-
err.span_note(deref_target, "deref defined here");
318+
if let Some(deref_target_span) = deref_target_span
319+
&& self.infcx.tcx.sess.source_map().is_span_accessible(deref_target_span)
320+
{
321+
err.span_note(deref_target_span, "deref defined here");
320322
}
321323
}
322324

@@ -3765,38 +3767,27 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
37653767

37663768
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diag<'_>) {
37673769
let tcx = self.infcx.tcx;
3768-
if let (
3769-
Some(Terminator {
3770-
kind: TerminatorKind::Call { call_source: CallSource::OverloadedOperator, .. },
3771-
..
3772-
}),
3773-
Some((method_did, method_args)),
3774-
) = (
3775-
&self.body[loan.reserve_location.block].terminator,
3776-
rustc_middle::util::find_self_call(
3770+
if let Some(Terminator { kind: TerminatorKind::Call { call_source, fn_span, .. }, .. }) =
3771+
&self.body[loan.reserve_location.block].terminator
3772+
&& let Some((method_did, method_args)) = rustc_middle::util::find_self_call(
37773773
tcx,
37783774
self.body,
37793775
loan.assigned_place.local,
37803776
loan.reserve_location.block,
3781-
),
3782-
) {
3783-
if tcx.is_diagnostic_item(sym::deref_method, method_did) {
3784-
let deref_target =
3785-
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
3786-
Instance::try_resolve(
3787-
tcx,
3788-
self.infcx.typing_env(self.infcx.param_env),
3789-
deref_target,
3790-
method_args,
3791-
)
3792-
.transpose()
3793-
});
3794-
if let Some(Ok(instance)) = deref_target {
3795-
let deref_target_ty =
3796-
instance.ty(tcx, self.infcx.typing_env(self.infcx.param_env));
3797-
err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`"));
3798-
err.span_note(tcx.def_span(instance.def_id()), "deref defined here");
3799-
}
3777+
)
3778+
&& let CallKind::DerefCoercion { deref_target_span, deref_target_ty, .. } = call_kind(
3779+
self.infcx.tcx,
3780+
self.infcx.typing_env(self.infcx.param_env),
3781+
method_did,
3782+
method_args,
3783+
*fn_span,
3784+
call_source.from_hir_call(),
3785+
Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
3786+
)
3787+
{
3788+
err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`"));
3789+
if let Some(deref_target_span) = deref_target_span {
3790+
err.span_note(deref_target_span, "deref defined here");
38003791
}
38013792
}
38023793
}

compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use rustc_middle::mir::{
1616
};
1717
use rustc_middle::ty::adjustment::PointerCoercion;
1818
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
19-
use rustc_middle::util::CallKind;
2019
use rustc_span::{DesugaringKind, Span, kw, sym};
2120
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
21+
use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;
2222
use tracing::{debug, instrument};
2323

2424
use super::{RegionName, UseSpans, find_use};

compiler/rustc_borrowck/src/diagnostics/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ use rustc_middle::mir::{
2020
StatementKind, Terminator, TerminatorKind,
2121
};
2222
use rustc_middle::ty::print::Print;
23-
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
24-
use rustc_middle::util::{CallDesugaringKind, call_kind};
23+
use rustc_middle::ty::{self, Ty, TyCtxt};
2524
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex};
2625
use rustc_span::def_id::LocalDefId;
2726
use rustc_span::source_map::Spanned;
2827
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
2928
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
29+
use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};
3030
use rustc_trait_selection::infer::InferCtxtExt;
3131
use rustc_trait_selection::traits::{
3232
FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
@@ -63,7 +63,7 @@ pub(crate) use mutability_errors::AccessKind;
6363
pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder;
6464
pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
6565
pub(crate) use region_name::{RegionName, RegionNameSource};
66-
pub(crate) use rustc_middle::util::CallKind;
66+
pub(crate) use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;
6767

6868
pub(super) struct DescribePlaceOpt {
6969
including_downcast: bool,

compiler/rustc_const_eval/src/check_consts/ops.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ use rustc_middle::ty::{
1414
self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty,
1515
suggest_constraining_type_param,
1616
};
17-
use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind};
1817
use rustc_session::parse::add_feature_diagnostics;
1918
use rustc_span::{BytePos, Pos, Span, Symbol, sym};
19+
use rustc_trait_selection::error_reporting::traits::call_kind::{
20+
CallDesugaringKind, CallKind, call_kind,
21+
};
2022
use rustc_trait_selection::traits::SelectionContext;
2123
use tracing::debug;
2224

@@ -324,10 +326,12 @@ fn build_error_for_const_call<'tcx>(
324326
note_trait_if_possible(&mut err, self_ty, trait_id);
325327
err
326328
}
327-
CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
329+
CallKind::DerefCoercion { deref_target_span, deref_target_ty, self_ty } => {
328330
// Check first whether the source is accessible (issue #87060)
329-
let target = if tcx.sess.source_map().is_span_accessible(deref_target) {
330-
Some(deref_target)
331+
let target = if let Some(deref_target_span) = deref_target_span
332+
&& tcx.sess.source_map().is_span_accessible(deref_target_span)
333+
{
334+
Some(deref_target_span)
331335
} else {
332336
None
333337
};

compiler/rustc_middle/src/ty/instance.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::path::PathBuf;
55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_errors::ErrorGuaranteed;
77
use rustc_hir as hir;
8-
use rustc_hir::def::Namespace;
8+
use rustc_hir::def::{CtorKind, DefKind, Namespace};
99
use rustc_hir::def_id::{CrateNum, DefId};
1010
use rustc_hir::lang_items::LangItem;
1111
use rustc_index::bit_set::FiniteBitSet;
@@ -498,7 +498,8 @@ impl<'tcx> Instance<'tcx> {
498498

499499
/// Resolves a `(def_id, args)` pair to an (optional) instance -- most commonly,
500500
/// this is used to find the precise code that will run for a trait method invocation,
501-
/// if known.
501+
/// if known. This should only be used for functions and consts. If you want to
502+
/// resolve an associated type, use [`TyCtxt::try_normalize_erasing_regions`].
502503
///
503504
/// Returns `Ok(None)` if we cannot resolve `Instance` to a specific instance.
504505
/// For example, in a context like this,
@@ -527,6 +528,23 @@ impl<'tcx> Instance<'tcx> {
527528
def_id: DefId,
528529
args: GenericArgsRef<'tcx>,
529530
) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
531+
assert_matches!(
532+
tcx.def_kind(def_id),
533+
DefKind::Fn
534+
| DefKind::AssocFn
535+
| DefKind::Const
536+
| DefKind::AssocConst
537+
| DefKind::AnonConst
538+
| DefKind::InlineConst
539+
| DefKind::Static { .. }
540+
| DefKind::Ctor(_, CtorKind::Fn)
541+
| DefKind::Closure
542+
| DefKind::SyntheticCoroutineBody,
543+
"`Instance::try_resolve` should only be used to resolve instances of \
544+
functions, statics, and consts; to resolve associated types, use \
545+
`try_normalize_erasing_regions`."
546+
);
547+
530548
// Rust code can easily create exponentially-long types using only a
531549
// polynomial recursion depth. Even with the default recursion
532550
// depth, you can easily get cases that take >2^60 steps to run,

compiler/rustc_middle/src/util/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
pub mod bug;
2-
pub mod call_kind;
32
pub mod common;
43
pub mod find_self_call;
54

6-
pub use call_kind::{CallDesugaringKind, CallKind, call_kind};
75
pub use find_self_call::find_self_call;
86

97
#[derive(Default, Copy, Clone)]

compiler/rustc_middle/src/util/call_kind.rs renamed to compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs

+55-49
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
//! as well as errors when attempting to call a non-const function in a const
33
//! context.
44
5+
use rustc_hir::def::DefKind;
56
use rustc_hir::def_id::DefId;
67
use rustc_hir::{LangItem, lang_items};
8+
use rustc_middle::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv};
79
use rustc_span::{DesugaringKind, Ident, Span, sym};
810
use tracing::debug;
911

10-
use crate::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv};
12+
use crate::traits::specialization_graph;
1113

1214
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1315
pub enum CallDesugaringKind {
@@ -55,7 +57,7 @@ pub enum CallKind<'tcx> {
5557
DerefCoercion {
5658
/// The `Span` of the `Target` associated type
5759
/// in the `Deref` impl we are using.
58-
deref_target: Span,
60+
deref_target_span: Option<Span>,
5961
/// The type `T::Deref` we are dereferencing to
6062
deref_target_ty: Ty<'tcx>,
6163
self_ty: Ty<'tcx>,
@@ -89,61 +91,65 @@ pub fn call_kind<'tcx>(
8991
None
9092
};
9193

92-
let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
93-
9494
// Check for a 'special' use of 'self' -
9595
// an FnOnce call, an operator (e.g. `<<`), or a
9696
// 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) };
9999
} 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)))
112142
} else {
113143
None
114144
}
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)))
115151
} else {
116152
None
117153
};
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 }
149155
}

compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod ambiguity;
2+
pub mod call_kind;
23
mod fulfillment_errors;
34
pub mod on_unimplemented;
45
mod overflow;

tests/ui/self/arbitrary-self-from-method-substs-ice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ impl Foo {
1111
//~^ ERROR invalid generic `self` parameter type
1212
//~| ERROR destructor of `R` cannot be evaluated at compile-time
1313
self.0
14-
//~^ ERROR cannot call conditionally-const method `<R as Deref>::deref` in constant function
14+
//~^ ERROR cannot perform conditionally-const deref coercion on `R` in constant functions
1515
}
1616
}
1717

tests/ui/self/arbitrary-self-from-method-substs-ice.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
error[E0658]: cannot call conditionally-const method `<R as Deref>::deref` in constant functions
1+
error[E0658]: cannot perform conditionally-const deref coercion on `R` in constant functions
22
--> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9
33
|
44
LL | self.0
55
| ^^^^^^
66
|
7+
= note: attempting to deref into `Foo`
78
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
89
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
910
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable

0 commit comments

Comments
 (0)