about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-02-08 09:06:36 +0100
committerGitHub <noreply@github.com>2024-02-08 09:06:36 +0100
commita059dd88bf4bbfa13397966eee3b21973dbb91e7 (patch)
tree9e0c1da15f0f980ea5a82418382eb927f5268e1b
parent87e1e05aa1185125c4380bc77965b3d50f506c60 (diff)
parentc636c7ae2cbdf576aa920359f687b9f0716a9418 (diff)
downloadrust-a059dd88bf4bbfa13397966eee3b21973dbb91e7.tar.gz
rust-a059dd88bf4bbfa13397966eee3b21973dbb91e7.zip
Rollup merge of #120739 - lukas-code:pp-dyn-assoc, r=compiler-errors
improve pretty printing for associated items in trait objects

* Don't print a binder in front of associated items, because it's not valid syntax.
  * e.g. print `dyn for<'a> Trait<'a, Assoc = &'a u8>` instead of `dyn for<'a> Trait<'a, for<'a> Assoc = &'a u8>`.
* Don't print associated items that are implied by a supertrait bound.
  * e.g. if we have `trait Sub: Super<Assoc = u8> {}`, then just print `dyn Sub` instead of `dyn Sub<Assoc = u8>`.

I've added the test in the first commit, so you can see the diff of the compiler output in the second commit.
-rw-r--r--compiler/rustc_middle/src/traits/util.rs54
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs60
-rw-r--r--tests/ui/traits/object/pretty.rs37
-rw-r--r--tests/ui/traits/object/pretty.stderr157
-rw-r--r--tests/ui/wf/hir-wf-canonicalized.rs4
-rw-r--r--tests/ui/wf/hir-wf-canonicalized.stderr8
6 files changed, 281 insertions, 39 deletions
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
index b4054f8ff5e..fd5302dc75b 100644
--- a/compiler/rustc_middle/src/traits/util.rs
+++ b/compiler/rustc_middle/src/traits/util.rs
@@ -1,46 +1,60 @@
 use rustc_data_structures::fx::FxHashSet;
 
-use crate::ty::{PolyTraitRef, TyCtxt};
+use crate::ty::{Clause, PolyTraitRef, ToPolyTraitRef, ToPredicate, TyCtxt};
 
-/// Given a PolyTraitRef, get the PolyTraitRefs of the trait's (transitive) supertraits.
+/// Given a [`PolyTraitRef`], get the [`Clause`]s implied by the trait's definition.
+///
 /// This only exists in `rustc_middle` because the more powerful elaborator depends on
 /// `rustc_infer` for elaborating outlives bounds -- this should only be used for pretty
 /// printing.
+pub fn super_predicates_for_pretty_printing<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ref: PolyTraitRef<'tcx>,
+) -> impl Iterator<Item = Clause<'tcx>> {
+    let clause = trait_ref.to_predicate(tcx);
+    Elaborator { tcx, visited: FxHashSet::from_iter([clause]), stack: vec![clause] }
+}
+
+/// Like [`super_predicates_for_pretty_printing`], except it only returns traits and filters out
+/// all other [`Clause`]s.
 pub fn supertraits_for_pretty_printing<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: PolyTraitRef<'tcx>,
 ) -> impl Iterator<Item = PolyTraitRef<'tcx>> {
-    Elaborator { tcx, visited: FxHashSet::from_iter([trait_ref]), stack: vec![trait_ref] }
+    super_predicates_for_pretty_printing(tcx, trait_ref).filter_map(|clause| {
+        clause.as_trait_clause().map(|trait_clause| trait_clause.to_poly_trait_ref())
+    })
 }
 
 struct Elaborator<'tcx> {
     tcx: TyCtxt<'tcx>,
