Skip to content

Commit 84fb939

Browse files
committed
emit WF goals in relate, not in generalize
1 parent 2570c23 commit 84fb939

File tree

12 files changed

+265
-159
lines changed

12 files changed

+265
-159
lines changed

compiler/rustc_borrowck/src/polonius/liveness_constraints.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use std::collections::BTreeMap;
22

3+
use rustc_hir::def_id::DefId;
34
use rustc_index::bit_set::SparseBitMatrix;
45
use rustc_middle::mir::{Body, Location};
5-
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
6+
use rustc_middle::ty::relate::{
7+
self, Relate, RelateResult, TypeRelation, relate_args_with_variances,
8+
};
69
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
710
use rustc_mir_dataflow::points::PointIndex;
811

@@ -256,6 +259,20 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for VarianceExtractor<'_, 'tcx> {
256259
self.tcx
257260
}
258261

262+
fn relate_ty_args(
263+
&mut self,
264+
a_ty: Ty<'tcx>,
265+
_: Ty<'tcx>,
266+
def_id: DefId,
267+
a_args: ty::GenericArgsRef<'tcx>,
268+
b_args: ty::GenericArgsRef<'tcx>,
269+
_: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
270+
) -> RelateResult<'tcx, Ty<'tcx>> {
271+
let variances = self.cx().variances_of(def_id);
272+
relate_args_with_variances(self, variances, a_args, b_args)?;
273+
Ok(a_ty)
274+
}
275+
259276
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
260277
&mut self,
261278
variance: ty::Variance,

compiler/rustc_borrowck/src/type_check/relate_tys.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_data_structures::fx::FxHashMap;
22
use rustc_errors::ErrorGuaranteed;
3+
use rustc_hir::def_id::DefId;
34
use rustc_infer::infer::relate::{
45
PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
56
};
@@ -9,7 +10,7 @@ use rustc_infer::traits::solve::Goal;
910
use rustc_middle::mir::ConstraintCategory;
1011
use rustc_middle::traits::ObligationCause;
1112
use rustc_middle::traits::query::NoSolution;
12-
use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys};
13+
use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys};
1314
use rustc_middle::ty::{self, FnMutDelegate, Ty, TyCtxt, TypeVisitableExt};
1415
use rustc_middle::{bug, span_bug};
1516
use rustc_span::{Span, Symbol, sym};
@@ -303,6 +304,19 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
303304
self.type_checker.infcx.tcx
304305
}
305306

307+
fn relate_ty_args(
308+
&mut self,
309+
a_ty: Ty<'tcx>,
310+
b_ty: Ty<'tcx>,
311+
def_id: DefId,
312+
a_args: ty::GenericArgsRef<'tcx>,
313+
b_args: ty::GenericArgsRef<'tcx>,
314+
_: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
315+
) -> RelateResult<'tcx, Ty<'tcx>> {
316+
let variances = self.cx().variances_of(def_id);
317+
combine_ty_args(self, a_ty, b_ty, variances, a_args, b_args, |_| a_ty)
318+
}
319+
306320
#[instrument(skip(self, info), level = "trace", ret)]
307321
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
308322
&mut self,

compiler/rustc_infer/src/infer/outlives/test_type_match.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use std::collections::hash_map::Entry;
22

33
use rustc_data_structures::fx::FxHashMap;
4+
use rustc_hir::def_id::DefId;
45
use rustc_middle::ty::error::TypeError;
56
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
7+
use rustc_type_ir::relate::relate_args_with_variances;
68
use tracing::instrument;
79

810
use crate::infer::region_constraints::VerifyIfEq;
@@ -137,6 +139,20 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx>
137139
self.tcx
138140
}
139141

