Rollup merge of #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 #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](9583fd1bdd/compiler/rustc_traits/src/type_op.rs (L122-L157)
), or an imprecision in some parts of normalization as [described here](https://github.com/rust-lang/rust/pull/86700#discussion_r689086688)). Since we discussed these recently: - [here](https://github.com/rust-lang/rust/pull/86700#discussion_r689158868), cc ````@matthewjasper,```` - and [here](https://github.com/rust-lang/rust/issues/57374#issuecomment-901500856), cc ````@Aaron1011.```` It should only leave [this TAIT test](9583fd1bdd/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
) as still emitting [the terse error](9583fd1bdd/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.
This commit is contained in:
commit
1e94fe1a45
7 changed files with 78 additions and 47 deletions
|
@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::query::type_op;
|
use rustc_trait_selection::traits::query::type_op;
|
||||||
use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
|
use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
|
||||||
use rustc_traits::type_op_prove_predicate_with_span;
|
use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -104,10 +104,11 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'t
|
||||||
impl<'tcx> ToUniverseInfo<'tcx>
|
impl<'tcx> ToUniverseInfo<'tcx>
|
||||||
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
|
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
|
||||||
{
|
{
|
||||||
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||||
// Ascribe user type isn't usually called on types that have different
|
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
|
||||||
// bound regions.
|
canonical_query: self,
|
||||||
UniverseInfo::other()
|
base_universe,
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +268,37 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AscribeUserTypeQuery<'tcx> {
|
||||||
|
canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
|
||||||
|
base_universe: ty::UniverseIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||||
|
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||||
|
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
|
||||||
|
// and is only the fallback when the nice error fails. Consider improving this some more.
|
||||||
|
tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn base_universe(&self) -> ty::UniverseIndex {
|
||||||
|
self.base_universe
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nice_error(
|
||||||
|
&self,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
placeholder_region: ty::Region<'tcx>,
|
||||||
|
error_region: Option<ty::Region<'tcx>>,
|
||||||
|
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||||
|
tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
|
||||||
|
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
|
||||||
|
type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?;
|
||||||
|
try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn try_extract_error_from_fulfill_cx<'tcx>(
|
fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||||
mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
|
mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
|
|
@ -19,7 +19,7 @@ mod normalize_erasing_regions;
|
||||||
mod normalize_projection_ty;
|
mod normalize_projection_ty;
|
||||||
mod type_op;
|
mod type_op;
|
||||||
|
|
||||||
pub use type_op::type_op_prove_predicate_with_span;
|
pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
|
||||||
|
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
|
|
||||||
|
|
|
@ -40,20 +40,30 @@ fn type_op_ascribe_user_type<'tcx>(
|
||||||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
|
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
|
||||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
|
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
|
||||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
|
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
|
||||||
let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
|
type_op_ascribe_user_type_with_span(infcx, fulfill_cx, key, None)
|
||||||
|
|
||||||
debug!(
|
|
||||||
"type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
|
|
||||||
mir_ty, def_id, user_substs
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
|
|
||||||
cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
|
||||||
|
/// this query can be re-run to better track the span of the obligation cause, and improve the error
|
||||||
|
/// message. Do not call directly unless you're in that very specific context.
|
||||||
|
pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>(
|
||||||
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
|
fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
|
||||||
|
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
|
||||||
|
span: Option<Span>,
|
||||||
|
) -> Result<(), NoSolution> {
|
||||||
|
let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
|
||||||
|
debug!(
|
||||||
|
"type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
|
||||||
|
mir_ty, def_id, user_substs
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
|
||||||
|
cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs, span)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
struct AscribeUserTypeCx<'me, 'tcx> {
|
struct AscribeUserTypeCx<'me, 'tcx> {
|
||||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||||
param_env: ParamEnv<'tcx>,
|
param_env: ParamEnv<'tcx>,
|
||||||
|
@ -85,10 +95,15 @@ impl AscribeUserTypeCx<'me, 'tcx> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prove_predicate(&mut self, predicate: Predicate<'tcx>) {
|
fn prove_predicate(&mut self, predicate: Predicate<'tcx>, span: Option<Span>) {
|
||||||
|
let cause = if let Some(span) = span {
|
||||||
|
ObligationCause::dummy_with_span(span)
|
||||||
|
} else {
|
||||||
|
ObligationCause::dummy()
|
||||||
|
};
|
||||||
self.fulfill_cx.register_predicate_obligation(
|
self.fulfill_cx.register_predicate_obligation(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
Obligation::new(ObligationCause::dummy(), self.param_env, predicate),
|
Obligation::new(cause, self.param_env, predicate),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +123,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
|
||||||
mir_ty: Ty<'tcx>,
|
mir_ty: Ty<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
user_substs: UserSubsts<'tcx>,
|
user_substs: UserSubsts<'tcx>,
|
||||||
|
span: Option<Span>,
|
||||||
) -> Result<(), NoSolution> {
|
) -> Result<(), NoSolution> {
|
||||||
let UserSubsts { user_self_ty, substs } = user_substs;
|
let UserSubsts { user_self_ty, substs } = user_substs;
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
@ -129,7 +145,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
|
||||||
debug!(?instantiated_predicates.predicates);
|
debug!(?instantiated_predicates.predicates);
|
||||||
for instantiated_predicate in instantiated_predicates.predicates {
|
for instantiated_predicate in instantiated_predicates.predicates {
|
||||||
let instantiated_predicate = self.normalize(instantiated_predicate);
|
let instantiated_predicate = self.normalize(instantiated_predicate);
|
||||||
self.prove_predicate(instantiated_predicate);
|
self.prove_predicate(instantiated_predicate, span);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
|
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
|
||||||
|
@ -141,6 +157,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
|
||||||
|
|
||||||
self.prove_predicate(
|
self.prove_predicate(
|
||||||
ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
|
ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
|
||||||
|
span,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +172,10 @@ impl AscribeUserTypeCx<'me, 'tcx> {
|
||||||
// them? This would only be relevant if some input
|
// them? This would only be relevant if some input
|
||||||
// type were ill-formed but did not appear in `ty`,
|
// type were ill-formed but did not appear in `ty`,
|
||||||
// which...could happen with normalization...
|
// which...could happen with normalization...
|
||||||
self.prove_predicate(ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()));
|
self.prove_predicate(
|
||||||
|
ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
|
||||||
|
span,
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
error: higher-ranked subtype error
|
|
||||||
--> $DIR/due-to-where-clause.rs:2:5
|
|
||||||
|
|
|
||||||
LL | test::<FooS>(&mut 42);
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
error: higher-ranked subtype error
|
|
||||||
--> $DIR/hrtb-cache-issue-54302.rs:19:5
|
|
||||||
|
|
|
||||||
LL | assert_deserialize_owned::<&'static str>();
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
|
@ -17,11 +17,14 @@ LL | want_hrtb::<&'a u32>()
|
||||||
|
|
|
|
||||||
= help: consider replacing `'a` with `'static`
|
= help: consider replacing `'a` with `'static`
|
||||||
|
|
||||||
error: higher-ranked subtype error
|
error: implementation of `Foo` is not general enough
|
||||||
--> $DIR/hrtb-just-for-static.rs:30:5
|
--> $DIR/hrtb-just-for-static.rs:30:5
|
||||||
|
|
|
|
||||||
LL | want_hrtb::<&'a u32>()
|
LL | want_hrtb::<&'a u32>()
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
||||||
|
|
|
||||||
|
= note: `Foo<&'0 isize>` would have to be implemented for the type `&u32`, for any lifetime `'0`...
|
||||||
|
= note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
error: higher-ranked subtype error
|
|
||||||
--> $DIR/issue-54302.rs:13:5
|
|
||||||
|
|
|
||||||
LL | assert_deserialize_owned::<&'static str>();
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue