Skip to content

Commit d2b54b8

Browse files
authored
Unrolled build for #147249
Rollup merge of #147249 - jackh726:opaque-type-fallback, r=lcnr Do two passes of `handle_opaque_type_uses_next` Fixes rust-lang/trait-system-refactor-initiative#240 Also did a little bit of cleanup, can squash the commits if decided. r? lcnr
2 parents 2f7620a + d51f09e commit d2b54b8

File tree

4 files changed

+118
-49
lines changed

4 files changed

+118
-49
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,6 @@ fn add_hidden_type<'tcx>(
155155
}
156156
}
157157

158-
fn get_hidden_type<'tcx>(
159-
hidden_types: &DefinitionSiteHiddenTypes<'tcx>,
160-
def_id: LocalDefId,
161-
) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> {
162-
hidden_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty))
163-
}
164-
165158
#[derive(Debug)]
166159
struct DefiningUse<'tcx> {
167160
/// The opaque type using non NLL vars. This uses the actual
@@ -508,7 +501,8 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
508501
let tcx = infcx.tcx;
509502
let mut errors = Vec::new();
510503
for &(key, hidden_type) in opaque_types {
511-
let Some(expected) = get_hidden_type(hidden_types, key.def_id) else {
504+
let Some(expected) = hidden_types.0.get(&key.def_id).map(|ty| EarlyBinder::bind(*ty))
505+
else {
512506
if !tcx.use_typing_mode_borrowck() {
513507
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
514508
&& alias_ty.def_id == key.def_id.to_def_id()

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,12 @@ fn typeck_with_inspect<'tcx>(
219219
// the future.
220220
fcx.check_repeat_exprs();
221221

222+
// We need to handle opaque types before emitting ambiguity errors as applying
223+
// defining uses may guide type inference.
224+
if fcx.next_trait_solver() {
225+
fcx.try_handle_opaque_type_uses_next();
226+
}
227+
222228
fcx.type_inference_fallback();
223229

224230
// Even though coercion casts provide type hints, we check casts after fallback for

compiler/rustc_hir_typeck/src/opaque_types.rs

Lines changed: 66 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,50 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
2222
/// inference variables.
2323
///
2424
/// It then uses these defining uses to guide inference for all other uses.
25+
///
26+
/// Unlike `handle_opaque_type_uses_next`, this does not report errors.
27+
#[instrument(level = "debug", skip(self))]
28+
pub(super) fn try_handle_opaque_type_uses_next(&mut self) {
29+
// We clone the opaques instead of stealing them here as we still need
30+
// to use them after fallback.
31+
let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
32+
33+
self.compute_definition_site_hidden_types(opaque_types, false);
34+
}
35+
36+
/// This takes all the opaque type uses during HIR typeck. It first computes
37+
/// the concrete hidden type by iterating over all defining uses.
38+
///
39+
/// A use during HIR typeck is defining if all non-lifetime arguments are
40+
/// unique generic parameters and the hidden type does not reference any
41+
/// inference variables.
42+
///
43+
/// It then uses these defining uses to guide inference for all other uses.
2544
#[instrument(level = "debug", skip(self))]
2645
pub(super) fn handle_opaque_type_uses_next(&mut self) {
2746
// We clone the opaques instead of stealing them here as they are still used for
2847
// normalization in the next generation trait solver.
29-
let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types();
48+
let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
3049
let num_entries = self.inner.borrow_mut().opaque_types().num_entries();
3150
let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries));
3251
debug_assert_eq!(prev, None);
33-
for entry in &mut opaque_types {
34-
*entry = self.resolve_vars_if_possible(*entry);
35-
}
36-
debug!(?opaque_types);
3752

38-
self.compute_definition_site_hidden_types(&opaque_types);
39-
self.apply_definition_site_hidden_types(&opaque_types);
53+
self.compute_definition_site_hidden_types(opaque_types, true);
4054
}
4155
}
4256

57+
#[derive(Copy, Clone, Debug)]
4358
enum UsageKind<'tcx> {
4459
None,
4560
NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>),
4661
UnconstrainedHiddenType(OpaqueHiddenType<'tcx>),
47-
HasDefiningUse,
62+
HasDefiningUse(OpaqueHiddenType<'tcx>),
4863
}
4964

5065
impl<'tcx> UsageKind<'tcx> {
5166
fn merge(&mut self, other: UsageKind<'tcx>) {
5267
match (&*self, &other) {
53-
(UsageKind::HasDefiningUse, _) | (_, UsageKind::None) => unreachable!(),
68+
(UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(),
5469
(UsageKind::None, _) => *self = other,
5570
// When mergining non-defining uses, prefer earlier ones. This means
5671
// the error happens as early as possible.
@@ -64,7 +79,7 @@ impl<'tcx> UsageKind<'tcx> {
6479
// intended to be defining.
6580
(
6681
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
67-
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse,
82+
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
6883
) => *self = other,
6984
}
7085
}
@@ -73,8 +88,14 @@ impl<'tcx> UsageKind<'tcx> {
7388
impl<'tcx> FnCtxt<'_, 'tcx> {
7489
fn compute_definition_site_hidden_types(
7590
&mut self,
76-
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
91+
mut opaque_types: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>,
92+
error_on_missing_defining_use: bool,
7793
) {
94+
for entry in opaque_types.iter_mut() {
95+
*entry = self.resolve_vars_if_possible(*entry);
96+
}
97+
debug!(?opaque_types);
98+
7899
let tcx = self.tcx;
79100
let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
80101
else {
@@ -88,19 +109,47 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
88109
_ => unreachable!("not opaque or generator: {def_id:?}"),
89110
}
90111

112+
// We do actually need to check this the second pass (we can't just
113+
// store this), because we can go from `UnconstrainedHiddenType` to
114+
// `HasDefiningUse` (because of fallback)
91115
let mut usage_kind = UsageKind::None;
92-
for &(opaque_type_key, hidden_type) in opaque_types {
116+
for &(opaque_type_key, hidden_type) in &opaque_types {
93117
if opaque_type_key.def_id != def_id {
94118
continue;
95119
}
96120

97121
usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
98-
if let UsageKind::HasDefiningUse = usage_kind {
122+
123+
if let UsageKind::HasDefiningUse(..) = usage_kind {
99124
break;
100125
}
101126
}
102127

128+
if let UsageKind::HasDefiningUse(ty) = usage_kind {
129+
for &(opaque_type_key, hidden_type) in &opaque_types {
130+
if opaque_type_key.def_id != def_id {
131+
continue;
132+
}
133+
134+
let expected = EarlyBinder::bind(ty.ty).instantiate(tcx, opaque_type_key.args);
135+
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
136+
}
137+
138+
// Being explicit here: it may be possible that we in a
139+
// previous call to this function we did an insert, but this
140+
// should be just fine, since they all get equated anyways and
141+
// we shouldn't ever go from `HasDefiningUse` to anyway else.
142+
let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty);
143+
}
144+
145+
// If we're in `fn try_handle_opaque_type_uses_next` then do not
146+
// report any errors.
147+
if !error_on_missing_defining_use {
148+
continue;
149+
}
150+
103151
let guar = match usage_kind {
152+
UsageKind::HasDefiningUse(_) => continue,
104153
UsageKind::None => {
105154
if let Some(guar) = self.tainted_by_errors() {
106155
guar
@@ -137,7 +186,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
137186
.emit()
138187
}
139188
}
140-
UsageKind::HasDefiningUse => continue,
141189
};
142190

143191
self.typeck_results
@@ -148,8 +196,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
148196
}
149197
}
150198

199+
#[tracing::instrument(skip(self), ret)]
151200
fn consider_opaque_type_use(
152-
&mut self,
201+
&self,
153202
opaque_type_key: OpaqueTypeKey<'tcx>,
154203
hidden_type: OpaqueHiddenType<'tcx>,
155204
) -> UsageKind<'tcx> {
@@ -161,11 +210,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
161210
) {
162211
match err {
163212
NonDefiningUseReason::Tainted(guar) => {
164-
self.typeck_results.borrow_mut().hidden_types.insert(
165-
opaque_type_key.def_id,
166-
OpaqueHiddenType::new_error(self.tcx, guar),
167-
);
168-
return UsageKind::HasDefiningUse;
213+
return UsageKind::HasDefiningUse(OpaqueHiddenType::new_error(self.tcx, guar));
169214
}
170215
_ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
171216
};
@@ -193,27 +238,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
193238
self.tcx,
194239
DefiningScopeKind::HirTypeck,
195240
);
196-
197-
let prev = self
198-
.typeck_results
199-
.borrow_mut()
200-
.hidden_types
201-
.insert(opaque_type_key.def_id, hidden_type);
202-
assert!(prev.is_none());
203-
UsageKind::HasDefiningUse
204-
}
205-
206-
fn apply_definition_site_hidden_types(
207-
&mut self,
208-
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
209-
) {
210-
let tcx = self.tcx;
211-
for &(key, hidden_type) in opaque_types {
212-
let expected = *self.typeck_results.borrow_mut().hidden_types.get(&key.def_id).unwrap();
213-
214-
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
215-
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
216-
}
241+
UsageKind::HasDefiningUse(hidden_type)
217242
}
218243

219244
/// We may in theory add further uses of an opaque after cloning the opaque
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
4+
//@ check-pass
5+
6+
// Regression test for trait-system-refactor-initiative#240. Hidden types should
7+
// equate *before* inference var fallback, otherwise we can get mismatched types.
8+
9+
#[derive(Clone, Copy)]
10+
struct FileSystem;
11+
impl FileSystem {
12+
fn build<T>(self, commands: T) -> Option<impl Sized> {
13+
match false {
14+
true => Some(commands),
15+
false => {
16+
drop(match self.build::<_>(commands) {
17+
Some(x) => x,
18+
None => return None,
19+
});
20+
panic!()
21+
},
22+
}
23+
}
24+
}
25+
26+
fn build2<T, U>() -> impl Sized {
27+
if false {
28+
build2::<U, T>()
29+
} else {
30+
loop {}
31+
};
32+
1u32
33+
}
34+
35+
fn build3<'a>() -> impl Sized + use<'a> {
36+
if false {
37+
build3()
38+
} else {
39+
loop {}
40+
};
41+
1u32
42+
}
43+
44+
fn main() {}

0 commit comments

Comments
 (0)