Skip to content
/ rust Public
forked from rust-lang/rust

Commit efb1e3d

Browse files
committed
Auto merge of rust-lang#139768 - compiler-errors:split-fold, r=lcnr
Split `TypeFolder` and `FallibleTypeFolder` atwain Right now there is a coherence problem with `TypeFolder` and `FallibleTypeFolder`. Namely, it's impossible to implement a `FallibleTypeFolder` that is generic over interner, b/c it has a *downstream* conflict with the blanket impl: ``` impl<I, F> FallibleTypeFolder<I> for F where F: TypeFolder<I> {} ``` Because downstream crates may implement `TypeFolder<SomeLocalInterner>` for the fallible type folder. This PR removes the relationship between `FallibleTypeFolder` and `TypeFolder`; it leads to *modest* code duplication, but otherwise does not affect perf and really doesn't matter in general.
2 parents cacb9ee + c774adc commit efb1e3d

File tree

12 files changed

+402
-218
lines changed

12 files changed

+402
-218
lines changed

compiler/rustc_infer/src/traits/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::hash::{Hash, Hasher};
1212

1313
use hir::def_id::LocalDefId;
1414
use rustc_hir as hir;
15+
use rustc_macros::{TypeFoldable, TypeVisitable};
1516
use rustc_middle::traits::query::NoSolution;
1617
use rustc_middle::traits::solve::Certainty;
1718
pub use rustc_middle::traits::*;
@@ -35,9 +36,11 @@ use crate::infer::InferCtxt;
3536
/// either identifying an `impl` (e.g., `impl Eq for i32`) that
3637
/// satisfies the obligation, or else finding a bound that is in
3738
/// scope. The eventual result is usually a `Selection` (defined below).
38-
#[derive(Clone)]
39+
#[derive(Clone, TypeFoldable, TypeVisitable)]
3940
pub struct Obligation<'tcx, T> {
4041
/// The reason we have to prove this thing.
42+
#[type_foldable(identity)]
43+
#[type_visitable(ignore)]
4144
pub cause: ObligationCause<'tcx>,
4245

4346
/// The environment in which we should prove this thing.
@@ -51,6 +54,8 @@ pub struct Obligation<'tcx, T> {
5154
/// If this goes over a certain threshold, we abort compilation --
5255
/// in such cases, we can not say whether or not the predicate
5356
/// holds for certain. Stupid halting problem; such a drag.
57+
#[type_foldable(identity)]
58+
#[type_visitable(ignore)]
5459
pub recursion_depth: usize,
5560
}
5661

Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use std::fmt;
22

3-
use rustc_middle::ty::{
4-
self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, try_visit,
5-
};
3+
use rustc_middle::ty;
64

75
use crate::traits;
86
use crate::traits::project::Normalized;
@@ -34,31 +32,3 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
3432
write!(f, "MismatchedProjectionTypes({:?})", self.err)
3533
}
3634
}
37-
38-
///////////////////////////////////////////////////////////////////////////
39-
// TypeFoldable implementations.
40-
41-
impl<'tcx, O: TypeFoldable<TyCtxt<'tcx>>> TypeFoldable<TyCtxt<'tcx>>
42-
for traits::Obligation<'tcx, O>
43-
{
44-
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
45-
self,
46-
folder: &mut F,
47-
) -> Result<Self, F::Error> {
48-
Ok(traits::Obligation {
49-
cause: self.cause,
50-
recursion_depth: self.recursion_depth,
51-
predicate: self.predicate.try_fold_with(folder)?,
52-
param_env: self.param_env.try_fold_with(folder)?,
53-
})
54-
}
55-
}
56-
57-
impl<'tcx, O: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>>
58-
for traits::Obligation<'tcx, O>
59-
{
60-
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
61-
try_visit!(self.predicate.visit_with(visitor));
62-
self.param_env.visit_with(visitor)
63-
}
64-
}

compiler/rustc_macros/src/type_foldable.rs

+43-17
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,13 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m
1414

