Skip to content

Commit 448cc57

Browse files
committed
Auto merge of #48557 - matthewjasper:allow-trvial-bounds, r=nikomatsakis
Implement RFC 2056 trivial constraints in where clauses This is an implementation of the new behaviour for #48214. Tests are mostly updated to show the effects of this. Feature gate hasn't been added yet. Some things that are worth noting and are maybe not want we want * `&mut T: Copy` doesn't allow as much as someone might expect because there is often an implicit reborrow. * ~There isn't a check that a where clause is well-formed any more, so `where Vec<str>: Debug` is now allowed (without a `str: Sized` bound).~ r? @nikomatsakis
2 parents 3ec2058 + be2900c commit 448cc57

38 files changed

+1084
-65
lines changed

src/librustc/traits/error_reporting.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1479,6 +1479,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
14791479
}
14801480
ObligationCauseCode::ReturnType(_) |
14811481
ObligationCauseCode::BlockTailExpression(_) => (),
1482+
ObligationCauseCode::TrivialBound => {
1483+
err.help("see issue #48214");
1484+
if tcx.sess.opts.unstable_features.is_nightly_build() {
1485+
err.help("add #![feature(trivial_bounds)] to the \
1486+
crate attributes to enable",
1487+
);
1488+
}
1489+
}
14821490
}
14831491
}
14841492

src/librustc/traits/fulfill.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
330330
ty::Predicate::Trait(ref data) => {
331331
let trait_obligation = obligation.with(data.clone());
332332

333-
if data.is_global() {
333+
if data.is_global() && !data.has_late_bound_regions() {
334334
// no type variables present, can use evaluation for better caching.
335335
// FIXME: consider caching errors too.
336336
if selcx.infcx().predicate_must_hold(&obligation) {

src/librustc/traits/mod.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ pub enum ObligationCauseCode<'tcx> {
243243

244244
/// Block implicit return
245245
BlockTailExpression(ast::NodeId),
246+
247+
/// #[feature(trivial_bounds)] is not enabled
248+
TrivialBound,
246249
}
247250

248251
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -641,17 +644,8 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
641644

642645
let predicates: Vec<_> =
643646
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec())
644-
.filter(|p| !p.is_global()) // (*)
645647
.collect();
646648

647-
// (*) Any predicate like `i32: Trait<u32>` or whatever doesn't
648-
// need to be in the *environment* to be proven, so screen those
649-
// out. This is important for the soundness of inter-fn
650-
// caching. Note though that we should probably check that these
651-
// predicates hold at the point where the environment is
652-
// constructed, but I am not currently doing so out of laziness.
653-
// -nmatsakis
654-
655649
debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
656650
predicates);
657651

src/librustc/traits/select.rs

+28-37
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,6 @@ enum BuiltinImplConditions<'tcx> {
305305
/// There is no built-in impl. There may be some other
306306
/// candidate (a where-clause or user-defined impl).
307307
None,
308-
/// There is *no* impl for this, builtin or not. Ignore
309-
/// all where-clauses.
310-
Never,
311308
/// It is unknown whether there is an impl.
312309
Ambiguous
313310
}
@@ -781,13 +778,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
781778
mut obligation: TraitObligation<'tcx>)
782779
-> Result<EvaluationResult, OverflowError>
783780
{
784-
debug!("evaluate_trait_predicate_recursively({:?})",
785-
obligation);
781+
debug!("evaluate_trait_predicate_recursively({:?})", obligation);
786782

787-
if !self.intercrate.is_some() && obligation.is_global() {
788-
// If a param env is consistent, global obligations do not depend on its particular
789-
// value in order to work, so we can clear out the param env and get better
790-
// caching. (If the current param env is inconsistent, we don't care what happens).
783+
if self.intercrate.is_none() && obligation.is_global()
784+
&& obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst()) {
785+
// If a param env has no global bounds, global obligations do not
786+
// depend on its particular value in order to work, so we can clear
787+
// out the param env and get better caching.
791788
debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation);
792789
obligation.param_env = obligation.param_env.without_caller_bounds();
793790
}
@@ -1451,22 +1448,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
14511448
let sized_conditions = self.sized_conditions(obligation);
14521449
self.assemble_builtin_bound_candidates(sized_conditions,
14531450
&mut candidates)?;
1454-
} else if lang_items.unsize_trait() == Some(def_id) {
1455-
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
1456-
} else {
1457-
if lang_items.clone_trait() == Some(def_id) {
1458-
// Same builtin conditions as `Copy`, i.e. every type which has builtin support
1459-
// for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
1460-
// types have builtin support for `Clone`.
1461-
let clone_conditions = self.copy_clone_conditions(obligation);
1462-
self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
1463-
}
1464-
1465-
self.assemble_generator_candidates(obligation, &mut candidates)?;
1466-
self.assemble_closure_candidates(obligation, &mut candidates)?;
1467-
self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
1468-
self.assemble_candidates_from_impls(obligation, &mut candidates)?;
1469-
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
1451+
} else if lang_items.unsize_trait() == Some(def_id) {
1452+
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
1453+
} else {
1454+
if lang_items.clone_trait() == Some(def_id) {
1455+
// Same builtin conditions as `Copy`, i.e. every type which has builtin support
1456+
// for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
1457+
// types have builtin support for `Clone`.
1458+
let clone_conditions = self.copy_clone_conditions(obligation);
1459+
self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
1460+
}
1461+
1462+
self.assemble_generator_candidates(obligation, &mut candidates)?;
1463+
self.assemble_closure_candidates(obligation, &mut candidates)?;
1464+
self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
1465+
self.assemble_candidates_from_impls(obligation, &mut candidates)?;
1466+
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
14701467
}
14711468

