Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion compiler/rustc_borrowck/src/polonius/liveness_constraints.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::collections::BTreeMap;

use rustc_hir::def_id::DefId;
use rustc_index::bit_set::SparseBitMatrix;
use rustc_middle::mir::{Body, Location};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::relate::{
self, Relate, RelateResult, TypeRelation, relate_args_with_variances,
};
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
use rustc_mir_dataflow::points::PointIndex;

Expand Down Expand Up @@ -256,6 +259,20 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for VarianceExtractor<'_, 'tcx> {
self.tcx
}

fn relate_ty_args(
&mut self,
a_ty: Ty<'tcx>,
_: Ty<'tcx>,
def_id: DefId,
a_args: ty::GenericArgsRef<'tcx>,
b_args: ty::GenericArgsRef<'tcx>,
_: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
) -> RelateResult<'tcx, Ty<'tcx>> {
let variances = self.cx().variances_of(def_id);
relate_args_with_variances(self, variances, a_args, b_args)?;
Ok(a_ty)
}

fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
&mut self,
variance: ty::Variance,
Expand Down
35 changes: 33 additions & 2 deletions compiler/rustc_borrowck/src/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::relate::{
PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
};
Expand All @@ -9,7 +10,8 @@ use rustc_infer::traits::solve::Goal;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys};
use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys};
use rustc_middle::ty::relate::relate_args_invariantly;
use rustc_middle::ty::{self, FnMutDelegate, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::{bug, span_bug};
use rustc_span::{Span, Symbol, sym};
Expand Down Expand Up @@ -303,6 +305,35 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
self.type_checker.infcx.tcx
}

fn relate_ty_args(
&mut self,
a_ty: Ty<'tcx>,
b_ty: Ty<'tcx>,
def_id: DefId,
a_args: ty::GenericArgsRef<'tcx>,
b_args: ty::GenericArgsRef<'tcx>,
_: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
) -> RelateResult<'tcx, Ty<'tcx>> {
if self.ambient_variance == ty::Invariant {
// Avoid fetching the variance if we are in an invariant context,
// slightly improves perf.
relate_args_invariantly(self, a_args, b_args)?;
Ok(a_ty)
} else {
let variances = self.cx().variances_of(def_id);
combine_ty_args(
&self.type_checker.infcx.infcx,
self,
a_ty,
b_ty,
variances,
a_args,
b_args,
|_| a_ty,
)
}
}

#[instrument(skip(self, info), level = "trace", ret)]
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
&mut self,
Expand All @@ -328,7 +359,7 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
let infcx = self.type_checker.infcx;

let a = self.type_checker.infcx.shallow_resolve(a);
let a = infcx.shallow_resolve(a);
assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);

if a == b {
Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_infer/src/infer/outlives/test_type_match.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::collections::hash_map::Entry;

use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_type_ir::relate::relate_args_with_variances;
use tracing::instrument;

use crate::infer::region_constraints::VerifyIfEq;
Expand Down Expand Up @@ -137,6 +139,20 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx>
self.tcx
}

fn relate_ty_args(
&mut self,
a_ty: Ty<'tcx>,
_: Ty<'tcx>,
def_id: DefId,
a_args: ty::GenericArgsRef<'tcx>,
b_args: ty::GenericArgsRef<'tcx>,
_: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
) -> RelateResult<'tcx, Ty<'tcx>> {
let variances = self.cx().variances_of(def_id);
relate_args_with_variances(self, variances, a_args, b_args)?;
Ok(a_ty)
}

#[instrument(level = "trace", skip(self))]
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
&mut self,
Expand All @@ -145,6 +161,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx>
a: T,
b: T,
) -> RelateResult<'tcx, T> {
// FIXME(@lcnr): This is weird. We are ignoring the ambient variance
// here, effectively treating everything as being in either a covariant
// or contravariant context.
//
// Opaque types args have lifetime parameters.
// We must not check them to be equal, as we never insert anything to make them so.
if variance != ty::Bivariant { self.relate(a, b) } else { Ok(a) }
Expand Down
118 changes: 34 additions & 84 deletions compiler/rustc_infer/src/infer/relate/generalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,13 @@ impl<'tcx> InferCtxt<'tcx> {
//
// We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
// `?1 <: ?3`.
let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self
.generalize(
relation.span(),
relation.structurally_relate_aliases(),
target_vid,
instantiation_variance,
source_ty,
)?;
let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
relation.span(),
relation.structurally_relate_aliases(),
target_vid,
instantiation_variance,
source_ty,
)?;

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

// See the comment on `Generalization::has_unconstrained_ty_var`.
if has_unconstrained_ty_var {
relation.register_predicates([ty::ClauseKind::WellFormed(generalized_ty.into())]);
}

// Finally, relate `generalized_ty` to `source_ty`, as described in previous comment.
//
// FIXME(#16847): This code is non-ideal because all these subtype
Expand Down Expand Up @@ -210,19 +204,15 @@ impl<'tcx> InferCtxt<'tcx> {
) -> RelateResult<'tcx, ()> {
// FIXME(generic_const_exprs): Occurs check failures for unevaluated
// constants and generic expressions are not yet handled correctly.
let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = self
.generalize(
relation.span(),
relation.structurally_relate_aliases(),
target_vid,
ty::Invariant,
source_ct,
)?;
let Generalization { value_may_be_infer: generalized_ct } = self.generalize(
relation.span(),
relation.structurally_relate_aliases(),
target_vid,
ty::Invariant,
source_ct,
)?;

