Skip to content

Commit

Permalink
Auto merge of #54757 - nikomatsakis:nll-issue-54573-user-annot, r=pnk…
Browse files Browse the repository at this point in the history
…felix

user annotations in patterns

Fixes #54573

r? @pnkfelix
  • Loading branch information
bors committed Oct 9, 2018
2 parents 607243b + ccba716 commit e1643a8
Show file tree
Hide file tree
Showing 18 changed files with 387 additions and 77 deletions.
6 changes: 3 additions & 3 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ macro_rules! make_mir_visitor {
self.super_ty(ty);
}

fn visit_canonical_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
fn visit_user_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
self.super_canonical_ty(ty);
}

Expand Down Expand Up @@ -640,7 +640,7 @@ macro_rules! make_mir_visitor {
c_ty: & $($mutability)* CanonicalTy<'tcx>,
location: Location) {
self.visit_place(place, PlaceContext::Validate, location);
self.visit_canonical_ty(c_ty);
self.visit_user_ty(c_ty);
}

fn super_place(&mut self,
Expand Down Expand Up @@ -736,7 +736,7 @@ macro_rules! make_mir_visitor {
source_info: *source_info,
});
if let Some(user_ty) = user_ty {
self.visit_canonical_ty(user_ty);
self.visit_user_ty(user_ty);
}
self.visit_source_info(source_info);
self.visit_source_scope(visibility_scope);
Expand Down
23 changes: 9 additions & 14 deletions src/librustc_mir/borrow_check/nll/renumber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
use rustc::mir::{BasicBlock, Location, Mir, Place, Statement, StatementKind};
use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};

Expand Down Expand Up @@ -65,6 +65,14 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
debug!("visit_ty: ty={:?}", ty);
}

fn visit_user_ty(&mut self, _ty: &mut CanonicalTy<'tcx>) {
// `user_ty` annotations represent the types that the user
// wrote in the progarm. We don't want to erase the regions
// from these types: rather, we want to add them as
// constraints at type-check time.
debug!("visit_user_ty: skipping renumber");
}

fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
debug!("visit_substs(substs={:?}, location={:?})", substs, location);

Expand Down Expand Up @@ -112,19 +120,6 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
debug!("visit_closure_substs: substs={:?}", substs);
}

fn visit_ascribe_user_ty(
&mut self,
_place: &mut Place<'tcx>,
_variance: &mut ty::Variance,
_c_ty: &mut CanonicalTy<'tcx>,
_location: Location,
) {
// User-assert-ty statements represent types that the user added explicitly.
// We don't want to erase the regions from these types: rather, we want to
// add them as constraints at type-check time.
debug!("visit_user_assert_ty: skipping renumber");
}

fn visit_statement(
&mut self,
block: BasicBlock,
Expand Down
8 changes: 8 additions & 0 deletions src/librustc_mir/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
) {
for ascription in ascriptions {
let source_info = self.source_info(ascription.span);

debug!(
"adding user ascription at span {:?} of place {:?} and {:?}",
source_info.span,
ascription.source,
ascription.user_ty,
);

self.cfg.push(
block,
Statement {
Expand Down
46 changes: 8 additions & 38 deletions src/librustc_mir/hair/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use rustc_data_structures::indexed_vec::Idx;
use hair::cx::Cx;
use hair::cx::block;
use hair::cx::to_ref::ToRef;
use hair::util::UserAnnotatedTyHelpers;
use rustc::hir::def::{Def, CtorKind};
use rustc::mir::interpret::GlobalId;
use rustc::ty::{self, AdtKind, Ty};
Expand Down Expand Up @@ -475,7 +476,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
adt_def: adt,
variant_index: 0,
substs,
user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt),
user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
fields: field_refs(cx, fields),
base: base.as_ref().map(|base| {
FruInfo {
Expand All @@ -501,7 +502,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
adt_def: adt,
variant_index: index,
substs,
user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt),
user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
fields: field_refs(cx, fields),
base: None,
}
Expand Down Expand Up @@ -787,48 +788,17 @@ fn user_annotated_ty_for_def(
// user.
Def::StructCtor(_def_id, CtorKind::Const) |
Def::VariantCtor(_def_id, CtorKind::Const) =>
match &cx.tables().node_id_to_type(hir_id).sty {
ty::Adt(adt_def, _) => user_annotated_ty_for_adt(cx, hir_id, adt_def),
sty => bug!("unexpected sty: {:?}", sty),
},
cx.user_substs_applied_to_ty_of_hir_id(hir_id),

// `Self` is used in expression as a tuple struct constructor or an unit struct constructor
Def::SelfCtor(_) => {
let sty = &cx.tables().node_id_to_type(hir_id).sty;
match sty {
ty::FnDef(ref def_id, _) => {
Some(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| {
// Here, we just pair a `DefId` with the
// `user_substs`, so no new types etc are introduced.
cx.tcx().mk_fn_def(*def_id, user_substs)
}))
}
ty::Adt(ref adt_def, _) => {
user_annotated_ty_for_adt(cx, hir_id, adt_def)
}
_ => {
bug!("unexpected sty: {:?}", sty)
}
}
}
Def::SelfCtor(_) =>
cx.user_substs_applied_to_ty_of_hir_id(hir_id),

_ =>
bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id)
}
}

fn user_annotated_ty_for_adt(
cx: &mut Cx<'a, 'gcx, 'tcx>,
hir_id: hir::HirId,
adt_def: &'tcx AdtDef,
) -> Option<CanonicalTy<'tcx>> {
let user_substs = cx.tables().user_substs(hir_id)?;
Some(user_substs.unchecked_map(|user_substs| {
// Here, we just pair an `AdtDef` with the
// `user_substs`, so no new types etc are introduced.
cx.tcx().mk_adt(adt_def, user_substs)
}))
}

fn method_callee<'a, 'gcx, 'tcx>(
cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: &hir::Expr,
Expand Down Expand Up @@ -943,7 +913,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
adt_def,
variant_index: adt_def.variant_index_with_id(def_id),
substs,
user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt_def),
user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt_def),
fields: vec![],
base: None,
}
Expand Down
11 changes: 11 additions & 0 deletions src/librustc_mir/hair/cx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//!
use hair::*;
use hair::util::UserAnnotatedTyHelpers;

use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
Expand Down Expand Up @@ -272,6 +273,16 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
}
}

impl UserAnnotatedTyHelpers<'gcx, 'tcx> for Cx<'_, 'gcx, 'tcx> {
fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
self.tcx()
}

fn tables(&self) -> &ty::TypeckTables<'tcx> {
self.tables()
}
}

fn lint_level_for_hir_id(tcx: TyCtxt, mut id: ast::NodeId) -> ast::NodeId {
// Right now we insert a `with_ignore` node in the dep graph here to
// ignore the fact that `lint_levels` below depends on the entire crate.
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/hair/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub mod cx;
pub mod pattern;
pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};

mod util;

#[derive(Copy, Clone, Debug)]
pub enum LintLevel {
Inherited,
Expand Down
47 changes: 39 additions & 8 deletions src/librustc_mir/hair/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pub(crate) use self::check_match::check_match;

use const_eval::{const_field, const_variant_index};

use hair::util::UserAnnotatedTyHelpers;

use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
Expand Down Expand Up @@ -529,8 +531,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
field: Field::new(i),
pattern: self.lower_pattern(field),
})
.collect();
self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
.collect();

self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns)
}

PatKind::Struct(ref qpath, ref fields, _) => {
Expand All @@ -546,7 +549,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
})
.collect();

self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns)
}
};

Expand Down Expand Up @@ -637,12 +640,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
fn lower_variant_or_leaf(
&mut self,
def: Def,
hir_id: hir::HirId,
span: Span,
ty: Ty<'tcx>,
subpatterns: Vec<FieldPattern<'tcx>>)
-> PatternKind<'tcx>
{
match def {
subpatterns: Vec<FieldPattern<'tcx>>,
) -> PatternKind<'tcx> {
let mut kind = match def {
Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
let adt_def = self.tcx.adt_def(enum_id);
Expand Down Expand Up @@ -675,7 +678,24 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
self.errors.push(PatternError::NonConstPath(span));
PatternKind::Wild
}
};

if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
let subpattern = Pattern {
span,
ty,
kind: Box::new(kind),
};

debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span);

kind = PatternKind::AscribeUserType {
subpattern,
user_ty,
};
}

kind
}

/// Takes a HIR Path. If the path is a constant, evaluates it and feeds
Expand Down Expand Up @@ -729,7 +749,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
},
}
}
_ => self.lower_variant_or_leaf(def, span, ty, vec![]),
_ => self.lower_variant_or_leaf(def, id, span, ty, vec![]),
};

Pattern {
Expand Down Expand Up @@ -894,6 +914,17 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}
}

impl UserAnnotatedTyHelpers<'tcx, 'tcx> for PatternContext<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'_, 'tcx, 'tcx> {
self.tcx
}

fn tables(&self) -> &ty::TypeckTables<'tcx> {
self.tables
}
}


pub trait PatternFoldable<'tcx> : Sized {
fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
self.super_fold_with(folder)
Expand Down
56 changes: 56 additions & 0 deletions src/librustc_mir/hair/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2016 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.

use rustc::hir;
use rustc::ty::{self, AdtDef, CanonicalTy, TyCtxt};

crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>;

fn tables(&self) -> &ty::TypeckTables<'tcx>;

fn user_substs_applied_to_adt(
&self,
hir_id: hir::HirId,
adt_def: &'tcx AdtDef,
) -> Option<CanonicalTy<'tcx>> {
let user_substs = self.tables().user_substs(hir_id)?;
Some(user_substs.unchecked_map(|user_substs| {
// Here, we just pair an `AdtDef` with the
// `user_substs`, so no new types etc are introduced.
self.tcx().mk_adt(adt_def, user_substs)
}))
}

/// Looks up the type associated with this hir-id and applies the
/// user-given substitutions; the hir-id must map to a suitable
/// type.
fn user_substs_applied_to_ty_of_hir_id(&self, hir_id: hir::HirId) -> Option<CanonicalTy<'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(user_substs.unchecked_map(|user_substs| {
// Ok to call `unchecked_map` because we just pair an
// `AdtDef` with the `user_substs`, so no new types
// etc are introduced.
self.tcx().mk_adt(adt_def, user_substs)
})),
ty::FnDef(def_id, _) => Some(user_substs.unchecked_map(|user_substs| {
// Here, we just pair a `DefId` with the
// `user_substs`, so no new types etc are introduced.
self.tcx().mk_fn_def(*def_id, user_substs)
})),
sty => bug!(
"sty: {:?} should not have user-substs {:?} recorded ",
sty,
user_substs
),
}
}
}
Loading

0 comments on commit e1643a8

Please sign in to comment.