about summary refs log tree commit diff
diff options
context:
space:
mode:
authorb-naber <bn263@gmx.de>2022-03-22 10:38:46 +0100
committerb-naber <bn263@gmx.de>2022-03-22 11:35:59 +0100
commit8ff1edbe5e38cede450d926d2761191f07bb0af1 (patch)
treecb401f40ca781065e809e7ae004ed1e83b9f82ff
parent6cf3409e16845bf52e72f4ffdac9db139a24a8d3 (diff)
downloadrust-8ff1edbe5e38cede450d926d2761191f07bb0af1.tar.gz
rust-8ff1edbe5e38cede450d926d2761191f07bb0af1.zip
fix previous failures and address review
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs13
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs208
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs6
-rw-r--r--compiler/rustc_typeck/src/check/dropck.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-83765.rs118
-rw-r--r--src/test/ui/const-generics/issues/issue-83765.stderr10
9 files changed, 204 insertions, 166 deletions
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index e7fd7d2928e..45502c720ae 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -20,8 +20,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
-use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::mir::interpret::EvalToConstValueResult;
+use rustc_middle::mir::interpret::{ErrorHandled, EvalToConstValueResult};
 use rustc_middle::traits::select;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
@@ -695,9 +694,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
     ) -> bool {
         // Reject any attempt to unify two unevaluated constants that contain inference
-        // variables.
-        // FIXME `TyCtxt::const_eval_resolve` already rejects the resolution of those
-        // constants early, but the canonicalization below messes with that mechanism.
+        // variables, since inference variables in queries lead to ICEs.
         if a.substs.has_infer_types_or_consts() || b.substs.has_infer_types_or_consts() {
             debug!("a or b contain infer vars in its substs -> cannot unify");
             return false;
@@ -1621,8 +1618,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         // Postpone the evaluation of constants whose substs depend on inference
         // variables
         if substs.has_infer_types_or_consts() {
-            debug!("has infer types or consts");
-            return Err(ErrorHandled::TooGeneric);
+            debug!("substs have infer types or consts: {:?}", substs);
+            if substs.has_infer_types_or_consts() {
+                return Err(ErrorHandled::TooGeneric);
+            }
         }
 
         let param_env_erased = self.tcx.erase_regions(param_env);
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 155ee210ebe..639a9bc600a 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -43,7 +43,7 @@ impl<'tcx> TyCtxt<'tcx> {
         // variables. We reject those here since `resolve_opt_const_arg`
         // would fail otherwise
         if ct.substs.has_infer_types_or_consts() {
-            return Err(ErrorHandled::TooGeneric);
+            bug!("did not expect inference variables here");
         }
 
         match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 0c33ea858fd..c44e9613630 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -569,6 +569,18 @@ pub(super) fn thir_abstract_const<'tcx>(
     }
 }
 
+/// Tries to unify two abstract constants using structural equality.
+#[instrument(skip(tcx), level = "debug")]
+pub(super) fn try_unify<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    a: AbstractConst<'tcx>,
+    b: AbstractConst<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> bool {
+    let const_unify_ctxt = ConstUnifyCtxt::new(tcx, param_env);
+    const_unify_ctxt.try_unify_inner(a, b)
+}
+
 pub(super) fn try_unify_abstract_consts<'tcx>(
     tcx: TyCtxt<'tcx>,
     (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
@@ -622,115 +634,119 @@ where
     recurse(tcx, ct, &mut f)
 }
 
-// Substitutes generics repeatedly to allow AbstractConsts to unify where a
-// ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
-// Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
-#[inline]
-#[instrument(skip(tcx), level = "debug")]
-fn try_replace_substs_in_root<'tcx>(
+pub(super) struct ConstUnifyCtxt<'tcx> {
     tcx: TyCtxt<'tcx>,
-    mut abstr_const: AbstractConst<'tcx>,
-) -> Option<AbstractConst<'tcx>> {
-    while let Node::Leaf(ct) = abstr_const.root(tcx) {
-        match AbstractConst::from_const(tcx, ct) {
-            Ok(Some(act)) => abstr_const = act,
-            Ok(None) => break,
-            Err(_) => return None,
-        }
-    }
-
-    Some(abstr_const)
+    param_env: ty::ParamEnv<'tcx>,
 }
 
