Auto merge of #121462 - compiler-errors:eq-and-sub, r=lcnr

Combine `Sub` and `Equate`

Combine `Sub` and `Equate` into a new relation called `TypeRelating` (that name sounds familiar...)

Tracks the difference between `Sub` and `Equate` via `ambient_variance: ty::Variance` much like the `NllTypeRelating` relation, but implemented slightly jankier because it's a more general purpose relation.

r? lcnr
This commit is contained in:
bors 2024-03-01 10:30:42 +00:00
commit b0696a5160
28 changed files with 510 additions and 841 deletions

View file

@ -1066,7 +1066,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
&cause,
param_env,
hidden_ty.ty,
true,
&mut obligations,
)?;

View file

@ -120,7 +120,6 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let infcx = self.type_checker.infcx;
debug_assert!(!infcx.next_trait_solver());
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
// `handle_opaque_type` cannot handle subtyping, so to support subtyping
// we instead eagerly generalize here. This is a bit of a mess but will go
// away once we're using the new solver.
@ -161,8 +160,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
),
};
let cause = ObligationCause::dummy_with_span(self.span());
let obligations =
infcx.handle_opaque_type(a, b, true, &cause, self.param_env())?.obligations;
let obligations = infcx.handle_opaque_type(a, b, &cause, self.param_env())?.obligations;
self.register_obligations(obligations);
Ok(())
}
@ -331,10 +329,6 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
"nll::subtype"
}
fn a_is_expected(&self) -> bool {
true
}
#[instrument(skip(self, info), level = "trace", ret)]
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
@ -349,12 +343,15 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
debug!(?self.ambient_variance);
// In a bivariant context this always succeeds.
let r =
if self.ambient_variance == ty::Variance::Bivariant { a } else { self.relate(a, b)? };
let r = if self.ambient_variance == ty::Variance::Bivariant {
Ok(a)
} else {
self.relate(a, b)
};
self.ambient_variance = old_ambient_variance;
Ok(r)
r
}
#[instrument(skip(self), level = "debug")]
@ -579,10 +576,6 @@ impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx
);
}
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance")
}
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(

View file

@ -1493,6 +1493,21 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
return;
}
let (expected, found) = if label_expression_as_expected {
// In the case where this is a "forced unit", like
// `break`, we want to call the `()` "expected"
// since it is implied by the syntax.
// (Note: not all force-units work this way.)"
(expression_ty, self.merged_ty())
} else {
// Otherwise, the "expected" type for error
// reporting is the current unification type,
// which is basically the LUB of the expressions
// we've seen so far (combined with the expected
// type)
(self.merged_ty(), expression_ty)
};
// Handle the actual type unification etc.
let result = if let Some(expression) = expression {
if self.pushed == 0 {
@ -1540,12 +1555,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
// Another example is `break` with no argument expression.
assert!(expression_ty.is_unit(), "if let hack without unit type");
fcx.at(cause, fcx.param_env)
// needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
.eq_exp(
.eq(
// needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
DefineOpaqueTypes::Yes,
label_expression_as_expected,
expression_ty,
self.merged_ty(),
expected,
found,
)
.map(|infer_ok| {
fcx.register_infer_ok_obligations(infer_ok);
@ -1579,20 +1593,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
fcx.set_tainted_by_errors(
fcx.dcx().span_delayed_bug(cause.span, "coercion error but no error emitted"),
);
let (expected, found) = if label_expression_as_expected {
// In the case where this is a "forced unit", like
// `break`, we want to call the `()` "expected"
// since it is implied by the syntax.
// (Note: not all force-units work this way.)"
(expression_ty, self.merged_ty())
} else {
// Otherwise, the "expected" type for error
// reporting is the current unification type,
// which is basically the LUB of the expressions
// we've seen so far (combined with the expected
// type)
(self.merged_ty(), expression_ty)
};
let (expected, found) = fcx.resolve_vars_if_possible((expected, found));
let mut err;

View file

@ -49,7 +49,6 @@ pub struct At<'a, 'tcx> {
pub struct Trace<'a, 'tcx> {
at: At<'a, 'tcx>,
a_is_expected: bool,
trace: TypeTrace<'tcx>,
}
@ -105,23 +104,6 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
}
impl<'a, 'tcx> At<'a, 'tcx> {
/// Makes `a <: b`, where `a` may or may not be expected.
///
/// See [`At::trace_exp`] and [`Trace::sub`] for a version of
/// this method that only requires `T: Relate<'tcx>`
pub fn sub_exp<T>(
self,
define_opaque_types: DefineOpaqueTypes,
a_is_expected: bool,
a: T,
b: T,
) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
self.trace_exp(a_is_expected, a, b).sub(define_opaque_types, a, b)
}
/// Makes `actual <: expected`. For example, if type-checking a
/// call like `foo(x)`, where `foo: fn(i32)`, you might have
/// `sup(i32, x)`, since the "expected" type is the type that
@ -138,7 +120,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
where
T: ToTrace<'tcx>,
{
self.sub_exp(define_opaque_types, false, actual, expected)
self.trace(expected, actual).sup(define_opaque_types, expected, actual)
}
/// Makes `expected <: actual`.
@ -154,24 +136,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
where
T: ToTrace<'tcx>,
{
self.sub_exp(define_opaque_types, true, expected, actual)
}
/// Makes `expected <: actual`.
///
/// See [`At::trace_exp`] and [`Trace::eq`] for a version of
/// this method that only requires `T: Relate<'tcx>`
pub fn eq_exp<T>(
self,
define_opaque_types: DefineOpaqueTypes,
a_is_expected: bool,
a: T,
b: T,
) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
self.trace_exp(a_is_expected, a, b).eq(define_opaque_types, a, b)
self.trace(expected, actual).sub(define_opaque_types, expected, actual)
}
/// Makes `expected <: actual`.
@ -260,48 +225,50 @@ impl<'a, 'tcx> At<'a, 'tcx> {
where
T: ToTrace<'tcx>,
{
self.trace_exp(true, expected, actual)
}
/// Like `trace`, but the expected value is determined by the
/// boolean argument (if true, then the first argument `a` is the
/// "expected" value).
pub fn trace_exp<T>(self, a_is_expected: bool, a: T, b: T) -> Trace<'a, 'tcx>
where
T: ToTrace<'tcx>,
{
let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
Trace { at: self, trace, a_is_expected }
let trace = ToTrace::to_trace(self.cause, true, expected, actual);
Trace { at: self, trace }
}
}
impl<'a, 'tcx> Trace<'a, 'tcx> {
/// Makes `a <: b` where `a` may or may not be expected (if
/// `a_is_expected` is true, then `a` is expected).
/// Makes `a <: b`.
#[instrument(skip(self), level = "debug")]
pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
let Trace { at, trace } = self;
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.sub(a_is_expected)
.sub()
.relate(a, b)
.map(move |_| InferOk { value: (), obligations: fields.obligations })
}
/// Makes `a == b`; the expectation is set by the call to
/// `trace()`.
/// Makes `a :> b`.
#[instrument(skip(self), level = "debug")]
pub fn sup<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
where
T: Relate<'tcx>,
{
let Trace { at, trace } = self;
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.sup()
.relate(a, b)
.map(move |_| InferOk { value: (), obligations: fields.obligations })
}
/// Makes `a == b`.
#[instrument(skip(self), level = "debug")]
pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
let Trace { at, trace } = self;
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.equate(StructurallyRelateAliases::No, a_is_expected)
.equate(StructurallyRelateAliases::No)
.relate(a, b)
.map(move |_| InferOk { value: (), obligations: fields.obligations })
}
@ -313,11 +280,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
let Trace { at, trace } = self;
debug_assert!(at.infcx.next_trait_solver());
let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::No);
fields
.equate(StructurallyRelateAliases::Yes, a_is_expected)
.equate(StructurallyRelateAliases::Yes)
.relate(a, b)
.map(move |_| InferOk { value: (), obligations: fields.obligations })
}
@ -327,10 +294,10 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
let Trace { at, trace } = self;
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.lub(a_is_expected)
.lub()
.relate(a, b)
.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
@ -340,10 +307,10 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
let Trace { at, trace } = self;
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.glb(a_is_expected)
.glb()
.relate(a, b)
.map(move |t| InferOk { value: t, obligations: fields.obligations })
}

