connect NLL type checker to the impl trait code
We now add the suitable `impl Trait` constraints.
This commit is contained in:
parent
da63aaa7ab
commit
93afb1affc
14 changed files with 339 additions and 38 deletions
|
@ -93,20 +93,34 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
/// Moreover, it returns a `AnonTypeMap` that would map `?0` to
|
/// Moreover, it returns a `AnonTypeMap` that would map `?0` to
|
||||||
/// info about the `impl Iterator<..>` type and `?1` to info about
|
/// info about the `impl Iterator<..>` type and `?1` to info about
|
||||||
/// the `impl Debug` type.
|
/// the `impl Debug` type.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// - `parent_def_id` -- we will only instantiate anonymous types
|
||||||
|
/// with this parent. This is typically the def-id of the function
|
||||||
|
/// in whose return type anon types are being instantiated.
|
||||||
|
/// - `body_id` -- the body-id with which the resulting obligations should
|
||||||
|
/// be associated
|
||||||
|
/// - `param_env` -- the in-scope parameter environment to be used for
|
||||||
|
/// obligations
|
||||||
|
/// - `value` -- the value within which we are instantiating anon types
|
||||||
pub fn instantiate_anon_types<T: TypeFoldable<'tcx>>(
|
pub fn instantiate_anon_types<T: TypeFoldable<'tcx>>(
|
||||||
&self,
|
&self,
|
||||||
|
parent_def_id: DefId,
|
||||||
body_id: ast::NodeId,
|
body_id: ast::NodeId,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
value: &T,
|
value: &T,
|
||||||
) -> InferOk<'tcx, (T, AnonTypeMap<'tcx>)> {
|
) -> InferOk<'tcx, (T, AnonTypeMap<'tcx>)> {
|
||||||
debug!(
|
debug!(
|
||||||
"instantiate_anon_types(value={:?}, body_id={:?}, param_env={:?})",
|
"instantiate_anon_types(value={:?}, parent_def_id={:?}, body_id={:?}, param_env={:?})",
|
||||||
value,
|
value,
|
||||||
|
parent_def_id,
|
||||||
body_id,
|
body_id,
|
||||||
param_env,
|
param_env,
|
||||||
);
|
);
|
||||||
let mut instantiator = Instantiator {
|
let mut instantiator = Instantiator {
|
||||||
infcx: self,
|
infcx: self,
|
||||||
|
parent_def_id,
|
||||||
body_id,
|
body_id,
|
||||||
param_env,
|
param_env,
|
||||||
anon_types: DefIdMap(),
|
anon_types: DefIdMap(),
|
||||||
|
@ -480,6 +494,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
parent_def_id: DefId,
|
||||||
body_id: ast::NodeId,
|
body_id: ast::NodeId,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
anon_types: AnonTypeMap<'tcx>,
|
anon_types: AnonTypeMap<'tcx>,
|
||||||
|
@ -489,11 +504,33 @@ struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||||
impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
||||||
fn instantiate_anon_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
|
fn instantiate_anon_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
|
||||||
debug!("instantiate_anon_types_in_map(value={:?})", value);
|
debug!("instantiate_anon_types_in_map(value={:?})", value);
|
||||||
|
let tcx = self.infcx.tcx;
|
||||||
value.fold_with(&mut BottomUpFolder {
|
value.fold_with(&mut BottomUpFolder {
|
||||||
tcx: self.infcx.tcx,
|
tcx,
|
||||||
fldop: |ty| if let ty::TyAnon(def_id, substs) = ty.sty {
|
fldop: |ty| {
|
||||||
self.fold_anon_ty(ty, def_id, substs)
|
if let ty::TyAnon(def_id, substs) = ty.sty {
|
||||||
} else {
|
// Check that this is `impl Trait` type is declared by
|
||||||
|
// `parent_def_id`. During the first phase of type-check, this
|
||||||
|
// is true, but during NLL type-check, we sometimes encounter
|
||||||
|
// `impl Trait` types in e.g. inferred closure signatures that
|
||||||
|
// are not 'local' to the current function and hence which
|
||||||
|
// ought not to be instantiated.
|
||||||
|
if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) {
|
||||||
|
let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
|
||||||
|
let anon_parent_def_id = tcx.hir.local_def_id(anon_parent_node_id);
|
||||||
|
if self.parent_def_id == anon_parent_def_id {
|
||||||
|
return self.fold_anon_ty(ty, def_id, substs);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("instantiate_anon_types_in_map: \
|
||||||
|
encountered anon with wrong parent \
|
||||||
|
def_id={:?} \
|
||||||
|
anon_parent_def_id={:?}",
|
||||||
|
def_id,
|
||||||
|
anon_parent_def_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ty
|
ty
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -865,6 +865,9 @@ impl fmt::Debug for ty::RegionVid {
|
||||||
define_print! {
|
define_print! {
|
||||||
() ty::InferTy, (self, f, cx) {
|
() ty::InferTy, (self, f, cx) {
|
||||||
display {
|
display {
|
||||||
|
if cx.is_verbose {
|
||||||
|
print!(f, cx, print_debug(self))
|
||||||
|
} else {
|
||||||
match *self {
|
match *self {
|
||||||
ty::TyVar(_) => write!(f, "_"),
|
ty::TyVar(_) => write!(f, "_"),
|
||||||
ty::IntVar(_) => write!(f, "{}", "{integer}"),
|
ty::IntVar(_) => write!(f, "{}", "{integer}"),
|
||||||
|
@ -874,6 +877,7 @@ define_print! {
|
||||||
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
|
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
debug {
|
debug {
|
||||||
match *self {
|
match *self {
|
||||||
ty::TyVar(ref v) => write!(f, "{:?}", v),
|
ty::TyVar(ref v) => write!(f, "{:?}", v),
|
||||||
|
|
|
@ -77,13 +77,12 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
||||||
Option<ClosureRegionRequirements<'gcx>>,
|
Option<ClosureRegionRequirements<'gcx>>,
|
||||||
) {
|
) {
|
||||||
// Run the MIR type-checker.
|
// Run the MIR type-checker.
|
||||||
let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
|
|
||||||
let liveness = &LivenessResults::compute(mir);
|
let liveness = &LivenessResults::compute(mir);
|
||||||
let constraint_sets = &type_check::type_check(
|
let constraint_sets = &type_check::type_check(
|
||||||
infcx,
|
infcx,
|
||||||
mir_node_id,
|
|
||||||
param_env,
|
param_env,
|
||||||
mir,
|
mir,
|
||||||
|
def_id,
|
||||||
&universal_regions,
|
&universal_regions,
|
||||||
&liveness,
|
&liveness,
|
||||||
flow_inits,
|
flow_inits,
|
||||||
|
|
|
@ -246,13 +246,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
.map(|origin| RegionDefinition::new(origin))
|
.map(|origin| RegionDefinition::new(origin))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let nll_dump_cause = ty::tls::with(|tcx| tcx.sess.opts.debugging_opts.nll_dump_cause);
|
||||||
|
|
||||||
let mut result = Self {
|
let mut result = Self {
|
||||||
definitions,
|
definitions,
|
||||||
elements: elements.clone(),
|
elements: elements.clone(),
|
||||||
liveness_constraints: RegionValues::new(
|
liveness_constraints: RegionValues::new(
|
||||||
elements,
|
elements,
|
||||||
num_region_variables,
|
num_region_variables,
|
||||||
TrackCauses(true),
|
TrackCauses(nll_dump_cause),
|
||||||
),
|
),
|
||||||
inferred_values: None,
|
inferred_values: None,
|
||||||
constraints: Vec::new(),
|
constraints: Vec::new(),
|
||||||
|
|
|
@ -16,7 +16,7 @@ use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||||
|
|
||||||
/// Replaces all free regions appearing in the MIR with fresh
|
/// Replaces all free regions appearing in the MIR with fresh
|
||||||
/// inference variables, returning the number of variables created.
|
/// inference variables, returning the number of variables created.
|
||||||
pub fn renumber_mir<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &mut Mir<'tcx>) {
|
pub fn renumber_mir<'tcx>(infcx: &InferCtxt<'_, '_, 'tcx>, mir: &mut Mir<'tcx>) {
|
||||||
debug!("renumber_mir()");
|
debug!("renumber_mir()");
|
||||||
debug!("renumber_mir: mir.arg_count={:?}", mir.arg_count);
|
debug!("renumber_mir: mir.arg_count={:?}", mir.arg_count);
|
||||||
|
|
||||||
|
@ -24,26 +24,36 @@ pub fn renumber_mir<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &mut
|
||||||
visitor.visit_mir(mir);
|
visitor.visit_mir(mir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replaces all regions appearing in `value` with fresh inference
|
||||||
|
/// variables.
|
||||||
|
pub fn renumber_regions<'tcx, T>(
|
||||||
|
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||||
|
ty_context: TyContext,
|
||||||
|
value: &T,
|
||||||
|
) -> T
|
||||||
|
where
|
||||||
|
T: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
debug!("renumber_regions(value={:?})", value);
|
||||||
|
|
||||||
|
infcx
|
||||||
|
.tcx
|
||||||
|
.fold_regions(value, &mut false, |_region, _depth| {
|
||||||
|
let origin = NLLRegionVariableOrigin::Inferred(ty_context);
|
||||||
|
infcx.next_nll_region_var(origin)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
|
||||||
/// Replaces all regions appearing in `value` with fresh inference
|
|
||||||
/// variables. This is what we do for almost the entire MIR, with
|
|
||||||
/// the exception of the declared types of our arguments.
|
|
||||||
fn renumber_regions<T>(&mut self, ty_context: TyContext, value: &T) -> T
|
fn renumber_regions<T>(&mut self, ty_context: TyContext, value: &T) -> T
|
||||||
where
|
where
|
||||||
T: TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
debug!("renumber_regions(value={:?})", value);
|
renumber_regions(self.infcx, ty_context, value)
|
||||||
|
|
||||||
self.infcx
|
|
||||||
.tcx
|
|
||||||
.fold_regions(value, &mut false, |_region, _depth| {
|
|
||||||
let origin = NLLRegionVariableOrigin::Inferred(ty_context);
|
|
||||||
self.infcx.next_nll_region_var(origin)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,15 @@
|
||||||
//! `RETURN_PLACE` the MIR arguments) are always fully normalize (and
|
//! `RETURN_PLACE` the MIR arguments) are always fully normalize (and
|
||||||
//! contain revealed `impl Trait` values).
|
//! contain revealed `impl Trait` values).
|
||||||
|
|
||||||
|
use borrow_check::nll::renumber;
|
||||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||||
|
use rustc::hir::def_id::DefId;
|
||||||
|
use rustc::infer::InferOk;
|
||||||
use rustc::ty::Ty;
|
use rustc::ty::Ty;
|
||||||
|
use rustc::ty::subst::Subst;
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
|
use rustc::mir::visit::TyContext;
|
||||||
|
use rustc::traits::PredicateObligations;
|
||||||
|
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
|
|
||||||
|
@ -29,13 +35,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
pub(super) fn equate_inputs_and_outputs(
|
pub(super) fn equate_inputs_and_outputs(
|
||||||
&mut self,
|
&mut self,
|
||||||
mir: &Mir<'tcx>,
|
mir: &Mir<'tcx>,
|
||||||
|
mir_def_id: DefId,
|
||||||
universal_regions: &UniversalRegions<'tcx>,
|
universal_regions: &UniversalRegions<'tcx>,
|
||||||
) {
|
) {
|
||||||
|
let tcx = self.infcx.tcx;
|
||||||
|
|
||||||
let &UniversalRegions {
|
let &UniversalRegions {
|
||||||
unnormalized_output_ty,
|
unnormalized_output_ty,
|
||||||
unnormalized_input_tys,
|
unnormalized_input_tys,
|
||||||
..
|
..
|
||||||
} = universal_regions;
|
} = universal_regions;
|
||||||
|
let infcx = self.infcx;
|
||||||
|
|
||||||
let start_position = Location {
|
let start_position = Location {
|
||||||
block: START_BLOCK,
|
block: START_BLOCK,
|
||||||
|
@ -52,10 +62,88 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// Return types are a bit more complex. They may contain existential `impl Trait`
|
// Return types are a bit more complex. They may contain existential `impl Trait`
|
||||||
// types.
|
// types.
|
||||||
|
debug!(
|
||||||
|
"equate_inputs_and_outputs: unnormalized_output_ty={:?}",
|
||||||
|
unnormalized_output_ty
|
||||||
|
);
|
||||||
let output_ty = self.normalize(&unnormalized_output_ty, start_position);
|
let output_ty = self.normalize(&unnormalized_output_ty, start_position);
|
||||||
|
debug!(
|
||||||
|
"equate_inputs_and_outputs: normalized output_ty={:?}",
|
||||||
|
output_ty
|
||||||
|
);
|
||||||
let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
|
let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
|
||||||
self.equate_normalized_input_or_output(start_position, output_ty, mir_output_ty);
|
let anon_type_map = self.fully_perform_op(start_position.at_self(), |cx| {
|
||||||
|
let mut obligations = ObligationAccumulator::default();
|
||||||
|
|
||||||
|
let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
|
||||||
|
mir_def_id,
|
||||||
|
cx.body_id,
|
||||||
|
cx.param_env,
|
||||||
|
&output_ty,
|
||||||
|
));
|
||||||
|
debug!(
|
||||||
|
"equate_inputs_and_outputs: instantiated output_ty={:?}",
|
||||||
|
output_ty
|
||||||
|
);
|
||||||
|
debug!(
|
||||||
|
"equate_inputs_and_outputs: anon_type_map={:#?}",
|
||||||
|
anon_type_map
|
||||||
|
);
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"equate_inputs_and_outputs: mir_output_ty={:?}",
|
||||||
|
mir_output_ty
|
||||||
|
);
|
||||||
|
obligations.add(infcx
|
||||||
|
.at(&cx.misc(cx.last_span), cx.param_env)
|
||||||
|
.eq(output_ty, mir_output_ty)?);
|
||||||
|
|
||||||
|
for (&anon_def_id, anon_decl) in &anon_type_map {
|
||||||
|
let anon_defn_ty = tcx.type_of(anon_def_id);
|
||||||
|
let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs);
|
||||||
|
let anon_defn_ty = renumber::renumber_regions(
|
||||||
|
cx.infcx,
|
||||||
|
TyContext::Location(start_position),
|
||||||
|
&anon_defn_ty,
|
||||||
|
);
|
||||||
|
debug!(
|
||||||
|
"equate_inputs_and_outputs: concrete_ty={:?}",
|
||||||
|
anon_decl.concrete_ty
|
||||||
|
);
|
||||||
|
debug!("equate_inputs_and_outputs: anon_defn_ty={:?}", anon_defn_ty);
|
||||||
|
obligations.add(infcx
|
||||||
|
.at(&cx.misc(cx.last_span), cx.param_env)
|
||||||
|
.eq(anon_decl.concrete_ty, anon_defn_ty)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("equate_inputs_and_outputs: equated");
|
||||||
|
|
||||||
|
Ok(InferOk {
|
||||||
|
value: Some(anon_type_map),
|
||||||
|
obligations: obligations.into_vec(),
|
||||||
|
})
|
||||||
|
}).unwrap_or_else(|terr| {
|
||||||
|
span_mirbug!(
|
||||||
|
self,
|
||||||
|
start_position,
|
||||||
|
"equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
|
||||||
|
output_ty,
|
||||||
|
mir_output_ty,
|
||||||
|
terr
|
||||||
|
);
|
||||||
|
None
|
||||||
|
});
|
||||||
|
|
||||||
|
// Finally
|
||||||
|
if let Some(anon_type_map) = anon_type_map {
|
||||||
|
self.fully_perform_op(start_position.at_self(), |_cx| {
|
||||||
|
infcx.constrain_anon_types(&anon_type_map, universal_regions);
|
||||||
|
Ok(InferOk {
|
||||||
|
value: (),
|
||||||
|
obligations: vec![],
|
||||||
|
})
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) {
|
fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||||
|
@ -73,3 +161,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct ObligationAccumulator<'tcx> {
|
||||||
|
obligations: PredicateObligations<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ObligationAccumulator<'tcx> {
|
||||||
|
fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
|
||||||
|
let InferOk { value, obligations } = value;
|
||||||
|
self.obligations.extend(obligations);
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_vec(self) -> PredicateObligations<'tcx> {
|
||||||
|
self.obligations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ use borrow_check::nll::universal_regions::UniversalRegions;
|
||||||
use dataflow::FlowAtLocation;
|
use dataflow::FlowAtLocation;
|
||||||
use dataflow::MaybeInitializedLvals;
|
use dataflow::MaybeInitializedLvals;
|
||||||
use dataflow::move_paths::MoveData;
|
use dataflow::move_paths::MoveData;
|
||||||
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
|
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
|
||||||
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
|
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
|
||||||
use rustc::traits::{self, FulfillmentContext};
|
use rustc::traits::{self, FulfillmentContext};
|
||||||
|
@ -77,9 +78,9 @@ mod input_output;
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
///
|
///
|
||||||
/// - `infcx` -- inference context to use
|
/// - `infcx` -- inference context to use
|
||||||
/// - `body_id` -- body-id of the MIR being checked
|
|
||||||
/// - `param_env` -- parameter environment to use for trait solving
|
/// - `param_env` -- parameter environment to use for trait solving
|
||||||
/// - `mir` -- MIR to type-check
|
/// - `mir` -- MIR to type-check
|
||||||
|
/// - `mir_def_id` -- DefId from which the MIR is derived (must be local)
|
||||||
/// - `region_bound_pairs` -- the implied outlives obligations between type parameters
|
/// - `region_bound_pairs` -- the implied outlives obligations between type parameters
|
||||||
/// and lifetimes (e.g., `&'a T` implies `T: 'a`)
|
/// and lifetimes (e.g., `&'a T` implies `T: 'a`)
|
||||||
/// - `implicit_region_bound` -- a region which all generic parameters are assumed
|
/// - `implicit_region_bound` -- a region which all generic parameters are assumed
|
||||||
|
@ -94,14 +95,15 @@ mod input_output;
|
||||||
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
|
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
|
||||||
pub(crate) fn type_check<'gcx, 'tcx>(
|
pub(crate) fn type_check<'gcx, 'tcx>(
|
||||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||||
body_id: ast::NodeId,
|
|
||||||
param_env: ty::ParamEnv<'gcx>,
|
param_env: ty::ParamEnv<'gcx>,
|
||||||
mir: &Mir<'tcx>,
|
mir: &Mir<'tcx>,
|
||||||
|
mir_def_id: DefId,
|
||||||
universal_regions: &UniversalRegions<'tcx>,
|
universal_regions: &UniversalRegions<'tcx>,
|
||||||
liveness: &LivenessResults,
|
liveness: &LivenessResults,
|
||||||
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
|
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
) -> MirTypeckRegionConstraints<'tcx> {
|
) -> MirTypeckRegionConstraints<'tcx> {
|
||||||
|
let body_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
|
||||||
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
|
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
|
||||||
type_check_internal(
|
type_check_internal(
|
||||||
infcx,
|
infcx,
|
||||||
|
@ -113,7 +115,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
||||||
&mut |cx| {
|
&mut |cx| {
|
||||||
liveness::generate(cx, mir, liveness, flow_inits, move_data);
|
liveness::generate(cx, mir, liveness, flow_inits, move_data);
|
||||||
|
|
||||||
cx.equate_inputs_and_outputs(mir, universal_regions);
|
cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||||
use rustc::infer::region_constraints::GenericKind;
|
use rustc::infer::region_constraints::GenericKind;
|
||||||
use rustc::infer::outlives::bounds::{self, OutlivesBound};
|
use rustc::infer::outlives::bounds::{self, OutlivesBound};
|
||||||
|
use rustc::infer::outlives::free_region_map::FreeRegionRelations;
|
||||||
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
|
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
|
||||||
use rustc::ty::fold::TypeFoldable;
|
use rustc::ty::fold::TypeFoldable;
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
|
@ -484,9 +485,6 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||||
let (unnormalized_output_ty, unnormalized_input_tys) =
|
let (unnormalized_output_ty, unnormalized_input_tys) =
|
||||||
inputs_and_output.split_last().unwrap();
|
inputs_and_output.split_last().unwrap();
|
||||||
|
|
||||||
// we should not have created any more variables
|
|
||||||
assert_eq!(self.infcx.num_region_vars(), num_universals);
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"build: global regions = {}..{}",
|
"build: global regions = {}..{}",
|
||||||
FIRST_GLOBAL_INDEX,
|
FIRST_GLOBAL_INDEX,
|
||||||
|
@ -793,3 +791,16 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This trait is used by the `impl-trait` constraint code to abstract
|
||||||
|
/// over the `FreeRegionMap` from lexical regions and
|
||||||
|
/// `UniversalRegions` (from NLL)`.
|
||||||
|
impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegions<'tcx> {
|
||||||
|
fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool {
|
||||||
|
let shorter = shorter.to_region_vid();
|
||||||
|
assert!(self.is_universal_region(shorter));
|
||||||
|
let longer = longer.to_region_vid();
|
||||||
|
assert!(self.is_universal_region(longer));
|
||||||
|
self.outlives(longer, shorter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -985,7 +985,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
|
||||||
|
|
||||||
let ret_ty = fn_sig.output();
|
let ret_ty = fn_sig.output();
|
||||||
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::SizedReturnType);
|
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::SizedReturnType);
|
||||||
let ret_ty = fcx.instantiate_anon_types_from_return_value(&ret_ty);
|
let ret_ty = fcx.instantiate_anon_types_from_return_value(fn_id, &ret_ty);
|
||||||
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
|
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
|
||||||
fn_sig = fcx.tcx.mk_fn_sig(
|
fn_sig = fcx.tcx.mk_fn_sig(
|
||||||
fn_sig.inputs().iter().cloned(),
|
fn_sig.inputs().iter().cloned(),
|
||||||
|
@ -1880,11 +1880,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
/// function with type variables and records the `AnonTypeMap` for
|
/// function with type variables and records the `AnonTypeMap` for
|
||||||
/// later use during writeback. See
|
/// later use during writeback. See
|
||||||
/// `InferCtxt::instantiate_anon_types` for more details.
|
/// `InferCtxt::instantiate_anon_types` for more details.
|
||||||
fn instantiate_anon_types_from_return_value<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
|
fn instantiate_anon_types_from_return_value<T: TypeFoldable<'tcx>>(
|
||||||
debug!("instantiate_anon_types_from_return_value(value={:?})", value);
|
&self,
|
||||||
|
fn_id: ast::NodeId,
|
||||||
|
value: &T,
|
||||||
|
) -> T {
|
||||||
|
let fn_def_id = self.tcx.hir.local_def_id(fn_id);
|
||||||
|
debug!(
|
||||||
|
"instantiate_anon_types_from_return_value(fn_def_id={:?}, value={:?})",
|
||||||
|
fn_def_id,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
|
||||||
let (value, anon_type_map) = self.register_infer_ok_obligations(
|
let (value, anon_type_map) = self.register_infer_ok_obligations(
|
||||||
self.instantiate_anon_types(
|
self.instantiate_anon_types(
|
||||||
|
fn_def_id,
|
||||||
self.body_id,
|
self.body_id,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
value,
|
value,
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// revisions: normal nll
|
||||||
|
//[nll] compile-flags: -Znll -Zborrowck=mir
|
||||||
|
|
||||||
#![feature(conservative_impl_trait,
|
#![feature(conservative_impl_trait,
|
||||||
universal_impl_trait,
|
universal_impl_trait,
|
||||||
fn_traits,
|
fn_traits,
|
||||||
|
|
27
src/test/ui/nll/ty-outlives/impl-trait-captures.rs
Normal file
27
src/test/ui/nll/ty-outlives/impl-trait-captures.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||||
|
|
||||||
|
#![allow(warnings)]
|
||||||
|
#![feature(conservative_impl_trait)]
|
||||||
|
|
||||||
|
trait Foo<'a> {
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Foo<'a> for T { }
|
||||||
|
|
||||||
|
fn foo<'a, T>(x: &T) -> impl Foo<'a> {
|
||||||
|
x
|
||||||
|
//~^ WARNING not reporting region error due to -Znll
|
||||||
|
//~| ERROR free region `'_#2r` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
14
src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
Normal file
14
src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
warning: not reporting region error due to -Znll
|
||||||
|
--> $DIR/impl-trait-captures.rs:22:5
|
||||||
|
|
|
||||||
|
22 | x
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: free region `'_#2r` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||||
|
--> $DIR/impl-trait-captures.rs:22:5
|
||||||
|
|
|
||||||
|
22 | x
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
51
src/test/ui/nll/ty-outlives/impl-trait-outlives.rs
Normal file
51
src/test/ui/nll/ty-outlives/impl-trait-outlives.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||||
|
|
||||||
|
#![allow(warnings)]
|
||||||
|
#![feature(conservative_impl_trait)]
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
|
||||||
|
//~^ WARNING not reporting region error due to -Znll
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
|
x
|
||||||
|
//~^ ERROR `T` does not outlive
|
||||||
|
}
|
||||||
|
|
||||||
|
fn correct_region<'a, T>(x: Box<T>) -> impl Debug + 'a
|
||||||
|
where
|
||||||
|
T: 'a + Debug,
|
||||||
|
{
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
|
||||||
|
//~^ WARNING not reporting region error due to -Znll
|
||||||
|
where
|
||||||
|
T: 'b + Debug,
|
||||||
|
{
|
||||||
|
x
|
||||||
|
//~^ ERROR `T` does not outlive
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outlives_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
|
||||||
|
where
|
||||||
|
T: 'b + Debug,
|
||||||
|
'b: 'a,
|
||||||
|
{
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
26
src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
Normal file
26
src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
warning: not reporting region error due to -Znll
|
||||||
|
--> $DIR/impl-trait-outlives.rs:18:35
|
||||||
|
|
|
||||||
|
18 | fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: not reporting region error due to -Znll
|
||||||
|
--> $DIR/impl-trait-outlives.rs:34:42
|
||||||
|
|
|
||||||
|
34 | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: `T` does not outlive `'_#1r`
|
||||||
|
--> $DIR/impl-trait-outlives.rs:23:5
|
||||||
|
|
|
||||||
|
23 | x
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: `T` does not outlive `'_#1r`
|
||||||
|
--> $DIR/impl-trait-outlives.rs:39:5
|
||||||
|
|
|
||||||
|
39 | x
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue