Skip to content

Commit 717ed47

Browse files
committed
An ugly, awful hack that works
1 parent 335ffbf commit 717ed47

File tree

19 files changed

+389
-67
lines changed

19 files changed

+389
-67
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -2101,8 +2101,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
21012101

21022102
let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
21032103

2104+
let ty = self.normalize(*ty, location);
21042105
if let Err(terr) = self.eq_types(
2105-
*ty,
2106+
ty,
21062107
ty_fn_ptr_from,
21072108
location.to_locations(),
21082109
ConstraintCategory::Cast,
@@ -2124,9 +2125,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
21242125
_ => bug!(),
21252126
};
21262127
let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety));
2128+
let ty_fn_ptr_from = self.normalize(ty_fn_ptr_from, location);
21272129

2130+
let ty = self.normalize(*ty, location);
21282131
if let Err(terr) = self.eq_types(
2129-
*ty,
2132+
ty,
21302133
ty_fn_ptr_from,
21312134
location.to_locations(),
21322135
ConstraintCategory::Cast,
@@ -2154,8 +2157,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
21542157

21552158
let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
21562159

2160+
let ty = self.normalize(*ty, location);
21572161
if let Err(terr) = self.eq_types(
2158-
*ty,
2162+
ty,
21592163
ty_fn_ptr_from,
21602164
location.to_locations(),
21612165
ConstraintCategory::Cast,

compiler/rustc_infer/src/infer/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
920920
.region_constraints_added_in_snapshot(&snapshot.undo_snapshot)
921921
}
922922

923+
pub fn any_instantiations(&self, snapshot: &CombinedSnapshot<'a, 'tcx>) -> bool {
924+
self.inner.borrow_mut().any_instantiations(&snapshot.undo_snapshot)
925+
}
926+
923927
pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
924928
self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
925929
}

compiler/rustc_infer/src/infer/undo_log.rs

+31
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,23 @@ pub(crate) enum UndoLog<'tcx> {
2929
PushRegionObligation,
3030
}
3131

