Skip to content

Commit 19c1736

Browse files
Nashenas88nikomatsakis
authored andcommitted
Check rvalue aggregates during check_stmt in tycheck, add initial, (not passing) test
1 parent 4fecccb commit 19c1736

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

src/librustc_mir/transform/type_check.rs

Lines changed: 86 additions & 0 deletions
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,91 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
10111012
}
10121013
}
10131014

1015+
fn aggregate_field_ty(&mut self, ak: &Box<AggregateKind<'tcx>>, field: usize, location: Location)
1016+
-> Result<Ty<'tcx>, FieldAccessError>
1017+
{
1018+
let tcx = self.tcx();
1019+
1020+
let (variant, substs) = match **ak {
1021+
AggregateKind::Adt(def, variant, substs, _) => { // handle unions?
1022+
(&def.variants[variant], substs)
1023+
},
1024+
AggregateKind::Closure(def_id, substs) => {
1025+
return match substs.upvar_tys(def_id, tcx).nth(field) {
1026+
Some(ty) => Ok(ty),
1027+
None => Err(FieldAccessError::OutOfRange {
1028+
field_count: substs.upvar_tys(def_id, tcx).count()
1029+
}),
1030+
}
1031+
},
1032+
AggregateKind::Generator(def_id, substs, _) => {
1033+
if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field) {
1034+
return Ok(ty);
1035+
}
1036+
1037+
return match substs.field_tys(def_id, tcx).nth(field) {
1038+
Some(ty) => Ok(ty),
1039+
None => Err(FieldAccessError::OutOfRange {
1040+
field_count: substs.field_tys(def_id, tcx).count() + 1
1041+
}),
1042+
}
1043+
},
1044+
AggregateKind::Array(ty) => {
1045+
return Ok(ty);
1046+
},
1047+
AggregateKind::Tuple => {
1048+
unreachable!("This should have been covered in check_rvalues");
1049+
},
1050+
};
1051+
1052+
if let Some(field) = variant.fields.get(field) {
1053+
Ok(self.normalize(&field.ty(tcx, substs), location))
1054+
} else {
1055+
Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
1056+
}
1057+
}
1058+
1059+
#[allow(dead_code)]
1060+
fn check_rvalue(&mut self, mir: &Mir<'tcx>, rv: &Rvalue<'tcx>, location: Location) {
1061+
let tcx = self.tcx();
1062+
match rv {
1063+
Rvalue::Aggregate(ref ak, ref ops) => {
1064+
match **ak {
1065+
// tuple rvalue field type is always the type of the op. Nothing to check here.
1066+
AggregateKind::Tuple => { },
1067+
_ => {
1068+
for (i, op) in ops.iter().enumerate() {
1069+
let field_ty = if let Ok(field_ty) = self.aggregate_field_ty(ak, i, location) {
1070+
field_ty
1071+
} else {
1072+
// TODO(nashenas88) log span_mirbug terr??
1073+
continue;
1074+
};
1075+
let op_ty = match op {
1076+
Operand::Consume(lv) => lv.ty(mir, tcx).to_ty(tcx),
1077+
Operand::Constant(c) => c.ty,
1078+
};
1079+
if let Err(_terr) = self.sub_types(op_ty, field_ty, location.at_successor_within_block()) {
1080+
// TODO(nashenas88) log span_mirbug terr??
1081+
}
1082+
}
1083+
},
1084+
}
1085+
},
1086+
// FIXME: These other cases have to be implemented in future PRs
1087+
Rvalue::Use(..) |
1088+
Rvalue::Repeat(..) |
1089+
Rvalue::Ref(..) |
1090+
Rvalue::Len(..) |
1091+
Rvalue::Cast(..) |
1092+
Rvalue::BinaryOp(..) |
1093+
Rvalue::CheckedBinaryOp(..) |
1094+
Rvalue::UnaryOp(..) |
1095+
Rvalue::Discriminant(..) |
1096+
Rvalue::NullaryOp(..) => { }
1097+
}
1098+
}
1099+
10141100
fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
10151101
self.last_span = mir.span;
10161102
debug!("run_on_mir: {:?}", mir.span);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
//compile-flags: -Z emit-end-regions -Z borrowck-mir -Z mir
11+
12+
#![allow(unused_assignments)]
13+
14+
struct Wrap<'a> { w: &'a mut u32 }
15+
16+
fn foo() {
17+
let mut x = 22u64;
18+
let wrapper = Wrap { w: &mut x };
19+
x += 1; //~ ERROR cannot assign to `x`
20+
*wrapper.w += 1;
21+
}
22+
23+
fn main() { }

0 commit comments

Comments
 (0)