]> git.lizzy.rs Git - rust.git/commitdiff
Check that all hidden types are the same and then deduplicate them.
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Wed, 6 Apr 2022 15:02:37 +0000 (15:02 +0000)
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Wed, 6 Apr 2022 15:02:37 +0000 (15:02 +0000)
compiler/rustc_borrowck/src/region_infer/opaque_types.rs
src/test/ui/type-alias-impl-trait/multiple_definitions.rs [new file with mode: 0644]

index f454141dc522995afa50fd81e3bc3245ab8b242d..0bb6559e6545288bc7492124c4318ba9a500b371 100644 (file)
@@ -55,75 +55,93 @@ pub(crate) fn infer_opaque_types(
         infcx: &InferCtxt<'_, 'tcx>,
         opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
     ) -> VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>> {
-        opaque_ty_decls
-            .into_iter()
-            .map(|(opaque_type_key, (concrete_type, origin))| {
-                let substs = opaque_type_key.substs;
-                debug!(?concrete_type, ?substs);
+        let mut result: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>> = VecMap::new();
+        for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls {
+            let substs = opaque_type_key.substs;
+            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, _| {
-                    if let ty::RePlaceholder(..) = region.kind() {
-                        // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs.
-                        return region;
+            let mut subst_regions = vec![self.universal_regions.fr_static];
+            let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
+                if let ty::RePlaceholder(..) = region.kind() {
+                    // 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
                     }
-                    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(
-                                concrete_type.span,
-                                "opaque type with non-universal region substs",
-                            );
-                            infcx.tcx.lifetimes.re_static
-                        }
+                    None => {
+                        subst_regions.push(vid);
+                        infcx.tcx.sess.delay_span_bug(
+                            concrete_type.span,
+                            "opaque type with non-universal region substs",
+                        );
+                        infcx.tcx.lifetimes.re_static
                     }
-                });
+                }
+            });
 
-                subst_regions.sort();
-                subst_regions.dedup();
+            subst_regions.sort();
+            subst_regions.dedup();
 
-                let universal_concrete_type =
-                    infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region {
-                        ty::ReVar(vid) => subst_regions
-                            .iter()
-                            .find(|ur_vid| self.eval_equal(vid, **ur_vid))
-                            .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
-                            .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
-                        _ => region,
-                    });
+            let universal_concrete_type =
+                infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region {
+                    ty::ReVar(vid) => subst_regions
+                        .iter()
+                        .find(|ur_vid| self.eval_equal(vid, **ur_vid))
+                        .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
+                        .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
+                    _ => region,
+                });
 
-                debug!(?universal_concrete_type, ?universal_substs);
+            debug!(?universal_concrete_type, ?universal_substs);
 
-                let opaque_type_key =
-                    OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
-                let remapped_type = infcx.infer_opaque_definition_from_instantiation(
-                    opaque_type_key,
-                    universal_concrete_type,
-                );
-                let ty = if check_opaque_type_parameter_valid(
-                    infcx.tcx,
-                    opaque_type_key,
-                    origin,
-                    concrete_type.span,
-                ) {
-                    remapped_type
-                } else {
-                    infcx.tcx.ty_error()
-                };
-                (opaque_type_key, OpaqueHiddenType { ty, span: concrete_type.span })
-            })
-            .collect()
+            let opaque_type_key =
+                OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
+            let remapped_type = infcx.infer_opaque_definition_from_instantiation(
+                opaque_type_key,
+                universal_concrete_type,
+            );
+            let ty = if check_opaque_type_parameter_valid(
+                infcx.tcx,
+                opaque_type_key,
+                origin,
+                concrete_type.span,
+            ) {
+                remapped_type
+            } else {
+                infcx.tcx.ty_error()
+            };
+            // Sometimes two opaque types are the same only after we remap the generic parameters
+            // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
+            // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
+            // once we convert the generic parameters to those of the opaque type.
+            if let Some(prev) = result.get_mut(&opaque_type_key) {
+                if prev.ty != ty {
+                    let mut err = infcx.tcx.sess.struct_span_err(
+                        concrete_type.span,
+                        &format!("hidden type `{}` differed from previous `{}`", ty, prev.ty),
+                    );
+                    err.span_note(prev.span, "previous hidden type bound here");
+                    err.emit();
+                    prev.ty = infcx.tcx.ty_error();
+                }
+                // Pick a better span if there is one.
+                // FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
+                prev.span = prev.span.substitute_dummy(concrete_type.span);
+            } else {
+                result.insert(opaque_type_key, OpaqueHiddenType { ty, span: concrete_type.span });
+            }
+        }
+        result
     }
 
     /// Map the regions in the type to named regions. This is similar to what
diff --git a/src/test/ui/type-alias-impl-trait/multiple_definitions.rs b/src/test/ui/type-alias-impl-trait/multiple_definitions.rs
new file mode 100644 (file)
index 0000000..9e6268e
--- /dev/null
@@ -0,0 +1,30 @@
+// check-pass
+
+use std::marker::PhantomData;
+
+pub struct ConcreteError {}
+pub trait IoBase {}
+struct X {}
+impl IoBase for X {}
+
+pub struct ClusterIterator<B, E, S = B> {
+    pub fat: B,
+    phantom_s: PhantomData<S>,
+    phantom_e: PhantomData<E>,
+}
+
+pub struct FileSystem<IO: IoBase> {
+    pub disk: IO,
+}
+
+impl<IO: IoBase> FileSystem<IO> {
+    pub fn cluster_iter(&self) -> ClusterIterator<impl IoBase + '_, ConcreteError> {
+        ClusterIterator {
+            fat: X {},
+            phantom_s: PhantomData::default(),
+            phantom_e: PhantomData::default(),
+        }
+    }
+}
+
+fn main() {}