View file

@ -2654,10 +2654,6 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
"SameTypeModuloInfer"
}
fn a_is_expected(&self) -> bool {
true
}
fn relate_with_variance<T: relate::Relate<'tcx>>(
&mut self,
_variance: ty::Variance,

View file

@ -836,7 +836,6 @@ impl<'tcx> InferCtxt<'tcx> {
CombineFields {
infcx: self,
trace,
cause: None,
param_env,
obligations: PredicateObligations::new(),
define_opaque_types,
@ -1033,7 +1032,11 @@ impl<'tcx> InferCtxt<'tcx> {
}
self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
if a_is_expected {
Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::No, a, b))
} else {
Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::No, b, a))
}
})
}

View file

@ -78,9 +78,7 @@ impl<'tcx> InferCtxt<'tcx> {
span,
});
obligations.extend(
self.handle_opaque_type(ty, ty_var, true, &cause, param_env)
.unwrap()
.obligations,
self.handle_opaque_type(ty, ty_var, &cause, param_env).unwrap().obligations,
);
ty_var
}
@ -94,15 +92,13 @@ impl<'tcx> InferCtxt<'tcx> {
&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
a_is_expected: bool,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> InferResult<'tcx, ()> {
if a.references_error() || b.references_error() {
return Ok(InferOk { value: (), obligations: vec![] });
}
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
let def_id = def_id.expect_local();
match self.defining_use_anchor {
@ -169,14 +165,13 @@ impl<'tcx> InferCtxt<'tcx> {
cause.clone(),
param_env,
b,
a_is_expected,
))
}
_ => None,
};
if let Some(res) = process(a, b, true) {
if let Some(res) = process(a, b) {
res
} else if let Some(res) = process(b, a, false) {
} else if let Some(res) = process(b, a) {
res
} else {
let (a, b) = self.resolve_vars_if_possible((a, b));
@ -520,18 +515,10 @@ impl<'tcx> InferCtxt<'tcx> {
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
a_is_expected: bool,
) -> InferResult<'tcx, ()> {
let mut obligations = Vec::new();
self.insert_hidden_type(
opaque_type_key,
&cause,
param_env,
hidden_ty,
a_is_expected,
&mut obligations,
)?;
self.insert_hidden_type(opaque_type_key, &cause, param_env, hidden_ty, &mut obligations)?;
self.add_item_bounds_for_hidden_type(
opaque_type_key.def_id.to_def_id(),
@ -558,7 +545,6 @@ impl<'tcx> InferCtxt<'tcx> {
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
a_is_expected: bool,
obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Result<(), TypeError<'tcx>> {
// Ideally, we'd get the span where *this specific `ty` came
@ -586,7 +572,7 @@ impl<'tcx> InferCtxt<'tcx> {
if let Some(prev) = prev {
obligations.extend(
self.at(cause, param_env)
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
.eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
.obligations,
);
}

View file

@ -144,10 +144,6 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
self.tcx
}
fn a_is_expected(&self) -> bool {
true
} // irrelevant
#[instrument(level = "trace", skip(self))]
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,

View file

@ -1,4 +1,6 @@
//! There are four type combiners: [Equate], [Sub], [Lub], and [Glb].
//! There are four type combiners: [TypeRelating], [Lub], and [Glb],
//! and `NllTypeRelating` in rustc_borrowck, which is only used for NLL.
//!
//! Each implements the trait [TypeRelation] and contains methods for
//! combining two instances of various things and yielding a new instance.
//! These combiner methods always yield a `Result<T>`. To relate two
@ -15,17 +17,10 @@
//!
//! On success, the LUB/GLB operations return the appropriate bound. The
//! return value of `Equate` or `Sub` shouldn't really be used.
//!
//! ## Contravariance
//!
//! We explicitly track which argument is expected using
//! [TypeRelation::a_is_expected], so when dealing with contravariance
//! this should be correctly updated.
use super::equate::Equate;
use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
use super::type_relating::TypeRelating;
use super::StructurallyRelateAliases;
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
use crate::traits::{Obligation, PredicateObligations};
@ -41,7 +36,6 @@ use rustc_span::Span;
pub struct CombineFields<'infcx, 'tcx> {
pub infcx: &'infcx InferCtxt<'tcx>,
pub trace: TypeTrace<'tcx>,
pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'tcx>,
pub obligations: PredicateObligations<'tcx>,
pub define_opaque_types: DefineOpaqueTypes,
@ -57,7 +51,6 @@ impl<'tcx> InferCtxt<'tcx> {
where
R: ObligationEmittingRelation<'tcx>,
{
let a_is_expected = relation.a_is_expected();
debug_assert!(!a.has_escaping_bound_vars());
debug_assert!(!b.has_escaping_bound_vars());
@ -68,20 +61,20 @@ impl<'tcx> InferCtxt<'tcx> {
.borrow_mut()
.int_unification_table()
.unify_var_var(a_id, b_id)
.map_err(|e| int_unification_error(a_is_expected, e))?;
.map_err(|e| int_unification_error(true, e))?;
Ok(a)
}
(&ty::Infer(ty::IntVar(v_id)), &ty::Int(v)) => {
self.unify_integral_variable(a_is_expected, v_id, IntType(v))
self.unify_integral_variable(true, v_id, IntType(v))
}
(&ty::Int(v), &ty::Infer(ty::IntVar(v_id))) => {
self.unify_integral_variable(!a_is_expected, v_id, IntType(v))
self.unify_integral_variable(false, v_id, IntType(v))
}
(&ty::Infer(ty::IntVar(v_id)), &ty::Uint(v)) => {
self.unify_integral_variable(a_is_expected, v_id, UintType(v))
self.unify_integral_variable(true, v_id, UintType(v))
}
(&ty::Uint(v), &ty::Infer(ty::IntVar(v_id))) => {
self.unify_integral_variable(!a_is_expected, v_id, UintType(v))
self.unify_integral_variable(false, v_id, UintType(v))
}
// Relate floating-point variables to other types
@ -90,14 +83,14 @@ impl<'tcx> InferCtxt<'tcx> {
.borrow_mut()
.float_unification_table()
.unify_var_var(a_id, b_id)
.map_err(|e| float_unification_error(a_is_expected, e))?;
.map_err(|e| float_unification_error(true, e))?;
Ok(a)
}
(&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
self.unify_float_variable(a_is_expected, v_id, v)
self.unify_float_variable(true, v_id, v)
}
(&ty::Float(v), &ty::Infer(ty::FloatVar(v_id))) => {
self.unify_float_variable(!a_is_expected, v_id, v)
self.unify_float_variable(false, v_id, v)
}
// We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
@ -130,7 +123,7 @@ impl<'tcx> InferCtxt<'tcx> {
// All other cases of inference are errors
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b)))
Err(TypeError::Sorts(ty::relate::expected_found(a, b)))
}
// During coherence, opaque types should be treated as *possibly*
@ -228,12 +221,12 @@ impl<'tcx> InferCtxt<'tcx> {
}
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
self.instantiate_const_var(relation, relation.a_is_expected(), vid, b)?;
self.instantiate_const_var(relation, true, vid, b)?;
Ok(b)
}
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
self.instantiate_const_var(relation, !relation.a_is_expected(), vid, a)?;
self.instantiate_const_var(relation, false, vid, a)?;
Ok(a)
}
@ -250,8 +243,6 @@ impl<'tcx> InferCtxt<'tcx> {
{
match relation.structurally_relate_aliases() {
StructurallyRelateAliases::No => {
let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) };
relation.register_predicates([if self.next_trait_solver() {
ty::PredicateKind::AliasRelate(
a.into(),
@ -321,21 +312,24 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
pub fn equate<'a>(
&'a mut self,
structurally_relate_aliases: StructurallyRelateAliases,
a_is_expected: bool,
) -> Equate<'a, 'infcx, 'tcx> {
Equate::new(self, structurally_relate_aliases, a_is_expected)
) -> TypeRelating<'a, 'infcx, 'tcx> {
TypeRelating::new(self, structurally_relate_aliases, ty::Invariant)
}
pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'tcx> {
Sub::new(self, a_is_expected)
pub fn sub<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> {
TypeRelating::new(self, StructurallyRelateAliases::No, ty::Covariant)
}
pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'tcx> {
Lub::new(self, a_is_expected)
pub fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> {
TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant)
}
pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'tcx> {
Glb::new(self, a_is_expected)
pub fn lub<'a>(&'a mut self) -> Lub<'a, 'infcx, 'tcx> {
Lub::new(self)
}
pub fn glb<'a>(&'a mut self) -> Glb<'a, 'infcx, 'tcx> {
Glb::new(self)
}
pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
@ -367,19 +361,8 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
/// be used if control over the obligation causes is required.
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>);
/// Register an obligation that both types must be related to each other according to
/// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
a.into(),
b.into(),
self.alias_relate_direction(),
))]);
}
/// Relation direction emitted for `AliasRelate` predicates, corresponding to the direction
/// of the relation.
fn alias_relate_direction(&self) -> ty::AliasRelationDirection;
/// Register `AliasRelate` obligation(s) that both types must be related to each other.
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
}
fn int_unification_error<'tcx>(