32+
impl<'tcx> std::fmt::Debug for UndoLog<'tcx> {
33+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34+
match self {
35+
Self::TypeVariables(_) => f.debug_tuple("TypeVariables").finish(),
36+
Self::ConstUnificationTable(_) => f.debug_tuple("ConstUnificationTable").finish(),
37+
Self::IntUnificationTable(_) => f.debug_tuple("IntUnificationTable").finish(),
38+
Self::FloatUnificationTable(_) => f.debug_tuple("FloatUnificationTable").finish(),
39+
Self::RegionConstraintCollector(_) => {
40+
f.debug_tuple("RegionConstraintCollector").finish()
41+
}
42+
Self::RegionUnificationTable(_) => f.debug_tuple("RegionUnificationTable").finish(),
43+
Self::ProjectionCache(_) => f.debug_tuple("ProjectionCache").finish(),
44+
Self::PushRegionObligation => write!(f, "PushRegionObligation"),
45+
}
46+
}
47+
}
48+
3249
macro_rules! impl_from {
3350
($($ctor: ident ($ty: ty),)*) => {
3451
$(
@@ -165,6 +182,10 @@ impl<'tcx> InferCtxtInner<'tcx> {
165182

166183
self.undo_log.num_open_snapshots -= 1;
167184
}
185+
186+
pub fn any_instantiations(&mut self, snapshot: &Snapshot<'tcx>) -> bool {
187+
self.undo_log.instantiations_in_snapshot(snapshot).next().is_some()
188+
}
168189
}
169190

170191
impl<'tcx> InferCtxtUndoLogs<'tcx> {
@@ -173,6 +194,16 @@ impl<'tcx> InferCtxtUndoLogs<'tcx> {
173194
Snapshot { undo_len: self.logs.len(), _marker: PhantomData }
174195
}
175196

197+
pub(crate) fn instantiations_in_snapshot(
198+
&self,
199+
s: &Snapshot<'tcx>,
200+
) -> impl Iterator<Item = &'_ type_variable::UndoLog<'tcx>> + Clone {
201+
self.logs[s.undo_len..].iter().filter_map(|log| match log {
202+
UndoLog::TypeVariables(log) => Some(log),
203+
_ => None,
204+
})
205+
}
206+
176207
pub(crate) fn region_constraints_in_snapshot(
177208
&self,
178209
s: &Snapshot<'tcx>,

compiler/rustc_trait_selection/src/traits/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ pub use self::object_safety::is_vtable_safe_method;
5555
pub use self::object_safety::MethodViolationCode;
5656
pub use self::object_safety::ObjectSafetyViolation;
5757
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
58-
pub use self::project::{normalize, normalize_projection_type, normalize_to};
58+
pub use self::project::{
59+
normalize, normalize_projection_type, normalize_to, normalize_with_depth_to,
60+
project_and_unify_type,
61+
};
5962
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
6063
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
6164
pub use self::specialize::specialization_graph::FutureCompatOverlapError;

compiler/rustc_trait_selection/src/traits/project.rs

+72-34
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'
4242

4343
pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>>;
4444

45-
pub(super) struct InProgress;
45+
pub struct InProgress;
4646

4747
/// When attempting to resolve `<T as TraitRef>::Name` ...
4848
#[derive(Debug)]
@@ -188,7 +188,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
188188
/// If successful, this may result in additional obligations.
189189
///
190190
/// See [poly_project_and_unify_type] for an explanation of the return value.
191-
fn project_and_unify_type<'cx, 'tcx>(
191+
pub fn project_and_unify_type<'cx, 'tcx>(
192192
selcx: &mut SelectionContext<'cx, 'tcx>,
193193
obligation: &ProjectionObligation<'tcx>,
194194
) -> Result<
@@ -484,7 +484,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
484484
// there won't be bound vars there.
485485

486486
let data = data.super_fold_with(self);
487-
let normalized_ty = if self.eager_inference_replacement {
487+
let normalized_ty = if self.selcx.normalization_mode.eager_inference_replacement {
488488
normalize_projection_type(
489489
self.selcx,
490490
self.param_env,
@@ -914,7 +914,8 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
914914
// Don't use the projection cache in intercrate mode -
915915
// the `infcx` may be re-used between intercrate in non-intercrate
916916
// mode, which could lead to using incorrect cache results.
917-
let use_cache = !selcx.is_intercrate();
917+
let use_cache =
918+
!selcx.is_intercrate() && selcx.normalization_mode.allow_infer_constraint_during_projection;
918919

919920
let projection_ty = infcx.resolve_vars_if_possible(projection_ty);
920921
let cache_key = ProjectionCacheKey::new(projection_ty);
@@ -1168,7 +1169,7 @@ fn project<'cx, 'tcx>(
11681169

11691170
match candidates {
11701171
ProjectionCandidateSet::Single(candidate) => {
1171-
Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate)))
1172+
Ok(confirm_candidate(selcx, obligation, candidate))
11721173
}
11731174
ProjectionCandidateSet::None => Ok(Projected::NoProgress(
11741175
// FIXME(associated_const_generics): this may need to change in the future?
@@ -1583,7 +1584,7 @@ fn confirm_candidate<'cx, 'tcx>(
15831584
selcx: &mut SelectionContext<'cx, 'tcx>,
15841585
obligation: &ProjectionTyObligation<'tcx>,
15851586
candidate: ProjectionCandidate<'tcx>,
1586-
) -> Progress<'tcx> {
1587+
) -> Projected<'tcx> {
15871588
debug!(?obligation, ?candidate, "confirm_candidate");
15881589
let mut progress = match candidate {
15891590
ProjectionCandidate::ParamEnv(poly_projection)
@@ -1596,7 +1597,7 @@ fn confirm_candidate<'cx, 'tcx>(
15961597
}
15971598

15981599
ProjectionCandidate::Select(impl_source) => {
1599-
confirm_select_candidate(selcx, obligation, impl_source)
1600+
Projected::Progress(confirm_select_candidate(selcx, obligation, impl_source))
16001601
}
16011602
};
16021603

@@ -1605,9 +1606,11 @@ fn confirm_candidate<'cx, 'tcx>(
16051606
// with new region variables, we need to resolve them to existing variables
16061607
// when possible for this to work. See `auto-trait-projection-recursion.rs`
16071608
// for a case where this matters.
1608-
if progress.term.has_infer_regions() {
1609-
progress.term =
1610-
progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx()));
1609+
if let Projected::Progress(progress) = &mut progress {
1610+
if progress.term.has_infer_regions() {
1611+
progress.term =
1612+
progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx()));
1613+
}
16111614
}
16121615
progress
16131616
}
@@ -1688,9 +1691,12 @@ fn confirm_generator_candidate<'cx, 'tcx>(
16881691
}
16891692
});
16901693

1691-
confirm_param_env_candidate(selcx, obligation, predicate, false)
1692-
.with_addl_obligations(impl_source.nested)
1693-
.with_addl_obligations(obligations)
1694+
let progress = confirm_param_env_candidate(selcx, obligation, predicate, false);
1695+
let progress = match progress {
1696+
Projected::Progress(progress) => progress,
1697+
Projected::NoProgress(_) => bug!(),
1698+
};
1699+
progress.with_addl_obligations(impl_source.nested).with_addl_obligations(obligations)
16941700
}
16951701

16961702
fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
@@ -1715,7 +1721,12 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
17151721

17161722
// We get here from `poly_project_and_unify_type` which replaces bound vars
17171723
// with placeholders, so dummy is okay here.
1718-
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
1724+
let progress =
1725+
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false);
1726+
match progress {
1727+
Projected::Progress(progress) => progress,
1728+
Projected::NoProgress(_) => bug!(),
1729+
}
17191730
}
17201731

17211732
fn confirm_pointee_candidate<'cx, 'tcx>(
@@ -1746,8 +1757,12 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
17461757
term: metadata_ty.into(),
17471758
};
17481759

1749-
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
1750-
.with_addl_obligations(obligations)
1760+
let progress =
1761+
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false);
1762+
match progress {
1763+
Projected::Progress(progress) => progress.with_addl_obligations(obligations),
1764+
Projected::NoProgress(_) => bug!(),
1765+
}
17511766
}
17521767

17531768
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
@@ -1819,15 +1834,19 @@ fn confirm_callable_candidate<'cx, 'tcx>(
18191834
term: ret_type.into(),
18201835
});
18211836

1822-
confirm_param_env_candidate(selcx, obligation, predicate, true)
1837+
let progress = confirm_param_env_candidate(selcx, obligation, predicate, true);
1838+
match progress {
1839+
Projected::Progress(progress) => progress,
1840+
Projected::NoProgress(_) => bug!(),
1841+
}
18231842
}
18241843

18251844
fn confirm_param_env_candidate<'cx, 'tcx>(
18261845
selcx: &mut SelectionContext<'cx, 'tcx>,
18271846
obligation: &ProjectionTyObligation<'tcx>,
18281847
poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
18291848
potentially_unnormalized_candidate: bool,
1830-
) -> Progress<'tcx> {
1849+
) -> Projected<'tcx> {
18311850
let infcx = selcx.infcx();
18321851
let cause = &obligation.cause;
18331852
let param_env = obligation.param_env;
@@ -1868,23 +1887,42 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
18681887

18691888
debug!(?cache_projection, ?obligation_projection);
18701889

1871-
match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
1872-
Ok(InferOk { value: _, obligations }) => {
1873-
nested_obligations.extend(obligations);
1874-
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
1875-
// FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
1876-
// a term instead.
1877-
Progress { term: cache_entry.term, obligations: nested_obligations }
1878-
}
1879-
Err(e) => {
1880-
let msg = format!(
1881-
"Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}",
1882-
obligation, poly_cache_entry, e,
1883-
);
1884-
debug!("confirm_param_env_candidate: {}", msg);
1885-
let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg);
1886-
Progress { term: err.into(), obligations: vec![] }
1890+
match infcx.commit_if_ok(|snapshot| {
1891+
let progress = match infcx.at(cause, param_env).eq(cache_projection, obligation_projection)
1892+
{
1893+
Ok(InferOk { value: _, obligations }) => {
1894+
nested_obligations.extend(obligations);
1895+
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
1896+
// FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
1897+
// a term instead.
1898+
Progress { term: cache_entry.term, obligations: nested_obligations }
1899+
}
1900+
Err(e) => {
1901+
let msg = format!(
1902+
"Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}",
1903+
obligation, poly_cache_entry, e,
1904+
);
1905+
debug!("confirm_param_env_candidate: {}", msg);
1906+
let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg);
1907+
Progress { term: err.into(), obligations: vec![] }
1908+
}
1909+
};
1910+
1911+
let any_instantiations = infcx.any_instantiations(&snapshot);
1912+
1913+
if any_instantiations && !selcx.normalization_mode.allow_infer_constraint_during_projection
1914+
{
1915+
Err(ty::Term::Ty(
1916+
infcx
1917+
.tcx
1918+
.mk_projection(obligation_projection.item_def_id, obligation_projection.substs),
1919+
))
1920+
} else {
1921+
Ok(progress)
18871922
}
1923+
}) {
1924+
Ok(p) => Projected::Progress(p),
1925+
Err(p) => Projected::NoProgress(p),
18881926
}
18891927
}
18901928

compiler/rustc_trait_selection/src/traits/select/mod.rs

+31
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,17 @@ pub struct SelectionContext<'cx, 'tcx> {
132132
/// policy. In essence, canonicalized queries need their errors propagated
133133
/// rather than immediately reported because we do not have accurate spans.
134134
query_mode: TraitQueryMode,
135+
136+
pub normalization_mode: NormalizationMode,
137+
}
138+
139+
#[derive(Copy, Clone)]
140+
pub struct NormalizationMode {
141+
pub allow_infer_constraint_during_projection: bool,
142+
/// If true, when a projection is unable to be completed, an inference
143+
/// variable will be created and an obligation registered to project to that
144+
/// inference variable. Also, constants will be eagerly evaluated.
145+
pub eager_inference_replacement: bool,
135146
}
136147

137148
// A stack that walks back up the stack frame.
@@ -221,6 +232,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
221232
intercrate_ambiguity_causes: None,
222233
allow_negative_impls: false,
223234
query_mode: TraitQueryMode::Standard,
235+
normalization_mode: NormalizationMode {
236+
allow_infer_constraint_during_projection: true,
237+
eager_inference_replacement: true,
238+
},
224239
}
225240
}
226241

@@ -232,6 +247,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
232247
intercrate_ambiguity_causes: None,
233248
allow_negative_impls: false,
234249
query_mode: TraitQueryMode::Standard,
250+
normalization_mode: NormalizationMode {
251+
allow_infer_constraint_during_projection: true,
252+
eager_inference_replacement: true,
253+
},
235254
}
236255
}
237256

@@ -247,6 +266,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
247266
intercrate_ambiguity_causes: None,
248267
allow_negative_impls,
249268
query_mode: TraitQueryMode::Standard,
269+
normalization_mode: NormalizationMode {
270+
allow_infer_constraint_during_projection: true,
271+
eager_inference_replacement: true,
272+
},
250273
}
251274
}
252275

@@ -262,6 +285,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
262285
intercrate_ambiguity_causes: None,
263286
allow_negative_impls: false,
264287
query_mode,
288+
normalization_mode: NormalizationMode {
289+
allow_infer_constraint_during_projection: true,
290+
eager_inference_replacement: true,
291+
},
265292
}
266293
}
267294

@@ -297,6 +324,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
297324
self.intercrate
298325
}
299326

327+
pub fn normalization_mode(&self) -> NormalizationMode {
328+
self.normalization_mode
329+
}
330+
300331
///////////////////////////////////////////////////////////////////////////
301332
// Selection
302333
//

0 commit comments

Comments
 (0)