Skip to content

Commit 024ca99

Browse files
Uplift Canonical to rustc_type_ir
1 parent b66fe58 commit 024ca99

File tree

12 files changed

+201
-95
lines changed

12 files changed

+201
-95
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
207207
) {
208208
debug!("fcx {}", self.tag());
209209

210-
if !canonical_user_type_annotation.is_identity() {
210+
// FIXME: is_identity being on `UserType` and not `Canonical<UserType>` is awkward
211+
if !canonical_user_type_annotation.value.is_identity() {
211212
self.typeck_results
212213
.borrow_mut()
213214
.user_provided_types_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/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

+15-15
Original file line numberDiff line numberDiff line change
@@ -594,11 +594,24 @@ 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+
impl<'tcx> UserType<'tcx> {
598611
/// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
599612
/// i.e., each thing is mapped to a canonical variable with the same index.
600613
pub fn is_identity(&self) -> bool {
601-
match self.value {
614+
match self {
602615
UserType::Ty(_) => false,
603616
UserType::TypeOf(_, user_args) => {
604617
if user_args.user_self_ty.is_some() {
@@ -640,19 +653,6 @@ impl<'tcx> CanonicalUserType<'tcx> {
640653
}
641654
}
642655

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-
656656
impl<'tcx> std::fmt::Display for UserType<'tcx> {
657657
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
658658
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;

compiler/rustc_type_ir/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ pub mod visit;
2626

2727
#[macro_use]
2828
mod macros;
29+
mod canonical;
2930
mod const_kind;
3031
mod debug;
3132
mod flags;
3233
mod interner;
3334
mod predicate_kind;
3435
mod region_kind;
3536

37+
pub use canonical::*;
3638
pub use codec::*;
3739
pub use const_kind::*;
3840
pub use debug::{DebugWithInfcx, InferCtxtLike, WithInfcx};

compiler/rustc_type_ir/src/macros.rs

+1
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,5 @@ TrivialTypeTraversalImpls! {
5050
String,
5151
crate::DebruijnIndex,
5252
crate::AliasRelationDirection,
53+
crate::UniverseIndex,
5354
}

compiler/rustc_type_ir/src/region_kind.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ impl<I: Interner> fmt::Debug for RegionKind<I> {
307307
}
308308

309309
// This is manually implemented because a derive would require `I: Encodable`
310-
impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I>
310+
impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for RegionKind<I>
311311
where
312312
I::EarlyBoundRegion: Encodable<E>,
313313
I::BoundRegion: Encodable<E>,

0 commit comments

Comments
 (0)