Skip to content

Commit f783ce9

Browse files
authored
Rollup merge of #117008 - compiler-errors:canonical, r=lcnr
Uplift `Canonical` to `rustc_type_ir` I plan on moving the new trait solver's canonicalizer into either `rustc_type_ir` or a child crate. One dependency on this is lifting `Canonical<V>` to `rustc_type_ir` so we can actually name the canonicalized values. I may also later lift `CanonicalVarInfo` into the new trait solver. I can't really tell what other changes need to be done, but I'm just putting this up sooner than later since I'm almost certain it'll need to be done regardless of other design choices. There are a couple of warts introduced by this PR, since we no longer can define inherent `Canonical` impls in `rustc_middle` -- see the changes to: * `compiler/rustc_trait_selection/src/traits/query/normalize.rs` * `compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs` r? lcnr
2 parents d30fe8b + 8f3b4f9 commit f783ce9

File tree

13 files changed

+207
-97
lines changed

13 files changed

+207
-97
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_middle::ty::error::TypeError;
2626
use rustc_middle::ty::fold::TypeFoldable;
2727
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
2828
use rustc_middle::ty::{
29-
self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType,
29+
self, AdtKind, CanonicalUserType, GenericParamDefKind, IsIdentity, Ty, TyCtxt, UserType,
3030
};
3131
use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy};
3232
use rustc_session::lint;
@@ -207,6 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
207207
) {
208208
debug!("fcx {}", self.tag());
209209

210+
// FIXME: is_identity being on `UserType` and not `Canonical<UserType>` is awkward
210211
if !canonical_user_type_annotation.is_identity() {
211212
self.typeck_results
212213
.borrow_mut()

compiler/rustc_middle/src/infer/canonical.rs

+6-74
Original file line numberDiff line numberDiff line change
@@ -21,35 +21,17 @@
2121
//!
2222
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
2323
24-
use crate::infer::MemberConstraint;
25-
use crate::mir::ConstraintCategory;
26-
use crate::ty::GenericArg;
27-
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
2824
use rustc_macros::HashStable;
25+
use rustc_type_ir::Canonical as IrCanonical;
2926
use smallvec::SmallVec;
30-
use std::fmt::Display;
3127
use std::ops::Index;
3228

33-
/// A "canonicalized" type `V` is one where all free inference
34-
/// variables have been rewritten to "canonical vars". These are
35-
/// numbered starting from 0 in order of first appearance.
36-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
37-
#[derive(HashStable, TypeFoldable, TypeVisitable)]
38-
pub struct Canonical<'tcx, V> {
39-
pub value: V,
40-
pub max_universe: ty::UniverseIndex,
41-
pub variables: CanonicalVarInfos<'tcx>,
42-
}
29+
use crate::infer::MemberConstraint;
30+
use crate::mir::ConstraintCategory;
31+
use crate::ty::GenericArg;
32+
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
4333

44-
impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> {
45-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46-
write!(
47-
f,
48-
"Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
49-
self.value, self.max_universe, self.variables
50-
)
51-
}
52-
}
34+
pub type Canonical<'tcx, V> = IrCanonical<TyCtxt<'tcx>, V>;
5335

5436
pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
5537

@@ -379,56 +361,6 @@ impl<'tcx, R> QueryResponse<'tcx, R> {
379361
}
380362
}
381363