View file

@ -1,228 +0,0 @@
use super::combine::{CombineFields, ObligationEmittingRelation};
use super::StructurallyRelateAliases;
use crate::infer::BoundRegionConversionTime::HigherRankedType;
use crate::infer::{DefineOpaqueTypes, SubregionOrigin};
use crate::traits::PredicateObligations;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::TyVar;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
use rustc_span::Span;
/// Ensures `a` is made equal to `b`. Returns `a` on success.
pub struct Equate<'combine, 'infcx, 'tcx> {
fields: &'combine mut CombineFields<'infcx, 'tcx>,
structurally_relate_aliases: StructurallyRelateAliases,
a_is_expected: bool,
}
impl<'combine, 'infcx, 'tcx> Equate<'combine, 'infcx, 'tcx> {
pub fn new(
fields: &'combine mut CombineFields<'infcx, 'tcx>,
structurally_relate_aliases: StructurallyRelateAliases,
a_is_expected: bool,
) -> Equate<'combine, 'infcx, 'tcx> {
Equate { fields, structurally_relate_aliases, a_is_expected }
}
}
impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
fn tag(&self) -> &'static str {
"Equate"
}
fn tcx(&self) -> TyCtxt<'tcx> {
self.fields.tcx()
}
fn a_is_expected(&self) -> bool {
self.a_is_expected
}
fn relate_item_args(
&mut self,
_item_def_id: DefId,
a_arg: GenericArgsRef<'tcx>,
b_arg: GenericArgsRef<'tcx>,
) -> RelateResult<'tcx, GenericArgsRef<'tcx>> {
// N.B., once we are equating types, we don't care about
// variance, so don't try to lookup the variance here. This
// also avoids some cycles (e.g., #41849) since looking up
// variance requires computing types which can require
// performing trait matching (which then performs equality
// unification).
relate::relate_args_invariantly(self, a_arg, b_arg)
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
_info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
self.relate(a, b)
}
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
if a == b {
return Ok(a);
}
trace!(a = ?a.kind(), b = ?b.kind());
let infcx = self.fields.infcx;
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
match (a.kind(), b.kind()) {
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
}
(&ty::Infer(TyVar(a_vid)), _) => {
infcx.instantiate_ty_var(self, self.a_is_expected, a_vid, ty::Invariant, b)?;
}
(_, &ty::Infer(TyVar(b_vid))) => {
infcx.instantiate_ty_var(self, !self.a_is_expected, b_vid, ty::Invariant, a)?;
}
(&ty::Error(e), _) | (_, &ty::Error(e)) => {
infcx.set_tainted_by_errors(e);
return Ok(Ty::new_error(self.tcx(), e));
}
(
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
) if a_def_id == b_def_id => {
infcx.super_combine_tys(self, a, b)?;
}
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
&& def_id.is_local()
&& !self.fields.infcx.next_trait_solver() =>
{
self.fields.obligations.extend(
infcx
.handle_opaque_type(
a,
b,
self.a_is_expected(),
&self.fields.trace.cause,
self.param_env(),
)?
.obligations,
);
}
_ => {
infcx.super_combine_tys(self, a, b)?;
}
}
Ok(a)
}
fn regions(
&mut self,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
self.fields
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.make_eqregion(origin, a, b);
Ok(a)
}
fn consts(
&mut self,
a: ty::Const<'tcx>,
b: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
self.fields.infcx.super_combine_consts(self, a, b)
}
fn binders<T>(
&mut self,
a: ty::Binder<'tcx, T>,
b: ty::Binder<'tcx, T>,
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
where
T: Relate<'tcx>,
{
// A binder is equal to itself if it's structurally equal to itself
if a == b {
return Ok(a);
}
if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
// Fast path for the common case.
self.relate(a, b)?;
} else {
// When equating binders, we check that there is a 1-to-1
// correspondence between the bound vars in both types.
//
// We do so by separately instantiating one of the binders with
// placeholders and the other with inference variables and then
// equating the instantiated types.
//
// We want `for<..> A == for<..> B` -- therefore we want
// `exists<..> A == for<..> B` and `exists<..> B == for<..> A`.
let span = self.fields.trace.cause.span;
let infcx = self.fields.infcx;
// Check if `exists<..> A == for<..> B`
infcx.enter_forall(b, |b| {
let a = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, a);
self.relate(a, b)
})?;
// Check if `exists<..> B == for<..> A`.
infcx.enter_forall(a, |a| {
let b = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, b);
self.relate(a, b)
})?;
}
Ok(a)
}
}
impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
fn span(&self) -> Span {
self.fields.trace.span()
}
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
self.structurally_relate_aliases
}
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.fields.param_env
}
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
self.fields.register_predicates(obligations);
}
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations);
}
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
ty::AliasRelationDirection::Equate
}
}