14721469
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
@@ -2081,13 +2078,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
20812078
// BUILTIN BOUNDS
20822079
//
20832080
// These cover the traits that are built-in to the language
2084-
// itself. This includes `Copy` and `Sized` for sure. For the
2085-
// moment, it also includes `Send` / `Sync` and a few others, but
2086-
// those will hopefully change to library-defined traits in the
2087-
// future.
2081+
// itself: `Copy`, `Clone` and `Sized`.
20882082

2089-
// HACK: if this returns an error, selection exits without considering
2090-
// other impls.
20912083
fn assemble_builtin_bound_candidates<'o>(&mut self,
20922084
conditions: BuiltinImplConditions<'tcx>,
20932085
candidates: &mut SelectionCandidateSet<'tcx>)
@@ -2106,14 +2098,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
21062098
debug!("assemble_builtin_bound_candidates: ambiguous builtin");
21072099
Ok(candidates.ambiguous = true)
21082100
}
2109-
BuiltinImplConditions::Never => { Err(Unimplemented) }
21102101
}
21112102
}
21122103

21132104
fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
21142105
-> BuiltinImplConditions<'tcx>
21152106
{
2116-
use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
2107+
use self::BuiltinImplConditions::{Ambiguous, None, Where};
21172108

21182109
// NOTE: binder moved to (*)
21192110
let self_ty = self.infcx.shallow_resolve(
@@ -2130,7 +2121,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
21302121
Where(ty::Binder::dummy(Vec::new()))
21312122
}
21322123

2133-
ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never,
2124+
ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => None,
21342125

21352126
ty::TyTuple(tys) => {
21362127
Where(ty::Binder::bind(tys.last().into_iter().cloned().collect()))
@@ -2164,7 +2155,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
21642155
let self_ty = self.infcx.shallow_resolve(
21652156
obligation.predicate.skip_binder().self_ty());
21662157

2167-
use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
2158+
use self::BuiltinImplConditions::{Ambiguous, None, Where};
21682159

21692160
match self_ty.sty {
21702161
ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
@@ -2182,7 +2173,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
21822173
ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
21832174
ty::TyGenerator(..) | ty::TyGeneratorWitness(..) | ty::TyForeign(..) |
21842175
ty::TyRef(_, _, hir::MutMutable) => {
2185-
Never
2176+
None
21862177
}
21872178

21882179
ty::TyArray(element_ty, _) => {
@@ -2202,7 +2193,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
22022193
if is_copy_trait || is_clone_trait {
22032194
Where(ty::Binder::bind(substs.upvar_tys(def_id, self.tcx()).collect()))
22042195
} else {
2205-
Never
2196+
None
22062197
}
22072198
}
22082199

src/librustc/traits/structural_impls.rs

+1
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
243243
super::IntrinsicType => Some(super::IntrinsicType),
244244
super::MethodReceiver => Some(super::MethodReceiver),
245245
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
246+
super::TrivialBound => Some(super::TrivialBound),
246247
}
247248
}
248249
}