142+
fn relate_ty_args(
143+
&mut self,
144+
a_ty: Ty<'tcx>,
145+
_: Ty<'tcx>,
146+
def_id: DefId,
147+
a_args: ty::GenericArgsRef<'tcx>,
148+
b_args: ty::GenericArgsRef<'tcx>,
149+
_: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
150+
) -> RelateResult<'tcx, Ty<'tcx>> {
151+
let variances = self.cx().variances_of(def_id);
152+
relate_args_with_variances(self, variances, a_args, b_args)?;
153+
Ok(a_ty)
154+
}
155+
140156
#[instrument(level = "trace", skip(self))]
141157
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
142158
&mut self,
@@ -145,6 +161,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx>
145161
a: T,
146162
b: T,
147163
) -> RelateResult<'tcx, T> {
164+
// FIXME(@lcnr): This is weird. We are ignoring the ambient variance
165+
// here, effectively treating everything as being in either a covariant
166+
// or contravariant context.
167+
//
148168
// Opaque types args have lifetime parameters.
149169
// We must not check them to be equal, as we never insert anything to make them so.
150170
if variance != ty::Bivariant { self.relate(a, b) } else { Ok(a) }

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

Lines changed: 33 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,13 @@ impl<'tcx> InferCtxt<'tcx> {
7070
//
7171
// We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
7272
// `?1 <: ?3`.
73-
let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self
74-
.generalize(
75-
relation.span(),
76-
relation.structurally_relate_aliases(),
77-
target_vid,
78-
instantiation_variance,
79-
source_ty,
80-
)?;
73+
let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
74+
relation.span(),
75+
relation.structurally_relate_aliases(),
76+
target_vid,
77+
instantiation_variance,
78+
source_ty,
79+
)?;
8180

8281
// Constrain `b_vid` to the generalized type `generalized_ty`.
8382
if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
@@ -86,11 +85,6 @@ impl<'tcx> InferCtxt<'tcx> {
8685
self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty);
8786
}
8887

89-
// See the comment on `Generalization::has_unconstrained_ty_var`.
90-
if has_unconstrained_ty_var {
91-
relation.register_predicates([ty::ClauseKind::WellFormed(generalized_ty.into())]);
92-
}
93-
9488
// Finally, relate `generalized_ty` to `source_ty`, as described in previous comment.
9589
//
9690
// FIXME(#16847): This code is non-ideal because all these subtype
@@ -210,19 +204,15 @@ impl<'tcx> InferCtxt<'tcx> {
210204
) -> RelateResult<'tcx, ()> {
211205
// FIXME(generic_const_exprs): Occurs check failures for unevaluated
212206
// constants and generic expressions are not yet handled correctly.
213-
let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = self
214-
.generalize(
215-
relation.span(),
216-
relation.structurally_relate_aliases(),
217-
target_vid,
218-
ty::Invariant,
219-
source_ct,
220-
)?;
207+
let Generalization { value_may_be_infer: generalized_ct } = self.generalize(
208+
relation.span(),
209+
relation.structurally_relate_aliases(),
210+
target_vid,
211+
ty::Invariant,
212+
source_ct,
213+
)?;
221214

222215
debug_assert!(!generalized_ct.is_ct_infer());
223-
if has_unconstrained_ty_var {
224-
bug!("unconstrained ty var when generalizing `{source_ct:?}`");
225-
}
226216

227217
self.inner
228218
.borrow_mut()
@@ -281,12 +271,10 @@ impl<'tcx> InferCtxt<'tcx> {
281271
ambient_variance,
282272
in_alias: false,
283273
cache: Default::default(),
284-
has_unconstrained_ty_var: false,
285274
};
286275

287276
let value_may_be_infer = generalizer.relate(source_term, source_term)?;
288-
let has_unconstrained_ty_var = generalizer.has_unconstrained_ty_var;
289-
Ok(Generalization { value_may_be_infer, has_unconstrained_ty_var })
277+
Ok(Generalization { value_may_be_infer })
290278
}
291279
}
292280

@@ -376,9 +364,6 @@ struct Generalizer<'me, 'tcx> {
376364
in_alias: bool,
377365

378366
cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>,
379-
380-
/// See the field `has_unconstrained_ty_var` in `Generalization`.
381-
has_unconstrained_ty_var: bool,
382367
}
383368

