use borrow_check::nll::region_infer::values::{RegionValueElements, LivenessValues};
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
+use borrow_check::nll::type_check::liveness::liveness_map::NllLivenessMap;
use borrow_check::nll::universal_regions::UniversalRegions;
use borrow_check::nll::LocalWithRegion;
use borrow_check::nll::ToRegionVid;
use rustc::traits::query::type_op;
use rustc::traits::query::{Fallible, NoSolution};
use rustc::ty::fold::TypeFoldable;
-use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
+use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
use rustc_errors::Diagnostic;
use std::fmt;
use std::rc::Rc;
mod constraint_conversion;
pub mod free_region_relations;
mod input_output;
-mod liveness;
+crate mod liveness;
mod relate_tys;
/// Type checks the given `mir` in the context of the inference
universal_regions: &Rc<UniversalRegions<'tcx>>,
location_table: &LocationTable,
borrow_set: &BorrowSet<'tcx>,
- liveness: &LivenessResults<LocalWithRegion>,
all_facts: &mut Option<AllFacts>,
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
elements: &Rc<RegionValueElements>,
errors_buffer: &mut Vec<Diagnostic>,
-) -> (
- MirTypeckRegionConstraints<'tcx>,
- Rc<UniversalRegionRelations<'tcx>>,
-) {
+) -> MirTypeckResults<'tcx> {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
let mut constraints = MirTypeckRegionConstraints {
liveness_constraints: LivenessValues::new(elements),
all_facts,
);
- {
+ let (liveness, liveness_map) = {
let mut borrowck_context = BorrowCheckContext {
universal_regions,
location_table,
Some(&mut borrowck_context),
Some(errors_buffer),
|cx| {
- liveness::generate(cx, mir, liveness, flow_inits, move_data);
cx.equate_inputs_and_outputs(
mir,
mir_def_id,
&universal_region_relations,
&normalized_inputs_and_output,
);
+ liveness::generate(cx, mir, flow_inits, move_data)
},
- );
- }
+ )
+ };
- (constraints, universal_region_relations)
+ MirTypeckResults {
+ constraints,
+ universal_region_relations,
+ liveness,
+ liveness_map,
+ }
}
-fn type_check_internal<'a, 'gcx, 'tcx, F>(
+fn type_check_internal<'a, 'gcx, 'tcx, R>(
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
mir_def_id: DefId,
param_env: ty::ParamEnv<'gcx>,
implicit_region_bound: Option<ty::Region<'tcx>>,
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
errors_buffer: Option<&mut Vec<Diagnostic>>,
- mut extra: F,
-) where
- F: FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>),
-{
+ mut extra: impl FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) -> R,
+) -> R where {
let mut checker = TypeChecker::new(
infcx,
mir,
checker.typeck_mir(mir, errors_buffer);
}
- extra(&mut checker);
+ extra(&mut checker)
}
fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
// constraints on `'a` and `'b`. These constraints
// would be lost if we just look at the normalized
// value.
- if let ty::TyFnDef(def_id, substs) = constant.literal.ty.sty {
+ if let ty::FnDef(def_id, substs) = constant.literal.ty.sty {
let tcx = self.tcx();
let type_checker = &mut self.cx;
}
ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
ty: match base_ty.sty {
- ty::TyArray(inner, size) => {
+ ty::Array(inner, size) => {
let size = size.unwrap_usize(tcx);
let min_size = (from as u64) + (to as u64);
if let Some(rest_size) = size.checked_sub(min_size) {
)
}
}
- ty::TySlice(..) => base_ty,
+ ty::Slice(..) => base_ty,
_ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty),
},
},
ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty {
- ty::TyAdt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => {
+ ty::Adt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => {
if index >= adt_def.variants.len() {
PlaceTy::Ty {
ty: span_mirbug_and_err!(
variant_index,
} => (&adt_def.variants[variant_index], substs),
PlaceTy::Ty { ty } => match ty.sty {
- ty::TyAdt(adt_def, substs) if !adt_def.is_enum() => (&adt_def.variants[0], substs),
- ty::TyClosure(def_id, substs) => {
+ ty::Adt(adt_def, substs) if !adt_def.is_enum() => (&adt_def.variants[0], substs),
+ ty::Closure(def_id, substs) => {
return match substs.upvar_tys(def_id, tcx).nth(field.index()) {
Some(ty) => Ok(ty),
None => Err(FieldAccessError::OutOfRange {
}),
}
}
- ty::TyGenerator(def_id, substs, _) => {
+ ty::Generator(def_id, substs, _) => {
// Try pre-transform fields first (upvars and current state)
if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field.index()) {
return Ok(ty);
}),
};
}
- ty::TyTuple(tys) => {
+ ty::Tuple(tys) => {
return match tys.get(field.index()) {
Some(&ty) => Ok(ty),
None => Err(FieldAccessError::OutOfRange {
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
}
+crate struct MirTypeckResults<'tcx> {
+ crate constraints: MirTypeckRegionConstraints<'tcx>,
+ crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
+ crate liveness: LivenessResults<LocalWithRegion>,
+ crate liveness_map: NllLivenessMap,
+}
+
/// A collection of region constraints that must be satisfied for the
/// program to be considered well-typed.
crate struct MirTypeckRegionConstraints<'tcx> {
/// predicates, or otherwise uses the inference context, executes
/// `op` and then executes all the further obligations that `op`
/// returns. This will yield a set of outlives constraints amongst
- /// regions which are extracted and stored as having occured at
+ /// regions which are extracted and stored as having occurred at
/// `locations`.
///
/// **Any `rustc::infer` operations that might generate region
// they are not caused by the user, but rather artifacts
// of lowering. Assignments to other sorts of places *are* interesting
// though.
- let is_temp = if let Place::Local(l) = place {
- !mir.local_decls[*l].is_user_variable.is_some()
+ let is_temp = if let Place::Local(l) = *place {
+ l != RETURN_PLACE &&
+ !mir.local_decls[l].is_user_variable.is_some()
} else {
false
};
);
}
self.check_rvalue(mir, rv, location);
- let trait_ref = ty::TraitRef {
- def_id: tcx.lang_items().sized_trait().unwrap(),
- substs: tcx.mk_substs_trait(place_ty, &[]),
- };
- self.prove_trait_ref(trait_ref, location.interesting());
+ if !self.tcx().features().unsized_locals {
+ let trait_ref = ty::TraitRef {
+ def_id: tcx.lang_items().sized_trait().unwrap(),
+ substs: tcx.mk_substs_trait(place_ty, &[]),
+ };
+ self.prove_trait_ref(trait_ref, location.interesting());
+ }
}
StatementKind::SetDiscriminant {
ref place,
} => {
let place_type = place.ty(mir, tcx).to_ty(tcx);
let adt = match place_type.sty {
- TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt,
+ TyKind::Adt(adt, _) if adt.is_enum() => adt,
_ => {
span_bug!(
stmt.source_info.span,
mir: &Mir<'tcx>,
term: &Terminator<'tcx>,
term_location: Location,
+ errors_buffer: &mut Option<&mut Vec<Diagnostic>>,
) {
debug!("check_terminator: {:?}", term);
let tcx = self.tcx();
let func_ty = func.ty(mir, tcx);
debug!("check_terminator: call, func_ty={:?}", func_ty);
let sig = match func_ty.sty {
- ty::TyFnDef(..) | ty::TyFnPtr(_) => func_ty.fn_sig(tcx),
+ ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx),
_ => {
span_mirbug!(self, term, "call to non-function {:?}", func_ty);
return;
&sig,
);
let sig = self.normalize(sig, term_location);
- self.check_call_dest(mir, term, &sig, destination, term_location);
+ self.check_call_dest(mir, term, &sig, destination, term_location, errors_buffer);
self.prove_predicates(
sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)),
sig: &ty::FnSig<'tcx>,
destination: &Option<(Place<'tcx>, BasicBlock)>,
term_location: Location,
+ errors_buffer: &mut Option<&mut Vec<Diagnostic>>,
) {
let tcx = self.tcx();
match *destination {
Some((ref dest, _target_block)) => {
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
- let locations = term_location.interesting();
+ let is_temp = if let Place::Local(l) = *dest {
+ l != RETURN_PLACE &&
+ !mir.local_decls[l].is_user_variable.is_some()
+ } else {
+ false
+ };
+
+ let locations = if is_temp {
+ term_location.boring()
+ } else {
+ term_location.interesting()
+ };
+
if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) {
span_mirbug!(
self,
terr
);
}
+
+ // When `#![feature(unsized_locals)]` is not enabled,
+ // this check is done at `check_local`.
+ if self.tcx().features().unsized_locals {
+ let span = term.source_info.span;
+ self.ensure_place_sized(dest_ty, span, errors_buffer);
+ }
}
None => {
// FIXME(canndrew): This is_never should probably be an is_uninhabited
LocalKind::Var | LocalKind::Temp => {}
}
- let span = local_decl.source_info.span;
- let ty = local_decl.ty;
+ // When `#![feature(unsized_locals)]` is enabled, only function calls
+ // are checked in `check_call_dest`.
+ if !self.tcx().features().unsized_locals {
+ let span = local_decl.source_info.span;
+ let ty = local_decl.ty;
+ self.ensure_place_sized(ty, span, errors_buffer);
+ }
+ }
+
+ fn ensure_place_sized(&mut self,
+ ty: Ty<'tcx>,
+ span: Span,
+ errors_buffer: &mut Option<&mut Vec<Diagnostic>>) {
+ let tcx = self.tcx();
// Erase the regions from `ty` to get a global type. The
// `Sized` bound in no way depends on precise regions, so this
// shouldn't affect `is_sized`.
- let gcx = self.tcx().global_tcx();
- let erased_ty = gcx.lift(&self.tcx().erase_regions(&ty)).unwrap();
+ let gcx = tcx.global_tcx();
+ let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap();
if !erased_ty.is_sized(gcx.at(span), self.param_env) {
// in current MIR construction, all non-control-flow rvalue
// expressions evaluate through `as_temp` or `into` a return
CastKind::ClosureFnPointer => {
let sig = match op.ty(mir, tcx).sty {
- ty::TyClosure(def_id, substs) => {
+ ty::Closure(def_id, substs) => {
substs.closure_sig_ty(def_id, tcx).fn_sig(tcx)
}
_ => bug!(),
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
match base_ty.sty {
- ty::TyRef(ref_region, _, mutbl) => {
+ ty::Ref(ref_region, _, mutbl) => {
constraints.outlives_constraints.push(OutlivesConstraint {
sup: ref_region.to_region_vid(),
sub: borrow_region.to_region_vid(),
}
}
}
- ty::TyRawPtr(..) => {
+ ty::RawPtr(..) => {
// deref of raw pointer, guaranteed to be valid
break;
}
- ty::TyAdt(def, _) if def.is_box() => {
+ ty::Adt(def, _) if def.is_box() => {
// deref of `Box`, need the base to be valid - propagate
}
_ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place),
location.statement_index += 1;
}
- self.check_terminator(mir, block_data.terminator(), location);
+ self.check_terminator(mir, block_data.terminator(), location, &mut errors_buffer);
self.check_iscleanup(mir, block_data);
}
}