@@ -5,6 +5,7 @@ use crate::traits::{self, ObligationCause, ObligationCtxt};
5
5
use hir:: LangItem ;
6
6
use rustc_data_structures:: fx:: FxIndexSet ;
7
7
use rustc_hir as hir;
8
+ use rustc_hir:: def_id:: DefId ;
8
9
use rustc_infer:: infer:: canonical:: Canonical ;
9
10
use rustc_infer:: infer:: { RegionResolutionError , TyCtxtInferExt } ;
10
11
use rustc_infer:: traits:: query:: NoSolution ;
@@ -22,6 +23,7 @@ pub enum CopyImplementationError<'tcx> {
22
23
23
24
pub enum ConstParamTyImplementationError < ' tcx > {
24
25
InfrigingFields ( Vec < ( & ' tcx ty:: FieldDef , Ty < ' tcx > , InfringingFieldsReason < ' tcx > ) > ) ,
26
+ InfringingReferee ( DefId ) ,
25
27
NotAnAdtOrBuiltinAllowed ,
26
28
}
27
29
@@ -92,6 +94,49 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
92
94
parent_cause : ObligationCause < ' tcx > ,
93
95
) -> Result < ( ) , ConstParamTyImplementationError < ' tcx > > {
94
96
let ( adt, args) = match self_type. kind ( ) {
97
+ // Special case for impls like `impl ConstParamTy for &Foo`, where
98
+ // Foo doesn't `impl ConstParamTy`. These kinds of impls aren't caught
99
+ // by coherence checking since `core`'s impl is restricted to &T where
100
+ // T: ConstParamTy.
101
+ // `has_concrete_skeleton()` avoids reporting `core`'s blanket impl.
102
+ & ty:: Ref ( .., ty, hir:: Mutability :: Not ) if ty. peel_refs ( ) . has_concrete_skeleton ( ) => {
103
+ let ty = ty. peel_refs ( ) ;
104
+ type_allowed_to_implement_const_param_ty ( tcx, param_env, ty, parent_cause) ?;
105
+ // Check the ty behind the ref impls `ConstParamTy` itself. This additional
106
+ // logic is needed when checking refs because we need to check not only if
107
+ // all fields implement ConstParamTy, but also that the type itself implements
108
+ // ConstParamTy. Simply recursing into the ref only checks the former.
109
+ if !ty. references_error ( )
110
+ && let & ty:: Adt ( adt, _) = ty. kind ( )
111
+ {
112
+ let adt_did = adt. did ( ) ;
113
+ let adt_span = tcx. def_span ( adt_did) ;
114
+ let trait_did = tcx. require_lang_item ( hir:: LangItem :: ConstParamTy , Some ( adt_span) ) ;
115
+
116
+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
117
+ let ocx = traits:: ObligationCtxt :: new ( & infcx) ;
118
+
119
+ let ty = ocx. normalize ( & ObligationCause :: dummy_with_span ( adt_span) , param_env, ty) ;
120
+ let norm_errs = ocx. select_where_possible ( ) ;
121
+ if !norm_errs. is_empty ( ) || ty. references_error ( ) {
122
+ return Ok ( ( ) ) ;
123
+ }
124
+
125
+ ocx. register_bound (
126
+ ObligationCause :: dummy_with_span ( adt_span) ,
127
+ param_env,
128
+ ty,
129
+ trait_did,
130
+ ) ;
131
+ let errs = ocx. select_all_or_error ( ) ;
132
+ if !errs. is_empty ( ) {
133
+ return Err ( ConstParamTyImplementationError :: InfringingReferee ( adt_did) ) ;
134
+ }
135
+ }
136
+
137
+ return Ok ( ( ) ) ;
138
+ }
139
+
95
140
// `core` provides these impls.
96
141
ty:: Uint ( _)
97
142
| ty:: Int ( _)
0 commit comments