Skip to content

change binders from tuple structs to named fields #112786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 32 additions & 30 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,10 @@ impl BoundVariableKind {
/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[derive(HashStable, Lift)]
pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>);
pub struct Binder<'tcx, T> {
value: T,
bound_vars: &'tcx List<BoundVariableKind>,
}

impl<'tcx, T> Binder<'tcx, T>
where
Expand All @@ -1023,15 +1026,15 @@ where
!value.has_escaping_bound_vars(),
"`{value:?}` has escaping bound vars, so it cannot be wrapped in a dummy binder."
);
Binder(value, ty::List::empty())
Binder { value, bound_vars: ty::List::empty() }
}

pub fn bind_with_vars(value: T, vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> {
pub fn bind_with_vars(value: T, bound_vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> {
if cfg!(debug_assertions) {
let mut validator = ValidateBoundVars::new(vars);
let mut validator = ValidateBoundVars::new(bound_vars);
value.visit_with(&mut validator);
}
Binder(value, vars)
Binder { value, bound_vars }
}
}

Expand All @@ -1053,30 +1056,30 @@ impl<'tcx, T> Binder<'tcx, T> {
/// - comparing the self type of a PolyTraitRef to see if it is equal to
/// a type parameter `X`, since the type `X` does not reference any regions
pub fn skip_binder(self) -> T {
self.0
self.value
}

pub fn bound_vars(&self) -> &'tcx List<BoundVariableKind> {
self.1
self.bound_vars
}

pub fn as_ref(&self) -> Binder<'tcx, &T> {
Binder(&self.0, self.1)
Binder { value: &self.value, bound_vars: self.bound_vars }
}

pub fn as_deref(&self) -> Binder<'tcx, &T::Target>
where
T: Deref,
{
Binder(&self.0, self.1)
Binder { value: &self.value, bound_vars: self.bound_vars }
}

pub fn map_bound_ref_unchecked<F, U>(&self, f: F) -> Binder<'tcx, U>
where
F: FnOnce(&T) -> U,
{
let value = f(&self.0);
Binder(value, self.1)
let value = f(&self.value);
Binder { value, bound_vars: self.bound_vars }
}

pub fn map_bound_ref<F, U: TypeVisitable<TyCtxt<'tcx>>>(&self, f: F) -> Binder<'tcx, U>
Expand All @@ -1090,12 +1093,13 @@ impl<'tcx, T> Binder<'tcx, T> {
where
F: FnOnce(T) -> U,
{
let value = f(self.0);
let Binder { value, bound_vars } = self;
let value = f(value);
if cfg!(debug_assertions) {
let mut validator = ValidateBoundVars::new(self.1);
let mut validator = ValidateBoundVars::new(bound_vars);
value.visit_with(&mut validator);
}
Binder(value, self.1)
Binder { value, bound_vars }
}

pub fn try_map_bound<F, U: TypeVisitable<TyCtxt<'tcx>>, E>(
Expand All @@ -1105,12 +1109,13 @@ impl<'tcx, T> Binder<'tcx, T> {
where
F: FnOnce(T) -> Result<U, E>,
{
let value = f(self.0)?;
let Binder { value, bound_vars } = self;
let value = f(value)?;
if cfg!(debug_assertions) {
let mut validator = ValidateBoundVars::new(self.1);
let mut validator = ValidateBoundVars::new(bound_vars);
value.visit_with(&mut validator);
}
Ok(Binder(value, self.1))
Ok(Binder { value, bound_vars })
}

/// Wraps a `value` in a binder, using the same bound variables as the
Expand All @@ -1126,11 +1131,7 @@ impl<'tcx, T> Binder<'tcx, T> {
where
U: TypeVisitable<TyCtxt<'tcx>>,
{
if cfg!(debug_assertions) {
let mut validator = ValidateBoundVars::new(self.bound_vars());
value.visit_with(&mut validator);
}
Binder(value, self.1)
Binder::bind_with_vars(value, self.bound_vars)
}

/// Unwraps and returns the value within, but only if it contains
Expand All @@ -1147,7 +1148,7 @@ impl<'tcx, T> Binder<'tcx, T> {
where
T: TypeVisitable<TyCtxt<'tcx>>,
{
if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
}

/// Splits the contents into two things that share the same binder
Expand All @@ -1160,22 +1161,23 @@ impl<'tcx, T> Binder<'tcx, T> {
where
F: FnOnce(T) -> (U, V),
{
let (u, v) = f(self.0);
(Binder(u, self.1), Binder(v, self.1))
let Binder { value, bound_vars } = self;
let (u, v) = f(value);
(Binder { value: u, bound_vars }, Binder { value: v, bound_vars })
}
}

impl<'tcx, T> Binder<'tcx, Option<T>> {
pub fn transpose(self) -> Option<Binder<'tcx, T>> {
let bound_vars = self.1;
self.0.map(|v| Binder(v, bound_vars))
let Binder { value, bound_vars } = self;
value.map(|value| Binder { value, bound_vars })
}
}

impl<'tcx, T: IntoIterator> Binder<'tcx, T> {
pub fn iter(self) -> impl Iterator<Item = ty::Binder<'tcx, T::Item>> {
let bound_vars = self.1;
self.0.into_iter().map(|v| Binder(v, bound_vars))
let Binder { value, bound_vars } = self;
value.into_iter().map(|value| Binder { value, bound_vars })
}
}

Expand All @@ -1184,7 +1186,7 @@ where
T: IntoDiagnosticArg,
{
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
self.0.into_diagnostic_arg()
self.value.into_diagnostic_arg()
}
}

Expand Down
53 changes: 28 additions & 25 deletions compiler/rustc_middle/src/ty/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,19 +538,21 @@ impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for &'tcx
/// [`subst_identity`](EarlyBinder::subst_identity) or [`skip_binder`](EarlyBinder::skip_binder).
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[derive(Encodable, Decodable, HashStable)]
pub struct EarlyBinder<T>(T);
pub struct EarlyBinder<T> {
value: T,
}

/// For early binders, you should first call `subst` before using any visitors.
impl<'tcx, T> !TypeFoldable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
impl<'tcx, T> !TypeVisitable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}

impl<T> EarlyBinder<T> {
pub fn bind(inner: T) -> EarlyBinder<T> {
EarlyBinder(inner)
pub fn bind(value: T) -> EarlyBinder<T> {
EarlyBinder { value }
}

pub fn as_ref(&self) -> EarlyBinder<&T> {
EarlyBinder(&self.0)
EarlyBinder { value: &self.value }
}

pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U>
Expand All @@ -564,20 +566,20 @@ impl<T> EarlyBinder<T> {
where
F: FnOnce(T) -> U,
{
let value = f(self.0);
EarlyBinder(value)
let value = f(self.value);
EarlyBinder { value }
}

pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E>
where
F: FnOnce(T) -> Result<U, E>,
{
let value = f(self.0)?;
Ok(EarlyBinder(value))
let value = f(self.value)?;
Ok(EarlyBinder { value })
}

pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> {
EarlyBinder(value)
EarlyBinder { value }
}

/// Skips the binder and returns the "bound" value.
Expand All @@ -592,19 +594,20 @@ impl<T> EarlyBinder<T> {
/// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is
/// the analogous operation on [`super::Binder`].
pub fn skip_binder(self) -> T {
self.0
self.value
}
}

impl<T> EarlyBinder<Option<T>> {
pub fn transpose(self) -> Option<EarlyBinder<T>> {
self.0.map(|v| EarlyBinder(v))
self.value.map(|value| EarlyBinder { value })
}
}

impl<T, U> EarlyBinder<(T, U)> {
pub fn transpose_tuple2(self) -> (EarlyBinder<T>, EarlyBinder<U>) {
(EarlyBinder(self.0.0), EarlyBinder(self.0.1))
let EarlyBinder { value: (lhs, rhs) } = self;
(EarlyBinder { value: lhs }, EarlyBinder { value: rhs })
}
}

Expand All @@ -617,13 +620,13 @@ where
tcx: TyCtxt<'tcx>,
substs: &'s [GenericArg<'tcx>],
) -> SubstIter<'s, 'tcx, I> {
SubstIter { it: self.0.into_iter(), tcx, substs }
SubstIter { it: self.value.into_iter(), tcx, substs }
}

/// Similar to [`subst_identity`](EarlyBinder::subst_identity),
/// but on an iterator of `TypeFoldable` values.
pub fn subst_identity_iter(self) -> I::IntoIter {
self.0.into_iter()
self.value.into_iter()
}
}

Expand All @@ -640,7 +643,7 @@ where
type Item = I::Item;

fn next(&mut self) -> Option<Self::Item> {
Some(EarlyBinder(self.it.next()?).subst(self.tcx, self.substs))
Some(EarlyBinder { value: self.it.next()? }.subst(self.tcx, self.substs))
}

fn size_hint(&self) -> (usize, Option<usize>) {
Expand All @@ -654,7 +657,7 @@ where
I::Item: TypeFoldable<TyCtxt<'tcx>>,
{
fn next_back(&mut self) -> Option<Self::Item> {
Some(EarlyBinder(self.it.next_back()?).subst(self.tcx, self.substs))
Some(EarlyBinder { value: self.it.next_back()? }.subst(self.tcx, self.substs))
}
}

Expand All @@ -675,13 +678,13 @@ where
tcx: TyCtxt<'tcx>,
substs: &'s [GenericArg<'tcx>],
) -> SubstIterCopied<'s, 'tcx, I> {
SubstIterCopied { it: self.0.into_iter(), tcx, substs }
SubstIterCopied { it: self.value.into_iter(), tcx, substs }
}

/// Similar to [`subst_identity`](EarlyBinder::subst_identity),
/// but on an iterator of values that deref to a `TypeFoldable`.
pub fn subst_identity_iter_copied(self) -> impl Iterator<Item = <I::Item as Deref>::Target> {
self.0.into_iter().map(|v| *v)
self.value.into_iter().map(|v| *v)
}
}

