mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 02:03:53 +00:00
Always check well-formedness.
This commit uses the map introduced by the previous commit to ensure that types are always checked for well-formedness by the NLL type check. Previously, without the map introduced by the previous commit, types would not be checked for well-formedness if the `AscribeUserType` statement that would trigger that check was removed as unreachable code.
This commit is contained in:
parent
24a7a010d1
commit
f2532012dd
@ -62,7 +62,8 @@ use syntax_pos::symbol::InternedString;
|
||||
use traits;
|
||||
use traits::query::{
|
||||
CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
|
||||
CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal,
|
||||
CanonicalTypeOpAscribeUserTypeWellFormedGoal, CanonicalTypeOpEqGoal,
|
||||
CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal,
|
||||
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal,
|
||||
};
|
||||
use ty::{TyCtxt, FnSig, Instance, InstanceDef,
|
||||
@ -650,6 +651,7 @@ 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>),
|
||||
|
@ -28,6 +28,10 @@ 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>>>;
|
||||
|
||||
|
@ -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};
|
||||
use ty::{self, ParamEnvAnd, Ty, TyCtxt, UserTypeAnnotation};
|
||||
use ty::subst::UserSubsts;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
@ -22,7 +22,7 @@ impl<'tcx> AscribeUserType<'tcx> {
|
||||
user_substs: UserSubsts<'tcx>,
|
||||
projs: &'tcx ty::List<ProjectionKind<'tcx>>,
|
||||
) -> Self {
|
||||
AscribeUserType { mir_ty, variance, def_id, user_substs, projs }
|
||||
Self { mir_ty, variance, def_id, user_substs, projs }
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,3 +68,59 @@ 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
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ use mir::interpret::GlobalId;
|
||||
use traits;
|
||||
use traits::query::{
|
||||
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
|
||||
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
|
||||
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpAscribeUserTypeWellFormedGoal,
|
||||
CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
|
||||
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
|
||||
};
|
||||
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||
@ -124,6 +125,15 @@ 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()
|
||||
|
@ -26,7 +26,8 @@ use session::config::OutputFilenames;
|
||||
use traits::{self, Vtable};
|
||||
use traits::query::{
|
||||
CanonicalPredicateGoal, CanonicalProjectionGoal,
|
||||
CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal,
|
||||
CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
|
||||
CanonicalTypeOpAscribeUserTypeWellFormedGoal, CanonicalTypeOpEqGoal,
|
||||
CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
|
||||
CanonicalTypeOpNormalizeGoal, NoSolution,
|
||||
};
|
||||
@ -609,6 +610,14 @@ 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>
|
||||
|
@ -1208,6 +1208,7 @@ 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 |
|
||||
|
@ -916,6 +916,28 @@ 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];
|
||||
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`
|
||||
@ -2389,6 +2411,8 @@ 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
|
||||
|
@ -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;
|
||||
use rustc::traits::query::type_op::ascribe_user_type::{AscribeUserType, AscribeUserTypeWellFormed};
|
||||
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,6 +17,7 @@ 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;
|
||||
@ -26,6 +27,7 @@ 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,
|
||||
@ -48,7 +50,7 @@ fn type_op_ascribe_user_type<'tcx>(
|
||||
) = key.into_parts();
|
||||
|
||||
debug!(
|
||||
"type_op_user_type_relation: mir_ty={:?} variance={:?} def_id={:?} \
|
||||
"type_op_ascribe_user_type: mir_ty={:?} variance={:?} def_id={:?} \
|
||||
user_substs={:?} projs={:?}",
|
||||
mir_ty, variance, def_id, user_substs, projs
|
||||
);
|
||||
@ -60,6 +62,28 @@ 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>,
|
||||
@ -109,6 +133,56 @@ 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>,
|
||||
@ -118,7 +192,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();
|
||||
@ -158,19 +232,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
|
||||
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`
|
||||
@ -184,19 +245,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,21 @@ LL | let z: &'a & usize = &(&y);
|
||||
LL | }
|
||||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error: aborting due to previous error
|
||||
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
|
||||
| |
|
||||
| assignment requires that `y` is borrowed for `'a`
|
||||
...
|
||||
LL | }
|
||||
| - `y` dropped here while still borrowed
|
||||
|
||||
For more information about this error, try `rustc --explain E0716`.
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors occurred: E0597, E0716.
|
||||
For more information about an error, try `rustc --explain E0597`.
|
||||
|
@ -31,9 +31,7 @@ fn with_assoc<'a,'b>() {
|
||||
// outlive 'a. In this case, that means TheType<'b>::TheAssocType,
|
||||
// which is &'b (), must outlive 'a.
|
||||
|
||||
// FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
|
||||
// `_x` is changed to `_`
|
||||
let _x: &'a WithAssoc<TheType<'b>> = loop { };
|
||||
let _: &'a WithAssoc<TheType<'b>> = loop { };
|
||||
//~^ ERROR reference has a longer lifetime
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
|
||||
--> $DIR/regions-outlives-projection-container-wc.rs:36:13
|
||||
--> $DIR/regions-outlives-projection-container-wc.rs:34:12
|
||||
|
|
||||
LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the pointer is valid for the lifetime 'a as defined on the function body at 28:15
|
||||
--> $DIR/regions-outlives-projection-container-wc.rs:28:15
|
||||
|
Loading…
Reference in New Issue
Block a user