View file

@ -130,7 +130,7 @@ impl<'tcx> InferCtxt<'tcx> {
// instantiate_ty_var(?b, A) # expected and variance flipped
// A rel A'
// ```
if target_is_expected == relation.a_is_expected() {
if target_is_expected {
relation.relate(generalized_ty, source_ty)?;
} else {
debug!("flip relation");
@ -204,9 +204,9 @@ impl<'tcx> InferCtxt<'tcx> {
.const_unification_table()
.union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
// HACK: make sure that we `a_is_expected` continues to be
// correct when relating the generalized type with the source.
if target_is_expected == relation.a_is_expected() {
// Make sure that the order is correct when relating the
// generalized const and the source.
if target_is_expected {
relation.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
@ -398,10 +398,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
"Generalizer"
}
fn a_is_expected(&self) -> bool {
true
}
fn relate_item_args(
&mut self,
item_def_id: DefId,
@ -440,9 +436,9 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
debug!(?self.ambient_variance, "new ambient variance");
// Recursive calls to `relate` can overflow the stack. For example a deeper version of
// `ui/associated-consts/issue-93775.rs`.
let r = ensure_sufficient_stack(|| self.relate(a, b))?;
let r = ensure_sufficient_stack(|| self.relate(a, b));
self.ambient_variance = old_ambient_variance;
Ok(r)
r
}
#[instrument(level = "debug", skip(self, t2), ret)]

View file

@ -13,15 +13,11 @@ use crate::traits::{ObligationCause, PredicateObligations};
/// "Greatest lower bound" (common subtype)
pub struct Glb<'combine, 'infcx, 'tcx> {
fields: &'combine mut CombineFields<'infcx, 'tcx>,
a_is_expected: bool,
}
impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> {
pub fn new(
fields: &'combine mut CombineFields<'infcx, 'tcx>,
a_is_expected: bool,
) -> Glb<'combine, 'infcx, 'tcx> {
Glb { fields, a_is_expected }
pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Glb<'combine, 'infcx, 'tcx> {
Glb { fields }
}
}
@ -34,10 +30,6 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
self.fields.tcx()
}
fn a_is_expected(&self) -> bool {
self.a_is_expected
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
@ -46,13 +38,11 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
b: T,
) -> RelateResult<'tcx, T> {
match variance {
ty::Invariant => {
self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b)
}
ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
ty::Covariant => self.relate(a, b),
// FIXME(#41044) -- not correct, need test
ty::Bivariant => Ok(a),
ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b),
ty::Contravariant => self.fields.lub().relate(a, b),
}
}
@ -126,7 +116,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
}
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let mut sub = self.fields.sub(self.a_is_expected);
let mut sub = self.fields.sub();
sub.relate(v, a)?;
sub.relate(v, b)?;
Ok(())
@ -158,8 +148,12 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
self.fields.register_obligations(obligations);
}
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
// FIXME(deferred_projection_equality): This isn't right, I think?
ty::AliasRelationDirection::Equate
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
a.into(),
b.into(),
// FIXME(deferred_projection_equality): This isn't right, I think?
ty::AliasRelationDirection::Equate,
))]);
}
}

View file

