1
Fork 0

Auto merge of #95767 - oli-obk:all_your_generics_belong_to_the_definitions, r=compiler-errors

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.

r? `@compiler-errors`

This does not affect diagnostics, because the diagnostic messages are exactly the same.
This commit is contained in:
bors 2022-04-07 19:37:43 +00:00
commit e745b4ddbd
5 changed files with 44 additions and 34 deletions

View file

@ -1,6 +1,7 @@
//! The entry point of the NLL borrow checker. //! The entry point of the NLL borrow checker.
use rustc_data_structures::vec_map::VecMap; use rustc_data_structures::vec_map::VecMap;
use rustc_hir::def_id::DefId;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; 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, BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
Promoted, Promoted,
}; };
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid}; use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use std::env; use std::env;
use std::fmt::Debug; use std::fmt::Debug;
@ -43,7 +44,7 @@ pub type PoloniusOutput = Output<RustcFacts>;
/// closure requirements to propagate, and any generated errors. /// closure requirements to propagate, and any generated errors.
crate struct NllOutput<'tcx> { crate struct NllOutput<'tcx> {
pub regioncx: RegionInferenceContext<'tcx>, pub regioncx: RegionInferenceContext<'tcx>,
pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, pub opaque_type_values: VecMap<DefId, OpaqueHiddenType<'tcx>>,
pub polonius_input: Option<Box<AllFacts>>, pub polonius_input: Option<Box<AllFacts>>,
pub polonius_output: Option<Rc<PoloniusOutput>>, pub polonius_output: Option<Rc<PoloniusOutput>>,
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>, pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
@ -372,7 +373,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
body: &Body<'tcx>, body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>, regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>, closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, opaque_type_values: &VecMap<DefId, OpaqueHiddenType<'tcx>>,
errors: &mut crate::error::BorrowckErrors<'tcx>, errors: &mut crate::error::BorrowckErrors<'tcx>,
) { ) {
let tcx = infcx.tcx; let tcx = infcx.tcx;

View file

@ -1,5 +1,6 @@
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::vec_map::VecMap; use rustc_data_structures::vec_map::VecMap;
use rustc_hir::def_id::DefId;
use rustc_hir::OpaqueTyOrigin; use rustc_hir::OpaqueTyOrigin;
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::GenericArgKind;
@ -54,8 +55,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&self, &self,
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
) -> VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>> { ) -> VecMap<DefId, OpaqueHiddenType<'tcx>> {
let mut result: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>> = VecMap::new(); let mut result: VecMap<DefId, OpaqueHiddenType<'tcx>> = VecMap::new();
for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls { for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls {
let substs = opaque_type_key.substs; let substs = opaque_type_key.substs;
debug!(?concrete_type, ?substs); debug!(?concrete_type, ?substs);
@ -124,21 +125,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)` // 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 // 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. // 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 { if prev.ty != ty {
let mut err = infcx.tcx.sess.struct_span_err( if !ty.references_error() {
concrete_type.span, prev.report_mismatch(
&format!("hidden type `{}` differed from previous `{}`", ty, prev.ty), &OpaqueHiddenType { ty, span: concrete_type.span },
); infcx.tcx,
err.span_note(prev.span, "previous hidden type bound here"); );
err.emit(); }
prev.ty = infcx.tcx.ty_error(); prev.ty = infcx.tcx.ty_error();
} }
// Pick a better span if there is one. // Pick a better span if there is one.
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road. // FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
prev.span = prev.span.substitute_dummy(concrete_type.span); prev.span = prev.span.substitute_dummy(concrete_type.span);
} else { } 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 result

View file

@ -9,7 +9,6 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_index::bit_set::BitMatrix; use rustc_index::bit_set::BitMatrix;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use rustc_middle::ty::OpaqueTypeKey;
use rustc_span::Span; use rustc_span::Span;
use rustc_target::abi::VariantIdx; use rustc_target::abi::VariantIdx;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -242,7 +241,7 @@ pub struct BorrowCheckResult<'tcx> {
/// All the opaque types that are restricted to concrete types /// All the opaque types that are restricted to concrete types
/// by this function. Unlike the value in `TypeckResults`, this has /// by this function. Unlike the value in `TypeckResults`, this has
/// unerased regions. /// unerased regions.
pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, pub concrete_opaque_types: VecMap<DefId, OpaqueHiddenType<'tcx>>,
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>, pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
pub used_mut_upvars: SmallVec<[Field; 8]>, pub used_mut_upvars: SmallVec<[Field; 8]>,
pub tainted_by_errors: Option<ErrorGuaranteed>, pub tainted_by_errors: Option<ErrorGuaranteed>,

View file

@ -1112,6 +1112,26 @@ pub struct OpaqueHiddenType<'tcx> {
pub ty: Ty<'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! { rustc_index::newtype_index! {
/// "Universes" are used during type- and trait-checking in the /// "Universes" are used during type- and trait-checking in the
/// presence of `for<..>` binders to control what sets of names are /// presence of `for<..>` binders to control what sets of names are

View file

@ -356,7 +356,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let concrete_ty = tcx let concrete_ty = tcx
.mir_borrowck(owner) .mir_borrowck(owner)
.concrete_opaque_types .concrete_opaque_types
.get_value_matching(|(key, _)| key.def_id == def_id.to_def_id()) .get(&def_id.to_def_id())
.copied() .copied()
.map(|concrete| concrete.ty) .map(|concrete| concrete.ty)
.unwrap_or_else(|| { .unwrap_or_else(|| {
@ -591,31 +591,17 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
// Use borrowck to get the type with unerased regions. // Use borrowck to get the type with unerased regions.
let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
debug!(?concrete_opaque_types); debug!(?concrete_opaque_types);
for &(opaque_type_key, concrete_type) in concrete_opaque_types { for &(def_id, concrete_type) in concrete_opaque_types {
if opaque_type_key.def_id != self.def_id { if def_id != self.def_id {
// Ignore constraints for other opaque types. // Ignore constraints for other opaque types.
continue; continue;
} }
debug!(?concrete_type, ?opaque_type_key.substs, "found constraint"); debug!(?concrete_type, "found constraint");
if let Some(prev) = self.found { if let Some(prev) = self.found {
if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() { if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() {
// Found different concrete types for the opaque type. prev.report_mismatch(&concrete_type, self.tcx);
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();
} }
} else { } else {
self.found = Some(concrete_type); self.found = Some(concrete_type);