From 28fd1b04e56f33fecc843c0a78fc490b03100f43 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 18 Dec 2018 21:27:22 +0100 Subject: [PATCH] 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. --- src/librustc/dep_graph/dep_node.rs | 4 +- src/librustc/traits/query/mod.rs | 4 - .../traits/query/type_op/ascribe_user_type.rs | 58 +--------- src/librustc/ty/query/config.rs | 12 +- src/librustc/ty/query/mod.rs | 11 +- src/librustc/ty/query/plumbing.rs | 1 - src/librustc/ty/wf.rs | 7 +- .../borrow_check/nll/type_check/mod.rs | 53 --------- src/librustc_traits/type_op.rs | 103 +++++------------- src/test/ui/issue-54943-3.rs | 21 ++++ src/test/ui/issue-54943.rs | 11 +- src/test/ui/issue-54943.stderr | 11 -- ...ns-free-region-ordering-caller1.nll.stderr | 19 +--- 13 files changed, 70 insertions(+), 245 deletions(-) create mode 100644 src/test/ui/issue-54943-3.rs delete mode 100644 src/test/ui/issue-54943.stderr diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 1f19e6fc689c1..e5fd0aa3c9cbd 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -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>), diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 3203dc4e8cf82..59f786025b224 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -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>>>; diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs index 993d09d2ed02d..b2f30564de93a 100644 --- a/src/librustc/traits/query/type_op/ascribe_user_type.rs +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -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 { - None - } - - fn perform_query( - tcx: TyCtxt<'_, 'gcx, 'tcx>, - canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible> { - 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 - } -} diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index bed4dfd97ca49..3464464aa229c 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -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() diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index c2f208308b2d1..842aea07614dd 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -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>>, - NoSolution, - >, - /// Do not call this query directly: part of the `Eq` type-op [] fn type_op_eq: TypeOpEq( CanonicalTypeOpEqGoal<'tcx> diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index cdb3cd3ffcb6b..5d23ee0994a06 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -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 | diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index f4a998fb9905a..aacc63c47de61 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -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 } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index d0ca050f0dff7..796a2f79f7554 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -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(&mut self, value: T, location: impl NormalizeLocation) -> T diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 6691a036ac28c..52fcb5b80f4ae 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -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>>, 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(()) } } diff --git a/src/test/ui/issue-54943-3.rs b/src/test/ui/issue-54943-3.rs new file mode 100644 index 0000000000000..185077bd684a8 --- /dev/null +++ b/src/test/ui/issue-54943-3.rs @@ -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) { } + +fn bar<'a>() { + return; + + let _x = foo::>(Vec::<&'a u32>::new()); + //~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477] +} + +fn main() {} diff --git a/src/test/ui/issue-54943.rs b/src/test/ui/issue-54943.rs index d5d0ae1a5e295..c720f62797580 100644 --- a/src/test/ui/issue-54943.rs +++ b/src/test/ui/issue-54943.rs @@ -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() { } -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() {} diff --git a/src/test/ui/issue-54943.stderr b/src/test/ui/issue-54943.stderr deleted file mode 100644 index 62aacee811110..0000000000000 --- a/src/test/ui/issue-54943.stderr +++ /dev/null @@ -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`. diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr index 539343a68294f..92c21fcb4aec5 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr @@ -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 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`.