diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index f454141dc52..0bb6559e654 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -55,75 +55,93 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx: &InferCtxt<'_, 'tcx>, opaque_ty_decls: VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, ) -> VecMap, 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, 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(); + + 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, }); - subst_regions.sort(); - subst_regions.dedup(); + debug!(?universal_concrete_type, ?universal_substs); - 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); - - 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` mapped to `(X, Y)` + // and `OpaqueType` 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 index 00000000000..9e6268e63cd --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/multiple_definitions.rs @@ -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 { + pub fat: B, + phantom_s: PhantomData, + phantom_e: PhantomData, +} + +pub struct FileSystem { + pub disk: IO, +} + +impl FileSystem { + pub fn cluster_iter(&self) -> ClusterIterator { + ClusterIterator { + fat: X {}, + phantom_s: PhantomData::default(), + phantom_e: PhantomData::default(), + } + } +} + +fn main() {}