Auto merge of #92007 - oli-obk:lazy_tait2, r=nikomatsakis
Lazy type-alias-impl-trait Previously opaque types were processed by 1. replacing all mentions of them with inference variables 2. memorizing these inference variables in a side-table 3. at the end of typeck, resolve the inference variables in the side table and use the resolved type as the hidden type of the opaque type This worked okayish for `impl Trait` in return position, but required lots of roundabout type inference hacks and processing. This PR instead stops this process of replacing opaque types with inference variables, and just keeps the opaque types around. Whenever an opaque type `O` is compared with another type `T`, we make the comparison succeed and record `T` as the hidden type. If `O` is compared to `U` while there is a recorded hidden type for it, we grab the recorded type (`T`) and compare that against `U`. This makes implementing * https://github.com/rust-lang/rfcs/pull/2515 much simpler (previous attempts on the inference based scheme were very prone to ICEs and general misbehaviour that was not explainable except by random implementation defined oddities). r? `@nikomatsakis` fixes #93411 fixes #88236
This commit is contained in:
commit
e7cc3bddbe
359 changed files with 3311 additions and 2447 deletions
|
@ -124,8 +124,9 @@ fn mir_borrowck<'tcx>(
|
|||
) -> &'tcx BorrowCheckResult<'tcx> {
|
||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
|
||||
let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
|
||||
|
||||
let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
|
||||
let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| {
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
let promoted: &IndexVec<_, _> = &promoted.borrow();
|
||||
do_mir_borrowck(&infcx, input_body, promoted, false).0
|
||||
|
@ -140,7 +141,7 @@ fn mir_borrowck<'tcx>(
|
|||
/// If `return_body_with_facts` is true, then return the body with non-erased
|
||||
/// region ids on which the borrow checking was performed together with Polonius
|
||||
/// facts.
|
||||
#[instrument(skip(infcx, input_body, input_promoted), level = "debug")]
|
||||
#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")]
|
||||
fn do_mir_borrowck<'a, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'tcx>,
|
||||
input_body: &Body<'tcx>,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
use rustc_hir::OpaqueTyOrigin;
|
||||
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
|
||||
|
@ -54,27 +53,44 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
pub(crate) fn infer_opaque_types(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
|
||||
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (Ty<'tcx>, Span, OpaqueTyOrigin)>,
|
||||
span: Span,
|
||||
) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
|
||||
opaque_ty_decls
|
||||
.into_iter()
|
||||
.filter_map(|(opaque_type_key, decl)| {
|
||||
.map(|(opaque_type_key, (concrete_type, decl_span, origin))| {
|
||||
let substs = opaque_type_key.substs;
|
||||
let concrete_type = decl.concrete_ty;
|
||||
// FIXME: why are the spans in decl_span often DUMMY_SP?
|
||||
let span = decl_span.substitute_dummy(span);
|
||||
debug!(?concrete_type, ?substs);
|
||||
|
||||
let mut subst_regions = vec![self.universal_regions.fr_static];
|
||||
let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
|
||||
let vid = self.universal_regions.to_region_vid(region);
|
||||
subst_regions.push(vid);
|
||||
self.definitions[vid].external_name.unwrap_or_else(|| {
|
||||
infcx
|
||||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(span, "opaque type with non-universal region substs");
|
||||
infcx.tcx.lifetimes.re_static
|
||||
})
|
||||
if let ty::RePlaceholder(..) = region {
|
||||
// Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs.
|
||||
return region;
|
||||
}
|
||||
let vid = self.to_region_vid(region);
|
||||
trace!(?vid);
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
trace!(?scc);
|
||||
match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
|
||||
self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
|
||||
}) {
|
||||
Some(region) => {
|
||||
let vid = self.universal_regions.to_region_vid(region);
|
||||
subst_regions.push(vid);
|
||||
region
|
||||
}
|
||||
None => {
|
||||
subst_regions.push(vid);
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
span,
|
||||
"opaque type with non-universal region substs",
|
||||
);
|
||||
infcx.tcx.lifetimes.re_static
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
subst_regions.sort();
|
||||
|
@ -100,12 +116,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
span,
|
||||
);
|
||||
|
||||
check_opaque_type_parameter_valid(
|
||||
infcx.tcx,
|
||||
(
|
||||
opaque_type_key,
|
||||
OpaqueTypeDecl { concrete_ty: remapped_type, ..decl },
|
||||
if check_opaque_type_parameter_valid(infcx.tcx, opaque_type_key, origin, span) {
|
||||
remapped_type
|
||||
} else {
|
||||
infcx.tcx.ty_error()
|
||||
},
|
||||
)
|
||||
.then_some((opaque_type_key, remapped_type))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -149,9 +167,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
fn check_opaque_type_parameter_valid(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_type_key: OpaqueTypeKey<'_>,
|
||||
decl: OpaqueTypeDecl<'_>,
|
||||
origin: OpaqueTyOrigin,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
match decl.origin {
|
||||
match origin {
|
||||
// No need to check return position impl trait (RPIT)
|
||||
// because for type and const parameters they are correct
|
||||
// by construction: we convert
|
||||
|
@ -177,7 +196,6 @@ fn check_opaque_type_parameter_valid(
|
|||
// Check these
|
||||
OpaqueTyOrigin::TyAlias => {}
|
||||
}
|
||||
let span = decl.definition_span;
|
||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
||||
let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
|
||||
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
|
||||
|
|
|
@ -147,9 +147,9 @@ 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;
|
||||
if let Err(terr) = self.eq_opaque_type_and_type(
|
||||
mir_output_ty,
|
||||
if let Err(terr) = self.eq_types(
|
||||
normalized_output_ty,
|
||||
mir_output_ty,
|
||||
Locations::All(output_span),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
) {
|
||||
|
@ -169,9 +169,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let user_provided_output_ty = user_provided_sig.output();
|
||||
let user_provided_output_ty =
|
||||
self.normalize(user_provided_output_ty, Locations::All(output_span));
|
||||
if let Err(err) = self.eq_opaque_type_and_type(
|
||||
mir_output_ty,
|
||||
if let Err(err) = self.eq_types(
|
||||
user_provided_output_ty,
|
||||
mir_output_ty,
|
||||
Locations::All(output_span),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
) {
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::{fmt, iter, mem};
|
|||
|
||||
use either::Either;
|
||||
|
||||
use hir::OpaqueTyOrigin;
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
|
@ -15,7 +16,6 @@ use rustc_hir::def_id::LocalDefId;
|
|||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{
|
||||
|
@ -41,7 +41,7 @@ use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
|||
use rustc_trait_selection::traits::query::type_op;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
|
||||
use rustc_trait_selection::traits::{self, ObligationCause};
|
||||
|
||||
use rustc_const_eval::transform::{
|
||||
check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
|
||||
|
@ -75,7 +75,7 @@ macro_rules! span_mirbug {
|
|||
$context.last_span,
|
||||
&format!(
|
||||
"broken MIR in {:?} ({:?}): {}",
|
||||
$context.body.source.def_id(),
|
||||
$context.body().source.def_id(),
|
||||
$elem,
|
||||
format_args!($($message)*),
|
||||
),
|
||||
|
@ -190,59 +190,44 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
|
||||
|
||||
translate_outlives_facts(&mut cx);
|
||||
let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
|
||||
let opaque_type_values =
|
||||
infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
|
||||
opaque_type_values
|
||||
.into_iter()
|
||||
.filter_map(|(opaque_type_key, mut decl)| {
|
||||
decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
|
||||
.map(|(opaque_type_key, decl)| {
|
||||
cx.fully_perform_op(
|
||||
Locations::All(body.span),
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
infcx.register_member_constraints(
|
||||
param_env,
|
||||
opaque_type_key,
|
||||
decl.hidden_type.ty,
|
||||
decl.hidden_type.span,
|
||||
);
|
||||
Ok(InferOk { value: (), obligations: vec![] })
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type.ty);
|
||||
trace!(
|
||||
"finalized opaque type {:?} to {:#?}",
|
||||
opaque_type_key,
|
||||
decl.concrete_ty.kind()
|
||||
hidden_type.kind()
|
||||
);
|
||||
if decl.concrete_ty.has_infer_types_or_consts() {
|
||||
if hidden_type.has_infer_types_or_consts() {
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
body.span,
|
||||
&format!("could not resolve {:#?}", decl.concrete_ty.kind()),
|
||||
decl.hidden_type.span,
|
||||
&format!("could not resolve {:#?}", hidden_type.kind()),
|
||||
);
|
||||
decl.concrete_ty = infcx.tcx.ty_error();
|
||||
hidden_type = infcx.tcx.ty_error();
|
||||
}
|
||||
let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind()
|
||||
{
|
||||
*def_id == opaque_type_key.def_id
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if concrete_is_opaque {
|
||||
// We're using an opaque `impl Trait` type without
|
||||
// 'revealing' it. For example, code like this:
|
||||
//
|
||||
// type Foo = impl Debug;
|
||||
// fn foo1() -> Foo { ... }
|
||||
// fn foo2() -> Foo { foo1() }
|
||||
//
|
||||
// In `foo2`, we're not revealing the type of `Foo` - we're
|
||||
// just treating it as the opaque type.
|
||||
//
|
||||
// When this occurs, we do *not* want to try to equate
|
||||
// the concrete type with the underlying defining type
|
||||
// of the opaque type - this will always fail, since
|
||||
// the defining type of an opaque type is always
|
||||
// some other type (e.g. not itself)
|
||||
// Essentially, none of the normal obligations apply here -
|
||||
// we're just passing around some unknown opaque type,
|
||||
// without actually looking at the underlying type it
|
||||
// gets 'revealed' into
|
||||
debug!(
|
||||
"eq_opaque_type_and_type: non-defining use of {:?}",
|
||||
opaque_type_key.def_id,
|
||||
);
|
||||
None
|
||||
} else {
|
||||
Some((opaque_type_key, decl))
|
||||
}
|
||||
(opaque_type_key, (hidden_type, decl.hidden_type.span, decl.origin))
|
||||
})
|
||||
.collect()
|
||||
},
|
||||
|
@ -274,7 +259,7 @@ fn type_check_internal<'a, 'tcx, R>(
|
|||
borrowck_context,
|
||||
);
|
||||
let errors_reported = {
|
||||
let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
|
||||
let mut verifier = TypeVerifier::new(&mut checker, promoted);
|
||||
verifier.visit_body(&body);
|
||||
verifier.errors_reported
|
||||
};
|
||||
|
@ -331,7 +316,6 @@ enum FieldAccessError {
|
|||
/// is a problem.
|
||||
struct TypeVerifier<'a, 'b, 'tcx> {
|
||||
cx: &'a mut TypeChecker<'b, 'tcx>,
|
||||
body: &'b Body<'tcx>,
|
||||
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
|
||||
last_span: Span,
|
||||
errors_reported: bool,
|
||||
|
@ -467,7 +451,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
self.super_rvalue(rvalue, location);
|
||||
let rval_ty = rvalue.ty(self.body, self.tcx());
|
||||
let rval_ty = rvalue.ty(self.body(), self.tcx());
|
||||
self.sanitize_type(rvalue, rval_ty);
|
||||
}
|
||||
|
||||
|
@ -526,10 +510,13 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
fn new(
|
||||
cx: &'a mut TypeChecker<'b, 'tcx>,
|
||||
body: &'b Body<'tcx>,
|
||||
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
|
||||
) -> Self {
|
||||
TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false }
|
||||
TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false }
|
||||
}
|
||||
|
||||
fn body(&self) -> &Body<'tcx> {
|
||||
self.cx.body
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
|
@ -554,7 +541,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
) -> PlaceTy<'tcx> {
|
||||
debug!("sanitize_place: {:?}", place);
|
||||
|
||||
let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
|
||||
let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);
|
||||
|
||||
for elem in place.projection.iter() {
|
||||
if place_ty.variant_index.is_none() {
|
||||
|
@ -599,7 +586,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
// checker on the promoted MIR, then transfer the constraints back to
|
||||
// the main MIR, changing the locations to the provided location.
|
||||
|
||||
let parent_body = mem::replace(&mut self.body, promoted_body);
|
||||
let parent_body = mem::replace(&mut self.cx.body, promoted_body);
|
||||
|
||||
// Use new sets of constraints and closure bounds so that we can
|
||||
// modify their locations.
|
||||
|
@ -635,7 +622,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
self.cx.typeck_mir(promoted_body);
|
||||
}
|
||||
|
||||
self.body = parent_body;
|
||||
self.cx.body = parent_body;
|
||||
// Merge the outlives constraints back in, at the given location.
|
||||
swap_constraints(self);
|
||||
|
||||
|
@ -697,7 +684,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
}))
|
||||
}
|
||||
ProjectionElem::Index(i) => {
|
||||
let index_ty = Place::from(i).ty(self.body, tcx).ty;
|
||||
let index_ty = Place::from(i).ty(self.body(), tcx).ty;
|
||||
if index_ty != tcx.types.usize {
|
||||
PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i))
|
||||
} else {
|
||||
|
@ -906,7 +893,7 @@ struct BorrowCheckContext<'a, 'tcx> {
|
|||
crate struct MirTypeckResults<'tcx> {
|
||||
crate constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
|
||||
crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, (Ty<'tcx>, Span, OpaqueTyOrigin)>,
|
||||
}
|
||||
|
||||
/// A collection of region constraints that must be satisfied for the
|
||||
|
@ -1056,17 +1043,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
checker
|
||||
}
|
||||
|
||||
fn body(&self) -> &Body<'tcx> {
|
||||
self.body
|
||||
}
|
||||
|
||||
fn unsized_feature_enabled(&self) -> bool {
|
||||
let features = self.tcx().features();
|
||||
features.unsized_locals || features.unsized_fn_params
|
||||
}
|
||||
|
||||
/// Equate the inferred type and the annotated type for user type annotations
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn check_user_type_annotations(&mut self) {
|
||||
debug!(
|
||||
"check_user_type_annotations: user_type_annotations={:?}",
|
||||
self.user_type_annotations
|
||||
);
|
||||
debug!(?self.user_type_annotations);
|
||||
for user_annotation in self.user_type_annotations {
|
||||
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
||||
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
|
||||
|
@ -1207,131 +1196,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Equates a type `anon_ty` that may contain opaque types whose
|
||||
/// values are to be inferred by the MIR.
|
||||
///
|
||||
/// The type `revealed_ty` contains the same type as `anon_ty`, but with the
|
||||
/// hidden types for impl traits revealed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Consider a piece of code like
|
||||
///
|
||||
/// ```rust
|
||||
/// type Foo<U> = impl Debug;
|
||||
///
|
||||
/// fn foo<T: Debug>(t: T) -> Box<Foo<T>> {
|
||||
/// Box::new((t, 22_u32))
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here, the function signature would be something like
|
||||
/// `fn(T) -> Box<impl Debug>`. The MIR return slot would have
|
||||
/// the type with the opaque type revealed, so `Box<(T, u32)>`.
|
||||
///
|
||||
/// In terms of our function parameters:
|
||||
///
|
||||
/// * `anon_ty` would be `Box<Foo<T>>` where `Foo<T>` is an opaque type
|
||||
/// scoped to this function (note that it is parameterized by the
|
||||
/// generics of `foo`). Note that `anon_ty` is not just the opaque type,
|
||||
/// but the entire return type (which may contain opaque types within it).
|
||||
/// * `revealed_ty` would be `Box<(T, u32)>`
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn eq_opaque_type_and_type(
|
||||
&mut self,
|
||||
revealed_ty: Ty<'tcx>,
|
||||
anon_ty: Ty<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) -> Fallible<()> {
|
||||
// Fast path for the common case.
|
||||
if !anon_ty.has_opaque_types() {
|
||||
if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
locations,
|
||||
"eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`",
|
||||
revealed_ty,
|
||||
anon_ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let param_env = self.param_env;
|
||||
let body = self.body;
|
||||
let mir_def_id = body.source.def_id().expect_local();
|
||||
|
||||
debug!(?mir_def_id);
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
let mut obligations = ObligationAccumulator::default();
|
||||
|
||||
let dummy_body_id = hir::CRATE_HIR_ID;
|
||||
|
||||
// Replace the opaque types defined by this function with
|
||||
// inference variables, creating a map. In our example above,
|
||||
// this would transform the type `Box<Foo<T>>` (where `Foo` is an opaque type)
|
||||
// to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`.
|
||||
// (Note that the key of the map is both the def-id of `Foo` along with
|
||||
// any generic parameters.)
|
||||
let output_ty = obligations.add(infcx.instantiate_opaque_types(
|
||||
dummy_body_id,
|
||||
param_env,
|
||||
anon_ty,
|
||||
locations.span(body),
|
||||
));
|
||||
debug!(?output_ty, ?revealed_ty);
|
||||
|
||||
// Make sure that the inferred types are well-formed. I'm
|
||||
// not entirely sure this is needed (the HIR type check
|
||||
// didn't do this) but it seems sensible to prevent opaque
|
||||
// types hiding ill-formed types.
|
||||
obligations.obligations.push(traits::Obligation::new(
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into()))
|
||||
.to_predicate(infcx.tcx),
|
||||
));
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(output_ty, revealed_ty)?,
|
||||
);
|
||||
|
||||
debug!("equated");
|
||||
|
||||
Ok(InferOk { value: (), obligations: obligations.into_vec() })
|
||||
},
|
||||
|| "input_output".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
// Finally, if we instantiated the anon types successfully, we
|
||||
// have to solve any bounds (e.g., `-> impl Iterator` needs to
|
||||
// prove that `T: Iterator` where `T` is the type we
|
||||
// instantiated it with).
|
||||
let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone();
|
||||
for (opaque_type_key, opaque_decl) in opaque_type_map {
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
|
||||
Ok(InferOk { value: (), obligations: vec![] })
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
@ -2773,20 +2637,3 @@ impl NormalizeLocation for Location {
|
|||
Locations::Single(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ObligationAccumulator<'tcx> {
|
||||
obligations: PredicateObligations<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationAccumulator<'tcx> {
|
||||
fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
|
||||
let InferOk { value, obligations } = value;
|
||||
self.obligations.extend(obligations);
|
||||
value
|
||||
}
|
||||
|
||||
fn into_vec(self) -> PredicateObligations<'tcx> {
|
||||
self.obligations
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_infer::infer::{InferOk, NllRegionVariableOrigin};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::{self, Const, Ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::diagnostics::UniverseInfo;
|
||||
use crate::type_check::{Locations, TypeChecker};
|
||||
use crate::type_check::{CustomTypeOp, Locations, TypeChecker};
|
||||
|
||||
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
|
||||
|
@ -63,6 +65,10 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
||||
fn span(&self) -> Span {
|
||||
self.locations.span(self.type_checker.body)
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.type_checker.param_env
|
||||
}
|
||||
|
@ -117,6 +123,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
|||
|
||||
// We don't have to worry about the equality of consts during borrow checking
|
||||
// as consts always have a static lifetime.
|
||||
// FIXME(oli-obk): is this really true? We can at least have HKL and with
|
||||
// inline consts we may have further lifetimes that may be unsound to treat as
|
||||
// 'static.
|
||||
fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
|
@ -126,4 +135,33 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
|||
fn forbid_inference_vars() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn register_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool) {
|
||||
let param_env = self.param_env();
|
||||
let span = self.span();
|
||||
let def_id = self.type_checker.body.source.def_id().expect_local();
|
||||
let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
|
||||
let cause = ObligationCause::misc(span, body_id);
|
||||
self.type_checker
|
||||
.fully_perform_op(
|
||||
self.locations,
|
||||
self.category,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
Ok(InferOk {
|
||||
value: (),
|
||||
obligations: vec![infcx.opaque_ty_obligation(
|
||||
a,
|
||||
b,
|
||||
a_is_expected,
|
||||
param_env,
|
||||
cause,
|
||||
)],
|
||||
})
|
||||
},
|
||||
|| "register_opaque_type".to_string(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -728,6 +728,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
|||
self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, indices))]
|
||||
fn replace_bound_regions_with_nll_infer_vars<T>(
|
||||
&self,
|
||||
origin: NllRegionVariableOrigin,
|
||||
|
@ -738,22 +739,15 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
|||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
debug!(
|
||||
"replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})",
|
||||
value, all_outlive_scope,
|
||||
);
|
||||
let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
|
||||
debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
|
||||
debug!(?br);
|
||||
let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
|
||||
scope: all_outlive_scope.to_def_id(),
|
||||
bound_region: br.kind,
|
||||
}));
|
||||
let region_vid = self.next_nll_region_var(origin);
|
||||
indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
|
||||
debug!(
|
||||
"replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}",
|
||||
liberated_region, region_vid
|
||||
);
|
||||
debug!(?liberated_region, ?region_vid);
|
||||
region_vid
|
||||
});
|
||||
value
|
||||
|
@ -768,6 +762,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
|||
/// entries for them and store them in the indices map. This code iterates over the complete
|
||||
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the
|
||||
/// inputs vector.
|
||||
#[instrument(skip(self, indices))]
|
||||
fn replace_late_bound_regions_with_nll_infer_vars(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
|
@ -779,6 +774,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
|||
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = self.next_nll_region_var(FR);
|
||||
debug!(?region_vid);
|
||||
indices.insert_late_bound_region(r, region_vid.to_region_vid());
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue