Skip to content

Commit

Permalink
nll: don't normalize types for implied bounds
Browse files Browse the repository at this point in the history
We now do it automatically inside implied_outlives_bounds query.
  • Loading branch information
aliemjay committed Mar 23, 2023
1 parent ba76f10 commit e9e0e7e
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 117 deletions.
104 changes: 18 additions & 86 deletions compiler/rustc_borrowck/src/type_check/free_region_relations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty::{self, RegionVid, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc;
use type_op::TypeOpOutput;
Expand All @@ -35,16 +34,9 @@ pub(crate) struct UniversalRegionRelations<'tcx> {
inverse_outlives: TransitiveRelation<RegionVid>,
}

/// As part of computing the free region relations, we also have to
/// normalize the input-output types, which we then need later. So we
/// return those. This vector consists of first the input types and
/// then the output type as the last element.
type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;

pub(crate) struct CreateResult<'tcx> {
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
}

pub(crate) fn create<'tcx>(
Expand Down Expand Up @@ -222,68 +214,27 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
.chain(Some(self.universal_regions.unnormalized_output_ty));

// For each of the input/output types:
// - Normalize the type. This will create some region
// constraints, which we buffer up because we are
// not ready to process them yet.
// - Then compute the implied bounds. This will adjust
// - Compute the implied bounds. This will adjust
// the `region_bound_pairs` and so forth.
// - After this is done, we'll process the constraints, once
// the `relations` is built.
let mut normalized_inputs_and_output =
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
let mut constraints = vec![];
for ty in unnormalized_input_output_tys {
debug!("build: input_or_output={:?}", ty);
// We add implied bounds from both the unnormalized and normalized ty.
// See issue #87748
let constraints_unnorm = self.add_implied_bounds(ty);
if let Some(c) = constraints_unnorm {
constraints.push(c)
}
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
.fully_perform(self.infcx)
.unwrap_or_else(|_| {
let guar = self
.infcx
.tcx
.sess
.delay_span_bug(span, &format!("failed to normalize {:?}", ty));
TypeOpOutput {
output: self.infcx.tcx.ty_error(guar),
constraints: None,
error_info: None,
}
});
if let Some(c) = constraints_normalize {
constraints.push(c)
}

// Note: we need this in examples like
// ```
// trait Foo {
// type Bar;
// fn foo(&self) -> &Self::Bar;
// }
// impl Foo for () {
// type Bar = ();
// fn foo(&self) ->&() {}
// }
// ```
// Both &Self::Bar and &() are WF
if ty != norm_ty {
let constraints_norm = self.add_implied_bounds(norm_ty);
if let Some(c) = constraints_norm {
constraints.push(c)
}
}

normalized_inputs_and_output.push(norm_ty);
}

for c in constraints {
self.push_region_constraints(c, span);
let constraint_sets: Vec<_> =
unnormalized_input_output_tys.flat_map(|ty| self.add_implied_bounds(ty)).collect();

// Subtle: We can convert constraints only after the relations are built.
for data in &constraint_sets {
constraint_conversion::ConstraintConversion::new(
self.infcx,
&self.universal_regions,
&self.region_bound_pairs,
self.implicit_region_bound,
self.param_env,
Locations::All(span),
span,
ConstraintCategory::Internal,
&mut self.constraints,
)
.convert_all(data);
}

CreateResult {
Expand All @@ -293,28 +244,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
inverse_outlives: self.inverse_outlives.freeze(),
}),
region_bound_pairs: self.region_bound_pairs,
normalized_inputs_and_output,
}
}

#[instrument(skip(self, data), level = "debug")]
fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) {
debug!("constraints generated: {:#?}", data);

constraint_conversion::ConstraintConversion::new(
self.infcx,
&self.universal_regions,
&self.region_bound_pairs,
self.implicit_region_bound,
self.param_env,
Locations::All(span),
span,
ConstraintCategory::Internal,
&mut self.constraints,
)
.convert_all(data);
}

/// Update the type of a single local, which should represent
/// either the return type of the MIR or one of its arguments. At
/// the same time, compute and add any implied bounds that come
Expand Down
25 changes: 11 additions & 14 deletions compiler/rustc_borrowck/src/type_check/input_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;

use crate::universal_regions::UniversalRegions;

use super::{Locations, TypeChecker};

impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Expand Down Expand Up @@ -60,21 +58,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}

#[instrument(skip(self, body, universal_regions), level = "debug")]
pub(super) fn equate_inputs_and_outputs(
&mut self,
body: &Body<'tcx>,
universal_regions: &UniversalRegions<'tcx>,
normalized_inputs_and_output: &[Ty<'tcx>],
) {
let (&normalized_output_ty, normalized_input_tys) =
normalized_inputs_and_output.split_last().unwrap();
#[instrument(skip(self, body), level = "debug")]
pub(super) fn equate_inputs_and_outputs(&mut self, body: &Body<'tcx>) {
let universal_regions = self.borrowck_context.universal_regions;

debug!(?normalized_output_ty);
debug!(?normalized_input_tys);
debug!(?universal_regions.unnormalized_input_tys, ?body.local_decls);

// Equate expected input tys with those in the MIR.
for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
for (argument_index, &unnormalized_input_ty) in
universal_regions.unnormalized_input_tys.iter().enumerate()
{
if argument_index + 1 >= body.local_decls.len() {
self.tcx()
.sess
Expand All @@ -88,6 +81,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let mir_input_ty = body.local_decls[local].ty;

let mir_input_span = body.local_decls[local].source_info.span;
let normalized_input_ty =
self.normalize(unnormalized_input_ty, Locations::All(mir_input_span));
self.equate_normalized_input_or_output(
normalized_input_ty,
mir_input_ty,
Expand Down Expand Up @@ -125,6 +120,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// Return types are a bit more complex. They may contain opaque `impl Trait` types.
let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
let output_span = body.local_decls[RETURN_PLACE].source_info.span;
let normalized_output_ty =
self.normalize(universal_regions.unnormalized_output_ty, Locations::All(output_span));
if let Err(terr) = self.eq_types(
normalized_output_ty,
mir_output_ty,
Expand Down
23 changes: 9 additions & 14 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,19 +147,14 @@ pub(crate) fn type_check<'mir, 'tcx>(
universe_causes: FxIndexMap::default(),
};

let CreateResult {
universal_region_relations,
region_bound_pairs,
normalized_inputs_and_output,
} = free_region_relations::create(
infcx,
param_env,
implicit_region_bound,
universal_regions,
&mut constraints,
);

debug!(?normalized_inputs_and_output);
let CreateResult { universal_region_relations, region_bound_pairs } =
free_region_relations::create(
infcx,
param_env,
implicit_region_bound,
universal_regions,
&mut constraints,
);

for u in ty::UniverseIndex::ROOT..=infcx.universe() {
constraints.universe_causes.insert(u, UniverseInfo::other());
Expand Down Expand Up @@ -194,7 +189,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
checker.typeck_mir(body);
}

checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
checker.equate_inputs_and_outputs(&body);
checker.check_signature_annotation(&body);

liveness::generate(
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,8 @@ fn compare_method_predicate_entailment<'tcx>(
// we have to do this before normalization, since the normalized ty may
// not contain the input parameters. See issue #87748.
wf_tys.extend(trait_sig.inputs_and_output.iter());

let trait_sig = ocx.normalize(&norm_cause, param_env, trait_sig);
// We also have to add the normalized trait signature
// as we don't normalize during implied bounds computation.
wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));

debug!("compare_impl_method: trait_fty={:?}", trait_fty);
Expand Down

0 comments on commit e9e0e7e

Please sign in to comment.