@@ -21,7 +21,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
21
21
use rustc_middle:: infer:: unify_key:: { ConstVariableOrigin , ConstVariableOriginKind , ToType } ;
22
22
use rustc_middle:: mir:: interpret:: { ErrorHandled , EvalToValTreeResult } ;
23
23
use rustc_middle:: traits:: select;
24
- use rustc_middle:: ty:: abstract_const:: AbstractConst ;
24
+ use rustc_middle:: ty:: abstract_const:: { AbstractConst , FailureKind } ;
25
25
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
26
26
use rustc_middle:: ty:: fold:: { TypeFoldable , TypeFolder , TypeSuperFoldable } ;
27
27
use rustc_middle:: ty:: relate:: RelateResult ;
@@ -1675,7 +1675,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1675
1675
#[ instrument( skip( self ) , level = "debug" ) ]
1676
1676
pub fn const_eval_resolve (
1677
1677
& self ,
1678
- param_env : ty:: ParamEnv < ' tcx > ,
1678
+ mut param_env : ty:: ParamEnv < ' tcx > ,
1679
1679
unevaluated : ty:: Unevaluated < ' tcx > ,
1680
1680
span : Option < Span > ,
1681
1681
) -> EvalToValTreeResult < ' tcx > {
@@ -1686,10 +1686,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1686
1686
// variables
1687
1687
if substs. has_infer_types_or_consts ( ) {
1688
1688
let ac = AbstractConst :: new ( self . tcx , unevaluated. shrink ( ) ) ;
1689
- if let Ok ( None ) = ac {
1690
- substs = InternalSubsts :: identity_for_item ( self . tcx , unevaluated. def . did ) ;
1691
- } else {
1692
- return Err ( ErrorHandled :: TooGeneric ) ;
1689
+ match ac {
1690
+ Ok ( None ) => {
1691
+ substs = InternalSubsts :: identity_for_item ( self . tcx , unevaluated. def . did ) ;
1692
+ param_env = self . tcx . param_env ( unevaluated. def . did ) ;
1693
+ }
1694
+ Ok ( Some ( ct) ) => {
1695
+ if ct. unify_failure_kind ( self . tcx ) == FailureKind :: Concrete {
1696
+ substs = replace_param_and_infer_substs_with_placeholder ( self . tcx , substs) ;
1697
+ } else {
1698
+ return Err ( ErrorHandled :: TooGeneric ) ;
1699
+ }
1700
+ }
1701
+ Err ( guar) => return Err ( ErrorHandled :: Reported ( guar) ) ,
1693
1702
}
1694
1703
}
1695
1704
@@ -2000,3 +2009,43 @@ impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
2000
2009
)
2001
2010
}
2002
2011
}
2012
+
2013
+ /// Replaces substs that reference param or infer variables with suitable
2014
+ /// placeholders. This function is meant to remove these param and infer
2015
+ /// substs when they're not actually needed to evaluate a constant.
2016
+ fn replace_param_and_infer_substs_with_placeholder < ' tcx > (
2017
+ tcx : TyCtxt < ' tcx > ,
2018
+ substs : SubstsRef < ' tcx > ,
2019
+ ) -> SubstsRef < ' tcx > {
2020
+ tcx. mk_substs ( substs. iter ( ) . enumerate ( ) . map ( |( idx, arg) | {
2021
+ match arg. unpack ( ) {
2022
+ GenericArgKind :: Type ( _)
2023
+ if arg. has_param_types_or_consts ( ) || arg. has_infer_types_or_consts ( ) =>
2024
+ {
2025
+ tcx. mk_ty ( ty:: Placeholder ( ty:: PlaceholderType {
2026
+ universe : ty:: UniverseIndex :: ROOT ,
2027
+ name : ty:: BoundVar :: from_usize ( idx) ,
2028
+ } ) )
2029
+ . into ( )
2030
+ }
2031
+ GenericArgKind :: Const ( ct)
2032
+ if ct. has_infer_types_or_consts ( ) || ct. has_param_types_or_consts ( ) =>
2033
+ {
2034
+ let ty = ct. ty ( ) ;
2035
+ // If the type references param or infer, replace that too...
2036
+ if ty. has_param_types_or_consts ( ) || ty. has_infer_types_or_consts ( ) {
2037
+ bug ! ( "const `{ct}`'s type should not reference params or types" ) ;
2038
+ }
2039
+ tcx. mk_const ( ty:: ConstS {
2040
+ ty,
2041
+ kind : ty:: ConstKind :: Placeholder ( ty:: PlaceholderConst {
2042
+ universe : ty:: UniverseIndex :: ROOT ,
2043
+ name : ty:: BoundConst { ty, var : ty:: BoundVar :: from_usize ( idx) } ,
2044
+ } ) ,
2045
+ } )
2046
+ . into ( )
2047
+ }
2048
+ _ => arg,
2049
+ }
2050
+ } ) )
2051
+ }
0 commit comments