1
1
//! Traits for transforming bits of IR.
2
2
3
3
use crate :: * ;
4
+ use std:: convert:: Infallible ;
4
5
use std:: fmt:: Debug ;
5
6
6
7
mod binder_impls;
@@ -20,6 +21,11 @@ pub use self::subst::Subst;
20
21
/// `FallibleTypeFolder`, will reconstruct itself, invoking the folder's
21
22
/// methods to transform each of the types/lifetimes embedded within.
22
23
///
24
+ /// As the name suggests, folds performed by `FallibleTypeFolder` can
25
+ /// fail (with type `Error`); if the folder cannot fail, consider
26
+ /// implementing `TypeFolder` instead (which is an infallible, but
27
+ /// otherwise equivalent, trait).
28
+ ///
23
29
/// # Usage patterns
24
30
///
25
31
/// ## Substituting for free variables
@@ -316,6 +322,289 @@ pub trait FallibleTypeFolder<I: Interner> {
316
322
fn interner ( & self ) -> I ;
317
323
}
318
324
325
+ /// A "folder" is a transformer that can be used to make a copy of
326
+ /// some term -- that is, some bit of IR, such as a `Goal` -- with
327
+ /// certain changes applied. The idea is that it contains methods that
328
+ /// let you swap types/lifetimes for new types/lifetimes; meanwhile,
329
+ /// each bit of IR implements the `TypeFoldable` trait which, given a
330
+ /// `TypeFolder`, will reconstruct itself, invoking the folder's methods
331
+ /// to transform each of the types/lifetimes embedded within.
332
+ ///
333
+ /// Folds performed by `TypeFolder` cannot fail. If folds might fail,
334
+ /// consider implementing `FallibleTypeFolder` instead (which is a
335
+ /// fallible, but otherwise equivalent, trait).
336
+ ///
337
+ /// # Usage patterns
338
+ ///
339
+ /// ## Substituting for free variables
340
+ ///
341
+ /// Most of the time, though, we are not interested in adjust
342
+ /// arbitrary types/lifetimes, but rather just free variables (even
343
+ /// more often, just free existential variables) that appear within
344
+ /// the term.
345
+ ///
346
+ /// For this reason, the `TypeFolder` trait extends two other traits that
347
+ /// contain methods that are invoked when just those particular
348
+ ///
349
+ /// In particular, folders can intercept references to free variables
350
+ /// (either existentially or universally quantified) and replace them
351
+ /// with other types/lifetimes as appropriate.
352
+ ///
353
+ /// To create a folder `F`, one never implements `TypeFolder` directly, but instead
354
+ /// implements one of each of these three sub-traits:
355
+ ///
356
+ /// - `FreeVarFolder` -- folds `BoundVar` instances that appear free
357
+ /// in the term being folded (use `DefaultFreeVarFolder` to
358
+ /// ignore/forbid these altogether)
359
+ /// - `InferenceFolder` -- folds existential `InferenceVar` instances
360
+ /// that appear in the term being folded (use
361
+ /// `DefaultInferenceFolder` to ignore/forbid these altogether)
362
+ /// - `PlaceholderFolder` -- folds universal `Placeholder` instances
363
+ /// that appear in the term being folded (use
364
+ /// `DefaultPlaceholderFolder` to ignore/forbid these altogether)
365
+ ///
366
+ /// To **apply** a folder, use the `TypeFoldable::fold_with` method, like so
367
+ ///
368
+ /// ```rust,ignore
369
+ /// let x = x.fold_with(&mut folder, 0);
370
+ /// ```
371
+ pub trait TypeFolder < I : Interner > : FallibleTypeFolder < I , Error = Infallible > {
372
+ /// Creates a `dyn` value from this folder. Unfortunately, this
373
+ /// must be added manually to each impl of TypeFolder; it permits the
374
+ /// default implements below to create a `&mut dyn TypeFolder` from
375
+ /// `Self` without knowing what `Self` is (by invoking this
376
+ /// method). Effectively, this limits impls of `TypeFolder` to types
377
+ /// for which we are able to create a dyn value (i.e., not `[T]`
378
+ /// types).
379
+ fn as_dyn ( & mut self ) -> & mut dyn TypeFolder < I > ;
380
+
381
+ /// Top-level callback: invoked for each `Ty<I>` that is
382
+ /// encountered when folding. By default, invokes
383
+ /// `super_fold_with`, which will in turn invoke the more
384
+ /// specialized folding methods below, like `fold_free_var_ty`.
385
+ fn fold_ty ( & mut self , ty : Ty < I > , outer_binder : DebruijnIndex ) -> Ty < I > {
386
+ ty. super_fold_with ( TypeFolder :: as_dyn ( self ) , outer_binder)
387
+ }
388
+
389
+ /// Top-level callback: invoked for each `Lifetime<I>` that is
390
+ /// encountered when folding. By default, invokes
391
+ /// `super_fold_with`, which will in turn invoke the more
392
+ /// specialized folding methods below, like `fold_free_var_lifetime`.
393
+ fn fold_lifetime ( & mut self , lifetime : Lifetime < I > , outer_binder : DebruijnIndex ) -> Lifetime < I > {
394
+ lifetime. super_fold_with ( TypeFolder :: as_dyn ( self ) , outer_binder)
395
+ }
396
+
397
+ /// Top-level callback: invoked for each `Const<I>` that is
398
+ /// encountered when folding. By default, invokes
399
+ /// `super_fold_with`, which will in turn invoke the more
400
+ /// specialized folding methods below, like `fold_free_var_const`.
401
+ fn fold_const ( & mut self , constant : Const < I > , outer_binder : DebruijnIndex ) -> Const < I > {
402
+ constant. super_fold_with ( TypeFolder :: as_dyn ( self ) , outer_binder)
403
+ }
404
+
405
+ /// Invoked for every program clause. By default, recursively folds the goals contents.
406
+ fn fold_program_clause (
407
+ & mut self ,
408
+ clause : ProgramClause < I > ,
409
+ outer_binder : DebruijnIndex ,
410
+ ) -> ProgramClause < I > {
411
+ clause. super_fold_with ( TypeFolder :: as_dyn ( self ) , outer_binder)
412
+ }
413
+
414
+ /// Invoked for every goal. By default, recursively folds the goals contents.
415
+ fn fold_goal ( & mut self , goal : Goal < I > , outer_binder : DebruijnIndex ) -> Goal < I > {
416
+ goal. super_fold_with ( TypeFolder :: as_dyn ( self ) , outer_binder)
417
+ }
418
+
419
+ /// If overridden to return true, then folding will panic if a
420
+ /// free variable is encountered. This should be done if free
421
+ /// type/lifetime variables are not expected.
422
+ fn forbid_free_vars ( & self ) -> bool {
423
+ false
424
+ }
425
+
426
+ /// Invoked for `TyKind::BoundVar` instances that are not bound
427
+ /// within the type being folded over:
428
+ ///
429
+ /// - `depth` is the depth of the `TyKind::BoundVar`; this has
430
+ /// been adjusted to account for binders in scope.
431
+ /// - `binders` is the number of binders in scope.
432
+ ///
433
+ /// This should return a type suitable for a context with
434
+ /// `binders` in scope.
435
+ fn fold_free_var_ty ( & mut self , bound_var : BoundVar , outer_binder : DebruijnIndex ) -> Ty < I > {
436
+ if TypeFolder :: forbid_free_vars ( self ) {
437
+ panic ! (
438
+ "unexpected free variable with depth `{:?}` with outer binder {:?}" ,
439
+ bound_var, outer_binder
440
+ )
441
+ } else {
442
+ let bound_var = bound_var. shifted_in_from ( outer_binder) ;
443
+ TyKind :: < I > :: BoundVar ( bound_var) . intern ( TypeFolder :: interner ( self ) )
444
+ }
445
+ }
446
+
447
+ /// As `fold_free_var_ty`, but for lifetimes.
448
+ fn fold_free_var_lifetime (
449
+ & mut self ,
450
+ bound_var : BoundVar ,
451
+ outer_binder : DebruijnIndex ,
452
+ ) -> Lifetime < I > {
453
+ if TypeFolder :: forbid_free_vars ( self ) {
454
+ panic ! (
455
+ "unexpected free variable with depth `{:?}` with outer binder {:?}" ,
456
+ bound_var, outer_binder
457
+ )
458
+ } else {
459
+ let bound_var = bound_var. shifted_in_from ( outer_binder) ;
460
+ LifetimeData :: < I > :: BoundVar ( bound_var) . intern ( TypeFolder :: interner ( self ) )
461
+ }
462
+ }
463
+
464
+ /// As `fold_free_var_ty`, but for constants.
465
+ fn fold_free_var_const (
466
+ & mut self ,
467
+ ty : Ty < I > ,
468
+ bound_var : BoundVar ,
469
+ outer_binder : DebruijnIndex ,
470
+ ) -> Const < I > {
471
+ if TypeFolder :: forbid_free_vars ( self ) {
472
+ panic ! (
473
+ "unexpected free variable with depth `{:?}` with outer binder {:?}" ,
474
+ bound_var, outer_binder
475
+ )
476
+ } else {
477
+ let bound_var = bound_var. shifted_in_from ( outer_binder) ;
478
+ ConstData {
479
+ ty : ty. fold_with ( TypeFolder :: as_dyn ( self ) , outer_binder) ,
480
+ value : ConstValue :: < I > :: BoundVar ( bound_var) ,
481
+ }
482
+ . intern ( TypeFolder :: interner ( self ) )
483
+ }
484
+ }
485
+
486
+ /// If overridden to return true, we will panic when a free
487
+ /// placeholder type/lifetime/const is encountered.
488
+ fn forbid_free_placeholders ( & self ) -> bool {
489
+ false
490
+ }
491
+
492
+ /// Invoked for each occurrence of a placeholder type; these are
493
+ /// used when we instantiate binders universally. Returns a type
494
+ /// to use instead, which should be suitably shifted to account
495
+ /// for `binders`.
496
+ ///
497
+ /// - `universe` is the universe of the `TypeName::ForAll` that was found
498
+ /// - `binders` is the number of binders in scope
499
+ #[ allow( unused_variables) ]
500
+ fn fold_free_placeholder_ty (
501
+ & mut self ,
502
+ universe : PlaceholderIndex ,
503
+ outer_binder : DebruijnIndex ,
504
+ ) -> Ty < I > {
505
+ if TypeFolder :: forbid_free_placeholders ( self ) {
506
+ panic ! ( "unexpected placeholder type `{:?}`" , universe)
507
+ } else {
508
+ universe. to_ty :: < I > ( TypeFolder :: interner ( self ) )
509
+ }
510
+ }
511
+
512
+ /// As with `fold_free_placeholder_ty`, but for lifetimes.
513
+ #[ allow( unused_variables) ]
514
+ fn fold_free_placeholder_lifetime (
515
+ & mut self ,
516
+ universe : PlaceholderIndex ,
517
+ outer_binder : DebruijnIndex ,
518
+ ) -> Lifetime < I > {
519
+ if TypeFolder :: forbid_free_placeholders ( self ) {
520
+ panic ! ( "unexpected placeholder lifetime `{:?}`" , universe)
521
+ } else {
522
+ universe. to_lifetime ( TypeFolder :: interner ( self ) )
523
+ }
524
+ }
525
+
526
+ /// As with `fold_free_placeholder_ty`, but for constants.
527
+ #[ allow( unused_variables) ]
528
+ fn fold_free_placeholder_const (
529
+ & mut self ,
530
+ ty : Ty < I > ,
531
+ universe : PlaceholderIndex ,
532
+ outer_binder : DebruijnIndex ,
533
+ ) -> Const < I > {
534
+ if TypeFolder :: forbid_free_placeholders ( self ) {
535
+ panic ! ( "unexpected placeholder const `{:?}`" , universe)
536
+ } else {
537
+ universe. to_const (
538
+ TypeFolder :: interner ( self ) ,
539
+ ty. fold_with ( TypeFolder :: as_dyn ( self ) , outer_binder) ,
540
+ )
541
+ }
542
+ }
543
+
544
+ /// If overridden to return true, inference variables will trigger
545
+ /// panics when folded. Used when inference variables are
546
+ /// unexpected.
547
+ fn forbid_inference_vars ( & self ) -> bool {
548
+ false
549
+ }
550
+
551
+ /// Invoked for each occurrence of a inference type; these are
552
+ /// used when we instantiate binders universally. Returns a type
553
+ /// to use instead, which should be suitably shifted to account
554
+ /// for `binders`.
555
+ ///
556
+ /// - `universe` is the universe of the `TypeName::ForAll` that was found
557
+ /// - `binders` is the number of binders in scope
558
+ #[ allow( unused_variables) ]
559
+ fn fold_inference_ty (
560
+ & mut self ,
561
+ var : InferenceVar ,
562
+ kind : TyVariableKind ,
563
+ outer_binder : DebruijnIndex ,
564
+ ) -> Ty < I > {
565
+ if TypeFolder :: forbid_inference_vars ( self ) {
566
+ panic ! ( "unexpected inference type `{:?}`" , var)
567
+ } else {
568
+ var. to_ty ( TypeFolder :: interner ( self ) , kind)
569
+ }
570
+ }
571
+
572
+ /// As with `fold_inference_ty`, but for lifetimes.
573
+ #[ allow( unused_variables) ]
574
+ fn fold_inference_lifetime (
575
+ & mut self ,
576
+ var : InferenceVar ,
577
+ outer_binder : DebruijnIndex ,
578
+ ) -> Lifetime < I > {
579
+ if TypeFolder :: forbid_inference_vars ( self ) {
580
+ panic ! ( "unexpected inference lifetime `'{:?}`" , var)
581
+ } else {
582
+ var. to_lifetime ( TypeFolder :: interner ( self ) )
583
+ }
584
+ }
585
+
586
+ /// As with `fold_inference_ty`, but for constants.
587
+ #[ allow( unused_variables) ]
588
+ fn fold_inference_const (
589
+ & mut self ,
590
+ ty : Ty < I > ,
591
+ var : InferenceVar ,
592
+ outer_binder : DebruijnIndex ,
593
+ ) -> Const < I > {
594
+ if TypeFolder :: forbid_inference_vars ( self ) {
595
+ panic ! ( "unexpected inference const `{:?}`" , var)
596
+ } else {
597
+ var. to_const (
598
+ TypeFolder :: interner ( self ) ,
599
+ ty. fold_with ( TypeFolder :: as_dyn ( self ) , outer_binder) ,
600
+ )
601
+ }
602
+ }
603
+
604
+ /// Gets the interner that is being folded from.
605
+ fn interner ( & self ) -> I ;
606
+ }
607
+
319
608
/// Applies the given `TypeFolder` to a value, producing a folded result
320
609
/// of type `Self::Result`. The result type is typically the same as
321
610
/// the source type, but in some cases we convert from borrowed
@@ -332,6 +621,14 @@ pub trait TypeFoldable<I: Interner>: Debug + Sized {
332
621
folder : & mut dyn FallibleTypeFolder < I , Error = E > ,
333
622
outer_binder : DebruijnIndex ,
334
623
) -> Result < Self , E > ;
624
+
625
+ /// A convenient alternative to `try_fold_with` for use with infallible
626
+ /// folders. Do not override this method, to ensure coherence with
627
+ /// `try_fold_with`.
628
+ fn fold_with ( self , folder : & mut dyn TypeFolder < I > , outer_binder : DebruijnIndex ) -> Self {
629
+ self . try_fold_with ( FallibleTypeFolder :: as_dyn ( folder) , outer_binder)
630
+ . unwrap ( )
631
+ }
335
632
}
336
633
337
634
/// For types where "fold" invokes a callback on the `TypeFolder`, the
@@ -344,6 +641,14 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
344
641
folder : & mut dyn FallibleTypeFolder < I , Error = E > ,
345
642
outer_binder : DebruijnIndex ,
346
643
) -> Result < Self , E > ;
644
+
645
+ /// A convenient alternative to `try_super_fold_with` for use with
646
+ /// infallible folders. Do not override this method, to ensure coherence
647
+ /// with `try_super_fold_with`.
648
+ fn super_fold_with ( self , folder : & mut dyn TypeFolder < I > , outer_binder : DebruijnIndex ) -> Self {
649
+ self . try_super_fold_with ( FallibleTypeFolder :: as_dyn ( folder) , outer_binder)
650
+ . unwrap ( )
651
+ }
347
652
}
348
653
349
654
/// "Folding" a type invokes the `try_fold_ty` method on the folder; this
0 commit comments