Skip to content

Commit d3996cc

Browse files
Rollup merge of rust-lang#88270 - lqd:hrtb-type-ascription, r=nikomatsakis
Handle type ascription type ops in NLL HRTB diagnostics Currently, there are still a few cases of the "higher-ranked subtype error" of yore, 4 of which are related to type ascription. This PR is a follow-up to rust-lang#86700, adding support for type ascription type ops, and makes 3 of these tests output the same diagnostics in NLL mode as the migrate mode (and 1 is now much closer, especially if you ignore that it already outputs an additional error in NLL mode -- which could be a duplicate caused by a lack of normalization like [these comments point out](https://github.com/rust-lang/rust/blob/9583fd1bdd0127328e25e5b8c24dff575ec2c86b/compiler/rustc_traits/src/type_op.rs#L122-L157), or an imprecision in some parts of normalization as [described here](rust-lang#86700 (comment))). Since we discussed these recently: - [here](rust-lang#86700 (comment)), cc ``@matthewjasper,`` - and [here](rust-lang#57374 (comment)), cc ``@Aaron1011.`` It should only leave [this TAIT test](https://github.com/rust-lang/rust/blob/9583fd1bdd0127328e25e5b8c24dff575ec2c86b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs) as still emitting [the terse error](https://github.com/rust-lang/rust/blob/9583fd1bdd0127328e25e5b8c24dff575ec2c86b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr). r? ``@estebank`` (so that they shake their fist at NLL's general direction less often) or ``@nikomatsakis`` or matthew or aaron, the more the merrier.
2 parents b937bd4 + 7b0e564 commit d3996cc

File tree

7 files changed

+77
-46
lines changed

7 files changed

+77
-46
lines changed

compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs

+37-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
99
use rustc_span::Span;
1010
use rustc_trait_selection::traits::query::type_op;
1111
use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
12-
use rustc_traits::type_op_prove_predicate_with_span;
12+
use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
1313

1414
use std::fmt;
1515
use std::rc::Rc;
@@ -104,10 +104,11 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'t
104104
impl<'tcx> ToUniverseInfo<'tcx>
105105
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
106106
{
107-
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
108-
// Ascribe user type isn't usually called on types that have different
109-
// bound regions.
110-
UniverseInfo::other()
107+
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
108+
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
109+
canonical_query: self,
110+
base_universe,
111+
})))
111112
}
112113
}
113114

@@ -267,6 +268,37 @@ where
267268
}
268269
}
269270

271+
struct AscribeUserTypeQuery<'tcx> {
272+
canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
273+
base_universe: ty::UniverseIndex,
274+
}
275+
276+
impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
277+
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
278+
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
279+
// and is only the fallback when the nice error fails. Consider improving this some more.
280+
tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
281+
}
282+
283+
fn base_universe(&self) -> ty::UniverseIndex {
284+
self.base_universe
285+
}
286+
287+
fn nice_error(
288+
&self,
289+
tcx: TyCtxt<'tcx>,
290+
span: Span,
291+
placeholder_region: ty::Region<'tcx>,
292+
error_region: Option<ty::Region<'tcx>>,
293+
) -> Option<DiagnosticBuilder<'tcx>> {
294+
tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
295+
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
296+
type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?;
297+
try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
298+
})
299+
}
300+
}
301+
270302
fn try_extract_error_from_fulfill_cx<'tcx>(
271303
mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
272304
infcx: &InferCtxt<'_, 'tcx>,

compiler/rustc_traits/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ mod normalize_erasing_regions;
1919
mod normalize_projection_ty;
2020
mod type_op;
2121

22-
pub use type_op::type_op_prove_predicate_with_span;
22+
pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
2323

2424
use rustc_middle::ty::query::Providers;
2525

compiler/rustc_traits/src/type_op.rs

