diff options
| author | Aaron Hill <aa1ronham@gmail.com> | 2019-11-18 14:46:16 -0500 |
|---|---|---|
| committer | Aaron Hill <aa1ronham@gmail.com> | 2019-11-24 14:37:24 -0500 |
| commit | cec7d944baa4a1d5ae0c09d68537ce20fe6b47f4 (patch) | |
| tree | 47b3f277ba86aa435350df7b15e0ebdb7db6f9cd | |
| parent | 542383f65b5419820e90f4374f93d2d1207f3f08 (diff) | |
| download | rust-cec7d944baa4a1d5ae0c09d68537ce20fe6b47f4.tar.gz rust-cec7d944baa4a1d5ae0c09d68537ce20fe6b47f4.zip | |
Add example and extra documentation
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a1f1ac3f2d3..9182eb10545 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -879,6 +879,30 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: DefId) -> &DefIdSet { /// variables introduced by the projection of associated types. This ensures that /// any opaque types used in the signature continue to refer to generic parameters, /// allowing them to be considered for defining uses in the function body +/// +/// For example, consider this code. +/// +/// ```rust +/// trait MyTrait { +/// type MyItem; +/// fn use_it(self) -> Self::MyItem +/// } +/// impl<T, I> MyTrait for T where T: Iterator<Item = I> { +/// type MyItem = impl Iterator<Item = I>; +/// fn use_it(self) -> Self::MyItem { +/// self +/// } +/// } +/// ``` +/// +/// When we normalize the signature of `use_it` from the impl block, +/// we will normalize `Self::MyItem` to the opaque type `impl Iterator<Item = I>` +/// However, this projection result may contain inference variables, due +/// to the way that projection works. We didn't have any inference variables +/// in the signature to begin with - leaving them in will cause us to incorrectly +/// conclude that we don't have a defining use of `MyItem`. By mapping inference +/// variables back to the actual generic parameters, we will correctly see that +/// we have a defining use of `MyItem` fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: &T) -> T where T: TypeFoldable<'tcx> { struct FixupFolder<'tcx> { tcx: TyCtxt<'tcx> @@ -893,6 +917,14 @@ fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: &T) -> T where T: TypeFol match ty.kind { ty::Opaque(def_id, substs) => { debug!("fixup_opaque_types: found type {:?}", ty); + // Here, we replace any inference variables that occur within + // the substs of an opaque type. By definition, any type occuring + // in the substs has a corresponding generic parameter, which is what + // we replace it with. + // This replacement is only run on the function signature, so any + // inference variables that we come across must be the rust of projection + // (there's no other way for a user to get inference variables into + // a function signature). if ty.needs_infer() { let new_substs = InternalSubsts::for_item(self.tcx, def_id, |param, _| { let old_param = substs[param.index as usize]; |
