1
Fork 0

Auto merge of #53873 - nikomatsakis:nll-universe-subtyping-and-pattern-ascription, r=pnkfelix

support ascription for patterns in NLL

This implements the strategy outlined in [this comment](https://github.com/rust-lang/rust/issues/47184#issuecomment-416669986):

- We first extend the NLL subtyping code so it can handle inference variables and subtyping.
- Then we extend HAIR patterns with type ascription.
- Then we treat the type `T` in `let pat: T = ...` as an ascription.

Before landing, a few things:

- [x] Fix the WF rule bug (filed a FIXME https://github.com/rust-lang/rust/issues/54105)
- [x] Fix an ICE I encountered locally around bound regions, or else file a follow-up
- [x] More tests probably =)

r? @pnkfelix
This commit is contained in:
bors 2018-09-11 20:59:11 +00:00
commit 2f1547c0aa
55 changed files with 1868 additions and 1003 deletions

View file

@ -24,6 +24,7 @@ impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
mutability,
ty,
user_ty,
name,
source_info,
visibility_scope,
@ -255,9 +256,10 @@ for mir::StatementKind<'gcx> {
op.hash_stable(hcx, hasher);
places.hash_stable(hcx, hasher);
}
mir::StatementKind::UserAssertTy(ref c_ty, ref local) => {
mir::StatementKind::AscribeUserType(ref place, ref variance, ref c_ty) => {
place.hash_stable(hcx, hasher);
variance.hash_stable(hcx, hasher);
c_ty.hash_stable(hcx, hasher);
local.hash_stable(hcx, hasher);
}
mir::StatementKind::Nop => {}
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {

File diff suppressed because it is too large Load diff

View file

@ -640,6 +640,12 @@ pub struct LocalDecl<'tcx> {
/// Type of this local.
pub ty: Ty<'tcx>,
/// If the user manually ascribed a type to this variable,
/// e.g. via `let x: T`, then we carry that type here. The MIR
/// borrow checker needs this information since it can affect
/// region inference.
pub user_ty: Option<CanonicalTy<'tcx>>,
/// Name of the local, used in debuginfo and pretty-printing.
///
/// Note that function arguments can also have this set to `Some(_)`
@ -802,6 +808,7 @@ impl<'tcx> LocalDecl<'tcx> {
LocalDecl {
mutability,
ty,
user_ty: None,
name: None,
source_info: SourceInfo {
span,
@ -821,6 +828,7 @@ impl<'tcx> LocalDecl<'tcx> {
LocalDecl {
mutability: Mutability::Mut,
ty: return_ty,
user_ty: None,
source_info: SourceInfo {
span,
scope: OUTERMOST_SOURCE_SCOPE,
@ -1636,22 +1644,19 @@ pub enum StatementKind<'tcx> {
/// (The starting point(s) arise implicitly from borrows.)
EndRegion(region::Scope),
/// Encodes a user's type assertion. These need to be preserved intact so that NLL can respect
/// them. For example:
/// Encodes a user's type ascription. These need to be preserved
/// intact so that NLL can respect them. For example:
///
/// let (a, b): (T, U) = y;
/// let a: T = y;
///
/// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y`
/// is the right thing.
/// The effect of this annotation is to relate the type `T_y` of the place `y`
/// to the user-given type `T`. The effect depends on the specified variance:
///
/// `CanonicalTy` is used to capture "inference variables" from the user's types. For example:
///
/// let x: Vec<_> = ...;
/// let y: &u32 = ...;
///
/// would result in `Vec<?0>` and `&'?0 u32` respectively (where `?0` is a canonicalized
/// variable).
UserAssertTy(CanonicalTy<'tcx>, Local),
/// - `Covariant` -- requires that `T_y <: T`
/// - `Contravariant` -- requires that `T_y :> T`
/// - `Invariant` -- requires that `T_y == T`
/// - `Bivariant` -- no effect
AscribeUserType(Place<'tcx>, ty::Variance, CanonicalTy<'tcx>),
/// No-op. Useful for deleting instructions without affecting statement indices.
Nop,
@ -1728,8 +1733,8 @@ impl<'tcx> Debug for Statement<'tcx> {
ref outputs,
ref inputs,
} => write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs),
UserAssertTy(ref c_ty, ref local) => {
write!(fmt, "UserAssertTy({:?}, {:?})", c_ty, local)
AscribeUserType(ref place, ref variance, ref c_ty) => {
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
}
Nop => write!(fmt, "nop"),
}
@ -2616,6 +2621,7 @@ BraceStructTypeFoldableImpl! {
is_user_variable,
internal,
ty,
user_ty,
name,
source_info,
visibility_scope,
@ -2652,7 +2658,7 @@ EnumTypeFoldableImpl! {
(StatementKind::InlineAsm) { asm, outputs, inputs },
(StatementKind::Validate)(a, b),
(StatementKind::EndRegion)(a),
(StatementKind::UserAssertTy)(a, b),
(StatementKind::AscribeUserType)(a, v, b),
(StatementKind::Nop),
}
}

View file

@ -144,11 +144,12 @@ macro_rules! make_mir_visitor {
self.super_operand(operand, location);
}
fn visit_user_assert_ty(&mut self,
c_ty: & $($mutability)* CanonicalTy<'tcx>,
local: & $($mutability)* Local,
location: Location) {
self.super_user_assert_ty(c_ty, local, location);
fn visit_ascribe_user_ty(&mut self,
place: & $($mutability)* Place<'tcx>,
variance: & $($mutability)* ty::Variance,
c_ty: & $($mutability)* CanonicalTy<'tcx>,
location: Location) {
self.super_ascribe_user_ty(place, variance, c_ty, location);
}
fn visit_place(&mut self,
@ -386,9 +387,12 @@ macro_rules! make_mir_visitor {
self.visit_operand(input, location);
}
}
StatementKind::UserAssertTy(ref $($mutability)* c_ty,
ref $($mutability)* local) => {
self.visit_user_assert_ty(c_ty, local, location);
StatementKind::AscribeUserType(
ref $($mutability)* place,
ref $($mutability)* variance,
ref $($mutability)* c_ty,
) => {
self.visit_ascribe_user_ty(place, variance, c_ty, location);
}
StatementKind::Nop => {}
}
@ -629,12 +633,13 @@ macro_rules! make_mir_visitor {
}
}
fn super_user_assert_ty(&mut self,
c_ty: & $($mutability)* CanonicalTy<'tcx>,
local: & $($mutability)* Local,
location: Location) {
fn super_ascribe_user_ty(&mut self,
place: & $($mutability)* Place<'tcx>,
_variance: & $($mutability)* ty::Variance,
c_ty: & $($mutability)* CanonicalTy<'tcx>,
location: Location) {
self.visit_place(place, PlaceContext::Validate, location);
self.visit_canonical_ty(c_ty);
self.visit_local(local, PlaceContext::Validate, location);
}
fn super_place(&mut self,
@ -716,6 +721,7 @@ macro_rules! make_mir_visitor {
let LocalDecl {
mutability: _,
ref $($mutability)* ty,
ref $($mutability)* user_ty,
name: _,
ref $($mutability)* source_info,
ref $($mutability)* visibility_scope,
@ -727,6 +733,9 @@ macro_rules! make_mir_visitor {
local,
source_info: *source_info,
});
if let Some(user_ty) = user_ty {
self.visit_canonical_ty(user_ty);
}
self.visit_source_info(source_info);
self.visit_source_scope(visibility_scope);
}

View file

@ -356,8 +356,8 @@ pub struct TypeckTables<'tcx> {
/// belongs, but it may not exist if it's a tuple field (`tuple.0`).
field_indices: ItemLocalMap<usize>,
/// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in
/// MIR.
/// Stores the canonicalized types provided by the user. See also
/// `AscribeUserType` statement in MIR.
user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
/// Stores the types for various nodes in the AST. Note that this table

View file

@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! {
::ty::ClosureKind,
::ty::IntVarValue,
::ty::ParamTy,
::ty::Variance,
::syntax_pos::Span,
}

View file

@ -92,7 +92,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
mir::StatementKind::ReadForMatch(_) |
mir::StatementKind::EndRegion(_) |
mir::StatementKind::Validate(..) |
mir::StatementKind::UserAssertTy(..) |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => bx,
}
}

View file

@ -535,10 +535,10 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
// flow_state already handled).
}
StatementKind::Nop
| StatementKind::UserAssertTy(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Validate(..)
| StatementKind::StorageLive(..) => {
// `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
// `Nop`, `AscribeUserType`, `Validate`, and `StorageLive` are irrelevant
// to borrow check.
}
StatementKind::StorageDead(local) => {

View file

@ -17,7 +17,7 @@ use rustc::infer::InferCtxt;
use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor;
use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
use rustc::mir::{Local, Statement, Terminator};
use rustc::mir::{Statement, Terminator};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, RegionVid};
@ -175,10 +175,11 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
self.super_terminator(block, terminator, location);
}
fn visit_user_assert_ty(
fn visit_ascribe_user_ty(
&mut self,
_place: &Place<'tcx>,
_variance: &ty::Variance,
_c_ty: &CanonicalTy<'tcx>,
_local: &Local,
_location: Location,
) {
}

View file

@ -144,10 +144,10 @@ impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tc
// EndRegion matters to older NLL/MIR AST borrowck, not to alias NLL
StatementKind::EndRegion(..) |
StatementKind::Nop |
StatementKind::UserAssertTy(..) |
StatementKind::AscribeUserType(..) |
StatementKind::Validate(..) |
StatementKind::StorageLive(..) => {
// `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
// `Nop`, `AscribeUserType`, `Validate`, and `StorageLive` are irrelevant
// to borrow check.
}
StatementKind::StorageDead(local) => {

View file

@ -319,23 +319,34 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
for variable in self.definitions.indices() {
let scc = self.constraint_sccs.scc(variable);
match self.definitions[variable].origin {
NLLRegionVariableOrigin::FreeRegion => {
// For each free, universally quantified region X:
// Add all nodes in the CFG to liveness constraints
let variable_scc = self.constraint_sccs.scc(variable);
self.liveness_constraints.add_all_points(variable);
self.scc_values.add_all_points(variable_scc);
self.scc_values.add_all_points(scc);
// Add `end(X)` into the set for X.
self.add_element_to_scc_of(variable, variable);
self.scc_values.add_element(scc, variable);
}
NLLRegionVariableOrigin::BoundRegion(ui) => {
// Each placeholder region X outlives its
// associated universe but nothing else.
self.add_element_to_scc_of(variable, ui);
// associated universe but nothing else. Every
// placeholder region is always in a universe that
// contains `ui` -- but when placeholder regions
// are placed into an SCC, that SCC may include
// things from other universes that do not include
// `ui`.
let scc_universe = self.scc_universes[scc];
if ui.is_subset_of(scc_universe) {
self.scc_values.add_element(scc, ui);
} else {
self.add_incompatible_universe(scc);
}
}
NLLRegionVariableOrigin::Existential => {
@ -383,13 +394,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.scc_universes[scc]
}
/// Adds `elem` to the value of the SCC in which `v` appears.
fn add_element_to_scc_of(&mut self, v: RegionVid, elem: impl ToElementIndex) {
debug!("add_live_element({:?}, {:?})", v, elem);
let scc = self.constraint_sccs.scc(v);
self.scc_values.add_element(scc, elem);
}
/// Perform region inference and report errors if we see any
/// unsatisfiable constraints. If this is a closure, returns the
/// region requirements to propagate to our creator, if any.
@ -516,22 +520,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// merge the bits.
self.scc_values.add_region(scc_a, scc_b);
} else {
// Otherwise, the only way for `A` to outlive `B`
// is for it to outlive static. This is actually stricter
// than necessary: ideally, we'd support bounds like `for<'a: 'b`>`
// that might then allow us to approximate `'a` with `'b` and not
// `'static`. But it will have to do for now.
//
// The code here is a bit hacky: we grab the current
// value of the SCC in which `'static` appears, but
// this value may not be fully computed yet. That's ok
// though: it will contain the base liveness values,
// which include (a) the static free region element
// and (b) all the points in the CFG, so it is "good
// enough" to bring it in here for our purposes.
let fr_static = self.universal_regions.fr_static;
let scc_static = constraint_sccs.scc(fr_static);
self.scc_values.add_region(scc_a, scc_static);
self.add_incompatible_universe(scc_a);
}
}
@ -563,6 +552,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.all(|u| u.is_subset_of(universe_a))
}
/// Extend `scc` so that it can outlive some placeholder region
/// from a universe it can't name; at present, the only way for
/// this to be true is if `scc` outlives `'static`. This is
/// actually stricter than necessary: ideally, we'd support bounds
/// like `for<'a: 'b`>` that might then allow us to approximate
/// `'a` with `'b` and not `'static`. But it will have to do for
/// now.
fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) {
let fr_static = self.universal_regions.fr_static;
self.scc_values.add_all_points(scc);
self.scc_values.add_element(scc, fr_static);
}
/// Once regions have been propagated, this method is used to see
/// whether the "type tests" produced by typeck were satisfied;
/// type tests encode type-outlives relationships like `T:

View file

@ -10,7 +10,7 @@
use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind};
use rustc::mir::{BasicBlock, Location, Mir, Place, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
@ -112,8 +112,13 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
debug!("visit_closure_substs: substs={:?}", substs);
}
fn visit_user_assert_ty(&mut self, _c_ty: &mut CanonicalTy<'tcx>, _local: &mut Local,
_location: Location) {
fn visit_ascribe_user_ty(
&mut self,
_place: &mut Place<'tcx>,
_variance: &mut ty::Variance,
_c_ty: &mut CanonicalTy<'tcx>,
_location: Location,
) {
// User-assert-ty statements represent types that the user added explicitly.
// We don't want to erase the regions from these types: rather, we want to
// add them as constraints at type-check time.

View file

@ -17,7 +17,9 @@ use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
use borrow_check::nll::facts::AllFacts;
use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
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::free_region_relations::{
CreateResult, UniversalRegionRelations,
};
use borrow_check::nll::universal_regions::UniversalRegions;
use borrow_check::nll::ToRegionVid;
use dataflow::move_paths::MoveData;
@ -246,10 +248,12 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
self.sanitize_type(constant, constant.ty);
if let Some(user_ty) = constant.user_ty {
if let Err(terr) =
self.cx
.eq_canonical_type_and_type(user_ty, constant.ty, location.boring())
{
if let Err(terr) = self.cx.relate_type_and_user_type(
constant.ty,
ty::Variance::Invariant,
user_ty,
location.boring(),
) {
span_mirbug!(
self,
constant,
@ -271,6 +275,25 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
self.super_local_decl(local, local_decl);
self.sanitize_type(local_decl, local_decl.ty);
if let Some(user_ty) = local_decl.user_ty {
if let Err(terr) = self.cx.relate_type_and_user_type(
local_decl.ty,
ty::Variance::Invariant,
user_ty,
Locations::All,
) {
span_mirbug!(
self,
local,
"bad user type on variable {:?}: {:?} != {:?} ({:?})",
local,
local_decl.ty,
local_decl.user_ty,
terr,
);
}
}
}
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
@ -850,15 +873,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
)
}
fn eq_canonical_type_and_type(
fn relate_type_and_user_type(
&mut self,
a: CanonicalTy<'tcx>,
b: Ty<'tcx>,
a: Ty<'tcx>,
v: ty::Variance,
b: CanonicalTy<'tcx>,
locations: Locations,
) -> Fallible<()> {
relate_tys::eq_canonical_type_and_type(
relate_tys::relate_type_and_user_type(
self.infcx,
a,
v,
b,
locations,
self.borrowck_context.as_mut().map(|x| &mut **x),
@ -879,8 +904,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
// of lowering. Assignments to other sorts of places *are* interesting
// though.
let is_temp = if let Place::Local(l) = *place {
l != RETURN_PLACE &&
!mir.local_decls[l].is_user_variable.is_some()
l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some()
} else {
false
};
@ -905,9 +929,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
if let Some(user_ty) = self.rvalue_user_ty(rv) {
if let Err(terr) = self.eq_canonical_type_and_type(
user_ty,
if let Err(terr) = self.relate_type_and_user_type(
rv_ty,
ty::Variance::Invariant,
user_ty,
location.boring(),
) {
span_mirbug!(
@ -955,15 +980,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
);
};
}
StatementKind::UserAssertTy(c_ty, local) => {
let local_ty = mir.local_decls()[local].ty;
if let Err(terr) = self.eq_canonical_type_and_type(c_ty, local_ty, Locations::All) {
StatementKind::AscribeUserType(ref place, variance, c_ty) => {
let place_ty = place.ty(mir, tcx).to_ty(tcx);
if let Err(terr) =
self.relate_type_and_user_type(place_ty, variance, c_ty, Locations::All)
{
span_mirbug!(
self,
stmt,
"bad type assert ({:?} = {:?}): {:?}",
"bad type assert ({:?} <: {:?}): {:?}",
place_ty,
c_ty,
local_ty,
terr
);
}
@ -1142,8 +1169,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
Some((ref dest, _target_block)) => {
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
let is_temp = if let Place::Local(l) = *dest {
l != RETURN_PLACE &&
!mir.local_decls[l].is_user_variable.is_some()
l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some()
} else {
false
};
@ -1562,22 +1588,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
/// If this rvalue supports a user-given type annotation, then
/// extract and return it. This represents the final type of the
/// rvalue and will be unified with the inferred type.
fn rvalue_user_ty(
&self,
rvalue: &Rvalue<'tcx>,
) -> Option<CanonicalTy<'tcx>> {
fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<CanonicalTy<'tcx>> {
match rvalue {
Rvalue::Use(_) |
Rvalue::Repeat(..) |
Rvalue::Ref(..) |
Rvalue::Len(..) |
Rvalue::Cast(..) |
Rvalue::BinaryOp(..) |
Rvalue::CheckedBinaryOp(..) |
Rvalue::NullaryOp(..) |
Rvalue::UnaryOp(..) |
Rvalue::Discriminant(..) =>
None,
Rvalue::Use(_)
| Rvalue::Repeat(..)
| Rvalue::Ref(..)
| Rvalue::Len(..)
| Rvalue::Cast(..)
| Rvalue::BinaryOp(..)
| Rvalue::CheckedBinaryOp(..)
| Rvalue::NullaryOp(..)
| Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..) => None,
Rvalue::Aggregate(aggregate, _) => match **aggregate {
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
@ -1585,7 +1607,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
AggregateKind::Tuple => None,
AggregateKind::Closure(_, _) => None,
AggregateKind::Generator(_, _, _) => None,
}
},
}
}

View file

@ -21,8 +21,8 @@ use rustc::ty::subst::Kind;
use rustc::ty::{self, CanonicalTy, CanonicalVar, RegionVid, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::IndexVec;
use std::mem;
/// Adds sufficient constraints to ensure that `a <: b`.
pub(super) fn sub_types<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: Ty<'tcx>,
@ -41,6 +41,7 @@ pub(super) fn sub_types<'tcx>(
Ok(())
}
/// Adds sufficient constraints to ensure that `a == b`.
pub(super) fn eq_types<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: Ty<'tcx>,
@ -59,28 +60,38 @@ pub(super) fn eq_types<'tcx>(
Ok(())
}
pub(super) fn eq_canonical_type_and_type<'tcx>(
/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
/// a user-given type (which means it may have canonical variables
/// encoding things like `_`).
pub(super) fn relate_type_and_user_type<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: CanonicalTy<'tcx>,
b: Ty<'tcx>,
a: Ty<'tcx>,
v: ty::Variance,
b: CanonicalTy<'tcx>,
locations: Locations,
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
) -> Fallible<()> {
debug!(
"eq_canonical_type_and_type(a={:?}, b={:?}, locations={:?})",
"sub_type_and_user_type(a={:?}, b={:?}, locations={:?})",
a, b, locations
);
let Canonical {
variables: a_variables,
value: a_value,
} = a;
variables: b_variables,
value: b_value,
} = b;
// The `TypeRelating` code assumes that the "canonical variables"
// appear in the "a" side, so flip `Contravariant` ambient
// variance to get the right relationship.
let v1 = ty::Contravariant.xform(v);
TypeRelating::new(
infcx,
ty::Variance::Invariant,
v1,
locations,
borrowck_context,
a_variables,
).relate(&a_value, &b)?;
b_variables,
).relate(&b_value, &a)?;
Ok(())
}
@ -128,7 +139,7 @@ struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
/// how can we enforce that? I guess I could add some kind of
/// "minimum universe constraint" that we can feed to the NLL checker.
/// --> also, we know this doesn't happen
canonical_var_values: IndexVec<CanonicalVar, Option<ScopesAndKind<'tcx>>>,
canonical_var_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>>,
}
#[derive(Clone, Debug)]
@ -194,23 +205,44 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
scope
}
/// When we encounter binders during the type traversal, we record
/// the value to substitute for each of the things contained in
/// that binder. (This will be either a universal placeholder or
/// an existential inference variable.) Given the debruijn index
/// `debruijn` (and name `br`) of some binder we have now
/// encountered, this routine finds the value that we instantiated
/// the region with; to do so, it indexes backwards into the list
/// of ambient scopes `scopes`.
fn lookup_bound_region(
debruijn: ty::DebruijnIndex,
br: &ty::BoundRegion,
first_free_index: ty::DebruijnIndex,
scopes: &[BoundRegionScope],
) -> RegionVid {
// The debruijn index is a "reverse index" into the
// scopes listing. So when we have INNERMOST (0), we
// want the *last* scope pushed, and so forth.
let debruijn_index = debruijn.index() - first_free_index.index();
let scope = &scopes[scopes.len() - debruijn_index - 1];
// Find this bound region in that scope to map to a
// particular region.
scope.map[br]
}
/// If `r` is a bound region, find the scope in which it is bound
/// (from `scopes`) and return the value that we instantiated it
/// with. Otherwise just return `r`.
fn replace_bound_region(
&self,
universal_regions: &UniversalRegions<'tcx>,
r: ty::Region<'tcx>,
first_free_index: ty::DebruijnIndex,
scopes: &[BoundRegionScope],
) -> RegionVid {
match r {
ty::ReLateBound(debruijn, br) => {
// The debruijn index is a "reverse index" into the
// scopes listing. So when we have INNERMOST (0), we
// want the *last* scope pushed, and so forth.
let debruijn_index = debruijn.index() - ty::INNERMOST.index();
let scope = &scopes[scopes.len() - debruijn_index - 1];
// Find this bound region in that scope to map to a
// particular region.
scope.map[br]
Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
}
ty::ReVar(v) => *v,
@ -219,6 +251,8 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
}
}
/// Push a new outlives requirement into our output set of
/// constraints.
fn push_outlives(&mut self, sup: RegionVid, sub: RegionVid) {
debug!("push_outlives({:?}: {:?})", sup, sub);
@ -236,46 +270,55 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
}
}
fn equate_var(
/// When we encounter a canonical variable `var` in the output,
/// equate it with `kind`. If the variable has been previously
/// equated, then equate it again.
fn relate_var(
&mut self,
var: CanonicalVar,
b_kind: Kind<'tcx>,
) -> RelateResult<'tcx, Kind<'tcx>> {
debug!("equate_var(var={:?}, b_kind={:?})", var, b_kind);
// We only encounter canonical variables when equating.
assert_eq!(self.ambient_variance, ty::Variance::Invariant);
let generalized_kind = match self.canonical_var_values[var] {
Some(v) => v,
None => {
let generalized_kind = self.generalize_value(b_kind);
self.canonical_var_values[var] = Some(generalized_kind);
generalized_kind
}
};
// The canonical variable already had a value. Equate that
// value with `b`.
let old_value = self.canonical_var_values[var].clone();
if let Some(ScopesAndKind { scopes, kind }) = old_value {
debug!("equate_var: installing kind={:?} scopes={:?}", kind, scopes);
let old_a_scopes = mem::replace(&mut self.a_scopes, scopes);
let result = self.relate(&kind, &b_kind);
self.a_scopes = old_a_scopes;
debug!("equate_var: complete, result = {:?}", result);
return result;
}
// The generalized values we extract from `canonical_var_values` have
// been fully instantiated and hence the set of scopes we have
// doesn't matter -- just to be sure, put an empty vector
// in there.
let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
// Not yet. Capture the value from the RHS and carry on.
self.canonical_var_values[var] = Some(ScopesAndKind {
scopes: self.b_scopes.clone(),
kind: b_kind,
});
debug!(
"equate_var: capturing value {:?}",
self.canonical_var_values[var]
);
// Relate the generalized kind to the original one.
let result = self.relate(&generalized_kind, &b_kind);
// FIXME -- technically, we should add some sort of
// assertion that this value can be named in the universe
// of the canonical variable. But in practice these
// canonical variables only arise presently in cases where
// they are in the root universe and the main typeck has
// ensured there are no universe errors. So we just kind
// of over look this right now.
Ok(b_kind)
// Restore the old scopes now.
self.a_scopes = old_a_scopes;
debug!("equate_var: complete, result = {:?}", result);
return result;
}
fn generalize_value(
&self,
kind: Kind<'tcx>,
) -> Kind<'tcx> {
TypeGeneralizer {
type_rel: self,
first_free_index: ty::INNERMOST,
ambient_variance: self.ambient_variance,
// These always correspond to an `_` or `'_` written by
// user, and those are always in the root universe.
universe: ty::UniverseIndex::ROOT,
}.relate(&kind, &kind)
.unwrap()
}
}
@ -326,7 +369,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
// Watch out for the case that we are matching a `?T` against the
// right-hand side.
if let ty::Infer(ty::CanonicalTy(var)) = a.sty {
self.equate_var(var, b.into())?;
self.relate_var(var, b.into())?;
Ok(a)
} else {
debug!(
@ -348,7 +391,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
}) = self.borrowck_context
{
if let ty::ReCanonical(var) = a {
self.equate_var(*var, b.into())?;
self.relate_var(*var, b.into())?;
return Ok(a);
}
@ -357,8 +400,10 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
a, b, self.ambient_variance
);
let v_a = self.replace_bound_region(universal_regions, a, &self.a_scopes);
let v_b = self.replace_bound_region(universal_regions, b, &self.b_scopes);
let v_a =
self.replace_bound_region(universal_regions, a, ty::INNERMOST, &self.a_scopes);
let v_b =
self.replace_bound_region(universal_regions, b, ty::INNERMOST, &self.b_scopes);
debug!("regions: v_a = {:?}", v_a);
debug!("regions: v_b = {:?}", v_b);
@ -425,19 +470,30 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
self.b_scopes.push(b_scope);
self.a_scopes.push(a_scope);
// FIXME -- to be fully correct, we would set the ambient
// variance to Covariant here. As is, we will sometimes
// propagate down an ambient variance of Equal -- this in
// turn causes us to report errors in some cases where
// types perhaps *ought* to be equal. See the
// `hr-fn-aau-eq-abu.rs` test for an example. Fixing this
// though is a bit nontrivial: in particular, it would
// require a more involved handling of canonical
// variables, since we would no longer be able to rely on
// having an `==` relationship for canonical variables.
// Reset the ambient variance to covariant. This is needed
// to correctly handle cases like
//
// for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32)
//
// Somewhat surprisingly, these two types are actually
// **equal**, even though the one on the right looks more
// polymorphic. The reason is due to subtyping. To see it,
// consider that each function can call the other:
//
// - The left function can call the right with `'b` and
// `'c` both equal to `'a`
//
// - The right function can call the left with `'a` set to
// `{P}`, where P is the point in the CFG where the call
// itself occurs. Note that `'b` and `'c` must both
// include P. At the point, the call works because of
// subtyping (i.e., `&'b u32 <: &{P} u32`).
let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
self.relate(a.skip_binder(), b.skip_binder())?;
self.ambient_variance = variance;
self.b_scopes.pop().unwrap();
self.a_scopes.pop().unwrap();
}
@ -458,8 +514,17 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
self.a_scopes.push(a_scope);
self.b_scopes.push(b_scope);
// Reset ambient variance to contravariance. See the
// covariant case above for an explanation.
let variance = ::std::mem::replace(
&mut self.ambient_variance,
ty::Variance::Contravariant,
);
self.relate(a.skip_binder(), b.skip_binder())?;
self.ambient_variance = variance;
self.b_scopes.pop().unwrap();
self.a_scopes.pop().unwrap();
}
@ -468,7 +533,14 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
}
}
struct ScopeInstantiator<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> {
/// When we encounter a binder like `for<..> fn(..)`, we actually have
/// to walk the `fn` value to find all the values bound by the `for`
/// (these are not explicitly present in the ty representation right
/// now). This visitor handles that: it descends the type, tracking
/// binder depth, and finds late-bound regions targeting the
/// `for<..`>. For each of those, it creates an entry in
/// `bound_region_scope`.
struct ScopeInstantiator<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
// The debruijn index of the scope we are instantiating.
target_index: ty::DebruijnIndex,
@ -510,3 +582,143 @@ impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
false
}
}
/// The "type generalize" is used when handling inference variables.
///
/// The basic strategy for handling a constraint like `?A <: B` is to
/// apply a "generalization strategy" to the type `B` -- this replaces
/// all the lifetimes in the type `B` with fresh inference
/// variables. (You can read more about the strategy in this [blog
/// post].)
///
/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
/// establishes `'0: 'x` as a constraint.
///
/// As a side-effect of this generalization procedure, we also replace
/// all the bound regions that we have traversed with concrete values,
/// so that the resulting generalized type is independent from the
/// scopes.
///
/// [blog post]: https://is.gd/0hKvIr
struct TypeGeneralizer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
type_rel: &'me TypeRelating<'me, 'bccx, 'gcx, 'tcx>,
/// After we generalize this type, we are going to relative it to
/// some other type. What will be the variance at this point?
ambient_variance: ty::Variance,
first_free_index: ty::DebruijnIndex,
universe: ty::UniverseIndex,
}
impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'bbcx, 'gcx, 'tcx> {
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
self.type_rel.infcx.tcx
}
fn tag(&self) -> &'static str {
"nll::generalizer"
}
fn a_is_expected(&self) -> bool {
true
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
a: &T,
b: &T,
) -> RelateResult<'tcx, T> {
debug!(
"TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
variance, a, b
);
let old_ambient_variance = self.ambient_variance;
self.ambient_variance = self.ambient_variance.xform(variance);
debug!(
"TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
self.ambient_variance
);
let r = self.relate(a, b)?;
self.ambient_variance = old_ambient_variance;
debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
Ok(r)
}
fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("TypeGeneralizer::tys(a={:?})", a,);
match a.sty {
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
bug!(
"unexpected inference variable encountered in NLL generalization: {:?}",
a
);
}
_ => relate::super_relate_tys(self, a, a),
}
}
fn regions(
&mut self,
a: ty::Region<'tcx>,
_: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("TypeGeneralizer::regions(a={:?})", a,);
if let ty::ReLateBound(debruijn, _) = a {
if *debruijn < self.first_free_index {
return Ok(a);
}
}
// For now, we just always create a fresh region variable to
// replace all the regions in the source type. In the main
// type checker, we special case the case where the ambient
// variance is `Invariant` and try to avoid creating a fresh
// region variable, but since this comes up so much less in
// NLL (only when users use `_` etc) it is much less
// important.
//
// As an aside, since these new variables are created in
// `self.universe` universe, this also serves to enforce the
// universe scoping rules.
//
// FIXME(#54105) -- if the ambient variance is bivariant,
// though, we may however need to check well-formedness or
// risk a problem like #41677 again.
let replacement_region_vid = self.type_rel
.infcx
.next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, self.universe);
Ok(replacement_region_vid)
}
fn binders<T>(
&mut self,
a: &ty::Binder<T>,
_: &ty::Binder<T>,
) -> RelateResult<'tcx, ty::Binder<T>>
where
T: Relate<'tcx>,
{
debug!("TypeGeneralizer::binders(a={:?})", a,);
self.first_free_index.shift_in(1);
let result = self.relate(a.skip_binder(), a.skip_binder())?;
self.first_free_index.shift_out(1);
Ok(ty::Binder::bind(result))
}
}

