Skip to content

Commit 6583025

Browse files
authored
Rollup merge of #111853 - compiler-errors:opaque-check, r=oli-obk
Check opaques for mismatch during writeback Revive #111705. I realized that we don't need to put any substs in the writeback results since all of the hidden types have already been remapped. See the comment in `compiler/rustc_middle/src/ty/typeck_results.rs`, which should make that clear for other explorers of the codebase. Additionally, we need to do some diagnostic stashing because the diagnostics we produce during HIR typeck is very poor and we should prefer the diagnostic that comes from MIR, if we have one. r? `@oli-obk`
2 parents 4b26b80 + 0307db4 commit 6583025

File tree

12 files changed

+131
-25
lines changed

12 files changed

+131
-25
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+2
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
152152
let guar = ty.error_reported().err().unwrap_or_else(|| {
153153
prev.report_mismatch(
154154
&OpaqueHiddenType { ty, span: concrete_type.span },
155+
opaque_type_key.def_id,
155156
infcx.tcx,
156157
)
158+
.emit()
157159
});
158160
prev.ty = infcx.tcx.ty_error(guar);
159161
}

compiler/rustc_errors/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ pub enum StashKey {
478478
MaybeFruTypo,
479479
CallAssocMethod,
480480
TraitMissingMethod,
481+
OpaqueHiddenTypeMismatch,
481482
}
482483

483484
fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {

compiler/rustc_hir_analysis/src/collect/type_of.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,8 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
584584
debug!(?concrete_type, "found constraint");
585585
if let Some(prev) = &mut self.found {
586586
if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
587-
let guar = prev.report_mismatch(&concrete_type, self.tcx);
587+
let guar =
588+
prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
588589
prev.ty = self.tcx.ty_error(guar);
589590
}
590591
} else {
@@ -678,10 +679,10 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
678679
// Only check against typeck if we didn't already error
679680
if !hidden.ty.references_error() {
680681
for concrete_type in locator.typeck_types {
681-
if tcx.erase_regions(concrete_type.ty) != tcx.erase_regions(hidden.ty)
682+
if concrete_type.ty != tcx.erase_regions(hidden.ty)
682683
&& !(concrete_type, hidden).references_error()
683684
{
684-
hidden.report_mismatch(&concrete_type, tcx);
685+
hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
685686
}
686687
}
687688
}
@@ -722,7 +723,7 @@ fn find_opaque_ty_constraints_for_rpit(
722723
if concrete_type.ty != self.found.ty
723724
&& !(concrete_type, self.found).references_error()
724725
{
725-
self.found.report_mismatch(&concrete_type, self.tcx);
726+
self.found.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
726727
}
727728
}
728729
}

compiler/rustc_hir_typeck/src/writeback.rs

+31-13
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use crate::FnCtxt;
66
use hir::def_id::LocalDefId;
77
use rustc_data_structures::fx::FxHashMap;
8-
use rustc_errors::ErrorGuaranteed;
8+
use rustc_errors::{ErrorGuaranteed, StashKey};
99
use rustc_hir as hir;
1010
use rustc_hir::intravisit::{self, Visitor};
1111
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
@@ -82,10 +82,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8282
wbcx.typeck_results.treat_byte_string_as_slice =
8383
mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice);
8484

85-
if let Some(e) = self.tainted_by_errors() {
86-
wbcx.typeck_results.tainted_by_errors = Some(e);
87-
}
88-
8985
debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results);
9086

9187
self.tcx.arena.alloc(wbcx.typeck_results)
@@ -118,12 +114,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
118114
) -> WritebackCx<'cx, 'tcx> {
119115
let owner = body.id().hir_id.owner;
120116

121-
WritebackCx {
117+
let mut wbcx = WritebackCx {
122118
fcx,
123119
typeck_results: ty::TypeckResults::new(owner),
124120
body,
125121
rustc_dump_user_substs,
122+
};
123+
124+
// HACK: We specifically don't want the (opaque) error from tainting our
125+
// inference context. That'll prevent us from doing opaque type inference
126+
// later on in borrowck, which affects diagnostic spans pretty negatively.
127+
if let Some(e) = fcx.tainted_by_errors() {
128+
wbcx.typeck_results.tainted_by_errors = Some(e);
126129
}
130+
131+
wbcx
127132
}
128133

129134
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -578,13 +583,26 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
578583
continue;
579584
}
580585

581-
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
582-
opaque_type_key,
583-
self.fcx.infcx.tcx,
584-
true,
585-
);
586-
587-
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
586+
let hidden_type =
587+
self.tcx().erase_regions(hidden_type.remap_generic_params_to_declaration_params(
588+
opaque_type_key,
589+
self.tcx(),
590+
true,
591+
));
592+
593+
if let Some(last_opaque_ty) = self
594+
.typeck_results
595+
.concrete_opaque_types
596+
.insert(opaque_type_key.def_id, hidden_type)
597+
&& last_opaque_ty.ty != hidden_type.ty
598+
{
599+
hidden_type
600+
.report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
601+
.stash(
602+
self.tcx().def_span(opaque_type_key.def_id),
603+
StashKey::OpaqueHiddenTypeMismatch,
604+
);
605+
}
588606
}
589607
}
590608