Expand All @@ -699,7 +702,7 @@ where
type Item = <I::Item as Deref>::Target;

fn next(&mut self) -> Option<Self::Item> {
Some(EarlyBinder(*self.it.next()?).subst(self.tcx, self.substs))
self.it.next().map(|value| EarlyBinder { value: *value }.subst(self.tcx, self.substs))
}

fn size_hint(&self) -> (usize, Option<usize>) {
Expand All @@ -714,7 +717,7 @@ where
<I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>,
{
fn next_back(&mut self) -> Option<Self::Item> {
Some(EarlyBinder(*self.it.next_back()?).subst(self.tcx, self.substs))
self.it.next_back().map(|value| EarlyBinder { value: *value }.subst(self.tcx, self.substs))
}
}

Expand All @@ -732,15 +735,15 @@ pub struct EarlyBinderIter<T> {

impl<T: IntoIterator> EarlyBinder<T> {
pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> {
EarlyBinderIter { t: self.0.into_iter() }
EarlyBinderIter { t: self.value.into_iter() }
}
}

impl<T: Iterator> Iterator for EarlyBinderIter<T> {
type Item = EarlyBinder<T::Item>;

fn next(&mut self) -> Option<Self::Item> {
self.t.next().map(|i| EarlyBinder(i))
self.t.next().map(|value| EarlyBinder { value })
}

fn size_hint(&self) -> (usize, Option<usize>) {
Expand All @@ -751,7 +754,7 @@ impl<T: Iterator> Iterator for EarlyBinderIter<T> {
impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> {
pub fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T {
let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
self.0.fold_with(&mut folder)
self.value.fold_with(&mut folder)
}

/// Makes the identity substitution `T0 => T0, ..., TN => TN`.
Expand All @@ -763,12 +766,12 @@ impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> {
/// - Inside of the body of `foo`, we treat `T` as a placeholder by calling
/// `subst_identity` to discharge the `EarlyBinder`.
pub fn subst_identity(self) -> T {
self.0
self.value
}

/// Returns the inner value, but only if it contains no bound vars.
pub fn no_bound_vars(self) -> Option<T> {
if !self.0.has_param() { Some(self.0) } else { None }
if !self.value.has_param() { Some(self.value) } else { None }
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/chalkify/bugs/async.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ LL | async fn foo(x: u32) -> u32 {
= help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]`
= note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited

error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ... }, Term::Ty(u32)), []), depth=0)`
error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder { value: ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ... }, Term::Ty(u32)), bound_vars: [] }, depth=0)`
--> $DIR/async.rs:23:25
|
LL | async fn foo(x: u32) -> u32 {
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/traits/cache-reached-depth-ice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ fn test<X: ?Sized + Send>() {}

fn main() {
test::<A>();
//~^ ERROR evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk)
//~^ ERROR evaluate(Binder { value: TraitPredicate(<A as std::marker::Send>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk)
}
2 changes: 1 addition & 1 deletion tests/ui/traits/cache-reached-depth-ice.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk)
error: evaluate(Binder { value: TraitPredicate(<A as std::marker::Send>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk)
--> $DIR/cache-reached-depth-ice.rs:43:5
|
LL | fn test<X: ?Sized + Send>() {}
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/traits/issue-83538-tainted-cache-after-cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ fn main() {
// Key is that Vec<First> is "ok" and Third<'_, Ty> is "ok modulo regions":

forward();
//~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
//~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
//~^ ERROR evaluate(Binder { value: TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk)
//~| ERROR evaluate(Binder { value: TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions)

reverse();
//~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
//~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
//~^ ERROR evaluate(Binder { value: TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk)
//~| ERROR evaluate(Binder { value: TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions)
}
Loading