From 25876b35410d3b6fddc895c73033c31200dd059b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Apr 2022 13:39:38 +0000 Subject: [PATCH 1/2] Report opaque type mismatches directly during borrowck of the function instead of within the `type_of` query. This allows us to only store a single hidden type per opaque type instead of having to store one per set of substitutions. --- compiler/rustc_borrowck/src/nll.rs | 7 +++-- .../src/region_infer/opaque_types.rs | 31 +++++++++++++------ compiler/rustc_middle/src/mir/query.rs | 3 +- compiler/rustc_typeck/src/collect/type_of.rs | 8 ++--- 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 9242c6aeb8b28..927eb080b2008 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -1,6 +1,7 @@ //! The entry point of the NLL borrow checker. use rustc_data_structures::vec_map::VecMap; +use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; @@ -8,7 +9,7 @@ use rustc_middle::mir::{ BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, }; -use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid}; +use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid}; use rustc_span::symbol::sym; use std::env; use std::fmt::Debug; @@ -43,7 +44,7 @@ pub type PoloniusOutput = Output; /// closure requirements to propagate, and any generated errors. crate struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: VecMap, OpaqueHiddenType<'tcx>>, + pub opaque_type_values: VecMap>, pub polonius_input: Option>, pub polonius_output: Option>, pub opt_closure_req: Option>, @@ -372,7 +373,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, - opaque_type_values: &VecMap, OpaqueHiddenType<'tcx>>, + opaque_type_values: &VecMap>, errors: &mut crate::error::BorrowckErrors<'tcx>, ) { let tcx = infcx.tcx; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 0bb6559e65452..980b2657829d9 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; +use rustc_hir::def_id::DefId; use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::subst::GenericArgKind; @@ -54,8 +55,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'tcx>, opaque_ty_decls: VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, - ) -> VecMap, OpaqueHiddenType<'tcx>> { - let mut result: VecMap, OpaqueHiddenType<'tcx>> = VecMap::new(); + ) -> VecMap> { + let mut result: VecMap> = VecMap::new(); for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls { let substs = opaque_type_key.substs; debug!(?concrete_type, ?substs); @@ -124,21 +125,31 @@ impl<'tcx> RegionInferenceContext<'tcx> { // 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 let Some(prev) = result.get_mut(&opaque_type_key.def_id) { 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(); + if !ty.references_error() { + let mut err = infcx.tcx.sess.struct_span_err( + concrete_type.span, + "concrete type differs from previous defining opaque type use", + ); + err.span_label(prev.span, format!("expected `{}`, got `{}`", prev.ty, ty)); + if prev.span == concrete_type.span { + err.span_label(prev.span, "this expression supplies two conflicting concrete types for the same opaque type"); + } else { + err.span_note(prev.span, "previous use 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.insert( + opaque_type_key.def_id, + OpaqueHiddenType { ty, span: concrete_type.span }, + ); } } result diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index cee510a42413a..4d4eed179ca9d 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -9,7 +9,6 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::bit_set::BitMatrix; use rustc_index::vec::IndexVec; -use rustc_middle::ty::OpaqueTypeKey; use rustc_span::Span; use rustc_target::abi::VariantIdx; use smallvec::SmallVec; @@ -242,7 +241,7 @@ pub struct BorrowCheckResult<'tcx> { /// All the opaque types that are restricted to concrete types /// by this function. Unlike the value in `TypeckResults`, this has /// unerased regions. - pub concrete_opaque_types: VecMap, OpaqueHiddenType<'tcx>>, + pub concrete_opaque_types: VecMap>, pub closure_requirements: Option>, pub used_mut_upvars: SmallVec<[Field; 8]>, pub tainted_by_errors: Option, diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index cb32e88588af2..737f9e7b9e12c 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -356,7 +356,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let concrete_ty = tcx .mir_borrowck(owner) .concrete_opaque_types - .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id()) + .get(&def_id.to_def_id()) .copied() .map(|concrete| concrete.ty) .unwrap_or_else(|| { @@ -591,13 +591,13 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; debug!(?concrete_opaque_types); - for &(opaque_type_key, concrete_type) in concrete_opaque_types { - if opaque_type_key.def_id != self.def_id { + for &(def_id, concrete_type) in concrete_opaque_types { + if def_id != self.def_id { // Ignore constraints for other opaque types. continue; } - debug!(?concrete_type, ?opaque_type_key.substs, "found constraint"); + debug!(?concrete_type, "found constraint"); if let Some(prev) = self.found { if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() { From 7d2cad68d2ac83bb2d5d62227be0ef0c358f5991 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Apr 2022 13:52:59 +0000 Subject: [PATCH 2/2] Deduplicate the error printing code for hidden type mismatches --- .../src/region_infer/opaque_types.rs | 13 +++--------- compiler/rustc_middle/src/ty/mod.rs | 20 +++++++++++++++++++ compiler/rustc_typeck/src/collect/type_of.rs | 16 +-------------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 980b2657829d9..fa07c4fa9491d 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -128,17 +128,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let Some(prev) = result.get_mut(&opaque_type_key.def_id) { if prev.ty != ty { if !ty.references_error() { - let mut err = infcx.tcx.sess.struct_span_err( - concrete_type.span, - "concrete type differs from previous defining opaque type use", + prev.report_mismatch( + &OpaqueHiddenType { ty, span: concrete_type.span }, + infcx.tcx, ); - err.span_label(prev.span, format!("expected `{}`, got `{}`", prev.ty, ty)); - if prev.span == concrete_type.span { - err.span_label(prev.span, "this expression supplies two conflicting concrete types for the same opaque type"); - } else { - err.span_note(prev.span, "previous use here"); - } - err.emit(); } prev.ty = infcx.tcx.ty_error(); } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 45a215354d081..6e3dc92a2332f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1112,6 +1112,26 @@ pub struct OpaqueHiddenType<'tcx> { pub ty: Ty<'tcx>, } +impl<'tcx> OpaqueHiddenType<'tcx> { + pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) { + // Found different concrete types for the opaque type. + let mut err = tcx.sess.struct_span_err( + other.span, + "concrete type differs from previous defining opaque type use", + ); + err.span_label(other.span, format!("expected `{}`, got `{}`", self.ty, other.ty)); + if self.span == other.span { + err.span_label( + self.span, + "this expression supplies two conflicting concrete types for the same opaque type", + ); + } else { + err.span_note(self.span, "previous use here"); + } + err.emit(); + } +} + rustc_index::newtype_index! { /// "Universes" are used during type- and trait-checking in the /// presence of `for<..>` binders to control what sets of names are diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 737f9e7b9e12c..785538ab0df3d 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -601,21 +601,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { if let Some(prev) = self.found { if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() { - // Found different concrete types for the opaque type. - let mut err = self.tcx.sess.struct_span_err( - concrete_type.span, - "concrete type differs from previous defining opaque type use", - ); - err.span_label( - concrete_type.span, - format!("expected `{}`, got `{}`", prev.ty, concrete_type.ty), - ); - if prev.span == concrete_type.span { - err.span_label(prev.span, "this expression supplies two conflicting concrete types for the same opaque type"); - } else { - err.span_note(prev.span, "previous use here"); - } - err.emit(); + prev.report_mismatch(&concrete_type, self.tcx); } } else { self.found = Some(concrete_type);