Skip to content

Commit c76e557

Browse files
committed
Type check unnanotated constant items with NLL
1 parent 65fe251 commit c76e557

File tree

3 files changed

+128
-62
lines changed

3 files changed

+128
-62
lines changed

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

+49-62
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp;
3535
use rustc::traits::query::{Fallible, NoSolution};
3636
use rustc::traits::{ObligationCause, PredicateObligations};
3737
use rustc::ty::fold::TypeFoldable;
38-
use rustc::ty::subst::{Subst, Substs, UnpackedKind};
38+
use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSubsts};
3939
use rustc::ty::{
4040
self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserType,
4141
CanonicalUserTypeAnnotation, UserTypeAnnotationIndex,
@@ -283,7 +283,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
283283
location.to_locations(),
284284
ConstraintCategory::Boring,
285285
) {
286-
let annotation = self.cx.instantiated_type_annotations[&annotation_index];
286+
let annotation = &self.mir.user_type_annotations[annotation_index];
287287
span_mirbug!(
288288
self,
289289
constant,
@@ -293,6 +293,39 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
293293
terr,
294294
);
295295
}
296+
} else {
297+
match *constant.literal {
298+
ty::LazyConst::Unevaluated(def_id, substs) => {
299+
if let Err(terr) = self.cx.fully_perform_op(
300+
location.to_locations(),
301+
ConstraintCategory::Boring,
302+
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
303+
constant.ty, def_id, UserSubsts { substs, user_self_ty: None },
304+
)),
305+
) {
306+
span_mirbug!(
307+
self,
308+
constant,
309+
"bad constant type {:?} ({:?})",
310+
constant,
311+
terr
312+
);
313+
}
314+
}
315+
ty::LazyConst::Evaluated(lit) => {
316+
if let ty::FnDef(def_id, substs) = lit.ty.sty {
317+
let tcx = self.tcx();
318+
319+
let instantiated_predicates = tcx
320+
.predicates_of(def_id)
321+
.instantiate(tcx, substs);
322+
self.cx.normalize_and_prove_instantiated_predicates(
323+
instantiated_predicates,
324+
location.to_locations(),
325+
);
326+
}
327+
}
328+
}
296329
}
297330
}
298331

@@ -374,8 +407,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
374407
}
375408
}
376409

377-
/// Checks that the constant's `ty` field matches up with what
378-
/// would be expected from its literal.
410+
/// Checks that the constant's `ty` field matches up with what would be
411+
/// expected from its literal. Unevaluated constants and well-formed
412+
/// constraints are checked by `visit_constant`.
379413
fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
380414
debug!(
381415
"sanitize_constant(constant={:?}, location={:?})",
@@ -387,35 +421,6 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
387421
ty::LazyConst::Unevaluated(..) => return,
388422
};
389423

390-
// FIXME(#46702) -- We need some way to get the predicates
391-
// associated with the "pre-evaluated" form of the
392-
// constant. For example, consider that the constant
393-
// may have associated constant projections (`<Foo as
394-
// Trait<'a, 'b>>::SOME_CONST`) that impose
395-
// constraints on `'a` and `'b`. These constraints
396-
// would be lost if we just look at the normalized
397-
// value.
398-
if let ty::FnDef(def_id, substs) = literal.ty.sty {
399-
let tcx = self.tcx();
400-
let type_checker = &mut self.cx;
401-
402-
// FIXME -- For now, use the substitutions from
403-
// `value.ty` rather than `value.val`. The
404-
// renumberer will rewrite them to independent
405-
// sets of regions; in principle, we ought to
406-
// derive the type of the `value.val` from "first
407-
// principles" and equate with value.ty, but as we
408-
// are transitioning to the miri-based system, we
409-
// don't have a handy function for that, so for
410-
// now we just ignore `value.val` regions.
411-
412-
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
413-
type_checker.normalize_and_prove_instantiated_predicates(
414-
instantiated_predicates,
415-
location.to_locations(),
416-
);
417-
}
418-
419424
debug!("sanitize_constant: expected_ty={:?}", literal.ty);
420425

421426
if let Err(terr) = self.cx.eq_types(
@@ -740,15 +745,6 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
740745
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
741746
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
742747
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
743-
/// For each user-type annotation (identified by a UserTypeAnnotationIndex), we create
744-
/// an "instantiated" version at the beginning of type check, which replaces each
745-
/// canonical variable with a fresh inference variable. These instantiated versions are
746-
/// stored either in this field or in user_substs, depending on the kind of user-type
747-
/// annotation. They are then referenced by the code which has the job of enforcing these
748-
/// annotations. Part of the reason for this setup is that it allows us to enforce basic
749-
/// WF criteria on the types even if the code that referenced them is dead
750-
/// code (see #54943).
751-
instantiated_type_annotations: FxHashMap<UserTypeAnnotationIndex, Ty<'tcx>>,
752748
}
753749

754750
struct BorrowCheckContext<'a, 'tcx: 'a> {
@@ -905,23 +901,19 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
905901
borrowck_context,
906902
reported_errors: Default::default(),
907903
universal_region_relations,
908-
instantiated_type_annotations: Default::default(),
909904
};
910-
checker.instantiate_user_type_annotations();
905+
checker.check_user_type_annotations();
911906
checker
912907
}
913908

914-
/// Instantiate canonical types from user type annotations in the `Mir` into the
915-
/// `TypeChecker`. Used when relating user type annotations and when checking if
916-
/// annotations are well-formed.
917-
fn instantiate_user_type_annotations(&mut self) {
909+
/// Equate the inferred type and the annotated type for user type annotations
910+
fn check_user_type_annotations(&mut self) {
918911
debug!(
919-
"instantiate_user_type_annotations: user_type_annotations={:?}",
912+
"check_user_type_annotations: user_type_annotations={:?}",
920913
self.mir.user_type_annotations
921914
);
922-
for annotation_index in self.mir.user_type_annotations.indices() {
923-
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } =
924-
self.mir.user_type_annotations[annotation_index];
915+
for user_annotation in &self.mir.user_type_annotations {
916+
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
925917
let (annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
926918
span, user_ty
927919
);
@@ -937,7 +929,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
937929
) {
938930
span_mirbug!(
939931
self,
940-
self.mir.user_type_annotations[annotation_index],
932+
user_annotation,
941933
"bad user type ({:?} = {:?}): {:?}",
942934
ty,
943935
inferred_ty,
@@ -961,7 +953,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
961953
) {
962954
span_mirbug!(
963955
self,
964-
self.mir.user_type_annotations[annotation_index],
956+
user_annotation,
965957
"bad user type AscribeUserType({:?}, {:?} {:?}): {:?}",
966958
inferred_ty,
967959
def_id,
@@ -971,12 +963,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
971963
}
972964
},
973965
}
974-
self.instantiated_type_annotations.insert(annotation_index, inferred_ty);
975966
}
976-
debug!(
977-
"instantiate_user_type_annotations: instantiated_type_annotations={:?}",
978-
self.instantiated_type_annotations,
979-
);
980967
}
981968

982969
/// Given some operation `op` that manipulates types, proves
@@ -1108,7 +1095,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
11081095
a, v, user_ty, locations,
11091096
);
11101097

1111-
let annotated_type = self.instantiated_type_annotations[&user_ty.base];
1098+
let annotated_type = self.mir.user_type_annotations[user_ty.base].inferred_ty;
11121099
let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
11131100

11141101
let tcx = self.infcx.tcx;
@@ -1293,7 +1280,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
12931280
location.to_locations(),
12941281
ConstraintCategory::Boring,
12951282
) {
1296-
let annotation = self.instantiated_type_annotations[&annotation_index];
1283+
let annotation = &mir.user_type_annotations[annotation_index];
12971284
span_mirbug!(
12981285
self,
12991286
stmt,
@@ -1352,7 +1339,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
13521339
Locations::All(stmt.source_info.span),
13531340
ConstraintCategory::TypeAnnotation,
13541341
) {
1355-
let annotation = self.instantiated_type_annotations[&projection.base];
1342+
let annotation = &mir.user_type_annotations[projection.base];
13561343
span_mirbug!(
13571344
self,
13581345
stmt,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Test that we still check constants are well-formed, even when we there's no
2+
// type annotation to check.
3+
4+
#![feature(nll)]
5+
6+
const FUN: fn(&'static ()) = |_| {};
7+
struct A;
8+
impl A {
9+
const ASSOCIATED_FUN: fn(&'static ()) = |_| {};
10+
}
11+
12+
struct B<'a>(&'a ());
13+
impl B<'static> {
14+
const ALSO_ASSOCIATED_FUN: fn(&'static ()) = |_| {};
15+
}
16+
17+
trait Z: 'static {
18+
const TRAIT_ASSOCIATED_FUN: fn(&'static Self) = |_| ();
19+
}
20+
21+
impl Z for () {}
22+
23+
fn main() {
24+
let x = ();
25+
FUN(&x); //~ ERROR `x` does not live long enough
26+
A::ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough
27+
B::ALSO_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough
28+
<_>::TRAIT_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
error[E0597]: `x` does not live long enough
2+
--> $DIR/constant-in-expr-inherent-2.rs:25:9
3+
|
4+
LL | FUN(&x); //~ ERROR `x` does not live long enough
5+
| ----^^-
6+
| | |
7+
| | borrowed value does not live long enough
8+
| argument requires that `x` is borrowed for `'static`
9+
...
10+
LL | }
11+
| - `x` dropped here while still borrowed
12+
13+
error[E0597]: `x` does not live long enough
14+
--> $DIR/constant-in-expr-inherent-2.rs:26:23
15+
|
16+
LL | A::ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough
17+
| ------------------^^-
18+
| | |
19+
| | borrowed value does not live long enough
20+
| argument requires that `x` is borrowed for `'static`
21+
...
22+
LL | }
23+
| - `x` dropped here while still borrowed
24+
25+
error[E0597]: `x` does not live long enough
26+
--> $DIR/constant-in-expr-inherent-2.rs:27:28
27+
|
28+
LL | B::ALSO_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough
29+
| -----------------------^^-
30+
| | |
31+
| | borrowed value does not live long enough
32+
| argument requires that `x` is borrowed for `'static`
33+
LL | <_>::TRAIT_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough
34+
LL | }
35+
| - `x` dropped here while still borrowed
36+
37+
error[E0597]: `x` does not live long enough
38+
--> $DIR/constant-in-expr-inherent-2.rs:28:31
39+
|
40+
LL | <_>::TRAIT_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough
41+
| --------------------------^^-
42+
| | |
43+
| | borrowed value does not live long enough
44+
| argument requires that `x` is borrowed for `'static`
45+
LL | }
46+
| - `x` dropped here while still borrowed
47+
48+
error: aborting due to 4 previous errors
49+
50+
For more information about this error, try `rustc --explain E0597`.

0 commit comments

Comments
 (0)