Type check defaults.
And refactor duplicated code.
This commit is contained in:
parent
0ff9872b22
commit
4d9703373d
@ -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<Ty<'tcx>>)
|
||||
{
|
||||
@ -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,
|
||||
|
@ -34,3 +34,4 @@ fn issue_36540() {
|
||||
}
|
||||
|
||||
trait Trait<T> {}
|
||||
impl Trait<i32> for i32 {}
|
||||
|
31
src/test/ui/type-check-defaults.rs
Normal file
31
src/test/ui/type-check-defaults.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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: FromIterator<T>>(T, U);
|
||||
struct WellFormed<Z = Foo<i32, i32>>(Z);
|
||||
|
||||
struct WellFormedProjection<A, T=<A as Iterator>::Item>(A, T);
|
||||
|
||||
struct Bounds<T:Copy=String>(T);
|
||||
|
||||
struct WhereClause<T=String>(T) where T: Copy;
|
||||
|
||||
trait TraitBound<T:Copy=String> {}
|
||||
|
||||
trait SelfBound<T:Copy=Self> {}
|
||||
|
||||
trait FooTrait<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
|
||||
|
||||
fn main() { }
|
62
src/test/ui/type-check-defaults.stderr
Normal file
62
src/test/ui/type-check-defaults.stderr
Normal file
@ -0,0 +1,62 @@
|
||||
error[E0277]: the trait bound `i32: std::iter::FromIterator<i32>` is not satisfied
|
||||
--> $DIR/type-check-defaults.rs:17:1
|
||||
|
|
||||
17 | struct WellFormed<Z = Foo<i32, i32>>(Z);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a collection of type `i32` cannot be built from an iterator over elements of type `i32`
|
||||
|
|
||||
= help: the trait `std::iter::FromIterator<i32>` 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<A, T=<A as Iterator>::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:Copy=String>(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=String>(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<T:Copy=String> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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<T:Copy=Self> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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<u8>` is not satisfied
|
||||
--> $DIR/type-check-defaults.rs:29:1
|
||||
|
|
||||
29 | trait FooTrait<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8`
|
||||
|
|
||||
= help: the trait `std::ops::Add<u8>` is not implemented for `i32`
|
||||
= note: required by `std::ops::Add`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
Loading…
x
Reference in New Issue
Block a user