View file

@ -106,7 +106,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
remainder_scope,
init_scope,
pattern,
ty,
initializer,
lint_level
} => {
@ -136,7 +135,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
let scope = (init_scope, source_info);
this.in_scope(scope, lint_level, block, |this| {
this.expr_into_pattern(block, ty, pattern, init)
this.expr_into_pattern(block, pattern, init)
})
}));
} else {
@ -144,16 +143,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
None, remainder_span, lint_level, slice::from_ref(&pattern),
ArmHasGuard(false), None);
// FIXME(#47184): We currently only insert `UserAssertTy` statements for
// patterns that are bindings, this is as we do not want to deconstruct
// the type being assertion to match the pattern.
if let PatternKind::Binding { var, .. } = *pattern.kind {
if let Some(ty) = ty {
this.user_assert_ty(block, ty, var, span);
}
}
this.visit_bindings(&pattern, &mut |this, _, _, _, node, span, _| {
this.visit_bindings(&pattern, None, &mut |this, _, _, _, node, span, _, _| {
this.storage_live_binding(block, node, span, OutsideGuard);
this.schedule_drop_for_binding(node, span, OutsideGuard);
})

View file

@ -296,6 +296,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let ptr_temp = this.local_decls.push(LocalDecl {
mutability: Mutability::Mut,
ty: ptr_ty,
user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,7 @@
//! testing a value against a constant.
use build::{BlockAnd, BlockAndExtension, Builder};
use build::matches::{Binding, MatchPair, Candidate};
use build::matches::{Ascription, Binding, MatchPair, Candidate};
use hair::*;
use rustc::mir::*;
@ -63,6 +63,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
candidate: &mut Candidate<'pat, 'tcx>)
-> Result<(), MatchPair<'pat, 'tcx>> {
match *match_pair.pattern.kind {
PatternKind::AscribeUserType { ref subpattern, user_ty } => {
candidate.ascriptions.push(Ascription {
span: match_pair.pattern.span,
user_ty,
source: match_pair.place.clone(),
});
candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
Ok(())
}
PatternKind::Wild => {
// nothing left to do
Ok(())

View file

@ -96,6 +96,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
PatternKind::AscribeUserType { .. } |
PatternKind::Array { .. } |
PatternKind::Slice { .. } |
PatternKind::Wild |
@ -138,6 +139,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
PatternKind::Array { .. } |
PatternKind::Wild |
PatternKind::Binding { .. } |
PatternKind::AscribeUserType { .. } |
PatternKind::Leaf { .. } |
PatternKind::Deref { .. } => {
// don't know how to add these patterns to a switch
@ -638,6 +640,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
span: candidate.span,
match_pairs: other_match_pairs,
bindings: candidate.bindings.clone(),
ascriptions: candidate.ascriptions.clone(),
guard: candidate.guard.clone(),
arm_index: candidate.arm_index,
pat_index: candidate.pat_index,
@ -702,6 +705,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
span: candidate.span,
match_pairs: all_match_pairs,
bindings: candidate.bindings.clone(),
ascriptions: candidate.ascriptions.clone(),
guard: candidate.guard.clone(),
arm_index: candidate.arm_index,
pat_index: candidate.pat_index,

View file

@ -730,6 +730,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
self.local_decls.push(LocalDecl {
mutability: Mutability::Mut,
ty,
user_ty: None,
source_info,
visibility_scope: source_info.scope,
name,

View file

@ -338,7 +338,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
mir::StatementKind::SetDiscriminant { .. } |
mir::StatementKind::StorageLive(..) |
mir::StatementKind::Validate(..) |
mir::StatementKind::UserAssertTy(..) |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => {}
}

View file

@ -304,7 +304,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
}
StatementKind::EndRegion(_) |
StatementKind::Validate(..) |
StatementKind::UserAssertTy(..) |
StatementKind::AscribeUserType(..) |
StatementKind::Nop => {}
}
}

View file

@ -76,14 +76,26 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
first_statement_index: region::FirstStatementIndex::new(index),
});
let ty = local.ty.clone().map(|ty| ty.hir_id);
let pattern = cx.pattern_from_hir(&local.pat);
let mut pattern = cx.pattern_from_hir(&local.pat);
if let Some(ty) = &local.ty {
if let Some(user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) {
pattern = Pattern {
ty: pattern.ty,
span: pattern.span,
kind: Box::new(PatternKind::AscribeUserType {
user_ty: *user_ty,
subpattern: pattern
})
};
}
}
result.push(StmtRef::Mirror(Box::new(Stmt {
kind: StmtKind::Let {
remainder_scope: remainder_scope,
init_scope: region::Scope::Node(hir_id.local_id),
pattern,
ty,
initializer: local.init.to_ref(),
lint_level: cx.lint_level_of(local.id),
},

View file

@ -93,12 +93,11 @@ pub enum StmtKind<'tcx> {
/// lifetime of temporaries
init_scope: region::Scope,
/// let <PAT>: ty = ...
/// `let <PAT> = ...`
///
/// if a type is included, it is added as an ascription pattern
pattern: Pattern<'tcx>,
/// let pat: <TY> = init ...
ty: Option<hir::HirId>,
/// let pat: ty = <INIT> ...
initializer: Option<ExprRef<'tcx>>,

View file

@ -1235,6 +1235,8 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt,
-> Option<Vec<Constructor<'tcx>>>
{
match *pat.kind {
PatternKind::AscribeUserType { ref subpattern, .. } =>
pat_constructors(cx, subpattern, pcx),
PatternKind::Binding { .. } | PatternKind::Wild => None,
PatternKind::Leaf { .. } | PatternKind::Deref { .. } => Some(vec![Single]),
PatternKind::Variant { adt_def, variant_index, .. } => {
@ -1606,6 +1608,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
let pat = &r[0];
let head: Option<Vec<&Pattern>> = match *pat.kind {
PatternKind::AscribeUserType { ref subpattern, .. } =>
specialize(cx, ::std::slice::from_ref(&subpattern), constructor, wild_patterns),
PatternKind::Binding { .. } | PatternKind::Wild => {
Some(wild_patterns.to_owned())
}

View file

@ -20,7 +20,7 @@ use interpret::{const_field, const_variant_index};
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind, RangeEnd};
use rustc::hir::def::{Def, CtorKind};
@ -66,6 +66,11 @@ pub struct Pattern<'tcx> {
pub enum PatternKind<'tcx> {
Wild,
AscribeUserType {
user_ty: CanonicalTy<'tcx>,
subpattern: Pattern<'tcx>,
},
/// x, ref x, x @ P, etc
Binding {
mutability: Mutability,
@ -125,6 +130,8 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.kind {
PatternKind::Wild => write!(f, "_"),
PatternKind::AscribeUserType { ref subpattern, .. } =>
write!(f, "{}: _", subpattern),
PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => {
let is_mut = match mode {
BindingMode::ByValue => mutability == Mutability::Mut,
@ -939,7 +946,7 @@ macro_rules! CloneImpls {
CloneImpls!{ <'tcx>
Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>, CanonicalTy<'tcx>
}
impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
@ -973,6 +980,13 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
match *self {
PatternKind::Wild => PatternKind::Wild,
PatternKind::AscribeUserType {
ref subpattern,
user_ty,
} => PatternKind::AscribeUserType {
subpattern: subpattern.fold_with(folder),
user_ty: user_ty.fold_with(folder),
},
PatternKind::Binding {
mutability,
name,

View file

@ -159,7 +159,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
}
EndRegion(..) => {}
UserAssertTy(..) => {}
AscribeUserType(..) => {}
// Defined to do nothing. These are added by optimization passes, to avoid changing the
// size of MIR constantly.

View file

@ -39,6 +39,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
#![feature(if_while_or_patterns)]
#![feature(try_from)]
#![feature(reverse_bits)]
#![feature(underscore_imports)]
#![recursion_limit="256"]

View file

@ -140,7 +140,9 @@ enum CallKind {
fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span };
LocalDecl {
mutability, ty, name: None,
mutability, ty,
user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,
internal: false,

View file

@ -114,7 +114,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
StatementKind::StorageDead(..) |
StatementKind::EndRegion(..) |
StatementKind::Validate(..) |
StatementKind::UserAssertTy(..) |
StatementKind::AscribeUserType(..) |
StatementKind::Nop => {
// safe (at least as emitted during MIR construction)
}

View file

@ -12,7 +12,7 @@
//!
//! - `CleanEndRegions`, that reduces the set of `EndRegion` statements
//! in the MIR.
//! - `CleanUserAssertTy`, that replaces all `UserAssertTy` statements
//! - `CleanAscribeUserType`, that replaces all `AscribeUserType` statements
//! with `Nop`.
//!
//! The `CleanEndRegions` "pass" is actually implemented as two
@ -24,10 +24,10 @@
//! MIR and removes any `EndRegion` that is applied to a region that
//! was not seen in the previous pass.
//!
//! The `CleanUserAssertTy` pass runs at a distinct time from the
//! `CleanEndRegions` pass. It is important that the `CleanUserAssertTy`
//! The `CleanAscribeUserType` pass runs at a distinct time from the
//! `CleanEndRegions` pass. It is important that the `CleanAscribeUserType`
//! pass runs after the MIR borrowck so that the NLL type checker can
//! perform the type assertion when it encounters the `UserAssertTy`
//! perform the type assertion when it encounters the `AscribeUserType`
//! statements.
use rustc_data_structures::fx::FxHashSet;
@ -110,26 +110,26 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> {
}
}
pub struct CleanUserAssertTy;
pub struct CleanAscribeUserType;
pub struct DeleteUserAssertTy;
pub struct DeleteAscribeUserType;
impl MirPass for CleanUserAssertTy {
impl MirPass for CleanAscribeUserType {
fn run_pass<'a, 'tcx>(&self,
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
_source: MirSource,
mir: &mut Mir<'tcx>) {
let mut delete = DeleteUserAssertTy;
let mut delete = DeleteAscribeUserType;
delete.visit_mir(mir);
}
}
impl<'tcx> MutVisitor<'tcx> for DeleteUserAssertTy {
impl<'tcx> MutVisitor<'tcx> for DeleteAscribeUserType {
fn visit_statement(&mut self,
block: BasicBlock,
statement: &mut Statement<'tcx>,
location: Location) {
if let StatementKind::UserAssertTy(..) = statement.kind {
if let StatementKind::AscribeUserType(..) = statement.kind {
statement.make_nop();
}
self.super_statement(block, statement, location);

View file

@ -303,6 +303,7 @@ fn replace_result_variable<'tcx>(
let new_ret = LocalDecl {
mutability: Mutability::Mut,
ty: ret_ty,
user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,
@ -656,6 +657,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
mir.local_decls[RETURN_PLACE] = LocalDecl {
mutability: Mutability::Mut,
ty: tcx.mk_nil(),
user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,
@ -672,6 +674,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
ty: gen_ty,
mutbl: hir::Mutability::MutMutable,
}),
user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,

View file

@ -238,8 +238,8 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
simplify_branches::SimplifyBranches::new("initial"),
remove_noop_landing_pads::RemoveNoopLandingPads,
simplify::SimplifyCfg::new("early-opt"),
// Remove all `UserAssertTy` statements.
cleanup_post_borrowck::CleanUserAssertTy,
// Remove all `AscribeUserType` statements.
cleanup_post_borrowck::CleanAscribeUserType,
// These next passes must be executed together
add_call_guards::CriticalCallEdges,

View file

@ -1098,7 +1098,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
StatementKind::InlineAsm {..} |
StatementKind::EndRegion(_) |
StatementKind::Validate(..) |
StatementKind::UserAssertTy(..) |
StatementKind::AscribeUserType(..) |
StatementKind::Nop => {}
}
});

View file

@ -230,7 +230,7 @@ fn check_statement(
| StatementKind::StorageDead(_)
| StatementKind::Validate(..)
| StatementKind::EndRegion(_)
| StatementKind::UserAssertTy(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Nop => Ok(()),
}
}

View file

@ -53,7 +53,7 @@ impl RemoveNoopLandingPads {
StatementKind::StorageLive(_) |
StatementKind::StorageDead(_) |
StatementKind::EndRegion(_) |
StatementKind::UserAssertTy(..) |
StatementKind::AscribeUserType(..) |
StatementKind::Nop => {
// These are all nops in a landing pad (there's some
// borrowck interaction between EndRegion and storage

View file

@ -163,7 +163,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir::StatementKind::InlineAsm { .. } |
mir::StatementKind::EndRegion(_) |
mir::StatementKind::Validate(..) |
mir::StatementKind::UserAssertTy(..) |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => continue,
mir::StatementKind::SetDiscriminant{ .. } =>
span_bug!(stmt.source_info.span,

View file

@ -17,6 +17,7 @@ use rustc::ty::item_path;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
use std::fmt::Display;
use std::fmt::Write as _;
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
@ -493,14 +494,18 @@ fn write_scope_tree(
};
let indent = indent + INDENT.len();
let indented_var = format!(
"{0:1$}let {2}{3:?}: {4:?};",
let mut indented_var = format!(
"{0:1$}let {2}{3:?}: {4:?}",
INDENT,
indent,
mut_str,
local,
var.ty
);
if let Some(user_ty) = var.user_ty {
write!(indented_var, " as {:?}", user_ty).unwrap();
}
indented_var.push_str(";");
writeln!(
w,
"{0:1$} // \"{2}\" in {3}",

View file

@ -92,7 +92,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
StatementKind::StorageLive(..) => "StatementKind::StorageLive",
StatementKind::StorageDead(..) => "StatementKind::StorageDead",
StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm",
StatementKind::UserAssertTy(..) => "StatementKind::UserAssertTy",
StatementKind::AscribeUserType(..) => "StatementKind::AscribeUserType",
StatementKind::Nop => "StatementKind::Nop",
}, &statement.kind);
self.super_statement(block, statement, location);

View file

@ -49,7 +49,7 @@ pub fn add_type() {
#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,TypeckTables,MirValidated")]
except="HirBody,TypeckTables,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
pub fn add_type() {
let _x: u32 = 2u32;

View file

@ -19,9 +19,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// check that codegen of assignment expressions is sane. Assignments
// tend to be absent in simple code, so subtle breakage in them can
// leave a quite hard-to-find trail of destruction.
// Check codegen for assignments (`a = b`) where the left-hand-side is
// not yet initialized. Assignments tend to be absent in simple code,
// so subtle breakage in them can leave a quite hard-to-find trail of
// destruction.
// ignore-tidy-linelength
@ -29,60 +30,42 @@ fn main() {
let nodrop_x = false;
let nodrop_y;
// Since boolean does not require drop, this can be a simple
// assignment:
nodrop_y = nodrop_x;
let drop_x : Option<Box<u32>> = None;
let drop_y;
// Since the type of `drop_y` has drop, we generate a `replace`
// terminator:
drop_y = drop_x;
}
// END RUST SOURCE
// START rustc.main.SimplifyCfg-initial.after.mir
// bb0: {
// StorageLive(_1);
// _1 = const false;
// StorageLive(_2);
// StorageLive(_3);
// _3 = _1;
// _2 = move _3;
// StorageDead(_3);
// StorageLive(_4);
// UserAssertTy(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }, _4);
// _4 = std::option::Option<std::boxed::Box<u32>>::None;
// StorageLive(_5);
// StorageLive(_6);
// _6 = move _4;
// replace(_5 <-move _6) -> [return: bb2, unwind: bb5];
// }
// bb1: {
// resume;
// }
// bb2: {
// drop(_6) -> [return: bb6, unwind: bb4];
// }
// bb3: {
// drop(_4) -> bb1;
// }
// bb4: {
// drop(_5) -> bb3;
// }
// bb5: {
// drop(_6) -> bb4;
// }
// bb6: {
// StorageDead(_6);
// _0 = ();
// drop(_5) -> [return: bb7, unwind: bb3];
// }
// bb7: {
// StorageDead(_5);
// drop(_4) -> [return: bb8, unwind: bb1];
// }
// bb8: {
// StorageDead(_4);
// StorageDead(_2);
// StorageDead(_1);
// return;
// }
// bb0: {
// StorageLive(_1);
// _1 = const false;
// StorageLive(_2);
// StorageLive(_3);
// _3 = _1;
// _2 = move _3;
// StorageDead(_3);
// StorageLive(_4);
// _4 = std::option::Option<std::boxed::Box<u32>>::None;
// AscribeUserType(_4, o, Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> });
// StorageLive(_5);
// StorageLive(_6);
// _6 = move _4;
// replace(_5 <- move _6) -> [return: bb2, unwind: bb5];
// }
// ...
// bb2: {
// drop(_6) -> [return: bb6, unwind: bb4];
// }
// ...
// bb5: {
// drop(_6) -> bb4;
// }
// END rustc.main.SimplifyCfg-initial.after.mir

View file

@ -1,38 +0,0 @@
// Copyright 2012-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.
// Basic test for reborrow constraints: the region (`R5`) that appears
// in the type of `r_a` must outlive the region (`R7`) that appears in
// the type of `r_b`
// compile-flags:-Zborrowck=mir -Zverbose
// ^^^^^^^^^ force compiler to dump more region information
#![allow(warnings)]
fn use_x(_: &mut i32) -> bool { true }
fn main() {
let mut foo: i32 = 22;
let r_a: &mut i32 = &mut foo;
let r_b: &mut i32 = &mut *r_a;
use_x(r_b);
}
// END RUST SOURCE
// START rustc.main.nll.0.mir
// | '_#7r | U0 | {bb0[4], bb0[8..=17]}
// ...
// | '_#9r | U0 | {bb0[10], bb0[14..=17]}
// ...
// let _4: &'_#9r mut i32;
// ...
// let _2: &'_#7r mut i32;
// END rustc.main.nll.0.mir

View file

@ -1,22 +0,0 @@
error: `foo` is not yet stable as a const fn
--> $DIR/dont_promote_unstable_const_fn.rs:25:25
|
LL | const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
| ^^^^^
|
= help: in Nightly builds, add `#![feature(foo)]` to the crate attributes to enable
error[E0597]: borrowed value does not live long enough
--> $DIR/dont_promote_unstable_const_fn.rs:33:26
|
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
LL | //~^ does not live long enough
LL | }
| - temporary value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0597`.

View file

@ -1,13 +0,0 @@
error[E0597]: borrowed value does not live long enough
--> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:19:29
|
LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough
| ^^^^^ temporary value does not live long enough
LL | }
| - temporary value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.

View file

@ -20,8 +20,17 @@ fn make_it() -> for<'a> fn(&'a u32, &'a u32) -> &'a u32 {
panic!()
}
fn main() {
fn foo() {
let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
//~^ ERROR higher-ranked subtype error
drop(a);
}
fn bar() {
// The code path for patterns is mildly different, so go ahead and
// test that too:
let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
//~^ ERROR higher-ranked subtype error
}
fn main() { }

View file

@ -4,5 +4,11 @@ error: higher-ranked subtype error
LL | let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
| ^^^^^^^^^
error: aborting due to previous error
error: higher-ranked subtype error
--> $DIR/hr-fn-aaa-as-aba.rs:32:58
|
LL | let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
| ^^^^^^^^^
error: aborting due to 2 previous errors

View file

@ -16,9 +16,7 @@
// another -- effectively, the single lifetime `'a` is just inferred
// to be the intersection of the two distinct lifetimes.
//
// FIXME: However, we currently reject this example with an error,
// because of how we handle binders and equality in `relate_tys`.
//
// compile-pass
// compile-flags:-Zno-leak-check
#![feature(nll)]
@ -31,7 +29,6 @@ fn make_cell_aa() -> Cell<for<'a> fn(&'a u32, &'a u32)> {
fn aa_eq_ab() {
let a: Cell<for<'a, 'b> fn(&'a u32, &'b u32)> = make_cell_aa();
//~^ ERROR higher-ranked subtype error
drop(a);
}

View file

@ -1,8 +0,0 @@
error: higher-ranked subtype error
--> $DIR/hr-fn-aau-eq-abu.rs:33:53
|
LL | let a: Cell<for<'a, 'b> fn(&'a u32, &'b u32)> = make_cell_aa();
| ^^^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -0,0 +1,17 @@
// Test that the NLL `relate_tys` code correctly deduces that a
// function returning either argument CANNOT be upcast to one
// that returns always its first argument.
//
// compile-flags:-Zno-leak-check
#![feature(nll)]
fn make_it() -> fn(&'static u32) -> &'static u32 {
panic!()
}
fn main() {
let a: fn(_) -> _ = make_it();
let b: fn(&u32) -> &u32 = a;
drop(a);
}

View file

@ -0,0 +1,8 @@
error: higher-ranked subtype error
--> $DIR/universe-violation.rs:15:31
|
LL | let b: fn(&u32) -> &u32 = a;
| ^
error: aborting due to previous error

View file

@ -0,0 +1,38 @@
// Copyright 2017 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.
// Test that the NLL `relate_tys` code correctly deduces that a
// function returning always its first argument can be upcast to one
// that returns either first or second argument.
#![feature(nll)]
#![allow(warnings)]
use std::cell::Cell;
type DoubleCell<A> = Cell<(A, A)>;
type DoublePair<A> = (A, A);
fn make_cell<'b>(x: &'b u32) -> Cell<(&'static u32, &'b u32)> {
panic!()
}
fn main() {
let a: &'static u32 = &22;
let b = 44;
// Here we get an error because `DoubleCell<_>` requires the same type
// on both parts of the `Cell`, and we can't have that.
let x: DoubleCell<_> = make_cell(&b); //~ ERROR
// Here we do not get an error because `DoublePair<_>` permits
// variance on the lifetimes involved.
let y: DoublePair<_> = make_cell(&b).get();
}

View file

@ -0,0 +1,14 @@
error[E0597]: `b` does not live long enough
--> $DIR/var-appears-twice.rs:33:38
|
LL | let x: DoubleCell<_> = make_cell(&b); //~ ERROR
| ^^ borrowed value does not live long enough
...
LL | }
| - `b` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.

View file

@ -0,0 +1,121 @@
// Test that various patterns also enforce types.
#![feature(nll)]
fn variable_no_initializer() {
let x = 22;
let y: &'static u32;
y = &x; //~ ERROR
}
fn tuple_no_initializer() {
// FIXME(#47187): We are not propagating ascribed type through tuples.
let x = 22;
let (y, z): (&'static u32, &'static u32);
y = &x;
}
fn ref_with_ascribed_static_type() -> u32 {
// Check the behavior in some wacky cases.
let x = 22;
let y = &x; //~ ERROR
let ref z: &'static u32 = y;
**z
}
fn ref_with_ascribed_any_type() -> u32 {
let x = 22;
let y = &x;
let ref z: &u32 = y;
**z
}
struct Single<T> { value: T }
fn struct_no_initializer() {
// FIXME(#47187): We are not propagating ascribed type through patterns.
let x = 22;
let Single { value: y }: Single<&'static u32>;
y = &x;
}
fn variable_with_initializer() {
let x = 22;
let y: &'static u32 = &x; //~ ERROR
}
fn underscore_with_initializer() {
let x = 22;
let _: &'static u32 = &x; //~ ERROR
let _: Vec<&'static String> = vec![&String::new()];
//~^ ERROR borrowed value does not live long enough [E0597]
let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
//~^ ERROR borrowed value does not live long enough [E0597]
let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
//~^ ERROR borrowed value does not live long enough [E0597]
}
fn pair_underscores_with_initializer() {
let x = 22;
let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR
}
fn pair_variable_with_initializer() {
let x = 22;
let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR
}
fn struct_single_field_variable_with_initializer() {
let x = 22;
let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR
}
fn struct_single_field_underscore_with_initializer() {
let x = 22;
let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR
}
struct Double<T> { value1: T, value2: T }
fn struct_double_field_underscore_with_initializer() {
let x = 22;
let Double { value1: _, value2: _ }: Double<&'static u32> = Double {
value1: &x, //~ ERROR
value2: &44,
};
}
fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
// The error in this test is inconsistency with
// `static_to_a_to_static_through_tuple`, but "feels right" to
// me. It occurs because we special case the single binding case
// and force the type of `y` to be `&'a u32`, even though the
// right-hand side has type `&'static u32`.
let y: &'a u32 = &22;
y //~ ERROR
}
fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 {
// FIXME(#47187): The fact that this type-checks is perhaps surprising.
// What happens is that the right-hand side is constrained to have
// type `&'a u32`, which is possible, because it has type
// `&'static u32`. The variable `y` is then forced to have type
// `&'static u32`, but it is constrained only by the right-hand
// side, not the ascribed type, and hence it passes.
let (y, _z): (&'a u32, u32) = (&22, 44);
y
}
fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 {
let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR
y
}
fn main() { }

View file

@ -0,0 +1,143 @@
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:8:9
|
LL | y = &x; //~ ERROR
| ^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:22:13
|
LL | let y = &x; //~ ERROR
| ^^ borrowed value does not live long enough
...
LL | }
| - `x` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:46:27
|
LL | let y: &'static u32 = &x; //~ ERROR
| ^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:51:27
|
LL | let _: &'static u32 = &x; //~ ERROR
| ^^ borrowed value does not live long enough
...
LL | }
| - `x` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
--> $DIR/patterns.rs:53:41
|
LL | let _: Vec<&'static String> = vec![&String::new()];
| ^^^^^^^^^^^^^ - temporary value only lives until here
| |
| temporary value does not live long enough
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
--> $DIR/patterns.rs:56:52
|
LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
| ^^^^^^^^^^^^^ - temporary value only lives until here
| |
| temporary value does not live long enough
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
--> $DIR/patterns.rs:59:53
|
LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
| ^^^^^^^^^^^^^ - temporary value only lives until here
| |
| temporary value does not live long enough
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:65:40
|
LL | let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR
| ^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:70:40
|
LL | let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR
| ^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:75:69
|
LL | let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR
| ^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:80:69
|
LL | let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR
| ^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:88:17
|
LL | value1: &x, //~ ERROR
| ^^ borrowed value does not live long enough
...
LL | }
| - `x` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error: unsatisfied lifetime constraints
--> $DIR/patterns.rs:101:5
|
LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
...
LL | y //~ ERROR
| ^ returning this value requires that `'a` must outlive `'static`
error: unsatisfied lifetime constraints
--> $DIR/patterns.rs:117:40
|
LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
LL | let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR
| ^^^^^^^ requires that `'a` must outlive `'static`
error: aborting due to 14 previous errors
For more information about this error, try `rustc --explain E0597`.

View file

@ -1,13 +1,14 @@
error[E0597]: `my_string` does not live long enough
--> $DIR/try-block-bad-lifetime.rs:25:33
|
LL | let result: Result<(), &str> = try {
| ------ borrow later used here
LL | let my_string = String::from("");
LL | let my_str: & str = & my_string;
| ^^^^^^^^^^^ borrowed value does not live long enough
...
LL | };
| - `my_string` dropped here while still borrowed
LL | do_something_with(result);
| ------ borrow later used here
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/try-block-bad-lifetime.rs:39:13