@ -1,64 +1,11 @@
//! Helper routines for higher-ranked things. See the `doc` module at
//! the end of the file for details.
use super::combine::CombineFields;
use crate::infer::CombinedSnapshot;
use crate::infer::{HigherRankedType, InferCtxt};
use crate::infer::InferCtxt;
use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable};
impl<'a, 'tcx> CombineFields<'a, 'tcx> {
/// Checks whether `for<..> sub <: for<..> sup` holds.
///
/// For this to hold, **all** instantiations of the super type
/// have to be a super type of **at least one** instantiation of
/// the subtype.
///
/// This is implemented by first entering a new universe.
/// We then replace all bound variables in `sup` with placeholders,
/// and all bound variables in `sub` with inference vars.
/// We can then just relate the two resulting types as normal.
///
/// Note: this is a subtle algorithm. For a full explanation, please see
/// the [rustc dev guide][rd]
///
/// [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html
#[instrument(skip(self), level = "debug")]
pub fn higher_ranked_sub<T>(
&mut self,
sub: Binder<'tcx, T>,
sup: Binder<'tcx, T>,
sub_is_expected: bool,
) -> RelateResult<'tcx, ()>
where
T: Relate<'tcx>,
{
let span = self.trace.cause.span;
// First, we instantiate each bound region in the supertype with a
// fresh placeholder region. Note that this automatically creates
// a new universe if needed.
self.infcx.enter_forall(sup, |sup_prime| {
// Next, we instantiate each bound region in the subtype
// with a fresh region variable. These region variables --
// but no other preexisting region variables -- can name
// the placeholders.
let sub_prime =
self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub);
debug!("a_prime={:?}", sub_prime);
debug!("b_prime={:?}", sup_prime);
// Compare types now that bound regions have been replaced.
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime);
if result.is_ok() {
debug!("OK result={result:?}");
}
// NOTE: returning the result here would be dangerous as it contains
// placeholders which **must not** be named afterwards.
result.map(|_| ())
})
}
}
use rustc_middle::ty::relate::RelateResult;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
impl<'tcx> InferCtxt<'tcx> {
/// Replaces all bound variables (lifetimes, types, and constants) bound by

View file

@ -116,9 +116,7 @@ where
&& !this.infcx().next_trait_solver() =>
{
this.register_obligations(
infcx
.handle_opaque_type(a, b, this.a_is_expected(), this.cause(), this.param_env())?
.obligations,
infcx.handle_opaque_type(a, b, this.cause(), this.param_env())?.obligations,
);
Ok(a)
}

View file

@ -13,15 +13,11 @@ use rustc_span::Span;
/// "Least upper bound" (common supertype)
pub struct Lub<'combine, 'infcx, 'tcx> {
fields: &'combine mut CombineFields<'infcx, 'tcx>,
a_is_expected: bool,
}
impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> {
pub fn new(
fields: &'combine mut CombineFields<'infcx, 'tcx>,
a_is_expected: bool,
) -> Lub<'combine, 'infcx, 'tcx> {
Lub { fields, a_is_expected }
pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Lub<'combine, 'infcx, 'tcx> {
Lub { fields }
}
}
@ -34,10 +30,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
self.fields.tcx()
}
fn a_is_expected(&self) -> bool {
self.a_is_expected
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
@ -46,13 +38,11 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
b: T,
) -> RelateResult<'tcx, T> {
match variance {
ty::Invariant => {
self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b)
}
ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
ty::Covariant => self.relate(a, b),
// FIXME(#41044) -- not correct, need test
ty::Bivariant => Ok(a),
ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b),
ty::Contravariant => self.fields.glb().relate(a, b),
}
}
@ -126,7 +116,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
}
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let mut sub = self.fields.sub(self.a_is_expected);
let mut sub = self.fields.sub();
sub.relate(a, v)?;
sub.relate(b, v)?;
Ok(())
@ -158,8 +148,12 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
self.fields.register_obligations(obligations)
}
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
// FIXME(deferred_projection_equality): This isn't right, I think?
ty::AliasRelationDirection::Equate
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
a.into(),
b.into(),
// FIXME(deferred_projection_equality): This isn't right, I think?
ty::AliasRelationDirection::Equate,
))]);
}
}

View file

@ -2,13 +2,12 @@
//! (except for some relations used for diagnostics and heuristics in the compiler).
pub(super) mod combine;
mod equate;
mod generalize;
mod glb;
mod higher_ranked;
mod lattice;
mod lub;
mod sub;
mod type_relating;
/// Whether aliases should be related structurally or not. Used
/// to adjust the behavior of generalization and combine.

View file

@ -1,229 +0,0 @@
use super::combine::CombineFields;
use super::StructurallyRelateAliases;
use crate::infer::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin};
use crate::traits::{Obligation, PredicateObligations};
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::TyVar;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
use std::mem;
/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
pub struct Sub<'combine, 'a, 'tcx> {
fields: &'combine mut CombineFields<'a, 'tcx>,
a_is_expected: bool,
}
impl<'combine, 'infcx, 'tcx> Sub<'combine, 'infcx, 'tcx> {
pub fn new(
f: &'combine mut CombineFields<'infcx, 'tcx>,
a_is_expected: bool,
) -> Sub<'combine, 'infcx, 'tcx> {
Sub { fields: f, a_is_expected }
}
fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
self.a_is_expected = !self.a_is_expected;
let result = f(self);
self.a_is_expected = !self.a_is_expected;
result
}
}
impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
fn tag(&self) -> &'static str {
"Sub"
}
fn tcx(&self) -> TyCtxt<'tcx> {
self.fields.infcx.tcx
}
fn a_is_expected(&self) -> bool {
self.a_is_expected
}
fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
debug!("sub with_cause={:?}", cause);
let old_cause = mem::replace(&mut self.fields.cause, Some(cause));
let r = f(self);
debug!("sub old_cause={:?}", old_cause);
self.fields.cause = old_cause;
r
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
_info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
match variance {
ty::Invariant => {
self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b)
}
ty::Covariant => self.relate(a, b),
ty::Bivariant => Ok(a),
ty::Contravariant => self.with_expected_switched(|this| this.relate(b, a)),
}
}
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
if a == b {
return Ok(a);
}
let infcx = self.fields.infcx;
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
match (a.kind(), b.kind()) {
(&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
// Shouldn't have any LBR here, so we can safely put
// this under a binder below without fear of accidental
// capture.
assert!(!a.has_escaping_bound_vars());
assert!(!b.has_escaping_bound_vars());
// can't make progress on `A <: B` if both A and B are
// type variables, so record an obligation.
self.fields.obligations.push(Obligation::new(
self.tcx(),
self.fields.trace.cause.clone(),
self.fields.param_env,
ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
a_is_expected: self.a_is_expected,
a,
b,
})),
));
Ok(a)
}
(&ty::Infer(TyVar(a_vid)), _) => {
infcx.instantiate_ty_var(self, self.a_is_expected, a_vid, ty::Covariant, b)?;
Ok(a)
}
(_, &ty::Infer(TyVar(b_vid))) => {
infcx.instantiate_ty_var(self, !self.a_is_expected, b_vid, ty::Contravariant, a)?;
Ok(a)
}
(&ty::Error(e), _) | (_, &ty::Error(e)) => {
infcx.set_tainted_by_errors(e);
Ok(Ty::new_error(self.tcx(), e))
}
(
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
) if a_def_id == b_def_id => {
self.fields.infcx.super_combine_tys(self, a, b)?;
Ok(a)
}
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
&& def_id.is_local()
&& !self.fields.infcx.next_trait_solver() =>
{
self.fields.obligations.extend(
infcx
.handle_opaque_type(
a,
b,
self.a_is_expected,
&self.fields.trace.cause,
self.param_env(),
)?
.obligations,
);
Ok(a)
}
_ => {
self.fields.infcx.super_combine_tys(self, a, b)?;
Ok(a)
}
}
}
fn regions(
&mut self,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("{}.regions({:?}, {:?}) self.cause={:?}", self.tag(), a, b, self.fields.cause);
// FIXME -- we have more fine-grained information available
// from the "cause" field, we could perhaps give more tailored
// error messages.
let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
// Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
self.fields
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.make_subregion(origin, b, a);
Ok(a)
}
fn consts(
&mut self,
a: ty::Const<'tcx>,
b: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
self.fields.infcx.super_combine_consts(self, a, b)
}
fn binders<T>(
&mut self,
a: ty::Binder<'tcx, T>,
b: ty::Binder<'tcx, T>,
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
where
T: Relate<'tcx>,
{
// A binder is always a subtype of itself if it's structurally equal to itself
if a == b {
return Ok(a);
}
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
Ok(a)
}
}
impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
fn span(&self) -> Span {
self.fields.trace.span()
}
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
StructurallyRelateAliases::No
}
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.fields.param_env
}
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
self.fields.register_predicates(obligations);
}
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations);
}
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
ty::AliasRelationDirection::Subtype
}
}

