@@ -1306,6 +1306,68 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
1306
1306
}
1307
1307
}
1308
1308
1309
+ /// "Universes" are used during type- and trait-checking in the
1310
+ /// presence of `for<..>` binders to control what sets of names are
1311
+ /// visible. Universes are arranged into a tree: the root universe
1312
+ /// contains names that are always visible. But when you enter into
1313
+ /// some subuniverse, then it may add names that are only visible
1314
+ /// within that subtree (but it can still name the names of its
1315
+ /// ancestor universes).
1316
+ ///
1317
+ /// To make this more concrete, consider this program:
1318
+ ///
1319
+ /// ```
1320
+ /// struct Foo { }
1321
+ /// fn bar<T>(x: T) {
1322
+ /// let y: for<'a> fn(&'a u8, Foo) = ...;
1323
+ /// }
1324
+ /// ```
1325
+ ///
1326
+ /// The struct name `Foo` is in the root universe U0. But the type
1327
+ /// parameter `T`, introduced on `bar`, is in a subuniverse U1 --
1328
+ /// i.e., within `bar`, we can name both `T` and `Foo`, but outside of
1329
+ /// `bar`, we cannot name `T`. Then, within the type of `y`, the
1330
+ /// region `'a` is in a subuniverse U2 of U1, because we can name it
1331
+ /// inside the fn type but not outside.
1332
+ ///
1333
+ /// Universes are related to **skolemization** -- which is a way of
1334
+ /// doing type- and trait-checking around these "forall" binders (also
1335
+ /// called **universal quantification**). The idea is that when, in
1336
+ /// the body of `bar`, we refer to `T` as a type, we aren't referring
1337
+ /// to any type in particular, but rather a kind of "fresh" type that
1338
+ /// is distinct from all other types we have actually declared. This
1339
+ /// is called a **skolemized** type, and we use universes to talk
1340
+ /// about this. In other words, a type name in universe 0 always
1341
+ /// corresponds to some "ground" type that the user declared, but a
1342
+ /// type name in a non-zero universe is a skolemized type -- an
1343
+ /// idealized representative of "types in general" that we use for
1344
+ /// checking generic functions.
1345
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
1346
+ pub struct UniverseIndex ( u32 ) ;
1347
+
1348
+ impl UniverseIndex {
1349
+ /// The root universe, where things that the user defined are
1350
+ /// visible.
1351
+ pub fn root ( ) -> UniverseIndex {
1352
+ UniverseIndex ( 0 )
1353
+ }
1354
+
1355
+ /// A "subuniverse" corresponds to being inside a `forall` quantifier.
1356
+ /// So, for example, suppose we have this type in universe `U`:
1357
+ ///
1358
+ /// ```
1359
+ /// for<'a> fn(&'a u32)
1360
+ /// ```
1361
+ ///
1362
+ /// Once we "enter" into this `for<'a>` quantifier, we are in a
1363
+ /// subuniverse of `U` -- in this new universe, we can name the
1364
+ /// region `'a`, but that region was not nameable from `U` because
1365
+ /// it was not in scope there.
1366
+ pub fn subuniverse ( self ) -> UniverseIndex {
1367
+ UniverseIndex ( self . 0 + 1 )
1368
+ }
1369
+ }
1370
+
1309
1371
/// When type checking, we use the `ParamEnv` to track
1310
1372
/// details about the set of where-clauses that are in scope at this
1311
1373
/// particular point.
0 commit comments