From 4d9703373d91fe83155798be0571b3349a9513f9 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Fri, 15 Dec 2017 16:04:25 -0200 Subject: [PATCH 01/15] Type check defaults. And refactor duplicated code. --- src/librustc_typeck/check/wfcheck.rs | 146 ++++++++++++++++++++---- src/test/run-pass/type-macros-simple.rs | 1 + src/test/ui/type-check-defaults.rs | 31 +++++ src/test/ui/type-check-defaults.stderr | 62 ++++++++++ 4 files changed, 218 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/type-check-defaults.rs create mode 100644 src/test/ui/type-check-defaults.stderr diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 3668fc46ddc27..c3aaeae69633f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -185,10 +185,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { reject_shadowing_type_parameters(fcx.tcx, item.def_id); let sig = fcx.tcx.fn_sig(item.def_id); let sig = fcx.normalize_associated_types_in(span, &sig); - let predicates = fcx.tcx.predicates_of(item.def_id) - .instantiate_identity(fcx.tcx); - let predicates = fcx.normalize_associated_types_in(span, &predicates); - this.check_fn_or_method(fcx, span, sig, &predicates, + this.check_fn_or_method(fcx, span, sig, item.def_id, &mut implied_bounds); let sig_if_method = sig_if_method.expect("bad signature for method"); this.check_method_receiver(fcx, sig_if_method, &item, self_ty); @@ -272,9 +269,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } } - let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx); - let predicates = fcx.normalize_associated_types_in(item.span, &predicates); - this.check_where_clauses(fcx, item.span, &predicates); + self.check_where_clauses(fcx, item.span, def_id); vec![] // no implied bounds in a struct def'n }); @@ -282,10 +277,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fn check_trait(&mut self, item: &hir::Item) { let trait_def_id = self.tcx.hir.local_def_id(item.id); - self.for_item(item).with_fcx(|fcx, this| { - let predicates = fcx.tcx.predicates_of(trait_def_id).instantiate_identity(fcx.tcx); - let predicates = fcx.normalize_associated_types_in(item.span, &predicates); - this.check_where_clauses(fcx, item.span, &predicates); + + self.for_item(item).with_fcx(|fcx, _| { + self.check_where_clauses(fcx, item.span, trait_def_id); vec![] }); } @@ -295,12 +289,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let def_id = fcx.tcx.hir.local_def_id(item.id); let sig = fcx.tcx.fn_sig(def_id); let sig = fcx.normalize_associated_types_in(item.span, &sig); - - let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx); - let predicates = fcx.normalize_associated_types_in(item.span, &predicates); - let mut implied_bounds = vec![]; - this.check_fn_or_method(fcx, item.span, sig, &predicates, + this.check_fn_or_method(fcx, item.span, sig, def_id, &mut implied_bounds); implied_bounds }) @@ -354,19 +344,132 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } } - let predicates = fcx.tcx.predicates_of(item_def_id).instantiate_identity(fcx.tcx); - let predicates = fcx.normalize_associated_types_in(item.span, &predicates); - this.check_where_clauses(fcx, item.span, &predicates); + this.check_where_clauses(fcx, item.span, item_def_id); fcx.impl_implied_bounds(item_def_id, item.span) }); } + /// Checks where clauses and inline bounds. fn check_where_clauses<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, - predicates: &ty::InstantiatedPredicates<'tcx>) + def_id: DefId) { + use ty::subst::Subst; + use ty::Predicate; + + // Check that each default fulfills the bounds on it's parameter. + // We go over each predicate and duplicate it, substituting defaults in the self type. + let mut predicates = fcx.tcx.predicates_of(def_id); + let mut default_predicates = Vec::new(); + for pred in &predicates.predicates { + let mut self_ty = match pred { + Predicate::Trait(trait_pred) => trait_pred.skip_binder().self_ty(), + Predicate::TypeOutlives(outlives_pred) => (outlives_pred.0).0, + Predicate::Projection(proj_pred) => { + fcx.tcx.mk_ty(ty::TyProjection(proj_pred.skip_binder().projection_ty)) + } + // Lifetime params can't have defaults. + Predicate::RegionOutlives(..) => continue, + _ => bug!("Predicate {:?} not supported in where clauses.", pred) + }; + + let mut skip = false; + let mut no_default = true; + let generics = self.tcx.generics_of(def_id); + let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { + // All regions are identity. + fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) + }, |def, _| { + // No default or generic comes from parent, identity substitution. + if !def.has_default || (def.index as usize) < generics.parent_count() { + fcx.tcx.mk_param_from_def(def) + } else { + no_default = false; + // Has a default, use it in the substitution. + let default_ty = fcx.tcx.type_of(def.def_id); + // Skip `Self : Self` in traits, it's problematic. + // This means we probably check less than we could. + let should_skip = match self_ty.sty { + ty::TyParam(ref p) => { + // lhs is Self && rhs is Self + p.is_self() && match pred { + Predicate::Trait(p) => p.def_id() == def_id, + Predicate::TypeOutlives(_) => false, + _ => bug!("Unexpected predicate {:?}", pred) + } + } + ty::TyProjection(ref proj) => { + let mut projection = proj; + let mut next_typ = &projection.substs[0].as_type().unwrap().sty; + // Dig through projections. + while let ty::TyProjection(ref proj) = next_typ { + projection = proj; + next_typ = &projection.substs[0].as_type().unwrap().sty; + } + let lhs_is_self = match next_typ { + ty::TyParam(ref p) => p.is_self(), + _ => false + }; + let rhs = fcx.tcx.associated_item(projection.item_def_id) + .container + .assert_trait(); + lhs_is_self && rhs == def_id + } + _ => false + }; + skip = skip || should_skip; + + match default_ty.sty { + // Skip `Self: Sized` when `Self` is the default. Needed in traits. + ty::TyParam(ref p) if p.is_self() => { + if let Predicate::Trait(p) = pred { + if Some(p.def_id()) == fcx.tcx.lang_items().sized_trait() { + skip = true; + } + } + } + _ => () + } + default_ty + } + }); + + if skip || no_default { + continue; + } + + self_ty = self_ty.subst(fcx.tcx, substs); + default_predicates.push(match pred { + Predicate::Trait(trait_pred) => { + let mut substs = trait_pred.skip_binder().trait_ref.substs.to_vec(); + substs[0] = self_ty.into(); + let substs = fcx.tcx.intern_substs(&substs); + let trait_ref = ty::Binder(ty::TraitRef::new(trait_pred.def_id(), substs)); + Predicate::Trait(trait_ref.to_poly_trait_predicate()) + } + Predicate::TypeOutlives(pred) => { + Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(self_ty, (pred.0).1))) + } + Predicate::Projection(proj_pred) => { + let projection_ty = match self_ty.sty { + ty::TyProjection(proj_ty) => proj_ty, + _ => bug!("self_ty not projection for projection predicate.") + }; + Predicate::Projection(ty::Binder(ty::ProjectionPredicate { + projection_ty, + ty: proj_pred.ty().skip_binder() + })) + } + _ => bug!("Predicate {:?} not supported for type params.", pred) + }); + } + + predicates.predicates.extend(default_predicates); + let predicates = predicates.instantiate_identity(fcx.tcx); + let predicates = fcx.normalize_associated_types_in(span, &predicates); + let obligations = predicates.predicates .iter() @@ -385,7 +488,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, sig: ty::PolyFnSig<'tcx>, - predicates: &ty::InstantiatedPredicates<'tcx>, def_id: DefId, implied_bounds: &mut Vec>) { @@ -402,7 +504,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // FIXME(#25759) return types should not be implied bounds implied_bounds.push(sig.output()); - self.check_where_clauses(fcx, span, predicates); + self.check_where_clauses(fcx, span, def_id); } fn check_method_receiver<'fcx, 'tcx>(&mut self, diff --git a/src/test/run-pass/type-macros-simple.rs b/src/test/run-pass/type-macros-simple.rs index c61133f795b34..67b1d2c06e314 100644 --- a/src/test/run-pass/type-macros-simple.rs +++ b/src/test/run-pass/type-macros-simple.rs @@ -34,3 +34,4 @@ fn issue_36540() { } trait Trait {} +impl Trait for i32 {} diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs new file mode 100644 index 0000000000000..6e50dd46afc71 --- /dev/null +++ b/src/test/ui/type-check-defaults.rs @@ -0,0 +1,31 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// compile-flags: --error-format=human + +use std::iter::FromIterator; +use std::vec::IntoIter; +use std::ops::Add; + +struct Foo>(T, U); +struct WellFormed>(Z); + +struct WellFormedProjection::Item>(A, T); + +struct Bounds(T); + +struct WhereClause(T) where T: Copy; + +trait TraitBound {} + +trait SelfBound {} + +trait FooTrait> where T::Item : Add {} + +fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr new file mode 100644 index 0000000000000..6f9fee62e5076 --- /dev/null +++ b/src/test/ui/type-check-defaults.stderr @@ -0,0 +1,62 @@ +error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied + --> $DIR/type-check-defaults.rs:17:1 + | +17 | struct WellFormed>(Z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` + | + = help: the trait `std::iter::FromIterator` is not implemented for `i32` + = note: required by `Foo` + +error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied + --> $DIR/type-check-defaults.rs:19:1 + | +19 | struct WellFormedProjection::Item>(A, T); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `A` is not an iterator; maybe try calling `.iter()` or a similar method + | + = help: the trait `std::iter::Iterator` is not implemented for `A` + = help: consider adding a `where A: std::iter::Iterator` bound + +error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied + --> $DIR/type-check-defaults.rs:21:1 + | +21 | struct Bounds(T); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | + = note: required by `std::marker::Copy` + +error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied + --> $DIR/type-check-defaults.rs:23:1 + | +23 | struct WhereClause(T) where T: Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | + = note: required by `std::marker::Copy` + +error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied + --> $DIR/type-check-defaults.rs:25:1 + | +25 | trait TraitBound {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | + = note: required by `std::marker::Copy` + +error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied + --> $DIR/type-check-defaults.rs:27:1 + | +27 | trait SelfBound {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Self` + | + = help: consider adding a `where Self: std::marker::Copy` bound + = note: required by `std::marker::Copy` + +error[E0277]: the trait bound `i32: std::ops::Add` is not satisfied + --> $DIR/type-check-defaults.rs:29:1 + | +29 | trait FooTrait> where T::Item : Add {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` + | + = help: the trait `std::ops::Add` is not implemented for `i32` + = note: required by `std::ops::Add` + +error: aborting due to 7 previous errors + From a6bb32c9cc95a21835c81baa6f531ce38d67fbde Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 18 Dec 2017 12:40:15 -0200 Subject: [PATCH 02/15] Check WF of defaults even when there are no bounds. --- src/librustc_typeck/check/wfcheck.rs | 11 +++++++- src/test/ui/type-check-defaults.rs | 1 + src/test/ui/type-check-defaults.stderr | 39 ++++++++++++++++---------- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index c3aaeae69633f..bf004df824b11 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -359,6 +359,16 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { use ty::subst::Subst; use ty::Predicate; + let generics = self.tcx.generics_of(def_id); + let defaults = generics.types.iter().filter_map(|p| match p.has_default { + true => Some(p.def_id), + false => None, + }); + // Defaults must be well-formed. + for d in defaults { + fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone()); + } + // Check that each default fulfills the bounds on it's parameter. // We go over each predicate and duplicate it, substituting defaults in the self type. let mut predicates = fcx.tcx.predicates_of(def_id); @@ -377,7 +387,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let mut skip = false; let mut no_default = true; - let generics = self.tcx.generics_of(def_id); let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { // All regions are identity. fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index 6e50dd46afc71..2264fb860f155 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -15,6 +15,7 @@ use std::ops::Add; struct Foo>(T, U); struct WellFormed>(Z); +struct WellFormedNoBounds>(Z); struct WellFormedProjection::Item>(A, T); diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index 6f9fee62e5076..2a9f4eb693caa 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -1,62 +1,71 @@ error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied - --> $DIR/type-check-defaults.rs:17:1 + --> $DIR/type-check-defaults.rs:17:19 | 17 | struct WellFormed>(Z); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` + | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` + | + = help: the trait `std::iter::FromIterator` is not implemented for `i32` + = note: required by `Foo` + +error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied + --> $DIR/type-check-defaults.rs:18:27 + | +18 | struct WellFormedNoBounds>(Z); + | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` = note: required by `Foo` error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied - --> $DIR/type-check-defaults.rs:19:1 + --> $DIR/type-check-defaults.rs:20:1 | -19 | struct WellFormedProjection::Item>(A, T); +20 | struct WellFormedProjection::Item>(A, T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `A` is not an iterator; maybe try calling `.iter()` or a similar method | = help: the trait `std::iter::Iterator` is not implemented for `A` = help: consider adding a `where A: std::iter::Iterator` bound error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:21:1 + --> $DIR/type-check-defaults.rs:22:1 | -21 | struct Bounds(T); +22 | struct Bounds(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:23:1 + --> $DIR/type-check-defaults.rs:24:1 | -23 | struct WhereClause(T) where T: Copy; +24 | struct WhereClause(T) where T: Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:25:1 + --> $DIR/type-check-defaults.rs:26:1 | -25 | trait TraitBound {} +26 | trait TraitBound {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:27:1 + --> $DIR/type-check-defaults.rs:28:1 | -27 | trait SelfBound {} +28 | trait SelfBound {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Self` | = help: consider adding a `where Self: std::marker::Copy` bound = note: required by `std::marker::Copy` error[E0277]: the trait bound `i32: std::ops::Add` is not satisfied - --> $DIR/type-check-defaults.rs:29:1 + --> $DIR/type-check-defaults.rs:30:1 | -29 | trait FooTrait> where T::Item : Add {} +30 | trait FooTrait> where T::Item : Add {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` | = help: the trait `std::ops::Add` is not implemented for `i32` = note: required by `std::ops::Add` -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors From 87c2ad048a8ef674e2f7c147cf81f7f6f5ed3872 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 21 Dec 2017 11:25:32 -0200 Subject: [PATCH 03/15] default WF: Leverage type substitution, less workarounding `Predicate` is `TypeFoldable`, use that. Be less clever with the workaround. --- src/librustc_typeck/check/wfcheck.rs | 111 ++++++++------------------- 1 file changed, 31 insertions(+), 80 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index bf004df824b11..2b004eb53c81e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -279,7 +279,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let trait_def_id = self.tcx.hir.local_def_id(item.id); self.for_item(item).with_fcx(|fcx, _| { - self.check_where_clauses(fcx, item.span, trait_def_id); + self.check_trait_where_clauses(fcx, item.span, trait_def_id); vec![] }); } @@ -350,41 +350,46 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { }); } - /// Checks where clauses and inline bounds. + /// Checks where clauses and inline bounds that are declared on def_id. fn check_where_clauses<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, - def_id: DefId) + def_id: DefId) { + self.inner_check_where_clauses(fcx, span, def_id, false) + } + + fn check_trait_where_clauses<'fcx, 'tcx>(&mut self, + fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, + span: Span, + def_id: DefId) { + self.inner_check_where_clauses(fcx, span, def_id, true) + } + + /// Checks where clauses and inline bounds that are declared on def_id. + fn inner_check_where_clauses<'fcx, 'tcx>(&mut self, + fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, + span: Span, + def_id: DefId, + is_trait: bool) { use ty::subst::Subst; - use ty::Predicate; + use rustc::ty::TypeFoldable; let generics = self.tcx.generics_of(def_id); - let defaults = generics.types.iter().filter_map(|p| match p.has_default { - true => Some(p.def_id), - false => None, - }); + let defaulted_params = generics.types.iter() + .filter(|def| def.has_default && + def.index >= generics.parent_count() as u32); // Defaults must be well-formed. - for d in defaults { + for d in defaulted_params.map(|p| p.def_id) { fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone()); } - // Check that each default fulfills the bounds on it's parameter. // We go over each predicate and duplicate it, substituting defaults in the self type. let mut predicates = fcx.tcx.predicates_of(def_id); let mut default_predicates = Vec::new(); - for pred in &predicates.predicates { - let mut self_ty = match pred { - Predicate::Trait(trait_pred) => trait_pred.skip_binder().self_ty(), - Predicate::TypeOutlives(outlives_pred) => (outlives_pred.0).0, - Predicate::Projection(proj_pred) => { - fcx.tcx.mk_ty(ty::TyProjection(proj_pred.skip_binder().projection_ty)) - } - // Lifetime params can't have defaults. - Predicate::RegionOutlives(..) => continue, - _ => bug!("Predicate {:?} not supported in where clauses.", pred) - }; - + // In `trait Trait : Super` predicates as `Self: Trait` and `Self: Super` are a problem. + // Therefore we skip such predicates. This means we check less than we could. + for pred in predicates.predicates.iter().filter(|p| !(is_trait && p.has_self_ty())) { let mut skip = false; let mut no_default = true; let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { @@ -398,42 +403,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { no_default = false; // Has a default, use it in the substitution. let default_ty = fcx.tcx.type_of(def.def_id); - // Skip `Self : Self` in traits, it's problematic. - // This means we probably check less than we could. - let should_skip = match self_ty.sty { - ty::TyParam(ref p) => { - // lhs is Self && rhs is Self - p.is_self() && match pred { - Predicate::Trait(p) => p.def_id() == def_id, - Predicate::TypeOutlives(_) => false, - _ => bug!("Unexpected predicate {:?}", pred) - } - } - ty::TyProjection(ref proj) => { - let mut projection = proj; - let mut next_typ = &projection.substs[0].as_type().unwrap().sty; - // Dig through projections. - while let ty::TyProjection(ref proj) = next_typ { - projection = proj; - next_typ = &projection.substs[0].as_type().unwrap().sty; - } - let lhs_is_self = match next_typ { - ty::TyParam(ref p) => p.is_self(), - _ => false - }; - let rhs = fcx.tcx.associated_item(projection.item_def_id) - .container - .assert_trait(); - lhs_is_self && rhs == def_id - } - _ => false - }; - skip = skip || should_skip; - match default_ty.sty { + match default_ty.sty { // Skip `Self: Sized` when `Self` is the default. Needed in traits. - ty::TyParam(ref p) if p.is_self() => { - if let Predicate::Trait(p) = pred { + ty::TyParam(ref p) if is_trait && p.is_self() => { + if let ty::Predicate::Trait(p) = pred { if Some(p.def_id()) == fcx.tcx.lang_items().sized_trait() { skip = true; } @@ -449,30 +423,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { continue; } - self_ty = self_ty.subst(fcx.tcx, substs); - default_predicates.push(match pred { - Predicate::Trait(trait_pred) => { - let mut substs = trait_pred.skip_binder().trait_ref.substs.to_vec(); - substs[0] = self_ty.into(); - let substs = fcx.tcx.intern_substs(&substs); - let trait_ref = ty::Binder(ty::TraitRef::new(trait_pred.def_id(), substs)); - Predicate::Trait(trait_ref.to_poly_trait_predicate()) - } - Predicate::TypeOutlives(pred) => { - Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(self_ty, (pred.0).1))) - } - Predicate::Projection(proj_pred) => { - let projection_ty = match self_ty.sty { - ty::TyProjection(proj_ty) => proj_ty, - _ => bug!("self_ty not projection for projection predicate.") - }; - Predicate::Projection(ty::Binder(ty::ProjectionPredicate { - projection_ty, - ty: proj_pred.ty().skip_binder() - })) - } - _ => bug!("Predicate {:?} not supported for type params.", pred) - }); + default_predicates.push(pred.subst(fcx.tcx, substs)); } predicates.predicates.extend(default_predicates); From d9c336afb782e30e90471887d7f63cfa4c28fc74 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 21 Dec 2017 13:36:16 -0200 Subject: [PATCH 04/15] default WF: Substitute defaults individually in the clauses. --- src/librustc_typeck/check/wfcheck.rs | 80 +++++++++++++------------- src/test/ui/type-check-defaults.rs | 6 ++ src/test/ui/type-check-defaults.stderr | 20 ++++++- 3 files changed, 64 insertions(+), 42 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 2b004eb53c81e..0a919eb3b8c15 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -375,58 +375,56 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { use ty::subst::Subst; use rustc::ty::TypeFoldable; + let mut predicates = fcx.tcx.predicates_of(def_id); + let mut substituted_predicates = Vec::new(); + let generics = self.tcx.generics_of(def_id); let defaulted_params = generics.types.iter() .filter(|def| def.has_default && def.index >= generics.parent_count() as u32); - // Defaults must be well-formed. - for d in defaulted_params.map(|p| p.def_id) { + for param_def in defaulted_params { + // Defaults must be well-formed. + let d = param_def.def_id; fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone()); - } - // Check that each default fulfills the bounds on it's parameter. - // We go over each predicate and duplicate it, substituting defaults in the self type. - let mut predicates = fcx.tcx.predicates_of(def_id); - let mut default_predicates = Vec::new(); - // In `trait Trait : Super` predicates as `Self: Trait` and `Self: Super` are a problem. - // Therefore we skip such predicates. This means we check less than we could. - for pred in predicates.predicates.iter().filter(|p| !(is_trait && p.has_self_ty())) { - let mut skip = false; - let mut no_default = true; - let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { - // All regions are identity. - fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) - }, |def, _| { - // No default or generic comes from parent, identity substitution. - if !def.has_default || (def.index as usize) < generics.parent_count() { - fcx.tcx.mk_param_from_def(def) - } else { - no_default = false; - // Has a default, use it in the substitution. - let default_ty = fcx.tcx.type_of(def.def_id); - - match default_ty.sty { - // Skip `Self: Sized` when `Self` is the default. Needed in traits. - ty::TyParam(ref p) if is_trait && p.is_self() => { - if let ty::Predicate::Trait(p) = pred { - if Some(p.def_id()) == fcx.tcx.lang_items().sized_trait() { - skip = true; - } - } + // Check the clauses are well-formed when the param is substituted by it's default. + // In trait definitions, predicates as `Self: Trait` and `Self: Super` are problematic. + // Therefore we skip such predicates. This means we check less than we could. + for pred in predicates.predicates.iter().filter(|p| !(is_trait && p.has_self_ty())) { + let mut skip = true; + let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { + // All regions are identity. + fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) + }, |def, _| { + let identity_substs = fcx.tcx.mk_param_from_def(def); + if def.index != param_def.index { + identity_substs + } else { + let sized = fcx.tcx.lang_items().sized_trait(); + let pred_is_sized = match pred { + ty::Predicate::Trait(p) => Some(p.def_id()) == sized, + _ => false, + }; + let default_ty = fcx.tcx.type_of(def.def_id); + let default_is_self = match default_ty.sty { + ty::TyParam(ref p) => p.is_self(), + _ => false + }; + // In trait defs, skip `Self: Sized` when `Self` is the default. + if is_trait && pred_is_sized && default_is_self { + identity_substs + } else { + skip = false; + default_ty } - _ => () } - default_ty + }); + if !skip { + substituted_predicates.push(pred.subst(fcx.tcx, substs)); } - }); - - if skip || no_default { - continue; } - - default_predicates.push(pred.subst(fcx.tcx, substs)); } - predicates.predicates.extend(default_predicates); + predicates.predicates.extend(substituted_predicates); let predicates = predicates.instantiate_identity(fcx.tcx); let predicates = fcx.normalize_associated_types_in(span, &predicates); diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index 2264fb860f155..a6e475eb1a3b5 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -29,4 +29,10 @@ trait SelfBound {} trait FooTrait> where T::Item : Add {} +trait Trait {} +struct TwoParams(T, U); +impl Trait for TwoParams {} +// Check that each default is substituted individually in the clauses. +struct Bogus(TwoParams) where TwoParams: Trait; + fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index 2a9f4eb693caa..cf11282f7d20c 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -67,5 +67,23 @@ error[E0277]: the trait bound `i32: std::ops::Add` is not satisfied = help: the trait `std::ops::Add` is not implemented for `i32` = note: required by `std::ops::Add` -error: aborting due to 8 previous errors +error[E0277]: the trait bound `TwoParams: Trait` is not satisfied + --> $DIR/type-check-defaults.rs:36:1 + | +36 | struct Bogus(TwoParams) where TwoParams: Trait; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams` + | + = help: consider adding a `where TwoParams: Trait` bound + = note: required by `Trait` + +error[E0277]: the trait bound `TwoParams: Trait` is not satisfied + --> $DIR/type-check-defaults.rs:36:1 + | +36 | struct Bogus(TwoParams) where TwoParams: Trait; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams` + | + = help: consider adding a `where TwoParams: Trait` bound + = note: required by `Trait` + +error: aborting due to 10 previous errors From 3b4a06272e8453c8b90f282b2b5b0e4c27993ff1 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sat, 23 Dec 2017 11:29:01 -0200 Subject: [PATCH 05/15] Go back to checking only the LHS of trait predicates. --- src/librustc_typeck/check/wfcheck.rs | 19 +++++++--- src/test/run-pass/defaults-well-formedness.rs | 14 ++++++++ src/test/ui/type-check-defaults.rs | 11 +++++- src/test/ui/type-check-defaults.stderr | 36 +++++++++---------- 4 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 src/test/run-pass/defaults-well-formedness.rs diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 0a919eb3b8c15..a16b806b6f125 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -387,7 +387,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let d = param_def.def_id; fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone()); // Check the clauses are well-formed when the param is substituted by it's default. - // In trait definitions, predicates as `Self: Trait` and `Self: Super` are problematic. + // In trait definitions, the predicate `Self: Trait` is problematic. // Therefore we skip such predicates. This means we check less than we could. for pred in predicates.predicates.iter().filter(|p| !(is_trait && p.has_self_ty())) { let mut skip = true; @@ -418,9 +418,20 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } } }); - if !skip { - substituted_predicates.push(pred.subst(fcx.tcx, substs)); - } + if skip { continue; } + substituted_predicates.push(match pred { + // In trait predicates, substitute defaults only for the LHS. + ty::Predicate::Trait(trait_pred) => { + let t_pred = trait_pred.skip_binder(); + let self_ty = t_pred.self_ty().subst(fcx.tcx, substs); + let mut trait_substs = t_pred.trait_ref.substs.to_vec(); + trait_substs[0] = self_ty.into(); + let trait_ref = ty::TraitRef::new(t_pred.def_id(), + fcx.tcx.intern_substs(&trait_substs)); + ty::Predicate::Trait(ty::Binder(trait_ref).to_poly_trait_predicate()) + } + _ => pred.subst(fcx.tcx, substs) + }); } } diff --git a/src/test/run-pass/defaults-well-formedness.rs b/src/test/run-pass/defaults-well-formedness.rs new file mode 100644 index 0000000000000..92c7f8731bab1 --- /dev/null +++ b/src/test/run-pass/defaults-well-formedness.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait {} +struct Foo(U, V) where U: Trait; + +fn main() {} diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index a6e475eb1a3b5..7c379a1f1bc99 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: --error-format=human use std::iter::FromIterator; use std::vec::IntoIter; @@ -15,24 +14,34 @@ use std::ops::Add; struct Foo>(T, U); struct WellFormed>(Z); +//~^ error: the trait bound `i32: std::iter::FromIterator` is not satisfied [E0277] struct WellFormedNoBounds>(Z); +//~^ error: the trait bound `i32: std::iter::FromIterator` is not satisfied [E0277] struct WellFormedProjection::Item>(A, T); +//~^ error: the trait bound `A: std::iter::Iterator` is not satisfied [E0277] struct Bounds(T); +//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] struct WhereClause(T) where T: Copy; +//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] trait TraitBound {} +//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] trait SelfBound {} +//~^ error: the trait bound `Self: std::marker::Copy` is not satisfied [E0277] trait FooTrait> where T::Item : Add {} +//~^ error: the trait bound `i32: std::ops::Add` is not satisfied [E0277] trait Trait {} struct TwoParams(T, U); impl Trait for TwoParams {} // Check that each default is substituted individually in the clauses. struct Bogus(TwoParams) where TwoParams: Trait; +//~^ error: the trait bound `TwoParams: Trait` is not satisfied [E0277] +//~^^ error: the trait bound `TwoParams: Trait` is not satisfied [E0277] fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index cf11282f7d20c..3ac6e4c26b4f0 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied - --> $DIR/type-check-defaults.rs:17:19 + --> $DIR/type-check-defaults.rs:16:19 | -17 | struct WellFormed>(Z); +16 | struct WellFormed>(Z); | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` @@ -17,69 +17,69 @@ error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfi = note: required by `Foo` error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied - --> $DIR/type-check-defaults.rs:20:1 + --> $DIR/type-check-defaults.rs:21:1 | -20 | struct WellFormedProjection::Item>(A, T); +21 | struct WellFormedProjection::Item>(A, T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `A` is not an iterator; maybe try calling `.iter()` or a similar method | = help: the trait `std::iter::Iterator` is not implemented for `A` = help: consider adding a `where A: std::iter::Iterator` bound error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:22:1 + --> $DIR/type-check-defaults.rs:24:1 | -22 | struct Bounds(T); +24 | struct Bounds(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:24:1 + --> $DIR/type-check-defaults.rs:27:1 | -24 | struct WhereClause(T) where T: Copy; +27 | struct WhereClause(T) where T: Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:26:1 + --> $DIR/type-check-defaults.rs:30:1 | -26 | trait TraitBound {} +30 | trait TraitBound {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:28:1 + --> $DIR/type-check-defaults.rs:33:1 | -28 | trait SelfBound {} +33 | trait SelfBound {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Self` | = help: consider adding a `where Self: std::marker::Copy` bound = note: required by `std::marker::Copy` error[E0277]: the trait bound `i32: std::ops::Add` is not satisfied - --> $DIR/type-check-defaults.rs:30:1 + --> $DIR/type-check-defaults.rs:36:1 | -30 | trait FooTrait> where T::Item : Add {} +36 | trait FooTrait> where T::Item : Add {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` | = help: the trait `std::ops::Add` is not implemented for `i32` = note: required by `std::ops::Add` error[E0277]: the trait bound `TwoParams: Trait` is not satisfied - --> $DIR/type-check-defaults.rs:36:1 + --> $DIR/type-check-defaults.rs:43:1 | -36 | struct Bogus(TwoParams) where TwoParams: Trait; +43 | struct Bogus(TwoParams) where TwoParams: Trait; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams` | = help: consider adding a `where TwoParams: Trait` bound = note: required by `Trait` error[E0277]: the trait bound `TwoParams: Trait` is not satisfied - --> $DIR/type-check-defaults.rs:36:1 + --> $DIR/type-check-defaults.rs:43:1 | -36 | struct Bogus(TwoParams) where TwoParams: Trait; +43 | struct Bogus(TwoParams) where TwoParams: Trait; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams` | = help: consider adding a `where TwoParams: Trait` bound From 7c1b6848db84636845ddce2413a57fa2f8d3ff63 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 16 Jan 2018 19:20:26 -0200 Subject: [PATCH 06/15] use `map_bound` instead of `skip_binder` --- src/librustc_typeck/check/wfcheck.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index a16b806b6f125..7648feea457d0 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -277,7 +277,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fn check_trait(&mut self, item: &hir::Item) { let trait_def_id = self.tcx.hir.local_def_id(item.id); - self.for_item(item).with_fcx(|fcx, _| { self.check_trait_where_clauses(fcx, item.span, trait_def_id); vec![] @@ -421,14 +420,13 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { if skip { continue; } substituted_predicates.push(match pred { // In trait predicates, substitute defaults only for the LHS. - ty::Predicate::Trait(trait_pred) => { - let t_pred = trait_pred.skip_binder(); - let self_ty = t_pred.self_ty().subst(fcx.tcx, substs); - let mut trait_substs = t_pred.trait_ref.substs.to_vec(); - trait_substs[0] = self_ty.into(); - let trait_ref = ty::TraitRef::new(t_pred.def_id(), - fcx.tcx.intern_substs(&trait_substs)); - ty::Predicate::Trait(ty::Binder(trait_ref).to_poly_trait_predicate()) + ty::Predicate::Trait(t_pred) => { + let trait_ref = t_pred.map_bound(|t_pred| { + let mut trait_subs = t_pred.trait_ref.substs.to_vec(); + trait_subs[0] = t_pred.self_ty().subst(fcx.tcx, substs).into(); + ty::TraitRef::new(t_pred.def_id(), fcx.tcx.intern_substs(&trait_subs)) + }); + ty::Predicate::Trait(trait_ref.to_poly_trait_predicate()) } _ => pred.subst(fcx.tcx, substs) }); From 35499aa9fcef2cab965f0c1e04da1b97ec715d64 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sat, 20 Jan 2018 13:33:44 -0200 Subject: [PATCH 07/15] Expand comments, address nits. --- src/librustc_typeck/check/wfcheck.rs | 19 +++++++++---- src/test/ui/type-check-defaults.rs | 4 +++ src/test/ui/type-check-defaults.stderr | 39 ++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 7648feea457d0..91c5b8703c28d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -381,12 +381,20 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let defaulted_params = generics.types.iter() .filter(|def| def.has_default && def.index >= generics.parent_count() as u32); + // WF checks for type parameter defaults. See test `type-check-defaults.rs` for examples. for param_def in defaulted_params { - // Defaults must be well-formed. + // This parameter has a default value. Check that this default value is well-formed. + // For example this forbids the declaration: + // struct Foo> { .. } + // Here `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. let d = param_def.def_id; fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone()); + // Check the clauses are well-formed when the param is substituted by it's default. - // In trait definitions, the predicate `Self: Trait` is problematic. + // For example this forbids the following declaration because `String` is not `Copy`: + // struct Foo { .. } + // + // In `trait Trait: Super`, checking `Self: Trait` or `Self: Super` is problematic. // Therefore we skip such predicates. This means we check less than we could. for pred in predicates.predicates.iter().filter(|p| !(is_trait && p.has_self_ty())) { let mut skip = true; @@ -394,9 +402,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // All regions are identity. fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) }, |def, _| { - let identity_substs = fcx.tcx.mk_param_from_def(def); + let identity_ty = fcx.tcx.mk_param_from_def(def); if def.index != param_def.index { - identity_substs + identity_ty } else { let sized = fcx.tcx.lang_items().sized_trait(); let pred_is_sized = match pred { @@ -410,7 +418,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { }; // In trait defs, skip `Self: Sized` when `Self` is the default. if is_trait && pred_is_sized && default_is_self { - identity_substs + identity_ty } else { skip = false; default_ty @@ -420,6 +428,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { if skip { continue; } substituted_predicates.push(match pred { // In trait predicates, substitute defaults only for the LHS. + // See test `defaults-well-formedness.rs` for why substituting the RHS is bad. ty::Predicate::Trait(t_pred) => { let trait_ref = t_pred.map_bound(|t_pred| { let mut trait_subs = t_pred.trait_ref.substs.to_vec(); diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index 7c379a1f1bc99..8f0714ebc3b13 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -44,4 +44,8 @@ struct Bogus(TwoParams) where TwoParams: Trait; //~^ error: the trait bound `TwoParams: Trait` is not satisfied [E0277] //~^^ error: the trait bound `TwoParams: Trait` is not satisfied [E0277] +trait Super { } +trait Base: Super { } +//~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277] + fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index 3ac6e4c26b4f0..8be46a53370e8 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -5,7 +5,11 @@ error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfi | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` - = note: required by `Foo` +note: required by `Foo` + --> $DIR/type-check-defaults.rs:15:1 + | +15 | struct Foo>(T, U); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied --> $DIR/type-check-defaults.rs:18:27 @@ -14,7 +18,11 @@ error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfi | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` - = note: required by `Foo` +note: required by `Foo` + --> $DIR/type-check-defaults.rs:15:1 + | +15 | struct Foo>(T, U); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied --> $DIR/type-check-defaults.rs:21:1 @@ -74,7 +82,11 @@ error[E0277]: the trait bound `TwoParams: Trait` is not satisfied | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams` | = help: consider adding a `where TwoParams: Trait` bound - = note: required by `Trait` +note: required by `Trait` + --> $DIR/type-check-defaults.rs:39:1 + | +39 | trait Trait {} + | ^^^^^^^^^^^ error[E0277]: the trait bound `TwoParams: Trait` is not satisfied --> $DIR/type-check-defaults.rs:43:1 @@ -83,7 +95,24 @@ error[E0277]: the trait bound `TwoParams: Trait` is not satisfied | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams` | = help: consider adding a `where TwoParams: Trait` bound - = note: required by `Trait` +note: required by `Trait` + --> $DIR/type-check-defaults.rs:39:1 + | +39 | trait Trait {} + | ^^^^^^^^^^^ + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/type-check-defaults.rs:48:1 + | +48 | trait Base: Super { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | + = help: consider adding a `where T: std::marker::Copy` bound +note: required by `Super` + --> $DIR/type-check-defaults.rs:47:1 + | +47 | trait Super { } + | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors From addc404d32b8b153f65b180c4bcdc5ccaaba2a77 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sun, 21 Jan 2018 12:09:06 -0200 Subject: [PATCH 08/15] Check WF of predicate with defaults only if all in LHS have default Given a trait predicate, if all params appearing in the LHS have defaults then it should be a backwards compatible predicate. We verify that by checking the WF of predicate with all defaults substituted simultaneously. --- src/librustc/ty/mod.rs | 7 + src/librustc_typeck/check/wfcheck.rs | 120 +++++++++--------- src/test/run-pass/defaults-well-formedness.rs | 7 + src/test/ui/type-check-defaults.rs | 18 +-- src/test/ui/type-check-defaults.stderr | 57 +++------ 5 files changed, 99 insertions(+), 110 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3ab2cd274b90e..2c538d2bba56d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1040,6 +1040,13 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)), } } + + pub fn as_poly_trait_predicate(&self) -> Option<&PolyTraitPredicate<'tcx>> { + match self { + Predicate::Trait(trait_pred) => Some(trait_pred), + _ => None + } + } } #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 91c5b8703c28d..463cc2aa6b3eb 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -378,67 +378,69 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let mut substituted_predicates = Vec::new(); let generics = self.tcx.generics_of(def_id); - let defaulted_params = generics.types.iter() - .filter(|def| def.has_default && - def.index >= generics.parent_count() as u32); - // WF checks for type parameter defaults. See test `type-check-defaults.rs` for examples. - for param_def in defaulted_params { - // This parameter has a default value. Check that this default value is well-formed. - // For example this forbids the declaration: - // struct Foo> { .. } - // Here `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. - let d = param_def.def_id; + let is_our_default = |def: &ty::TypeParameterDef| + def.has_default && def.index >= generics.parent_count() as u32; + let defaulted_params = generics.types.iter().cloned().filter(&is_our_default); + // Check that defaults are well-formed. See test `type-check-defaults.rs`. + // For example this forbids the declaration: + // struct Foo> { .. } + // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. + for d in defaulted_params.map(|p| p.def_id) { fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone()); + } - // Check the clauses are well-formed when the param is substituted by it's default. - // For example this forbids the following declaration because `String` is not `Copy`: - // struct Foo { .. } - // - // In `trait Trait: Super`, checking `Self: Trait` or `Self: Super` is problematic. - // Therefore we skip such predicates. This means we check less than we could. - for pred in predicates.predicates.iter().filter(|p| !(is_trait && p.has_self_ty())) { - let mut skip = true; - let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { - // All regions are identity. - fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) - }, |def, _| { - let identity_ty = fcx.tcx.mk_param_from_def(def); - if def.index != param_def.index { - identity_ty - } else { - let sized = fcx.tcx.lang_items().sized_trait(); - let pred_is_sized = match pred { - ty::Predicate::Trait(p) => Some(p.def_id()) == sized, - _ => false, - }; - let default_ty = fcx.tcx.type_of(def.def_id); - let default_is_self = match default_ty.sty { - ty::TyParam(ref p) => p.is_self(), - _ => false - }; - // In trait defs, skip `Self: Sized` when `Self` is the default. - if is_trait && pred_is_sized && default_is_self { - identity_ty - } else { - skip = false; - default_ty - } - } - }); - if skip { continue; } - substituted_predicates.push(match pred { - // In trait predicates, substitute defaults only for the LHS. - // See test `defaults-well-formedness.rs` for why substituting the RHS is bad. - ty::Predicate::Trait(t_pred) => { - let trait_ref = t_pred.map_bound(|t_pred| { - let mut trait_subs = t_pred.trait_ref.substs.to_vec(); - trait_subs[0] = t_pred.self_ty().subst(fcx.tcx, substs).into(); - ty::TraitRef::new(t_pred.def_id(), fcx.tcx.intern_substs(&trait_subs)) - }); - ty::Predicate::Trait(trait_ref.to_poly_trait_predicate()) - } - _ => pred.subst(fcx.tcx, substs) - }); + // Check that trait predicates are WF when params are substituted by their defaults. + // We don't want to overly constrain the predicates that may be written but we + // want to catch obviously wrong cases such as `struct Foo` + // or cases that may cause backwards incompatibility such as a library going from + // `pub struct Foo` to `pub struct Foo` where U: Trait` + // which may break existing uses of Foo. + // Therefore the check we do is: If if all params appearing in the LHS of the predicate + // have defaults then we verify that it is WF with all defaults substituted simultaneously. + // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`. + // + // First, we build the defaulted substitution. + let mut defaulted_params = Vec::new(); + let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { + // All regions are identity. + fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) + }, |def, _| { + if !is_our_default(def) { + // Identity substitution. + fcx.tcx.mk_param_from_def(def) + } else { + // Substitute with default. + defaulted_params.push(def.index); + fcx.tcx.type_of(def.def_id) + } + }); + // In `trait Trait: Super`, checking `Self: Trait` or `Self: Super` is problematic. + // We avoid those by skipping any predicates in trait declarations that contain `Self`, + // which is excessive so we end up checking less than we could. + for pred in predicates.predicates.iter() + .filter_map(ty::Predicate::as_poly_trait_predicate) + .filter(|p| !(is_trait && p.has_self_ty())) { + let is_defaulted_param = |ty: ty::Ty| match ty.sty { + ty::TyParam(p) => defaulted_params.contains(&p.idx), + _ => false + }; + // If there is a non-defaulted param in the LHS, don't check the substituted predicate. + // `skip_binder()` is ok, we're only inspecting the type params. + if !pred.skip_binder().self_ty().walk().all(is_defaulted_param) { + continue; + } + let substituted_pred = pred.subst(fcx.tcx, substs); + // `skip_binder()` is ok, we're only inspecting for `has_self_ty()`. + let substituted_lhs = substituted_pred.skip_binder().self_ty(); + // In trait defs, don't check `Self: Sized` when `Self` is the default. + let pred_is_sized = Some(pred.def_id()) == fcx.tcx.lang_items().sized_trait(); + if is_trait && substituted_lhs.has_self_ty() && pred_is_sized { + continue; + } + let pred = ty::Predicate::Trait(pred.subst(fcx.tcx, substs)); + // Avoid duplicates. + if !predicates.predicates.contains(&pred) { + substituted_predicates.push(pred); } } diff --git a/src/test/run-pass/defaults-well-formedness.rs b/src/test/run-pass/defaults-well-formedness.rs index 92c7f8731bab1..abbd35b3909a6 100644 --- a/src/test/run-pass/defaults-well-formedness.rs +++ b/src/test/run-pass/defaults-well-formedness.rs @@ -11,4 +11,11 @@ trait Trait {} struct Foo(U, V) where U: Trait; +trait Trait2 {} +struct TwoParams(T, U); +impl Trait2 for TwoParams {} +// Check that defaults are substituted simultaneously. +struct IndividuallyBogus(TwoParams) where TwoParams: Trait2; +// Clauses with non-defaulted params are not checked. +struct NonDefaultedInClause(TwoParams) where TwoParams: Trait2; fn main() {} diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index 8f0714ebc3b13..cc20f81ae1647 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -33,19 +33,15 @@ trait TraitBound {} trait SelfBound {} //~^ error: the trait bound `Self: std::marker::Copy` is not satisfied [E0277] -trait FooTrait> where T::Item : Add {} -//~^ error: the trait bound `i32: std::ops::Add` is not satisfied [E0277] - -trait Trait {} -struct TwoParams(T, U); -impl Trait for TwoParams {} -// Check that each default is substituted individually in the clauses. -struct Bogus(TwoParams) where TwoParams: Trait; -//~^ error: the trait bound `TwoParams: Trait` is not satisfied [E0277] -//~^^ error: the trait bound `TwoParams: Trait` is not satisfied [E0277] - trait Super { } trait Base: Super { } //~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277] +trait Trait {} +struct DefaultedLhs(U, V) where V: Trait; +//~^ error: the trait bound `i32: Trait` is not satisfied [E0277] + +// FIXME: Deal with projection predicates +// trait ProjectionPred> where T::Item : Add {} +// ~^ error: the trait bound `i32: std::ops::Add` is not satisfied [E0277] fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index 8be46a53370e8..ede1b417c7c92 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -66,53 +66,30 @@ error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied = help: consider adding a `where Self: std::marker::Copy` bound = note: required by `std::marker::Copy` -error[E0277]: the trait bound `i32: std::ops::Add` is not satisfied - --> $DIR/type-check-defaults.rs:36:1 - | -36 | trait FooTrait> where T::Item : Add {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` - | - = help: the trait `std::ops::Add` is not implemented for `i32` - = note: required by `std::ops::Add` - -error[E0277]: the trait bound `TwoParams: Trait` is not satisfied - --> $DIR/type-check-defaults.rs:43:1 - | -43 | struct Bogus(TwoParams) where TwoParams: Trait; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams` - | - = help: consider adding a `where TwoParams: Trait` bound -note: required by `Trait` - --> $DIR/type-check-defaults.rs:39:1 - | -39 | trait Trait {} - | ^^^^^^^^^^^ - -error[E0277]: the trait bound `TwoParams: Trait` is not satisfied - --> $DIR/type-check-defaults.rs:43:1 - | -43 | struct Bogus(TwoParams) where TwoParams: Trait; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams` - | - = help: consider adding a `where TwoParams: Trait` bound -note: required by `Trait` - --> $DIR/type-check-defaults.rs:39:1 - | -39 | trait Trait {} - | ^^^^^^^^^^^ - error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:48:1 + --> $DIR/type-check-defaults.rs:37:1 | -48 | trait Base: Super { } +37 | trait Base: Super { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound note: required by `Super` - --> $DIR/type-check-defaults.rs:47:1 + --> $DIR/type-check-defaults.rs:36:1 | -47 | trait Super { } +36 | trait Super { } | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error[E0277]: the trait bound `i32: Trait` is not satisfied + --> $DIR/type-check-defaults.rs:41:1 + | +41 | struct DefaultedLhs(U, V) where V: Trait; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `i32` + | +note: required by `Trait` + --> $DIR/type-check-defaults.rs:40:1 + | +40 | trait Trait {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors From 75997d85c50b3c489f6a0bf0e388c86ad7a839e4 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 22 Jan 2018 13:36:51 -0200 Subject: [PATCH 09/15] Check WF of predicates with defaults only if all params have defaults --- src/librustc/ty/mod.rs | 7 --- src/librustc_typeck/check/wfcheck.rs | 57 ++++++++++--------- src/test/run-pass/defaults-well-formedness.rs | 10 ++-- src/test/ui/type-check-defaults.rs | 15 +++-- src/test/ui/type-check-defaults.stderr | 29 +++++++--- 5 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2c538d2bba56d..3ab2cd274b90e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1040,13 +1040,6 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)), } } - - pub fn as_poly_trait_predicate(&self) -> Option<&PolyTraitPredicate<'tcx>> { - match self { - Predicate::Trait(trait_pred) => Some(trait_pred), - _ => None - } - } } #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 463cc2aa6b3eb..16115fa9be46a 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -392,14 +392,13 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // Check that trait predicates are WF when params are substituted by their defaults. // We don't want to overly constrain the predicates that may be written but we // want to catch obviously wrong cases such as `struct Foo` - // or cases that may cause backwards incompatibility such as a library going from - // `pub struct Foo` to `pub struct Foo` where U: Trait` - // which may break existing uses of Foo. - // Therefore the check we do is: If if all params appearing in the LHS of the predicate - // have defaults then we verify that it is WF with all defaults substituted simultaneously. + // or cases where defaults don't work together such as: + // `struct Foo where T: into` + // Therefore we check if a predicate in which all type params are defaulted + // is WF with those defaults simultaneously substituted. // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`. // - // First, we build the defaulted substitution. + // First we build the defaulted substitution. let mut defaulted_params = Vec::new(); let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { // All regions are identity. @@ -414,33 +413,35 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fcx.tcx.type_of(def.def_id) } }); - // In `trait Trait: Super`, checking `Self: Trait` or `Self: Super` is problematic. - // We avoid those by skipping any predicates in trait declarations that contain `Self`, - // which is excessive so we end up checking less than we could. - for pred in predicates.predicates.iter() - .filter_map(ty::Predicate::as_poly_trait_predicate) - .filter(|p| !(is_trait && p.has_self_ty())) { - let is_defaulted_param = |ty: ty::Ty| match ty.sty { - ty::TyParam(p) => defaulted_params.contains(&p.idx), - _ => false - }; - // If there is a non-defaulted param in the LHS, don't check the substituted predicate. - // `skip_binder()` is ok, we're only inspecting the type params. - if !pred.skip_binder().self_ty().walk().all(is_defaulted_param) { + let defaulted_params = &defaulted_params; + // Now we build the substituted predicates. + for &pred in predicates.predicates.iter() { + struct HasNonDefaulted<'a> { defaulted_params: &'a Vec } + impl<'tcx, 'a> ty::fold::TypeVisitor<'tcx> for HasNonDefaulted<'a> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.sty { + ty::TyParam(p) => !self.defaulted_params.contains(&p.idx), + _ => t.super_visit_with(self) + } + } + } + // If there is a non-defaulted param in the predicate, don't check it. + if pred.visit_with(&mut HasNonDefaulted { defaulted_params }) { continue; } let substituted_pred = pred.subst(fcx.tcx, substs); - // `skip_binder()` is ok, we're only inspecting for `has_self_ty()`. - let substituted_lhs = substituted_pred.skip_binder().self_ty(); // In trait defs, don't check `Self: Sized` when `Self` is the default. - let pred_is_sized = Some(pred.def_id()) == fcx.tcx.lang_items().sized_trait(); - if is_trait && substituted_lhs.has_self_ty() && pred_is_sized { - continue; + if let ty::Predicate::Trait(trait_pred) = substituted_pred { + // `skip_binder()` is ok, we're only inspecting for `has_self_ty()`. + let lhs_is_self = trait_pred.skip_binder().self_ty().has_self_ty(); + let pred_sized = Some(trait_pred.def_id()) == fcx.tcx.lang_items().sized_trait(); + if is_trait && lhs_is_self && pred_sized { + continue; + } } - let pred = ty::Predicate::Trait(pred.subst(fcx.tcx, substs)); - // Avoid duplicates. - if !predicates.predicates.contains(&pred) { - substituted_predicates.push(pred); + // Avoid duplication of predicates that contain no parameters, for example. + if !predicates.predicates.contains(&substituted_pred) { + substituted_predicates.push(substituted_pred); } } diff --git a/src/test/run-pass/defaults-well-formedness.rs b/src/test/run-pass/defaults-well-formedness.rs index abbd35b3909a6..6a7b1c51ccd28 100644 --- a/src/test/run-pass/defaults-well-formedness.rs +++ b/src/test/run-pass/defaults-well-formedness.rs @@ -11,11 +11,13 @@ trait Trait {} struct Foo(U, V) where U: Trait; -trait Trait2 {} +trait Marker {} struct TwoParams(T, U); -impl Trait2 for TwoParams {} +impl Marker for TwoParams {} // Check that defaults are substituted simultaneously. -struct IndividuallyBogus(TwoParams) where TwoParams: Trait2; +struct IndividuallyBogus(TwoParams) where TwoParams: Marker; // Clauses with non-defaulted params are not checked. -struct NonDefaultedInClause(TwoParams) where TwoParams: Trait2; +struct NonDefaultedInClause(TwoParams) where TwoParams: Marker; +struct DefaultedLhs(U, V) where V: Trait; + fn main() {} diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index cc20f81ae1647..ff3fb44bb264e 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -37,11 +37,14 @@ trait Super { } trait Base: Super { } //~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277] -trait Trait {} -struct DefaultedLhs(U, V) where V: Trait; -//~^ error: the trait bound `i32: Trait` is not satisfied [E0277] +trait ProjectionPred> where T::Item : Add {} +//~^ error: the trait bound `i32: std::ops::Add` is not satisfied [E0277] + +// Defaults must work together. +struct TwoParams(T, U) where T: Bar; +//~^ the trait bound `u32: Bar` is not satisfied [E0277] +trait Bar {} +impl Bar for u32 { } +impl Bar for String { } -// FIXME: Deal with projection predicates -// trait ProjectionPred> where T::Item : Add {} -// ~^ error: the trait bound `i32: std::ops::Add` is not satisfied [E0277] fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index ede1b417c7c92..412a7966f0aac 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -79,17 +79,28 @@ note: required by `Super` 36 | trait Super { } | ^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `i32: Trait` is not satisfied - --> $DIR/type-check-defaults.rs:41:1 +error[E0277]: the trait bound `i32: std::ops::Add` is not satisfied + --> $DIR/type-check-defaults.rs:40:1 | -41 | struct DefaultedLhs(U, V) where V: Trait; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `i32` +40 | trait ProjectionPred> where T::Item : Add {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` | -note: required by `Trait` - --> $DIR/type-check-defaults.rs:40:1 + = help: the trait `std::ops::Add` is not implemented for `i32` + = note: required by `std::ops::Add` + +error[E0277]: the trait bound `u32: Bar` is not satisfied + --> $DIR/type-check-defaults.rs:44:1 + | +44 | struct TwoParams(T, U) where T: Bar; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `u32` + | + = help: the following implementations were found: + > +note: required by `Bar` + --> $DIR/type-check-defaults.rs:46:1 | -40 | trait Trait {} - | ^^^^^^^^^^^^^^ +46 | trait Bar {} + | ^^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors From 81ab26c99a4775c613ff30e18fe0ee01661a635e Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 5 Feb 2018 21:51:58 -0200 Subject: [PATCH 10/15] Add tests for dependent defaults. --- src/test/run-pass/defaults-well-formedness.rs | 2 ++ src/test/ui/type-check-defaults.rs | 4 ++++ src/test/ui/type-check-defaults.stderr | 11 ++++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/test/run-pass/defaults-well-formedness.rs b/src/test/run-pass/defaults-well-formedness.rs index 6a7b1c51ccd28..60e78e29afd8b 100644 --- a/src/test/run-pass/defaults-well-formedness.rs +++ b/src/test/run-pass/defaults-well-formedness.rs @@ -19,5 +19,7 @@ struct IndividuallyBogus(TwoParams) where TwoParams(TwoParams) where TwoParams: Marker; struct DefaultedLhs(U, V) where V: Trait; +// Dependent defaults. +struct Dependent(T, U) where U: Copy; fn main() {} diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index ff3fb44bb264e..d57b39464806a 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -47,4 +47,8 @@ trait Bar {} impl Bar for u32 { } impl Bar for String { } +// Dependent defaults. +struct Dependent(T, U) where U: Copy; +//~^ the trait bound `T: std::marker::Copy` is not satisfied [E0277] + fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index 412a7966f0aac..032e80cdb1485 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -102,5 +102,14 @@ note: required by `Bar` 46 | trait Bar {} | ^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/type-check-defaults.rs:51:1 + | +51 | struct Dependent(T, U) where U: Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | + = help: consider adding a `where T: std::marker::Copy` bound + = note: required by `std::marker::Copy` + +error: aborting due to 11 previous errors From ac17948d0fdbe8ac4c5d1bb4f8be83a307545f46 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 6 Feb 2018 12:32:22 -0200 Subject: [PATCH 11/15] Mark non-defaulted params as TyError to avoid a custom visitor. --- src/librustc_typeck/check/wfcheck.rs | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 16115fa9be46a..21660d817b213 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -399,37 +399,25 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`. // // First we build the defaulted substitution. - let mut defaulted_params = Vec::new(); let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { // All regions are identity. fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) }, |def, _| { if !is_our_default(def) { - // Identity substitution. - fcx.tcx.mk_param_from_def(def) + // We don't want to use non-defaulted params in a substitution, mark as err. + fcx.tcx.types.err } else { // Substitute with default. - defaulted_params.push(def.index); fcx.tcx.type_of(def.def_id) } }); - let defaulted_params = &defaulted_params; // Now we build the substituted predicates. for &pred in predicates.predicates.iter() { - struct HasNonDefaulted<'a> { defaulted_params: &'a Vec } - impl<'tcx, 'a> ty::fold::TypeVisitor<'tcx> for HasNonDefaulted<'a> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.sty { - ty::TyParam(p) => !self.defaulted_params.contains(&p.idx), - _ => t.super_visit_with(self) - } - } - } + let substituted_pred = pred.subst(fcx.tcx, substs); // If there is a non-defaulted param in the predicate, don't check it. - if pred.visit_with(&mut HasNonDefaulted { defaulted_params }) { + if substituted_pred.references_error() { continue; } - let substituted_pred = pred.subst(fcx.tcx, substs); // In trait defs, don't check `Self: Sized` when `Self` is the default. if let ty::Predicate::Trait(trait_pred) = substituted_pred { // `skip_binder()` is ok, we're only inspecting for `has_self_ty()`. From c74f85f935189021345cbc0efdfcccb98047c29e Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Fri, 9 Feb 2018 08:42:11 -0200 Subject: [PATCH 12/15] Check only predicates with a single param with a concrete default. This is the most conservative possible and should be always correct. --- src/librustc_typeck/check/wfcheck.rs | 72 ++++++++----------- src/test/run-pass/defaults-well-formedness.rs | 9 ++- src/test/ui/type-check-defaults.rs | 16 +---- src/test/ui/type-check-defaults.stderr | 53 +++----------- 4 files changed, 49 insertions(+), 101 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 21660d817b213..258860d3d5e40 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -278,7 +278,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fn check_trait(&mut self, item: &hir::Item) { let trait_def_id = self.tcx.hir.local_def_id(item.id); self.for_item(item).with_fcx(|fcx, _| { - self.check_trait_where_clauses(fcx, item.span, trait_def_id); + self.check_where_clauses(fcx, item.span, trait_def_id); vec![] }); } @@ -354,23 +354,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, def_id: DefId) { - self.inner_check_where_clauses(fcx, span, def_id, false) - } - - fn check_trait_where_clauses<'fcx, 'tcx>(&mut self, - fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, - span: Span, - def_id: DefId) { - self.inner_check_where_clauses(fcx, span, def_id, true) - } - - /// Checks where clauses and inline bounds that are declared on def_id. - fn inner_check_where_clauses<'fcx, 'tcx>(&mut self, - fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, - span: Span, - def_id: DefId, - is_trait: bool) - { use ty::subst::Subst; use rustc::ty::TypeFoldable; @@ -390,12 +373,10 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } // Check that trait predicates are WF when params are substituted by their defaults. - // We don't want to overly constrain the predicates that may be written but we - // want to catch obviously wrong cases such as `struct Foo` - // or cases where defaults don't work together such as: - // `struct Foo where T: into` - // Therefore we check if a predicate in which all type params are defaulted - // is WF with those defaults simultaneously substituted. + // We don't want to overly constrain the predicates that may be written but we want to + // catch cases where a default my never be applied such as `struct Foo`. + // Therefore we check if a predicate which contains a single type param + // with a concrete default is WF with that default substituted. // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`. // // First we build the defaulted substitution. @@ -403,30 +384,39 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // All regions are identity. fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) }, |def, _| { - if !is_our_default(def) { - // We don't want to use non-defaulted params in a substitution, mark as err. - fcx.tcx.types.err - } else { - // Substitute with default. - fcx.tcx.type_of(def.def_id) + // If the param has a default, + if is_our_default(def) { + let default_ty = fcx.tcx.type_of(def.def_id); + // and it's not a dependent default + if !default_ty.needs_subst() { + // then substitute with the default. + return default_ty; + } } + // Mark unwanted params as err. + fcx.tcx.types.err }); // Now we build the substituted predicates. for &pred in predicates.predicates.iter() { + struct CountParams { params: FxHashSet } + impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.sty { + ty::TyParam(p) => { + self.params.insert(p.idx); + t.super_visit_with(self) + } + _ => t.super_visit_with(self) + } + } + } + let mut param_count = CountParams { params: FxHashSet() }; + pred.visit_with(&mut param_count); let substituted_pred = pred.subst(fcx.tcx, substs); - // If there is a non-defaulted param in the predicate, don't check it. - if substituted_pred.references_error() { + // Don't check non-defaulted params, dependent defaults or preds with multiple params. + if substituted_pred.references_error() || param_count.params.len() > 1 { continue; } - // In trait defs, don't check `Self: Sized` when `Self` is the default. - if let ty::Predicate::Trait(trait_pred) = substituted_pred { - // `skip_binder()` is ok, we're only inspecting for `has_self_ty()`. - let lhs_is_self = trait_pred.skip_binder().self_ty().has_self_ty(); - let pred_sized = Some(trait_pred.def_id()) == fcx.tcx.lang_items().sized_trait(); - if is_trait && lhs_is_self && pred_sized { - continue; - } - } // Avoid duplication of predicates that contain no parameters, for example. if !predicates.predicates.contains(&substituted_pred) { substituted_predicates.push(substituted_pred); diff --git a/src/test/run-pass/defaults-well-formedness.rs b/src/test/run-pass/defaults-well-formedness.rs index 60e78e29afd8b..552665bac4e6c 100644 --- a/src/test/run-pass/defaults-well-formedness.rs +++ b/src/test/run-pass/defaults-well-formedness.rs @@ -14,12 +14,15 @@ struct Foo(U, V) where U: Trait; trait Marker {} struct TwoParams(T, U); impl Marker for TwoParams {} -// Check that defaults are substituted simultaneously. + +// Clauses with more than 1 param are not checked. struct IndividuallyBogus(TwoParams) where TwoParams: Marker; +struct BogusTogether(T, U) where TwoParams: Marker; // Clauses with non-defaulted params are not checked. struct NonDefaultedInClause(TwoParams) where TwoParams: Marker; struct DefaultedLhs(U, V) where V: Trait; -// Dependent defaults. -struct Dependent(T, U) where U: Copy; +// Dependent defaults are not checked. +struct Dependent(T, U) where U: Copy; +trait SelfBound {} fn main() {} diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index d57b39464806a..65560df9f21f2 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -30,25 +30,11 @@ struct WhereClause(T) where T: Copy; trait TraitBound {} //~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] -trait SelfBound {} -//~^ error: the trait bound `Self: std::marker::Copy` is not satisfied [E0277] - trait Super { } trait Base: Super { } //~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277] trait ProjectionPred> where T::Item : Add {} -//~^ error: the trait bound `i32: std::ops::Add` is not satisfied [E0277] - -// Defaults must work together. -struct TwoParams(T, U) where T: Bar; -//~^ the trait bound `u32: Bar` is not satisfied [E0277] -trait Bar {} -impl Bar for u32 { } -impl Bar for String { } - -// Dependent defaults. -struct Dependent(T, U) where U: Copy; -//~^ the trait bound `T: std::marker::Copy` is not satisfied [E0277] +//~^ error: cannot add `u8` to `i32` [E0277] fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index 032e80cdb1485..c73c0792f8e7c 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -25,13 +25,14 @@ note: required by `Foo` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied - --> $DIR/type-check-defaults.rs:21:1 + --> $DIR/type-check-defaults.rs:21:32 | 21 | struct WellFormedProjection::Item>(A, T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `A` is not an iterator; maybe try calling `.iter()` or a similar method + | ^ `A` is not an iterator; maybe try calling `.iter()` or a similar method | = help: the trait `std::iter::Iterator` is not implemented for `A` = help: consider adding a `where A: std::iter::Iterator` bound + = note: required by `std::iter::Iterator` error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:24:1 @@ -57,59 +58,27 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not sa | = note: required by `std::marker::Copy` -error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:33:1 - | -33 | trait SelfBound {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Self` - | - = help: consider adding a `where Self: std::marker::Copy` bound - = note: required by `std::marker::Copy` - error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:37:1 + --> $DIR/type-check-defaults.rs:34:1 | -37 | trait Base: Super { } +34 | trait Base: Super { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound note: required by `Super` - --> $DIR/type-check-defaults.rs:36:1 + --> $DIR/type-check-defaults.rs:33:1 | -36 | trait Super { } +33 | trait Super { } | ^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `i32: std::ops::Add` is not satisfied - --> $DIR/type-check-defaults.rs:40:1 +error[E0277]: cannot add `u8` to `i32` + --> $DIR/type-check-defaults.rs:37:1 | -40 | trait ProjectionPred> where T::Item : Add {} +37 | trait ProjectionPred> where T::Item : Add {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` | = help: the trait `std::ops::Add` is not implemented for `i32` = note: required by `std::ops::Add` -error[E0277]: the trait bound `u32: Bar` is not satisfied - --> $DIR/type-check-defaults.rs:44:1 - | -44 | struct TwoParams(T, U) where T: Bar; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `u32` - | - = help: the following implementations were found: - > -note: required by `Bar` - --> $DIR/type-check-defaults.rs:46:1 - | -46 | trait Bar {} - | ^^^^^^^^^^^^ - -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:51:1 - | -51 | struct Dependent(T, U) where U: Copy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound - = note: required by `std::marker::Copy` - -error: aborting due to 11 previous errors +error: aborting due to 8 previous errors From a7c7c8a4d7439e69f22386af1bb44f7686252f12 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 14 Feb 2018 20:55:37 -0200 Subject: [PATCH 13/15] Check only concrete defaults for well formedness --- src/librustc_typeck/check/wfcheck.rs | 11 +++--- src/test/run-pass/defaults-well-formedness.rs | 2 ++ src/test/ui/type-check-defaults.rs | 3 -- src/test/ui/type-check-defaults.stderr | 36 +++++++------------ 4 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 258860d3d5e40..4eb3e29ec6946 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -363,13 +363,16 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let generics = self.tcx.generics_of(def_id); let is_our_default = |def: &ty::TypeParameterDef| def.has_default && def.index >= generics.parent_count() as u32; - let defaulted_params = generics.types.iter().cloned().filter(&is_our_default); - // Check that defaults are well-formed. See test `type-check-defaults.rs`. + + // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`. // For example this forbids the declaration: // struct Foo> { .. } // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. - for d in defaulted_params.map(|p| p.def_id) { - fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone()); + for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) { + let ty = fcx.tcx.type_of(d); + if !ty.needs_subst() { + fcx.register_wf_obligation(ty, fcx.tcx.def_span(d), self.code.clone()); + } } // Check that trait predicates are WF when params are substituted by their defaults. diff --git a/src/test/run-pass/defaults-well-formedness.rs b/src/test/run-pass/defaults-well-formedness.rs index 552665bac4e6c..f359467909553 100644 --- a/src/test/run-pass/defaults-well-formedness.rs +++ b/src/test/run-pass/defaults-well-formedness.rs @@ -24,5 +24,7 @@ struct DefaultedLhs(U, V) where V: Trait; // Dependent defaults are not checked. struct Dependent(T, U) where U: Copy; trait SelfBound {} +// Not even for well-formedness. +struct WellFormedProjection::Item>(A, T); fn main() {} diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index 65560df9f21f2..f916df5d32d04 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -18,9 +18,6 @@ struct WellFormed>(Z); struct WellFormedNoBounds>(Z); //~^ error: the trait bound `i32: std::iter::FromIterator` is not satisfied [E0277] -struct WellFormedProjection::Item>(A, T); -//~^ error: the trait bound `A: std::iter::Iterator` is not satisfied [E0277] - struct Bounds(T); //~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index c73c0792f8e7c..4af8f5da0dd05 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -24,61 +24,51 @@ note: required by `Foo` 15 | struct Foo>(T, U); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied - --> $DIR/type-check-defaults.rs:21:32 - | -21 | struct WellFormedProjection::Item>(A, T); - | ^ `A` is not an iterator; maybe try calling `.iter()` or a similar method - | - = help: the trait `std::iter::Iterator` is not implemented for `A` - = help: consider adding a `where A: std::iter::Iterator` bound - = note: required by `std::iter::Iterator` - error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:24:1 + --> $DIR/type-check-defaults.rs:21:1 | -24 | struct Bounds(T); +21 | struct Bounds(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:27:1 + --> $DIR/type-check-defaults.rs:24:1 | -27 | struct WhereClause(T) where T: Copy; +24 | struct WhereClause(T) where T: Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:30:1 + --> $DIR/type-check-defaults.rs:27:1 | -30 | trait TraitBound {} +27 | trait TraitBound {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:34:1 + --> $DIR/type-check-defaults.rs:31:1 | -34 | trait Base: Super { } +31 | trait Base: Super { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound note: required by `Super` - --> $DIR/type-check-defaults.rs:33:1 + --> $DIR/type-check-defaults.rs:30:1 | -33 | trait Super { } +30 | trait Super { } | ^^^^^^^^^^^^^^^^^^^^ error[E0277]: cannot add `u8` to `i32` - --> $DIR/type-check-defaults.rs:37:1 + --> $DIR/type-check-defaults.rs:34:1 | -37 | trait ProjectionPred> where T::Item : Add {} +34 | trait ProjectionPred> where T::Item : Add {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` | = help: the trait `std::ops::Add` is not implemented for `i32` = note: required by `std::ops::Add` -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors From c84b7815b363ad5f2dec9d5f830666ccef440458 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 27 Feb 2018 17:36:33 -0500 Subject: [PATCH 14/15] add a comment --- src/librustc_typeck/check/wfcheck.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 4eb3e29ec6946..39e757c52ff29 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -370,6 +370,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) { let ty = fcx.tcx.type_of(d); + // ignore dependent defaults -- that is, where the default of one type + // parameter includes another (e.g., ). In those cases, we can't + // be sure if it will error or not as user might always specify the other. if !ty.needs_subst() { fcx.register_wf_obligation(ty, fcx.tcx.def_span(d), self.code.clone()); } From 3e84aeda0fa308424338529611a8ee157776b221 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 28 Feb 2018 12:59:30 -0300 Subject: [PATCH 15/15] Update UI test --- src/test/ui/type-check-defaults.stderr | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index 4af8f5da0dd05..f39b7dcb31f0c 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -1,33 +1,33 @@ error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied --> $DIR/type-check-defaults.rs:16:19 | -16 | struct WellFormed>(Z); +LL | struct WellFormed>(Z); | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` note: required by `Foo` --> $DIR/type-check-defaults.rs:15:1 | -15 | struct Foo>(T, U); +LL | struct Foo>(T, U); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied --> $DIR/type-check-defaults.rs:18:27 | -18 | struct WellFormedNoBounds>(Z); +LL | struct WellFormedNoBounds>(Z); | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` note: required by `Foo` --> $DIR/type-check-defaults.rs:15:1 | -15 | struct Foo>(T, U); +LL | struct Foo>(T, U); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:21:1 | -21 | struct Bounds(T); +LL | struct Bounds(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` @@ -35,7 +35,7 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not sa error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:24:1 | -24 | struct WhereClause(T) where T: Copy; +LL | struct WhereClause(T) where T: Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` @@ -43,7 +43,7 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not sa error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:27:1 | -27 | trait TraitBound {} +LL | trait TraitBound {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required by `std::marker::Copy` @@ -51,20 +51,20 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not sa error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:31:1 | -31 | trait Base: Super { } +LL | trait Base: Super { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound note: required by `Super` --> $DIR/type-check-defaults.rs:30:1 | -30 | trait Super { } +LL | trait Super { } | ^^^^^^^^^^^^^^^^^^^^ error[E0277]: cannot add `u8` to `i32` --> $DIR/type-check-defaults.rs:34:1 | -34 | trait ProjectionPred> where T::Item : Add {} +LL | trait ProjectionPred> where T::Item : Add {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` | = help: the trait `std::ops::Add` is not implemented for `i32` @@ -72,3 +72,4 @@ error[E0277]: cannot add `u8` to `i32` error: aborting due to 7 previous errors +If you want more information on this error, try using "rustc --explain E0277"