+34-14
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,28 @@ fn type_op_ascribe_user_type<'tcx>(
4040
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
4141
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
4242
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
43-
let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
44-
45-
debug!(
46-
"type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
47-
mir_ty, def_id, user_substs
48-
);
43+
type_op_ascribe_user_type_with_span(infcx, fulfill_cx, key, None)
44+
})
45+
}
4946

50-
let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
51-
cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?;
47+
/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
48+
/// this query can be re-run to better track the span of the obligation cause, and improve the error
49+
/// message. Do not call directly unless you're in that very specific context.
50+
pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>(
51+
infcx: &'a InferCtxt<'a, 'tcx>,
52+
fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
53+
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
54+
span: Option<Span>,
55+
) -> Result<(), NoSolution> {
56+
let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
57+
debug!(
58+
"type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
59+
mir_ty, def_id, user_substs
60+
);
5261

53-
Ok(())
54-
})
62+
let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
63+
cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs, span)?;
64+
Ok(())
5565
}
5666

5767
struct AscribeUserTypeCx<'me, 'tcx> {
@@ -85,10 +95,15 @@ impl AscribeUserTypeCx<'me, 'tcx> {
8595
Ok(())
8696
}
8797

88-
fn prove_predicate(&mut self, predicate: Predicate<'tcx>) {
98+
fn prove_predicate(&mut self, predicate: Predicate<'tcx>, span: Option<Span>) {
99+
let cause = if let Some(span) = span {
100+
ObligationCause::dummy_with_span(span)
101+
} else {
102+
ObligationCause::dummy()
103+
};
89104
self.fulfill_cx.register_predicate_obligation(
90105
self.infcx,
91-
Obligation::new(ObligationCause::dummy(), self.param_env, predicate),
106+
Obligation::new(cause, self.param_env, predicate),
92107
);
93108
}
94109

@@ -108,6 +123,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
108123
mir_ty: Ty<'tcx>,
109124
def_id: DefId,
110125
user_substs: UserSubsts<'tcx>,
126+
span: Option<Span>,
111127
) -> Result<(), NoSolution> {
112128
let UserSubsts { user_self_ty, substs } = user_substs;
113129
let tcx = self.tcx();
@@ -129,7 +145,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
129145
debug!(?instantiated_predicates.predicates);
130146
for instantiated_predicate in instantiated_predicates.predicates {
131147
let instantiated_predicate = self.normalize(instantiated_predicate);
132-
self.prove_predicate(instantiated_predicate);
148+
self.prove_predicate(instantiated_predicate, span);
133149
}
134150

135151
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
@@ -141,6 +157,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
141157

142158
self.prove_predicate(
143159
ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
160+
span,
144161
);
145162
}
146163

@@ -155,7 +172,10 @@ impl AscribeUserTypeCx<'me, 'tcx> {
155172
// them? This would only be relevant if some input
156173
// type were ill-formed but did not appear in `ty`,
157174
// which...could happen with normalization...
158-
self.prove_predicate(ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()));
175+
self.prove_predicate(
176+
ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
177+
span,
178+
);
159179
Ok(())
160180
}
161181
}

src/test/ui/hrtb/due-to-where-clause.nll.stderr

-8
This file was deleted.

src/test/ui/hrtb/hrtb-cache-issue-54302.nll.stderr

-8
This file was deleted.

src/test/ui/hrtb/hrtb-just-for-static.nll.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ LL | want_hrtb::<&'a u32>()
1717
|
1818
= help: consider replacing `'a` with `'static`
1919

20-
error: higher-ranked subtype error
20+
error: implementation of `Foo` is not general enough
2121
--> $DIR/hrtb-just-for-static.rs:30:5
2222
|
2323
LL | want_hrtb::<&'a u32>()
24-
| ^^^^^^^^^^^^^^^^^^^^
24+
| ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
25+
|
26+
= note: `Foo<&'0 isize>` would have to be implemented for the type `&u32`, for any lifetime `'0`...
27+
= note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
2528

2629
error: aborting due to 3 previous errors
2730

src/test/ui/issues/issue-54302.nll.stderr

-8
This file was deleted.

0 commit comments

Comments
 (0)