Skip to content

Commit e09082c

Browse files
committed
default WF: Substitute defaults individually in the clauses.
1 parent 796195c commit e09082c

File tree

3 files changed

+64
-42
lines changed

3 files changed

+64
-42
lines changed

src/librustc_typeck/check/wfcheck.rs

+39-41
Original file line numberDiff line numberDiff line change
@@ -435,58 +435,56 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
435435
use ty::subst::Subst;
436436
use rustc::ty::TypeFoldable;
437437

438+
let mut predicates = fcx.tcx.predicates_of(def_id);
439+
let mut substituted_predicates = Vec::new();
440+
438441
let generics = self.tcx.generics_of(def_id);
439442
let defaulted_params = generics.types.iter()
440443
.filter(|def| def.has_default &&
441444
def.index >= generics.parent_count() as u32);
442-
// Defaults must be well-formed.
443-
for d in defaulted_params.map(|p| p.def_id) {
445+
for param_def in defaulted_params {
446+
// Defaults must be well-formed.
447+
let d = param_def.def_id;
444448
fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone());
445-
}
446-
// Check that each default fulfills the bounds on it's parameter.
447-
// We go over each predicate and duplicate it, substituting defaults in the self type.
448-
let mut predicates = fcx.tcx.predicates_of(def_id);
449-
let mut default_predicates = Vec::new();
450-
// In `trait Trait : Super` predicates as `Self: Trait` and `Self: Super` are a problem.
451-
// Therefore we skip such predicates. This means we check less than we could.
452-
for pred in predicates.predicates.iter().filter(|p| !(is_trait && p.has_self_ty())) {
453-
let mut skip = false;
454-
let mut no_default = true;
455-
let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
456-
// All regions are identity.
457-
fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
458-
}, |def, _| {
459-
// No default or generic comes from parent, identity substitution.
460-
if !def.has_default || (def.index as usize) < generics.parent_count() {
461-
fcx.tcx.mk_param_from_def(def)
462-
} else {
463-
no_default = false;
464-
// Has a default, use it in the substitution.
465-
let default_ty = fcx.tcx.type_of(def.def_id);
466-
467-
match default_ty.sty {
468-
// Skip `Self: Sized` when `Self` is the default. Needed in traits.
469-
ty::TyParam(ref p) if is_trait && p.is_self() => {
470-
if let ty::Predicate::Trait(p) = pred {
471-
if Some(p.def_id()) == fcx.tcx.lang_items().sized_trait() {
472-
skip = true;
473-
}
474-
}
449+
// Check the clauses are well-formed when the param is substituted by it's default.
450+
// In trait definitions, predicates as `Self: Trait` and `Self: Super` are problematic.
451+
// Therefore we skip such predicates. This means we check less than we could.
452+
for pred in predicates.predicates.iter().filter(|p| !(is_trait && p.has_self_ty())) {
453+
let mut skip = true;
454+
let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
455+
// All regions are identity.
456+
fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
457+
}, |def, _| {
458+
let identity_substs = fcx.tcx.mk_param_from_def(def);
459+
if def.index != param_def.index {
460+
identity_substs
461+
} else {
462+
let sized = fcx.tcx.lang_items().sized_trait();
463+
let pred_is_sized = match pred {
464+
ty::Predicate::Trait(p) => Some(p.def_id()) == sized,
465+
_ => false,
466+
};
467+
let default_ty = fcx.tcx.type_of(def.def_id);
468+
let default_is_self = match default_ty.sty {
469+
ty::TyParam(ref p) => p.is_self(),
470+
_ => false
471+
};
472+
// In trait defs, skip `Self: Sized` when `Self` is the default.
473+
if is_trait && pred_is_sized && default_is_self {
474+
identity_substs
475+
} else {
476+
skip = false;
477+
default_ty
475478
}
476-
_ => ()
477479
}
478-
default_ty
480+
});
481+
if !skip {
482+
substituted_predicates.push(pred.subst(fcx.tcx, substs));
479483
}
480-
});
481-
482-
if skip || no_default {
483-
continue;
484484
}
485-
486-
default_predicates.push(pred.subst(fcx.tcx, substs));
487485
}
488486

489-
predicates.predicates.extend(default_predicates);
487+
predicates.predicates.extend(substituted_predicates);
490488
let predicates = predicates.instantiate_identity(fcx.tcx);
491489
let predicates = fcx.normalize_associated_types_in(span, &predicates);
492490

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

+6
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,10 @@ trait SelfBound<T:Copy=Self> {}
2929

3030
trait FooTrait<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
3131

32+
trait Trait {}
33+
struct TwoParams<T, U>(T, U);
34+
impl Trait for TwoParams<i32, i32> {}
35+
// Check that each default is substituted individually in the clauses.
36+
struct Bogus<T = i32, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Trait;
37+
3238
fn main() { }

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

+19-1
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,23 @@ error[E0277]: the trait bound `i32: std::ops::Add<u8>` is not satisfied
6767
= help: the trait `std::ops::Add<u8>` is not implemented for `i32`
6868
= note: required by `std::ops::Add`
6969

70-
error: aborting due to 8 previous errors
70+
error[E0277]: the trait bound `TwoParams<i32, U>: Trait` is not satisfied
71+
--> $DIR/type-check-defaults.rs:36:1
72+
|
73+
36 | struct Bogus<T = i32, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Trait;
74+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams<i32, U>`
75+
|
76+
= help: consider adding a `where TwoParams<i32, U>: Trait` bound
77+
= note: required by `Trait`
78+
79+
error[E0277]: the trait bound `TwoParams<T, i32>: Trait` is not satisfied
80+
--> $DIR/type-check-defaults.rs:36:1
81+
|
82+
36 | struct Bogus<T = i32, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Trait;
83+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams<T, i32>`
84+
|
85+
= help: consider adding a `where TwoParams<T, i32>: Trait` bound
86+
= note: required by `Trait`
87+
88+
error: aborting due to 10 previous errors
7189

0 commit comments

Comments
 (0)