View file

@ -0,0 +1,326 @@
use super::combine::CombineFields;
use crate::infer::BoundRegionConversionTime::HigherRankedType;
use crate::infer::{
DefineOpaqueTypes, ObligationEmittingRelation, StructurallyRelateAliases, SubregionOrigin,
};
use crate::traits::{Obligation, PredicateObligations};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::TyVar;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
/// Enforce that `a` is equal to or a subtype of `b`.
pub struct TypeRelating<'combine, 'a, 'tcx> {
fields: &'combine mut CombineFields<'a, 'tcx>,
structurally_relate_aliases: StructurallyRelateAliases,
ambient_variance: ty::Variance,
}
impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> {
pub fn new(
f: &'combine mut CombineFields<'infcx, 'tcx>,
structurally_relate_aliases: StructurallyRelateAliases,
ambient_variance: ty::Variance,
) -> TypeRelating<'combine, 'infcx, 'tcx> {
TypeRelating { fields: f, structurally_relate_aliases, ambient_variance }
}
}
impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
fn tag(&self) -> &'static str {
"TypeRelating"
}
fn tcx(&self) -> TyCtxt<'tcx> {
self.fields.infcx.tcx
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
_info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
let old_ambient_variance = self.ambient_variance;
self.ambient_variance = self.ambient_variance.xform(variance);
debug!(?self.ambient_variance, "new ambient variance");
let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) };
self.ambient_variance = old_ambient_variance;
r
}
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
if a == b {
return Ok(a);
}
let infcx = self.fields.infcx;
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
match (a.kind(), b.kind()) {
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
match self.ambient_variance {
ty::Covariant => {
// can't make progress on `A <: B` if both A and B are
// type variables, so record an obligation.
self.fields.obligations.push(Obligation::new(
self.tcx(),
self.fields.trace.cause.clone(),
self.fields.param_env,
ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
a_is_expected: true,
a,
b,
})),
));
}
ty::Contravariant => {
// can't make progress on `B <: A` if both A and B are
// type variables, so record an obligation.
self.fields.obligations.push(Obligation::new(
self.tcx(),
self.fields.trace.cause.clone(),
self.fields.param_env,
ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
a_is_expected: false,
a: b,
b: a,
})),
));
}
ty::Invariant => {
infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
}
ty::Bivariant => {
unreachable!("Expected bivariance to be handled in relate_with_variance")
}
}
}
(&ty::Infer(TyVar(a_vid)), _) => {
infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?;
}
(_, &ty::Infer(TyVar(b_vid))) => {
infcx.instantiate_ty_var(
self,
false,
b_vid,
self.ambient_variance.xform(ty::Contravariant),
a,
)?;
}
(&ty::Error(e), _) | (_, &ty::Error(e)) => {
infcx.set_tainted_by_errors(e);
return Ok(Ty::new_error(self.tcx(), e));
}
(
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
) if a_def_id == b_def_id => {
infcx.super_combine_tys(self, a, b)?;
}
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
&& def_id.is_local()
&& !infcx.next_trait_solver() =>
{
self.fields.obligations.extend(
infcx
.handle_opaque_type(a, b, &self.fields.trace.cause, self.param_env())?
.obligations,
);
}
_ => {
infcx.super_combine_tys(self, a, b)?;
}
}
Ok(a)
}
fn regions(
&mut self,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
match self.ambient_variance {
// Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
ty::Covariant => {
self.fields
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.make_subregion(origin, b, a);
}
// Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b)
ty::Contravariant => {
self.fields
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.make_subregion(origin, a, b);
}
ty::Invariant => {
self.fields
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.make_eqregion(origin, a, b);
}
ty::Bivariant => {
unreachable!("Expected bivariance to be handled in relate_with_variance")
}
}
Ok(a)
}
fn consts(
&mut self,
a: ty::Const<'tcx>,
b: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
self.fields.infcx.super_combine_consts(self, a, b)
}
fn binders<T>(
&mut self,
a: ty::Binder<'tcx, T>,
b: ty::Binder<'tcx, T>,
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
where
T: Relate<'tcx>,
{
if a == b {
// Do nothing
} else if let Some(a) = a.no_bound_vars()
&& let Some(b) = b.no_bound_vars()
{
self.relate(a, b)?;
} else {
let span = self.fields.trace.cause.span;
let infcx = self.fields.infcx;
match self.ambient_variance {
// Checks whether `for<..> sub <: for<..> sup` holds.
//
// For this to hold, **all** instantiations of the super type
// have to be a super type of **at least one** instantiation of
// the subtype.
//
// This is implemented by first entering a new universe.
// We then replace all bound variables in `sup` with placeholders,
// and all bound variables in `sub` with inference vars.
// We can then just relate the two resulting types as normal.
//
// Note: this is a subtle algorithm. For a full explanation, please see
// the [rustc dev guide][rd]
//
// [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html
ty::Covariant => {
infcx.enter_forall(b, |b| {
let a = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, a);
self.relate(a, b)
})?;
}
ty::Contravariant => {
infcx.enter_forall(a, |a| {
let b = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, b);
self.relate(a, b)
})?;
}
// When **equating** binders, we check that there is a 1-to-1
// correspondence between the bound vars in both types.
//
// We do so by separately instantiating one of the binders with
// placeholders and the other with inference variables and then
// equating the instantiated types.
//
// We want `for<..> A == for<..> B` -- therefore we want
// `exists<..> A == for<..> B` and `exists<..> B == for<..> A`.
// Check if `exists<..> A == for<..> B`
ty::Invariant => {
infcx.enter_forall(b, |b| {
let a = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, a);
self.relate(a, b)
})?;
// Check if `exists<..> B == for<..> A`.
infcx.enter_forall(a, |a| {
let b = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, b);
self.relate(a, b)
})?;
}
ty::Bivariant => {
unreachable!("Expected bivariance to be handled in relate_with_variance")
}
}
}
Ok(a)
}
}
impl<'tcx> ObligationEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
fn span(&self) -> Span {
self.fields.trace.span()
}
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.fields.param_env
}
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
self.structurally_relate_aliases
}
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
self.fields.register_predicates(obligations);
}
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations);
}
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
a.into(),
b.into(),
ty::AliasRelationDirection::Subtype,
),
// a :> b is b <: a
ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
b.into(),
a.into(),
ty::AliasRelationDirection::Subtype,
),
ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
a.into(),
b.into(),
ty::AliasRelationDirection::Equate,
),
ty::Variance::Bivariant => {
unreachable!("Expected bivariance to be handled in relate_with_variance")
}
})]);
}
}

View file

@ -37,10 +37,6 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
self.tcx
}
fn a_is_expected(&self) -> bool {
true
} // irrelevant
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
@ -75,7 +71,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
) => Ok(a),
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
Err(TypeError::Sorts(relate::expected_found(self, a, b)))
Err(TypeError::Sorts(relate::expected_found(a, b)))
}
(&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)),
@ -100,7 +96,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
}
(ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
return Err(TypeError::ConstMismatch(relate::expected_found(self, a, b)));
return Err(TypeError::ConstMismatch(relate::expected_found(a, b)));
}
_ => {}

View file

@ -15,28 +15,12 @@ use std::iter;
pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
#[derive(Clone, Debug)]
pub enum Cause {
ExistentialRegionBound, // relating an existential region bound
}
pub trait TypeRelation<'tcx>: Sized {
fn tcx(&self) -> TyCtxt<'tcx>;
/// Returns a static string we can use for printouts.
fn tag(&self) -> &'static str;
/// Returns `true` if the value `a` is the "expected" type in the
/// relation. Just affects error messages.
fn a_is_expected(&self) -> bool;
fn with_cause<F, R>(&mut self, _cause: Cause, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
f(self)
}
/// Generic relation routine suitable for most anything.
fn relate<T: Relate<'tcx>>(&mut self, a: T, b: T) -> RelateResult<'tcx, T> {
Relate::relate(self, a, b)
@ -178,11 +162,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
let tcx = relation.tcx();
if a.c_variadic != b.c_variadic {
return Err(TypeError::VariadicMismatch(expected_found(
relation,
a.c_variadic,
b.c_variadic,
)));
return Err(TypeError::VariadicMismatch(expected_found(a.c_variadic, b.c_variadic)));
}
let unsafety = relation.relate(a.unsafety, b.unsafety)?;
let abi = relation.relate(a.abi, b.abi)?;
@ -227,39 +207,31 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
impl<'tcx> Relate<'tcx> for ty::BoundConstness {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
_relation: &mut R,
a: ty::BoundConstness,
b: ty::BoundConstness,
) -> RelateResult<'tcx, ty::BoundConstness> {
if a != b {
Err(TypeError::ConstnessMismatch(expected_found(relation, a, b)))
} else {
Ok(a)
}
if a != b { Err(TypeError::ConstnessMismatch(expected_found(a, b))) } else { Ok(a) }
}
}
impl<'tcx> Relate<'tcx> for hir::Unsafety {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
_relation: &mut R,
a: hir::Unsafety,
b: hir::Unsafety,
) -> RelateResult<'tcx, hir::Unsafety> {
if a != b {
Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b)))
} else {
Ok(a)
}
if a != b { Err(TypeError::UnsafetyMismatch(expected_found(a, b))) } else { Ok(a) }
}
}
impl<'tcx> Relate<'tcx> for abi::Abi {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
_relation: &mut R,
a: abi::Abi,
b: abi::Abi,
) -> RelateResult<'tcx, abi::Abi> {
if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(relation, a, b))) }
if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(a, b))) }
}
}
@ -270,7 +242,7 @@ impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> {
b: ty::AliasTy<'tcx>,
) -> RelateResult<'tcx, ty::AliasTy<'tcx>> {
if a.def_id != b.def_id {
Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id)))
Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id)))
} else {
let args = match relation.tcx().def_kind(a.def_id) {
DefKind::OpaqueTy => relate_args_with_variances(
@ -298,7 +270,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
b: ty::ExistentialProjection<'tcx>,
) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> {
if a.def_id != b.def_id {
Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id)))
Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id)))
} else {
let term = relation.relate_with_variance(
ty::Invariant,
@ -325,7 +297,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
) -> RelateResult<'tcx, ty::TraitRef<'tcx>> {
// Different traits cannot be related.
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
Err(TypeError::Traits(expected_found(a.def_id, b.def_id)))
} else {
let args = relate_args_invariantly(relation, a.args, b.args)?;
Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args))
@ -341,7 +313,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> {
// Different traits cannot be related.
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
Err(TypeError::Traits(expected_found(a.def_id, b.def_id)))
} else {
let args = relate_args_invariantly(relation, a.args, b.args)?;
Ok(ty::ExistentialTraitRef { def_id: a.def_id, args })
@ -452,10 +424,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
(&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr))
if a_repr == b_repr =>
{
let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
relation.relate(a_region, b_region)
})?;
Ok(Ty::new_dynamic(tcx, relation.relate(a_obj, b_obj)?, region_bound, a_repr))
Ok(Ty::new_dynamic(
tcx,
relation.relate(a_obj, b_obj)?,
relation.relate(a_region, b_region)?,
a_repr,
))
}
(&ty::Coroutine(a_id, a_args), &ty::Coroutine(b_id, b_args)) if a_id == b_id => {
@ -515,9 +489,9 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
let sz_b = sz_b.try_to_target_usize(tcx);
match (sz_a, sz_b) {
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err(
TypeError::FixedArraySize(expected_found(relation, sz_a_val, sz_b_val)),
),
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => {
Err(TypeError::FixedArraySize(expected_found(sz_a_val, sz_b_val)))
}
_ => Err(err),
}
}
@ -536,9 +510,9 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)),
)?)
} else if !(as_.is_empty() || bs.is_empty()) {
Err(TypeError::TupleSize(expected_found(relation, as_.len(), bs.len())))
Err(TypeError::TupleSize(expected_found(as_.len(), bs.len())))
} else {
Err(TypeError::Sorts(expected_found(relation, a, b)))
Err(TypeError::Sorts(expected_found(a, b)))
}
}
@ -559,7 +533,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
Ok(Ty::new_alias(tcx, a_kind, alias_ty))
}
_ => Err(TypeError::Sorts(expected_found(relation, a, b))),
_ => Err(TypeError::Sorts(expected_found(a, b))),
}
}
@ -657,13 +631,13 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
let related_args = tcx.mk_const_list(&related_args);
Expr::FunctionCall(func, related_args)
}
_ => return Err(TypeError::ConstMismatch(expected_found(r, a, b))),
_ => return Err(TypeError::ConstMismatch(expected_found(a, b))),
};
return Ok(ty::Const::new_expr(tcx, expr, a.ty()));
}
_ => false,
};
if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) }
if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(a, b))) }
}
impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
@ -685,7 +659,7 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
b_v.dedup();
if a_v.len() != b_v.len() {
return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)));
return Err(TypeError::ExistentialMismatch(expected_found(a, b)));
}
let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
@ -697,7 +671,7 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
))),
(AutoTrait(a), AutoTrait(b)) if a == b => Ok(ep_a.rebind(AutoTrait(a))),
_ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))),
_ => Err(TypeError::ExistentialMismatch(expected_found(a, b))),
}
});
tcx.mk_poly_existential_predicates_from_iter(v)
@ -797,15 +771,11 @@ impl<'tcx> Relate<'tcx> for GenericArg<'tcx> {
impl<'tcx> Relate<'tcx> for ty::ImplPolarity {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
_relation: &mut R,
a: ty::ImplPolarity,
b: ty::ImplPolarity,
) -> RelateResult<'tcx, ty::ImplPolarity> {
if a != b {
Err(TypeError::PolarityMismatch(expected_found(relation, a, b)))
} else {
Ok(a)
}
if a != b { Err(TypeError::PolarityMismatch(expected_found(a, b))) } else { Ok(a) }
}
}
@ -839,9 +809,6 @@ impl<'tcx> Relate<'tcx> for Term<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Error handling
pub fn expected_found<'tcx, R, T>(relation: &mut R, a: T, b: T) -> ExpectedFound<T>
where
R: TypeRelation<'tcx>,
{
ExpectedFound::new(relation.a_is_expected(), a, b)
pub fn expected_found<T>(a: T, b: T) -> ExpectedFound<T> {
ExpectedFound::new(true, a, b)
}

View file

@ -904,7 +904,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
&ObligationCause::dummy(),
param_env,
hidden_ty,
true,
&mut obligations,
)?;
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));