debug_assert!(!generalized_ct.is_ct_infer());
if has_unconstrained_ty_var {
bug!("unconstrained ty var when generalizing `{source_ct:?}`");
}

self.inner
.borrow_mut()
Expand Down Expand Up @@ -281,12 +271,10 @@ impl<'tcx> InferCtxt<'tcx> {
ambient_variance,
in_alias: false,
cache: Default::default(),
has_unconstrained_ty_var: false,
};

let value_may_be_infer = generalizer.relate(source_term, source_term)?;
let has_unconstrained_ty_var = generalizer.has_unconstrained_ty_var;
Ok(Generalization { value_may_be_infer, has_unconstrained_ty_var })
Ok(Generalization { value_may_be_infer })
}
}

Expand Down Expand Up @@ -376,9 +364,6 @@ struct Generalizer<'me, 'tcx> {
in_alias: bool,

cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>,

/// See the field `has_unconstrained_ty_var` in `Generalization`.
has_unconstrained_ty_var: bool,
}

impl<'tcx> Generalizer<'_, 'tcx> {
Expand All @@ -391,10 +376,8 @@ impl<'tcx> Generalizer<'_, 'tcx> {
}

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

Expand Down Expand Up @@ -461,29 +444,26 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
self.infcx.tcx
}

fn relate_item_args(
fn relate_ty_args(
&mut self,
item_def_id: DefId,
a_arg: ty::GenericArgsRef<'tcx>,
b_arg: ty::GenericArgsRef<'tcx>,
) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
if self.ambient_variance == ty::Invariant {
a_ty: Ty<'tcx>,
_: Ty<'tcx>,
def_id: DefId,
a_args: ty::GenericArgsRef<'tcx>,
b_args: ty::GenericArgsRef<'tcx>,
mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
) -> RelateResult<'tcx, Ty<'tcx>> {
let args = if self.ambient_variance == ty::Invariant {
// Avoid fetching the variance if we are in an invariant
// context; no need, and it can induce dependency cycles
// (e.g., #41849).
relate::relate_args_invariantly(self, a_arg, b_arg)
relate::relate_args_invariantly(self, a_args, b_args)
} else {
let tcx = self.cx();
let opt_variances = tcx.variances_of(item_def_id);
relate::relate_args_with_variances(
self,
item_def_id,
opt_variances,
a_arg,
b_arg,
false,
)
}
let variances = tcx.variances_of(def_id);
relate::relate_args_with_variances(self, variances, a_args, b_args)
}?;
if args == a_args { Ok(a_ty) } else { Ok(mk(args)) }
}

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

// Bivariant: make a fresh var, but remember that
// it is unconstrained. See the comment in
// `Generalization`.
ty::Bivariant => self.has_unconstrained_ty_var = true,

// Co/contravariant: this will be
// sufficiently constrained later on.
ty::Covariant | ty::Contravariant => (),
// We do need a fresh type variable otherwise.
ty::Bivariant | ty::Covariant | ty::Contravariant => (),
}

let origin = inner.type_variables().var_origin(vid);
Expand Down Expand Up @@ -771,32 +745,8 @@ struct Generalization<T> {
/// for `?0` generalization returns an inference
/// variable.
///
/// This has to be handled wotj care as it can
/// This has to be handled with care as it can
/// otherwise very easily result in infinite
/// recursion.
pub value_may_be_infer: T,

/// In general, we do not check whether all types which occur during
/// type checking are well-formed. We only check wf of user-provided types
/// and when actually using a type, e.g. for method calls.
///
/// This means that when subtyping, we may end up with unconstrained
/// inference variables if a generalized type has bivariant parameters.
/// A parameter may only be bivariant if it is constrained by a projection
/// bound in a where-clause. As an example, imagine a type:
///
/// struct Foo<A, B> where A: Iterator<Item = B> {
/// data: A
/// }
///
/// here, `A` will be covariant, but `B` is unconstrained.
///
/// However, whatever it is, for `Foo` to be WF, it must be equal to `A::Item`.
/// If we have an input `Foo<?A, ?B>`, then after generalization we will wind
/// up with a type like `Foo<?C, ?D>`. When we enforce `Foo<?A, ?B> <: Foo<?C, ?D>`,
/// we will wind up with the requirement that `?A <: ?C`, but no particular
/// relationship between `?B` and `?D` (after all, these types may be completely
/// different). If we do nothing else, this may mean that `?D` goes unconstrained
/// (as in #41677). To avoid this we emit a `WellFormed` obligation in these cases.
pub has_unconstrained_ty_var: bool,
}
16 changes: 15 additions & 1 deletion compiler/rustc_infer/src/infer/relate/lattice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
//!
//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
use rustc_hir::def_id::DefId;
use rustc_middle::traits::solve::Goal;
use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys};
use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
use rustc_span::Span;
Expand Down Expand Up @@ -75,6 +76,19 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
self.infcx.tcx
}

fn relate_ty_args(
&mut self,
a_ty: Ty<'tcx>,
b_ty: Ty<'tcx>,
def_id: DefId,
a_args: ty::GenericArgsRef<'tcx>,
b_args: ty::GenericArgsRef<'tcx>,
mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
) -> RelateResult<'tcx, Ty<'tcx>> {
let variances = self.cx().variances_of(def_id);
combine_ty_args(self.infcx, self, a_ty, b_ty, variances, a_args, b_args, |args| mk(args))
}

fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
&mut self,
variance: ty::Variance,
Expand Down
Loading
Loading