@@ -14,6 +14,7 @@ use rustc::lint;
14
14
use rustc:: mir:: { Field , BorrowKind , Mutability } ;
15
15
use rustc:: mir:: { UserTypeProjection } ;
16
16
use rustc:: mir:: interpret:: { GlobalId , ConstValue , get_slice_bytes, sign_extend} ;
17
+ use rustc:: traits:: { self , ConstPatternStructural , TraitEngine } ;
17
18
use rustc:: traits:: { ObligationCause , PredicateObligation } ;
18
19
use rustc:: ty:: { self , Region , TyCtxt , AdtDef , Ty , UserType , DefIdTree } ;
19
20
use rustc:: ty:: { CanonicalUserType , CanonicalUserTypeAnnotation , CanonicalUserTypeAnnotations } ;
@@ -1003,7 +1004,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
1003
1004
if self . include_lint_checks && !saw_error {
1004
1005
// If we were able to successfully convert the const to some pat, double-check
1005
1006
// that the type of the const obeys `#[structural_match]` constraint.
1006
- if let Some ( adt_def) = search_for_adt_without_structural_match ( self . tcx , cv. ty ) {
1007
+ if let Some ( adt_def) =
1008
+ search_for_adt_without_structural_match ( self . tcx , cv. ty , id, span)
1009
+ {
1007
1010
1008
1011
let path = self . tcx . def_path_str ( adt_def. did ) ;
1009
1012
let msg = format ! (
@@ -1173,8 +1176,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
1173
1176
}
1174
1177
1175
1178
/// This method traverses the structure of `ty`, trying to find an
1176
- /// instance of an ADT (i.e. struct or enum) that was declared without
1177
- /// the `#[structural_match]` attribute .
1179
+ /// instance of an ADT (i.e. struct or enum) that does not implement
1180
+ /// the `Structural` trait .
1178
1181
///
1179
1182
/// The "structure of a type" includes all components that would be
1180
1183
/// considered when doing a pattern match on a constant of that
@@ -1188,31 +1191,35 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
1188
1191
/// instantiated generic like `PhantomData<T>`.
1189
1192
///
1190
1193
/// The reason we do this search is Rust currently require all ADT's
1191
- /// reachable from a constant's type to be annotated with
1192
- /// `#[structural_match]`, an attribute which essentially says that
1193
- /// the implementation of `PartialEq::eq` behaves *equivalently* to a
1194
- /// comparison against the unfolded structure.
1194
+ /// reachable from a constant's type to implement `Structural`, a
1195
+ /// trait which essentially says that the implementation of
1196
+ /// `PartialEq::eq` behaves *equivalently* to a comparison against
1197
+ /// the unfolded structure.
1195
1198
///
1196
1199
/// For more background on why Rust has this requirement, and issues
1197
1200
/// that arose when the requirement was not enforced completely, see
1198
1201
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
1199
1202
fn search_for_adt_without_structural_match < ' tcx > ( tcx : TyCtxt < ' tcx > ,
1200
- ty : Ty < ' tcx > )
1203
+ ty : Ty < ' tcx > ,
1204
+ id : hir:: HirId ,
1205
+ span : Span )
1201
1206
-> Option < & ' tcx AdtDef >
1202
1207
{
1203
1208
// Import here (not mod level), because `TypeFoldable::fold_with`
1204
1209
// conflicts with `PatternFoldable::fold_with`
1205
1210
use crate :: rustc:: ty:: fold:: TypeVisitor ;
1206
1211
use crate :: rustc:: ty:: TypeFoldable ;
1207
1212
1208
- let mut search = Search { tcx, found : None , seen : FxHashSet :: default ( ) } ;
1213
+ let mut search = Search { tcx, id , span , found : None , seen : FxHashSet :: default ( ) } ;
1209
1214
ty. visit_with ( & mut search) ;
1210
1215
return search. found ;
1211
1216
1212
1217
struct Search < ' tcx > {
1213
1218
tcx : TyCtxt < ' tcx > ,
1219
+ id : hir:: HirId ,
1220
+ span : Span ,
1214
1221
1215
- // records the first ADT we find without `#[structural_match`
1222
+ // records the first ADT we find that does not implement `Structural`.
1216
1223
found : Option < & ' tcx AdtDef > ,
1217
1224
1218
1225
// tracks ADT's previously encountered during search, so that
@@ -1251,18 +1258,34 @@ fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
1251
1258
}
1252
1259
} ;
1253
1260
1254
- if !self . tcx . has_attr ( adt_def. did , sym:: structural_match) {
1255
- self . found = Some ( & adt_def) ;
1256
- debug ! ( "Search found adt_def: {:?}" , adt_def) ;
1257
- return true // Halt visiting!
1258
- }
1259
-
1260
1261
if self . seen . contains ( adt_def) {
1261
1262
debug ! ( "Search already seen adt_def: {:?}" , adt_def) ;
1262
1263
// let caller continue its search
1263
1264
return false ;
1264
1265
}
1265
1266
1267
+ let non_structural = self . tcx . infer_ctxt ( ) . enter ( |infcx| {
1268
+ let cause = ObligationCause :: new ( self . span , self . id , ConstPatternStructural ) ;
1269
+ let mut fulfillment_cx = traits:: FulfillmentContext :: new ( ) ;
1270
+ let structural_def_id = self . tcx . lang_items ( ) . structural_trait ( ) . unwrap ( ) ;
1271
+ fulfillment_cx. register_bound (
1272
+ & infcx, ty:: ParamEnv :: empty ( ) , ty, structural_def_id, cause) ;
1273
+ if let Err ( _err) = fulfillment_cx. select_all_or_error ( & infcx) {
1274
+ // initial prototype: don't report any trait fulfillment error here.
1275
+ //
1276
+ // infcx.report_fulfillment_errors(&err, None, false);
1277
+ true
1278
+ } else {
1279
+ false
1280
+ }
1281
+ } ) ;
1282
+
1283
+ if non_structural {
1284
+ debug ! ( "Search found ty: {:?}" , ty) ;
1285
+ self . found = Some ( & adt_def) ;
1286
+ return true // Halt visiting!
1287
+ }
1288
+
1266
1289
self . seen . insert ( adt_def) ;
1267
1290
1268
1291
// `#[structural_match]` does not care about the
0 commit comments