View file

@ -116,24 +116,6 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut())
}
/// Makes `expected <: actual`.
pub fn eq_exp<T>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a_is_expected: bool,
a: T,
b: T,
) -> Result<(), TypeError<'tcx>>
where
T: ToTrace<'tcx>,
{
self.infcx
.at(cause, param_env)
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, a, b)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
pub fn eq<T: ToTrace<'tcx>>(
&self,
cause: &ObligationCause<'tcx>,

View file

@ -1528,6 +1528,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::Coercion { .. }
);
let (expected, actual) = if is_normalized_term_expected {
(normalized_term, data.term)
} else {
(data.term, normalized_term)
};
// constrain inference variables a bit more to nested obligations from normalize so
// we can have more helpful errors.
//
@ -1535,13 +1541,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// since the normalization is just done to improve the error message.
let _ = ocx.select_where_possible();
if let Err(new_err) = ocx.eq_exp(
&obligation.cause,
obligation.param_env,
is_normalized_term_expected,
normalized_term,
data.term,
) {
if let Err(new_err) =
ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
{
(Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
} else {
(None, error.err)

View file

@ -13,8 +13,8 @@ fn main() {
}
fn weird0() -> impl Sized + !Sized {}
//~^ ERROR type mismatch resolving `() == impl !Sized + Sized`
//~^ ERROR type mismatch resolving `impl !Sized + Sized == ()`
fn weird1() -> impl !Sized + Sized {}
//~^ ERROR type mismatch resolving `() == impl !Sized + Sized`
//~^ ERROR type mismatch resolving `impl !Sized + Sized == ()`
fn weird2() -> impl !Sized {}
//~^ ERROR type mismatch resolving `() == impl !Sized`
//~^ ERROR type mismatch resolving `impl !Sized == ()`

View file

@ -1,16 +1,16 @@
error[E0271]: type mismatch resolving `() == impl !Sized + Sized`
error[E0271]: type mismatch resolving `impl !Sized + Sized == ()`
--> $DIR/opaque-type-unsatisfied-bound.rs:15:16
|
LL | fn weird0() -> impl Sized + !Sized {}
| ^^^^^^^^^^^^^^^^^^^ types differ
error[E0271]: type mismatch resolving `() == impl !Sized + Sized`
error[E0271]: type mismatch resolving `impl !Sized + Sized == ()`
--> $DIR/opaque-type-unsatisfied-bound.rs:17:16
|
LL | fn weird1() -> impl !Sized + Sized {}
| ^^^^^^^^^^^^^^^^^^^ types differ
error[E0271]: type mismatch resolving `() == impl !Sized`
error[E0271]: type mismatch resolving `impl !Sized == ()`
--> $DIR/opaque-type-unsatisfied-bound.rs:19:16
|
LL | fn weird2() -> impl !Sized {}

View file

@ -3,6 +3,6 @@
#![feature(negative_bounds, unboxed_closures)]
fn produce() -> impl !Fn<(u32,)> {}
//~^ ERROR type mismatch resolving `() == impl !Fn<(u32,)>`
//~^ ERROR type mismatch resolving `impl !Fn<(u32,)> == ()`
fn main() {}

View file

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `() == impl !Fn<(u32,)>`
error[E0271]: type mismatch resolving `impl !Fn<(u32,)> == ()`
--> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17
|
LL | fn produce() -> impl !Fn<(u32,)> {}

View file

@ -8,6 +8,9 @@ LL | let _: i32 = closure();
| --- ^^^^^^^^^ expected `i32`, found opaque type
| |
| expected due to this
|
= note: expected type `i32`
found opaque type `<() as Foo>::Assoc`
error[E0308]: mismatched types
--> $DIR/itiat-allow-nested-closures.rs:22:9