Skip to content

Commit b9b82fd

Browse files
committed
Auto merge of #46054 - nikomatsakis:nll-master-to-rust-master-1, r=arielb1
typeck aggregate rvalues in MIR type checker This branch is an attempt to land content by @spastorino and @Nashenas88 that was initially landed on nll-master while we waited for #45825 to land. The biggest change it contains is that it extends the MIR type-checker to also type-check MIR aggregate rvalues (at least partially). Specifically, it checks that the operands provided for each field have the right type. It does not yet check that their well-formedness predicates are met. That is #45827. It also does not check other kinds of rvalues (that is #45959). @spastorino is working on those issues now. r? @arielb1
2 parents 247d98e + c52e51d commit b9b82fd

File tree

9 files changed

+169
-37
lines changed

9 files changed

+169
-37
lines changed

src/librustc/infer/lexical_region_resolve/mod.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
171171
for (r, vid) in seeds {
172172
// While all things transitively reachable in the graph
173173
// from the variable (`'0` in the example above).
174-
let seed_index = NodeIndex(vid.index as usize);
174+
let seed_index = NodeIndex(vid.index() as usize);
175175
for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
176176
let succ_index = succ_index.0;
177177

@@ -512,16 +512,16 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
512512
match *constraint {
513513
Constraint::VarSubVar(a_id, b_id) => {
514514
graph.add_edge(
515-
NodeIndex(a_id.index as usize),
516-
NodeIndex(b_id.index as usize),
515+
NodeIndex(a_id.index() as usize),
516+
NodeIndex(b_id.index() as usize),
517517
*constraint,
518518
);
519519
}
520520
Constraint::RegSubVar(_, b_id) => {
521-
graph.add_edge(dummy_source, NodeIndex(b_id.index as usize), *constraint);
521+
graph.add_edge(dummy_source, NodeIndex(b_id.index() as usize), *constraint);
522522
}
523523
Constraint::VarSubReg(a_id, _) => {
524-
graph.add_edge(NodeIndex(a_id.index as usize), dummy_sink, *constraint);
524+
graph.add_edge(NodeIndex(a_id.index() as usize), dummy_sink, *constraint);
525525
}
526526
Constraint::RegSubReg(..) => {
527527
// this would be an edge from `dummy_source` to
@@ -630,9 +630,9 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
630630
let node_idx = state.stack.pop().unwrap();
631631

632632
// check whether we've visited this node on some previous walk
633-
if dup_vec[node_idx.index as usize] == u32::MAX {
634-
dup_vec[node_idx.index as usize] = orig_node_idx.index;
635-
} else if dup_vec[node_idx.index as usize] != orig_node_idx.index {
633+
if dup_vec[node_idx.index() as usize] == u32::MAX {
634+
dup_vec[node_idx.index() as usize] = orig_node_idx.index() as u32;
635+
} else if dup_vec[node_idx.index() as usize] != orig_node_idx.index() as u32 {
636636
state.dup_found = true;
637637
}
638638

@@ -659,7 +659,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
659659
) {
660660
debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
661661

662-
let source_node_index = NodeIndex(source_vid.index as usize);
662+
let source_node_index = NodeIndex(source_vid.index() as usize);
663663
for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
664664
match edge.data {
665665
Constraint::VarSubVar(from_vid, to_vid) => {

src/librustc/infer/region_constraints/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use self::CombineMapType::*;
1616
use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin};
1717
use super::unify_key;
1818

19-
use rustc_data_structures::indexed_vec::IndexVec;
19+
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
2020
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2121
use rustc_data_structures::unify::{self, UnificationTable};
2222
use ty::{self, Ty, TyCtxt};
@@ -404,7 +404,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
404404
}
405405
AddVar(vid) => {
406406
self.var_origins.pop().unwrap();
407-
assert_eq!(self.var_origins.len(), vid.index as usize);
407+
assert_eq!(self.var_origins.len(), vid.index() as usize);
408408
}
409409
AddConstraint(ref constraint) => {
410410
self.data.constraints.remove(constraint);

src/librustc/infer/unify_key.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub struct RegionVidKey {
3333

3434
impl Combine for RegionVidKey {
3535
fn combine(&self, other: &RegionVidKey) -> RegionVidKey {
36-
let min_vid = if self.min_vid.index < other.min_vid.index {
36+
let min_vid = if self.min_vid.index() < other.min_vid.index() {
3737
self.min_vid
3838
} else {
3939
other.min_vid
@@ -45,8 +45,8 @@ impl Combine for RegionVidKey {
4545

4646
impl UnifyKey for ty::RegionVid {
4747
type Value = RegionVidKey;
48-
fn index(&self) -> u32 { self.index }
49-
fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid { index: i } }
48+
fn index(&self) -> u32 { self.0 }
49+
fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid(i) }
5050
fn tag(_: Option<ty::RegionVid>) -> &'static str { "RegionVid" }
5151
}
5252

src/librustc/mir/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -1375,10 +1375,14 @@ pub enum AggregateKind<'tcx> {
13751375
/// The type is of the element
13761376
Array(Ty<'tcx>),
13771377
Tuple,
1378-
/// The second field is variant number (discriminant), it's equal to 0
1379-
/// for struct and union expressions. The fourth field is active field
1380-
/// number and is present only for union expressions.
1378+
1379+
/// The second field is variant number (discriminant), it's equal
1380+
/// to 0 for struct and union expressions. The fourth field is
1381+
/// active field number and is present only for union expressions
1382+
/// -- e.g. for a union expression `SomeUnion { c: .. }`, the
1383+
/// active field index would identity the field `c`
13811384
Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<usize>),
1385+
13821386
Closure(DefId, ClosureSubsts<'tcx>),
13831387
Generator(DefId, ClosureSubsts<'tcx>, GeneratorInterior<'tcx>),
13841388
}

src/librustc/ty/sty.rs

+5-16
Original file line numberDiff line numberDiff line change
@@ -998,22 +998,11 @@ pub struct FloatVid {
998998
pub index: u32,
999999
}
10001000

1001-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy, PartialOrd, Ord)]
1002-
pub struct RegionVid {
1003-
pub index: u32,
1004-
}
1005-
1006-
// FIXME: We could convert this to use `newtype_index!`
1007-
impl Idx for RegionVid {
1008-
fn new(value: usize) -> Self {
1009-
assert!(value < ::std::u32::MAX as usize);
1010-
RegionVid { index: value as u32 }
1011-
}
1012-
1013-
fn index(self) -> usize {
1014-
self.index as usize
1015-
}
1016-
}
1001+
newtype_index!(RegionVid
1002+
{
1003+
pub idx
1004+
DEBUG_FORMAT = custom,
1005+
});
10171006

10181007
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)]
10191008
pub struct SkolemizedRegionVid {

src/librustc/util/ppaux.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ define_print! {
726726
}
727727
}
728728
ty::ReVar(region_vid) if cx.identify_regions => {
729-
write!(f, "'{}rv", region_vid.index)
729+
write!(f, "'{}rv", region_vid.index())
730730
}
731731
ty::ReScope(_) |
732732
ty::ReVar(_) |
@@ -850,7 +850,7 @@ impl fmt::Debug for ty::FloatVid {
850850

851851
impl fmt::Debug for ty::RegionVid {
852852
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
853-
write!(f, "'_#{}r", self.index)
853+
write!(f, "'_#{}r", self.index())
854854
}
855855
}
856856

src/librustc_mir/shim.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -825,10 +825,16 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
825825
-> Mir<'tcx>
826826
{
827827
let tcx = infcx.tcx;
828+
let gcx = tcx.global_tcx();
828829
let def_id = tcx.hir.local_def_id(ctor_id);
829-
let sig = tcx.no_late_bound_regions(&tcx.fn_sig(def_id))
830+
let sig = gcx.no_late_bound_regions(&gcx.fn_sig(def_id))
830831
.expect("LBR in ADT constructor signature");
831-
let sig = tcx.erase_regions(&sig);
832+
let sig = gcx.erase_regions(&sig);
833+
let param_env = gcx.param_env(def_id);
834+
835+
// Normalize the sig now that we have liberated the late-bound
836+
// regions.
837+
let sig = gcx.normalize_associated_type_in_env(&sig, param_env);
832838

833839
let (adt_def, substs) = match sig.output().sty {
834840
ty::TyAdt(adt_def, substs) => (adt_def, substs),

src/librustc_mir/transform/type_check.rs

+106
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
549549
terr
550550
);
551551
}
552+
self.check_rvalue(mir, rv, location);
552553
}
553554
StatementKind::SetDiscriminant {
554555
ref lvalue,
@@ -1011,6 +1012,111 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
10111012
}
10121013
}
10131014

1015+
fn aggregate_field_ty(
1016+
&mut self,
1017+
ak: &Box<AggregateKind<'tcx>>,
1018+
field_index: usize,
1019+
location: Location,
1020+
) -> Result<Ty<'tcx>, FieldAccessError> {
1021+
let tcx = self.tcx();
1022+
1023+
match **ak {
1024+
AggregateKind::Adt(def, variant_index, substs, active_field_index) => {
1025+
let variant = &def.variants[variant_index];
1026+
let adj_field_index = active_field_index.unwrap_or(field_index);
1027+
if let Some(field) = variant.fields.get(adj_field_index) {
1028+
Ok(self.normalize(&field.ty(tcx, substs), location))
1029+
} else {
1030+
Err(FieldAccessError::OutOfRange {
1031+
field_count: variant.fields.len(),
1032+
})
1033+
}
1034+
}
1035+
AggregateKind::Closure(def_id, substs) => {
1036+
match substs.upvar_tys(def_id, tcx).nth(field_index) {
1037+
Some(ty) => Ok(ty),
1038+
None => Err(FieldAccessError::OutOfRange {
1039+
field_count: substs.upvar_tys(def_id, tcx).count(),
1040+
}),
1041+
}
1042+
}
1043+
AggregateKind::Generator(def_id, substs, _) => {
1044+
if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field_index) {
1045+
Ok(ty)
1046+
} else {
1047+
match substs.field_tys(def_id, tcx).nth(field_index) {
1048+
Some(ty) => Ok(ty),
1049+
None => Err(FieldAccessError::OutOfRange {
1050+
field_count: substs.field_tys(def_id, tcx).count() + 1,
1051+
}),
1052+
}
1053+
}
1054+
}
1055+
AggregateKind::Array(ty) => {
1056+
Ok(ty)
1057+
}
1058+
AggregateKind::Tuple => {
1059+
unreachable!("This should have been covered in check_rvalues");
1060+
}
1061+
}
1062+
}
1063+
1064+
fn check_rvalue(&mut self, mir: &Mir<'tcx>, rv: &Rvalue<'tcx>, location: Location) {
1065+
let tcx = self.tcx();
1066+
match rv {
1067+
Rvalue::Aggregate(ak, ops) => {
1068+
match **ak {
1069+
// tuple rvalue field type is always the type of the op. Nothing to check here.
1070+
AggregateKind::Tuple => {}
1071+
_ => {
1072+
for (i, op) in ops.iter().enumerate() {
1073+
let field_ty = match self.aggregate_field_ty(ak, i, location) {
1074+
Ok(field_ty) => field_ty,
1075+
Err(FieldAccessError::OutOfRange { field_count }) => {
1076+
span_mirbug!(
1077+
self,
1078+
rv,
1079+
"accessed field #{} but variant only has {}",
1080+
i,
1081+
field_count
1082+
);
1083+
continue;
1084+
}
1085+
};
1086+
let op_ty = op.ty(mir, tcx);
1087+
if let Err(terr) = self.sub_types(
1088+
op_ty,
1089+
field_ty,
1090+
location.at_successor_within_block(),
1091+
)
1092+
{
1093+
span_mirbug!(
1094+
self,
1095+
rv,
1096+
"{:?} is not a subtype of {:?}: {:?}",
1097+
op_ty,
1098+
field_ty,
1099+
terr
1100+
);
1101+
}
1102+
}
1103+
}
1104+
}
1105+
}
1106+
// FIXME: These other cases have to be implemented in future PRs
1107+
Rvalue::Use(..) |
1108+
Rvalue::Repeat(..) |
1109+
Rvalue::Ref(..) |
1110+
Rvalue::Len(..) |
1111+
Rvalue::Cast(..) |
1112+
Rvalue::BinaryOp(..) |
1113+
Rvalue::CheckedBinaryOp(..) |
1114+
Rvalue::UnaryOp(..) |
1115+
Rvalue::Discriminant(..) |
1116+
Rvalue::NullaryOp(..) => {}
1117+
}
1118+
}
1119+
10141120
fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
10151121
self.last_span = mir.span;
10161122
debug!("run_on_mir: {:?}", mir.span);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
//revisions: ast mir
11+
//[mir] compile-flags: -Z emit-end-regions -Z borrowck-mir -Z nll
12+
13+
#![allow(unused_assignments)]
14+
15+
struct Wrap<'a> { w: &'a mut u32 }
16+
17+
fn foo() {
18+
let mut x = 22;
19+
let wrapper = Wrap { w: &mut x };
20+
x += 1; //[ast]~ ERROR cannot assign to `x` because it is borrowed [E0506]
21+
//[mir]~^ ERROR cannot assign to `x` because it is borrowed (Ast) [E0506]
22+
//[mir]~^^ ERROR cannot assign to `x` because it is borrowed (Mir) [E0506]
23+
//[mir]~^^^ ERROR cannot use `x` because it was mutably borrowed (Mir) [E0503]
24+
*wrapper.w += 1;
25+
}
26+
27+
fn main() { }

0 commit comments

Comments
 (0)