From f6adaedd9b0696c559df352652bdd8da8ea47d91 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 18 Jun 2021 11:44:56 -0400 Subject: [PATCH 1/2] add various coments to explain how the code works --- compiler/rustc_middle/src/ty/context.rs | 28 ++++++++++ .../src/borrow_check/type_check/mod.rs | 56 ++++++++++++++++++- .../rustc_trait_selection/src/opaque_types.rs | 12 +--- 3 files changed, 85 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 73991436b7b..a74070100f4 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -392,6 +392,34 @@ pub struct TypeckResults<'tcx> { /// (including late-bound regions) are replaced with free /// equivalents. This table is not used in codegen (since regions /// 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>, /// For each FRU expression, record the normalized types of the fields diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 09cafddeeff..984a9a7f053 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1206,6 +1206,35 @@ 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 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 = impl Debug; + /// + /// fn foo(t: T) -> Box> { + /// Box::new((t, 22_u32)) + /// } + /// ``` + /// + /// Here, the function signature would be something like + /// `fn(T) -> Box`. 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>` 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, u32)>` + /// * `anon_owner_def_id` would be the def-id of `foo` fn eq_opaque_type_and_type( &mut self, revealed_ty: Ty<'tcx>, @@ -1240,6 +1269,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let tcx = infcx.tcx; let param_env = self.param_env; let body = self.body; + + // the "concrete opaque types" maps let concrete_opaque_types = &tcx.typeck(anon_owner_def_id).concrete_opaque_types; let mut opaque_type_values = VecMap::new(); @@ -1252,6 +1283,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { 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>` (where `Foo` is an opaque type) + // to `Box`, returning an `opaque_type_map` mapping `{Foo -> ?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) = obligations.add(infcx.instantiate_opaque_types( anon_owner_def_id, @@ -1267,6 +1305,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { revealed_ty={:?}", output_ty, opaque_type_map, 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 @@ -1282,6 +1321,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .eq(output_ty, revealed_ty)?, ); + // For each opaque type `Foo` 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 { 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() { @@ -1290,6 +1332,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { 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 .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, }; 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); + + // "Renumber" this, meaning that we replace all the regions + // with fresh inference variables. Not relevant to our example. let renumbered_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 { - // Equate concrete_ty (an inference variable) with - // the renumbered type from typeck. + // Equate the instantiated opaque type `opaque_decl.concrete_ty` (`?T`, + // in our example) with the renumbered version that we took from + // the type check results (`Foo<(T, u32)>`). obligations.add( infcx .at(&ObligationCause::dummy(), param_env) diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 89ec211f262..0061ce4ed37 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -5,7 +5,6 @@ use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; 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::free_regions::FreeRegionRelations; 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); parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id) }; - let (in_definition_scope, origin) = match tcx.hir().find(opaque_hir_id) { - Some(Node::Item(item)) => match item.kind { + let (in_definition_scope, origin) = + match tcx.hir().expect_item(opaque_hir_id).kind { // Anonymous `impl Trait` hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(parent), @@ -1000,12 +999,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { origin, ), _ => (def_scope_default(), hir::OpaqueTyOrigin::Misc), - }, - _ => bug!( - "expected item, found {}", - tcx.hir().node_to_string(opaque_hir_id), - ), - }; + }; if in_definition_scope { let opaque_type_key = OpaqueTypeKey { def_id: def_id.to_def_id(), substs }; From 831759a4438736980574478b29a3e9ab6e837f3f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 18 Jun 2021 18:20:07 -0400 Subject: [PATCH 2/2] fix typos --- compiler/rustc_mir/src/borrow_check/type_check/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 984a9a7f053..bd951ef72b5 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1230,10 +1230,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// /// In terms of our function parameters: /// - /// * `anon_ty` would be `Box>` where `Foo` is an opaque type + /// * `anon_ty` would be `Box>` 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, u32)>` + /// 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)>` /// * `anon_owner_def_id` would be the def-id of `foo` fn eq_opaque_type_and_type( &mut self,