Skip to content

Commit

Permalink
Auto merge of #121462 - compiler-errors:eq-and-sub, r=lcnr
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Mar 1, 2024
2 parents 6cbf092 + 5072b65 commit b0696a5
Show file tree
Hide file tree
Showing 28 changed files with 509 additions and 840 deletions.
1 change: 0 additions & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1066,7 +1066,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
&cause,
param_env,
hidden_ty.ty,
true,
&mut obligations,
)?;

Expand Down
21 changes: 7 additions & 14 deletions compiler/rustc_borrowck/src/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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(())
}
Expand Down Expand Up @@ -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,
Expand All @@ -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")]
Expand Down Expand Up @@ -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(
Expand Down
38 changes: 19 additions & 19 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
91 changes: 29 additions & 62 deletions compiler/rustc_infer/src/infer/at.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
}

Expand Down Expand Up @@ -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
Expand All @@ -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`.
Expand All @@ -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`.
Expand Down Expand Up @@ -260,48 +225,50 @@ impl<'a, 'tcx> At<'a, 'tcx> {
where
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>
impl<'a, 'tcx> Trace<'a, 'tcx> {
/// 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: ToTrace<'tcx>,
T: Relate<'tcx>,
{
let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
Trace { at: self, trace, a_is_expected }
let Trace { at, trace } = self;
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.sub()
.relate(a, b)
.map(move |_| InferOk { value: (), obligations: fields.obligations })
}
}

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, ()>
pub fn sup<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)
.sup()
.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 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 })
}
Expand All @@ -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 })
}
Expand All @@ -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 })
}
Expand All @@ -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 })
}
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,6 @@ impl<'tcx> InferCtxt<'tcx> {
CombineFields {
infcx: self,
trace,
cause: None,
param_env,
obligations: PredicateObligations::new(),
define_opaque_types,
Expand Down Expand Up @@ -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))
}
})
}

Expand Down
Loading

0 comments on commit b0696a5

Please sign in to comment.