Stop well-formedness checking unreachable code.

This commit stops well-formedness checking applying to unreachable code
and therefore stops some of the ICEs that the intended solution taken by
this PR causes.

By disabling these checks, we can land the other fixes and larger
refactors that this PR includes.
This commit is contained in:
David Wood 2018-12-18 21:27:22 +01:00
parent 95c18382cb
commit 28fd1b04e5
No known key found for this signature in database
GPG Key ID: 01760B4F9F53F154
13 changed files with 70 additions and 245 deletions

View File

@ -62,8 +62,7 @@ use syntax_pos::symbol::InternedString;
use traits;
use traits::query::{
CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
CanonicalTypeOpAscribeUserTypeWellFormedGoal, CanonicalTypeOpEqGoal,
CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal,
CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal,
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal,
};
use ty::{TyCtxt, FnSig, Instance, InstanceDef,
@ -651,7 +650,6 @@ define_dep_nodes!( <'tcx>
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
[] EvaluateGoal(traits::ChalkCanonicalGoal<'tcx>),
[] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>),
[] TypeOpAscribeUserTypeWellFormed(CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx>),
[] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>),
[] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>),
[] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>),

View File

@ -28,10 +28,6 @@ pub type CanonicalPredicateGoal<'tcx> =
pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>;
pub type CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx,
type_op::ascribe_user_type::AscribeUserTypeWellFormed<'tcx>>>;
pub type CanonicalTypeOpEqGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>;

View File

@ -2,7 +2,7 @@ use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, Que
use traits::query::Fallible;
use hir::def_id::DefId;
use mir::ProjectionKind;
use ty::{self, ParamEnvAnd, Ty, TyCtxt, UserTypeAnnotation};
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
use ty::subst::UserSubsts;
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@ -68,59 +68,3 @@ impl_stable_hash_for! {
mir_ty, variance, def_id, user_substs, projs
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct AscribeUserTypeWellFormed<'tcx> {
pub user_type_annotation: UserTypeAnnotation<'tcx>,
}
impl<'tcx> AscribeUserTypeWellFormed<'tcx> {
pub fn new(
user_type_annotation: UserTypeAnnotation<'tcx>,
) -> Self {
Self { user_type_annotation, }
}
}
impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserTypeWellFormed<'tcx> {
type QueryResponse = ();
fn try_fast_path(
_tcx: TyCtxt<'_, 'gcx, 'tcx>,
_key: &ParamEnvAnd<'tcx, Self>,
) -> Option<Self::QueryResponse> {
None
}
fn perform_query(
tcx: TyCtxt<'_, 'gcx, 'tcx>,
canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
) -> Fallible<CanonicalizedQueryResponse<'gcx, ()>> {
tcx.type_op_ascribe_user_type_well_formed(canonicalized)
}
fn shrink_to_tcx_lifetime(
v: &'a CanonicalizedQueryResponse<'gcx, ()>,
) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> {
v
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for AscribeUserTypeWellFormed<'tcx> {
user_type_annotation
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for AscribeUserTypeWellFormed<'a> {
type Lifted = AscribeUserTypeWellFormed<'tcx>;
user_type_annotation
}
}
impl_stable_hash_for! {
struct AscribeUserTypeWellFormed<'tcx> {
user_type_annotation
}
}

View File

@ -5,8 +5,7 @@ use mir::interpret::GlobalId;
use traits;
use traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpAscribeUserTypeWellFormedGoal,
CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
};
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
@ -125,15 +124,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type<'tcx> {
}
}
impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type_well_formed<'tcx> {
fn describe(
_tcx: TyCtxt<'_, '_, '_>,
goal: CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx>,
) -> Cow<'static, str> {
format!("evaluating `type_op_ascribe_user_type_well_formed` `{:?}`", goal).into()
}
}
impl<'tcx> QueryDescription<'tcx> for queries::type_op_eq<'tcx> {
fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTypeOpEqGoal<'tcx>) -> Cow<'static, str> {
format!("evaluating `type_op_eq` `{:?}`", goal).into()

View File

@ -27,8 +27,7 @@ use traits::{self, Vtable};
use traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal,
CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
CanonicalTypeOpAscribeUserTypeWellFormedGoal, CanonicalTypeOpEqGoal,
CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
CanonicalTypeOpNormalizeGoal, NoSolution,
};
use traits::query::method_autoderef::MethodAutoderefStepsResult;
@ -610,14 +609,6 @@ define_queries! { <'tcx>
NoSolution,
>,
/// Do not call this query directly: part of the `Eq` type-op
[] fn type_op_ascribe_user_type_well_formed: TypeOpAscribeUserTypeWellFormed(
CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx>
) -> Result<
Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>,
NoSolution,
>,
/// Do not call this query directly: part of the `Eq` type-op
[] fn type_op_eq: TypeOpEq(
CanonicalTypeOpEqGoal<'tcx>

View File

@ -1208,7 +1208,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::EvaluateObligation |
DepKind::EvaluateGoal |
DepKind::TypeOpAscribeUserType |
DepKind::TypeOpAscribeUserTypeWellFormed |
DepKind::TypeOpEq |
DepKind::TypeOpSubtype |
DepKind::TypeOpProvePredicate |

View File

@ -289,6 +289,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
self.out.extend(obligations);
}
ty::FnDef(did, substs) => {
let obligations = self.nominal_obligations(did, substs);
self.out.extend(obligations);
}
ty::Ref(r, rty, _) => {
// WfReference
if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
@ -349,7 +354,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
}
}
ty::FnDef(..) | ty::FnPtr(_) => {
ty::FnPtr(_) => {
// let the loop iterate into the argument/return
// types appearing in the fn signature
}

View File

@ -928,37 +928,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
);
}
/// Check that user type annotations are well formed.
fn check_user_type_annotations_are_well_formed(&mut self) {
for index in self.mir.user_type_annotations.indices() {
let (span, _) = &self.mir.user_type_annotations[index];
let type_annotation = self.instantiated_type_annotations[&index];
match type_annotation {
// We can't check the well-formedness of a `UserTypeAnnotation::Ty` here, it will
// cause ICEs (see comment in `relate_type_and_user_type`).
UserTypeAnnotation::TypeOf(..) => {
if let Err(terr) = self.fully_perform_op(
Locations::All(*span),
ConstraintCategory::Assignment,
self.param_env.and(
type_op::ascribe_user_type::AscribeUserTypeWellFormed::new(
type_annotation,
)
),
) {
span_mirbug!(
self,
type_annotation,
"bad user type annotation: {:?}",
terr,
);
}
},
_ => {},
}
}
}
/// Given some operation `op` that manipulates types, proves
/// predicates, or otherwise uses the inference context, executes
/// `op` and then executes all the further obligations that `op`
@ -1127,27 +1096,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
if let Ok(projected_ty) = curr_projected_ty {
let ty = projected_ty.to_ty(tcx);
self.relate_types(ty, v1, a, locations, category)?;
// We'll get an ICE if we check for well-formedness of a
// `UserTypeAnnotation::Ty` that hasn't had types related.
//
// Doing this without the types having been related will result in
// `probe_ty_var` failing in the canonicalizer - in practice, this
// results in three run-pass tests failing. You can work around that
// by keeping an vec of projections instead of annotations and performing
// the projections before storing into `instantiated_type_annotations`
// but that still fails in dead code.
self.fully_perform_op(
locations,
category,
self.param_env.and(
type_op::ascribe_user_type::AscribeUserTypeWellFormed::new(
UserTypeAnnotation::Ty(ty),
)
),
)?;
}
}
UserTypeAnnotation::TypeOf(def_id, user_substs) => {
let projs = self.infcx.tcx.intern_projs(&user_ty.projs);
@ -2453,8 +2402,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
self.check_terminator(mir, block_data.terminator(), location);
self.check_iscleanup(mir, block_data);
}
self.check_user_type_annotations_are_well_formed();
}
fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T

View File

