From bd93741bd34071faa74dc3c7de862ce289378cba Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 12:32:00 -0400 Subject: [PATCH 01/21] remove outdated assertion This dates from the days before we instantiated user types with inference variables. --- src/librustc/infer/canonical/query_response.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index c29a75c34cf9d..b9edc9f51eaa8 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -19,7 +19,7 @@ use infer::canonical::substitute::substitute_value; use infer::canonical::{ - Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, + Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues, QueryRegionConstraint, QueryResponse, }; use infer::region_constraints::{Constraint, RegionConstraintData}; @@ -262,13 +262,6 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { where R: Debug + TypeFoldable<'tcx>, { - // In an NLL query, there should be no type variables in the - // query, only region variables. - debug_assert!(query_response.variables.iter().all(|v| match v.kind { - CanonicalVarKind::Ty(_) => false, - CanonicalVarKind::Region => true, - })); - let result_subst = self.query_response_substitution_guess(cause, original_values, query_response); From ebdfda64f893f30675320e15349b2948b2194ea9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 09:58:52 -0400 Subject: [PATCH 02/21] convert `FnDef` to `TypeOf`, which is more general --- src/librustc/ich/impls_mir.rs | 2 +- src/librustc/mir/mod.rs | 11 +++++++++-- .../borrow_check/nll/type_check/relate_tys.rs | 6 ++++-- src/librustc_mir/hair/cx/expr.rs | 2 +- src/librustc_mir/hair/util.rs | 2 +- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index b660187945cdb..4c3e084af4d7d 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -597,7 +597,7 @@ impl<'a, 'gcx> HashStable> for mir::UserTypeAnnotation< mir::UserTypeAnnotation::Ty(ref ty) => { ty.hash_stable(hcx, hasher); } - mir::UserTypeAnnotation::FnDef(ref def_id, ref substs) => { + mir::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9a0623ca53938..8dcb14485f572 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2425,14 +2425,21 @@ pub struct Constant<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum UserTypeAnnotation<'tcx> { Ty(CanonicalTy<'tcx>), - FnDef(DefId, CanonicalUserSubsts<'tcx>), + + /// The canonical type is the result of `type_of(def_id)` with the + /// given substitutions applied. + TypeOf(DefId, CanonicalUserSubsts<'tcx>), + + /// The canonical type is the given ADT with the given + /// substitutions applied (in this case, `user_self_ty` had better + /// be `None`). AdtDef(&'tcx AdtDef, CanonicalUserSubsts<'tcx>), } EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> { (UserTypeAnnotation::Ty)(ty), - (UserTypeAnnotation::FnDef)(def, substs), + (UserTypeAnnotation::TypeOf)(def, substs), (UserTypeAnnotation::AdtDef)(def, substs), } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 72120eb18413b..2ccfe6a73a287 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -90,7 +90,7 @@ pub(super) fn relate_type_and_user_type<'tcx>( type_relating.relate(&ty, &a)?; Ok(ty) } - UserTypeAnnotation::FnDef(def_id, canonical_substs) => { + UserTypeAnnotation::TypeOf(def_id, canonical_substs) => { let ( UserSubsts { substs, @@ -98,7 +98,9 @@ pub(super) fn relate_type_and_user_type<'tcx>( }, _, ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - let ty = infcx.tcx.mk_fn_def(def_id, substs); + + let ty = infcx.tcx.type_of(def_id); + let ty = ty.subst(infcx.tcx, substs); type_relating.relate(&ty, &a)?; diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 56a29f29d685f..621e0d1b10cf5 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -772,7 +772,7 @@ fn user_substs_applied_to_def( Def::Method(_) | Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) => - Some(UserTypeAnnotation::FnDef(def.def_id(), cx.tables().user_substs(hir_id)?)), + Some(UserTypeAnnotation::TypeOf(def.def_id(), cx.tables().user_substs(hir_id)?)), Def::Const(_def_id) | Def::AssociatedConst(_def_id) => diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs index 71cbac6b7c88e..fa5f2be62b80e 100644 --- a/src/librustc_mir/hair/util.rs +++ b/src/librustc_mir/hair/util.rs @@ -36,7 +36,7 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { let user_substs = self.tables().user_substs(hir_id)?; match &self.tables().node_id_to_type(hir_id).sty { ty::Adt(adt_def, _) => Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)), - ty::FnDef(def_id, _) => Some(UserTypeAnnotation::FnDef(*def_id, user_substs)), + ty::FnDef(def_id, _) => Some(UserTypeAnnotation::TypeOf(*def_id, user_substs)), sty => bug!( "sty: {:?} should not have user-substs {:?} recorded ", sty, From e94959b9369d611aed86a4c179406a96e983278a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 10:14:29 -0400 Subject: [PATCH 03/21] propagate user-type annotation for constants in expressions --- src/librustc_mir/hair/cx/expr.rs | 27 ++++++++++--------- .../constant-in-expr-inherent-1.rs | 15 +++++++++++ .../constant-in-expr-inherent-1.stderr | 10 +++++++ .../constant-in-expr-trait-item-1.rs | 16 +++++++++++ .../constant-in-expr-trait-item-1.stderr | 10 +++++++ .../constant-in-expr-trait-item-2.rs | 16 +++++++++++ .../constant-in-expr-trait-item-2.stderr | 10 +++++++ 7 files changed, 91 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs create mode 100644 src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr create mode 100644 src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs create mode 100644 src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr create mode 100644 src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs create mode 100644 src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 621e0d1b10cf5..bb1e940d4a9ed 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -771,13 +771,11 @@ fn user_substs_applied_to_def( Def::Fn(_) | Def::Method(_) | Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) => + Def::VariantCtor(_, CtorKind::Fn) | + Def::Const(_) | + Def::AssociatedConst(_) => Some(UserTypeAnnotation::TypeOf(def.def_id(), cx.tables().user_substs(hir_id)?)), - Def::Const(_def_id) | - Def::AssociatedConst(_def_id) => - bug!("unimplemented"), - // A unit struct/variant which is used as a value (e.g., // `None`). This has the type of the enum/struct that defines // this variant -- but with the substitutions given by the @@ -889,14 +887,17 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }, Def::Const(def_id) | - Def::AssociatedConst(def_id) => ExprKind::Literal { - literal: ty::Const::unevaluated( - cx.tcx, - def_id, - substs, - cx.tables().node_id_to_type(expr.hir_id), - ), - user_ty: None, // FIXME(#47184) -- user given type annot on constants + Def::AssociatedConst(def_id) => { + let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); + ExprKind::Literal { + literal: ty::Const::unevaluated( + cx.tcx, + def_id, + substs, + cx.tables().node_id_to_type(expr.hir_id), + ), + user_ty, + } }, Def::StructCtor(def_id, CtorKind::Const) | diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs new file mode 100644 index 0000000000000..058ebaee9e512 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs @@ -0,0 +1,15 @@ +#![feature(nll)] + +struct Foo<'a> { x: &'a u32 } + +impl<'a> Foo<'a> { + const C: &'a u32 = &22; +} + +fn foo<'a>(_: &'a u32) -> &'static u32 { + >::C //~ ERROR +} + +fn main() { +} + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr new file mode 100644 index 0000000000000..94fbe01772412 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -0,0 +1,10 @@ +error: unsatisfied lifetime constraints + --> $DIR/constant-in-expr-inherent-1.rs:10:5 + | +LL | fn foo<'a>(_: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | >::C //~ ERROR + | ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs new file mode 100644 index 0000000000000..daa0d7bc24140 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs @@ -0,0 +1,16 @@ +#![feature(nll)] + +trait Foo<'a> { + const C: &'a u32; +} + +impl<'a, T> Foo<'a> for T { + const C: &'a u32 = &22; +} + +fn foo<'a>(_: &'a u32) -> &'static u32 { + <() as Foo<'a>>::C //~ ERROR +} + +fn main() { +} diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr new file mode 100644 index 0000000000000..fee9abc1ed83a --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr @@ -0,0 +1,10 @@ +error: unsatisfied lifetime constraints + --> $DIR/constant-in-expr-trait-item-1.rs:12:5 + | +LL | fn foo<'a>(_: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | <() as Foo<'a>>::C //~ ERROR + | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs new file mode 100644 index 0000000000000..cd66e7a49cb83 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs @@ -0,0 +1,16 @@ +#![feature(nll)] + +trait Foo<'a> { + const C: &'a u32; +} + +impl<'a, T> Foo<'a> for T { + const C: &'a u32 = &22; +} + +fn foo<'a, T: Foo<'a>>() -> &'static u32 { + >::C //~ ERROR +} + +fn main() { +} diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr new file mode 100644 index 0000000000000..047aad9831923 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr @@ -0,0 +1,10 @@ +error: unsatisfied lifetime constraints + --> $DIR/constant-in-expr-trait-item-2.rs:12:5 + | +LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { + | -- lifetime `'a` defined here +LL | >::C //~ ERROR + | ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + From a0a3b4c0585129405c09a9be46a1a3f8d3411b3b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 11:48:41 -0400 Subject: [PATCH 04/21] replace `UserTypeAnnotation::AdtDef` with `TypeOf` --- src/librustc/ich/impls_mir.rs | 4 ---- src/librustc/mir/mod.rs | 6 ------ .../borrow_check/nll/type_check/relate_tys.rs | 16 ---------------- src/librustc_mir/hair/cx/expr.rs | 2 +- src/librustc_mir/hair/util.rs | 4 ++-- 5 files changed, 3 insertions(+), 29 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 4c3e084af4d7d..a82a8ca6bdff0 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -601,10 +601,6 @@ impl<'a, 'gcx> HashStable> for mir::UserTypeAnnotation< def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } - mir::UserTypeAnnotation::AdtDef(ref def_id, ref substs) => { - def_id.hash_stable(hcx, hasher); - substs.hash_stable(hcx, hasher); - } } } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 8dcb14485f572..34fc81a495e24 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2429,18 +2429,12 @@ pub enum UserTypeAnnotation<'tcx> { /// The canonical type is the result of `type_of(def_id)` with the /// given substitutions applied. TypeOf(DefId, CanonicalUserSubsts<'tcx>), - - /// The canonical type is the given ADT with the given - /// substitutions applied (in this case, `user_self_ty` had better - /// be `None`). - AdtDef(&'tcx AdtDef, CanonicalUserSubsts<'tcx>), } EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> { (UserTypeAnnotation::Ty)(ty), (UserTypeAnnotation::TypeOf)(def, substs), - (UserTypeAnnotation::AdtDef)(def, substs), } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 2ccfe6a73a287..665ed24ac3d26 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -132,22 +132,6 @@ pub(super) fn relate_type_and_user_type<'tcx>( Ok(ty) } - UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => { - let ( - UserSubsts { - substs, - user_self_ty, - }, - _, - ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - - // We don't extract adt-defs with a self-type. - assert!(user_self_ty.is_none()); - - let ty = infcx.tcx.mk_adt(adt_def, substs); - type_relating.relate(&ty, &a)?; - Ok(ty) - } } } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index bb1e940d4a9ed..04dd1aa3c8880 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -295,7 +295,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let substs = cx.tables().node_substs(fun.hir_id); let user_ty = cx.tables().user_substs(fun.hir_id) - .map(|user_substs| UserTypeAnnotation::AdtDef(adt_def, user_substs)); + .map(|user_substs| UserTypeAnnotation::TypeOf(adt_def.did, user_substs)); let field_refs = args.iter() .enumerate() diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs index fa5f2be62b80e..f81a0fa5dfadb 100644 --- a/src/librustc_mir/hair/util.rs +++ b/src/librustc_mir/hair/util.rs @@ -23,7 +23,7 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { adt_def: &'tcx AdtDef, ) -> Option> { let user_substs = self.tables().user_substs(hir_id)?; - Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)) + Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs)) } /// Looks up the type associated with this hir-id and applies the @@ -35,7 +35,7 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { ) -> Option> { let user_substs = self.tables().user_substs(hir_id)?; match &self.tables().node_id_to_type(hir_id).sty { - ty::Adt(adt_def, _) => Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)), + ty::Adt(adt_def, _) => Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs)), ty::FnDef(def_id, _) => Some(UserTypeAnnotation::TypeOf(*def_id, user_substs)), sty => bug!( "sty: {:?} should not have user-substs {:?} recorded ", From e7ab33e7a61ff046f1736f1b027c16d9494e20b8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 12:15:56 -0400 Subject: [PATCH 05/21] type_check/mod.rs: rustfmt --- .../borrow_check/nll/type_check/mod.rs | 69 ++++++++----------- 1 file changed, 29 insertions(+), 40 deletions(-) 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 c5758cde9494d..11ea46fdef238 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -753,10 +753,8 @@ crate struct MirTypeckRegionConstraints<'tcx> { crate outlives_constraints: ConstraintSet, - crate closure_bounds_mapping: FxHashMap< - Location, - FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>, - >, + crate closure_bounds_mapping: + FxHashMap>, crate type_tests: Vec>, } @@ -866,7 +864,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, locations: Locations, category: ConstraintCategory, - op: impl type_op::TypeOp<'gcx, 'tcx, Output=R>, + op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>, ) -> Fallible { let (r, opt_data) = op.fully_perform(self.infcx)?; @@ -979,11 +977,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { category, self.borrowck_context.as_mut().map(|x| &mut **x), )?; - self.prove_predicate( - ty::Predicate::WellFormed(ty), - locations, - category, - ); + self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category); Ok(()) } @@ -1115,9 +1109,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let place_ty = place.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); if let Err(terr) = - self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) - { - span_mirbug!( + self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) + { + span_mirbug!( self, stmt, "bad assignment ({:?} = {:?}): {:?}", @@ -1125,7 +1119,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { rv_ty, terr ); - } + } if let Some(user_ty) = self.rvalue_user_ty(rv) { if let Err(terr) = self.relate_type_and_user_type( @@ -1245,9 +1239,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let locations = term_location.to_locations(); if let Err(terr) = - self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment) - { - span_mirbug!( + self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment) + { + span_mirbug!( self, term, "bad DropAndReplace ({:?} = {:?}): {:?}", @@ -1255,7 +1249,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { rv_ty, terr ); - } + } } TerminatorKind::SwitchInt { ref discr, @@ -1399,9 +1393,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let locations = term_location.to_locations(); if let Err(terr) = - self.sub_types_or_anon(sig.output(), dest_ty, locations, category) - { - span_mirbug!( + self.sub_types_or_anon(sig.output(), dest_ty, locations, category) + { + span_mirbug!( self, term, "call dest mismatch ({:?} <- {:?}): {:?}", @@ -1409,7 +1403,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { sig.output(), terr ); - } + } // When `#![feature(unsized_locals)]` is not enabled, // this check is done at `check_local`. @@ -2050,7 +2044,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { aggregate_kind, location ); - let instantiated_predicates = match aggregate_kind { + let instantiated_predicates = match aggregate_kind { AggregateKind::Adt(def, _, substs, _, _) => { tcx.predicates_of(def.did).instantiate(tcx, substs) } @@ -2096,15 +2090,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { substs: &'tcx Substs<'tcx>, location: Location, ) -> ty::InstantiatedPredicates<'tcx> { - if let Some(closure_region_requirements) = - tcx.mir_borrowck(def_id).closure_requirements - { - let closure_constraints = closure_region_requirements.apply_requirements( - tcx, - location, - def_id, - substs, - ); + if let Some(closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements { + let closure_constraints = + closure_region_requirements.apply_requirements(tcx, location, def_id, substs); if let Some(ref mut borrowck_context) = self.borrowck_context { let bounds_mapping = closure_constraints @@ -2113,10 +2101,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { .filter_map(|(idx, constraint)| { let ty::OutlivesPredicate(k1, r2) = constraint.no_late_bound_regions().unwrap_or_else(|| { - bug!( - "query_constraint {:?} contained bound regions", - constraint, - ); + bug!("query_constraint {:?} contained bound regions", constraint,); }); match k1.unpack() { @@ -2124,8 +2109,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // constraint is r1: r2 let r1_vid = borrowck_context.universal_regions.to_region_vid(r1); let r2_vid = borrowck_context.universal_regions.to_region_vid(r2); - let outlives_requirements = &closure_region_requirements - .outlives_requirements[idx]; + let outlives_requirements = + &closure_region_requirements.outlives_requirements[idx]; Some(( (r1_vid, r2_vid), ( @@ -2139,10 +2124,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }) .collect(); - let existing = borrowck_context.constraints + let existing = borrowck_context + .constraints .closure_bounds_mapping .insert(location, bounds_mapping); - assert!(existing.is_none(), "Multiple closures at the same location."); + assert!( + existing.is_none(), + "Multiple closures at the same location." + ); } self.push_region_constraints( From f99300fcbdfec2908aeb93c823fc37f92a4d2d30 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 14:55:42 -0400 Subject: [PATCH 06/21] pull `relate_type_and_user_type` code into `type_check` module It's really layered atop the core "relate-types" code --- .../borrow_check/nll/type_check/mod.rs | 111 ++++++++++++---- .../borrow_check/nll/type_check/relate_tys.rs | 120 ++---------------- 2 files changed, 99 insertions(+), 132 deletions(-) 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 11ea46fdef238..823a249760f5b 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -42,7 +42,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp; use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{Subst, Substs, UnpackedKind}; +use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSubsts, UserSelfTy}; use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; use std::rc::Rc; use std::{fmt, iter}; @@ -901,23 +901,37 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn sub_types( + /// Convenient wrapper around `relate_tys::relate_types` -- see + /// that fn for docs. + fn relate_types( &mut self, - sub: Ty<'tcx>, - sup: Ty<'tcx>, + a: Ty<'tcx>, + v: ty::Variance, + b: Ty<'tcx>, locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - relate_tys::sub_types( + relate_tys::relate_types( self.infcx, - sub, - sup, + a, + v, + b, locations, category, self.borrowck_context.as_mut().map(|x| &mut **x), ) } + fn sub_types( + &mut self, + sub: Ty<'tcx>, + sup: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + self.relate_types(sub, ty::Variance::Covariant, sup, locations, category) + } + /// Try to relate `sub <: sup`; if this fails, instantiate opaque /// variables in `sub` with their inferred definitions and try /// again. This is used for opaque types in places (e.g., `let x: @@ -950,34 +964,79 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - relate_tys::eq_types( - self.infcx, - a, - b, - locations, - category, - self.borrowck_context.as_mut().map(|x| &mut **x), - ) + self.relate_types(a, ty::Variance::Invariant, b, locations, category) } fn relate_type_and_user_type( &mut self, a: Ty<'tcx>, v: ty::Variance, - b: UserTypeAnnotation<'tcx>, + user_ty: UserTypeAnnotation<'tcx>, locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - let ty = relate_tys::relate_type_and_user_type( - self.infcx, - a, - v, - b, - locations, - category, - self.borrowck_context.as_mut().map(|x| &mut **x), - )?; - self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category); + let tcx = self.tcx(); + + debug!( + "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})", + a, v, user_ty, locations + ); + + // The `TypeRelating` code assumes that "unresolved inference + // variables" appear in the "a" side, so flip `Contravariant` + // ambient variance to get the right relationship. + let v1 = ty::Contravariant.xform(v); + + match user_ty { + UserTypeAnnotation::Ty(canonical_ty) => { + let (ty, _) = self.infcx + .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty); + + self.relate_types(ty, v1, a, locations, category)?; + + self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category); + } + UserTypeAnnotation::TypeOf(def_id, canonical_substs) => { + let ( + UserSubsts { + substs, + user_self_ty, + }, + _, + ) = self.infcx + .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); + + let ty = self.tcx().type_of(def_id); + let ty = ty.subst(tcx, substs); + + self.relate_types(ty, v1, a, locations, category)?; + + if let Some(UserSelfTy { + impl_def_id, + self_ty, + }) = user_self_ty + { + let impl_self_ty = tcx.type_of(impl_def_id); + let impl_self_ty = impl_self_ty.subst(tcx, &substs); + + // There may be type variables in `substs` and hence + // in `impl_self_ty`, but they should all have been + // resolved to some fixed value during the first call + // to `relate`, above. Therefore, if we use + // `resolve_type_vars_if_possible` we should get to + // something without type variables. This is important + // because the `b` type in `relate_with_variance` + // below is not permitted to have inference variables. + let impl_self_ty = self.infcx.resolve_type_vars_if_possible(&impl_self_ty); + assert!(!impl_self_ty.has_infer_types()); + + self.eq_types(self_ty, impl_self_ty, locations, category)?; + } + + self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category); + } + } + Ok(()) } diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 665ed24ac3d26..13ebf46bdb149 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -12,35 +12,23 @@ use borrow_check::nll::constraints::OutlivesConstraint; use borrow_check::nll::type_check::{BorrowCheckContext, Locations}; use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; -use rustc::mir::{ConstraintCategory, UserTypeAnnotation}; +use rustc::mir::ConstraintCategory; use rustc::traits::query::Fallible; use rustc::ty::relate::TypeRelation; -use rustc::ty::subst::{Subst, UserSelfTy, UserSubsts}; -use rustc::ty::{self, Ty, TypeFoldable}; -use syntax_pos::DUMMY_SP; - -/// Adds sufficient constraints to ensure that `a <: b`. -pub(super) fn sub_types<'tcx>( - infcx: &InferCtxt<'_, '_, 'tcx>, - a: Ty<'tcx>, - b: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>, -) -> Fallible<()> { - debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations); - TypeRelating::new( - infcx, - NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), - ty::Variance::Covariant, - ).relate(&a, &b)?; - Ok(()) -} - -/// Adds sufficient constraints to ensure that `a == b`. -pub(super) fn eq_types<'tcx>( +use rustc::ty::{self, Ty}; + +/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: +/// +/// - "Covariant" `a <: b` +/// - "Invariant" `a == b` +/// - "Contravariant" `a :> b` +/// +/// NB. The type `a` is permitted to have unresolved inference +/// variables, but not the type `b`. +pub(super) fn relate_types<'tcx>( infcx: &InferCtxt<'_, '_, 'tcx>, a: Ty<'tcx>, + v: ty::Variance, b: Ty<'tcx>, locations: Locations, category: ConstraintCategory, @@ -50,91 +38,11 @@ pub(super) fn eq_types<'tcx>( TypeRelating::new( infcx, NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), - ty::Variance::Invariant, + v, ).relate(&a, &b)?; Ok(()) } -/// Adds sufficient constraints to ensure that `a <: b`, where `b` is -/// a user-given type (which means it may have canonical variables -/// encoding things like `_`). -pub(super) fn relate_type_and_user_type<'tcx>( - infcx: &InferCtxt<'_, '_, 'tcx>, - a: Ty<'tcx>, - v: ty::Variance, - user_ty: UserTypeAnnotation<'tcx>, - locations: Locations, - category: ConstraintCategory, - borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>, -) -> Fallible> { - debug!( - "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})", - a, v, user_ty, locations - ); - - // The `TypeRelating` code assumes that the "canonical variables" - // appear in the "a" side, so flip `Contravariant` ambient - // variance to get the right relationship. - let v1 = ty::Contravariant.xform(v); - - let mut type_relating = TypeRelating::new( - infcx, - NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), - v1, - ); - - match user_ty { - UserTypeAnnotation::Ty(canonical_ty) => { - let (ty, _) = - infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty); - type_relating.relate(&ty, &a)?; - Ok(ty) - } - UserTypeAnnotation::TypeOf(def_id, canonical_substs) => { - let ( - UserSubsts { - substs, - user_self_ty, - }, - _, - ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - - let ty = infcx.tcx.type_of(def_id); - let ty = ty.subst(infcx.tcx, substs); - - type_relating.relate(&ty, &a)?; - - if let Some(UserSelfTy { - impl_def_id, - self_ty, - }) = user_self_ty - { - let impl_self_ty = infcx.tcx.type_of(impl_def_id); - let impl_self_ty = impl_self_ty.subst(infcx.tcx, &substs); - - // There may be type variables in `substs` and hence - // in `impl_self_ty`, but they should all have been - // resolved to some fixed value during the first call - // to `relate`, above. Therefore, if we use - // `resolve_type_vars_if_possible` we should get to - // something without type variables. This is important - // because the `b` type in `relate_with_variance` - // below is not permitted to have inference variables. - let impl_self_ty = infcx.resolve_type_vars_if_possible(&impl_self_ty); - assert!(!impl_self_ty.has_infer_types()); - - type_relating.relate_with_variance( - ty::Variance::Invariant, - &self_ty, - &impl_self_ty, - )?; - } - - Ok(ty) - } - } -} - struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> { infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>, From 121f3c8d19c3549ab0b51a14034ffb8b097faf42 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 12:31:44 -0400 Subject: [PATCH 07/21] normalize after substitution --- .../borrow_check/nll/type_check/mod.rs | 1 + .../constant-in-expr-normalize.rs | 24 +++++++++++++++++++ .../constant-in-expr-normalize.stderr | 10 ++++++++ 3 files changed, 35 insertions(+) create mode 100644 src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs create mode 100644 src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr 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 823a249760f5b..d64643430c943 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1008,6 +1008,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let ty = self.tcx().type_of(def_id); let ty = ty.subst(tcx, substs); + let ty = self.normalize(ty, locations); self.relate_types(ty, v1, a, locations, category)?; diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs new file mode 100644 index 0000000000000..4292fc710e98b --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs @@ -0,0 +1,24 @@ +#![feature(nll)] + +trait Mirror { + type Me; +} + +impl Mirror for T { + type Me = T; +} + +trait Foo<'a> { + const C: <&'a u32 as Mirror>::Me; +} + +impl<'a, T> Foo<'a> for T { + const C: &'a u32 = &22; +} + +fn foo<'a>(_: &'a u32) -> &'static u32 { + <() as Foo<'a>>::C //~ ERROR +} + +fn main() { +} diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr new file mode 100644 index 0000000000000..7aeb276eeb929 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr @@ -0,0 +1,10 @@ +error: unsatisfied lifetime constraints + --> $DIR/constant-in-expr-normalize.rs:20:5 + | +LL | fn foo<'a>(_: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | <() as Foo<'a>>::C //~ ERROR + | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + From bfb1d959c3cc64d54d1a1f3d586d90b6ce0d5357 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 11:10:08 -0400 Subject: [PATCH 08/21] normalize and prove predicates Also include a test that was not working previously. --- .../borrow_check/nll/type_check/mod.rs | 51 ++++++++++++++++++- .../constant-in-expr-trait-item-3.rs | 16 ++++++ .../constant-in-expr-trait-item-3.stderr | 10 ++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs create mode 100644 src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr 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 d64643430c943..6783083c9584c 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -42,7 +42,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp; use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSubsts, UserSelfTy}; +use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSelfTy, UserSubsts}; use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; use std::rc::Rc; use std::{fmt, iter}; @@ -1034,6 +1034,29 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.eq_types(self_ty, impl_self_ty, locations, category)?; } + // Prove the predicates coming along with `def_id`. + // + // Also, normalize the `instantiated_predicates` + // because otherwise we wind up with duplicate "type + // outlives" error messages. + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); + let instantiated_predicates = self.fold_to_region_vid(instantiated_predicates); + self.normalize_and_prove_instantiated_predicates( + instantiated_predicates, + locations, + ); + + // 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(ty::Predicate::WellFormed(ty), locations, category); } } @@ -1041,6 +1064,32 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Ok(()) } + /// Replace all free regions in `value` with their NLL `RegionVid` + /// equivalents; if not in NLL, does nothing. This is never + /// particularly necessary -- we'll do it lazilly as we process + /// the value anyway -- but in some specific cases it is useful to + /// normalize so we can suppress duplicate error messages. + fn fold_to_region_vid( + &self, + value: T + ) -> T + where T: TypeFoldable<'tcx> + { + if let Some(borrowck_context) = &self.borrowck_context { + self.tcx().fold_regions(&value, &mut false, |r, _debruijn| { + if r.has_free_regions() { + self.tcx().mk_region(ty::RegionKind::ReVar( + borrowck_context.universal_regions.to_region_vid(r), + )) + } else { + r + } + }) + } else { + value + } + } + fn eq_opaque_type_and_type( &mut self, revealed_ty: Ty<'tcx>, diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs new file mode 100644 index 0000000000000..f83ae2438e6d5 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs @@ -0,0 +1,16 @@ +#![feature(nll)] + +trait Foo<'a> { + const C: &'a u32; +} + +impl<'a, T> Foo<'a> for T { + const C: &'a u32 = &22; +} + +fn foo<'a, T: Foo<'a>>() -> &'static u32 { + T::C //~ ERROR +} + +fn main() { +} diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr new file mode 100644 index 0000000000000..b373cebacb063 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr @@ -0,0 +1,10 @@ +error: unsatisfied lifetime constraints + --> $DIR/constant-in-expr-trait-item-3.rs:12:5 + | +LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { + | -- lifetime `'a` defined here +LL | T::C //~ ERROR + | ^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + From e20fa70bb349026226616b92ea44f7bdfd270d75 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Oct 2018 09:00:11 -0400 Subject: [PATCH 09/21] suppress duplicate -- or near duplicate -- type test errors --- src/librustc/infer/region_constraints/mod.rs | 2 +- .../borrow_check/nll/region_infer/mod.rs | 30 ++++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 525ae03dfaf93..df30ad360062c 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -149,7 +149,7 @@ pub struct Verify<'tcx> { pub bound: VerifyBound<'tcx>, } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum GenericKind<'tcx> { Param(ty::ParamTy), Projection(ty::ProjectionTy<'tcx>), diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 0fabcfe456449..95b3943746d1b 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -25,7 +25,7 @@ use rustc::mir::{ use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common; use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; use rustc_data_structures::indexed_vec::IndexVec; use rustc_errors::{Diagnostic, DiagnosticBuilder}; @@ -580,6 +580,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) { let tcx = infcx.tcx; + // Sometimes we register equivalent type-tests that would + // result in basically the exact same error being reported to + // the user. Avoid that. + let mut deduplicate_errors = FxHashSet::default(); + for type_test in &self.type_tests { debug!("check_type_test: {:?}", type_test); @@ -605,11 +610,29 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - // Oh the humanity. Obviously we will do better than this error eventually. + // Type-test failed. Report the error. + + // Try to convert the lower-bound region into something named we can print for the user. let lower_bound_region = self.to_error_region(type_test.lower_bound); + + // Skip duplicate-ish errors. + let type_test_span = type_test.locations.span(mir); + let erased_generic_kind = tcx.erase_regions(&type_test.generic_kind); + if !deduplicate_errors.insert((erased_generic_kind, lower_bound_region, type_test.locations)) { + continue; + } else { + debug!( + "check_type_test: reporting error for erased_generic_kind={:?}, \ + lower_bound_region={:?}, \ + type_test.locations={:?}", + erased_generic_kind, + lower_bound_region, + type_test.locations, + ); + } + if let Some(lower_bound_region) = lower_bound_region { let region_scope_tree = &tcx.region_scope_tree(mir_def_id); - let type_test_span = type_test.locations.span(mir); infcx .construct_generic_bound_failure( region_scope_tree, @@ -629,7 +652,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { // to report it; we could probably handle it by // iterating over the universal regions and reporting // an error that multiple bounds are required. - let type_test_span = type_test.locations.span(mir); tcx.sess .struct_span_err( type_test_span, From 80ad300b890c07d4c95fbf63c0f9cd3e397e545f Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Tue, 2 Oct 2018 09:31:46 -0700 Subject: [PATCH 10/21] Wrap cast expressions inside of ValueTypeAscription --- src/librustc_mir/hair/cx/expr.rs | 23 +++++++++++++++++-- src/librustc_typeck/check/mod.rs | 2 ++ .../user-annotations/cast_static_lifetime.rs | 17 ++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/cast_static_lifetime.rs diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 04dd1aa3c8880..796f6753e9516 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -637,7 +637,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, name: Field::new(cx.tcx.field_index(expr.id, cx.tables)), } } - hir::ExprKind::Cast(ref source, _) => { + hir::ExprKind::Cast(ref source, ref ty) => { // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). if let Some(&TyCastKind::CoercionCast) = cx.tables() @@ -714,7 +714,26 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } else { source.to_ref() }; - ExprKind::Cast { source } + + let cast = ExprKind::Cast { source }; + + if let Some(user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) { + // NOTE: Creating a new Expr and wrapping a Cast inside of it may be + // inefficient, revisit this when performance becomes an issue. + let cast_expr = Expr { + temp_lifetime, + ty: expr_ty, + span: expr.span, + kind: cast, + }; + + ExprKind::ValueTypeAscription { + source: cast_expr.to_ref(), + user_ty: UserTypeAnnotation::Ty(*user_ty), + } + } else { + cast + } } } hir::ExprKind::Type(ref source, ref ty) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 14ce1bb4ccdee..e6922d1c4c7e4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4166,6 +4166,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { Ok(cast_check) => { + let c_ty = self.infcx.canonicalize_response(&t_cast); + self.tables.borrow_mut().user_provided_tys_mut().insert(t.hir_id, c_ty); deferred_cast_checks.push(cast_check); t_cast } diff --git a/src/test/ui/nll/user-annotations/cast_static_lifetime.rs b/src/test/ui/nll/user-annotations/cast_static_lifetime.rs new file mode 100644 index 0000000000000..aa2cf85dfd999 --- /dev/null +++ b/src/test/ui/nll/user-annotations/cast_static_lifetime.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(warnings)] +#![feature(nll)] + +fn main() { + let x = 22_u32; + let y: &u32 = (&x) as &'static u32; +} From 2d98e9e0aa6a990ec12f476c495be6720ad81f51 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 16:18:24 -0400 Subject: [PATCH 11/21] create type ascription for any cast Also, avoid shadowing of the `ty` variable by giving the `cast_ty` and `var_ty` variables different names. We want to get the user-provided type from `cast_ty.hir_id`. --- src/librustc_mir/hair/cx/expr.rs | 64 +++++++++++-------- .../cast_static_lifetime.stderr | 13 ++++ 2 files changed, 52 insertions(+), 25 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/cast_static_lifetime.stderr diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 796f6753e9516..a3e0c11551529 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -637,12 +637,25 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, name: Field::new(cx.tcx.field_index(expr.id, cx.tables)), } } - hir::ExprKind::Cast(ref source, ref ty) => { + hir::ExprKind::Cast(ref source, ref cast_ty) => { + // Check for a user-given type annotation on this `cast` + let user_ty = cx.tables.user_provided_tys().get(cast_ty.hir_id) + .map(|&t| UserTypeAnnotation::Ty(t)); + + debug!( + "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}", + expr, + cast_ty.hir_id, + user_ty, + ); + // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). - if let Some(&TyCastKind::CoercionCast) = cx.tables() - .cast_kinds() - .get(source.hir_id) { + let cast = if let Some(&TyCastKind::CoercionCast) = + cx.tables() + .cast_kinds() + .get(source.hir_id) + { // Convert the lexpr to a vexpr. ExprKind::Use { source: source.to_ref() } } else { @@ -679,24 +692,25 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } else { None }; - let source = if let Some((did, offset, ty)) = var { + + let source = if let Some((did, offset, var_ty)) = var { let mk_const = |literal| Expr { temp_lifetime, - ty, + ty: var_ty, span: expr.span, kind: ExprKind::Literal { literal, user_ty: None }, }.to_ref(); let offset = mk_const(ty::Const::from_bits( cx.tcx, offset as u128, - cx.param_env.and(ty), + cx.param_env.and(var_ty), )); match did { Some(did) => { // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = Substs::identity_for_item(cx.tcx(), did); - let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty)); + let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, var_ty)); let bin = ExprKind::Binary { op: BinOp::Add, lhs, @@ -704,7 +718,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; Expr { temp_lifetime, - ty, + ty: var_ty, span: expr.span, kind: bin, }.to_ref() @@ -715,25 +729,25 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, source.to_ref() }; - let cast = ExprKind::Cast { source }; + ExprKind::Cast { source } + }; - if let Some(user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) { - // NOTE: Creating a new Expr and wrapping a Cast inside of it may be - // inefficient, revisit this when performance becomes an issue. - let cast_expr = Expr { - temp_lifetime, - ty: expr_ty, - span: expr.span, - kind: cast, - }; + if let Some(user_ty) = user_ty { + // NOTE: Creating a new Expr and wrapping a Cast inside of it may be + // inefficient, revisit this when performance becomes an issue. + let cast_expr = Expr { + temp_lifetime, + ty: expr_ty, + span: expr.span, + kind: cast, + }; - ExprKind::ValueTypeAscription { - source: cast_expr.to_ref(), - user_ty: UserTypeAnnotation::Ty(*user_ty), - } - } else { - cast + ExprKind::ValueTypeAscription { + source: cast_expr.to_ref(), + user_ty: user_ty, } + } else { + cast } } hir::ExprKind::Type(ref source, ref ty) => { diff --git a/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr b/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr new file mode 100644 index 0000000000000..a35035b07ba54 --- /dev/null +++ b/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr @@ -0,0 +1,13 @@ +error[E0597]: `x` does not live long enough + --> $DIR/cast_static_lifetime.rs:16:19 + | +LL | let y: &u32 = (&x) as &'static u32; + | ^^^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From ab79cf951b6d4c853d855c9b351e826be4b8233e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 16:20:54 -0400 Subject: [PATCH 12/21] save the user-provided type immediately upon return from astconv --- src/librustc_typeck/check/mod.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e6922d1c4c7e4..b184b77b7edd7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2357,6 +2357,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { t } + pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { + let ty = self.to_ty(ast_ty); + let c_ty = self.infcx.canonicalize_response(&ty); + self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty); + ty + } + pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { match self.tables.borrow().node_types().get(id) { Some(&t) => t, @@ -4153,7 +4160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprKind::Cast(ref e, ref t) => { // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. - let t_cast = self.to_ty(t); + let t_cast = self.to_ty_saving_user_provided_ty(t); let t_cast = self.resolve_type_vars_if_possible(&t_cast); let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); let t_cast = self.resolve_type_vars_if_possible(&t_cast); @@ -4166,8 +4173,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { Ok(cast_check) => { - let c_ty = self.infcx.canonicalize_response(&t_cast); - self.tables.borrow_mut().user_provided_tys_mut().insert(t.hir_id, c_ty); deferred_cast_checks.push(cast_check); t_cast } @@ -4178,10 +4183,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } hir::ExprKind::Type(ref e, ref t) => { - let ty = self.to_ty(&t); + let ty = self.to_ty_saving_user_provided_ty(&t); self.check_expr_eq_type(&e, ty); - let c_ty = self.infcx.canonicalize_response(&ty); - self.tables.borrow_mut().user_provided_tys_mut().insert(t.hir_id, c_ty); ty } hir::ExprKind::Array(ref args) => { From 26fdac62244233a6dae0240ea649c49c188cc1b6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 16:40:43 -0400 Subject: [PATCH 13/21] pacify the mercilous tidy --- src/librustc_mir/hair/cx/expr.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index a3e0c11551529..72532766d4399 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -710,7 +710,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = Substs::identity_for_item(cx.tcx(), did); - let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, var_ty)); + let lhs = mk_const(ty::Const::unevaluated( + cx.tcx(), + did, + substs, + var_ty, + )); let bin = ExprKind::Binary { op: BinOp::Add, lhs, From d5d5e8c5f52ccc5f88f8cf691118e364e64bf75b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Oct 2018 05:58:20 -0400 Subject: [PATCH 14/21] lowering casts in constants now creates multiple uses This can trigger more errors than before. Not sure what is the best fix here. --- .../const-eval/conditional_array_execution.rs | 5 +++-- .../conditional_array_execution.stderr | 16 ++++++++++++---- .../ui/consts/const-eval/promoted_errors.stderr | 6 ++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.rs b/src/test/ui/consts/const-eval/conditional_array_execution.rs index b3f56f27f6352..9a6ffcd2c672a 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.rs +++ b/src/test/ui/consts/const-eval/conditional_array_execution.rs @@ -14,9 +14,10 @@ const X: u32 = 5; const Y: u32 = 6; const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~^ WARN this constant cannot be used +//~| ERROR fn main() { println!("{}", FOO); - //~^ ERROR erroneous constant used - //~| E0080 + //~^ ERROR + //~| ERROR } diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr index 29f5f8e2ade59..b22a8d8aead2e 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr @@ -13,7 +13,7 @@ LL | #![warn(const_err)] | ^^^^^^^^^ error[E0080]: referenced constant has errors - --> $DIR/conditional_array_execution.rs:19:20 + --> $DIR/conditional_array_execution.rs:20:20 | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; | ----- attempt to subtract with overflow @@ -21,12 +21,20 @@ LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; LL | println!("{}", FOO); | ^^^ -error[E0080]: erroneous constant used - --> $DIR/conditional_array_execution.rs:19:20 +error[E0080]: could not evaluate constant + --> $DIR/conditional_array_execution.rs:20:20 | LL | println!("{}", FOO); | ^^^ referenced constant has errors -error: aborting due to 2 previous errors +error[E0080]: constant evaluation error + --> $DIR/conditional_array_execution.rs:15:1 + | +LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; + | ^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | attempt to subtract with overflow + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr index 85b5696be947c..1c4868c2af972 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.stderr @@ -34,6 +34,12 @@ warning: attempt to divide by zero LL | println!("{}", 1/(false as u32)); | ^^^^^^^^^^^^^^^^ +warning: this expression will panic at runtime + --> $DIR/promoted_errors.rs:24:20 + | +LL | println!("{}", 1/(false as u32)); + | ^^^^^^^^^^^^^^^^ attempt to divide by zero + warning: attempt to divide by zero --> $DIR/promoted_errors.rs:26:14 | From a66ab2bedcc2ac34086d17753f777ffe31dc6349 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 18:23:43 -0400 Subject: [PATCH 15/21] skip user-type annotations if they don't have regions --- src/librustc_mir/build/expr/as_place.rs | 48 ++++++++++--------- src/librustc_mir/hair/cx/expr.rs | 12 +---- src/librustc_mir/hair/mod.rs | 4 +- src/librustc_typeck/check/mod.rs | 11 ++++- .../const-eval/conditional_array_execution.rs | 1 - .../conditional_array_execution.stderr | 16 ++----- .../consts/const-eval/promoted_errors.stderr | 6 --- 7 files changed, 43 insertions(+), 55 deletions(-) diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 29c3fb6933967..820822b7f5bbd 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -139,17 +139,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::PlaceTypeAscription { source, user_ty } => { let place = unpack!(block = this.as_place(block, source)); - this.cfg.push( - block, - Statement { - source_info, - kind: StatementKind::AscribeUserType( - place.clone(), - Variance::Invariant, - user_ty, - ), - }, - ); + if let Some(user_ty) = user_ty { + this.cfg.push( + block, + Statement { + source_info, + kind: StatementKind::AscribeUserType( + place.clone(), + Variance::Invariant, + user_ty, + ), + }, + ); + } block.and(place) } ExprKind::ValueTypeAscription { source, user_ty } => { @@ -157,17 +159,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let temp = unpack!( block = this.as_temp(block, source.temp_lifetime, source, mutability) ); - this.cfg.push( - block, - Statement { - source_info, - kind: StatementKind::AscribeUserType( - Place::Local(temp.clone()), - Variance::Invariant, - user_ty, - ), - }, - ); + if let Some(user_ty) = user_ty { + this.cfg.push( + block, + Statement { + source_info, + kind: StatementKind::AscribeUserType( + Place::Local(temp.clone()), + Variance::Invariant, + user_ty, + ), + }, + ); + } block.and(Place::Local(temp)) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 72532766d4399..5adaad15e4cc7 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -749,7 +749,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::ValueTypeAscription { source: cast_expr.to_ref(), - user_ty: user_ty, + user_ty: Some(user_ty), } } else { cast @@ -757,15 +757,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprKind::Type(ref source, ref ty) => { let user_provided_tys = cx.tables.user_provided_tys(); - let user_ty = UserTypeAnnotation::Ty( - *user_provided_tys - .get(ty.hir_id) - .expect(&format!( - "{:?} not found in user_provided_tys, source: {:?}", - ty, - source, - )) - ); + let user_ty = user_provided_tys.get(ty.hir_id).map(|&c_ty| UserTypeAnnotation::Ty(c_ty)); if source.is_place_expr() { ExprKind::PlaceTypeAscription { source: source.to_ref(), diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 781b6c92aa13a..788db5c0b7e52 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -276,12 +276,12 @@ pub enum ExprKind<'tcx> { PlaceTypeAscription { source: ExprRef<'tcx>, /// Type that the user gave to this expression - user_ty: UserTypeAnnotation<'tcx>, + user_ty: Option>, }, ValueTypeAscription { source: ExprRef<'tcx>, /// Type that the user gave to this expression - user_ty: UserTypeAnnotation<'tcx>, + user_ty: Option>, }, Closure { closure_id: DefId, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b184b77b7edd7..ff92104d127f1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2359,8 +2359,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { let ty = self.to_ty(ast_ty); - let c_ty = self.infcx.canonicalize_response(&ty); - self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty); + + // If the type given by the user has free regions, save it for + // later, since NLL would like to enforce those. Other sorts + // of things are already sufficiently enforced. =) + if ty.has_free_regions() { + let c_ty = self.infcx.canonicalize_response(&ty); + self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty); + } + ty } diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.rs b/src/test/ui/consts/const-eval/conditional_array_execution.rs index 9a6ffcd2c672a..8142ed0155aae 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.rs +++ b/src/test/ui/consts/const-eval/conditional_array_execution.rs @@ -14,7 +14,6 @@ const X: u32 = 5; const Y: u32 = 6; const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~^ WARN this constant cannot be used -//~| ERROR fn main() { println!("{}", FOO); diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr index b22a8d8aead2e..29f5f8e2ade59 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr @@ -13,7 +13,7 @@ LL | #![warn(const_err)] | ^^^^^^^^^ error[E0080]: referenced constant has errors - --> $DIR/conditional_array_execution.rs:20:20 + --> $DIR/conditional_array_execution.rs:19:20 | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; | ----- attempt to subtract with overflow @@ -21,20 +21,12 @@ LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; LL | println!("{}", FOO); | ^^^ -error[E0080]: could not evaluate constant - --> $DIR/conditional_array_execution.rs:20:20 +error[E0080]: erroneous constant used + --> $DIR/conditional_array_execution.rs:19:20 | LL | println!("{}", FOO); | ^^^ referenced constant has errors -error[E0080]: constant evaluation error - --> $DIR/conditional_array_execution.rs:15:1 - | -LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | attempt to subtract with overflow - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr index 1c4868c2af972..85b5696be947c 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.stderr @@ -34,12 +34,6 @@ warning: attempt to divide by zero LL | println!("{}", 1/(false as u32)); | ^^^^^^^^^^^^^^^^ -warning: this expression will panic at runtime - --> $DIR/promoted_errors.rs:24:20 - | -LL | println!("{}", 1/(false as u32)); - | ^^^^^^^^^^^^^^^^ attempt to divide by zero - warning: attempt to divide by zero --> $DIR/promoted_errors.rs:26:14 | From 02e5a902e8fc9ffda11eae3cea0e4988c08198c5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Oct 2018 20:09:52 -0400 Subject: [PATCH 16/21] pacify the mercilous tidy --- src/librustc_mir/hair/cx/expr.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 5adaad15e4cc7..1df5f78975139 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -757,7 +757,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprKind::Type(ref source, ref ty) => { let user_provided_tys = cx.tables.user_provided_tys(); - let user_ty = user_provided_tys.get(ty.hir_id).map(|&c_ty| UserTypeAnnotation::Ty(c_ty)); + let user_ty = user_provided_tys + .get(ty.hir_id) + .map(|&c_ty| UserTypeAnnotation::Ty(c_ty)); if source.is_place_expr() { ExprKind::PlaceTypeAscription { source: source.to_ref(), From 061c9a2bede792edeb2473d7fea7c6d8c5e8f089 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Oct 2018 10:44:33 -0400 Subject: [PATCH 17/21] region_infer/mod.rs: rustfmt --- .../borrow_check/nll/region_infer/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 95b3943746d1b..2c84a9e014e93 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -67,10 +67,8 @@ pub struct RegionInferenceContext<'tcx> { constraint_sccs: Rc>, /// Map closure bounds to a `Span` that should be used for error reporting. - closure_bounds_mapping: FxHashMap< - Location, - FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>, - >, + closure_bounds_mapping: + FxHashMap>, /// Contains the minimum universe of any variable within the same /// SCC. We will ensure that no SCC contains values that are not @@ -618,16 +616,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Skip duplicate-ish errors. let type_test_span = type_test.locations.span(mir); let erased_generic_kind = tcx.erase_regions(&type_test.generic_kind); - if !deduplicate_errors.insert((erased_generic_kind, lower_bound_region, type_test.locations)) { + if !deduplicate_errors.insert(( + erased_generic_kind, + lower_bound_region, + type_test.locations, + )) { continue; } else { debug!( "check_type_test: reporting error for erased_generic_kind={:?}, \ lower_bound_region={:?}, \ type_test.locations={:?}", - erased_generic_kind, - lower_bound_region, - type_test.locations, + erased_generic_kind, lower_bound_region, type_test.locations, ); } From 820c2657f2584501d5e062351306780d29385421 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Oct 2018 14:16:13 -0400 Subject: [PATCH 18/21] add useful debug log --- .../borrow_check/nll/type_check/constraint_conversion.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 4ab0f952bdee9..994f20a011d65 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -142,6 +142,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { } fn add_type_test(&mut self, type_test: TypeTest<'tcx>) { + debug!("add_type_test(type_test={:?})", type_test); self.type_tests.push(type_test); } } From 16b3ea1e2e690524796b37a4b4e2f88e60a9dc3e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Oct 2018 14:26:33 -0400 Subject: [PATCH 19/21] add a test that we enforce '`static` errors post normalization --- src/test/ui/nll/user-annotations/normalization.rs | 13 +++++++++++++ .../ui/nll/user-annotations/normalization.stderr | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/test/ui/nll/user-annotations/normalization.rs create mode 100644 src/test/ui/nll/user-annotations/normalization.stderr diff --git a/src/test/ui/nll/user-annotations/normalization.rs b/src/test/ui/nll/user-annotations/normalization.rs new file mode 100644 index 0000000000000..51d9adccd7372 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization.rs @@ -0,0 +1,13 @@ +// Test that we enforce a `&'static` requirement that is only visible +// after normalization. + +#![feature(nll)] +#![ignore(unused)] + +trait Foo { type Out; } +impl Foo for () { type Out = &'static u32; } + +fn main() { + let a = 22; + let b: <() as Foo>::Out = &a; //~ ERROR +} diff --git a/src/test/ui/nll/user-annotations/normalization.stderr b/src/test/ui/nll/user-annotations/normalization.stderr new file mode 100644 index 0000000000000..489f9feb044c8 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization.stderr @@ -0,0 +1,13 @@ +error[E0597]: `a` does not live long enough + --> $DIR/normalization.rs:12:31 + | +LL | let b: <() as Foo>::Out = &a; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `a` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From f5cc7dba8a32c1f83f3b3102f398405dc540841f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Oct 2018 14:26:45 -0400 Subject: [PATCH 20/21] even though we don't need it yet, fix the "fast path" code --- src/librustc_typeck/check/mod.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ff92104d127f1..ffa21e1fc22a5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2361,9 +2361,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty = self.to_ty(ast_ty); // If the type given by the user has free regions, save it for - // later, since NLL would like to enforce those. Other sorts - // of things are already sufficiently enforced. =) - if ty.has_free_regions() { + // later, since NLL would like to enforce those. Also pass in + // types that involve projections, since those can resolve to + // `'static` bounds (modulo #54940, which hopefully will be + // fixed by the time you see this comment, dear reader, + // although I have my doubts). Other sorts of things are + // already sufficiently enforced with erased regions. =) + if ty.has_free_regions() || ty.has_projections() { let c_ty = self.infcx.canonicalize_response(&ty); self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty); } From 9a7bb0ef249258aacf144d04f5d437ba70533128 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Oct 2018 15:48:48 -0400 Subject: [PATCH 21/21] normalize the self-type that we extract from impl --- .../borrow_check/nll/type_check/mod.rs | 1 + .../nll/user-annotations/normalize-self-ty.rs | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/test/ui/nll/user-annotations/normalize-self-ty.rs 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 6783083c9584c..7737fcc765d80 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1019,6 +1019,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { { let impl_self_ty = tcx.type_of(impl_def_id); let impl_self_ty = impl_self_ty.subst(tcx, &substs); + let impl_self_ty = self.normalize(impl_self_ty, locations); // There may be type variables in `substs` and hence // in `impl_self_ty`, but they should all have been diff --git a/src/test/ui/nll/user-annotations/normalize-self-ty.rs b/src/test/ui/nll/user-annotations/normalize-self-ty.rs new file mode 100644 index 0000000000000..d97cc88dd9af4 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalize-self-ty.rs @@ -0,0 +1,25 @@ +// Regression test for #55183: check a case where the self type from +// the inherent impl requires normalization to be equal to the +// user-provided type. +// +// run-pass + +#![feature(nll)] + +trait Mirror { + type Me; +} + +impl Mirror for T { + type Me = T; +} + +struct Foo(A, B); + +impl Foo::Me> { + fn m(b: A) { } +} + +fn main() { + >::m(&22); +}