From 8132d4e1000f012d1f25dbcedf006a9dc2f8598c Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 20 Sep 2018 14:13:41 -0700 Subject: [PATCH 1/4] Move is_place_expr to be a method on hir::Expr --- src/librustc/hir/mod.rs | 53 +++++++++++++++++++++++++ src/librustc_typeck/check/mod.rs | 67 ++++---------------------------- src/librustc_typeck/check/op.rs | 2 +- 3 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index de9808ffe7001..b55b175cade53 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1345,6 +1345,59 @@ impl Expr { ExprKind::Yield(..) => ExprPrecedence::Yield, } } + + pub fn is_place_expr(&self) -> bool { + match self.node { + ExprKind::Path(QPath::Resolved(_, ref path)) => { + match path.def { + Def::Local(..) | Def::Upvar(..) | Def::Static(..) | Def::Err => true, + _ => false, + } + } + + ExprKind::Type(ref e, _) => { + e.is_place_expr() + } + + ExprKind::Unary(UnDeref, _) | + ExprKind::Field(..) | + ExprKind::Index(..) => { + true + } + + // Partially qualified paths in expressions can only legally + // refer to associated items which are always rvalues. + ExprKind::Path(QPath::TypeRelative(..)) | + + ExprKind::Call(..) | + ExprKind::MethodCall(..) | + ExprKind::Struct(..) | + ExprKind::Tup(..) | + ExprKind::If(..) | + ExprKind::Match(..) | + ExprKind::Closure(..) | + ExprKind::Block(..) | + ExprKind::Repeat(..) | + ExprKind::Array(..) | + ExprKind::Break(..) | + ExprKind::Continue(..) | + ExprKind::Ret(..) | + ExprKind::While(..) | + ExprKind::Loop(..) | + ExprKind::Assign(..) | + ExprKind::InlineAsm(..) | + ExprKind::AssignOp(..) | + ExprKind::Lit(_) | + ExprKind::Unary(..) | + ExprKind::Box(..) | + ExprKind::AddrOf(..) | + ExprKind::Binary(..) | + ExprKind::Yield(..) | + ExprKind::Cast(..) => { + false + } + } + } } impl fmt::Debug for Expr { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index db0c4fdb03ae6..6d1f5be8470be 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2447,59 +2447,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn is_place_expr(&self, expr: &hir::Expr) -> bool { - match expr.node { - hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { - match path.def { - Def::Local(..) | Def::Upvar(..) | Def::Static(..) | Def::Err => true, - _ => false, - } - } - - hir::ExprKind::Type(ref e, _) => { - self.is_place_expr(e) - } - - hir::ExprKind::Unary(hir::UnDeref, _) | - hir::ExprKind::Field(..) | - hir::ExprKind::Index(..) => { - true - } - - // Partially qualified paths in expressions can only legally - // refer to associated items which are always rvalues. - hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | - - hir::ExprKind::Call(..) | - hir::ExprKind::MethodCall(..) | - hir::ExprKind::Struct(..) | - hir::ExprKind::Tup(..) | - hir::ExprKind::If(..) | - hir::ExprKind::Match(..) | - hir::ExprKind::Closure(..) | - hir::ExprKind::Block(..) | - hir::ExprKind::Repeat(..) | - hir::ExprKind::Array(..) | - hir::ExprKind::Break(..) | - hir::ExprKind::Continue(..) | - hir::ExprKind::Ret(..) | - hir::ExprKind::While(..) | - hir::ExprKind::Loop(..) | - hir::ExprKind::Assign(..) | - hir::ExprKind::InlineAsm(..) | - hir::ExprKind::AssignOp(..) | - hir::ExprKind::Lit(_) | - hir::ExprKind::Unary(..) | - hir::ExprKind::Box(..) | - hir::ExprKind::AddrOf(..) | - hir::ExprKind::Binary(..) | - hir::ExprKind::Yield(..) | - hir::ExprKind::Cast(..) => { - false - } - } - } - /// For the overloaded place expressions (`*x`, `x[3]`), the trait /// returns a type of `&T`, but the actual type we assign to the /// *expression* is `T`. So this function just peels off the return @@ -3762,10 +3709,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } - fn check_expr_kind(&self, - expr: &'gcx hir::Expr, - expected: Expectation<'tcx>, - needs: Needs) -> Ty<'tcx> { + fn check_expr_kind( + &self, + expr: &'gcx hir::Expr, + expected: Expectation<'tcx>, + needs: Needs + ) -> Ty<'tcx> { let tcx = self.tcx; let id = expr.id; match expr.node { @@ -3862,7 +3811,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { match ty.sty { ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { - if self.is_place_expr(&oprnd) { + if oprnd.is_place_expr() { // Places may legitimately have unsized types. // For example, dereferences of a fat pointer and // the last field of a struct can be unsized. @@ -4041,7 +3990,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => { // Only check this if not in an `if` condition, as the // mistyped comparison help is more appropriate. - if !self.is_place_expr(&lhs) { + if !lhs.is_place_expr() { struct_span_err!(self.tcx.sess, expr.span, E0070, "invalid left-hand side expression") .span_label(expr.span, "left-hand of expression not valid") diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 5004880ce47b8..304238488d8a9 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -40,7 +40,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return_ty }; - if !self.is_place_expr(lhs_expr) { + if !lhs_expr.is_place_expr() { struct_span_err!( self.tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression") From fba9d14779552c665c5431f0c993c0780c00adca Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 20 Sep 2018 18:43:35 -0700 Subject: [PATCH 2/4] Lower type ascriptions to HAIR and MIR --- src/librustc_mir/build/expr/as_place.rs | 35 ++++++++++++++++++++++++ src/librustc_mir/build/expr/as_rvalue.rs | 4 ++- src/librustc_mir/build/expr/category.rs | 4 ++- src/librustc_mir/build/expr/into.rs | 4 ++- src/librustc_mir/hair/cx/expr.rs | 18 +++++++++++- src/librustc_mir/hair/mod.rs | 10 +++++++ src/librustc_typeck/check/mod.rs | 2 ++ 7 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 5688ea9d260f5..29c3fb6933967 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -16,6 +16,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use hair::*; use rustc::mir::interpret::EvalErrorKind::BoundsCheck; use rustc::mir::*; +use rustc::ty::Variance; use rustc_data_structures::indexed_vec::Idx; @@ -136,6 +137,40 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty: expr.ty, }))), + 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, + ), + }, + ); + block.and(place) + } + ExprKind::ValueTypeAscription { source, user_ty } => { + let source = this.hir.mirror(source); + 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, + ), + }, + ); + block.and(Place::Local(temp)) + } + ExprKind::Array { .. } | ExprKind::Tuple { .. } | ExprKind::Adt { .. } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index b721120f74dbd..8fee74390cc6b 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -386,7 +386,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Continue { .. } | ExprKind::Return { .. } | ExprKind::InlineAsm { .. } - | ExprKind::StaticRef { .. } => { + | ExprKind::StaticRef { .. } + | ExprKind::PlaceTypeAscription { .. } + | ExprKind::ValueTypeAscription { .. } => { // these do not have corresponding `Rvalue` variants, // so make an operand and then return that debug_assert!(match Category::of(&expr.kind) { diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index 601fe2d01f861..05a9079cdb1ef 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -50,7 +50,9 @@ impl Category { | ExprKind::Index { .. } | ExprKind::SelfRef | ExprKind::VarRef { .. } - | ExprKind::StaticRef { .. } => Some(Category::Place), + | ExprKind::StaticRef { .. } + | ExprKind::PlaceTypeAscription { .. } + | ExprKind::ValueTypeAscription { .. } => Some(Category::Place), ExprKind::LogicalOp { .. } | ExprKind::If { .. } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 5708ac4e6b50f..c05719ce95a63 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -391,7 +391,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Adt { .. } | ExprKind::Closure { .. } | ExprKind::Literal { .. } - | ExprKind::Yield { .. } => { + | ExprKind::Yield { .. } + | ExprKind::PlaceTypeAscription { .. } + | ExprKind::ValueTypeAscription { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { Category::Rvalue(RvalueFunc::Into) => false, _ => true, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 3183f0f47eace..f94f1a1a8c8fe 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -718,7 +718,23 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::Cast { source } } } - hir::ExprKind::Type(ref source, _) => return source.make_mirror(cx), + 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) + .expect(&format!("{:?} not found in user_provided_tys, source: {:?}", ty, source)); + if source.is_place_expr() { + ExprKind::PlaceTypeAscription { + source: source.to_ref(), + user_ty, + } + } else { + ExprKind::ValueTypeAscription { + source: source.to_ref(), + user_ty, + } + } + } hir::ExprKind::Box(ref value) => { ExprKind::Box { value: value.to_ref(), diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index d86aee5431267..9258845ad06a7 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -268,6 +268,16 @@ pub enum ExprKind<'tcx> { fields: Vec>, base: Option> }, + PlaceTypeAscription { + source: ExprRef<'tcx>, + /// Type that the user gave to this expression + user_ty: CanonicalTy<'tcx>, + }, + ValueTypeAscription { + source: ExprRef<'tcx>, + /// Type that the user gave to this expression + user_ty: CanonicalTy<'tcx>, + }, Closure { closure_id: DefId, substs: UpvarSubsts<'tcx>, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6d1f5be8470be..40af4b5f5aaeb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4118,6 +4118,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprKind::Type(ref e, ref t) => { let ty = self.to_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 4a293a3990a0c1bf170d31d1d9bcbc79cef8a5b8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 24 Sep 2018 17:53:28 -0400 Subject: [PATCH 3/4] avoid infinite loop in MIR lowering --- src/librustc_mir/build/expr/into.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index c05719ce95a63..9ea3805fdc652 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -345,7 +345,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } // Avoid creating a temporary - ExprKind::VarRef { .. } | ExprKind::SelfRef | ExprKind::StaticRef { .. } => { + ExprKind::VarRef { .. } | + ExprKind::SelfRef | + ExprKind::StaticRef { .. } | + ExprKind::PlaceTypeAscription { .. } | + ExprKind::ValueTypeAscription { .. } => { debug_assert!(Category::of(&expr.kind) == Some(Category::Place)); let place = unpack!(block = this.as_place(block, expr)); @@ -391,11 +395,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Adt { .. } | ExprKind::Closure { .. } | ExprKind::Literal { .. } - | ExprKind::Yield { .. } - | ExprKind::PlaceTypeAscription { .. } - | ExprKind::ValueTypeAscription { .. } => { + | ExprKind::Yield { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { + // should be handled above Category::Rvalue(RvalueFunc::Into) => false, + + // must be handled above or else we get an + // infinite loop in the builder; see + // e.g. `ExprKind::VarRef` above + Category::Place => false, + _ => true, }); From 8380b25d13eeeb387efd6442c4e3638198b06412 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Tue, 25 Sep 2018 11:51:36 -0700 Subject: [PATCH 4/4] Add UI test for preserving user types in type ascriptions --- .../type_ascription_static_lifetime.rs | 19 +++++++++++++++++++ .../type_ascription_static_lifetime.stderr | 13 +++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs create mode 100644 src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr diff --git a/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs new file mode 100644 index 0000000000000..2785f71ebcf6b --- /dev/null +++ b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs @@ -0,0 +1,19 @@ +// Copyright 2012-2014 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)] +#![feature(type_ascription)] + +fn main() { + let x = 22_u32; + let y: &u32 = &x: &'static u32; //~ ERROR E0597 +} diff --git a/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr new file mode 100644 index 0000000000000..2303ed64db94d --- /dev/null +++ b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr @@ -0,0 +1,13 @@ +error[E0597]: `x` does not live long enough + --> $DIR/type_ascription_static_lifetime.rs:18:19 + | +LL | let y: &u32 = &x: &'static u32; //~ ERROR E0597 + | ^^ 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`.