提交 62f0fc51 编写于 作者: N Niko Matsakis

port the relate-types code from NLL type-check into a type-op

Add regression tests for #55219 and #55241

Also another test where a duplicate-like error appears to have been
suppressed; I'm not 100% sure why this output changes, though I could
imagine that some duplicate suppression is enabled by this PR.
上级 7c8887cc
......@@ -142,6 +142,28 @@ pub fn eq<T>(self,
self.trace(expected, actual).eq(&expected, &actual)
}
pub fn relate<T>(
self,
expected: T,
variance: ty::Variance,
actual: T,
) -> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
match variance {
ty::Variance::Covariant => self.sub(expected, actual),
ty::Variance::Invariant => self.eq(expected, actual),
ty::Variance::Contravariant => self.sup(expected, actual),
// We could make this make sense but it's not readily
// exposed and I don't feel like dealing with it. Note
// that bivariance in general does a bit more than just
// *nothing*, it checks that the types are the same
// "modulo variance" basically.
ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"),
}
}
/// Compute the least-upper-bound, or mutual supertype, of two
/// values. The order of the arguments doesn't matter, but since
/// this can result in an error (e.g., if asked to compute LUB of
......
......@@ -9,24 +9,27 @@
// except according to those terms.
use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
use mir::UserTypeAnnotation;
use traits::query::Fallible;
use hir::def_id::DefId;
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
use ty::subst::UserSubsts;
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct AscribeUserType<'tcx> {
pub mir_ty: Ty<'tcx>,
pub variance: ty::Variance,
pub user_ty: UserTypeAnnotation<'tcx>,
pub def_id: DefId,
pub user_substs: UserSubsts<'tcx>,
}
impl<'tcx> AscribeUserType<'tcx> {
pub fn new(
mir_ty: Ty<'tcx>,
variance: ty::Variance,
user_ty: UserTypeAnnotation<'tcx>,
def_id: DefId,
user_substs: UserSubsts<'tcx>,
) -> Self {
AscribeUserType { mir_ty, variance, user_ty }
AscribeUserType { mir_ty, variance, def_id, user_substs }
}
}
......@@ -56,19 +59,19 @@ fn shrink_to_tcx_lifetime(
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for AscribeUserType<'tcx> {
mir_ty, variance, user_ty
mir_ty, variance, def_id, user_substs
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> {
type Lifted = AscribeUserType<'tcx>;
mir_ty, variance, user_ty
mir_ty, variance, def_id, user_substs
}
}
impl_stable_hash_for! {
struct AscribeUserType<'tcx> {
mir_ty, variance, user_ty
mir_ty, variance, def_id, user_substs
}
}
......@@ -42,7 +42,7 @@
use rustc::traits::query::{Fallible, NoSolution};
use rustc::traits::{ObligationCause, PredicateObligations};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSelfTy, UserSubsts};
use rustc::ty::subst::{Subst, Substs, UnpackedKind};
use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
use std::rc::Rc;
use std::{fmt, iter};
......@@ -975,127 +975,43 @@ fn relate_type_and_user_type(
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
let tcx = self.tcx();
debug!(
"relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})",
a, v, user_ty, locations
"relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})",
a, v, user_ty, locations,
);
// The `TypeRelating` code assumes that "unresolved inference
// variables" appear in the "a" side, so flip `Contravariant`
// ambient variance to get the right relationship.
let v1 = ty::Contravariant.xform(v);
match user_ty {
UserTypeAnnotation::Ty(canonical_ty) => {
let (ty, _) = self.infcx
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
self.relate_types(ty, v1, a, locations, category)?;
// The `TypeRelating` code assumes that "unresolved inference
// variables" appear in the "a" side, so flip `Contravariant`
// ambient variance to get the right relationship.
let v1 = ty::Contravariant.xform(v);
self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category);
self.relate_types(ty, v1, a, locations, category)?;
}
UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
let (
UserSubsts {
substs,
user_self_ty,
},
user_substs,
_,
) = self.infcx
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
let ty = self.tcx().type_of(def_id);
let ty = ty.subst(tcx, substs);
debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
let ty = self.normalize(ty, locations);
self.relate_types(ty, v1, a, locations, category)?;
if let Some(UserSelfTy {
impl_def_id,
self_ty,
}) = user_self_ty
{
let impl_self_ty = tcx.type_of(impl_def_id);
let impl_self_ty = impl_self_ty.subst(tcx, &substs);
let impl_self_ty = self.normalize(impl_self_ty, locations);
// There may be type variables in `substs` and hence
// in `impl_self_ty`, but they should all have been
// resolved to some fixed value during the first call
// to `relate`, above. Therefore, if we use
// `resolve_type_vars_if_possible` we should get to
// something without type variables. This is important
// because the `b` type in `relate_with_variance`
// below is not permitted to have inference variables.
let impl_self_ty = self.infcx.resolve_type_vars_if_possible(&impl_self_ty);
assert!(!impl_self_ty.has_infer_types());
self.eq_types(self_ty, impl_self_ty, locations, category)?;
self.prove_predicate(
ty::Predicate::WellFormed(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,
self.fully_perform_op(
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);
category,
self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
a, v, def_id, user_substs,
)),
)?;
}
}
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>,
......
......@@ -8,20 +8,28 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::infer::at::ToTrace;
use rustc::infer::canonical::{Canonical, QueryResponse};
use rustc::infer::InferCtxt;
use rustc::hir::def_id::DefId;
use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType;
use rustc::traits::query::type_op::eq::Eq;
use rustc::traits::query::type_op::normalize::Normalize;
use rustc::traits::query::type_op::prove_predicate::ProvePredicate;
use rustc::traits::query::type_op::subtype::Subtype;
use rustc::traits::query::{Fallible, NoSolution};
use rustc::traits::{FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine,
TraitEngineExt};
use rustc::traits::{
FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt,
};
use rustc::ty::query::Providers;
use rustc::ty::{FnSig, Lift, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable};
use rustc::ty::subst::{Kind, Subst, UserSelfTy, UserSubsts};
use rustc::ty::{
FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance,
};
use rustc_data_structures::sync::Lrc;
use std::fmt;
use syntax::ast;
use syntax_pos::DUMMY_SP;
crate fn provide(p: &mut Providers) {
*p = Providers {
......@@ -43,12 +51,146 @@ fn type_op_ascribe_user_type<'tcx>(
) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>, NoSolution> {
tcx.infer_ctxt()
.enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
let (param_env, AscribeUserType { mir_ty, variance, user_ty }) = key.into_parts();
drop((infcx, fulfill_cx, param_env, mir_ty, variance, user_ty));
let (
param_env,
AscribeUserType {
mir_ty,
variance,
def_id,
user_substs,
},
) = key.into_parts();
debug!(
"type_op_ascribe_user_type(\
mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}\
)",
mir_ty, variance, def_id, user_substs,
);
let mut cx = AscribeUserTypeCx {
infcx,
param_env,
fulfill_cx,
};
cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs)?;
Ok(())
})
}
struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> {
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
param_env: ParamEnv<'tcx>,
fulfill_cx: &'me mut FulfillmentContext<'tcx>,
}
impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
fn normalize<T>(&mut self, value: T) -> T
where
T: TypeFoldable<'tcx>,
{
self.infcx
.partially_normalize_associated_types_in(
DUMMY_SP,
ast::CRATE_NODE_ID,
self.param_env,
&value,
)
.into_value_registering_obligations(self.infcx, self.fulfill_cx)
}
fn relate<T>(&mut self, a: T, variance: Variance, b: T) -> Result<(), NoSolution>
where
T: ToTrace<'tcx>,
{
Ok(self.infcx
.at(&ObligationCause::dummy(), self.param_env)
.relate(a, variance, b)?
.into_value_registering_obligations(self.infcx, self.fulfill_cx))
}
fn prove_predicate(&mut self, predicate: Predicate<'tcx>) {
self.fulfill_cx.register_predicate_obligation(
self.infcx,
Obligation::new(ObligationCause::dummy(), self.param_env, predicate),
);
}
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
self.infcx.tcx
}
fn subst<T>(&self, value: T, substs: &[Kind<'tcx>]) -> T
where
T: TypeFoldable<'tcx>,
{
value.subst(self.tcx(), substs)
}
fn relate_mir_and_user_ty(
&mut self,
mir_ty: Ty<'tcx>,
variance: Variance,
def_id: DefId,
user_substs: UserSubsts<'tcx>,
) -> Result<(), NoSolution> {
let UserSubsts {
substs,
user_self_ty,
} = user_substs;
let ty = self.tcx().type_of(def_id);
let ty = self.subst(ty, substs);
debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
let ty = self.normalize(ty);
self.relate(mir_ty, variance, ty)?;
if let Some(UserSelfTy {
impl_def_id,
self_ty,
}) = user_self_ty
{
let impl_self_ty = self.tcx().type_of(impl_def_id);
let impl_self_ty = self.subst(impl_self_ty, &substs);
let impl_self_ty = self.normalize(impl_self_ty);
self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
self.prove_predicate(Predicate::WellFormed(impl_self_ty));
}
// 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 = self.tcx()
.predicates_of(def_id)
.instantiate(self.tcx(), substs);
for instantiated_predicate in instantiated_predicates.predicates {
let instantiated_predicate = self.normalize(instantiated_predicate);
self.prove_predicate(instantiated_predicate);
}
// 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(Predicate::WellFormed(ty));
Ok(())
}
}
fn type_op_eq<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>,
......
// Regression test for #55219:
//
// The `Self::HASH_LEN` here expands to a "self-type" where `T` is not
// known. This unbound inference variable was causing an ICE.
//
// run-pass
#![feature(nll)]
pub struct Foo<T>(T);
impl<T> Foo<T> {
const HASH_LEN: usize = 20;
fn stuff() {
let _ = Self::HASH_LEN;
}
}
fn main() { }
// Regression test for #55241:
//
// The reference to `C::HASHED_NULL_NODE` resulted in a type like `<C
// as NodeCodec<_>>::Out`; normalizing this type requires knowing the
// value of `_`; solving that requires having normalized, so we can
// test against `C: NodeCodec<H>` in the environment.
//
// run-pass
#![feature(nll)]
pub trait Hasher {
type Out: Eq;
}
pub trait NodeCodec<H: Hasher> {
const HASHED_NULL_NODE: H::Out;
}
pub trait Trie<H: Hasher, C: NodeCodec<H>> {
/// Return the root of the trie.
fn root(&self) -> &H::Out;
/// Is the trie empty?
fn is_empty(&self) -> bool { *self.root() == C::HASHED_NULL_NODE }
}
fn main() { }
......@@ -12,21 +12,6 @@ LL | let z: &'a & usize = &(&y);
LL | }
| - temporary value is freed at the end of this statement
error[E0597]: `y` does not live long enough
--> $DIR/regions-free-region-ordering-caller1.rs:19:27
|
LL | fn call1<'a>(x: &'a usize) {
| -- lifetime `'a` defined here
...
LL | let z: &'a & usize = &(&y);
| ----------- ^^^^ borrowed value does not live long enough
| |
| type annotation requires that `y` is borrowed for `'a`
...
LL | }
| - `y` dropped here while still borrowed
error: aborting due to 2 previous errors
error: aborting due to previous error
Some errors occurred: E0597, E0716.
For more information about an error, try `rustc --explain E0597`.
For more information about this error, try `rustc --explain E0716`.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册