Skip to content

Lower type ascriptions to HAIR and MIR #54447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is on only one variant.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

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 @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -4169,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) => {
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`.