src/librustc/ty/flags.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl FlagComputation {
7979
}
8080

8181
&ty::TyParam(ref p) => {
82-
self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
82+
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
8383
if p.is_self() {
8484
self.add_flags(TypeFlags::HAS_SELF);
8585
} else {
@@ -89,7 +89,7 @@ impl FlagComputation {
8989

9090
&ty::TyGenerator(_, ref substs, _) => {
9191
self.add_flags(TypeFlags::HAS_TY_CLOSURE);
92-
self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
92+
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
9393
self.add_substs(&substs.substs);
9494
}
9595

@@ -101,12 +101,12 @@ impl FlagComputation {
101101

102102
&ty::TyClosure(_, ref substs) => {
103103
self.add_flags(TypeFlags::HAS_TY_CLOSURE);
104-
self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
104+
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
105105
self.add_substs(&substs.substs);
106106
}
107107

108108
&ty::TyInfer(infer) => {
109-
self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
109+
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right?
110110
self.add_flags(TypeFlags::HAS_TY_INFER);
111111
match infer {
112112
ty::FreshTy(_) |

src/librustc/ty/fold.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,14 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
116116

117117
/// Indicates whether this value references only 'global'
118118
/// types/lifetimes that are the same regardless of what fn we are
119-
/// in. This is used for caching. Errs on the side of returning
120-
/// false.
119+
/// in. This is used for caching.
121120
fn is_global(&self) -> bool {
122-
!self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES)
121+
!self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
122+
}
123+
124+
/// True if there are any late-bound regions
125+
fn has_late_bound_regions(&self) -> bool {
126+
self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
123127
}
124128
}
125129

src/librustc/ty/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ bitflags! {
441441

442442
// true if there are "names" of types and regions and so forth
443443
// that are local to a particular fn
444-
const HAS_LOCAL_NAMES = 1 << 10;
444+
const HAS_FREE_LOCAL_NAMES = 1 << 10;
445445

446446
// Present if the type belongs in a local type context.
447447
// Only set for TyInfer other than Fresh.
@@ -455,6 +455,10 @@ bitflags! {
455455
// ought to be true only for the results of canonicalization.
456456
const HAS_CANONICAL_VARS = 1 << 13;
457457

458+
/// Does this have any `ReLateBound` regions? Used to check
459+
/// if a global bound is safe to evaluate.
460+
const HAS_RE_LATE_BOUND = 1 << 14;
461+
458462
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
459463
TypeFlags::HAS_SELF.bits |
460464
TypeFlags::HAS_RE_EARLY_BOUND.bits;
@@ -472,9 +476,10 @@ bitflags! {
472476
TypeFlags::HAS_TY_ERR.bits |
473477
TypeFlags::HAS_PROJECTION.bits |
474478
TypeFlags::HAS_TY_CLOSURE.bits |
475-
TypeFlags::HAS_LOCAL_NAMES.bits |
479+
TypeFlags::HAS_FREE_LOCAL_NAMES.bits |
476480
TypeFlags::KEEP_IN_LOCAL_TCX.bits |
477-
TypeFlags::HAS_CANONICAL_VARS.bits;
481+
TypeFlags::HAS_CANONICAL_VARS.bits |
482+
TypeFlags::HAS_RE_LATE_BOUND.bits;
478483
}
479484
}
480485

src/librustc/ty/sty.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1268,7 +1268,9 @@ impl RegionKind {
12681268
flags = flags | TypeFlags::HAS_FREE_REGIONS;
12691269
flags = flags | TypeFlags::HAS_RE_SKOL;
12701270
}
1271-
ty::ReLateBound(..) => { }
1271+
ty::ReLateBound(..) => {
1272+
flags = flags | TypeFlags::HAS_RE_LATE_BOUND;
1273+
}
12721274
ty::ReEarlyBound(..) => {
12731275
flags = flags | TypeFlags::HAS_FREE_REGIONS;
12741276
flags = flags | TypeFlags::HAS_RE_EARLY_BOUND;
@@ -1291,8 +1293,8 @@ impl RegionKind {
12911293
}
12921294

12931295
match *self {
1294-
ty::ReStatic | ty::ReEmpty | ty::ReErased => (),
1295-
_ => flags = flags | TypeFlags::HAS_LOCAL_NAMES,
1296+
ty::ReStatic | ty::ReEmpty | ty::ReErased | ty::ReLateBound(..) => (),
1297+
_ => flags = flags | TypeFlags::HAS_FREE_LOCAL_NAMES,
12961298
}
12971299

12981300
debug!("type_flags({:?}) = {:?}", self, flags);

src/librustc_lint/builtin.rs

+58
Original file line numberDiff line numberDiff line change
@@ -1591,3 +1591,61 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate {
15911591
self.0 += 1;
15921592
}
15931593
}
1594+
1595+
/// Lint for trait and lifetime bounds that don't depend on type parameters
1596+
/// which either do nothing, or stop the item from being used.
1597+
pub struct TrivialConstraints;
1598+
1599+
declare_lint! {
1600+
TRIVIAL_BOUNDS,
1601+
Warn,
1602+
"these bounds don't depend on an type parameters"
1603+
}
1604+
1605+
impl LintPass for TrivialConstraints {
1606+
fn get_lints(&self) -> LintArray {
1607+
lint_array!(TRIVIAL_BOUNDS)
1608+
}
1609+
}
1610+
1611+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
1612+
fn check_item(
1613+
&mut self,
1614+
cx: &LateContext<'a, 'tcx>,
1615+
item: &'tcx hir::Item,
1616+
) {
1617+
use rustc::ty::fold::TypeFoldable;
1618+
use rustc::ty::Predicate::*;
1619+
1620+
1621+
if cx.tcx.features().trivial_bounds {
1622+
let def_id = cx.tcx.hir.local_def_id(item.id);
1623+
let predicates = cx.tcx.predicates_of(def_id);
1624+
for predicate in &predicates.predicates {
1625+
let predicate_kind_name = match *predicate {
1626+
Trait(..) => "Trait",
1627+
TypeOutlives(..) |
1628+
RegionOutlives(..) => "Lifetime",
1629+
1630+
// Ignore projections, as they can only be global
1631+
// if the trait bound is global
1632+
Projection(..) |
1633+
// Ignore bounds that a user can't type
1634+
WellFormed(..) |
1635+
ObjectSafe(..) |
1636+
ClosureKind(..) |
1637+
Subtype(..) |
1638+
ConstEvaluatable(..) => continue,
1639+
};
1640+
if predicate.is_global() {
1641+
cx.span_lint(
1642+
TRIVIAL_BOUNDS,
1643+
item.span,
1644+
&format!("{} bound {} does not depend on any type \
1645+
or lifetime parameters", predicate_kind_name, predicate),
1646+
);
1647+
}
1648+
}
1649+
}
1650+
}
1651+
}

src/librustc_lint/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
137137
UnreachablePub,
138138
TypeAliasBounds,
139139
UnusedBrokenConst,
140+
TrivialConstraints,
140141
);
141142

142143
add_builtin_with_new!(sess,

0 commit comments

Comments
 (0)