1
Fork 0

normalize and prove predicates

Also include a test that was not working previously.
This commit is contained in:
Niko Matsakis 2018-10-17 11:10:08 -04:00
parent 121f3c8d19
commit bfb1d959c3
3 changed files with 76 additions and 1 deletions

View file

@ -42,7 +42,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp;
use rustc::traits::query::{Fallible, NoSolution};
use rustc::traits::{ObligationCause, PredicateObligations};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSubsts, UserSelfTy};
use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSelfTy, UserSubsts};
use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
use std::rc::Rc;
use std::{fmt, iter};
@ -1034,6 +1034,29 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
self.eq_types(self_ty, impl_self_ty, locations, category)?;
}
// Prove the predicates coming along with `def_id`.
//
// Also, normalize the `instantiated_predicates`
// because otherwise we wind up with duplicate "type
// outlives" error messages.
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
let instantiated_predicates = self.fold_to_region_vid(instantiated_predicates);
self.normalize_and_prove_instantiated_predicates(
instantiated_predicates,
locations,
);
// In addition to proving the predicates, we have to
// prove that `ty` is well-formed -- this is because
// the WF of `ty` is predicated on the substs being
// well-formed, and we haven't proven *that*. We don't
// want to prove the WF of types from `substs` directly because they
// haven't been normalized.
//
// FIXME(nmatsakis): Well, perhaps we should normalize
// them? This would only be relevant if some input
// type were ill-formed but did not appear in `ty`,
// which...could happen with normalization...
self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category);
}
}
@ -1041,6 +1064,32 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
Ok(())
}
/// Replace all free regions in `value` with their NLL `RegionVid`
/// equivalents; if not in NLL, does nothing. This is never
/// particularly necessary -- we'll do it lazilly as we process
/// the value anyway -- but in some specific cases it is useful to
/// normalize so we can suppress duplicate error messages.
fn fold_to_region_vid<T>(
&self,
value: T
) -> T
where T: TypeFoldable<'tcx>
{
if let Some(borrowck_context) = &self.borrowck_context {
self.tcx().fold_regions(&value, &mut false, |r, _debruijn| {
if r.has_free_regions() {
self.tcx().mk_region(ty::RegionKind::ReVar(
borrowck_context.universal_regions.to_region_vid(r),
))
} else {
r
}
})
} else {
value
}
}
fn eq_opaque_type_and_type(
&mut self,
revealed_ty: Ty<'tcx>,

View file

@ -0,0 +1,16 @@
#![feature(nll)]
trait Foo<'a> {
const C: &'a u32;
}
impl<'a, T> Foo<'a> for T {
const C: &'a u32 = &22;
}
fn foo<'a, T: Foo<'a>>() -> &'static u32 {
T::C //~ ERROR
}
fn main() {
}

View file

@ -0,0 +1,10 @@
error: unsatisfied lifetime constraints
--> $DIR/constant-in-expr-trait-item-3.rs:12:5
|
LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
| -- lifetime `'a` defined here
LL | T::C //~ ERROR
| ^^^^ returning this value requires that `'a` must outlive `'static`
error: aborting due to previous error