compiler/rustc_middle/src/ty/mod.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use rustc_data_structures::intern::Interned;
3737
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
3838
use rustc_data_structures::steal::Steal;
3939
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
40-
use rustc_errors::ErrorGuaranteed;
40+
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey};
4141
use rustc_hir as hir;
4242
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
4343
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
@@ -1439,14 +1439,26 @@ pub struct OpaqueHiddenType<'tcx> {
14391439
}
14401440

14411441
impl<'tcx> OpaqueHiddenType<'tcx> {
1442-
pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) -> ErrorGuaranteed {
1442+
pub fn report_mismatch(
1443+
&self,
1444+
other: &Self,
1445+
opaque_def_id: LocalDefId,
1446+
tcx: TyCtxt<'tcx>,
1447+
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
1448+
if let Some(diag) = tcx
1449+
.sess
1450+
.diagnostic()
1451+
.steal_diagnostic(tcx.def_span(opaque_def_id), StashKey::OpaqueHiddenTypeMismatch)
1452+
{
1453+
diag.cancel();
1454+
}
14431455
// Found different concrete types for the opaque type.
14441456
let sub_diag = if self.span == other.span {
14451457
TypeMismatchReason::ConflictType { span: self.span }
14461458
} else {
14471459
TypeMismatchReason::PreviousUse { span: self.span }
14481460
};
1449-
tcx.sess.emit_err(OpaqueHiddenTypeMismatch {
1461+
tcx.sess.create_err(OpaqueHiddenTypeMismatch {
14501462
self_ty: self.ty,
14511463
other_ty: other.ty,
14521464
other_span: other.span,

compiler/rustc_middle/src/ty/typeck_results.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,14 @@ pub struct TypeckResults<'tcx> {
151151
/// this field will be set to `Some(ErrorGuaranteed)`.
152152
pub tainted_by_errors: Option<ErrorGuaranteed>,
153153

154-
/// All the opaque types that have hidden types set
155-
/// by this function. We also store the
156-
/// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
157-
/// even if they are only set in dead code (which doesn't show up in MIR).
154+
/// All the opaque types that have hidden types set by this function.
155+
/// We also store the type here, so that the compiler can use it as a hint
156+
/// for figuring out hidden types, even if they are only set in dead code
157+
/// (which doesn't show up in MIR).
158+
///
159+
/// These types are mapped back to the opaque's identity substitutions
160+
/// (with erased regions), which is why we don't associated substs with any
161+
/// of these usages.
158162
pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
159163

160164
/// Tracks the minimum captures required for a closure;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
type Tait<'a> = impl Sized + 'a;
4+
5+
fn foo<'a, 'b>() {
6+
if false {
7+
if { return } {
8+
let y: Tait<'b> = 1i32;
9+
//~^ ERROR concrete type differs from previous defining opaque type use
10+
}
11+
}
12+
let x: Tait<'a> = ();
13+
}
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: concrete type differs from previous defining opaque type use
2+
--> $DIR/different_defining_uses_never_type-2.rs:8:31
3+
|
4+
LL | let y: Tait<'b> = 1i32;
5+
| ^^^^ expected `()`, got `i32`
6+
|
7+
note: previous use here
8+
--> $DIR/different_defining_uses_never_type-2.rs:12:23
9+
|
10+
LL | let x: Tait<'a> = ();
11+
| ^^
12+
13+
error: aborting due to previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
type Tait<T> = impl Sized;
4+
5+
fn foo<T, U>() {
6+
if false {
7+
if { return } {
8+
let y: Tait<U> = 1i32;
9+
//~^ ERROR concrete type differs from previous defining opaque type use
10+
}
11+
}
12+
let x: Tait<T> = ();
13+
}
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: concrete type differs from previous defining opaque type use
2+
--> $DIR/different_defining_uses_never_type-3.rs:8:30
3+
|
4+
LL | let y: Tait<U> = 1i32;
5+
| ^^^^ expected `()`, got `i32`
6+
|
7+
note: previous use here
8+
--> $DIR/different_defining_uses_never_type-3.rs:12:22
9+
|
10+
LL | let x: Tait<T> = ();
11+
| ^^
12+
13+
error: aborting due to previous error
14+

tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type X<A, B> = impl Into<&'static A>;
88

99
fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
1010
//~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied
11+
//~| ERROR concrete type differs from previous defining opaque type use
1112
(a, a)
1213
}
1314

tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr

+10-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ help: consider introducing a `where` clause, but there might be an alternative b
1010
LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) where &'static B: From<&A> {
1111
| ++++++++++++++++++++++++++
1212

13-
error: aborting due to previous error
13+
error: concrete type differs from previous defining opaque type use
14+
--> $DIR/multiple-def-uses-in-one-fn.rs:9:45
15+
|
16+
LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
17+
| ^^^^^^^^^^^^^^^^^^
18+
| |
19+
| expected `&B`, got `&A`
20+
| this expression supplies two conflicting concrete types for the same opaque type
21+
22+
error: aborting due to 2 previous errors
1423

1524
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)