384369
impl<'tcx> Generalizer<'_, 'tcx> {
@@ -391,10 +376,8 @@ impl<'tcx> Generalizer<'_, 'tcx> {
391376
}
392377

393378
/// Create a new type variable in the universe of the target when
394-
/// generalizing an alias. This has to set `has_unconstrained_ty_var`
395-
/// if we're currently in a bivariant context.
379+
/// generalizing an alias.
396380
fn next_ty_var_for_alias(&mut self) -> Ty<'tcx> {
397-
self.has_unconstrained_ty_var |= self.ambient_variance == ty::Bivariant;
398381
self.infcx.next_ty_var_in_universe(self.span, self.for_universe)
399382
}
400383

@@ -461,29 +444,26 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
461444
self.infcx.tcx
462445
}
463446

464-
fn relate_item_args(
447+
fn relate_ty_args(
465448
&mut self,
466-
item_def_id: DefId,
467-
a_arg: ty::GenericArgsRef<'tcx>,
468-
b_arg: ty::GenericArgsRef<'tcx>,
469-
) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
470-
if self.ambient_variance == ty::Invariant {
449+
a_ty: Ty<'tcx>,
450+
_: Ty<'tcx>,
451+
def_id: DefId,
452+
a_args: ty::GenericArgsRef<'tcx>,
453+
b_args: ty::GenericArgsRef<'tcx>,
454+
mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
455+
) -> RelateResult<'tcx, Ty<'tcx>> {
456+
let args = if self.ambient_variance == ty::Invariant {
471457
// Avoid fetching the variance if we are in an invariant
472458
// context; no need, and it can induce dependency cycles
473459
// (e.g., #41849).
474-
relate::relate_args_invariantly(self, a_arg, b_arg)
460+
relate::relate_args_invariantly(self, a_args, b_args)
475461
} else {
476462
let tcx = self.cx();
477-
let opt_variances = tcx.variances_of(item_def_id);
478-
relate::relate_args_with_variances(
479-
self,
480-
item_def_id,
481-
opt_variances,
482-
a_arg,
483-
b_arg,
484-
false,
485-
)
486-
}
463+
let variances = tcx.variances_of(def_id);
464+
relate::relate_args_with_variances(self, variances, a_args, b_args)
465+
}?;
466+
if args == a_args { Ok(a_ty) } else { Ok(mk(args)) }
487467
}
488468

489469
#[instrument(level = "debug", skip(self, variance, b), ret)]
@@ -545,14 +525,8 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
545525
}
546526
}
547527

548-
// Bivariant: make a fresh var, but remember that
549-
// it is unconstrained. See the comment in
550-
// `Generalization`.
551-
ty::Bivariant => self.has_unconstrained_ty_var = true,
552-
553-
// Co/contravariant: this will be
554-
// sufficiently constrained later on.
555-
ty::Covariant | ty::Contravariant => (),
528+
// We do need a fresh type variable otherwise.
529+
ty::Bivariant | ty::Covariant | ty::Contravariant => (),
556530
}
557531