1515
s.add_bounds(synstructure::AddBounds::Generics);
1616
s.bind_with(|_| synstructure::BindStyle::Move);
17-
let body_fold = s.each_variant(|vi| {
17+
let try_body_fold = s.each_variant(|vi| {
1818
let bindings = vi.bindings();
1919
vi.construct(|_, index| {
2020
let bind = &bindings[index];
2121

22-
let mut fixed = false;
23-
2422
// retain value of fields with #[type_foldable(identity)]
25-
bind.ast().attrs.iter().for_each(|x| {
26-
if !x.path().is_ident("type_foldable") {
27-
return;
28-
}
29-
let _ = x.parse_nested_meta(|nested| {
30-
if nested.path.is_ident("identity") {
31-
fixed = true;
32-
}
33-
Ok(())
34-
});
35-
});
36-
37-
if fixed {
23+
if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
3824
bind.to_token_stream()
3925
} else {
4026
quote! {
@@ -44,15 +30,55 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m
4430
})
4531
});
4632

33+
let body_fold = s.each_variant(|vi| {
34+
let bindings = vi.bindings();
35+
vi.construct(|_, index| {
36+
let bind = &bindings[index];
37+
38+
// retain value of fields with #[type_foldable(identity)]
39+
if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
40+
bind.to_token_stream()
41+
} else {
42+
quote! {
43+
::rustc_middle::ty::TypeFoldable::fold_with(#bind, __folder)
44+
}
45+
}
46+
})
47+
});
48+
4749
s.bound_impl(
4850
quote!(::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>),
4951
quote! {
5052
fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(
5153
self,
5254
__folder: &mut __F
5355
) -> Result<Self, __F::Error> {
54-
Ok(match self { #body_fold })
56+
Ok(match self { #try_body_fold })
57+
}
58+
59+
fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(
60+
self,
61+
__folder: &mut __F
62+
) -> Self {
63+
match self { #body_fold }
5564
}
5665
},
5766
)
5867
}
68+
69+
fn has_ignore_attr(attrs: &[syn::Attribute], name: &'static str, meta: &'static str) -> bool {
70+
let mut ignored = false;
71+
attrs.iter().for_each(|attr| {
72+
if !attr.path().is_ident(name) {
73+
return;
74+
}
75+
let _ = attr.parse_nested_meta(|nested| {
76+
if nested.path.is_ident(meta) {
77+
ignored = true;
78+
}
79+
Ok(())
80+
});
81+
});
82+
83+
ignored
84+
}

compiler/rustc_middle/src/infer/canonical.rs

-9
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,6 @@ pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo<TyCtxt<'tcx>>;
3939
pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
4040
pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
4141

42-
impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
43-
fn try_fold_with<F: ty::FallibleTypeFolder<TyCtxt<'tcx>>>(
44-
self,
45-
folder: &mut F,
46-
) -> Result<Self, F::Error> {
47-
ty::util::fold_list(self, folder, |tcx, v| tcx.mk_canonical_var_infos(v))
48-
}
49-
}
50-
5142
/// When we canonicalize a value to form a query, we wind up replacing
5243
/// various parts of it with canonical variables. This struct stores
5344
/// those replaced bits to remember for when we process the query

compiler/rustc_middle/src/mir/syntax.rs

+4
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,8 @@ pub enum TerminatorKind<'tcx> {
931931
asm_macro: InlineAsmMacro,
932932

933933
/// The template for the inline assembly, with placeholders.
934+
#[type_foldable(identity)]
935+
#[type_visitable(ignore)]
934936
template: &'tcx [InlineAsmTemplatePiece],
935937

936938
/// The operands for the inline assembly, as `Operand`s or `Place`s.
@@ -941,6 +943,8 @@ pub enum TerminatorKind<'tcx> {
941943

942944
/// Source spans for each line of the inline assembly code. These are
943945
/// used to map assembler errors back to the line in the source code.
946+
#[type_foldable(identity)]
947+
#[type_visitable(ignore)]
944948
line_spans: &'tcx [Span],
945949

946950
/// Valid targets for the inline assembly.

compiler/rustc_middle/src/ty/generic_args.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use smallvec::SmallVec;
1717
use crate::ty::codec::{TyDecoder, TyEncoder};
1818
use crate::ty::{
1919
self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder, InlineConstArgs,
20-
Lift, List, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, VisitorResult,
20+
Lift, List, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, VisitorResult,
2121
walk_visitable_list,
2222
};
2323

@@ -337,6 +337,14 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArg<'tcx> {
337337
GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
338338
}
339339
}
340+
341+
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
342+
match self.unpack() {
343+
GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(),
344+
GenericArgKind::Type(ty) => ty.fold_with(folder).into(),
345+
GenericArgKind::Const(ct) => ct.fold_with(folder).into(),
346+
}
347+
}
340348
}
341349

342350
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for GenericArg<'tcx> {
@@ -606,6 +614,27 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> {
606614
}
607615
}
608616
0 => Ok(self),
617+
_ => ty::util::try_fold_list(self, folder, |tcx, v| tcx.mk_args(v)),
618+
}
619+
}
620+
621+
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
622+
// See justification for this behavior in `try_fold_with`.
623+
match self.len() {
624+
1 => {
625+
let param0 = self[0].fold_with(folder);
626+
if param0 == self[0] { self } else { folder.cx().mk_args(&[param0]) }
627+
}
628+
2 => {
629+
let param0 = self[0].fold_with(folder);
630+
let param1 = self[1].fold_with(folder);
631+
if param0 == self[0] && param1 == self[1] {
632+
self
633+
} else {
634+
folder.cx().mk_args(&[param0, param1])
635+
}
636+
}
637+
0 => self,
609638
_ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_args(v)),
610639
}
611640
}
@@ -641,6 +670,22 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
641670
Ok(folder.cx().mk_type_list(&[param0, param1]))
642671
}
643672
}
673+
_ => ty::util::try_fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)),
674+
}
675+
}
676+
677+
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
678+
// See comment justifying behavior in `try_fold_with`.
679+
match self.len() {
680+
2 => {
681+
let param0 = self[0].fold_with(folder);
682+
let param1 = self[1].fold_with(folder);
683+
if param0 == self[0] && param1 == self[1] {
684+
self
685+
} else {
686+
folder.cx().mk_type_list(&[param0, param1])
687+
}
688+
}
644689
_ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)),
645690
}
646691
}

compiler/rustc_middle/src/ty/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,13 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Term<'tcx> {
537537
ty::TermKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
538538
}
539539
}
540+
541+
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
542+
match self.unpack() {
543+
ty::TermKind::Ty(ty) => ty.fold_with(folder).into(),
544+
ty::TermKind::Const(ct) => ct.fold_with(folder).into(),
545+
}
546+
}
540547
}
541548

542549
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Term<'tcx> {

0 commit comments

Comments
 (0)