Skip to content

Report opaque type mismatches directly during borrowck of the function instead of within the type_of query. #95767

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions compiler/rustc_borrowck/src/nll.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
//! 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};
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;
Expand Down Expand Up @@ -43,7 +44,7 @@ pub type PoloniusOutput = Output<RustcFacts>;
/// closure requirements to propagate, and any generated errors.
crate struct NllOutput<'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_output: Option<Rc<PoloniusOutput>>,
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
Expand Down Expand Up @@ -372,7 +373,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
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>,
) {
let tcx = infcx.tcx;
Expand Down
24 changes: 14 additions & 10 deletions compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -54,8 +55,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&self,
infcx: &InferCtxt<'_, 'tcx>,
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
) -> VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>> {
let mut result: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>> = VecMap::new();
) -> VecMap<DefId, OpaqueHiddenType<'tcx>> {
let mut result: VecMap<DefId, 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);
Expand Down Expand Up @@ -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)`
// 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 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() {
prev.report_mismatch(
&OpaqueHiddenType { ty, span: concrete_type.span },
infcx.tcx,
);
}
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
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_middle/src/mir/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
pub concrete_opaque_types: VecMap<DefId, OpaqueHiddenType<'tcx>>,
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
pub used_mut_upvars: SmallVec<[Field; 8]>,
pub tainted_by_errors: Option<ErrorGuaranteed>,
Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 5 additions & 19 deletions compiler/rustc_typeck/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(|| {
Expand Down Expand Up @@ -591,31 +591,17 @@ 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() {
// 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);
Expand Down