558532
let origin = inner.type_variables().var_origin(vid);
@@ -771,32 +745,8 @@ struct Generalization<T> {
771745
/// for `?0` generalization returns an inference
772746
/// variable.
773747
///
774-
/// This has to be handled wotj care as it can
748+
/// This has to be handled with care as it can
775749
/// otherwise very easily result in infinite
776750
/// recursion.
777751
pub value_may_be_infer: T,
778-
779-
/// In general, we do not check whether all types which occur during
780-
/// type checking are well-formed. We only check wf of user-provided types
781-
/// and when actually using a type, e.g. for method calls.
782-
///
783-
/// This means that when subtyping, we may end up with unconstrained
784-
/// inference variables if a generalized type has bivariant parameters.
785-
/// A parameter may only be bivariant if it is constrained by a projection
786-
/// bound in a where-clause. As an example, imagine a type:
787-
///
788-
/// struct Foo<A, B> where A: Iterator<Item = B> {
789-
/// data: A
790-
/// }
791-
///
792-
/// here, `A` will be covariant, but `B` is unconstrained.
793-
///
794-
/// However, whatever it is, for `Foo` to be WF, it must be equal to `A::Item`.
795-
/// If we have an input `Foo<?A, ?B>`, then after generalization we will wind
796-
/// up with a type like `Foo<?C, ?D>`. When we enforce `Foo<?A, ?B> <: Foo<?C, ?D>`,
797-
/// we will wind up with the requirement that `?A <: ?C`, but no particular
798-
/// relationship between `?B` and `?D` (after all, these types may be completely
799-
/// different). If we do nothing else, this may mean that `?D` goes unconstrained
800-
/// (as in #41677). To avoid this we emit a `WellFormed` obligation in these cases.
801-
pub has_unconstrained_ty_var: bool,
802752
}

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
//!
1818
//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
1919
20+
use rustc_hir::def_id::DefId;
2021
use rustc_middle::traits::solve::Goal;
21-
use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys};
22+
use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys};
2223
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
2324
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
2425
use rustc_span::Span;
@@ -75,6 +76,19 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
7576
self.infcx.tcx
7677
}
7778

79+
fn relate_ty_args(
80+
&mut self,
81+
a_ty: Ty<'tcx>,
82+
b_ty: Ty<'tcx>,
83+
def_id: DefId,
84+
a_args: ty::GenericArgsRef<'tcx>,
85+
b_args: ty::GenericArgsRef<'tcx>,
86+
mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
87+
) -> RelateResult<'tcx, Ty<'tcx>> {
88+
let variances = self.cx().variances_of(def_id);
89+
combine_ty_args(self, a_ty, b_ty, variances, a_args, b_args, |args| mk(args))
90+
}
91+
7892
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
7993
&mut self,
8094
variance: ty::Variance,

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

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1+
use rustc_hir::def_id::DefId;
12
use rustc_middle::traits::solve::Goal;
2-
use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys};
3-
use rustc_middle::ty::relate::{
4-
Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances,
5-
};
3+
use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys};
4+
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation, relate_args_invariantly};
65
use rustc_middle::ty::{self, DelayedSet, Ty, TyCtxt, TyVar};
76
use rustc_span::Span;
87
use tracing::{debug, instrument};
@@ -79,21 +78,21 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, 'tcx> {
7978
self.infcx.tcx
8079
}
8180

82-
fn relate_item_args(
81+
fn relate_ty_args(
8382
&mut self,
84-
item_def_id: rustc_hir::def_id::DefId,
85-
a_arg: ty::GenericArgsRef<'tcx>,
86-
b_arg: ty::GenericArgsRef<'tcx>,
87-
) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
83+
a_ty: Ty<'tcx>,
84+
b_ty: Ty<'tcx>,
85+
def_id: DefId,
86+
a_args: ty::GenericArgsRef<'tcx>,
87+
b_args: ty::GenericArgsRef<'tcx>,
88+
_: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
89+
) -> RelateResult<'tcx, Ty<'tcx>> {
8890
if self.ambient_variance == ty::Invariant {
89-
// Avoid fetching the variance if we are in an invariant
90-
// context; no need, and it can induce dependency cycles
91-
// (e.g., #41849).
92-
relate_args_invariantly(self, a_arg, b_arg)
91+
relate_args_invariantly(self, a_args, b_args)?;
92+
Ok(a_ty)
9393
} else {
94-
let tcx = self.cx();
95-
let opt_variances = tcx.variances_of(item_def_id);
96-
relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, false)
94+
let variances = self.cx().variances_of(def_id);
95+
combine_ty_args(self, a_ty, b_ty, variances, a_args, b_args, |_| a_ty)
9796
}
9897
}
9998

0 commit comments

Comments
 (0)