-    visited: FxHashSet<PolyTraitRef<'tcx>>,
-    stack: Vec<PolyTraitRef<'tcx>>,
+    visited: FxHashSet<Clause<'tcx>>,
+    stack: Vec<Clause<'tcx>>,
 }
 
 impl<'tcx> Elaborator<'tcx> {
     fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) {
-        let supertrait_refs = self
-            .tcx
-            .super_predicates_of(trait_ref.def_id())
-            .predicates
-            .into_iter()
-            .flat_map(|(pred, _)| pred.subst_supertrait(self.tcx, &trait_ref).as_trait_clause())
-            .map(|t| t.map_bound(|pred| pred.trait_ref))
-            .filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
-
-        self.stack.extend(supertrait_refs);
+        let super_predicates =
+            self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map(
+                |&(pred, _)| {
+                    let clause = pred.subst_supertrait(self.tcx, &trait_ref);
+                    self.visited.insert(clause).then_some(clause)
+                },
+            );
+
+        self.stack.extend(super_predicates);
     }
 }
 
 impl<'tcx> Iterator for Elaborator<'tcx> {
-    type Item = PolyTraitRef<'tcx>;
+    type Item = Clause<'tcx>;
 
-    fn next(&mut self) -> Option<PolyTraitRef<'tcx>> {
-        if let Some(trait_ref) = self.stack.pop() {
-            self.elaborate(trait_ref);
-            Some(trait_ref)
+    fn next(&mut self) -> Option<Clause<'tcx>> {
+        if let Some(clause) = self.stack.pop() {
+            if let Some(trait_clause) = clause.as_trait_clause() {
+                self.elaborate(trait_clause.to_poly_trait_ref());
+            }
+            Some(clause)
         } else {
             None
         }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index c0bfd2380ad..f90703e6184 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,7 +1,7 @@
 use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::query::IntoQueryParam;
 use crate::query::Providers;
-use crate::traits::util::supertraits_for_pretty_printing;
+use crate::traits::util::{super_predicates_for_pretty_printing, supertraits_for_pretty_printing};
 use crate::ty::GenericArgKind;
 use crate::ty::{
     ConstInt, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable,
@@ -1255,8 +1255,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         // Generate the main trait ref, including associated types.
         let mut first = true;
 
-        if let Some(principal) = predicates.principal() {
-            self.wrap_binder(&principal, |principal, cx| {
+        if let Some(bound_principal) = predicates.principal() {
+            self.wrap_binder(&bound_principal, |principal, cx| {
                 define_scoped_cx!(cx);
                 p!(print_def_path(principal.def_id, &[]));
 
@@ -1281,19 +1281,53 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`,
                 // in order to place the projections inside the `<...>`.
                 if !resugared {
-                    // Use a type that can't appear in defaults of type parameters.
-                    let dummy_cx = Ty::new_fresh(cx.tcx(), 0);
-                    let principal = principal.with_self_ty(cx.tcx(), dummy_cx);
+                    let principal_with_self =
+                        principal.with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self);
 
                     let args = cx
                         .tcx()
-                        .generics_of(principal.def_id)
-                        .own_args_no_defaults(cx.tcx(), principal.args);
-
-                    let mut projections: Vec<_> = predicates.projection_bounds().collect();
-                    projections.sort_by_cached_key(|proj| {
-                        cx.tcx().item_name(proj.item_def_id()).to_string()
-                    });
+                        .generics_of(principal_with_self.def_id)
+                        .own_args_no_defaults(cx.tcx(), principal_with_self.args);
+
+                    let bound_principal_with_self = bound_principal
+                        .with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self);
+
+                    let super_projections: Vec<_> =
+                        super_predicates_for_pretty_printing(cx.tcx(), bound_principal_with_self)
+                            .filter_map(|clause| clause.as_projection_clause())
+                            .collect();
+
+                    let mut projections: Vec<_> = predicates
+                        .projection_bounds()
+                        .filter(|&proj| {
+                            // Filter out projections that are implied by the super predicates.
+                            let proj_is_implied = super_projections.iter().any(|&super_proj| {
+                                let super_proj = super_proj.map_bound(|super_proj| {
+                                    ty::ExistentialProjection::erase_self_ty(cx.tcx(), super_proj)
+                                });
+
+                                // This function is sometimes called on types with erased and
+                                // anonymized regions, but the super projections can still
+                                // contain named regions. So we erase and anonymize everything
+                                // here to compare the types modulo regions below.
+                                let proj = cx.tcx().erase_regions(proj);
+                                let proj = cx.tcx().anonymize_bound_vars(proj);
+                                let super_proj = cx.tcx().erase_regions(super_proj);
+                                let super_proj = cx.tcx().anonymize_bound_vars(super_proj);
+
+                                proj == super_proj
+                            });
+                            !proj_is_implied
+                        })
+                        .map(|proj| {
+                            // Skip the binder, because we don't want to print the binder in
+                            // front of the associated item.
+                            proj.skip_binder()
+                        })
+                        .collect();
+
+                    projections
+                        .sort_by_cached_key(|proj| cx.tcx().item_name(proj.def_id).to_string());
 
                     if !args.is_empty() || !projections.is_empty() {
                         p!(generic_delimiters(|cx| {
diff --git a/tests/ui/traits/object/pretty.rs b/tests/ui/traits/object/pretty.rs
new file mode 100644
index 00000000000..8958871ed5d
--- /dev/null
+++ b/tests/ui/traits/object/pretty.rs
@@ -0,0 +1,37 @@
+// Test for pretty-printing trait object types.
+
+trait Super {
+    type Assoc;
+}
+trait Any: Super {}
+trait Fixed: Super<Assoc = u8> {}
+trait FixedSub: Fixed {}
+trait FixedStatic: Super<Assoc = &'static u8> {}
+
+trait SuperGeneric<'a> {
+    type Assoc2;
+}
+trait AnyGeneric<'a>: SuperGeneric<'a> {}
+trait FixedGeneric1<'a>: SuperGeneric<'a, Assoc2 = &'a u8> {}
+trait FixedGeneric2<'a>: Super<Assoc = &'a u8> {}
+trait FixedHrtb: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> {}
+trait AnyDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {}
+trait FixedDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super<Assoc = u8> {}
+
+fn dyn_super(x: &dyn Super<Assoc = u8>) { x } //~ERROR mismatched types
+fn dyn_any(x: &dyn Any<Assoc = u8>) { x } //~ERROR mismatched types
+fn dyn_fixed(x: &dyn Fixed) { x } //~ERROR mismatched types
+fn dyn_fixed_multi(x: &dyn Fixed<Assoc = u16>) { x } //~ERROR mismatched types
+fn dyn_fixed_sub(x: &dyn FixedSub) { x } //~ERROR mismatched types
+fn dyn_fixed_static(x: &dyn FixedStatic) { x } //~ERROR mismatched types
+
+fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types
+fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types
+fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } //~ERROR mismatched types
+fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } //~ERROR mismatched types
+fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } //~ERROR mismatched types
+fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types
+fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x } //~ERROR mismatched types
+fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } //~ERROR mismatched types
+
+fn main() {}
diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr
new file mode 100644
index 00000000000..bc645e5f967
--- /dev/null
+++ b/tests/ui/traits/object/pretty.stderr
@@ -0,0 +1,157 @@
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:21:43
+   |
+LL | fn dyn_super(x: &dyn Super<Assoc = u8>) { x }
+   |                                        -  ^ expected `()`, found `&dyn Super<Assoc = u8>`
+   |                                        |
+   |                                        help: try adding a return type: `-> &dyn Super<Assoc = u8>`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn Super<Assoc = u8>`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:22:39
+   |
+LL | fn dyn_any(x: &dyn Any<Assoc = u8>) { x }
+   |                                    -  ^ expected `()`, found `&dyn Any<Assoc = u8>`
+   |                                    |
+   |                                    help: try adding a return type: `-> &dyn Any<Assoc = u8>`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn Any<Assoc = u8>`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:23:31
+   |
+LL | fn dyn_fixed(x: &dyn Fixed) { x }
+   |                            -  ^ expected `()`, found `&dyn Fixed`
+   |                            |
+   |                            help: try adding a return type: `-> &dyn Fixed`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn Fixed`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:24:50
+   |
+LL | fn dyn_fixed_multi(x: &dyn Fixed<Assoc = u16>) { x }
+   |                                               -  ^ expected `()`, found `&dyn Fixed<Assoc = u16>`
+   |                                               |
+   |                                               help: try adding a return type: `-> &dyn Fixed<Assoc = u16>`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn Fixed<Assoc = u16>`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:25:38
+   |
+LL | fn dyn_fixed_sub(x: &dyn FixedSub) { x }
+   |                                   -  ^ expected `()`, found `&dyn FixedSub`
+   |                                   |
+   |                                   help: try adding a return type: `-> &dyn FixedSub`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn FixedSub`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:26:44
+   |
+LL | fn dyn_fixed_static(x: &dyn FixedStatic) { x }
+   |                                         -  ^ expected `()`, found `&dyn FixedStatic`
+   |                                         |
+   |                                         help: try adding a return type: `-> &dyn FixedStatic`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn FixedStatic`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:28:75
+   |
+LL | fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x }
+   |                                                                        -  ^ expected `()`, found `&dyn SuperGeneric<'a, Assoc2 = &u8>`
+   |                                                                        |
+   |                                                                        help: try adding a return type: `-> &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:29:71
+   |
+LL | fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x }
+   |                                                                    -  ^ expected `()`, found `&dyn AnyGeneric<'a, Assoc2 = &u8>`
+   |                                                                    |
+   |                                                                    help: try adding a return type: `-> &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:30:60
+   |
+LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x }
+   |                                                         -  ^ expected `()`, found `&dyn FixedGeneric1<'a>`
+   |                                                         |
+   |                                                         help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a>`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn for<'a> FixedGeneric1<'a>`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:31:60
+   |
+LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x }
+   |                                                         -  ^ expected `()`, found `&dyn FixedGeneric2<'a>`
+   |                                                         |
+   |                                                         help: try adding a return type: `-> &dyn for<'a> FixedGeneric2<'a>`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn for<'a> FixedGeneric2<'a>`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:32:79
+   |
+LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x }
+   |                                                                            -  ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = ...>`
+   |                                                                            |
+   |                                                                            help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:33:40
+   |
+LL | fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x }
+   |                                     -  ^ expected `()`, found `&dyn FixedHrtb`
+   |                                     |
+   |                                     help: try adding a return type: `-> &dyn FixedHrtb`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn FixedHrtb`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:34:73
+   |
+LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x }
+   |                                                                      -  ^ expected `()`, found `&dyn AnyDifferentBinders<Assoc = ...>`
+   |                                                                      |
+   |                                                                      help: try adding a return type: `-> &dyn AnyDifferentBinders<Assoc = u8>`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn AnyDifferentBinders<Assoc = u8>`
+
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:35:65
+   |
+LL | fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x }
+   |                                                              -  ^ expected `()`, found `&dyn FixedDifferentBinders`
+   |                                                              |
+   |                                                              help: try adding a return type: `-> &dyn FixedDifferentBinders`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn FixedDifferentBinders`
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/wf/hir-wf-canonicalized.rs b/tests/ui/wf/hir-wf-canonicalized.rs
index bdb84409d00..eac238f0fca 100644
--- a/tests/ui/wf/hir-wf-canonicalized.rs
+++ b/tests/ui/wf/hir-wf-canonicalized.rs
@@ -9,8 +9,8 @@ trait Callback<T: Foo>: Fn(&Bar<'_, T>, &T::V) {}
 struct Bar<'a, T> {
     callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
     //~^ ERROR the trait bound `Bar<'a, T>: Foo` is not satisfied
-    //~| ERROR the trait bound `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static): Foo` is not satisfied
-    //~| ERROR the size for values of type `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)` cannot be known at compilation time
+    //~| ERROR the trait bound `(dyn Callback<Bar<'a, T>, Output = ()> + 'static): Foo` is not satisfied
+    //~| ERROR the size for values of type `(dyn Callback<Bar<'a, T>, Output = ()> + 'static)` cannot be known at compilation time
 }
 
 impl<T: Foo> Bar<'_, Bar<'_, T>> {}
diff --git a/tests/ui/wf/hir-wf-canonicalized.stderr b/tests/ui/wf/hir-wf-canonicalized.stderr
index 4dca1f65232..8938801ce3d 100644
--- a/tests/ui/wf/hir-wf-canonicalized.stderr
+++ b/tests/ui/wf/hir-wf-canonicalized.stderr
@@ -10,11 +10,11 @@ help: this trait has no implementations, consider adding one
 LL | trait Foo {
    | ^^^^^^^^^
 
-error[E0277]: the trait bound `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static): Foo` is not satisfied
+error[E0277]: the trait bound `(dyn Callback<Bar<'a, T>, Output = ()> + 'static): Foo` is not satisfied
   --> $DIR/hir-wf-canonicalized.rs:10:15
    |
 LL |     callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)`
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<Bar<'a, T>, Output = ()> + 'static)`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/hir-wf-canonicalized.rs:3:1
@@ -22,13 +22,13 @@ help: this trait has no implementations, consider adding one
 LL | trait Foo {
    | ^^^^^^^^^
 
-error[E0277]: the size for values of type `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)` cannot be known at compilation time
+error[E0277]: the size for values of type `(dyn Callback<Bar<'a, T>, Output = ()> + 'static)` cannot be known at compilation time
   --> $DIR/hir-wf-canonicalized.rs:10:15
    |
 LL |     callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `Sized` is not implemented for `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)`
+   = help: the trait `Sized` is not implemented for `(dyn Callback<Bar<'a, T>, Output = ()> + 'static)`
 note: required by an implicit `Sized` bound in `Bar`
   --> $DIR/hir-wf-canonicalized.rs:9:16
    |