@@ -1683,34 +1683,59 @@ pub struct BoundConst<'tcx> {
16831683
16841684pub 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