Skip to content

Commit 5c15163

Browse files
nikomatsakistmandry
andcommitted
prove defaults meet WF requirements, not that they are WF
If we have ```rust struct Foo<T: Copy = String> { .. } ``` the old code would have proven that `String: Copy` was WF -- this, incidentally, also proved that `String: Copy`. The new code just proves `String: Copy` directly. Co-authored-by: Tyler Mandry <[email protected]>
1 parent 2eb6969 commit 5c15163

File tree

2 files changed

+56
-22
lines changed

2 files changed

+56
-22
lines changed

src/librustc_typeck/check/wfcheck.rs

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -364,15 +364,16 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
364364
}
365365

366366
/// Checks where clauses and inline bounds that are declared on def_id.
367-
fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
368-
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
369-
span: Span,
370-
def_id: DefId) {
367+
fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
368+
tcx: TyCtxt<'a, 'gcx, 'gcx>,
369+
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
370+
span: Span,
371+
def_id: DefId,
372+
) {
371373
use ty::subst::Subst;
372374
use rustc::ty::TypeFoldable;
373375

374-
let mut predicates = fcx.tcx.predicates_of(def_id);
375-
let mut substituted_predicates = Vec::new();
376+
let predicates = fcx.tcx.predicates_of(def_id);
376377

377378
let generics = tcx.generics_of(def_id);
378379
let is_our_default = |def: &ty::GenericParamDef| {
@@ -433,7 +434,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
433434
}
434435
});
435436
// Now we build the substituted predicates.
436-
for &pred in predicates.predicates.iter() {
437+
let default_obligations = predicates.predicates.iter().flat_map(|&pred| {
437438
struct CountParams { params: FxHashSet<u32> }
438439
impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
439440
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
@@ -455,21 +456,37 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
455456
let substituted_pred = pred.subst(fcx.tcx, substs);
456457
// Don't check non-defaulted params, dependent defaults (including lifetimes)
457458
// or preds with multiple params.
458-
if substituted_pred.references_error() || param_count.params.len() > 1
459-
|| has_region {
460-
continue;
461-
}
462-
// Avoid duplication of predicates that contain no parameters, for example.
463-
if !predicates.predicates.contains(&substituted_pred) {
464-
substituted_predicates.push(substituted_pred);
459+
if {
460+
substituted_pred.references_error() || param_count.params.len() > 1
461+
|| has_region
462+
} {
463+
None
464+
} else if predicates.predicates.contains(&substituted_pred) {
465+
// Avoid duplication of predicates that contain no parameters, for example.
466+
None
467+
} else {
468+
Some(substituted_pred)
465469
}
466-
}
470+
}).map(|pred| {
471+
// convert each of those into an obligation. So if you have
472+
// something like `struct Foo<T: Copy = String>`, we would
473+
// take that predicate `T: Copy`, substitute to `String: Copy`
474+
// (actually that happens in the previous `flat_map` call),
475+
// and then try to prove it (in this case, we'll fail).
476+
//
477+
// Note the subtle difference from how we handle `predicates`
478+
// below: there, we are not trying to prove those predicates
479+
// to be *true* but merely *well-formed*.
480+
let pred = fcx.normalize_associated_types_in(span, &pred);
481+
let cause = traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def_id));
482+
traits::Obligation::new(cause, fcx.param_env, pred)
483+
});
467484

468-
predicates.predicates.extend(substituted_predicates);
469485
let predicates = predicates.instantiate_identity(fcx.tcx);
470486
let predicates = fcx.normalize_associated_types_in(span, &predicates);
471487

472-
let obligations =
488+
debug!("check_where_clauses: predicates={:?}", predicates.predicates);
489+
let wf_obligations =
473490
predicates.predicates
474491
.iter()
475492
.flat_map(|p| ty::wf::predicate_obligations(fcx,
@@ -478,7 +495,8 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
478495
p,
479496
span));
480497

481-
for obligation in obligations {
498+
for obligation in wf_obligations.chain(default_obligations) {
499+
debug!("next obligation cause: {:?}", obligation.cause);
482500
fcx.register_predicate(obligation);
483501
}
484502
}

src/test/ui/type-check-defaults.stderr

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,35 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not sa
3030
LL | struct Bounds<T:Copy=String>(T);
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
3232
|
33-
= note: required by `std::marker::Copy`
33+
note: required by `Bounds`
34+
--> $DIR/type-check-defaults.rs:21:1
35+
|
36+
LL | struct Bounds<T:Copy=String>(T);
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3438

3539
error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
3640
--> $DIR/type-check-defaults.rs:24:1
3741
|
3842
LL | struct WhereClause<T=String>(T) where T: Copy;
3943
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
4044
|
41-
= note: required by `std::marker::Copy`
45+
note: required by `WhereClause`
46+
--> $DIR/type-check-defaults.rs:24:1
47+
|
48+
LL | struct WhereClause<T=String>(T) where T: Copy;
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4250

4351
error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
4452
--> $DIR/type-check-defaults.rs:27:1
4553
|
4654
LL | trait TraitBound<T:Copy=String> {}
4755
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
4856
|
49-
= note: required by `std::marker::Copy`
57+
note: required by `TraitBound`
58+
--> $DIR/type-check-defaults.rs:27:1
59+
|
60+
LL | trait TraitBound<T:Copy=String> {}
61+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5062

5163
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
5264
--> $DIR/type-check-defaults.rs:31:1
@@ -68,7 +80,11 @@ LL | trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
6880
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8`
6981
|
7082
= help: the trait `std::ops::Add<u8>` is not implemented for `i32`
71-
= note: required by `std::ops::Add`
83+
note: required by `ProjectionPred`
84+
--> $DIR/type-check-defaults.rs:34:1
85+
|
86+
LL | trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
87+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7288

7389
error: aborting due to 7 previous errors
7490

0 commit comments

Comments
 (0)