Skip to content

Commit

Permalink
Rollup merge of rust-lang#90801 - b-naber:missing_normalization_equat…
Browse files Browse the repository at this point in the history
…e_inputs_output, r=jackh726

Normalize both arguments of `equate_normalized_input_or_output`

Fixes rust-lang#90638
Fixes rust-lang#90612

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

r? `@jackh726`
  • Loading branch information
matthiaskrgr authored Nov 15, 2021
2 parents 58d8d39 + 7a4aa65 commit 82b4e6a
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 24 deletions.
60 changes: 38 additions & 22 deletions compiler/rustc_borrowck/src/type_check/input_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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) =
Expand All @@ -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)
}
}
5 changes: 3 additions & 2 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>],
}

Expand Down Expand Up @@ -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>,
Expand Down
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit 82b4e6a

Please sign in to comment.