-/// Tries to unify two abstract constants using structural equality.
-#[instrument(skip(tcx), level = "debug")]
-pub(super) fn try_unify<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    a: AbstractConst<'tcx>,
-    b: AbstractConst<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-) -> bool {
-    let a = match try_replace_substs_in_root(tcx, a) {
-        Some(a) => a,
-        None => {
-            return true;
+impl<'tcx> ConstUnifyCtxt<'tcx> {
+    pub(super) fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+        ConstUnifyCtxt { tcx, param_env }
+    }
+
+    // Substitutes generics repeatedly to allow AbstractConsts to unify where a
+    // ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
+    // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
+    #[inline]
+    #[instrument(skip(self), level = "debug")]
+    pub(super) fn try_replace_substs_in_root(
+        &self,
+        mut abstr_const: AbstractConst<'tcx>,
+    ) -> Option<AbstractConst<'tcx>> {
+        while let Node::Leaf(ct) = abstr_const.root(self.tcx) {
+            match AbstractConst::from_const(self.tcx, ct) {
+                Ok(Some(act)) => abstr_const = act,
+                Ok(None) => break,
+                Err(_) => return None,
+            }
         }
-    };
 
-    let b = match try_replace_substs_in_root(tcx, b) {
-        Some(b) => b,
-        None => {
+        Some(abstr_const)
+    }
+
+    /// Tries to unify two abstract constants using structural equality.
+    #[instrument(skip(self), level = "debug")]
+    fn try_unify_inner(&self, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool {
+        let a = if let Some(a) = self.try_replace_substs_in_root(a) {
+            a
+        } else {
             return true;
-        }
-    };
+        };
 
-    let a_root = a.root(tcx);
-    let b_root = b.root(tcx);
-    debug!(?a_root, ?b_root);
+        let b = if let Some(b) = self.try_replace_substs_in_root(b) {
+            b
+        } else {
+            return true;
+        };
 
-    match (a_root, b_root) {
-        (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
-            let a_ct = a_ct.eval(tcx, param_env);
-            debug!("a_ct evaluated: {:?}", a_ct);
-            let b_ct = b_ct.eval(tcx, param_env);
-            debug!("b_ct evaluated: {:?}", b_ct);
+        let a_root = a.root(self.tcx);
+        let b_root = b.root(self.tcx);
+        debug!(?a_root, ?b_root);
 
-            if a_ct.ty() != b_ct.ty() {
-                return false;
-            }
+        match (a_root, b_root) {
+            (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
+                let a_ct = a_ct.eval(self.tcx, self.param_env);
+                debug!("a_ct evaluated: {:?}", a_ct);
+                let b_ct = b_ct.eval(self.tcx, self.param_env);
+                debug!("b_ct evaluated: {:?}", b_ct);
 
-            match (a_ct.val(), b_ct.val()) {
-                // We can just unify errors with everything to reduce the amount of
-                // emitted errors here.
-                (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
-                (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
-                    a_param == b_param
+                if a_ct.ty() != b_ct.ty() {
+                    return false;
                 }
-                (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
-                // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
-                // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
-                // means that we only allow inference variables if they are equal.
-                (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
-                // We expand generic anonymous constants at the start of this function, so this
-                // branch should only be taking when dealing with associated constants, at
-                // which point directly comparing them seems like the desired behavior.
-                //
-                // FIXME(generic_const_exprs): This isn't actually the case.
-                // We also take this branch for concrete anonymous constants and
-                // expand generic anonymous constants with concrete substs.
-                (ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => {
-                    a_uv == b_uv
+
+                match (a_ct.val(), b_ct.val()) {
+                    // We can just unify errors with everything to reduce the amount of
+                    // emitted errors here.
+                    (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
+                    (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
+                        a_param == b_param
+                    }
+                    (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
+                    // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
+                    // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
+                    // means that we only allow inference variables if they are equal.
+                    (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
+                    // We expand generic anonymous constants at the start of this function, so this
+                    // branch should only be taking when dealing with associated constants, at
+                    // which point directly comparing them seems like the desired behavior.
+                    //
+                    // FIXME(generic_const_exprs): This isn't actually the case.
+                    // We also take this branch for concrete anonymous constants and
+                    // expand generic anonymous constants with concrete substs.
+                    (ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => {
+                        a_uv == b_uv
+                    }
+                    // FIXME(generic_const_exprs): We may want to either actually try
+                    // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
+                    // this, for now we just return false here.
+                    _ => false,
                 }
-                // FIXME(generic_const_exprs): We may want to either actually try
-                // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
-                // this, for now we just return false here.
-                _ => false,
             }
+            (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
+                self.try_unify_inner(a.subtree(al), b.subtree(bl))
+                    && self.try_unify_inner(a.subtree(ar), b.subtree(br))
+            }
+            (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
+                self.try_unify_inner(a.subtree(av), b.subtree(bv))
+            }
+            (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
+                if a_args.len() == b_args.len() =>
+            {
+                self.try_unify_inner(a.subtree(a_f), b.subtree(b_f))
+                    && iter::zip(a_args, b_args)
+                        .all(|(&an, &bn)| self.try_unify_inner(a.subtree(an), b.subtree(bn)))
+            }
+            (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
+                if (a_ty == b_ty) && (a_kind == b_kind) =>
+            {
+                self.try_unify_inner(a.subtree(a_operand), b.subtree(b_operand))
+            }
+            // use this over `_ => false` to make adding variants to `Node` less error prone
+            (Node::Cast(..), _)
+            | (Node::FunctionCall(..), _)
+            | (Node::UnaryOp(..), _)
+            | (Node::Binop(..), _)
+            | (Node::Leaf(..), _) => false,
         }
-        (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
-            try_unify(tcx, a.subtree(al), b.subtree(bl), param_env)
-                && try_unify(tcx, a.subtree(ar), b.subtree(br), param_env)
-        }
-        (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
-            try_unify(tcx, a.subtree(av), b.subtree(bv), param_env)
-        }
-        (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
-            if a_args.len() == b_args.len() =>
-        {
-            try_unify(tcx, a.subtree(a_f), b.subtree(b_f), param_env)
-                && iter::zip(a_args, b_args)
-                    .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn), param_env))
-        }
-        (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
-            if (a_ty == b_ty) && (a_kind == b_kind) =>
-        {
-            try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand), param_env)
-        }
-        // use this over `_ => false` to make adding variants to `Node` less error prone
-        (Node::Cast(..), _)
-        | (Node::FunctionCall(..), _)
-        | (Node::UnaryOp(..), _)
-        | (Node::Binop(..), _)
-        | (Node::Leaf(..), _) => false,
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 62c6c845479..df1e8cdcde0 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -581,7 +581,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                         if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
                             (c1.val(), c2.val())
                         {
-                            if infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
+                            if infcx.try_unify_abstract_consts(
+                                a.shrink(),
+                                b.shrink(),
+                                obligation.param_env,
+                            ) {
                                 return ProcessResult::Changed(vec![]);
                             }
                         }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index bf94c61e6c2..e06ecc528aa 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -860,7 +860,10 @@ pub fn provide(providers: &mut ty::query::Providers) {
                 ty::WithOptConstParam { did, const_param_did: Some(param_did) },
             )
         },
-        try_unify_abstract_consts: const_evaluatable::try_unify_abstract_consts,
+        try_unify_abstract_consts: |tcx, param_env_and| {
+            let (param_env, (a, b)) = param_env_and.into_parts();
+            const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)
+        },
         ..*providers
     };
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 8af4606db85..fe369ca5c46 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -643,7 +643,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
                             (c1.val(), c2.val())
                         {
-                            if self.infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
+                            if self.infcx.try_unify_abstract_consts(
+                                a.shrink(),
+                                b.shrink(),
+                                obligation.param_env,
+                            ) {
                                 return Ok(EvaluatedToOk);
                             }
                         }
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index 1849ece9f76..57b642dc38f 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -243,7 +243,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
                 (
                     ty::PredicateKind::ConstEvaluatable(a),
                     ty::PredicateKind::ConstEvaluatable(b),
-                ) => tcx.try_unify_abstract_consts((a, b)),
+                ) => tcx.try_unify_abstract_consts(self_param_env.and((a, b))),
                 (
                     ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
                     ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
diff --git a/src/test/ui/const-generics/issues/issue-83765.rs b/src/test/ui/const-generics/issues/issue-83765.rs
index 67d813819e7..71c164ab0a5 100644
--- a/src/test/ui/const-generics/issues/issue-83765.rs
+++ b/src/test/ui/const-generics/issues/issue-83765.rs
@@ -2,103 +2,115 @@
 #![allow(incomplete_features)]
 
 trait TensorDimension {
-    const DIM : usize;
-    //~^ ERROR cycle detected when resolving instance `<LazyUpdim<T, {T::DIM}, DIM>
-    const ISSCALAR : bool = Self::DIM == 0;
-    fn is_scalar(&self) -> bool {Self::ISSCALAR}
+    const DIM: usize;
+    //~^ ERROR cycle detected when resolving instance
+    // FIXME Given the current state of the compiler its expected that we cycle here,
+    // but the cycle is still wrong.
+    const ISSCALAR: bool = Self::DIM == 0;
+    fn is_scalar(&self) -> bool {
+        Self::ISSCALAR
+    }
 }
 
-trait TensorSize : TensorDimension {
-    fn size(&self) -> [usize;Self::DIM];
-    fn inbounds(&self,index : [usize;Self::DIM]) -> bool {
-        index.iter().zip(self.size().iter()).all(|(i,s)| i < s)
+trait TensorSize: TensorDimension {
+    fn size(&self) -> [usize; Self::DIM];
+    fn inbounds(&self, index: [usize; Self::DIM]) -> bool {
+        index.iter().zip(self.size().iter()).all(|(i, s)| i < s)
     }
 }
 
-
 trait Broadcastable: TensorSize + Sized {
     type Element;
-    fn bget(&self, index:[usize;Self::DIM]) -> Option<Self::Element>;
-    fn lazy_updim<const NEWDIM : usize>(&self, size : [usize;NEWDIM] ) ->
-       LazyUpdim<Self,{Self::DIM},NEWDIM>
-    {
-        assert!(NEWDIM >= Self::DIM,
-            "Updimmed tensor cannot have fewer indices than the initial one.");
-        LazyUpdim {size,reference:&self}
+    fn bget(&self, index: [usize; Self::DIM]) -> Option<Self::Element>;
+    fn lazy_updim<const NEWDIM: usize>(
+        &self,
+        size: [usize; NEWDIM],
+    ) -> LazyUpdim<Self, { Self::DIM }, NEWDIM> {
+        assert!(
+            NEWDIM >= Self::DIM,
+            "Updimmed tensor cannot have fewer indices than the initial one."
+        );
+        LazyUpdim { size, reference: &self }
     }
-    fn bmap<T,F :Fn(Self::Element) -> T>(&self,foo : F) -> BMap<T,Self,F,{Self::DIM}>{
-        BMap {reference:self,closure : foo}
+    fn bmap<T, F: Fn(Self::Element) -> T>(&self, foo: F) -> BMap<T, Self, F, { Self::DIM }> {
+        BMap { reference: self, closure: foo }
     }
 }
 
-
-struct LazyUpdim<'a,T : Broadcastable,const OLDDIM : usize, const DIM : usize> {
-    size : [usize;DIM],
-    reference : &'a T
+struct LazyUpdim<'a, T: Broadcastable, const OLDDIM: usize, const DIM: usize> {
+    size: [usize; DIM],
+    reference: &'a T,
 }
 
-impl<'a,T : Broadcastable,const DIM : usize> TensorDimension for LazyUpdim<'a,T,{T::DIM},DIM> {
-    const DIM : usize = DIM;
+impl<'a, T: Broadcastable, const DIM: usize> TensorDimension for LazyUpdim<'a, T, { T::DIM }, DIM> {
+    const DIM: usize = DIM;
 }
 
-impl<'a,T : Broadcastable,const DIM : usize> TensorSize for LazyUpdim<'a,T,{T::DIM},DIM> {
-    fn size(&self) -> [usize;DIM] {self.size}
+impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T::DIM }, DIM> {
+    fn size(&self) -> [usize; DIM] {
+        self.size
+    }
 }
 
-impl<'a,T : Broadcastable,const DIM : usize>  Broadcastable for LazyUpdim<'a,T,{T::DIM},DIM>
-{
+impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> {
     type Element = T::Element;
-    fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
+    fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
         assert!(DIM >= T::DIM);
-        if !self.inbounds(index) {return None}
+        if !self.inbounds(index) {
+            return None;
+        }
         let size = self.size();
-        let newindex : [usize;T::DIM] = Default::default();
+        let newindex: [usize; T::DIM] = Default::default();
         self.reference.bget(newindex)
     }
 }
 
-struct BMap<'a,R, T : Broadcastable, F :  Fn(T::Element) -> R  , const DIM: usize> {
-    reference : &'a T,
-    closure : F
+struct BMap<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> {
+    reference: &'a T,
+    closure: F,
 }
 
-impl<'a,R, T : Broadcastable, F :  Fn(T::Element) -> R,
-     const DIM: usize> TensorDimension for BMap<'a,R,T,F,DIM> {
-
-    const DIM : usize = DIM;
+impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorDimension
+    for BMap<'a, R, T, F, DIM>
+{
+    const DIM: usize = DIM;
 }
-impl<'a,R, T : Broadcastable, F :  Fn(T::Element) -> R  ,
-      const DIM: usize> TensorSize for BMap<'a,R,T,F,DIM> {
-
-    fn size(&self) -> [usize;DIM] {self.reference.size()}
+impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorSize
+    for BMap<'a, R, T, F, DIM>
+{
+    fn size(&self) -> [usize; DIM] {
+        self.reference.size()
+    }
 }
 
-impl<'a,R, T : Broadcastable, F :  Fn(T::Element) -> R  ,
-  const DIM: usize> Broadcastable for BMap<'a,R,T,F,DIM> {
-
+impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> Broadcastable
+    for BMap<'a, R, T, F, DIM>
+{
     type Element = R;
-    fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
+    fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
         self.reference.bget(index).map(&self.closure)
     }
 }
 
 impl<T> TensorDimension for Vec<T> {
-    const DIM : usize = 1;
+    const DIM: usize = 1;
 }
 impl<T> TensorSize for Vec<T> {
-    fn size(&self) -> [usize;1] {[self.len()]}
+    fn size(&self) -> [usize; 1] {
+        [self.len()]
+    }
 }
 impl<T: Clone> Broadcastable for Vec<T> {
     type Element = T;
-    fn bget(& self,index : [usize;1]) -> Option<T> {
+    fn bget(&self, index: [usize; 1]) -> Option<T> {
         self.get(index[0]).cloned()
     }
 }
 
 fn main() {
-    let v = vec![1,2,3];
-    let bv = v.lazy_updim([3,4]);
-    let bbv = bv.bmap(|x| x*x);
+    let v = vec![1, 2, 3];
+    let bv = v.lazy_updim([3, 4]);
+    let bbv = bv.bmap(|x| x * x);
 
-    println!("The size of v is {:?}",bbv.bget([0,2]).expect("Out of bounds."));
+    println!("The size of v is {:?}", bbv.bget([0, 2]).expect("Out of bounds."));
 }
diff --git a/src/test/ui/const-generics/issues/issue-83765.stderr b/src/test/ui/const-generics/issues/issue-83765.stderr
index 0003969f7ac..8705a39fa4b 100644
--- a/src/test/ui/const-generics/issues/issue-83765.stderr
+++ b/src/test/ui/const-generics/issues/issue-83765.stderr
@@ -1,16 +1,16 @@
-error[E0391]: cycle detected when resolving instance `<LazyUpdim<T, {T::DIM}, DIM> as TensorDimension>::DIM`
+error[E0391]: cycle detected when resolving instance `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>::DIM`
   --> $DIR/issue-83765.rs:5:5
    |
-LL |     const DIM : usize;
-   |     ^^^^^^^^^^^^^^^^^^
+LL |     const DIM: usize;
+   |     ^^^^^^^^^^^^^^^^^
    |
 note: ...which requires checking if `TensorDimension` fulfills its obligations...
   --> $DIR/issue-83765.rs:4:1
    |
 LL | trait TensorDimension {
    | ^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which again requires resolving instance `<LazyUpdim<T, {T::DIM}, DIM> as TensorDimension>::DIM`, completing the cycle
-   = note: cycle used when normalizing `<LazyUpdim<T, {T::DIM}, DIM> as TensorDimension>::DIM`
+   = note: ...which again requires resolving instance `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>::DIM`, completing the cycle
+   = note: cycle used when normalizing `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>::DIM`
 
 error: aborting due to previous error