382-
impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
383-
pub fn is_proven(&self) -> bool {
384-
self.value.is_proven()
385-
}
386-
387-
pub fn is_ambiguous(&self) -> bool {
388-
!self.is_proven()
389-
}
390-
}
391-
392-
impl<'tcx, V> Canonical<'tcx, V> {
393-
/// Allows you to map the `value` of a canonical while keeping the
394-
/// same set of bound variables.
395-
///
396-
/// **WARNING:** This function is very easy to mis-use, hence the
397-
/// name! In particular, the new value `W` must use all **the
398-
/// same type/region variables** in **precisely the same order**
399-
/// as the original! (The ordering is defined by the
400-
/// `TypeFoldable` implementation of the type in question.)
401-
///
402-
/// An example of a **correct** use of this:
403-
///
404-
/// ```rust,ignore (not real code)
405-
/// let a: Canonical<'_, T> = ...;
406-
/// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
407-
/// ```
408-
///
409-
/// An example of an **incorrect** use of this:
410-
///
411-
/// ```rust,ignore (not real code)
412-
/// let a: Canonical<'tcx, T> = ...;
413-
/// let ty: Ty<'tcx> = ...;
414-
/// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
415-
/// ```
416-
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> {
417-
let Canonical { max_universe, variables, value } = self;
418-
Canonical { max_universe, variables, value: map_op(value) }
419-
}
420-
421-
/// Allows you to map the `value` of a canonical while keeping the same set of
422-
/// bound variables.
423-
///
424-
/// **WARNING:** This function is very easy to mis-use, hence the name! See
425-
/// the comment of [Canonical::unchecked_map] for more details.
426-
pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> {
427-
let Canonical { max_universe, variables, value: _ } = self;
428-
Canonical { max_universe, variables, value }
429-
}
430-
}
431-
432364
pub type QueryOutlivesConstraint<'tcx> =
433365
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
434366

compiler/rustc_middle/src/ty/context.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub mod tls;
66

77
use crate::arena::Arena;
88
use crate::dep_graph::{DepGraph, DepKindStruct};
9-
use crate::infer::canonical::CanonicalVarInfo;
9+
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
1010
use crate::lint::struct_lint_level;
1111
use crate::metadata::ModChild;
1212
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
@@ -88,6 +88,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
8888

8989
type Binder<T> = Binder<'tcx, T>;
9090
type TypeAndMut = TypeAndMut<'tcx>;
91+
type CanonicalVars = CanonicalVarInfos<'tcx>;
9192

9293
type Ty = Ty<'tcx>;
9394
type Tys = &'tcx List<Ty<'tcx>>;

compiler/rustc_middle/src/ty/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ pub use self::sty::{
106106
};
107107
pub use self::trait_def::TraitDef;
108108
pub use self::typeck_results::{
109-
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, TypeckResults,
110-
UserType, UserTypeAnnotationIndex,
109+
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
110+
TypeckResults, UserType, UserTypeAnnotationIndex,
111111
};
112112

113113
pub mod _match;

compiler/rustc_middle/src/ty/structural_impls.rs

