Skip to content

Commit 0307db4

Browse files
Check opaques for mismatch during writeback
1 parent cfcde24 commit 0307db4

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;
@@ -83,10 +83,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8383
wbcx.typeck_results.treat_byte_string_as_slice =
8484
mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice);
8585

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

9288
self.tcx.arena.alloc(wbcx.typeck_results)
@@ -119,12 +115,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
119115
) -> WritebackCx<'cx, 'tcx> {
120116
let owner = body.id().hir_id.owner;
121117

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

130135
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -579,13 +584,26 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
579584
continue;
580585
}
581586

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

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)