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:
commit
b0696a5160
28 changed files with 510 additions and 841 deletions
|
@ -1066,7 +1066,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
&cause,
|
&cause,
|
||||||
param_env,
|
param_env,
|
||||||
hidden_ty.ty,
|
hidden_ty.ty,
|
||||||
true,
|
|
||||||
&mut obligations,
|
&mut obligations,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
|
@ -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, ()> {
|
fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||||
let infcx = self.type_checker.infcx;
|
let infcx = self.type_checker.infcx;
|
||||||
debug_assert!(!infcx.next_trait_solver());
|
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
|
// `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
|
// we instead eagerly generalize here. This is a bit of a mess but will go
|
||||||
// away once we're using the new solver.
|
// 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 cause = ObligationCause::dummy_with_span(self.span());
|
||||||
let obligations =
|
let obligations = infcx.handle_opaque_type(a, b, &cause, self.param_env())?.obligations;
|
||||||
infcx.handle_opaque_type(a, b, true, &cause, self.param_env())?.obligations;
|
|
||||||
self.register_obligations(obligations);
|
self.register_obligations(obligations);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -331,10 +329,6 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||||
"nll::subtype"
|
"nll::subtype"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn a_is_expected(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(self, info), level = "trace", ret)]
|
#[instrument(skip(self, info), level = "trace", ret)]
|
||||||
fn relate_with_variance<T: Relate<'tcx>>(
|
fn relate_with_variance<T: Relate<'tcx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -349,12 +343,15 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||||
|
|
||||||
debug!(?self.ambient_variance);
|
debug!(?self.ambient_variance);
|
||||||
// In a bivariant context this always succeeds.
|
// In a bivariant context this always succeeds.
|
||||||
let r =
|
let r = if self.ambient_variance == ty::Variance::Bivariant {
|
||||||
if self.ambient_variance == ty::Variance::Bivariant { a } else { self.relate(a, b)? };
|
Ok(a)
|
||||||
|
} else {
|
||||||
|
self.relate(a, b)
|
||||||
|
};
|
||||||
|
|
||||||
self.ambient_variance = old_ambient_variance;
|
self.ambient_variance = old_ambient_variance;
|
||||||
|
|
||||||
Ok(r)
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[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>) {
|
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||||
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
|
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
|
||||||
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
|
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
|
||||||
|
|
|
@ -1493,6 +1493,21 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||||
return;
|
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.
|
// Handle the actual type unification etc.
|
||||||
let result = if let Some(expression) = expression {
|
let result = if let Some(expression) = expression {
|
||||||
if self.pushed == 0 {
|
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.
|
// Another example is `break` with no argument expression.
|
||||||
assert!(expression_ty.is_unit(), "if let hack without unit type");
|
assert!(expression_ty.is_unit(), "if let hack without unit type");
|
||||||
fcx.at(cause, fcx.param_env)
|
fcx.at(cause, fcx.param_env)
|
||||||
|
.eq(
|
||||||
// needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
|
// needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
|
||||||
.eq_exp(
|
|
||||||
DefineOpaqueTypes::Yes,
|
DefineOpaqueTypes::Yes,
|
||||||
label_expression_as_expected,
|
expected,
|
||||||
expression_ty,
|
found,
|
||||||
self.merged_ty(),
|
|
||||||
)
|
)
|
||||||
.map(|infer_ok| {
|
.map(|infer_ok| {
|
||||||
fcx.register_infer_ok_obligations(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.set_tainted_by_errors(
|
||||||
fcx.dcx().span_delayed_bug(cause.span, "coercion error but no error emitted"),
|
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 (expected, found) = fcx.resolve_vars_if_possible((expected, found));
|
||||||
|
|
||||||
let mut err;
|
let mut err;
|
||||||
|
|
|
@ -49,7 +49,6 @@ pub struct At<'a, 'tcx> {
|
||||||
|
|
||||||
pub struct Trace<'a, 'tcx> {
|
pub struct Trace<'a, 'tcx> {
|
||||||
at: At<'a, 'tcx>,
|
at: At<'a, 'tcx>,
|
||||||
a_is_expected: bool,
|
|
||||||
trace: TypeTrace<'tcx>,
|
trace: TypeTrace<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,23 +104,6 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> At<'a, 'tcx> {
|
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
|
/// Makes `actual <: expected`. For example, if type-checking a
|
||||||
/// call like `foo(x)`, where `foo: fn(i32)`, you might have
|
/// call like `foo(x)`, where `foo: fn(i32)`, you might have
|
||||||
/// `sup(i32, x)`, since the "expected" type is the type that
|
/// `sup(i32, x)`, since the "expected" type is the type that
|
||||||
|
@ -138,7 +120,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||||
where
|
where
|
||||||
T: ToTrace<'tcx>,
|
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`.
|
/// Makes `expected <: actual`.
|
||||||
|
@ -154,24 +136,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||||
where
|
where
|
||||||
T: ToTrace<'tcx>,
|
T: ToTrace<'tcx>,
|
||||||
{
|
{
|
||||||
self.sub_exp(define_opaque_types, true, expected, actual)
|
self.trace(expected, actual).sub(define_opaque_types, 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes `expected <: actual`.
|
/// Makes `expected <: actual`.
|
||||||
|
@ -260,48 +225,50 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||||
where
|
where
|
||||||
T: ToTrace<'tcx>,
|
T: ToTrace<'tcx>,
|
||||||
{
|
{
|
||||||
self.trace_exp(true, expected, actual)
|
let trace = ToTrace::to_trace(self.cause, true, expected, actual);
|
||||||
}
|
Trace { at: self, trace }
|
||||||
|
|
||||||
/// 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 }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Trace<'a, 'tcx> {
|
impl<'a, 'tcx> Trace<'a, 'tcx> {
|
||||||
/// Makes `a <: b` where `a` may or may not be expected (if
|
/// Makes `a <: b`.
|
||||||
/// `a_is_expected` is true, then `a` is expected).
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
||||||
where
|
where
|
||||||
T: Relate<'tcx>,
|
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);
|
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||||
fields
|
fields
|
||||||
.sub(a_is_expected)
|
.sub()
|
||||||
.relate(a, b)
|
.relate(a, b)
|
||||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes `a == b`; the expectation is set by the call to
|
/// Makes `a :> b`.
|
||||||
/// `trace()`.
|
#[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")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
||||||
where
|
where
|
||||||
T: Relate<'tcx>,
|
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);
|
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||||
fields
|
fields
|
||||||
.equate(StructurallyRelateAliases::No, a_is_expected)
|
.equate(StructurallyRelateAliases::No)
|
||||||
.relate(a, b)
|
.relate(a, b)
|
||||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||||
}
|
}
|
||||||
|
@ -313,11 +280,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
||||||
where
|
where
|
||||||
T: Relate<'tcx>,
|
T: Relate<'tcx>,
|
||||||
{
|
{
|
||||||
let Trace { at, trace, a_is_expected } = self;
|
let Trace { at, trace } = self;
|
||||||
debug_assert!(at.infcx.next_trait_solver());
|
debug_assert!(at.infcx.next_trait_solver());
|
||||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::No);
|
let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::No);
|
||||||
fields
|
fields
|
||||||
.equate(StructurallyRelateAliases::Yes, a_is_expected)
|
.equate(StructurallyRelateAliases::Yes)
|
||||||
.relate(a, b)
|
.relate(a, b)
|
||||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||||
}
|
}
|
||||||
|
@ -327,10 +294,10 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
||||||
where
|
where
|
||||||
T: Relate<'tcx>,
|
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);
|
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||||
fields
|
fields
|
||||||
.lub(a_is_expected)
|
.lub()
|
||||||
.relate(a, b)
|
.relate(a, b)
|
||||||
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||||
}
|
}
|
||||||
|
@ -340,10 +307,10 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
||||||
where
|
where
|
||||||
T: Relate<'tcx>,
|
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);
|
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||||
fields
|
fields
|
||||||
.glb(a_is_expected)
|
.glb()
|
||||||
.relate(a, b)
|
.relate(a, b)
|
||||||
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||||
}
|
}
|
||||||
|
|
|
@ -2654,10 +2654,6 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
|
||||||
"SameTypeModuloInfer"
|
"SameTypeModuloInfer"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn a_is_expected(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn relate_with_variance<T: relate::Relate<'tcx>>(
|
fn relate_with_variance<T: relate::Relate<'tcx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_variance: ty::Variance,
|
_variance: ty::Variance,
|
||||||
|
|
|
@ -836,7 +836,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
CombineFields {
|
CombineFields {
|
||||||
infcx: self,
|
infcx: self,
|
||||||
trace,
|
trace,
|
||||||
cause: None,
|
|
||||||
param_env,
|
param_env,
|
||||||
obligations: PredicateObligations::new(),
|
obligations: PredicateObligations::new(),
|
||||||
define_opaque_types,
|
define_opaque_types,
|
||||||
|
@ -1033,7 +1032,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
|
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))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,9 +78,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
span,
|
span,
|
||||||
});
|
});
|
||||||
obligations.extend(
|
obligations.extend(
|
||||||
self.handle_opaque_type(ty, ty_var, true, &cause, param_env)
|
self.handle_opaque_type(ty, ty_var, &cause, param_env).unwrap().obligations,
|
||||||
.unwrap()
|
|
||||||
.obligations,
|
|
||||||
);
|
);
|
||||||
ty_var
|
ty_var
|
||||||
}
|
}
|
||||||
|
@ -94,15 +92,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
&self,
|
&self,
|
||||||
a: Ty<'tcx>,
|
a: Ty<'tcx>,
|
||||||
b: Ty<'tcx>,
|
b: Ty<'tcx>,
|
||||||
a_is_expected: bool,
|
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> InferResult<'tcx, ()> {
|
) -> InferResult<'tcx, ()> {
|
||||||
if a.references_error() || b.references_error() {
|
if a.references_error() || b.references_error() {
|
||||||
return Ok(InferOk { value: (), obligations: vec![] });
|
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>| match *a.kind() {
|
||||||
let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
|
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
|
||||||
let def_id = def_id.expect_local();
|
let def_id = def_id.expect_local();
|
||||||
match self.defining_use_anchor {
|
match self.defining_use_anchor {
|
||||||
|
@ -169,14 +165,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
cause.clone(),
|
cause.clone(),
|
||||||
param_env,
|
param_env,
|
||||||
b,
|
b,
|
||||||
a_is_expected,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(res) = process(a, b, true) {
|
if let Some(res) = process(a, b) {
|
||||||
res
|
res
|
||||||
} else if let Some(res) = process(b, a, false) {
|
} else if let Some(res) = process(b, a) {
|
||||||
res
|
res
|
||||||
} else {
|
} else {
|
||||||
let (a, b) = self.resolve_vars_if_possible((a, b));
|
let (a, b) = self.resolve_vars_if_possible((a, b));
|
||||||
|
@ -520,18 +515,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
cause: ObligationCause<'tcx>,
|
cause: ObligationCause<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
hidden_ty: Ty<'tcx>,
|
hidden_ty: Ty<'tcx>,
|
||||||
a_is_expected: bool,
|
|
||||||
) -> InferResult<'tcx, ()> {
|
) -> InferResult<'tcx, ()> {
|
||||||
let mut obligations = Vec::new();
|
let mut obligations = Vec::new();
|
||||||
|
|
||||||
self.insert_hidden_type(
|
self.insert_hidden_type(opaque_type_key, &cause, param_env, hidden_ty, &mut obligations)?;
|
||||||
opaque_type_key,
|
|
||||||
&cause,
|
|
||||||
param_env,
|
|
||||||
hidden_ty,
|
|
||||||
a_is_expected,
|
|
||||||
&mut obligations,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
self.add_item_bounds_for_hidden_type(
|
self.add_item_bounds_for_hidden_type(
|
||||||
opaque_type_key.def_id.to_def_id(),
|
opaque_type_key.def_id.to_def_id(),
|
||||||
|
@ -558,7 +545,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
hidden_ty: Ty<'tcx>,
|
hidden_ty: Ty<'tcx>,
|
||||||
a_is_expected: bool,
|
|
||||||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||||
) -> Result<(), TypeError<'tcx>> {
|
) -> Result<(), TypeError<'tcx>> {
|
||||||
// Ideally, we'd get the span where *this specific `ty` came
|
// Ideally, we'd get the span where *this specific `ty` came
|
||||||
|
@ -586,7 +572,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
if let Some(prev) = prev {
|
if let Some(prev) = prev {
|
||||||
obligations.extend(
|
obligations.extend(
|
||||||
self.at(cause, param_env)
|
self.at(cause, param_env)
|
||||||
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
|
.eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
|
||||||
.obligations,
|
.obligations,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,10 +144,6 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
|
||||||
self.tcx
|
self.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn a_is_expected(&self) -> bool {
|
|
||||||
true
|
|
||||||
} // irrelevant
|
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self))]
|
#[instrument(level = "trace", skip(self))]
|
||||||
fn relate_with_variance<T: Relate<'tcx>>(
|
fn relate_with_variance<T: Relate<'tcx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -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
|
//! Each implements the trait [TypeRelation] and contains methods for
|
||||||
//! combining two instances of various things and yielding a new instance.
|
//! combining two instances of various things and yielding a new instance.
|
||||||
//! These combiner methods always yield a `Result<T>`. To relate two
|
//! 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
|
//! On success, the LUB/GLB operations return the appropriate bound. The
|
||||||
//! return value of `Equate` or `Sub` shouldn't really be used.
|
//! 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::glb::Glb;
|
||||||
use super::lub::Lub;
|
use super::lub::Lub;
|
||||||
use super::sub::Sub;
|
use super::type_relating::TypeRelating;
|
||||||
use super::StructurallyRelateAliases;
|
use super::StructurallyRelateAliases;
|
||||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
|
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
|
||||||
use crate::traits::{Obligation, PredicateObligations};
|
use crate::traits::{Obligation, PredicateObligations};
|
||||||
|
@ -41,7 +36,6 @@ use rustc_span::Span;
|
||||||
pub struct CombineFields<'infcx, 'tcx> {
|
pub struct CombineFields<'infcx, 'tcx> {
|
||||||
pub infcx: &'infcx InferCtxt<'tcx>,
|
pub infcx: &'infcx InferCtxt<'tcx>,
|
||||||
pub trace: TypeTrace<'tcx>,
|
pub trace: TypeTrace<'tcx>,
|
||||||
pub cause: Option<ty::relate::Cause>,
|
|
||||||
pub param_env: ty::ParamEnv<'tcx>,
|
pub param_env: ty::ParamEnv<'tcx>,
|
||||||
pub obligations: PredicateObligations<'tcx>,
|
pub obligations: PredicateObligations<'tcx>,
|
||||||
pub define_opaque_types: DefineOpaqueTypes,
|
pub define_opaque_types: DefineOpaqueTypes,
|
||||||
|
@ -57,7 +51,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
where
|
where
|
||||||
R: ObligationEmittingRelation<'tcx>,
|
R: ObligationEmittingRelation<'tcx>,
|
||||||
{
|
{
|
||||||
let a_is_expected = relation.a_is_expected();
|
|
||||||
debug_assert!(!a.has_escaping_bound_vars());
|
debug_assert!(!a.has_escaping_bound_vars());
|
||||||
debug_assert!(!b.has_escaping_bound_vars());
|
debug_assert!(!b.has_escaping_bound_vars());
|
||||||
|
|
||||||
|
@ -68,20 +61,20 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.int_unification_table()
|
.int_unification_table()
|
||||||
.unify_var_var(a_id, b_id)
|
.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)
|
Ok(a)
|
||||||
}
|
}
|
||||||
(&ty::Infer(ty::IntVar(v_id)), &ty::Int(v)) => {
|
(&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))) => {
|
(&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)) => {
|
(&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))) => {
|
(&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
|
// Relate floating-point variables to other types
|
||||||
|
@ -90,14 +83,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.float_unification_table()
|
.float_unification_table()
|
||||||
.unify_var_var(a_id, b_id)
|
.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)
|
Ok(a)
|
||||||
}
|
}
|
||||||
(&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
|
(&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))) => {
|
(&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.
|
// 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
|
// All other cases of inference are errors
|
||||||
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
|
(&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*
|
// During coherence, opaque types should be treated as *possibly*
|
||||||
|
@ -228,12 +221,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
|
(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)
|
Ok(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
(_, 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)
|
Ok(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,8 +243,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
{
|
{
|
||||||
match relation.structurally_relate_aliases() {
|
match relation.structurally_relate_aliases() {
|
||||||
StructurallyRelateAliases::No => {
|
StructurallyRelateAliases::No => {
|
||||||
let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) };
|
|
||||||
|
|
||||||
relation.register_predicates([if self.next_trait_solver() {
|
relation.register_predicates([if self.next_trait_solver() {
|
||||||
ty::PredicateKind::AliasRelate(
|
ty::PredicateKind::AliasRelate(
|
||||||
a.into(),
|
a.into(),
|
||||||
|
@ -321,21 +312,24 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||||
pub fn equate<'a>(
|
pub fn equate<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
structurally_relate_aliases: StructurallyRelateAliases,
|
structurally_relate_aliases: StructurallyRelateAliases,
|
||||||
a_is_expected: bool,
|
) -> TypeRelating<'a, 'infcx, 'tcx> {
|
||||||
) -> Equate<'a, 'infcx, 'tcx> {
|
TypeRelating::new(self, structurally_relate_aliases, ty::Invariant)
|
||||||
Equate::new(self, structurally_relate_aliases, a_is_expected)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'tcx> {
|
pub fn sub<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> {
|
||||||
Sub::new(self, a_is_expected)
|
TypeRelating::new(self, StructurallyRelateAliases::No, ty::Covariant)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'tcx> {
|
pub fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> {
|
||||||
Lub::new(self, a_is_expected)
|
TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'tcx> {
|
pub fn lub<'a>(&'a mut self) -> Lub<'a, 'infcx, 'tcx> {
|
||||||
Glb::new(self, a_is_expected)
|
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>) {
|
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.
|
/// be used if control over the obligation causes is required.
|
||||||
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>);
|
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
|
/// Register `AliasRelate` obligation(s) that both types must be related to each other.
|
||||||
/// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
|
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn int_unification_error<'tcx>(
|
fn int_unification_error<'tcx>(
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -130,7 +130,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
// instantiate_ty_var(?b, A) # expected and variance flipped
|
// instantiate_ty_var(?b, A) # expected and variance flipped
|
||||||
// A rel A'
|
// A rel A'
|
||||||
// ```
|
// ```
|
||||||
if target_is_expected == relation.a_is_expected() {
|
if target_is_expected {
|
||||||
relation.relate(generalized_ty, source_ty)?;
|
relation.relate(generalized_ty, source_ty)?;
|
||||||
} else {
|
} else {
|
||||||
debug!("flip relation");
|
debug!("flip relation");
|
||||||
|
@ -204,9 +204,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
.const_unification_table()
|
.const_unification_table()
|
||||||
.union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
|
.union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
|
||||||
|
|
||||||
// HACK: make sure that we `a_is_expected` continues to be
|
// Make sure that the order is correct when relating the
|
||||||
// correct when relating the generalized type with the source.
|
// generalized const and the source.
|
||||||
if target_is_expected == relation.a_is_expected() {
|
if target_is_expected {
|
||||||
relation.relate_with_variance(
|
relation.relate_with_variance(
|
||||||
ty::Variance::Invariant,
|
ty::Variance::Invariant,
|
||||||
ty::VarianceDiagInfo::default(),
|
ty::VarianceDiagInfo::default(),
|
||||||
|
@ -398,10 +398,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
||||||
"Generalizer"
|
"Generalizer"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn a_is_expected(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn relate_item_args(
|
fn relate_item_args(
|
||||||
&mut self,
|
&mut self,
|
||||||
item_def_id: DefId,
|
item_def_id: DefId,
|
||||||
|
@ -440,9 +436,9 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
||||||
debug!(?self.ambient_variance, "new ambient variance");
|
debug!(?self.ambient_variance, "new ambient variance");
|
||||||
// Recursive calls to `relate` can overflow the stack. For example a deeper version of
|
// Recursive calls to `relate` can overflow the stack. For example a deeper version of
|
||||||
// `ui/associated-consts/issue-93775.rs`.
|
// `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;
|
self.ambient_variance = old_ambient_variance;
|
||||||
Ok(r)
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, t2), ret)]
|
#[instrument(level = "debug", skip(self, t2), ret)]
|
||||||
|
|
|
@ -13,15 +13,11 @@ use crate::traits::{ObligationCause, PredicateObligations};
|
||||||
/// "Greatest lower bound" (common subtype)
|
/// "Greatest lower bound" (common subtype)
|
||||||
pub struct Glb<'combine, 'infcx, 'tcx> {
|
pub struct Glb<'combine, 'infcx, 'tcx> {
|
||||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
||||||
a_is_expected: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> {
|
impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> {
|
||||||
pub fn new(
|
pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Glb<'combine, 'infcx, 'tcx> {
|
||||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
Glb { fields }
|
||||||
a_is_expected: bool,
|
|
||||||
) -> Glb<'combine, 'infcx, 'tcx> {
|
|
||||||
Glb { fields, a_is_expected }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,10 +30,6 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||||
self.fields.tcx()
|
self.fields.tcx()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn a_is_expected(&self) -> bool {
|
|
||||||
self.a_is_expected
|
|
||||||
}
|
|
||||||
|
|
||||||
fn relate_with_variance<T: Relate<'tcx>>(
|
fn relate_with_variance<T: Relate<'tcx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
variance: ty::Variance,
|
variance: ty::Variance,
|
||||||
|
@ -46,13 +38,11 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||||
b: T,
|
b: T,
|
||||||
) -> RelateResult<'tcx, T> {
|
) -> RelateResult<'tcx, T> {
|
||||||
match variance {
|
match variance {
|
||||||
ty::Invariant => {
|
ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
|
||||||
self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b)
|
|
||||||
}
|
|
||||||
ty::Covariant => self.relate(a, b),
|
ty::Covariant => self.relate(a, b),
|
||||||
// FIXME(#41044) -- not correct, need test
|
// FIXME(#41044) -- not correct, need test
|
||||||
ty::Bivariant => Ok(a),
|
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, ()> {
|
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, a)?;
|
||||||
sub.relate(v, b)?;
|
sub.relate(v, b)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -158,8 +148,12 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||||
self.fields.register_obligations(obligations);
|
self.fields.register_obligations(obligations);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
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?
|
// FIXME(deferred_projection_equality): This isn't right, I think?
|
||||||
ty::AliasRelationDirection::Equate
|
ty::AliasRelationDirection::Equate,
|
||||||
|
))]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +1,11 @@
|
||||||
//! Helper routines for higher-ranked things. See the `doc` module at
|
//! Helper routines for higher-ranked things. See the `doc` module at
|
||||||
//! the end of the file for details.
|
//! the end of the file for details.
|
||||||
|
|
||||||
use super::combine::CombineFields;
|
|
||||||
use crate::infer::CombinedSnapshot;
|
use crate::infer::CombinedSnapshot;
|
||||||
use crate::infer::{HigherRankedType, InferCtxt};
|
use crate::infer::InferCtxt;
|
||||||
use rustc_middle::ty::fold::FnMutDelegate;
|
use rustc_middle::ty::fold::FnMutDelegate;
|
||||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
use rustc_middle::ty::relate::RelateResult;
|
||||||
use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, 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(|_| ())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> InferCtxt<'tcx> {
|
impl<'tcx> InferCtxt<'tcx> {
|
||||||
/// Replaces all bound variables (lifetimes, types, and constants) bound by
|
/// Replaces all bound variables (lifetimes, types, and constants) bound by
|
||||||
|
|
|
@ -116,9 +116,7 @@ where
|
||||||
&& !this.infcx().next_trait_solver() =>
|
&& !this.infcx().next_trait_solver() =>
|
||||||
{
|
{
|
||||||
this.register_obligations(
|
this.register_obligations(
|
||||||
infcx
|
infcx.handle_opaque_type(a, b, this.cause(), this.param_env())?.obligations,
|
||||||
.handle_opaque_type(a, b, this.a_is_expected(), this.cause(), this.param_env())?
|
|
||||||
.obligations,
|
|
||||||
);
|
);
|
||||||
Ok(a)
|
Ok(a)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,15 +13,11 @@ use rustc_span::Span;
|
||||||
/// "Least upper bound" (common supertype)
|
/// "Least upper bound" (common supertype)
|
||||||
pub struct Lub<'combine, 'infcx, 'tcx> {
|
pub struct Lub<'combine, 'infcx, 'tcx> {
|
||||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
||||||
a_is_expected: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> {
|
impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> {
|
||||||
pub fn new(
|
pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Lub<'combine, 'infcx, 'tcx> {
|
||||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
Lub { fields }
|
||||||
a_is_expected: bool,
|
|
||||||
) -> Lub<'combine, 'infcx, 'tcx> {
|
|
||||||
Lub { fields, a_is_expected }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,10 +30,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||||
self.fields.tcx()
|
self.fields.tcx()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn a_is_expected(&self) -> bool {
|
|
||||||
self.a_is_expected
|
|
||||||
}
|
|
||||||
|
|
||||||
fn relate_with_variance<T: Relate<'tcx>>(
|
fn relate_with_variance<T: Relate<'tcx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
variance: ty::Variance,
|
variance: ty::Variance,
|
||||||
|
@ -46,13 +38,11 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||||
b: T,
|
b: T,
|
||||||
) -> RelateResult<'tcx, T> {
|
) -> RelateResult<'tcx, T> {
|
||||||
match variance {
|
match variance {
|
||||||
ty::Invariant => {
|
ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
|
||||||
self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b)
|
|
||||||
}
|
|
||||||
ty::Covariant => self.relate(a, b),
|
ty::Covariant => self.relate(a, b),
|
||||||
// FIXME(#41044) -- not correct, need test
|
// FIXME(#41044) -- not correct, need test
|
||||||
ty::Bivariant => Ok(a),
|
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, ()> {
|
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(a, v)?;
|
||||||
sub.relate(b, v)?;
|
sub.relate(b, v)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -158,8 +148,12 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||||
self.fields.register_obligations(obligations)
|
self.fields.register_obligations(obligations)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
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?
|
// FIXME(deferred_projection_equality): This isn't right, I think?
|
||||||
ty::AliasRelationDirection::Equate
|
ty::AliasRelationDirection::Equate,
|
||||||
|
))]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
//! (except for some relations used for diagnostics and heuristics in the compiler).
|
//! (except for some relations used for diagnostics and heuristics in the compiler).
|
||||||
|
|
||||||
pub(super) mod combine;
|
pub(super) mod combine;
|
||||||
mod equate;
|
|
||||||
mod generalize;
|
mod generalize;
|
||||||
mod glb;
|
mod glb;
|
||||||
mod higher_ranked;
|
mod higher_ranked;
|
||||||
mod lattice;
|
mod lattice;
|
||||||
mod lub;
|
mod lub;
|
||||||
mod sub;
|
mod type_relating;
|
||||||
|
|
||||||
/// Whether aliases should be related structurally or not. Used
|
/// Whether aliases should be related structurally or not. Used
|
||||||
/// to adjust the behavior of generalization and combine.
|
/// to adjust the behavior of generalization and combine.
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
326
compiler/rustc_infer/src/infer/relate/type_relating.rs
Normal file
326
compiler/rustc_infer/src/infer/relate/type_relating.rs
Normal 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")
|
||||||
|
}
|
||||||
|
})]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,10 +37,6 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
|
||||||
self.tcx
|
self.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn a_is_expected(&self) -> bool {
|
|
||||||
true
|
|
||||||
} // irrelevant
|
|
||||||
|
|
||||||
fn relate_with_variance<T: Relate<'tcx>>(
|
fn relate_with_variance<T: Relate<'tcx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: ty::Variance,
|
_: ty::Variance,
|
||||||
|
@ -75,7 +71,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
|
||||||
) => Ok(a),
|
) => Ok(a),
|
||||||
|
|
||||||
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
|
(&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)),
|
(&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(_)) => {
|
(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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -15,28 +15,12 @@ use std::iter;
|
||||||
|
|
||||||
pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
|
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 {
|
pub trait TypeRelation<'tcx>: Sized {
|
||||||
fn tcx(&self) -> TyCtxt<'tcx>;
|
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||||
|
|
||||||
/// Returns a static string we can use for printouts.
|
/// Returns a static string we can use for printouts.
|
||||||
fn tag(&self) -> &'static str;
|
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.
|
/// Generic relation routine suitable for most anything.
|
||||||
fn relate<T: Relate<'tcx>>(&mut self, a: T, b: T) -> RelateResult<'tcx, T> {
|
fn relate<T: Relate<'tcx>>(&mut self, a: T, b: T) -> RelateResult<'tcx, T> {
|
||||||
Relate::relate(self, a, b)
|
Relate::relate(self, a, b)
|
||||||
|
@ -178,11 +162,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
|
||||||
let tcx = relation.tcx();
|
let tcx = relation.tcx();
|
||||||
|
|
||||||
if a.c_variadic != b.c_variadic {
|
if a.c_variadic != b.c_variadic {
|
||||||
return Err(TypeError::VariadicMismatch(expected_found(
|
return Err(TypeError::VariadicMismatch(expected_found(a.c_variadic, b.c_variadic)));
|
||||||
relation,
|
|
||||||
a.c_variadic,
|
|
||||||
b.c_variadic,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
let unsafety = relation.relate(a.unsafety, b.unsafety)?;
|
let unsafety = relation.relate(a.unsafety, b.unsafety)?;
|
||||||
let abi = relation.relate(a.abi, b.abi)?;
|
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 {
|
impl<'tcx> Relate<'tcx> for ty::BoundConstness {
|
||||||
fn relate<R: TypeRelation<'tcx>>(
|
fn relate<R: TypeRelation<'tcx>>(
|
||||||
relation: &mut R,
|
_relation: &mut R,
|
||||||
a: ty::BoundConstness,
|
a: ty::BoundConstness,
|
||||||
b: ty::BoundConstness,
|
b: ty::BoundConstness,
|
||||||
) -> RelateResult<'tcx, ty::BoundConstness> {
|
) -> RelateResult<'tcx, ty::BoundConstness> {
|
||||||
if a != b {
|
if a != b { Err(TypeError::ConstnessMismatch(expected_found(a, b))) } else { Ok(a) }
|
||||||
Err(TypeError::ConstnessMismatch(expected_found(relation, a, b)))
|
|
||||||
} else {
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Relate<'tcx> for hir::Unsafety {
|
impl<'tcx> Relate<'tcx> for hir::Unsafety {
|
||||||
fn relate<R: TypeRelation<'tcx>>(
|
fn relate<R: TypeRelation<'tcx>>(
|
||||||
relation: &mut R,
|
_relation: &mut R,
|
||||||
a: hir::Unsafety,
|
a: hir::Unsafety,
|
||||||
b: hir::Unsafety,
|
b: hir::Unsafety,
|
||||||
) -> RelateResult<'tcx, hir::Unsafety> {
|
) -> RelateResult<'tcx, hir::Unsafety> {
|
||||||
if a != b {
|
if a != b { Err(TypeError::UnsafetyMismatch(expected_found(a, b))) } else { Ok(a) }
|
||||||
Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b)))
|
|
||||||
} else {
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Relate<'tcx> for abi::Abi {
|
impl<'tcx> Relate<'tcx> for abi::Abi {
|
||||||
fn relate<R: TypeRelation<'tcx>>(
|
fn relate<R: TypeRelation<'tcx>>(
|
||||||
relation: &mut R,
|
_relation: &mut R,
|
||||||
a: abi::Abi,
|
a: abi::Abi,
|
||||||
b: abi::Abi,
|
b: abi::Abi,
|
||||||
) -> RelateResult<'tcx, 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>,
|
b: ty::AliasTy<'tcx>,
|
||||||
) -> RelateResult<'tcx, ty::AliasTy<'tcx>> {
|
) -> RelateResult<'tcx, ty::AliasTy<'tcx>> {
|
||||||
if a.def_id != b.def_id {
|
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 {
|
} else {
|
||||||
let args = match relation.tcx().def_kind(a.def_id) {
|
let args = match relation.tcx().def_kind(a.def_id) {
|
||||||
DefKind::OpaqueTy => relate_args_with_variances(
|
DefKind::OpaqueTy => relate_args_with_variances(
|
||||||
|
@ -298,7 +270,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
|
||||||
b: ty::ExistentialProjection<'tcx>,
|
b: ty::ExistentialProjection<'tcx>,
|
||||||
) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> {
|
) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> {
|
||||||
if a.def_id != b.def_id {
|
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 {
|
} else {
|
||||||
let term = relation.relate_with_variance(
|
let term = relation.relate_with_variance(
|
||||||
ty::Invariant,
|
ty::Invariant,
|
||||||
|
@ -325,7 +297,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
|
||||||
) -> RelateResult<'tcx, ty::TraitRef<'tcx>> {
|
) -> RelateResult<'tcx, ty::TraitRef<'tcx>> {
|
||||||
// Different traits cannot be related.
|
// Different traits cannot be related.
|
||||||
if a.def_id != b.def_id {
|
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 {
|
} else {
|
||||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||||
Ok(ty::TraitRef::new(relation.tcx(), a.def_id, 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>> {
|
) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> {
|
||||||
// Different traits cannot be related.
|
// Different traits cannot be related.
|
||||||
if a.def_id != b.def_id {
|
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 {
|
} else {
|
||||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||||
Ok(ty::ExistentialTraitRef { def_id: a.def_id, 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))
|
(&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr))
|
||||||
if a_repr == b_repr =>
|
if a_repr == b_repr =>
|
||||||
{
|
{
|
||||||
let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
|
Ok(Ty::new_dynamic(
|
||||||
relation.relate(a_region, b_region)
|
tcx,
|
||||||
})?;
|
relation.relate(a_obj, b_obj)?,
|
||||||
Ok(Ty::new_dynamic(tcx, relation.relate(a_obj, b_obj)?, region_bound, a_repr))
|
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 => {
|
(&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);
|
let sz_b = sz_b.try_to_target_usize(tcx);
|
||||||
|
|
||||||
match (sz_a, sz_b) {
|
match (sz_a, sz_b) {
|
||||||
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err(
|
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => {
|
||||||
TypeError::FixedArraySize(expected_found(relation, sz_a_val, sz_b_val)),
|
Err(TypeError::FixedArraySize(expected_found(sz_a_val, sz_b_val)))
|
||||||
),
|
}
|
||||||
_ => Err(err),
|
_ => 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)),
|
iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)),
|
||||||
)?)
|
)?)
|
||||||
} else if !(as_.is_empty() || bs.is_empty()) {
|
} 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 {
|
} 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))
|
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);
|
let related_args = tcx.mk_const_list(&related_args);
|
||||||
Expr::FunctionCall(func, 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()));
|
return Ok(ty::Const::new_expr(tcx, expr, a.ty()));
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => 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>> {
|
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.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
|
||||||
b_v.dedup();
|
b_v.dedup();
|
||||||
if a_v.len() != b_v.len() {
|
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)| {
|
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(),
|
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))),
|
(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)
|
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 {
|
impl<'tcx> Relate<'tcx> for ty::ImplPolarity {
|
||||||
fn relate<R: TypeRelation<'tcx>>(
|
fn relate<R: TypeRelation<'tcx>>(
|
||||||
relation: &mut R,
|
_relation: &mut R,
|
||||||
a: ty::ImplPolarity,
|
a: ty::ImplPolarity,
|
||||||
b: ty::ImplPolarity,
|
b: ty::ImplPolarity,
|
||||||
) -> RelateResult<'tcx, ty::ImplPolarity> {
|
) -> RelateResult<'tcx, ty::ImplPolarity> {
|
||||||
if a != b {
|
if a != b { Err(TypeError::PolarityMismatch(expected_found(a, b))) } else { Ok(a) }
|
||||||
Err(TypeError::PolarityMismatch(expected_found(relation, a, b)))
|
|
||||||
} else {
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,9 +809,6 @@ impl<'tcx> Relate<'tcx> for Term<'tcx> {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Error handling
|
// Error handling
|
||||||
|
|
||||||
pub fn expected_found<'tcx, R, T>(relation: &mut R, a: T, b: T) -> ExpectedFound<T>
|
pub fn expected_found<T>(a: T, b: T) -> ExpectedFound<T> {
|
||||||
where
|
ExpectedFound::new(true, a, b)
|
||||||
R: TypeRelation<'tcx>,
|
|
||||||
{
|
|
||||||
ExpectedFound::new(relation.a_is_expected(), a, b)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -904,7 +904,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
&ObligationCause::dummy(),
|
&ObligationCause::dummy(),
|
||||||
param_env,
|
param_env,
|
||||||
hidden_ty,
|
hidden_ty,
|
||||||
true,
|
|
||||||
&mut obligations,
|
&mut obligations,
|
||||||
)?;
|
)?;
|
||||||
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
||||||
|
|
|
@ -116,24 +116,6 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
||||||
self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut())
|
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>>(
|
pub fn eq<T: ToTrace<'tcx>>(
|
||||||
&self,
|
&self,
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
|
|
|
@ -1528,6 +1528,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
| ObligationCauseCode::Coercion { .. }
|
| 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
|
// constrain inference variables a bit more to nested obligations from normalize so
|
||||||
// we can have more helpful errors.
|
// 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.
|
// since the normalization is just done to improve the error message.
|
||||||
let _ = ocx.select_where_possible();
|
let _ = ocx.select_where_possible();
|
||||||
|
|
||||||
if let Err(new_err) = ocx.eq_exp(
|
if let Err(new_err) =
|
||||||
&obligation.cause,
|
ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
|
||||||
obligation.param_env,
|
{
|
||||||
is_normalized_term_expected,
|
|
||||||
normalized_term,
|
|
||||||
data.term,
|
|
||||||
) {
|
|
||||||
(Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
|
(Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
|
||||||
} else {
|
} else {
|
||||||
(None, error.err)
|
(None, error.err)
|
||||||
|
|
|
@ -13,8 +13,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn weird0() -> impl Sized + !Sized {}
|
fn weird0() -> impl Sized + !Sized {}
|
||||||
//~^ ERROR type mismatch resolving `() == impl !Sized + Sized`
|
//~^ ERROR type mismatch resolving `impl !Sized + Sized == ()`
|
||||||
fn weird1() -> 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 {}
|
fn weird2() -> impl !Sized {}
|
||||||
//~^ ERROR type mismatch resolving `() == impl !Sized`
|
//~^ ERROR type mismatch resolving `impl !Sized == ()`
|
||||||
|
|
|
@ -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
|
--> $DIR/opaque-type-unsatisfied-bound.rs:15:16
|
||||||
|
|
|
|
||||||
LL | fn weird0() -> impl Sized + !Sized {}
|
LL | fn weird0() -> impl Sized + !Sized {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^ types differ
|
| ^^^^^^^^^^^^^^^^^^^ 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
|
--> $DIR/opaque-type-unsatisfied-bound.rs:17:16
|
||||||
|
|
|
|
||||||
LL | fn weird1() -> impl !Sized + Sized {}
|
LL | fn weird1() -> impl !Sized + Sized {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^ types differ
|
| ^^^^^^^^^^^^^^^^^^^ types differ
|
||||||
|
|
||||||
error[E0271]: type mismatch resolving `() == impl !Sized`
|
error[E0271]: type mismatch resolving `impl !Sized == ()`
|
||||||
--> $DIR/opaque-type-unsatisfied-bound.rs:19:16
|
--> $DIR/opaque-type-unsatisfied-bound.rs:19:16
|
||||||
|
|
|
|
||||||
LL | fn weird2() -> impl !Sized {}
|
LL | fn weird2() -> impl !Sized {}
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
#![feature(negative_bounds, unboxed_closures)]
|
#![feature(negative_bounds, unboxed_closures)]
|
||||||
|
|
||||||
fn produce() -> impl !Fn<(u32,)> {}
|
fn produce() -> impl !Fn<(u32,)> {}
|
||||||
//~^ ERROR type mismatch resolving `() == impl !Fn<(u32,)>`
|
//~^ ERROR type mismatch resolving `impl !Fn<(u32,)> == ()`
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -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
|
--> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17
|
||||||
|
|
|
|
||||||
LL | fn produce() -> impl !Fn<(u32,)> {}
|
LL | fn produce() -> impl !Fn<(u32,)> {}
|
||||||
|
|
|
@ -8,6 +8,9 @@ LL | let _: i32 = closure();
|
||||||
| --- ^^^^^^^^^ expected `i32`, found opaque type
|
| --- ^^^^^^^^^ expected `i32`, found opaque type
|
||||||
| |
|
| |
|
||||||
| expected due to this
|
| expected due to this
|
||||||
|
|
|
||||||
|
= note: expected type `i32`
|
||||||
|
found opaque type `<() as Foo>::Assoc`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/itiat-allow-nested-closures.rs:22:9
|
--> $DIR/itiat-allow-nested-closures.rs:22:9
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue