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:
commit
2f1547c0aa
55 changed files with 1868 additions and 1003 deletions
|
@ -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
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! {
|
|||
::ty::ClosureKind,
|
||||
::ty::IntVarValue,
|
||||
::ty::ParamTy,
|
||||
::ty::Variance,
|
||||
::syntax_pos::Span,
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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,
|
||||
) {
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
})
|
||||
|
|
|
@ -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
|
@ -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(())
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 => {}
|
||||
|
||||
}
|
||||
|
|
|
@ -304,7 +304,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
}
|
||||
StatementKind::EndRegion(_) |
|
||||
StatementKind::Validate(..) |
|
||||
StatementKind::UserAssertTy(..) |
|
||||
StatementKind::AscribeUserType(..) |
|
||||
StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
|
|
|
@ -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>>,
|
||||
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"]
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 => {}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -230,7 +230,7 @@ fn check_statement(
|
|||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Validate(..)
|
||||
| StatementKind::EndRegion(_)
|
||||
| StatementKind::UserAssertTy(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Nop => Ok(()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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`.
|
|
@ -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`.
|
|
@ -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() { }
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
17
src/test/ui/nll/relate_tys/universe-violation.rs
Normal file
17
src/test/ui/nll/relate_tys/universe-violation.rs
Normal 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);
|
||||
}
|
8
src/test/ui/nll/relate_tys/universe-violation.stderr
Normal file
8
src/test/ui/nll/relate_tys/universe-violation.stderr
Normal 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
|
||||
|
38
src/test/ui/nll/relate_tys/var-appears-twice.rs
Normal file
38
src/test/ui/nll/relate_tys/var-appears-twice.rs
Normal 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();
|
||||
}
|
14
src/test/ui/nll/relate_tys/var-appears-twice.stderr
Normal file
14
src/test/ui/nll/relate_tys/var-appears-twice.stderr
Normal 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`.
|
121
src/test/ui/nll/user-annotations/patterns.rs
Normal file
121
src/test/ui/nll/user-annotations/patterns.rs
Normal 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() { }
|
143
src/test/ui/nll/user-annotations/patterns.stderr
Normal file
143
src/test/ui/nll/user-annotations/patterns.stderr
Normal 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`.
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue