add various coments to explain how the code works
This commit is contained in:
parent
1989b9a0b5
commit
f6adaedd9b
3 changed files with 85 additions and 11 deletions
|
@ -392,6 +392,34 @@ pub struct TypeckResults<'tcx> {
|
||||||
/// (including late-bound regions) are replaced with free
|
/// (including late-bound regions) are replaced with free
|
||||||
/// equivalents. This table is not used in codegen (since regions
|
/// equivalents. This table is not used in codegen (since regions
|
||||||
/// are erased there) and hence is not serialized to metadata.
|
/// are erased there) and hence is not serialized to metadata.
|
||||||
|
///
|
||||||
|
/// This table also contains the "revealed" values for any `impl Trait`
|
||||||
|
/// that appear in the signature and whose values are being inferred
|
||||||
|
/// by this function.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// fn foo(x: &u32) -> impl Debug { *x }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The function signature here would be:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// for<'a> fn(&'a u32) -> Foo
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// where `Foo` is an opaque type created for this function.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// The *liberated* form of this would be
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// fn(&'a u32) -> u32
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Note that `'a` is not bound (it would be an `ReFree`) and
|
||||||
|
/// that the `Foo` opaque type is replaced by its hidden type.
|
||||||
liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>,
|
liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>,
|
||||||
|
|
||||||
/// For each FRU expression, record the normalized types of the fields
|
/// For each FRU expression, record the normalized types of the fields
|
||||||
|
|
|
@ -1206,6 +1206,35 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Equates a type `anon_ty` that may contain opaque types whose
|
||||||
|
/// values are to be inferred by the MIR with def-id `anon_owner_def_id`.
|
||||||
|
///
|
||||||
|
/// 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` is an opaque type
|
||||||
|
/// scoped to this function (note that it is parameterized by the
|
||||||
|
/// generics of `foo`).
|
||||||
|
/// * `revealed_ty` would be `Box<(Foo<T>, u32)>`
|
||||||
|
/// * `anon_owner_def_id` would be the def-id of `foo`
|
||||||
fn eq_opaque_type_and_type(
|
fn eq_opaque_type_and_type(
|
||||||
&mut self,
|
&mut self,
|
||||||
revealed_ty: Ty<'tcx>,
|
revealed_ty: Ty<'tcx>,
|
||||||
|
@ -1240,6 +1269,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let param_env = self.param_env;
|
let param_env = self.param_env;
|
||||||
let body = self.body;
|
let body = self.body;
|
||||||
|
|
||||||
|
// the "concrete opaque types" maps
|
||||||
let concrete_opaque_types = &tcx.typeck(anon_owner_def_id).concrete_opaque_types;
|
let concrete_opaque_types = &tcx.typeck(anon_owner_def_id).concrete_opaque_types;
|
||||||
let mut opaque_type_values = VecMap::new();
|
let mut opaque_type_values = VecMap::new();
|
||||||
|
|
||||||
|
@ -1252,6 +1283,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let mut obligations = ObligationAccumulator::default();
|
let mut obligations = ObligationAccumulator::default();
|
||||||
|
|
||||||
let dummy_body_id = hir::CRATE_HIR_ID;
|
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, opaque_type_map) =
|
let (output_ty, opaque_type_map) =
|
||||||
obligations.add(infcx.instantiate_opaque_types(
|
obligations.add(infcx.instantiate_opaque_types(
|
||||||
anon_owner_def_id,
|
anon_owner_def_id,
|
||||||
|
@ -1267,6 +1305,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
revealed_ty={:?}",
|
revealed_ty={:?}",
|
||||||
output_ty, opaque_type_map, revealed_ty
|
output_ty, opaque_type_map, revealed_ty
|
||||||
);
|
);
|
||||||
|
|
||||||
// Make sure that the inferred types are well-formed. I'm
|
// Make sure that the inferred types are well-formed. I'm
|
||||||
// not entirely sure this is needed (the HIR type check
|
// not entirely sure this is needed (the HIR type check
|
||||||
// didn't do this) but it seems sensible to prevent opaque
|
// didn't do this) but it seems sensible to prevent opaque
|
||||||
|
@ -1282,6 +1321,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
.eq(output_ty, revealed_ty)?,
|
.eq(output_ty, revealed_ty)?,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// For each opaque type `Foo<T>` inferred by this value, we want to equate
|
||||||
|
// the inference variable `?T` with the revealed type that was computed
|
||||||
|
// earlier by type check.
|
||||||
for &(opaque_type_key, opaque_decl) in &opaque_type_map {
|
for &(opaque_type_key, opaque_decl) in &opaque_type_map {
|
||||||
let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty);
|
let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty);
|
||||||
let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
|
let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
|
||||||
|
@ -1290,6 +1332,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The revealed type computed by the earlier phase of type check.
|
||||||
|
// In our example, this would be `(U, u32)`. Note that this references
|
||||||
|
// the type parameter `U` from the definition of `Foo`.
|
||||||
let concrete_ty = match concrete_opaque_types
|
let concrete_ty = match concrete_opaque_types
|
||||||
.get_by(|(key, _)| key.def_id == opaque_type_key.def_id)
|
.get_by(|(key, _)| key.def_id == opaque_type_key.def_id)
|
||||||
{
|
{
|
||||||
|
@ -1308,7 +1353,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
Some(concrete_ty) => concrete_ty,
|
Some(concrete_ty) => concrete_ty,
|
||||||
};
|
};
|
||||||
debug!("concrete_ty = {:?}", concrete_ty);
|
debug!("concrete_ty = {:?}", concrete_ty);
|
||||||
|
|
||||||
|
// Apply the substitution, in this case `[U -> T]`, so that the
|
||||||
|
// concrete type becomes `Foo<(T, u32)>`
|
||||||
let subst_opaque_defn_ty = concrete_ty.subst(tcx, opaque_type_key.substs);
|
let subst_opaque_defn_ty = concrete_ty.subst(tcx, opaque_type_key.substs);
|
||||||
|
|
||||||
|
// "Renumber" this, meaning that we replace all the regions
|
||||||
|
// with fresh inference variables. Not relevant to our example.
|
||||||
let renumbered_opaque_defn_ty =
|
let renumbered_opaque_defn_ty =
|
||||||
renumber::renumber_regions(infcx, subst_opaque_defn_ty);
|
renumber::renumber_regions(infcx, subst_opaque_defn_ty);
|
||||||
|
|
||||||
|
@ -1318,8 +1369,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if !concrete_is_opaque {
|
if !concrete_is_opaque {
|
||||||
// Equate concrete_ty (an inference variable) with
|
// Equate the instantiated opaque type `opaque_decl.concrete_ty` (`?T`,
|
||||||
// the renumbered type from typeck.
|
// in our example) with the renumbered version that we took from
|
||||||
|
// the type check results (`Foo<(T, u32)>`).
|
||||||
obligations.add(
|
obligations.add(
|
||||||
infcx
|
infcx
|
||||||
.at(&ObligationCause::dummy(), param_env)
|
.at(&ObligationCause::dummy(), param_env)
|
||||||
|
|
|
@ -5,7 +5,6 @@ use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_data_structures::vec_map::VecMap;
|
use rustc_data_structures::vec_map::VecMap;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::Node;
|
|
||||||
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
|
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
|
||||||
use rustc_infer::infer::free_regions::FreeRegionRelations;
|
use rustc_infer::infer::free_regions::FreeRegionRelations;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
@ -982,8 +981,8 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||||
let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
|
let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
|
||||||
parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
|
parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
|
||||||
};
|
};
|
||||||
let (in_definition_scope, origin) = match tcx.hir().find(opaque_hir_id) {
|
let (in_definition_scope, origin) =
|
||||||
Some(Node::Item(item)) => match item.kind {
|
match tcx.hir().expect_item(opaque_hir_id).kind {
|
||||||
// Anonymous `impl Trait`
|
// Anonymous `impl Trait`
|
||||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||||
impl_trait_fn: Some(parent),
|
impl_trait_fn: Some(parent),
|
||||||
|
@ -1000,12 +999,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||||
origin,
|
origin,
|
||||||
),
|
),
|
||||||
_ => (def_scope_default(), hir::OpaqueTyOrigin::Misc),
|
_ => (def_scope_default(), hir::OpaqueTyOrigin::Misc),
|
||||||
},
|
};
|
||||||
_ => bug!(
|
|
||||||
"expected item, found {}",
|
|
||||||
tcx.hir().node_to_string(opaque_hir_id),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
if in_definition_scope {
|
if in_definition_scope {
|
||||||
let opaque_type_key =
|
let opaque_type_key =
|
||||||
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
|
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue