Skip to content

Commit 0dc5930

Browse files
committed
some type system cleanup
1 parent 2b43e75 commit 0dc5930

File tree

9 files changed

+171
-153
lines changed

9 files changed

+171
-153
lines changed

compiler/rustc_infer/src/infer/relate/combine.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub struct CombineFields<'infcx, 'tcx> {
4747
}
4848

4949
impl<'tcx> InferCtxt<'tcx> {
50-
pub fn super_combine_tys<R>(
50+
pub(super) fn super_combine_tys<R>(
5151
&self,
5252
relation: &mut R,
5353
a: Ty<'tcx>,
@@ -138,7 +138,7 @@ impl<'tcx> InferCtxt<'tcx> {
138138
}
139139
}
140140

141-
pub fn super_combine_consts<R>(
141+
pub(super) fn super_combine_consts<R>(
142142
&self,
143143
relation: &mut R,
144144
a: ty::Const<'tcx>,
@@ -194,15 +194,15 @@ impl<'tcx> InferCtxt<'tcx> {
194194
ty::ConstKind::Infer(InferConst::Var(b_vid)),
195195
) => {
196196
self.inner.borrow_mut().const_unification_table().union(a_vid, b_vid);
197-
return Ok(a);
197+
Ok(a)
198198
}
199199

200200
(
201201
ty::ConstKind::Infer(InferConst::EffectVar(a_vid)),
202202
ty::ConstKind::Infer(InferConst::EffectVar(b_vid)),
203203
) => {
204204
self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid);
205-
return Ok(a);
205+
Ok(a)
206206
}
207207

208208
// All other cases of inference with other variables are errors.
@@ -220,42 +220,42 @@ impl<'tcx> InferCtxt<'tcx> {
220220
}
221221

222222
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
223-
return self.instantiate_const_var(vid, b);
223+
self.instantiate_const_var(relation, relation.a_is_expected(), vid, b)?;
224+
Ok(b)
224225
}
225226

226227
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
227-
return self.instantiate_const_var(vid, a);
228+
self.instantiate_const_var(relation, !relation.a_is_expected(), vid, a)?;
229+
Ok(a)
228230
}
229231

230232
(ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => {
231-
return Ok(self.unify_effect_variable(vid, b));
233+
Ok(self.unify_effect_variable(vid, b))
232234
}
233235

234236
(_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => {
235-
return Ok(self.unify_effect_variable(vid, a));
237+
Ok(self.unify_effect_variable(vid, a))
236238
}
237239

238240
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
239241
if self.tcx.features().generic_const_exprs || self.next_trait_solver() =>
240242
{
241243
let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) };
242244

243-
relation.register_predicates([ty::Binder::dummy(if self.next_trait_solver() {
245+
relation.register_predicates([if self.next_trait_solver() {
244246
ty::PredicateKind::AliasRelate(
245247
a.into(),
246248
b.into(),
247249
ty::AliasRelationDirection::Equate,
248250
)
249251
} else {
250252
ty::PredicateKind::ConstEquate(a, b)
251-
})]);
253+
}]);
252254

253-
return Ok(b);
255+
Ok(b)
254256
}
255-
_ => {}
257+
_ => ty::relate::structurally_relate_consts(relation, a, b),
256258
}
257-
258-
ty::relate::structurally_relate_consts(relation, a, b)
259259
}
260260

261261
fn unify_integral_variable(

compiler/rustc_infer/src/infer/relate/generalize.rs

+71-52
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ impl<'tcx> InferCtxt<'tcx> {
2222
/// subtyping could occur. This also does the occurs checks, detecting whether
2323
/// instantiating `target_vid` would result in a cyclic type. We eagerly error
2424
/// in this case.
25-
#[instrument(skip(self, relation, target_is_expected), level = "debug")]
25+
#[instrument(level = "debug", skip(self, relation, target_is_expected))]
2626
pub(super) fn instantiate_ty_var<R: ObligationEmittingRelation<'tcx>>(
2727
&self,
2828
relation: &mut R,
@@ -158,36 +158,48 @@ impl<'tcx> InferCtxt<'tcx> {
158158
/// As `3 + 4` contains `N` in its args, this must not succeed.
159159
///
160160
/// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
161-
#[instrument(level = "debug", skip(self))]
162-
pub(super) fn instantiate_const_var(
161+
#[instrument(level = "debug", skip(self, relation))]
162+
pub(super) fn instantiate_const_var<R: ObligationEmittingRelation<'tcx>>(
163163
&self,
164+
relation: &mut R,
165+
target_is_expected: bool,
164166
target_vid: ty::ConstVid,
165167
source_ct: ty::Const<'tcx>,
166-
) -> RelateResult<'tcx, ty::Const<'tcx>> {
167-
let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) {
168-
ConstVariableValue::Known { value } => {
169-
bug!("instantiating a known const var: {target_vid:?} {value} {source_ct}")
170-
}
171-
ConstVariableValue::Unknown { origin, universe: _ } => origin.span,
172-
};
168+
) -> RelateResult<'tcx, ()> {
173169
// FIXME(generic_const_exprs): Occurs check failures for unevaluated
174170
// constants and generic expressions are not yet handled correctly.
175171
let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } =
176-
self.generalize(span, target_vid, ty::Variance::Invariant, source_ct)?;
172+
self.generalize(relation.span(), target_vid, ty::Variance::Invariant, source_ct)?;
177173

178174
debug_assert!(!generalized_ct.is_ct_infer());
179175
if has_unconstrained_ty_var {
180-
span_bug!(span, "unconstrained ty var when generalizing `{source_ct:?}`");
176+
bug!("unconstrained ty var when generalizing `{source_ct:?}`");
181177
}
182178

183179
self.inner
184180
.borrow_mut()
185181
.const_unification_table()
186182
.union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
187183

188-
// FIXME(generic_const_exprs): We have to make sure we actually equate
189-
// `generalized_ct` and `source_ct` here.
190-
Ok(generalized_ct)
184+
// HACK: make sure that we `a_is_expected` continues to be
185+
// correct when relating the generalized type with the source.
186+
if target_is_expected == relation.a_is_expected() {
187+
relation.relate_with_variance(
188+
ty::Variance::Invariant,
189+
ty::VarianceDiagInfo::default(),
190+
generalized_ct,
191+
source_ct,
192+
)?;
193+
} else {
194+
relation.relate_with_variance(
195+
ty::Variance::Invariant,
196+
ty::VarianceDiagInfo::default(),
197+
source_ct,
198+
generalized_ct,
199+
)?;
200+
}
201+
202+
Ok(())
191203
}
192204

193205
/// Attempts to generalize `source_term` for the type variable `target_vid`.
@@ -287,6 +299,49 @@ impl<'tcx> Generalizer<'_, 'tcx> {
287299
ty::TermKind::Const(ct) => TypeError::CyclicConst(ct),
288300
}
289301
}
302+
303+
/// An occurs check failure inside of an alias does not mean
304+
/// that the types definitely don't unify. We may be able
305+
/// to normalize the alias after all.
306+
///
307+
/// We handle this by lazily equating the alias and generalizing
308+
/// it to an inference variable.
309+
///
310+
/// This is incomplete and will hopefully soon get fixed by #119106.
311+
fn generalize_alias_ty(
312+
&mut self,
313+
alias: ty::AliasTy<'tcx>,
314+
) -> Result<Ty<'tcx>, TypeError<'tcx>> {
315+
let is_nested_alias = mem::replace(&mut self.in_alias, true);
316+
let result = match self.relate(alias, alias) {
317+
Ok(alias) => Ok(alias.to_ty(self.tcx())),
318+
Err(e) => {
319+
if is_nested_alias {
320+
return Err(e);
321+
} else {
322+
let mut visitor = MaxUniverse::new();
323+
alias.visit_with(&mut visitor);
324+
let infer_replacement_is_complete =
325+
self.for_universe.can_name(visitor.max_universe())
326+
&& !alias.has_escaping_bound_vars();
327+
if !infer_replacement_is_complete {
328+
warn!("may incompletely handle alias type: {alias:?}");
329+
}
330+
331+
debug!("generalization failure in alias");
332+
Ok(self.infcx.next_ty_var_in_universe(
333+
TypeVariableOrigin {
334+
kind: TypeVariableOriginKind::MiscVariable,
335+
span: self.span,
336+
},
337+
self.for_universe,
338+
))
339+
}
340+
}
341+
};
342+
self.in_alias = is_nested_alias;
343+
result
344+
}
290345
}
291346

292347
impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
@@ -433,43 +488,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
433488
}
434489
}
435490

436-
ty::Alias(kind, data) => {
437-
// An occurs check failure inside of an alias does not mean
438-
// that the types definitely don't unify. We may be able
439-
// to normalize the alias after all.
440-
//
441-
// We handle this by lazily equating the alias and generalizing
442-
// it to an inference variable.
443-
let is_nested_alias = mem::replace(&mut self.in_alias, true);
444-
let result = match self.relate(data, data) {
445-
Ok(data) => Ok(Ty::new_alias(self.tcx(), kind, data)),
446-
Err(e) => {
447-
if is_nested_alias {
448-
return Err(e);
449-
} else {
450-
let mut visitor = MaxUniverse::new();
451-
t.visit_with(&mut visitor);
452-
let infer_replacement_is_complete =
453-
self.for_universe.can_name(visitor.max_universe())
454-
&& !t.has_escaping_bound_vars();
455-
if !infer_replacement_is_complete {
456-
warn!("may incompletely handle alias type: {t:?}");
457-
}
458-
459-
debug!("generalization failure in alias");
460-
Ok(self.infcx.next_ty_var_in_universe(
461-
TypeVariableOrigin {
462-
kind: TypeVariableOriginKind::MiscVariable,
463-
span: self.span,
464-
},
465-
self.for_universe,
466-
))
467-
}
468-
}
469-
};
470-
self.in_alias = is_nested_alias;
471-
result
472-
}
491+
ty::Alias(_, data) => self.generalize_alias_ty(data),
473492

474493
_ => relate::structurally_relate_tys(self, t, t),
475494
}?;

compiler/rustc_trait_selection/src/solve/normalize.rs

+11-18
Original file line numberDiff line numberDiff line change
@@ -85,25 +85,16 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
8585
),
8686
);
8787

88-
// Do not emit an error if normalization is known to fail but instead
89-
// keep the projection unnormalized. This is the case for projections
90-
// with a `T: Trait` where-clause and opaque types outside of the defining
91-
// scope.
92-
let result = if infcx.predicate_may_hold(&obligation) {
93-
self.fulfill_cx.register_predicate_obligation(infcx, obligation);
94-
let errors = self.fulfill_cx.select_all_or_error(infcx);
95-
if !errors.is_empty() {
96-
return Err(errors);
97-
}
98-
let ty = infcx.resolve_vars_if_possible(new_infer_ty);
99-
100-
// Alias is guaranteed to be fully structurally resolved,
101-
// so we can super fold here.
102-
ty.try_super_fold_with(self)?
103-
} else {
104-
alias_ty.try_super_fold_with(self)?
105-
};
88+
self.fulfill_cx.register_predicate_obligation(infcx, obligation);
89+
let errors = self.fulfill_cx.select_all_or_error(infcx);
90+
if !errors.is_empty() {
91+
return Err(errors);
92+
}
10693

94+
// Alias is guaranteed to be fully structurally resolved,
95+
// so we can super fold here.
96+
let ty = infcx.resolve_vars_if_possible(new_infer_ty);
97+
let result = ty.try_super_fold_with(self)?;
10798
self.depth -= 1;
10899
Ok(result)
109100
}
@@ -178,6 +169,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
178169
Ok(t)
179170
}
180171

172+
#[instrument(level = "debug", skip(self), ret)]
181173
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
182174
let infcx = self.at.infcx;
183175
debug_assert_eq!(ty, infcx.shallow_resolve(ty));
@@ -204,6 +196,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
204196
}
205197
}
206198

199+
#[instrument(level = "debug", skip(self), ret)]
207200
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
208201
let infcx = self.at.infcx;
209202
debug_assert_eq!(ct, infcx.shallow_resolve(ct));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use crate::solve::EvalCtxt;
2+
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
3+
use rustc_middle::ty;
4+
5+
impl<'tcx> EvalCtxt<'_, 'tcx> {
6+
#[instrument(level = "debug", skip(self), ret)]
7+
pub(super) fn normalize_anon_const(
8+
&mut self,
9+
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
10+
) -> QueryResult<'tcx> {
11+
if let Some(normalized_const) = self.try_const_eval_resolve(
12+
goal.param_env,
13+
ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args),
14+
self.tcx()
15+
.type_of(goal.predicate.alias.def_id)
16+
.no_bound_vars()
17+
.expect("const ty should not rely on other generics"),
18+
) {
19+
self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?;
20+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
21+
} else {
22+
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)