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
@ -93,20 +93,34 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
/// Moreover, it returns a `AnonTypeMap` that would map `?0` to
|
||||
/// info about the `impl Iterator<..>` type and `?1` to info about
|
||||
/// 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>>(
|
||||
&self,
|
||||
parent_def_id: DefId,
|
||||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: &T,
|
||||
) -> InferOk<'tcx, (T, AnonTypeMap<'tcx>)> {
|
||||
debug!(
|
||||
"instantiate_anon_types(value={:?}, body_id={:?}, param_env={:?})",
|
||||
"instantiate_anon_types(value={:?}, parent_def_id={:?}, body_id={:?}, param_env={:?})",
|
||||
value,
|
||||
parent_def_id,
|
||||
body_id,
|
||||
param_env,
|
||||
);
|
||||
let mut instantiator = Instantiator {
|
||||
infcx: self,
|
||||
parent_def_id,
|
||||
body_id,
|
||||
param_env,
|
||||
anon_types: DefIdMap(),
|
||||
@ -480,6 +494,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
parent_def_id: DefId,
|
||||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
anon_types: AnonTypeMap<'tcx>,
|
||||
@ -489,11 +504,33 @@ struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
||||
fn instantiate_anon_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
|
||||
debug!("instantiate_anon_types_in_map(value={:?})", value);
|
||||
let tcx = self.infcx.tcx;
|
||||
value.fold_with(&mut BottomUpFolder {
|
||||
tcx: self.infcx.tcx,
|
||||
fldop: |ty| if let ty::TyAnon(def_id, substs) = ty.sty {
|
||||
self.fold_anon_ty(ty, def_id, substs)
|
||||
} else {
|
||||
tcx,
|
||||
fldop: |ty| {
|
||||
if let ty::TyAnon(def_id, substs) = ty.sty {
|
||||
// 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
|
||||
},
|
||||
})
|
||||
|
@ -865,13 +865,17 @@ impl fmt::Debug for ty::RegionVid {
|
||||
define_print! {
|
||||
() ty::InferTy, (self, f, cx) {
|
||||
display {
|
||||
match *self {
|
||||
ty::TyVar(_) => write!(f, "_"),
|
||||
ty::IntVar(_) => write!(f, "{}", "{integer}"),
|
||||
ty::FloatVar(_) => write!(f, "{}", "{float}"),
|
||||
ty::FreshTy(v) => write!(f, "FreshTy({})", v),
|
||||
ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
|
||||
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
|
||||
if cx.is_verbose {
|
||||
print!(f, cx, print_debug(self))
|
||||
} else {
|
||||
match *self {
|
||||
ty::TyVar(_) => write!(f, "_"),
|
||||
ty::IntVar(_) => write!(f, "{}", "{integer}"),
|
||||
ty::FloatVar(_) => write!(f, "{}", "{float}"),
|
||||
ty::FreshTy(v) => write!(f, "FreshTy({})", v),
|
||||
ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
|
||||
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
debug {
|
||||
|
@ -77,13 +77,12 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
||||
Option<ClosureRegionRequirements<'gcx>>,
|
||||
) {
|
||||
// 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 constraint_sets = &type_check::type_check(
|
||||
infcx,
|
||||
mir_node_id,
|
||||
param_env,
|
||||
mir,
|
||||
def_id,
|
||||
&universal_regions,
|
||||
&liveness,
|
||||
flow_inits,
|
||||
|
@ -246,13 +246,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
.map(|origin| RegionDefinition::new(origin))
|
||||
.collect();
|
||||
|
||||
let nll_dump_cause = ty::tls::with(|tcx| tcx.sess.opts.debugging_opts.nll_dump_cause);
|
||||
|
||||
let mut result = Self {
|
||||
definitions,
|
||||
elements: elements.clone(),
|
||||
liveness_constraints: RegionValues::new(
|
||||
elements,
|
||||
num_region_variables,
|
||||
TrackCauses(true),
|
||||
TrackCauses(nll_dump_cause),
|
||||
),
|
||||
inferred_values: None,
|
||||
constraints: Vec::new(),
|
||||
|
@ -16,7 +16,7 @@ use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||
|
||||
/// Replaces all free regions appearing in the MIR with fresh
|
||||
/// 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: 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);
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
infcx: &'a InferCtxt<'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
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
debug!("renumber_regions(value={:?})", value);
|
||||
|
||||
self.infcx
|
||||
.tcx
|
||||
.fold_regions(value, &mut false, |_region, _depth| {
|
||||
let origin = NLLRegionVariableOrigin::Inferred(ty_context);
|
||||
self.infcx.next_nll_region_var(origin)
|
||||
})
|
||||
renumber_regions(self.infcx, ty_context, value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,15 @@
|
||||
//! `RETURN_PLACE` the MIR arguments) are always fully normalize (and
|
||||
//! contain revealed `impl Trait` values).
|
||||
|
||||
use borrow_check::nll::renumber;
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::ty::Ty;
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::visit::TyContext;
|
||||
use rustc::traits::PredicateObligations;
|
||||
|
||||
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(
|
||||
&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
let &UniversalRegions {
|
||||
unnormalized_output_ty,
|
||||
unnormalized_input_tys,
|
||||
..
|
||||
} = universal_regions;
|
||||
let infcx = self.infcx;
|
||||
|
||||
let start_position = Location {
|
||||
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`
|
||||
// types.
|
||||
|
||||
debug!(
|
||||
"equate_inputs_and_outputs: unnormalized_output_ty={:?}",
|
||||
unnormalized_output_ty
|
||||
);
|
||||
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;
|
||||
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>) {
|
||||
@ -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::MaybeInitializedLvals;
|
||||
use dataflow::move_paths::MoveData;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
|
||||
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
|
||||
use rustc::traits::{self, FulfillmentContext};
|
||||
@ -77,9 +78,9 @@ mod input_output;
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `infcx` -- inference context to use
|
||||
/// - `body_id` -- body-id of the MIR being checked
|
||||
/// - `param_env` -- parameter environment to use for trait solving
|
||||
/// - `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
|
||||
/// and lifetimes (e.g., `&'a T` implies `T: 'a`)
|
||||
/// - `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
|
||||
pub(crate) fn type_check<'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
liveness: &LivenessResults,
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'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));
|
||||
type_check_internal(
|
||||
infcx,
|
||||
@ -113,7 +115,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
||||
&mut |cx| {
|
||||
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::region_constraints::GenericKind;
|
||||
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::fold::TypeFoldable;
|
||||
use rustc::ty::subst::Substs;
|
||||
@ -484,9 +485,6 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||
let (unnormalized_output_ty, unnormalized_input_tys) =
|
||||
inputs_and_output.split_last().unwrap();
|
||||
|
||||
// we should not have created any more variables
|
||||
assert_eq!(self.infcx.num_region_vars(), num_universals);
|
||||
|
||||
debug!(
|
||||
"build: global regions = {}..{}",
|
||||
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();
|
||||
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)));
|
||||
fn_sig = fcx.tcx.mk_fn_sig(
|
||||
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
|
||||
/// later use during writeback. See
|
||||
/// `InferCtxt::instantiate_anon_types` for more details.
|
||||
fn instantiate_anon_types_from_return_value<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
|
||||
debug!("instantiate_anon_types_from_return_value(value={:?})", value);
|
||||
fn instantiate_anon_types_from_return_value<T: TypeFoldable<'tcx>>(
|
||||
&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(
|
||||
self.instantiate_anon_types(
|
||||
fn_def_id,
|
||||
self.body_id,
|
||||
self.param_env,
|
||||
value,
|
||||
|
@ -8,6 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// revisions: normal nll
|
||||
//[nll] compile-flags: -Znll -Zborrowck=mir
|
||||
|
||||
#![feature(conservative_impl_trait,
|
||||
universal_impl_trait,
|
||||
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…
Reference in New Issue
Block a user