Skip to content

Commit

Permalink
Auto merge of #54447 - KiChjang:issue-54331, r=nikomatsakis
Browse files Browse the repository at this point in the history
Lower type ascriptions to HAIR and MIR

Fixes #54331.

r? @nikomatsakis
  • Loading branch information
bors committed Oct 4, 2018
2 parents 4bf883b + 8380b25 commit d078728
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 64 deletions.
53 changes: 53 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,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 {
Expand Down
35 changes: 35 additions & 0 deletions src/librustc_mir/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 { .. }
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_mir/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_mir/build/expr/category.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 { .. }
Expand Down
13 changes: 12 additions & 1 deletion src/librustc_mir/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -393,7 +397,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
| ExprKind::Literal { .. }
| 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,
});

Expand Down
18 changes: 17 additions & 1 deletion src/librustc_mir/hair/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
10 changes: 10 additions & 0 deletions src/librustc_mir/hair/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,16 @@ pub enum ExprKind<'tcx> {
fields: Vec<FieldExprRef<'tcx>>,
base: Option<FruInfo<'tcx>>
},
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>,
Expand Down
69 changes: 10 additions & 59 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2469,59 +2469,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
Expand Down Expand Up @@ -3799,10 +3746,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 {
Expand Down Expand Up @@ -3899,7 +3848,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.
Expand Down Expand Up @@ -4075,7 +4024,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")
Expand Down Expand Up @@ -4203,6 +4152,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) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
}
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit d078728

Please sign in to comment.