-1
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,6 @@ TrivialTypeTraversalImpls! {
449449
crate::ty::IntVarValue,
450450
crate::ty::adjustment::PointerCoercion,
451451
crate::ty::RegionVid,
452-
crate::ty::UniverseIndex,
453452
crate::ty::Variance,
454453
::rustc_span::Span,
455454
::rustc_span::symbol::Ident,

compiler/rustc_middle/src/ty/typeck_results.rs

+19-15
Original file line numberDiff line numberDiff line change
@@ -594,10 +594,27 @@ pub struct CanonicalUserTypeAnnotation<'tcx> {
594594
/// Canonical user type annotation.
595595
pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
596596

597-
impl<'tcx> CanonicalUserType<'tcx> {
597+
/// A user-given type annotation attached to a constant. These arise
598+
/// from constants that are named via paths, like `Foo::<A>::new` and
599+
/// so forth.
600+
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
601+
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
602+
pub enum UserType<'tcx> {
603+
Ty(Ty<'tcx>),
604+
605+
/// The canonical type is the result of `type_of(def_id)` with the
606+
/// given substitutions applied.
607+
TypeOf(DefId, UserArgs<'tcx>),
608+
}
609+
610+
pub trait IsIdentity {
611+
fn is_identity(&self) -> bool;
612+
}
613+
614+
impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
598615
/// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
599616
/// i.e., each thing is mapped to a canonical variable with the same index.
600-
pub fn is_identity(&self) -> bool {
617+
fn is_identity(&self) -> bool {
601618
match self.value {
602619
UserType::Ty(_) => false,
603620
UserType::TypeOf(_, user_args) => {
@@ -640,19 +657,6 @@ impl<'tcx> CanonicalUserType<'tcx> {
640657
}
641658
}
642659

643-
/// A user-given type annotation attached to a constant. These arise
644-
/// from constants that are named via paths, like `Foo::<A>::new` and
645-
/// so forth.
646-
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
647-
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
648-
pub enum UserType<'tcx> {
649-
Ty(Ty<'tcx>),
650-
651-
/// The canonical type is the result of `type_of(def_id)` with the
652-
/// given substitutions applied.
653-
TypeOf(DefId, UserArgs<'tcx>),
654-
}
655-
656660
impl<'tcx> std::fmt::Display for UserType<'tcx> {
657661
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
658662
match self {

compiler/rustc_trait_selection/src/traits/query/normalize.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
293293
_ => unreachable!(),
294294
}?;
295295
// We don't expect ambiguity.
296-
if result.is_ambiguous() {
296+
if !result.value.is_proven() {
297297
// Rustdoc normalizes possibly not well-formed types, so only
298298
// treat this as a bug if we're not in rustdoc.
299299
if !tcx.sess.opts.actually_rustdoc {
+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
use std::fmt;
2+
use std::hash;
3+
use std::ops::ControlFlow;
4+
5+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
6+
use rustc_serialize::{Decodable, Encodable};
7+
8+
use crate::fold::{FallibleTypeFolder, TypeFoldable};
9+
use crate::visit::{TypeVisitable, TypeVisitor};
10+
use crate::TyDecoder;
11+
use crate::{HashStableContext, Interner, TyEncoder, UniverseIndex};
12+
13+
/// A "canonicalized" type `V` is one where all free inference
14+
/// variables have been rewritten to "canonical vars". These are
15+
/// numbered starting from 0 in order of first appearance.
16+
pub struct Canonical<I: Interner, V> {
17+
pub value: V,
18+
pub max_universe: UniverseIndex,
19+
pub variables: I::CanonicalVars,
20+
}
21+
22+
impl<I: Interner, V> Canonical<I, V> {
23+
/// Allows you to map the `value` of a canonical while keeping the
24+
/// same set of bound variables.
25+
///
26+
/// **WARNING:** This function is very easy to mis-use, hence the
27+
/// name! In particular, the new value `W` must use all **the
28+
/// same type/region variables** in **precisely the same order**
29+
/// as the original! (The ordering is defined by the
30+
/// `TypeFoldable` implementation of the type in question.)
31+
///
32+
/// An example of a **correct** use of this:
33+
///
34+
/// ```rust,ignore (not real code)
35+
/// let a: Canonical<I, T> = ...;
36+
/// let b: Canonical<I, (T,)> = a.unchecked_map(|v| (v, ));
37+
/// ```
38+
///
39+
/// An example of an **incorrect** use of this:
40+
///
41+
/// ```rust,ignore (not real code)
42+
/// let a: Canonical<I, T> = ...;
43+
/// let ty: Ty<I> = ...;
44+
/// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty));
45+
/// ```
46+
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
47+
let Canonical { max_universe, variables, value } = self;
48+
Canonical { max_universe, variables, value: map_op(value) }
49+
}
50+
51+
/// Allows you to map the `value` of a canonical while keeping the same set of
52+
/// bound variables.
53+
///
54+
/// **WARNING:** This function is very easy to mis-use, hence the name! See
55+
/// the comment of [Canonical::unchecked_map] for more details.
56+
pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> {
57+
let Canonical { max_universe, variables, value: _ } = self;
58+
Canonical { max_universe, variables, value }
59+
}
60+
}
61+
62+
impl<I: Interner, V: hash::Hash> hash::Hash for Canonical<I, V> {
63+
fn hash<H: hash::Hasher>(&self, state: &mut H) {
64+
self.value.hash(state);
65+
self.max_universe.hash(state);
66+
self.variables.hash(state);
67+
}
68+
}
69+
70+
impl<CTX: HashStableContext, I: Interner, V: HashStable<CTX>> HashStable<CTX> for Canonical<I, V>
71+
where
72+
I::CanonicalVars: HashStable<CTX>,
73+
{
74+
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
75+
self.value.hash_stable(hcx, hasher);
76+
self.max_universe.hash_stable(hcx, hasher);
77+
self.variables.hash_stable(hcx, hasher);
78+
}
79+
}
80+
81+
impl<I: Interner, V: Eq> Eq for Canonical<I, V> {}
82+
83+
impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> {
84+
fn eq(&self, other: &Self) -> bool {
85+
self.value == other.value
86+
&& self.max_universe == other.max_universe
87+
&& self.variables == other.variables
88+
}
89+
}
90+
91+
impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
92+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93+
write!(
94+
f,
95+
"Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
96+
self.value, self.max_universe, self.variables
97+
)
98+
}
99+
}
100+
101+
impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> {
102+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103+
f.debug_struct("Canonical")
104+
.field("value", &self.value)
105+
.field("max_universe", &self.max_universe)
106+
.field("variables", &self.variables)
107+
.finish()
108+
}
109+
}
110+
111+
impl<I: Interner, V: Clone> Clone for Canonical<I, V> {
112+
fn clone(&self) -> Self {
113+
Canonical {
114+
value: self.value.clone(),
115+
max_universe: self.max_universe.clone(),
116+
variables: self.variables.clone(),
117+
}
118+
}
119+
}
120+
121+
impl<I: Interner, V: Copy> Copy for Canonical<I, V> where I::CanonicalVars: Copy {}
122+
123+
impl<I: Interner, V: TypeFoldable<I>> TypeFoldable<I> for Canonical<I, V>
124+
where
125+
I::CanonicalVars: TypeFoldable<I>,
126+
{
127+
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
128+
Ok(Canonical {
129+
value: self.value.try_fold_with(folder)?,
130+
max_universe: self.max_universe.try_fold_with(folder)?,
131+
variables: self.variables.try_fold_with(folder)?,
132+
})
133+
}
134+
}
135+
136+
impl<I: Interner, V: TypeVisitable<I>> TypeVisitable<I> for Canonical<I, V>
137+
where
138+
I::CanonicalVars: TypeVisitable<I>,
139+
{
140+
fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> ControlFlow<F::BreakTy> {
141+
self.value.visit_with(folder)?;
142+
self.max_universe.visit_with(folder)?;
143+
self.variables.visit_with(folder)
144+
}
145+
}
146+
147+
impl<I: Interner, E: TyEncoder<I = I>, V: Encodable<E>> Encodable<E> for Canonical<I, V>
148+
where
149+
I::CanonicalVars: Encodable<E>,
150+
{
151+
fn encode(&self, s: &mut E) {
152+
self.value.encode(s);
153+
self.max_universe.encode(s);
154+
self.variables.encode(s);
155+
}
156+
}
157+
158+
impl<I: Interner, D: TyDecoder<I = I>, V: Decodable<D>> Decodable<D> for Canonical<I, V>
159+
where
160+
I::CanonicalVars: Decodable<D>,
161+
{
162+
fn decode(d: &mut D) -> Self {
163+
Canonical {
164+
value: Decodable::decode(d),
165+
max_universe: Decodable::decode(d),
166+
variables: Decodable::decode(d),
167+
}
168+
}
169+
}

compiler/rustc_type_ir/src/interner.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub trait Interner: Sized {
1818

1919
type Binder<T>;
2020
type TypeAndMut: Clone + Debug + Hash + Ord;
21+
type CanonicalVars: Clone + Debug + Hash + Eq;
2122

2223
// Kinds of tys
2324
type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord;

0 commit comments

Comments
 (0)