Skip to content

Commit d577c53

Browse files
committed
Auto merge of rust-lang#78609 - lcnr:rustdoc-const-eval, r=matthewjasper
extend `WithOptConstParam` docs, move rustdoc test This should hopefully make things a bit clearer, feel free to comment on anything which can still be improved. cc `@ecstatic-morse` `@nikomatsakis` `@RalfJung`
2 parents a68864b + 4b23f40 commit d577c53

File tree

2 files changed

+38
-13
lines changed

2 files changed

+38
-13
lines changed

compiler/rustc_middle/src/ty/mod.rs

+38-13
Original file line numberDiff line numberDiff line change
@@ -1683,34 +1683,59 @@ pub struct BoundConst<'tcx> {
16831683

16841684
pub type PlaceholderConst<'tcx> = Placeholder<BoundConst<'tcx>>;
16851685

1686-
/// A `DefId` which is potentially bundled with its corresponding generic parameter
1687-
/// in case `did` is a const argument.
1686+
/// A `DefId` which, in case it is a const argument, is potentially bundled with
1687+
/// the `DefId` of the generic parameter it instantiates.
16881688
///
1689-
/// This is used to prevent cycle errors during typeck
1690-
/// as `type_of(const_arg)` depends on `typeck(owning_body)`
1691-
/// which once again requires the type of its generic arguments.
1692-
///
1693-
/// Luckily we only need to deal with const arguments once we
1694-
/// know their corresponding parameters. We (ab)use this by
1695-
/// calling `type_of(param_did)` for these arguments.
1689+
/// This is used to avoid calls to `type_of` for const arguments during typeck
1690+
/// which cause cycle errors.
16961691
///
16971692
/// ```rust
16981693
/// #![feature(const_generics)]
16991694
///
17001695
/// struct A;
17011696
/// impl A {
1702-
/// fn foo<const N: usize>(&self) -> usize { N }
1697+
/// fn foo<const N: usize>(&self) -> [u8; N] { [0; N] }
1698+
/// // ^ const parameter
17031699
/// }
17041700
/// struct B;
17051701
/// impl B {
1706-
/// fn foo<const N: u8>(&self) -> usize { 42 }
1702+
/// fn foo<const M: u8>(&self) -> usize { 42 }
1703+
/// // ^ const parameter
17071704
/// }
17081705
///
17091706
/// fn main() {
17101707
/// let a = A;
1711-
/// a.foo::<7>();
1708+
/// let _b = a.foo::<{ 3 + 7 }>();
1709+
/// // ^^^^^^^^^ const argument
17121710
/// }
17131711
/// ```
1712+
///
1713+
/// Let's look at the call `a.foo::<{ 3 + 7 }>()` here. We do not know
1714+
/// which `foo` is used until we know the type of `a`.
1715+
///
1716+
/// We only know the type of `a` once we are inside of `typeck(main)`.
1717+
/// We also end up normalizing the type of `_b` during `typeck(main)` which
1718+
/// requires us to evaluate the const argument.
1719+
///
1720+
/// To evaluate that const argument we need to know its type,
1721+
/// which we would get using `type_of(const_arg)`. This requires us to
1722+
/// resolve `foo` as it can be either `usize` or `u8` in this example.
1723+
/// However, resolving `foo` once again requires `typeck(main)` to get the type of `a`,
1724+
/// which results in a cycle.
1725+
///
1726+
/// In short we must not call `type_of(const_arg)` during `typeck(main)`.
1727+
///
1728+
/// When first creating the `ty::Const` of the const argument inside of `typeck` we have
1729+
/// already resolved `foo` so we know which const parameter this argument instantiates.
1730+
/// This means that we also know the expected result of `type_of(const_arg)` even if we
1731+
/// aren't allowed to call that query: it is equal to `type_of(const_param)` which is
1732+
/// trivial to compute.
1733+
///
1734+
/// If we now want to use that constant in a place which potentionally needs its type
1735+
/// we also pass the type of its `const_param`. This is the point of `WithOptConstParam`,
1736+
/// except that instead of a `Ty` we bundle the `DefId` of the const parameter.
1737+
/// Meaning that we need to use `type_of(const_param_did)` if `const_param_did` is `Some`
1738+
/// to get the type of `did`.
17141739
#[derive(Copy, Clone, Debug, TypeFoldable, Lift, TyEncodable, TyDecodable)]
17151740
#[derive(PartialEq, Eq, PartialOrd, Ord)]
17161741
#[derive(Hash, HashStable)]
@@ -1721,7 +1746,7 @@ pub struct WithOptConstParam<T> {
17211746
///
17221747
/// Note that even if `did` is a const argument, this may still be `None`.
17231748
/// All queries taking `WithOptConstParam` start by calling `tcx.opt_const_param_of(def.did)`
1724-
/// to potentially update `param_did` in case it `None`.
1749+
/// to potentially update `param_did` in the case it is `None`.
17251750
pub const_param_did: Option<DefId>,
17261751
}
17271752

0 commit comments

Comments
 (0)