@ -4,7 +4,7 @@ use rustc::infer::InferCtxt;
use rustc::hir::def_id::DefId;
use rustc::mir::ProjectionKind;
use rustc::mir::tcx::PlaceTy;
use rustc::traits::query::type_op::ascribe_user_type::{AscribeUserType, AscribeUserTypeWellFormed};
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;
@ -17,7 +17,6 @@ use rustc::ty::query::Providers;
use rustc::ty::subst::{Kind, Subst, UserSubsts, UserSelfTy};
use rustc::ty::{
FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance,
UserTypeAnnotation,
};
use rustc_data_structures::sync::Lrc;
use std::fmt;
@ -27,7 +26,6 @@ use syntax_pos::DUMMY_SP;
crate fn provide(p: &mut Providers) {
*p = Providers {
type_op_ascribe_user_type,
type_op_ascribe_user_type_well_formed,
type_op_eq,
type_op_prove_predicate,
type_op_subtype,
@ -62,28 +60,6 @@ fn type_op_ascribe_user_type<'tcx>(
})
}
fn type_op_ascribe_user_type_well_formed<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserTypeWellFormed<'tcx>>>,
) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>, NoSolution> {
tcx.infer_ctxt()
.enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
let (
param_env, AscribeUserTypeWellFormed { user_type_annotation }
) = key.into_parts();
debug!(
"type_op_ascribe_user_type_well_formed: user_type_annotation={:?}",
user_type_annotation,
);
let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
cx.well_formed(user_type_annotation)?;
Ok(())
})
}
struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> {
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
param_env: ParamEnv<'tcx>,
@ -133,56 +109,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
value.subst(self.tcx(), substs)
}
fn well_formed(
&mut self,
type_annotation: UserTypeAnnotation<'tcx>
) -> Result<(), NoSolution> {
match type_annotation {
UserTypeAnnotation::Ty(ty) => {
self.prove_predicate(Predicate::WellFormed(ty));
Ok(())
},
UserTypeAnnotation::TypeOf(did, user_substs) => {
let UserSubsts {
user_self_ty,
substs,
} = user_substs;
let ty = self.tcx().type_of(did);
let ty = self.subst(ty, substs);
debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
let ty = self.normalize(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));
}
// 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 relate_mir_and_user_ty(
&mut self,
mir_ty: Ty<'tcx>,
@ -192,7 +118,7 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
projs: &[ProjectionKind<'tcx>],
) -> Result<(), NoSolution> {
let UserSubsts {
user_self_ty: _,
user_self_ty,
substs,
} = user_substs;
let tcx = self.tcx();
@ -245,6 +171,31 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
self.prove_predicate(instantiated_predicate);
}
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));
}
// 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(())
}
}

View File

@ -0,0 +1,21 @@
// compile-pass
// FIXME(#54943) This test targets the scenario where proving the WF requirements requires
// knowing the value of the `_` type present in the user type annotation - unfortunately, figuring
// out the value of that `_` requires type-checking the surrounding code, but that code is dead,
// so our NLL region checker doesn't have access to it. This test should actually fail to compile.
#![feature(nll)]
#![allow(warnings)]
use std::fmt::Debug;
fn foo<T: 'static + Debug>(_: T) { }
fn bar<'a>() {
return;
let _x = foo::<Vec<_>>(Vec::<&'a u32>::new());
//~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477]
}
fn main() {}

View File

@ -1,8 +1,17 @@
// compile-pass
// FIXME(#54943) This test targets the scenario where proving the WF requirements of a user
// type annotation requires checking dead code. This test should actually fail to compile.
#![feature(nll)]
#![allow(warnings)]
fn foo<T: 'static>() { }
fn main<'a>() {
fn boo<'a>() {
return;
let x = foo::<&'a u32>();
//~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477]
}
fn main() {}

View File

@ -1,11 +0,0 @@
error[E0477]: the type `&'a u32` does not fulfill the required lifetime
--> $DIR/issue-54943.rs:6:13
|
LL | let x = foo::<&'a u32>();
| ^^^^^^^^^^^^^^
|
= note: type must satisfy the static lifetime
error: aborting due to previous error
For more information about this error, try `rustc --explain E0477`.

View File

@ -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:9: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 previous error
error: aborting due to 2 previous errors
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`.