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,
|
||||
param_env,
|
||||
hidden_ty.ty,
|
||||
true,
|
||||
&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, ()> {
|
||||
let infcx = self.type_checker.infcx;
|
||||
debug_assert!(!infcx.next_trait_solver());
|
||||
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
|
||||
// `handle_opaque_type` cannot handle subtyping, so to support subtyping
|
||||
// we instead eagerly generalize here. This is a bit of a mess but will go
|
||||
// away once we're using the new solver.
|
||||
|
@ -161,8 +160,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
),
|
||||
};
|
||||
let cause = ObligationCause::dummy_with_span(self.span());
|
||||
let obligations =
|
||||
infcx.handle_opaque_type(a, b, true, &cause, self.param_env())?.obligations;
|
||||
let obligations = infcx.handle_opaque_type(a, b, &cause, self.param_env())?.obligations;
|
||||
self.register_obligations(obligations);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -331,10 +329,6 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
"nll::subtype"
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[instrument(skip(self, info), level = "trace", ret)]
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
|
@ -349,12 +343,15 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
|
||||
debug!(?self.ambient_variance);
|
||||
// In a bivariant context this always succeeds.
|
||||
let r =
|
||||
if self.ambient_variance == ty::Variance::Bivariant { a } else { self.relate(a, b)? };
|
||||
let r = if self.ambient_variance == ty::Variance::Bivariant {
|
||||
Ok(a)
|
||||
} else {
|
||||
self.relate(a, b)
|
||||
};
|
||||
|
||||
self.ambient_variance = old_ambient_variance;
|
||||
|
||||
Ok(r)
|
||||
r
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
|
@ -579,10 +576,6 @@ impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx
|
|||
);
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance")
|
||||
}
|
||||
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
|
||||
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
|
||||
|
|
|
@ -1493,6 +1493,21 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
return;
|
||||
}
|
||||
|
||||
let (expected, found) = if label_expression_as_expected {
|
||||
// In the case where this is a "forced unit", like
|
||||
// `break`, we want to call the `()` "expected"
|
||||
// since it is implied by the syntax.
|
||||
// (Note: not all force-units work this way.)"
|
||||
(expression_ty, self.merged_ty())
|
||||
} else {
|
||||
// Otherwise, the "expected" type for error
|
||||
// reporting is the current unification type,
|
||||
// which is basically the LUB of the expressions
|
||||
// we've seen so far (combined with the expected
|
||||
// type)
|
||||
(self.merged_ty(), expression_ty)
|
||||
};
|
||||
|
||||
// Handle the actual type unification etc.
|
||||
let result = if let Some(expression) = expression {
|
||||
if self.pushed == 0 {
|
||||
|
@ -1540,12 +1555,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
// Another example is `break` with no argument expression.
|
||||
assert!(expression_ty.is_unit(), "if let hack without unit type");
|
||||
fcx.at(cause, fcx.param_env)
|
||||
// needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
|
||||
.eq_exp(
|
||||
.eq(
|
||||
// needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
|
||||
DefineOpaqueTypes::Yes,
|
||||
label_expression_as_expected,
|
||||
expression_ty,
|
||||
self.merged_ty(),
|
||||
expected,
|
||||
found,
|
||||
)
|
||||
.map(|infer_ok| {
|
||||
fcx.register_infer_ok_obligations(infer_ok);
|
||||
|
@ -1579,20 +1593,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
fcx.set_tainted_by_errors(
|
||||
fcx.dcx().span_delayed_bug(cause.span, "coercion error but no error emitted"),
|
||||
);
|
||||
let (expected, found) = if label_expression_as_expected {
|
||||
// In the case where this is a "forced unit", like
|
||||
// `break`, we want to call the `()` "expected"
|
||||
// since it is implied by the syntax.
|
||||
// (Note: not all force-units work this way.)"
|
||||
(expression_ty, self.merged_ty())
|
||||
} else {
|
||||
// Otherwise, the "expected" type for error
|
||||
// reporting is the current unification type,
|
||||
// which is basically the LUB of the expressions
|
||||
// we've seen so far (combined with the expected
|
||||
// type)
|
||||
(self.merged_ty(), expression_ty)
|
||||
};
|
||||
let (expected, found) = fcx.resolve_vars_if_possible((expected, found));
|
||||
|
||||
let mut err;
|
||||
|
|
|
@ -49,7 +49,6 @@ pub struct At<'a, 'tcx> {
|
|||
|
||||
pub struct Trace<'a, 'tcx> {
|
||||
at: At<'a, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
trace: TypeTrace<'tcx>,
|
||||
}
|
||||
|
||||
|
@ -105,23 +104,6 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
/// Makes `a <: b`, where `a` may or may not be expected.
|
||||
///
|
||||
/// See [`At::trace_exp`] and [`Trace::sub`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
pub fn sub_exp<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
a_is_expected: bool,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.trace_exp(a_is_expected, a, b).sub(define_opaque_types, a, b)
|
||||
}
|
||||
|
||||
/// Makes `actual <: expected`. For example, if type-checking a
|
||||
/// call like `foo(x)`, where `foo: fn(i32)`, you might have
|
||||
/// `sup(i32, x)`, since the "expected" type is the type that
|
||||
|
@ -138,7 +120,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.sub_exp(define_opaque_types, false, actual, expected)
|
||||
self.trace(expected, actual).sup(define_opaque_types, expected, actual)
|
||||
}
|
||||
|
||||
/// Makes `expected <: actual`.
|
||||
|
@ -154,24 +136,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.sub_exp(define_opaque_types, true, expected, actual)
|
||||
}
|
||||
|
||||
/// Makes `expected <: actual`.
|
||||
///
|
||||
/// See [`At::trace_exp`] and [`Trace::eq`] for a version of
|
||||
/// this method that only requires `T: Relate<'tcx>`
|
||||
pub fn eq_exp<T>(
|
||||
self,
|
||||
define_opaque_types: DefineOpaqueTypes,
|
||||
a_is_expected: bool,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.trace_exp(a_is_expected, a, b).eq(define_opaque_types, a, b)
|
||||
self.trace(expected, actual).sub(define_opaque_types, expected, actual)
|
||||
}
|
||||
|
||||
/// Makes `expected <: actual`.
|
||||
|
@ -260,48 +225,50 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.trace_exp(true, expected, actual)
|
||||
}
|
||||
|
||||
/// Like `trace`, but the expected value is determined by the
|
||||
/// boolean argument (if true, then the first argument `a` is the
|
||||
/// "expected" value).
|
||||
pub fn trace_exp<T>(self, a_is_expected: bool, a: T, b: T) -> Trace<'a, 'tcx>
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
|
||||
Trace { at: self, trace, a_is_expected }
|
||||
let trace = ToTrace::to_trace(self.cause, true, expected, actual);
|
||||
Trace { at: self, trace }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Trace<'a, 'tcx> {
|
||||
/// Makes `a <: b` where `a` may or may not be expected (if
|
||||
/// `a_is_expected` is true, then `a` is expected).
|
||||
/// Makes `a <: b`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace, a_is_expected } = self;
|
||||
let Trace { at, trace } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
fields
|
||||
.sub(a_is_expected)
|
||||
.sub()
|
||||
.relate(a, b)
|
||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
/// Makes `a == b`; the expectation is set by the call to
|
||||
/// `trace()`.
|
||||
/// Makes `a :> b`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn sup<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
fields
|
||||
.sup()
|
||||
.relate(a, b)
|
||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
/// Makes `a == b`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace, a_is_expected } = self;
|
||||
let Trace { at, trace } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
fields
|
||||
.equate(StructurallyRelateAliases::No, a_is_expected)
|
||||
.equate(StructurallyRelateAliases::No)
|
||||
.relate(a, b)
|
||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
@ -313,11 +280,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
|||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace, a_is_expected } = self;
|
||||
let Trace { at, trace } = self;
|
||||
debug_assert!(at.infcx.next_trait_solver());
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::No);
|
||||
fields
|
||||
.equate(StructurallyRelateAliases::Yes, a_is_expected)
|
||||
.equate(StructurallyRelateAliases::Yes)
|
||||
.relate(a, b)
|
||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
@ -327,10 +294,10 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
|||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace, a_is_expected } = self;
|
||||
let Trace { at, trace } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
fields
|
||||
.lub(a_is_expected)
|
||||
.lub()
|
||||
.relate(a, b)
|
||||
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
}
|
||||
|
@ -340,10 +307,10 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
|||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace, a_is_expected } = self;
|
||||
let Trace { at, trace } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
fields
|
||||
.glb(a_is_expected)
|
||||
.glb()
|
||||
.relate(a, b)
|
||||
.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
}
|
||||
|
|
|
@ -2654,10 +2654,6 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
|
|||
"SameTypeModuloInfer"
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: relate::Relate<'tcx>>(
|
||||
&mut self,
|
||||
_variance: ty::Variance,
|
||||
|
|
|
@ -836,7 +836,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
CombineFields {
|
||||
infcx: self,
|
||||
trace,
|
||||
cause: None,
|
||||
param_env,
|
||||
obligations: PredicateObligations::new(),
|
||||
define_opaque_types,
|
||||
|
@ -1033,7 +1032,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
|
||||
self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
|
||||
Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
|
||||
if a_is_expected {
|
||||
Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::No, a, b))
|
||||
} else {
|
||||
Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::No, b, a))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -78,9 +78,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
span,
|
||||
});
|
||||
obligations.extend(
|
||||
self.handle_opaque_type(ty, ty_var, true, &cause, param_env)
|
||||
.unwrap()
|
||||
.obligations,
|
||||
self.handle_opaque_type(ty, ty_var, &cause, param_env).unwrap().obligations,
|
||||
);
|
||||
ty_var
|
||||
}
|
||||
|
@ -94,15 +92,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
&self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
a_is_expected: bool,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> InferResult<'tcx, ()> {
|
||||
if a.references_error() || b.references_error() {
|
||||
return Ok(InferOk { value: (), obligations: vec![] });
|
||||
}
|
||||
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
|
||||
let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
|
||||
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
|
||||
let def_id = def_id.expect_local();
|
||||
match self.defining_use_anchor {
|
||||
|
@ -169,14 +165,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
cause.clone(),
|
||||
param_env,
|
||||
b,
|
||||
a_is_expected,
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(res) = process(a, b, true) {
|
||||
if let Some(res) = process(a, b) {
|
||||
res
|
||||
} else if let Some(res) = process(b, a, false) {
|
||||
} else if let Some(res) = process(b, a) {
|
||||
res
|
||||
} else {
|
||||
let (a, b) = self.resolve_vars_if_possible((a, b));
|
||||
|
@ -520,18 +515,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
a_is_expected: bool,
|
||||
) -> InferResult<'tcx, ()> {
|
||||
let mut obligations = Vec::new();
|
||||
|
||||
self.insert_hidden_type(
|
||||
opaque_type_key,
|
||||
&cause,
|
||||
param_env,
|
||||
hidden_ty,
|
||||
a_is_expected,
|
||||
&mut obligations,
|
||||
)?;
|
||||
self.insert_hidden_type(opaque_type_key, &cause, param_env, hidden_ty, &mut obligations)?;
|
||||
|
||||
self.add_item_bounds_for_hidden_type(
|
||||
opaque_type_key.def_id.to_def_id(),
|
||||
|
@ -558,7 +545,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
a_is_expected: bool,
|
||||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||
) -> Result<(), TypeError<'tcx>> {
|
||||
// Ideally, we'd get the span where *this specific `ty` came
|
||||
|
@ -586,7 +572,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
if let Some(prev) = prev {
|
||||
obligations.extend(
|
||||
self.at(cause, param_env)
|
||||
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
|
||||
.eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
|
||||
.obligations,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -144,10 +144,6 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
|
|||
self.tcx
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
true
|
||||
} // irrelevant
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
//! There are four type combiners: [Equate], [Sub], [Lub], and [Glb].
|
||||
//! There are four type combiners: [TypeRelating], [Lub], and [Glb],
|
||||
//! and `NllTypeRelating` in rustc_borrowck, which is only used for NLL.
|
||||
//!
|
||||
//! Each implements the trait [TypeRelation] and contains methods for
|
||||
//! combining two instances of various things and yielding a new instance.
|
||||
//! These combiner methods always yield a `Result<T>`. To relate two
|
||||
|
@ -15,17 +17,10 @@
|
|||
//!
|
||||
//! On success, the LUB/GLB operations return the appropriate bound. The
|
||||
//! return value of `Equate` or `Sub` shouldn't really be used.
|
||||
//!
|
||||
//! ## Contravariance
|
||||
//!
|
||||
//! We explicitly track which argument is expected using
|
||||
//! [TypeRelation::a_is_expected], so when dealing with contravariance
|
||||
//! this should be correctly updated.
|
||||
|
||||
use super::equate::Equate;
|
||||
use super::glb::Glb;
|
||||
use super::lub::Lub;
|
||||
use super::sub::Sub;
|
||||
use super::type_relating::TypeRelating;
|
||||
use super::StructurallyRelateAliases;
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
|
@ -41,7 +36,6 @@ use rustc_span::Span;
|
|||
pub struct CombineFields<'infcx, 'tcx> {
|
||||
pub infcx: &'infcx InferCtxt<'tcx>,
|
||||
pub trace: TypeTrace<'tcx>,
|
||||
pub cause: Option<ty::relate::Cause>,
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
pub obligations: PredicateObligations<'tcx>,
|
||||
pub define_opaque_types: DefineOpaqueTypes,
|
||||
|
@ -57,7 +51,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
where
|
||||
R: ObligationEmittingRelation<'tcx>,
|
||||
{
|
||||
let a_is_expected = relation.a_is_expected();
|
||||
debug_assert!(!a.has_escaping_bound_vars());
|
||||
debug_assert!(!b.has_escaping_bound_vars());
|
||||
|
||||
|
@ -68,20 +61,20 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.borrow_mut()
|
||||
.int_unification_table()
|
||||
.unify_var_var(a_id, b_id)
|
||||
.map_err(|e| int_unification_error(a_is_expected, e))?;
|
||||
.map_err(|e| int_unification_error(true, e))?;
|
||||
Ok(a)
|
||||
}
|
||||
(&ty::Infer(ty::IntVar(v_id)), &ty::Int(v)) => {
|
||||
self.unify_integral_variable(a_is_expected, v_id, IntType(v))
|
||||
self.unify_integral_variable(true, v_id, IntType(v))
|
||||
}
|
||||
(&ty::Int(v), &ty::Infer(ty::IntVar(v_id))) => {
|
||||
self.unify_integral_variable(!a_is_expected, v_id, IntType(v))
|
||||
self.unify_integral_variable(false, v_id, IntType(v))
|
||||
}
|
||||
(&ty::Infer(ty::IntVar(v_id)), &ty::Uint(v)) => {
|
||||
self.unify_integral_variable(a_is_expected, v_id, UintType(v))
|
||||
self.unify_integral_variable(true, v_id, UintType(v))
|
||||
}
|
||||
(&ty::Uint(v), &ty::Infer(ty::IntVar(v_id))) => {
|
||||
self.unify_integral_variable(!a_is_expected, v_id, UintType(v))
|
||||
self.unify_integral_variable(false, v_id, UintType(v))
|
||||
}
|
||||
|
||||
// Relate floating-point variables to other types
|
||||
|
@ -90,14 +83,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.borrow_mut()
|
||||
.float_unification_table()
|
||||
.unify_var_var(a_id, b_id)
|
||||
.map_err(|e| float_unification_error(a_is_expected, e))?;
|
||||
.map_err(|e| float_unification_error(true, e))?;
|
||||
Ok(a)
|
||||
}
|
||||
(&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
|
||||
self.unify_float_variable(a_is_expected, v_id, v)
|
||||
self.unify_float_variable(true, v_id, v)
|
||||
}
|
||||
(&ty::Float(v), &ty::Infer(ty::FloatVar(v_id))) => {
|
||||
self.unify_float_variable(!a_is_expected, v_id, v)
|
||||
self.unify_float_variable(false, v_id, v)
|
||||
}
|
||||
|
||||
// We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
|
||||
|
@ -130,7 +123,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
|
||||
// All other cases of inference are errors
|
||||
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
|
||||
Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b)))
|
||||
Err(TypeError::Sorts(ty::relate::expected_found(a, b)))
|
||||
}
|
||||
|
||||
// During coherence, opaque types should be treated as *possibly*
|
||||
|
@ -228,12 +221,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
|
||||
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
|
||||
self.instantiate_const_var(relation, relation.a_is_expected(), vid, b)?;
|
||||
self.instantiate_const_var(relation, true, vid, b)?;
|
||||
Ok(b)
|
||||
}
|
||||
|
||||
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
||||
self.instantiate_const_var(relation, !relation.a_is_expected(), vid, a)?;
|
||||
self.instantiate_const_var(relation, false, vid, a)?;
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
|
@ -250,8 +243,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
{
|
||||
match relation.structurally_relate_aliases() {
|
||||
StructurallyRelateAliases::No => {
|
||||
let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) };
|
||||
|
||||
relation.register_predicates([if self.next_trait_solver() {
|
||||
ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
|
@ -321,21 +312,24 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
pub fn equate<'a>(
|
||||
&'a mut self,
|
||||
structurally_relate_aliases: StructurallyRelateAliases,
|
||||
a_is_expected: bool,
|
||||
) -> Equate<'a, 'infcx, 'tcx> {
|
||||
Equate::new(self, structurally_relate_aliases, a_is_expected)
|
||||
) -> TypeRelating<'a, 'infcx, 'tcx> {
|
||||
TypeRelating::new(self, structurally_relate_aliases, ty::Invariant)
|
||||
}
|
||||
|
||||
pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'tcx> {
|
||||
Sub::new(self, a_is_expected)
|
||||
pub fn sub<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> {
|
||||
TypeRelating::new(self, StructurallyRelateAliases::No, ty::Covariant)
|
||||
}
|
||||
|
||||
pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'tcx> {
|
||||
Lub::new(self, a_is_expected)
|
||||
pub fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> {
|
||||
TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant)
|
||||
}
|
||||
|
||||
pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'tcx> {
|
||||
Glb::new(self, a_is_expected)
|
||||
pub fn lub<'a>(&'a mut self) -> Lub<'a, 'infcx, 'tcx> {
|
||||
Lub::new(self)
|
||||
}
|
||||
|
||||
pub fn glb<'a>(&'a mut self) -> Glb<'a, 'infcx, 'tcx> {
|
||||
Glb::new(self)
|
||||
}
|
||||
|
||||
pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
|
@ -367,19 +361,8 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
|
|||
/// be used if control over the obligation causes is required.
|
||||
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>);
|
||||
|
||||
/// Register an obligation that both types must be related to each other according to
|
||||
/// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
self.alias_relate_direction(),
|
||||
))]);
|
||||
}
|
||||
|
||||
/// Relation direction emitted for `AliasRelate` predicates, corresponding to the direction
|
||||
/// of the relation.
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection;
|
||||
/// Register `AliasRelate` obligation(s) that both types must be related to each other.
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
|
||||
}
|
||||
|
||||
fn int_unification_error<'tcx>(
|
||||
|
|
|
@ -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
|
||||
// A rel A'
|
||||
// ```
|
||||
if target_is_expected == relation.a_is_expected() {
|
||||
if target_is_expected {
|
||||
relation.relate(generalized_ty, source_ty)?;
|
||||
} else {
|
||||
debug!("flip relation");
|
||||
|
@ -204,9 +204,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.const_unification_table()
|
||||
.union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
|
||||
|
||||
// HACK: make sure that we `a_is_expected` continues to be
|
||||
// correct when relating the generalized type with the source.
|
||||
if target_is_expected == relation.a_is_expected() {
|
||||
// Make sure that the order is correct when relating the
|
||||
// generalized const and the source.
|
||||
if target_is_expected {
|
||||
relation.relate_with_variance(
|
||||
ty::Variance::Invariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
|
@ -398,10 +398,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||
"Generalizer"
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn relate_item_args(
|
||||
&mut self,
|
||||
item_def_id: DefId,
|
||||
|
@ -440,9 +436,9 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||
debug!(?self.ambient_variance, "new ambient variance");
|
||||
// Recursive calls to `relate` can overflow the stack. For example a deeper version of
|
||||
// `ui/associated-consts/issue-93775.rs`.
|
||||
let r = ensure_sufficient_stack(|| self.relate(a, b))?;
|
||||
let r = ensure_sufficient_stack(|| self.relate(a, b));
|
||||
self.ambient_variance = old_ambient_variance;
|
||||
Ok(r)
|
||||
r
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, t2), ret)]
|
||||
|
|
|
@ -13,15 +13,11 @@ use crate::traits::{ObligationCause, PredicateObligations};
|
|||
/// "Greatest lower bound" (common subtype)
|
||||
pub struct Glb<'combine, 'infcx, 'tcx> {
|
||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
}
|
||||
|
||||
impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> {
|
||||
pub fn new(
|
||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
) -> Glb<'combine, 'infcx, 'tcx> {
|
||||
Glb { fields, a_is_expected }
|
||||
pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Glb<'combine, 'infcx, 'tcx> {
|
||||
Glb { fields }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,10 +30,6 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
|||
self.fields.tcx()
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
self.a_is_expected
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
|
@ -46,13 +38,11 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
|||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
match variance {
|
||||
ty::Invariant => {
|
||||
self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b)
|
||||
}
|
||||
ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
|
||||
ty::Covariant => self.relate(a, b),
|
||||
// FIXME(#41044) -- not correct, need test
|
||||
ty::Bivariant => Ok(a),
|
||||
ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b),
|
||||
ty::Contravariant => self.fields.lub().relate(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +116,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
|
|||
}
|
||||
|
||||
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let mut sub = self.fields.sub(self.a_is_expected);
|
||||
let mut sub = self.fields.sub();
|
||||
sub.relate(v, a)?;
|
||||
sub.relate(v, b)?;
|
||||
Ok(())
|
||||
|
@ -158,8 +148,12 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
|||
self.fields.register_obligations(obligations);
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
// FIXME(deferred_projection_equality): This isn't right, I think?
|
||||
ty::AliasRelationDirection::Equate
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
// FIXME(deferred_projection_equality): This isn't right, I think?
|
||||
ty::AliasRelationDirection::Equate,
|
||||
))]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,64 +1,11 @@
|
|||
//! Helper routines for higher-ranked things. See the `doc` module at
|
||||
//! the end of the file for details.
|
||||
|
||||
use super::combine::CombineFields;
|
||||
use crate::infer::CombinedSnapshot;
|
||||
use crate::infer::{HigherRankedType, InferCtxt};
|
||||
use crate::infer::InferCtxt;
|
||||
use rustc_middle::ty::fold::FnMutDelegate;
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
impl<'a, 'tcx> CombineFields<'a, 'tcx> {
|
||||
/// Checks whether `for<..> sub <: for<..> sup` holds.
|
||||
///
|
||||
/// For this to hold, **all** instantiations of the super type
|
||||
/// have to be a super type of **at least one** instantiation of
|
||||
/// the subtype.
|
||||
///
|
||||
/// This is implemented by first entering a new universe.
|
||||
/// We then replace all bound variables in `sup` with placeholders,
|
||||
/// and all bound variables in `sub` with inference vars.
|
||||
/// We can then just relate the two resulting types as normal.
|
||||
///
|
||||
/// Note: this is a subtle algorithm. For a full explanation, please see
|
||||
/// the [rustc dev guide][rd]
|
||||
///
|
||||
/// [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn higher_ranked_sub<T>(
|
||||
&mut self,
|
||||
sub: Binder<'tcx, T>,
|
||||
sup: Binder<'tcx, T>,
|
||||
sub_is_expected: bool,
|
||||
) -> RelateResult<'tcx, ()>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let span = self.trace.cause.span;
|
||||
// First, we instantiate each bound region in the supertype with a
|
||||
// fresh placeholder region. Note that this automatically creates
|
||||
// a new universe if needed.
|
||||
self.infcx.enter_forall(sup, |sup_prime| {
|
||||
// Next, we instantiate each bound region in the subtype
|
||||
// with a fresh region variable. These region variables --
|
||||
// but no other preexisting region variables -- can name
|
||||
// the placeholders.
|
||||
let sub_prime =
|
||||
self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub);
|
||||
debug!("a_prime={:?}", sub_prime);
|
||||
debug!("b_prime={:?}", sup_prime);
|
||||
|
||||
// Compare types now that bound regions have been replaced.
|
||||
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime);
|
||||
if result.is_ok() {
|
||||
debug!("OK result={result:?}");
|
||||
}
|
||||
// NOTE: returning the result here would be dangerous as it contains
|
||||
// placeholders which **must not** be named afterwards.
|
||||
result.map(|_| ())
|
||||
})
|
||||
}
|
||||
}
|
||||
use rustc_middle::ty::relate::RelateResult;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Replaces all bound variables (lifetimes, types, and constants) bound by
|
||||
|
|
|
@ -116,9 +116,7 @@ where
|
|||
&& !this.infcx().next_trait_solver() =>
|
||||
{
|
||||
this.register_obligations(
|
||||
infcx
|
||||
.handle_opaque_type(a, b, this.a_is_expected(), this.cause(), this.param_env())?
|
||||
.obligations,
|
||||
infcx.handle_opaque_type(a, b, this.cause(), this.param_env())?.obligations,
|
||||
);
|
||||
Ok(a)
|
||||
}
|
||||
|
|
|
@ -13,15 +13,11 @@ use rustc_span::Span;
|
|||
/// "Least upper bound" (common supertype)
|
||||
pub struct Lub<'combine, 'infcx, 'tcx> {
|
||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
}
|
||||
|
||||
impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> {
|
||||
pub fn new(
|
||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
) -> Lub<'combine, 'infcx, 'tcx> {
|
||||
Lub { fields, a_is_expected }
|
||||
pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Lub<'combine, 'infcx, 'tcx> {
|
||||
Lub { fields }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,10 +30,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
|||
self.fields.tcx()
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
self.a_is_expected
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
|
@ -46,13 +38,11 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
|||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
match variance {
|
||||
ty::Invariant => {
|
||||
self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b)
|
||||
}
|
||||
ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
|
||||
ty::Covariant => self.relate(a, b),
|
||||
// FIXME(#41044) -- not correct, need test
|
||||
ty::Bivariant => Ok(a),
|
||||
ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b),
|
||||
ty::Contravariant => self.fields.glb().relate(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +116,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
|
|||
}
|
||||
|
||||
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let mut sub = self.fields.sub(self.a_is_expected);
|
||||
let mut sub = self.fields.sub();
|
||||
sub.relate(a, v)?;
|
||||
sub.relate(b, v)?;
|
||||
Ok(())
|
||||
|
@ -158,8 +148,12 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
|||
self.fields.register_obligations(obligations)
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
// FIXME(deferred_projection_equality): This isn't right, I think?
|
||||
ty::AliasRelationDirection::Equate
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
// FIXME(deferred_projection_equality): This isn't right, I think?
|
||||
ty::AliasRelationDirection::Equate,
|
||||
))]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
//! (except for some relations used for diagnostics and heuristics in the compiler).
|
||||
|
||||
pub(super) mod combine;
|
||||
mod equate;
|
||||
mod generalize;
|
||||
mod glb;
|
||||
mod higher_ranked;
|
||||
mod lattice;
|
||||
mod lub;
|
||||
mod sub;
|
||||
mod type_relating;
|
||||
|
||||
/// Whether aliases should be related structurally or not. Used
|
||||
/// to adjust the behavior of generalization and combine.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
true
|
||||
} // irrelevant
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
_: ty::Variance,
|
||||
|
@ -75,7 +71,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
|
|||
) => Ok(a),
|
||||
|
||||
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
|
||||
Err(TypeError::Sorts(relate::expected_found(self, a, b)))
|
||||
Err(TypeError::Sorts(relate::expected_found(a, b)))
|
||||
}
|
||||
|
||||
(&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)),
|
||||
|
@ -100,7 +96,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
|
|||
}
|
||||
|
||||
(ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
|
||||
return Err(TypeError::ConstMismatch(relate::expected_found(self, a, b)));
|
||||
return Err(TypeError::ConstMismatch(relate::expected_found(a, b)));
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
|
|
@ -15,28 +15,12 @@ use std::iter;
|
|||
|
||||
pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Cause {
|
||||
ExistentialRegionBound, // relating an existential region bound
|
||||
}
|
||||
|
||||
pub trait TypeRelation<'tcx>: Sized {
|
||||
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||
|
||||
/// Returns a static string we can use for printouts.
|
||||
fn tag(&self) -> &'static str;
|
||||
|
||||
/// Returns `true` if the value `a` is the "expected" type in the
|
||||
/// relation. Just affects error messages.
|
||||
fn a_is_expected(&self) -> bool;
|
||||
|
||||
fn with_cause<F, R>(&mut self, _cause: Cause, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut Self) -> R,
|
||||
{
|
||||
f(self)
|
||||
}
|
||||
|
||||
/// Generic relation routine suitable for most anything.
|
||||
fn relate<T: Relate<'tcx>>(&mut self, a: T, b: T) -> RelateResult<'tcx, T> {
|
||||
Relate::relate(self, a, b)
|
||||
|
@ -178,11 +162,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
|
|||
let tcx = relation.tcx();
|
||||
|
||||
if a.c_variadic != b.c_variadic {
|
||||
return Err(TypeError::VariadicMismatch(expected_found(
|
||||
relation,
|
||||
a.c_variadic,
|
||||
b.c_variadic,
|
||||
)));
|
||||
return Err(TypeError::VariadicMismatch(expected_found(a.c_variadic, b.c_variadic)));
|
||||
}
|
||||
let unsafety = relation.relate(a.unsafety, b.unsafety)?;
|
||||
let abi = relation.relate(a.abi, b.abi)?;
|
||||
|
@ -227,39 +207,31 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
|
|||
|
||||
impl<'tcx> Relate<'tcx> for ty::BoundConstness {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
_relation: &mut R,
|
||||
a: ty::BoundConstness,
|
||||
b: ty::BoundConstness,
|
||||
) -> RelateResult<'tcx, ty::BoundConstness> {
|
||||
if a != b {
|
||||
Err(TypeError::ConstnessMismatch(expected_found(relation, a, b)))
|
||||
} else {
|
||||
Ok(a)
|
||||
}
|
||||
if a != b { Err(TypeError::ConstnessMismatch(expected_found(a, b))) } else { Ok(a) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for hir::Unsafety {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
_relation: &mut R,
|
||||
a: hir::Unsafety,
|
||||
b: hir::Unsafety,
|
||||
) -> RelateResult<'tcx, hir::Unsafety> {
|
||||
if a != b {
|
||||
Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b)))
|
||||
} else {
|
||||
Ok(a)
|
||||
}
|
||||
if a != b { Err(TypeError::UnsafetyMismatch(expected_found(a, b))) } else { Ok(a) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for abi::Abi {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
_relation: &mut R,
|
||||
a: abi::Abi,
|
||||
b: abi::Abi,
|
||||
) -> RelateResult<'tcx, abi::Abi> {
|
||||
if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(relation, a, b))) }
|
||||
if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(a, b))) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,7 +242,7 @@ impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> {
|
|||
b: ty::AliasTy<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::AliasTy<'tcx>> {
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id)))
|
||||
Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id)))
|
||||
} else {
|
||||
let args = match relation.tcx().def_kind(a.def_id) {
|
||||
DefKind::OpaqueTy => relate_args_with_variances(
|
||||
|
@ -298,7 +270,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
|
|||
b: ty::ExistentialProjection<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> {
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id)))
|
||||
Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id)))
|
||||
} else {
|
||||
let term = relation.relate_with_variance(
|
||||
ty::Invariant,
|
||||
|
@ -325,7 +297,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
|
|||
) -> RelateResult<'tcx, ty::TraitRef<'tcx>> {
|
||||
// Different traits cannot be related.
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
|
||||
Err(TypeError::Traits(expected_found(a.def_id, b.def_id)))
|
||||
} else {
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args))
|
||||
|
@ -341,7 +313,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
|
|||
) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> {
|
||||
// Different traits cannot be related.
|
||||
if a.def_id != b.def_id {
|
||||
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
|
||||
Err(TypeError::Traits(expected_found(a.def_id, b.def_id)))
|
||||
} else {
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::ExistentialTraitRef { def_id: a.def_id, args })
|
||||
|
@ -452,10 +424,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||
(&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr))
|
||||
if a_repr == b_repr =>
|
||||
{
|
||||
let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
|
||||
relation.relate(a_region, b_region)
|
||||
})?;
|
||||
Ok(Ty::new_dynamic(tcx, relation.relate(a_obj, b_obj)?, region_bound, a_repr))
|
||||
Ok(Ty::new_dynamic(
|
||||
tcx,
|
||||
relation.relate(a_obj, b_obj)?,
|
||||
relation.relate(a_region, b_region)?,
|
||||
a_repr,
|
||||
))
|
||||
}
|
||||
|
||||
(&ty::Coroutine(a_id, a_args), &ty::Coroutine(b_id, b_args)) if a_id == b_id => {
|
||||
|
@ -515,9 +489,9 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||
let sz_b = sz_b.try_to_target_usize(tcx);
|
||||
|
||||
match (sz_a, sz_b) {
|
||||
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err(
|
||||
TypeError::FixedArraySize(expected_found(relation, sz_a_val, sz_b_val)),
|
||||
),
|
||||
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => {
|
||||
Err(TypeError::FixedArraySize(expected_found(sz_a_val, sz_b_val)))
|
||||
}
|
||||
_ => Err(err),
|
||||
}
|
||||
}
|
||||
|
@ -536,9 +510,9 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||
iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)),
|
||||
)?)
|
||||
} else if !(as_.is_empty() || bs.is_empty()) {
|
||||
Err(TypeError::TupleSize(expected_found(relation, as_.len(), bs.len())))
|
||||
Err(TypeError::TupleSize(expected_found(as_.len(), bs.len())))
|
||||
} else {
|
||||
Err(TypeError::Sorts(expected_found(relation, a, b)))
|
||||
Err(TypeError::Sorts(expected_found(a, b)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -559,7 +533,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||
Ok(Ty::new_alias(tcx, a_kind, alias_ty))
|
||||
}
|
||||
|
||||
_ => Err(TypeError::Sorts(expected_found(relation, a, b))),
|
||||
_ => Err(TypeError::Sorts(expected_found(a, b))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -657,13 +631,13 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
|
|||
let related_args = tcx.mk_const_list(&related_args);
|
||||
Expr::FunctionCall(func, related_args)
|
||||
}
|
||||
_ => return Err(TypeError::ConstMismatch(expected_found(r, a, b))),
|
||||
_ => return Err(TypeError::ConstMismatch(expected_found(a, b))),
|
||||
};
|
||||
return Ok(ty::Const::new_expr(tcx, expr, a.ty()));
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) }
|
||||
if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(a, b))) }
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
|
@ -685,7 +659,7 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
|||
b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
|
||||
b_v.dedup();
|
||||
if a_v.len() != b_v.len() {
|
||||
return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)));
|
||||
return Err(TypeError::ExistentialMismatch(expected_found(a, b)));
|
||||
}
|
||||
|
||||
let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
|
||||
|
@ -697,7 +671,7 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
|||
relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
|
||||
))),
|
||||
(AutoTrait(a), AutoTrait(b)) if a == b => Ok(ep_a.rebind(AutoTrait(a))),
|
||||
_ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))),
|
||||
_ => Err(TypeError::ExistentialMismatch(expected_found(a, b))),
|
||||
}
|
||||
});
|
||||
tcx.mk_poly_existential_predicates_from_iter(v)
|
||||
|
@ -797,15 +771,11 @@ impl<'tcx> Relate<'tcx> for GenericArg<'tcx> {
|
|||
|
||||
impl<'tcx> Relate<'tcx> for ty::ImplPolarity {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
_relation: &mut R,
|
||||
a: ty::ImplPolarity,
|
||||
b: ty::ImplPolarity,
|
||||
) -> RelateResult<'tcx, ty::ImplPolarity> {
|
||||
if a != b {
|
||||
Err(TypeError::PolarityMismatch(expected_found(relation, a, b)))
|
||||
} else {
|
||||
Ok(a)
|
||||
}
|
||||
if a != b { Err(TypeError::PolarityMismatch(expected_found(a, b))) } else { Ok(a) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -839,9 +809,6 @@ impl<'tcx> Relate<'tcx> for Term<'tcx> {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// Error handling
|
||||
|
||||
pub fn expected_found<'tcx, R, T>(relation: &mut R, a: T, b: T) -> ExpectedFound<T>
|
||||
where
|
||||
R: TypeRelation<'tcx>,
|
||||
{
|
||||
ExpectedFound::new(relation.a_is_expected(), a, b)
|
||||
pub fn expected_found<T>(a: T, b: T) -> ExpectedFound<T> {
|
||||
ExpectedFound::new(true, a, b)
|
||||
}
|
||||
|
|
|
@ -904,7 +904,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
&ObligationCause::dummy(),
|
||||
param_env,
|
||||
hidden_ty,
|
||||
true,
|
||||
&mut obligations,
|
||||
)?;
|
||||
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
||||
|
|
|
@ -116,24 +116,6 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
|||
self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut())
|
||||
}
|
||||
|
||||
/// Makes `expected <: actual`.
|
||||
pub fn eq_exp<T>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
a_is_expected: bool,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> Result<(), TypeError<'tcx>>
|
||||
where
|
||||
T: ToTrace<'tcx>,
|
||||
{
|
||||
self.infcx
|
||||
.at(cause, param_env)
|
||||
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, a, b)
|
||||
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
|
||||
}
|
||||
|
||||
pub fn eq<T: ToTrace<'tcx>>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
|
|
|
@ -1528,6 +1528,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
| ObligationCauseCode::Coercion { .. }
|
||||
);
|
||||
|
||||
let (expected, actual) = if is_normalized_term_expected {
|
||||
(normalized_term, data.term)
|
||||
} else {
|
||||
(data.term, normalized_term)
|
||||
};
|
||||
|
||||
// constrain inference variables a bit more to nested obligations from normalize so
|
||||
// we can have more helpful errors.
|
||||
//
|
||||
|
@ -1535,13 +1541,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
// since the normalization is just done to improve the error message.
|
||||
let _ = ocx.select_where_possible();
|
||||
|
||||
if let Err(new_err) = ocx.eq_exp(
|
||||
&obligation.cause,
|
||||
obligation.param_env,
|
||||
is_normalized_term_expected,
|
||||
normalized_term,
|
||||
data.term,
|
||||
) {
|
||||
if let Err(new_err) =
|
||||
ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
|
||||
{
|
||||
(Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
|
||||
} else {
|
||||
(None, error.err)
|
||||
|
|
|
@ -13,8 +13,8 @@ fn main() {
|
|||
}
|
||||
|
||||
fn weird0() -> impl Sized + !Sized {}
|
||||
//~^ ERROR type mismatch resolving `() == impl !Sized + Sized`
|
||||
//~^ ERROR type mismatch resolving `impl !Sized + Sized == ()`
|
||||
fn weird1() -> impl !Sized + Sized {}
|
||||
//~^ ERROR type mismatch resolving `() == impl !Sized + Sized`
|
||||
//~^ ERROR type mismatch resolving `impl !Sized + Sized == ()`
|
||||
fn weird2() -> impl !Sized {}
|
||||
//~^ ERROR type mismatch resolving `() == impl !Sized`
|
||||
//~^ ERROR type mismatch resolving `impl !Sized == ()`
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
error[E0271]: type mismatch resolving `() == impl !Sized + Sized`
|
||||
error[E0271]: type mismatch resolving `impl !Sized + Sized == ()`
|
||||
--> $DIR/opaque-type-unsatisfied-bound.rs:15:16
|
||||
|
|
||||
LL | fn weird0() -> impl Sized + !Sized {}
|
||||
| ^^^^^^^^^^^^^^^^^^^ types differ
|
||||
|
||||
error[E0271]: type mismatch resolving `() == impl !Sized + Sized`
|
||||
error[E0271]: type mismatch resolving `impl !Sized + Sized == ()`
|
||||
--> $DIR/opaque-type-unsatisfied-bound.rs:17:16
|
||||
|
|
||||
LL | fn weird1() -> impl !Sized + Sized {}
|
||||
| ^^^^^^^^^^^^^^^^^^^ types differ
|
||||
|
||||
error[E0271]: type mismatch resolving `() == impl !Sized`
|
||||
error[E0271]: type mismatch resolving `impl !Sized == ()`
|
||||
--> $DIR/opaque-type-unsatisfied-bound.rs:19:16
|
||||
|
|
||||
LL | fn weird2() -> impl !Sized {}
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
#![feature(negative_bounds, unboxed_closures)]
|
||||
|
||||
fn produce() -> impl !Fn<(u32,)> {}
|
||||
//~^ ERROR type mismatch resolving `() == impl !Fn<(u32,)>`
|
||||
//~^ ERROR type mismatch resolving `impl !Fn<(u32,)> == ()`
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error[E0271]: type mismatch resolving `() == impl !Fn<(u32,)>`
|
||||
error[E0271]: type mismatch resolving `impl !Fn<(u32,)> == ()`
|
||||
--> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17
|
||||
|
|
||||
LL | fn produce() -> impl !Fn<(u32,)> {}
|
||||
|
|
|
@ -8,6 +8,9 @@ LL | let _: i32 = closure();
|
|||
| --- ^^^^^^^^^ expected `i32`, found opaque type
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected type `i32`
|
||||
found opaque type `<() as Foo>::Assoc`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/itiat-allow-nested-closures.rs:22:9
|
||||
|
|
Loading…
Add table
Reference in a new issue