Rollup merge of #90801 - b-naber:missing_normalization_equate_inputs_output, r=jackh726

Normalize both arguments of `equate_normalized_input_or_output`

Fixes https://github.com/rust-lang/rust/issues/90638
Fixes https://github.com/rust-lang/rust/issues/90612

Temporary fix for a more complex underlying problem stemming from an inability to normalize closure substs during typecheck.

r? ````@jackh726````
This commit is contained in:
Yuki Okushi 2021-11-16 15:59:39 +09:00 committed by GitHub
commit 21bff4a4c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 121 additions and 24 deletions

View File

@ -7,13 +7,16 @@
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).
use crate::type_check::constraint_conversion::ConstraintConversion;
use rustc_index::vec::Idx;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::*;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty::Ty;
use rustc_span::Span;
use rustc_trait_selection::traits::query::normalize::AtExt;
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use rustc_trait_selection::traits::query::Fallible;
use type_op::TypeOpOutput;
use crate::universal_regions::UniversalRegions;
@ -30,6 +33,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let (&normalized_output_ty, normalized_input_tys) =
normalized_inputs_and_output.split_last().unwrap();
debug!(?normalized_output_ty);
debug!(?normalized_input_tys);
let mir_def_id = body.source.def_id().expect_local();
// If the user explicitly annotated the input types, extract
@ -75,10 +81,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
break;
}
// In MIR, argument N is stored in local N+1.
let local = Local::new(argument_index + 1);
let mir_input_ty = body.local_decls[local].ty;
let mir_input_span = body.local_decls[local].source_info.span;
self.equate_normalized_input_or_output(
normalized_input_ty,
@ -100,6 +108,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// If the user explicitly annotated the input types, enforce those.
let user_provided_input_ty =
self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
self.equate_normalized_input_or_output(
user_provided_input_ty,
mir_input_ty,
@ -167,30 +176,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
// like to normalize *before* inserting into `local_decls`, but
// doing so ends up causing some other trouble.
let b = match self
.infcx
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
.normalize(b)
{
Ok(n) => {
debug!("equate_inputs_and_outputs: {:?}", n);
if n.obligations.iter().all(|o| {
matches!(
o.predicate.kind().skip_binder(),
ty::PredicateKind::RegionOutlives(_)
| ty::PredicateKind::TypeOutlives(_)
)
}) {
n.value
} else {
b
}
}
let b = match self.normalize_and_add_constraints(b) {
Ok(n) => n,
Err(_) => {
debug!("equate_inputs_and_outputs: NoSolution");
b
}
};
// Note: if we have to introduce new placeholders during normalization above, then we won't have
// added those universes to the universe info, which we would want in `relate_tys`.
if let Err(terr) =
@ -207,4 +200,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
}
pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> {
let TypeOpOutput { output: norm_ty, constraints, .. } =
self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?;
debug!("{:?} normalized to {:?}", t, norm_ty);
for data in constraints.into_iter().collect::<Vec<_>>() {
ConstraintConversion::new(
self.infcx,
&self.borrowck_context.universal_regions,
&self.region_bound_pairs,
Some(self.implicit_region_bound),
self.param_env,
Locations::All(DUMMY_SP),
ConstraintCategory::Internal,
&mut self.borrowck_context.constraints,
)
.convert_all(&*data);
}
Ok(norm_ty)
}
}

View File

@ -893,11 +893,11 @@ struct TypeChecker<'a, 'tcx> {
}
struct BorrowCheckContext<'a, 'tcx> {
universal_regions: &'a UniversalRegions<'tcx>,
pub(crate) universal_regions: &'a UniversalRegions<'tcx>,
location_table: &'a LocationTable,
all_facts: &'a mut Option<AllFacts>,
borrow_set: &'a BorrowSet<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
upvars: &'a [Upvar<'tcx>],
}
@ -1157,6 +1157,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
}
#[instrument(skip(self, category), level = "debug")]
fn eq_types(
&mut self,
expected: Ty<'tcx>,

View File

@ -0,0 +1,43 @@
// check-pass
#![feature(generic_associated_types)]
use std::marker::PhantomData;
trait Family: Sized {
type Item<'a>;
fn apply_all<F>(&self, f: F)
where
F: FamilyItemFn<Self> { }
}
struct Array<T>(PhantomData<T>);
impl<T: 'static> Family for Array<T> {
type Item<'a> = &'a T;
}
trait FamilyItemFn<T: Family> {
fn apply(&self, item: T::Item<'_>);
}
impl<T, F> FamilyItemFn<T> for F
where
T: Family,
for<'a> F: Fn(T::Item<'a>)
{
fn apply(&self, item: T::Item<'_>) {
(*self)(item);
}
}
fn process<T: 'static>(array: Array<T>) {
// Works
array.apply_all(|x: &T| { });
// ICE: NoSolution
array.apply_all(|x: <Array<T> as Family>::Item<'_>| { });
}
fn main() {}

View File

@ -0,0 +1,37 @@
//check-pass
#![feature(generic_associated_types)]
trait Yokeable<'a>: 'static {
type Output: 'a;
}
trait IsCovariant<'a> {}
struct Yoke<Y: for<'a> Yokeable<'a>> {
data: Y,
}
impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
fn project<Y2: for<'a> Yokeable<'a>>(&self, _f: for<'a> fn(<Y as Yokeable<'a>>::Output, &'a ())
-> <Y2 as Yokeable<'a>>::Output) -> Yoke<Y2> {
unimplemented!()
}
}
fn _upcast<Y>(x: Yoke<Y>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> where
Y: for<'a> Yokeable<'a>,
for<'a> <Y as Yokeable<'a>>::Output: IsCovariant<'a>
{
x.project(|data, _| {
Box::new(data)
})
}
impl<'a> Yokeable<'a> for Box<dyn IsCovariant<'static> + 'static> {
type Output = Box<dyn IsCovariant<'a> + 'a>;
}
fn main() {}