Skip to content

Commit f253201

Browse files
committed
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.
1 parent 24a7a01 commit f253201

File tree

11 files changed

+209
-42
lines changed

11 files changed

+209
-42
lines changed

src/librustc/dep_graph/dep_node.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ use syntax_pos::symbol::InternedString;
6262
use traits;
6363
use traits::query::{
6464
CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
65-
CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal,
65+
CanonicalTypeOpAscribeUserTypeWellFormedGoal, CanonicalTypeOpEqGoal,
66+
CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal,
6667
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal,
6768
};
6869
use ty::{TyCtxt, FnSig, Instance, InstanceDef,
@@ -650,6 +651,7 @@ define_dep_nodes!( <'tcx>
650651
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
651652
[] EvaluateGoal(traits::ChalkCanonicalGoal<'tcx>),
652653
[] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>),
654+
[] TypeOpAscribeUserTypeWellFormed(CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx>),
653655
[] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>),
654656
[] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>),
655657
[] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>),

src/librustc/traits/query/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ pub type CanonicalPredicateGoal<'tcx> =
2828
pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> =
2929
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>;
3030

31+
pub type CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx> =
32+
Canonical<'tcx, ty::ParamEnvAnd<'tcx,
33+
type_op::ascribe_user_type::AscribeUserTypeWellFormed<'tcx>>>;
34+
3135
pub type CanonicalTypeOpEqGoal<'tcx> =
3236
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>;
3337

src/librustc/traits/query/type_op/ascribe_user_type.rs

+58-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, Que
22
use traits::query::Fallible;
33
use hir::def_id::DefId;
44
use mir::ProjectionKind;
5-
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
5+
use ty::{self, ParamEnvAnd, Ty, TyCtxt, UserTypeAnnotation};
66
use ty::subst::UserSubsts;
77

88
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -22,7 +22,7 @@ impl<'tcx> AscribeUserType<'tcx> {
2222
user_substs: UserSubsts<'tcx>,
2323
projs: &'tcx ty::List<ProjectionKind<'tcx>>,
2424
) -> Self {
25-
AscribeUserType { mir_ty, variance, def_id, user_substs, projs }
25+
Self { mir_ty, variance, def_id, user_substs, projs }
2626
}
2727
}
2828

@@ -68,3 +68,59 @@ impl_stable_hash_for! {
6868
mir_ty, variance, def_id, user_substs, projs
6969
}
7070
}
71+
72+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
73+
pub struct AscribeUserTypeWellFormed<'tcx> {
74+
pub user_type_annotation: UserTypeAnnotation<'tcx>,
75+
}
76+
77+
impl<'tcx> AscribeUserTypeWellFormed<'tcx> {
78+
pub fn new(
79+
user_type_annotation: UserTypeAnnotation<'tcx>,
80+
) -> Self {
81+
Self { user_type_annotation, }
82+
}
83+
}
84+
85+
impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserTypeWellFormed<'tcx> {
86+
type QueryResponse = ();
87+
88+
fn try_fast_path(
89+
_tcx: TyCtxt<'_, 'gcx, 'tcx>,
90+
_key: &ParamEnvAnd<'tcx, Self>,
91+
) -> Option<Self::QueryResponse> {
92+
None
93+
}
94+
95+
fn perform_query(
96+
tcx: TyCtxt<'_, 'gcx, 'tcx>,
97+
canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
98+
) -> Fallible<CanonicalizedQueryResponse<'gcx, ()>> {
99+
tcx.type_op_ascribe_user_type_well_formed(canonicalized)
100+
}
101+
102+
fn shrink_to_tcx_lifetime(
103+
v: &'a CanonicalizedQueryResponse<'gcx, ()>,
104+
) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> {
105+
v
106+
}
107+
}
108+
109+
BraceStructTypeFoldableImpl! {
110+
impl<'tcx> TypeFoldable<'tcx> for AscribeUserTypeWellFormed<'tcx> {
111+
user_type_annotation
112+
}
113+
}
114+
115+
BraceStructLiftImpl! {
116+
impl<'a, 'tcx> Lift<'tcx> for AscribeUserTypeWellFormed<'a> {
117+
type Lifted = AscribeUserTypeWellFormed<'tcx>;
118+
user_type_annotation
119+
}
120+
}
121+
122+
impl_stable_hash_for! {
123+
struct AscribeUserTypeWellFormed<'tcx> {
124+
user_type_annotation
125+
}
126+
}

src/librustc/ty/query/config.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use mir::interpret::GlobalId;
55
use traits;
66
use traits::query::{
77
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
8-
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
8+
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpAscribeUserTypeWellFormedGoal,
9+
CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
910
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
1011
};
1112
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
@@ -124,6 +125,15 @@ impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type<'tcx> {
124125
}
125126
}
126127

128+
impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type_well_formed<'tcx> {
129+
fn describe(
130+
_tcx: TyCtxt<'_, '_, '_>,
131+
goal: CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx>,
132+
) -> Cow<'static, str> {
133+
format!("evaluating `type_op_ascribe_user_type_well_formed` `{:?}`", goal).into()
134+
}
135+
}
136+
127137
impl<'tcx> QueryDescription<'tcx> for queries::type_op_eq<'tcx> {
128138
fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTypeOpEqGoal<'tcx>) -> Cow<'static, str> {
129139
format!("evaluating `type_op_eq` `{:?}`", goal).into()

src/librustc/ty/query/mod.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ use session::config::OutputFilenames;
2626
use traits::{self, Vtable};
2727
use traits::query::{
2828
CanonicalPredicateGoal, CanonicalProjectionGoal,
29-
CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal,
29+
CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
30+
CanonicalTypeOpAscribeUserTypeWellFormedGoal, CanonicalTypeOpEqGoal,
3031
CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
3132
CanonicalTypeOpNormalizeGoal, NoSolution,
3233
};
@@ -609,6 +610,14 @@ define_queries! { <'tcx>
609610
NoSolution,
610611
>,
611612

613+
/// Do not call this query directly: part of the `Eq` type-op
614+
[] fn type_op_ascribe_user_type_well_formed: TypeOpAscribeUserTypeWellFormed(
615+
CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx>
616+
) -> Result<
617+
Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>,
618+
NoSolution,
619+
>,
620+
612621
/// Do not call this query directly: part of the `Eq` type-op
613622
[] fn type_op_eq: TypeOpEq(
614623
CanonicalTypeOpEqGoal<'tcx>

src/librustc/ty/query/plumbing.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
12081208
DepKind::EvaluateObligation |
12091209
DepKind::EvaluateGoal |
12101210
DepKind::TypeOpAscribeUserType |
1211+
DepKind::TypeOpAscribeUserTypeWellFormed |
12111212
DepKind::TypeOpEq |
12121213
DepKind::TypeOpSubtype |
12131214
DepKind::TypeOpProvePredicate |

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+24
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,28 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
916916
);
917917
}
918918

919+
/// Check that user type annotations are well formed.
920+
fn check_user_type_annotations_are_well_formed(&mut self) {
921+
for index in self.mir.user_type_annotations.indices() {
922+
let (span, _) = &self.mir.user_type_annotations[index];
923+
let type_annotation = self.instantiated_type_annotations[&index];
924+
if let Err(terr) = self.fully_perform_op(
925+
Locations::All(*span),
926+
ConstraintCategory::Assignment,
927+
self.param_env.and(type_op::ascribe_user_type::AscribeUserTypeWellFormed::new(
928+
type_annotation,
929+
)),
930+
) {
931+
span_mirbug!(
932+
self,
933+
type_annotation,
934+
"bad user type annotation: {:?}",
935+
terr,
936+
);
937+
}
938+
}
939+
}
940+
919941
/// Given some operation `op` that manipulates types, proves
920942
/// predicates, or otherwise uses the inference context, executes
921943
/// `op` and then executes all the further obligations that `op`
@@ -2389,6 +2411,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
23892411
self.check_terminator(mir, block_data.terminator(), location);
23902412
self.check_iscleanup(mir, block_data);
23912413
}
2414+
2415+
self.check_user_type_annotations_are_well_formed();
23922416
}
23932417

23942418
fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T

src/librustc_traits/type_op.rs

+77-29
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc::infer::InferCtxt;
44
use rustc::hir::def_id::DefId;
55
use rustc::mir::ProjectionKind;
66
use rustc::mir::tcx::PlaceTy;
7-
use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType;
7+
use rustc::traits::query::type_op::ascribe_user_type::{AscribeUserType, AscribeUserTypeWellFormed};
88
use rustc::traits::query::type_op::eq::Eq;
99
use rustc::traits::query::type_op::normalize::Normalize;
1010
use rustc::traits::query::type_op::prove_predicate::ProvePredicate;
@@ -17,6 +17,7 @@ use rustc::ty::query::Providers;
1717
use rustc::ty::subst::{Kind, Subst, UserSubsts, UserSelfTy};
1818
use rustc::ty::{
1919
FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance,
20+
UserTypeAnnotation,
2021
};
2122
use rustc_data_structures::sync::Lrc;
2223
use std::fmt;
@@ -26,6 +27,7 @@ use syntax_pos::DUMMY_SP;
2627
crate fn provide(p: &mut Providers) {
2728
*p = Providers {
2829
type_op_ascribe_user_type,
30+
type_op_ascribe_user_type_well_formed,
2931
type_op_eq,
3032
type_op_prove_predicate,
3133
type_op_subtype,
@@ -48,7 +50,7 @@ fn type_op_ascribe_user_type<'tcx>(
4850
) = key.into_parts();
4951

5052
debug!(
51-
"type_op_user_type_relation: mir_ty={:?} variance={:?} def_id={:?} \
53+
"type_op_ascribe_user_type: mir_ty={:?} variance={:?} def_id={:?} \
5254
user_substs={:?} projs={:?}",
5355
mir_ty, variance, def_id, user_substs, projs
5456
);
@@ -60,6 +62,28 @@ fn type_op_ascribe_user_type<'tcx>(
6062
})
6163
}
6264

65+
fn type_op_ascribe_user_type_well_formed<'tcx>(
66+
tcx: TyCtxt<'_, 'tcx, 'tcx>,
67+
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserTypeWellFormed<'tcx>>>,
68+
) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>, NoSolution> {
69+
tcx.infer_ctxt()
70+
.enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
71+
let (
72+
param_env, AscribeUserTypeWellFormed { user_type_annotation }
73+
) = key.into_parts();
74+
75+
debug!(
76+
"type_op_ascribe_user_type_well_formed: user_type_annotation={:?}",
77+
user_type_annotation,
78+
);
79+
80+
let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
81+
cx.well_formed(user_type_annotation)?;
82+
83+
Ok(())
84+
})
85+
}
86+
6387
struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> {
6488
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
6589
param_env: ParamEnv<'tcx>,
@@ -109,6 +133,56 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
109133
value.subst(self.tcx(), substs)
110134
}
111135

136+
fn well_formed(
137+
&mut self,
138+
type_annotation: UserTypeAnnotation<'tcx>
139+
) -> Result<(), NoSolution> {
140+
match type_annotation {
141+
UserTypeAnnotation::Ty(ty) => {
142+
self.prove_predicate(Predicate::WellFormed(ty));
143+
Ok(())
144+
},
145+
UserTypeAnnotation::TypeOf(did, user_substs) => {
146+
let UserSubsts {
147+
user_self_ty,
148+
substs,
149+
} = user_substs;
150+
151+
let ty = self.tcx().type_of(did);
152+
let ty = self.subst(ty, substs);
153+
debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
154+
let ty = self.normalize(ty);
155+
156+
if let Some(UserSelfTy {
157+
impl_def_id,
158+
self_ty,
159+
}) = user_self_ty {
160+
let impl_self_ty = self.tcx().type_of(impl_def_id);
161+
let impl_self_ty = self.subst(impl_self_ty, &substs);
162+
let impl_self_ty = self.normalize(impl_self_ty);
163+
164+
self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
165+
166+
self.prove_predicate(Predicate::WellFormed(impl_self_ty));
167+
}
168+
169+
// In addition to proving the predicates, we have to
170+
// prove that `ty` is well-formed -- this is because
171+
// the WF of `ty` is predicated on the substs being
172+
// well-formed, and we haven't proven *that*. We don't
173+
// want to prove the WF of types from `substs` directly because they
174+
// haven't been normalized.
175+
//
176+
// FIXME(nmatsakis): Well, perhaps we should normalize
177+
// them? This would only be relevant if some input
178+
// type were ill-formed but did not appear in `ty`,
179+
// which...could happen with normalization...
180+
self.prove_predicate(Predicate::WellFormed(ty));
181+
Ok(())
182+
},
183+
}
184+
}
185+
112186
fn relate_mir_and_user_ty(
113187
&mut self,
114188
mir_ty: Ty<'tcx>,
@@ -118,7 +192,7 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
118192
projs: &[ProjectionKind<'tcx>],
119193
) -> Result<(), NoSolution> {
120194
let UserSubsts {
121-
user_self_ty,
195+
user_self_ty: _,
122196
substs,
123197
} = user_substs;
124198
let tcx = self.tcx();
@@ -158,19 +232,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
158232
self.relate(mir_ty, variance, ty)?;
159233
}
160234

161-
if let Some(UserSelfTy {
162-
impl_def_id,
163-
self_ty,
164-
}) = user_self_ty {
165-
let impl_self_ty = self.tcx().type_of(impl_def_id);
166-
let impl_self_ty = self.subst(impl_self_ty, &substs);
167-
let impl_self_ty = self.normalize(impl_self_ty);
168-
169-
self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
170-
171-
self.prove_predicate(Predicate::WellFormed(impl_self_ty));
172-
}
173-
174235
// Prove the predicates coming along with `def_id`.
175236
//
176237
// Also, normalize the `instantiated_predicates`
@@ -184,19 +245,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
184245
self.prove_predicate(instantiated_predicate);
185246
}
186247

187-
// In addition to proving the predicates, we have to
188-
// prove that `ty` is well-formed -- this is because
189-
// the WF of `ty` is predicated on the substs being
190-
// well-formed, and we haven't proven *that*. We don't
191-
// want to prove the WF of types from `substs` directly because they
192-
// haven't been normalized.
193-
//
194-
// FIXME(nmatsakis): Well, perhaps we should normalize
195-
// them? This would only be relevant if some input
196-
// type were ill-formed but did not appear in `ty`,
197-
// which...could happen with normalization...
198-
self.prove_predicate(Predicate::WellFormed(ty));
199-
200248
Ok(())
201249
}
202250
}

src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr

+17-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ LL | let z: &'a & usize = &(&y);
1212
LL | }
1313
| - temporary value is freed at the end of this statement
1414

15-
error: aborting due to previous error
15+
error[E0597]: `y` does not live long enough
16+
--> $DIR/regions-free-region-ordering-caller1.rs:9:27
17+
|
18+
LL | fn call1<'a>(x: &'a usize) {
19+
| -- lifetime `'a` defined here
20+
...
21+
LL | let z: &'a & usize = &(&y);
22+
| ----------- ^^^^ borrowed value does not live long enough
23+
| |
24+
| assignment requires that `y` is borrowed for `'a`
25+
...
26+
LL | }
27+
| - `y` dropped here while still borrowed
28+
29+
error: aborting due to 2 previous errors
1630

17-
For more information about this error, try `rustc --explain E0716`.
31+
Some errors occurred: E0597, E0716.
32+
For more information about an error, try `rustc --explain E0597`.

0 commit comments

Comments
 (0)