@@ -378,67 +378,69 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
378
378
let mut substituted_predicates = Vec :: new ( ) ;
379
379
380
380
let generics = self . tcx . generics_of ( def_id) ;
381
- let defaulted_params = generics. types . iter ( )
382
- . filter ( |def| def. has_default &&
383
- def. index >= generics. parent_count ( ) as u32 ) ;
384
- // WF checks for type parameter defaults. See test `type-check-defaults.rs` for examples.
385
- for param_def in defaulted_params {
386
- // This parameter has a default value. Check that this default value is well-formed.
387
- // For example this forbids the declaration:
388
- // struct Foo<T = Vec<[u32]>> { .. }
389
- // Here `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
390
- let d = param_def. def_id ;
381
+ let is_our_default = |def : & ty:: TypeParameterDef |
382
+ def. has_default && def. index >= generics. parent_count ( ) as u32 ;
383
+ let defaulted_params = generics. types . iter ( ) . cloned ( ) . filter ( & is_our_default) ;
384
+ // Check that defaults are well-formed. See test `type-check-defaults.rs`.
385
+ // For example this forbids the declaration:
386
+ // struct Foo<T = Vec<[u32]>> { .. }
387
+ // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
388
+ for d in defaulted_params. map ( |p| p. def_id ) {
391
389
fcx. register_wf_obligation ( fcx. tcx . type_of ( d) , fcx. tcx . def_span ( d) , self . code . clone ( ) ) ;
390
+ }
392
391
393
- // Check the clauses are well-formed when the param is substituted by it's default.
394
- // For example this forbids the following declaration because `String` is not `Copy`:
395
- // struct Foo<T: Copy = String> { .. }
396
- //
397
- // In `trait Trait: Super`, checking `Self: Trait` or `Self: Super` is problematic.
398
- // Therefore we skip such predicates. This means we check less than we could.
399
- for pred in predicates. predicates . iter ( ) . filter ( |p| !( is_trait && p. has_self_ty ( ) ) ) {
400
- let mut skip = true ;
401
- let substs = ty:: subst:: Substs :: for_item ( fcx. tcx , def_id, |def, _| {
402
- // All regions are identity.
403
- fcx. tcx . mk_region ( ty:: ReEarlyBound ( def. to_early_bound_region_data ( ) ) )
404
- } , |def, _| {
405
- let identity_ty = fcx. tcx . mk_param_from_def ( def) ;
406
- if def. index != param_def. index {
407
- identity_ty
408
- } else {
409
- let sized = fcx. tcx . lang_items ( ) . sized_trait ( ) ;
410
- let pred_is_sized = match pred {
411
- ty:: Predicate :: Trait ( p) => Some ( p. def_id ( ) ) == sized,
412
- _ => false ,
413
- } ;
414
- let default_ty = fcx. tcx . type_of ( def. def_id ) ;
415
- let default_is_self = match default_ty. sty {
416
- ty:: TyParam ( ref p) => p. is_self ( ) ,
417
- _ => false
418
- } ;
419
- // In trait defs, skip `Self: Sized` when `Self` is the default.
420
- if is_trait && pred_is_sized && default_is_self {
421
- identity_ty
422
- } else {
423
- skip = false ;
424
- default_ty
425
- }
426
- }
427
- } ) ;
428
- if skip { continue ; }
429
- substituted_predicates. push ( match pred {
430
- // In trait predicates, substitute defaults only for the LHS.
431
- // See test `defaults-well-formedness.rs` for why substituting the RHS is bad.
432
- ty:: Predicate :: Trait ( t_pred) => {
433
- let trait_ref = t_pred. map_bound ( |t_pred| {
434
- let mut trait_subs = t_pred. trait_ref . substs . to_vec ( ) ;
435
- trait_subs[ 0 ] = t_pred. self_ty ( ) . subst ( fcx. tcx , substs) . into ( ) ;
436
- ty:: TraitRef :: new ( t_pred. def_id ( ) , fcx. tcx . intern_substs ( & trait_subs) )
437
- } ) ;
438
- ty:: Predicate :: Trait ( trait_ref. to_poly_trait_predicate ( ) )
439
- }
440
- _ => pred. subst ( fcx. tcx , substs)
441
- } ) ;
392
+ // Check that trait predicates are WF when params are substituted by their defaults.
393
+ // We don't want to overly constrain the predicates that may be written but we
394
+ // want to catch obviously wrong cases such as `struct Foo<T: Copy = String>`
395
+ // or cases that may cause backwards incompatibility such as a library going from
396
+ // `pub struct Foo<T>` to `pub struct Foo<T, U = i32>` where U: Trait<T>`
397
+ // which may break existing uses of Foo<T>.
398
+ // Therefore the check we do is: If if all params appearing in the LHS of the predicate
399
+ // have defaults then we verify that it is WF with all defaults substituted simultaneously.
400
+ // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
401
+ //
402
+ // First, we build the defaulted substitution.
403
+ let mut defaulted_params = Vec :: new ( ) ;
404
+ let substs = ty:: subst:: Substs :: for_item ( fcx. tcx , def_id, |def, _| {
405
+ // All regions are identity.
406
+ fcx. tcx . mk_region ( ty:: ReEarlyBound ( def. to_early_bound_region_data ( ) ) )
407
+ } , |def, _| {
408
+ if !is_our_default ( def) {
409
+ // Identity substitution.
410
+ fcx. tcx . mk_param_from_def ( def)
411
+ } else {
412
+ // Substitute with default.
413
+ defaulted_params. push ( def. index ) ;
414
+ fcx. tcx . type_of ( def. def_id )
415
+ }
416
+ } ) ;
417
+ // In `trait Trait: Super`, checking `Self: Trait` or `Self: Super` is problematic.
418
+ // We avoid those by skipping any predicates in trait declarations that contain `Self`,
419
+ // which is excessive so we end up checking less than we could.
420
+ for pred in predicates. predicates . iter ( )
421
+ . filter_map ( ty:: Predicate :: as_poly_trait_predicate)
422
+ . filter ( |p| !( is_trait && p. has_self_ty ( ) ) ) {
423
+ let is_defaulted_param = |ty : ty:: Ty | match ty. sty {
424
+ ty:: TyParam ( p) => defaulted_params. contains ( & p. idx ) ,
425
+ _ => false
426
+ } ;
427
+ // If there is a non-defaulted param in the LHS, don't check the substituted predicate.
428
+ // `skip_binder()` is ok, we're only inspecting the type params.
429
+ if !pred. skip_binder ( ) . self_ty ( ) . walk ( ) . all ( is_defaulted_param) {
430
+ continue ;
431
+ }
432
+ let substituted_pred = pred. subst ( fcx. tcx , substs) ;
433
+ // `skip_binder()` is ok, we're only inspecting for `has_self_ty()`.
434
+ let substituted_lhs = substituted_pred. skip_binder ( ) . self_ty ( ) ;
435
+ // In trait defs, don't check `Self: Sized` when `Self` is the default.
436
+ let pred_is_sized = Some ( pred. def_id ( ) ) == fcx. tcx . lang_items ( ) . sized_trait ( ) ;
437
+ if is_trait && substituted_lhs. has_self_ty ( ) && pred_is_sized {
438
+ continue ;
439
+ }
440
+ let pred = ty:: Predicate :: Trait ( pred. subst ( fcx. tcx , substs) ) ;
441
+ // Avoid duplicates.
442
+ if !predicates. predicates . contains ( & pred) {
443
+ substituted_predicates. push ( pred) ;
442
444
}
443
445
}
444
446
0 commit comments