Auto merge of #53225 - nikomatsakis:nll-type-annot, r=pnkfelix
MIR: support user-given type annotations on fns, structs, and enums This branch adds tooling to track user-given type annotations on functions, structs, and enum variant expressions. The user-given types are passed onto NLL which then enforces them. cc #47184 — not a complete fix, as there are more cases to cover r? @eddyb cc @rust-lang/wg-compiler-nll
This commit is contained in:
commit
d95f078f0a
|
@ -68,7 +68,7 @@ pub enum Def {
|
|||
Const(DefId),
|
||||
Static(DefId, bool /* is_mutbl */),
|
||||
StructCtor(DefId, CtorKind), // DefId refers to NodeId of the struct's constructor
|
||||
VariantCtor(DefId, CtorKind),
|
||||
VariantCtor(DefId, CtorKind), // DefId refers to the enum variant
|
||||
Method(DefId),
|
||||
AssociatedConst(DefId),
|
||||
|
||||
|
|
|
@ -479,10 +479,11 @@ for mir::AggregateKind<'gcx> {
|
|||
mir::AggregateKind::Array(t) => {
|
||||
t.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => {
|
||||
mir::AggregateKind::Adt(adt_def, idx, substs, user_substs, active_field) => {
|
||||
adt_def.hash_stable(hcx, hasher);
|
||||
idx.hash_stable(hcx, hasher);
|
||||
substs.hash_stable(hcx, hasher);
|
||||
user_substs.hash_stable(hcx, hasher);
|
||||
active_field.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::AggregateKind::Closure(def_id, ref substs) => {
|
||||
|
@ -528,7 +529,7 @@ impl_stable_hash_for!(enum mir::NullOp {
|
|||
SizeOf
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
|
||||
impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, user_ty, literal });
|
||||
|
||||
impl_stable_hash_for!(struct mir::Location { block, statement_index });
|
||||
|
||||
|
|
|
@ -188,6 +188,36 @@ impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx, V> Canonical<'gcx, V> {
|
||||
/// Allows you to map the `value` of a canonical while keeping the
|
||||
/// same set of bound variables.
|
||||
///
|
||||
/// **WARNING:** This function is very easy to mis-use, hence the
|
||||
/// name! In particular, the new value `W` must use all **the
|
||||
/// same type/region variables** in **precisely the same order**
|
||||
/// as the original! (The ordering is defined by the
|
||||
/// `TypeFoldable` implementation of the type in question.)
|
||||
///
|
||||
/// An example of a **correct** use of this:
|
||||
///
|
||||
/// ```rust,ignore (not real code)
|
||||
/// let a: Canonical<'_, T> = ...;
|
||||
/// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
|
||||
/// ```
|
||||
///
|
||||
/// An example of an **incorrect** use of this:
|
||||
///
|
||||
/// ```rust,ignore (not real code)
|
||||
/// let a: Canonical<'tcx, T> = ...;
|
||||
/// let ty: Ty<'tcx> = ...;
|
||||
/// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
|
||||
/// ```
|
||||
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'gcx, W> {
|
||||
let Canonical { variables, value } = self;
|
||||
Canonical { variables, value: map_op(value) }
|
||||
}
|
||||
}
|
||||
|
||||
pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
|
|
|
@ -1888,12 +1888,15 @@ pub enum Operand<'tcx> {
|
|||
/// This implies that the type of the place must be `Copy`; this is true
|
||||
/// by construction during build, but also checked by the MIR type checker.
|
||||
Copy(Place<'tcx>),
|
||||
|
||||
/// Move: The value (including old borrows of it) will not be used again.
|
||||
///
|
||||
/// Safe for values of all types (modulo future developments towards `?Move`).
|
||||
/// Correct usage patterns are enforced by the borrow checker for safe code.
|
||||
/// `Copy` may be converted to `Move` to enable "last-use" optimizations.
|
||||
Move(Place<'tcx>),
|
||||
|
||||
/// Synthesizes a constant value.
|
||||
Constant(Box<Constant<'tcx>>),
|
||||
}
|
||||
|
||||
|
@ -1909,6 +1912,9 @@ impl<'tcx> Debug for Operand<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> Operand<'tcx> {
|
||||
/// Convenience helper to make a constant that refers to the fn
|
||||
/// with given def-id and substs. Since this is used to synthesize
|
||||
/// MIR, assumes `user_ty` is None.
|
||||
pub fn function_handle<'a>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
|
@ -1919,6 +1925,7 @@ impl<'tcx> Operand<'tcx> {
|
|||
Operand::Constant(box Constant {
|
||||
span,
|
||||
ty,
|
||||
user_ty: None,
|
||||
literal: ty::Const::zero_sized(tcx, ty),
|
||||
})
|
||||
}
|
||||
|
@ -2002,7 +2009,7 @@ pub enum AggregateKind<'tcx> {
|
|||
/// active field number and is present only for union expressions
|
||||
/// -- e.g. for a union expression `SomeUnion { c: .. }`, the
|
||||
/// active field index would identity the field `c`
|
||||
Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<usize>),
|
||||
Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<CanonicalTy<'tcx>>, Option<usize>),
|
||||
|
||||
Closure(DefId, ClosureSubsts<'tcx>),
|
||||
Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability),
|
||||
|
@ -2128,7 +2135,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
_ => fmt_tuple(fmt, places),
|
||||
},
|
||||
|
||||
AggregateKind::Adt(adt_def, variant, substs, _) => {
|
||||
AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => {
|
||||
let variant_def = &adt_def.variants[variant];
|
||||
|
||||
ppaux::parameterized(fmt, substs, variant_def.did, &[])?;
|
||||
|
@ -2207,6 +2214,14 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
pub struct Constant<'tcx> {
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
|
||||
/// Optional user-given type: for something like
|
||||
/// `collect::<Vec<_>>`, this would be present and would
|
||||
/// indicate that `Vec<_>` was explicitly specified.
|
||||
///
|
||||
/// Needed for NLL to impose user-given type constraints.
|
||||
pub user_ty: Option<CanonicalTy<'tcx>>,
|
||||
|
||||
pub literal: &'tcx ty::Const<'tcx>,
|
||||
}
|
||||
|
||||
|
@ -2798,8 +2813,14 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
|
|||
let kind = box match **kind {
|
||||
AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
|
||||
AggregateKind::Tuple => AggregateKind::Tuple,
|
||||
AggregateKind::Adt(def, v, substs, n) => {
|
||||
AggregateKind::Adt(def, v, substs.fold_with(folder), n)
|
||||
AggregateKind::Adt(def, v, substs, user_ty, n) => {
|
||||
AggregateKind::Adt(
|
||||
def,
|
||||
v,
|
||||
substs.fold_with(folder),
|
||||
user_ty.fold_with(folder),
|
||||
n,
|
||||
)
|
||||
}
|
||||
AggregateKind::Closure(id, substs) => {
|
||||
AggregateKind::Closure(id, substs.fold_with(folder))
|
||||
|
@ -2831,7 +2852,8 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
|
|||
(match **kind {
|
||||
AggregateKind::Array(ty) => ty.visit_with(visitor),
|
||||
AggregateKind::Tuple => false,
|
||||
AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor),
|
||||
AggregateKind::Adt(_, _, substs, user_ty, _) =>
|
||||
substs.visit_with(visitor) || user_ty.visit_with(visitor),
|
||||
AggregateKind::Closure(_, substs) => substs.visit_with(visitor),
|
||||
AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor),
|
||||
}) || fields.visit_with(visitor)
|
||||
|
@ -2902,6 +2924,7 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
|
|||
Constant {
|
||||
span: self.span.clone(),
|
||||
ty: self.ty.fold_with(folder),
|
||||
user_ty: self.user_ty.fold_with(folder),
|
||||
literal: self.literal.fold_with(folder),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,7 +216,7 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
AggregateKind::Tuple => {
|
||||
tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
|
||||
}
|
||||
AggregateKind::Adt(def, _, substs, _) => {
|
||||
AggregateKind::Adt(def, _, substs, _, _) => {
|
||||
tcx.type_of(def.did).subst(tcx, substs)
|
||||
}
|
||||
AggregateKind::Closure(did, substs) => {
|
||||
|
|
|
@ -213,6 +213,10 @@ macro_rules! make_mir_visitor {
|
|||
self.super_ty(ty);
|
||||
}
|
||||
|
||||
fn visit_canonical_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
|
||||
self.super_canonical_ty(ty);
|
||||
}
|
||||
|
||||
fn visit_region(&mut self,
|
||||
region: & $($mutability)* ty::Region<'tcx>,
|
||||
_: Location) {
|
||||
|
@ -585,6 +589,7 @@ macro_rules! make_mir_visitor {
|
|||
AggregateKind::Adt(_adt_def,
|
||||
_variant_index,
|
||||
ref $($mutability)* substs,
|
||||
_user_substs,
|
||||
_active_field_index) => {
|
||||
self.visit_substs(substs, location);
|
||||
}
|
||||
|
@ -625,9 +630,10 @@ macro_rules! make_mir_visitor {
|
|||
}
|
||||
|
||||
fn super_user_assert_ty(&mut self,
|
||||
_c_ty: & $($mutability)* CanonicalTy<'tcx>,
|
||||
c_ty: & $($mutability)* CanonicalTy<'tcx>,
|
||||
local: & $($mutability)* Local,
|
||||
location: Location) {
|
||||
self.visit_canonical_ty(c_ty);
|
||||
self.visit_local(local, PlaceContext::Validate, location);
|
||||
}
|
||||
|
||||
|
@ -740,11 +746,13 @@ macro_rules! make_mir_visitor {
|
|||
let Constant {
|
||||
ref $($mutability)* span,
|
||||
ref $($mutability)* ty,
|
||||
ref $($mutability)* user_ty,
|
||||
ref $($mutability)* literal,
|
||||
} = *constant;
|
||||
|
||||
self.visit_span(span);
|
||||
self.visit_ty(ty, TyContext::Location(location));
|
||||
drop(user_ty); // no visit method for this
|
||||
self.visit_const(literal, location);
|
||||
}
|
||||
|
||||
|
@ -764,6 +772,9 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_source_scope(scope);
|
||||
}
|
||||
|
||||
fn super_canonical_ty(&mut self, _ty: & $($mutability)* CanonicalTy<'tcx>) {
|
||||
}
|
||||
|
||||
fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
|
|||
use middle::stability;
|
||||
use mir::{self, Mir, interpret};
|
||||
use mir::interpret::Allocation;
|
||||
use ty::subst::{Kind, Substs, Subst};
|
||||
use ty::subst::{CanonicalSubsts, Kind, Substs, Subst};
|
||||
use ty::ReprOptions;
|
||||
use traits;
|
||||
use traits::{Clause, Clauses, Goal, Goals};
|
||||
|
@ -371,6 +371,18 @@ pub struct TypeckTables<'tcx> {
|
|||
/// other items.
|
||||
node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,
|
||||
|
||||
/// Stores the substitutions that the user explicitly gave (if any)
|
||||
/// attached to `id`. These will not include any inferred
|
||||
/// values. The canonical form is used to capture things like `_`
|
||||
/// or other unspecified values.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// If the user wrote `foo.collect::<Vec<_>>()`, then the
|
||||
/// canonical substitutions would include only `for<X> { Vec<X>
|
||||
/// }`.
|
||||
user_substs: ItemLocalMap<CanonicalSubsts<'tcx>>,
|
||||
|
||||
adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
|
||||
|
||||
/// Stores the actual binding mode for all instances of hir::BindingAnnotation.
|
||||
|
@ -444,6 +456,7 @@ impl<'tcx> TypeckTables<'tcx> {
|
|||
user_provided_tys: ItemLocalMap(),
|
||||
node_types: ItemLocalMap(),
|
||||
node_substs: ItemLocalMap(),
|
||||
user_substs: ItemLocalMap(),
|
||||
adjustments: ItemLocalMap(),
|
||||
pat_binding_modes: ItemLocalMap(),
|
||||
pat_adjustments: ItemLocalMap(),
|
||||
|
@ -561,6 +574,18 @@ impl<'tcx> TypeckTables<'tcx> {
|
|||
self.node_substs.get(&id.local_id).cloned()
|
||||
}
|
||||
|
||||
pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<CanonicalSubsts<'tcx>> {
|
||||
LocalTableInContextMut {
|
||||
local_id_root: self.local_id_root,
|
||||
data: &mut self.user_substs
|
||||
}
|
||||
}
|
||||
|
||||
pub fn user_substs(&self, id: hir::HirId) -> Option<CanonicalSubsts<'tcx>> {
|
||||
validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
|
||||
self.user_substs.get(&id.local_id).cloned()
|
||||
}
|
||||
|
||||
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
|
||||
// doesn't provide type parameter substitutions.
|
||||
pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> {
|
||||
|
@ -740,6 +765,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
|
|||
ref user_provided_tys,
|
||||
ref node_types,
|
||||
ref node_substs,
|
||||
ref user_substs,
|
||||
ref adjustments,
|
||||
ref pat_binding_modes,
|
||||
ref pat_adjustments,
|
||||
|
@ -762,6 +788,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
|
|||
user_provided_tys.hash_stable(hcx, hasher);
|
||||
node_types.hash_stable(hcx, hasher);
|
||||
node_substs.hash_stable(hcx, hasher);
|
||||
user_substs.hash_stable(hcx, hasher);
|
||||
adjustments.hash_stable(hcx, hasher);
|
||||
pat_binding_modes.hash_stable(hcx, hasher);
|
||||
pat_adjustments.hash_stable(hcx, hasher);
|
||||
|
|
|
@ -11,13 +11,15 @@
|
|||
// Type substitutions.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use ty::{self, Lift, List, Ty, TyCtxt};
|
||||
use infer::canonical::Canonical;
|
||||
use ty::{self, CanonicalVar, Lift, List, Ty, TyCtxt};
|
||||
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
|
||||
use serialize::{self, Encodable, Encoder, Decodable, Decoder};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||
use rustc_data_structures::array_vec::ArrayVec;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
use core::intrinsics;
|
||||
use std::cmp::Ordering;
|
||||
|
@ -339,6 +341,33 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type CanonicalSubsts<'gcx> = Canonical<'gcx, &'gcx Substs<'gcx>>;
|
||||
|
||||
impl<'gcx> CanonicalSubsts<'gcx> {
|
||||
/// True if this represents a substitution like
|
||||
///
|
||||
/// ```text
|
||||
/// [?0, ?1, ?2]
|
||||
/// ```
|
||||
///
|
||||
/// i.e., each thing is mapped to a canonical variable with the same index.
|
||||
pub fn is_identity(&self) -> bool {
|
||||
self.value.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| {
|
||||
match kind.unpack() {
|
||||
UnpackedKind::Type(ty) => match ty.sty {
|
||||
ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1,
|
||||
_ => false,
|
||||
},
|
||||
|
||||
UnpackedKind::Lifetime(r) => match r {
|
||||
ty::ReCanonical(cvar1) => cvar == *cvar1,
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -148,7 +148,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
|
|||
|
||||
mir::Rvalue::Aggregate(ref kind, ref operands) => {
|
||||
let (dest, active_field_index) = match **kind {
|
||||
mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
|
||||
mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
|
||||
dest.codegen_set_discr(&bx, variant_index);
|
||||
if adt_def.is_enum() {
|
||||
(dest.project_downcast(&bx, variant_index), active_field_index)
|
||||
|
|
|
@ -15,7 +15,7 @@ use borrow_check::borrow_set::BorrowSet;
|
|||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
|
||||
use borrow_check::nll::facts::AllFacts;
|
||||
use borrow_check::nll::region_infer::values::{RegionValueElements, LivenessValues};
|
||||
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::liveness::liveness_map::NllLivenessMap;
|
||||
|
@ -256,6 +256,22 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
self.super_constant(constant, location);
|
||||
self.sanitize_constant(constant, location);
|
||||
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())
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
constant,
|
||||
"bad constant user type {:?} vs {:?}: {:?}",
|
||||
user_ty,
|
||||
constant.ty,
|
||||
terr,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
|
@ -343,8 +359,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
|
||||
debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty);
|
||||
|
||||
if let Err(terr) = self
|
||||
.cx
|
||||
if let Err(terr) = self.cx
|
||||
.eq_types(constant.literal.ty, constant.ty, location.boring())
|
||||
{
|
||||
span_mirbug!(
|
||||
|
@ -902,6 +917,24 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
terr
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(user_ty) = self.rvalue_user_ty(rv) {
|
||||
if let Err(terr) = self.eq_canonical_type_and_type(
|
||||
user_ty,
|
||||
rv_ty,
|
||||
location.boring(),
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
stmt,
|
||||
"bad user type on rvalue ({:?} = {:?}): {:?}",
|
||||
user_ty,
|
||||
rv_ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.check_rvalue(mir, rv, location);
|
||||
if !self.tcx().features().unsized_locals {
|
||||
let trait_ref = ty::TraitRef {
|
||||
|
@ -1376,7 +1409,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
let tcx = self.tcx();
|
||||
|
||||
match *ak {
|
||||
AggregateKind::Adt(def, variant_index, substs, active_field_index) => {
|
||||
AggregateKind::Adt(def, variant_index, substs, _, active_field_index) => {
|
||||
let variant = &def.variants[variant_index];
|
||||
let adj_field_index = active_field_index.unwrap_or(field_index);
|
||||
if let Some(field) = variant.fields.get(adj_field_index) {
|
||||
|
@ -1542,6 +1575,36 @@ 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>> {
|
||||
match rvalue {
|
||||
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,
|
||||
AggregateKind::Array(_) => None,
|
||||
AggregateKind::Tuple => None,
|
||||
AggregateKind::Closure(_, _) => None,
|
||||
AggregateKind::Generator(_, _, _) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_aggregate_rvalue(
|
||||
&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
|
@ -1735,7 +1798,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
);
|
||||
|
||||
let instantiated_predicates = match aggregate_kind {
|
||||
AggregateKind::Adt(def, _, substs, _) => {
|
||||
AggregateKind::Adt(def, _, substs, _, _) => {
|
||||
tcx.predicates_of(def.did).instantiate(tcx, substs)
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
match kind {
|
||||
ExprKind::Scope { region_scope: _, lint_level: _, value } =>
|
||||
this.as_constant(value),
|
||||
ExprKind::Literal { literal } =>
|
||||
Constant { span: span, ty: ty, literal: literal },
|
||||
ExprKind::Literal { literal, user_ty } =>
|
||||
Constant { span, ty, user_ty, literal },
|
||||
_ =>
|
||||
span_bug!(
|
||||
span,
|
||||
|
|
|
@ -239,6 +239,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
operands.push(Operand::Constant(box Constant {
|
||||
span: expr_span,
|
||||
ty: this.hir.tcx().types.u32,
|
||||
user_ty: None,
|
||||
literal: ty::Const::from_bits(
|
||||
this.hir.tcx(),
|
||||
0,
|
||||
|
@ -254,7 +255,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
block.and(Rvalue::Aggregate(result, operands))
|
||||
}
|
||||
ExprKind::Adt {
|
||||
adt_def, variant_index, substs, fields, base
|
||||
adt_def, variant_index, substs, user_ty, fields, base
|
||||
} => { // see (*) above
|
||||
let is_union = adt_def.is_union();
|
||||
let active_field_index = if is_union { Some(fields[0].name.index()) } else { None };
|
||||
|
@ -284,8 +285,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
|
||||
};
|
||||
|
||||
let adt =
|
||||
box AggregateKind::Adt(adt_def, variant_index, substs, active_field_index);
|
||||
let adt = box AggregateKind::Adt(
|
||||
adt_def,
|
||||
variant_index,
|
||||
substs,
|
||||
user_ty,
|
||||
active_field_index,
|
||||
);
|
||||
block.and(Rvalue::Aggregate(adt, fields))
|
||||
}
|
||||
ExprKind::Assign { .. } |
|
||||
|
|
|
@ -128,6 +128,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
Constant {
|
||||
span: expr_span,
|
||||
ty: this.hir.bool_ty(),
|
||||
user_ty: None,
|
||||
literal: this.hir.true_literal(),
|
||||
});
|
||||
|
||||
|
@ -136,6 +137,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
Constant {
|
||||
span: expr_span,
|
||||
ty: this.hir.bool_ty(),
|
||||
user_ty: None,
|
||||
literal: this.hir.false_literal(),
|
||||
});
|
||||
|
||||
|
|
|
@ -344,7 +344,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
func: Operand::Constant(box Constant {
|
||||
span: test.span,
|
||||
ty: mty,
|
||||
literal: method
|
||||
|
||||
// FIXME(#47184): This constant comes from user
|
||||
// input (a constant in a pattern). Are
|
||||
// there forms where users can add type
|
||||
// annotations here? For example, an
|
||||
// associated constant? Need to
|
||||
// experiment.
|
||||
user_ty: None,
|
||||
|
||||
literal: method,
|
||||
}),
|
||||
args: vec![val, expect],
|
||||
destination: Some((eq_result.clone(), eq_block)),
|
||||
|
|
|
@ -32,6 +32,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
place
|
||||
}
|
||||
|
||||
/// Convenience function for creating a literal operand, one
|
||||
/// without any user type annotation.
|
||||
pub fn literal_operand(&mut self,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
|
@ -40,6 +42,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let constant = box Constant {
|
||||
span,
|
||||
ty,
|
||||
user_ty: None,
|
||||
literal,
|
||||
};
|
||||
Operand::Constant(constant)
|
||||
|
@ -69,6 +72,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
Constant {
|
||||
span: source_info.span,
|
||||
ty: self.hir.usize_ty(),
|
||||
user_ty: None,
|
||||
literal: self.hir.usize_literal(value),
|
||||
});
|
||||
temp
|
||||
|
|
|
@ -256,6 +256,16 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
};
|
||||
if let Some((adt_def, index)) = adt_data {
|
||||
let substs = cx.tables().node_substs(fun.hir_id);
|
||||
|
||||
let user_ty = cx.tables().user_substs(fun.hir_id)
|
||||
.map(|user_substs| {
|
||||
user_substs.unchecked_map(|user_substs| {
|
||||
// Here, we just pair an `AdtDef` with the
|
||||
// `user_substs`, so no new types etc are introduced.
|
||||
cx.tcx().mk_adt(adt_def, user_substs)
|
||||
})
|
||||
});
|
||||
|
||||
let field_refs = args.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, e)| {
|
||||
|
@ -270,6 +280,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
substs,
|
||||
variant_index: index,
|
||||
fields: field_refs,
|
||||
user_ty,
|
||||
base: None,
|
||||
}
|
||||
} else {
|
||||
|
@ -317,6 +328,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
|
||||
hir::ExprKind::Lit(ref lit) => ExprKind::Literal {
|
||||
literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
|
||||
user_ty: None,
|
||||
},
|
||||
|
||||
hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
|
||||
|
@ -406,6 +418,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
if let hir::ExprKind::Lit(ref lit) = arg.node {
|
||||
ExprKind::Literal {
|
||||
literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
|
||||
user_ty: None,
|
||||
}
|
||||
} else {
|
||||
ExprKind::Unary {
|
||||
|
@ -425,6 +438,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
adt_def: adt,
|
||||
variant_index: 0,
|
||||
substs,
|
||||
user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt),
|
||||
fields: field_refs(cx, fields),
|
||||
base: base.as_ref().map(|base| {
|
||||
FruInfo {
|
||||
|
@ -450,6 +464,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
adt_def: adt,
|
||||
variant_index: index,
|
||||
substs,
|
||||
user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt),
|
||||
fields: field_refs(cx, fields),
|
||||
base: None,
|
||||
}
|
||||
|
@ -631,7 +646,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
temp_lifetime,
|
||||
ty,
|
||||
span: expr.span,
|
||||
kind: ExprKind::Literal { literal },
|
||||
kind: ExprKind::Literal { literal, user_ty: None },
|
||||
}.to_ref();
|
||||
let offset = mk_const(ty::Const::from_bits(
|
||||
cx.tcx,
|
||||
|
@ -684,18 +699,77 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
expr: &hir::Expr,
|
||||
custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>)
|
||||
-> Expr<'tcx> {
|
||||
fn user_annotated_ty_for_def(
|
||||
cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
hir_id: hir::HirId,
|
||||
def: &Def,
|
||||
) -> Option<CanonicalTy<'tcx>> {
|
||||
match def {
|
||||
// A reference to something callable -- e.g., a fn, method, or
|
||||
// a tuple-struct or tuple-variant. This has the type of a
|
||||
// `Fn` but with the user-given substitutions.
|
||||
Def::Fn(_) |
|
||||
Def::Method(_) |
|
||||
Def::StructCtor(_, CtorKind::Fn) |
|
||||
Def::VariantCtor(_, CtorKind::Fn) =>
|
||||
Some(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| {
|
||||
// Here, we just pair a `DefId` with the
|
||||
// `user_substs`, so no new types etc are introduced.
|
||||
cx.tcx().mk_fn_def(def.def_id(), user_substs)
|
||||
})),
|
||||
|
||||
Def::Const(_def_id) |
|
||||
Def::AssociatedConst(_def_id) =>
|
||||
bug!("unimplemented"),
|
||||
|
||||
// A unit struct/variant which is used as a value (e.g.,
|
||||
// `None`). This has the type of the enum/struct that defines
|
||||
// this variant -- but with the substitutions given by the
|
||||
// user.
|
||||
Def::StructCtor(_def_id, CtorKind::Const) |
|
||||
Def::VariantCtor(_def_id, CtorKind::Const) =>
|
||||
match &cx.tables().node_id_to_type(hir_id).sty {
|
||||
ty::Adt(adt_def, _) => user_annotated_ty_for_adt(cx, hir_id, adt_def),
|
||||
sty => bug!("unexpected sty: {:?}", sty),
|
||||
},
|
||||
|
||||
_ =>
|
||||
bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn user_annotated_ty_for_adt(
|
||||
cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
hir_id: hir::HirId,
|
||||
adt_def: &'tcx AdtDef,
|
||||
) -> Option<CanonicalTy<'tcx>> {
|
||||
let user_substs = cx.tables().user_substs(hir_id)?;
|
||||
Some(user_substs.unchecked_map(|user_substs| {
|
||||
// Here, we just pair an `AdtDef` with the
|
||||
// `user_substs`, so no new types etc are introduced.
|
||||
cx.tcx().mk_adt(adt_def, user_substs)
|
||||
}))
|
||||
}
|
||||
|
||||
fn method_callee<'a, 'gcx, 'tcx>(
|
||||
cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
expr: &hir::Expr,
|
||||
overloaded_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
|
||||
) -> Expr<'tcx> {
|
||||
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||
let (def_id, substs) = custom_callee.unwrap_or_else(|| {
|
||||
if let Some(def) = cx.tables().type_dependent_defs().get(expr.hir_id) {
|
||||
(def.def_id(), cx.tables().node_substs(expr.hir_id))
|
||||
} else {
|
||||
span_bug!(expr.span, "no type-dependent def for method callee")
|
||||
let (def_id, substs, user_ty) = match overloaded_callee {
|
||||
Some((def_id, substs)) => (def_id, substs, None),
|
||||
None => {
|
||||
let type_dependent_defs = cx.tables().type_dependent_defs();
|
||||
let def = type_dependent_defs
|
||||
.get(expr.hir_id)
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(expr.span, "no type-dependent def for method callee")
|
||||
});
|
||||
let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, def);
|
||||
(def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty)
|
||||
}
|
||||
});
|
||||
};
|
||||
let ty = cx.tcx().mk_fn_def(def_id, substs);
|
||||
Expr {
|
||||
temp_lifetime,
|
||||
|
@ -703,6 +777,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
span: expr.span,
|
||||
kind: ExprKind::Literal {
|
||||
literal: ty::Const::zero_sized(cx.tcx(), ty),
|
||||
user_ty,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -753,11 +828,15 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
Def::Fn(_) |
|
||||
Def::Method(_) |
|
||||
Def::StructCtor(_, CtorKind::Fn) |
|
||||
Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
|
||||
literal: ty::Const::zero_sized(
|
||||
cx.tcx,
|
||||
cx.tables().node_id_to_type(expr.hir_id),
|
||||
),
|
||||
Def::VariantCtor(_, CtorKind::Fn) => {
|
||||
let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, &def);
|
||||
ExprKind::Literal {
|
||||
literal: ty::Const::zero_sized(
|
||||
cx.tcx,
|
||||
cx.tables().node_id_to_type(expr.hir_id),
|
||||
),
|
||||
user_ty,
|
||||
}
|
||||
},
|
||||
|
||||
Def::Const(def_id) |
|
||||
|
@ -768,6 +847,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
substs,
|
||||
cx.tables().node_id_to_type(expr.hir_id),
|
||||
),
|
||||
user_ty: None, // FIXME(#47184) -- user given type annot on constants
|
||||
},
|
||||
|
||||
Def::StructCtor(def_id, CtorKind::Const) |
|
||||
|
@ -780,6 +860,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
adt_def,
|
||||
variant_index: adt_def.variant_index_with_id(def_id),
|
||||
substs,
|
||||
user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt_def),
|
||||
fields: vec![],
|
||||
base: None,
|
||||
}
|
||||
|
@ -958,12 +1039,13 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
fn overloaded_place<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
place_ty: Ty<'tcx>,
|
||||
custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
|
||||
args: Vec<ExprRef<'tcx>>)
|
||||
-> ExprKind<'tcx> {
|
||||
fn overloaded_place<'a, 'gcx, 'tcx>(
|
||||
cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
place_ty: Ty<'tcx>,
|
||||
overloaded_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
|
||||
args: Vec<ExprRef<'tcx>>,
|
||||
) -> ExprKind<'tcx> {
|
||||
// For an overloaded *x or x[y] expression of type T, the method
|
||||
// call returns an &T and we must add the deref so that the types
|
||||
// line up (this is because `*x` and `x[y]` represent places):
|
||||
|
@ -988,7 +1070,7 @@ fn overloaded_place<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
// construct the complete expression `foo()` for the overloaded call,
|
||||
// which will yield the &T type
|
||||
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||
let fun = method_callee(cx, expr, custom_callee);
|
||||
let fun = method_callee(cx, expr, overloaded_callee);
|
||||
let ref_expr = Expr {
|
||||
temp_lifetime,
|
||||
ty: ref_ty,
|
||||
|
|
|
@ -18,7 +18,7 @@ use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const};
|
||||
use rustc::ty::{AdtDef, CanonicalTy, UpvarSubsts, Region, Ty, Const};
|
||||
use rustc::hir;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
|
@ -261,6 +261,11 @@ pub enum ExprKind<'tcx> {
|
|||
adt_def: &'tcx AdtDef,
|
||||
variant_index: usize,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
|
||||
/// Optional user-given substs: for something like `let x =
|
||||
/// Bar::<T> { ... }`.
|
||||
user_ty: Option<CanonicalTy<'tcx>>,
|
||||
|
||||
fields: Vec<FieldExprRef<'tcx>>,
|
||||
base: Option<FruInfo<'tcx>>
|
||||
},
|
||||
|
@ -272,6 +277,13 @@ pub enum ExprKind<'tcx> {
|
|||
},
|
||||
Literal {
|
||||
literal: &'tcx Const<'tcx>,
|
||||
|
||||
/// Optional user-given type: for something like
|
||||
/// `collect::<Vec<_>>`, this would be present and would
|
||||
/// indicate that `Vec<_>` was explicitly specified.
|
||||
///
|
||||
/// Needed for NLL to impose user-given type constraints.
|
||||
user_ty: Option<CanonicalTy<'tcx>>,
|
||||
},
|
||||
InlineAsm {
|
||||
asm: &'tcx hir::InlineAsm,
|
||||
|
|
|
@ -208,7 +208,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
|
||||
Aggregate(ref kind, ref operands) => {
|
||||
let (dest, active_field_index) = match **kind {
|
||||
mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
|
||||
mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
|
||||
self.write_discriminant_value(variant_index, dest)?;
|
||||
if adt_def.is_enum() {
|
||||
(self.place_downcast(dest, variant_index)?, active_field_index)
|
||||
|
|
|
@ -440,6 +440,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
let func = Operand::Constant(box Constant {
|
||||
span: self.span,
|
||||
ty: func_ty,
|
||||
user_ty: None,
|
||||
literal: ty::Const::zero_sized(self.tcx, func_ty),
|
||||
});
|
||||
|
||||
|
@ -498,6 +499,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
box Constant {
|
||||
span: self.span,
|
||||
ty: self.tcx.types.usize,
|
||||
user_ty: None,
|
||||
literal: ty::Const::from_usize(self.tcx, value),
|
||||
}
|
||||
}
|
||||
|
@ -725,6 +727,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
(Operand::Constant(box Constant {
|
||||
span,
|
||||
ty,
|
||||
user_ty: None,
|
||||
literal: ty::Const::zero_sized(tcx, ty),
|
||||
}),
|
||||
vec![rcvr])
|
||||
|
@ -847,7 +850,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
|
|||
kind: StatementKind::Assign(
|
||||
Place::Local(RETURN_PLACE),
|
||||
Rvalue::Aggregate(
|
||||
box AggregateKind::Adt(adt_def, variant_no, substs, None),
|
||||
box AggregateKind::Adt(adt_def, variant_no, substs, None, None),
|
||||
(1..sig.inputs().len()+1).map(|i| {
|
||||
Operand::Move(Place::Local(Local::new(i)))
|
||||
}).collect()
|
||||
|
|
|
@ -48,7 +48,7 @@ impl MirPass for Deaggregator {
|
|||
|
||||
let mut set_discriminant = None;
|
||||
let active_field_index = match *kind {
|
||||
AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
|
||||
AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
|
||||
if adt_def.is_enum() {
|
||||
set_discriminant = Some(Statement {
|
||||
kind: StatementKind::SetDiscriminant {
|
||||
|
|
|
@ -543,6 +543,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||
span,
|
||||
ty: self.tcx.types.bool,
|
||||
user_ty: None,
|
||||
literal: ty::Const::from_bool(self.tcx, val),
|
||||
})))
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ struct TransformVisitor<'a, 'tcx: 'a> {
|
|||
impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
||||
// Make a GeneratorState rvalue
|
||||
fn make_state(&self, idx: usize, val: Operand<'tcx>) -> Rvalue<'tcx> {
|
||||
let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None);
|
||||
let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None);
|
||||
Rvalue::Aggregate(box adt, vec![val])
|
||||
}
|
||||
|
||||
|
@ -177,6 +177,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
|||
let val = Operand::Constant(box Constant {
|
||||
span: source_info.span,
|
||||
ty: self.tcx.types.u32,
|
||||
user_ty: None,
|
||||
literal: ty::Const::from_bits(
|
||||
self.tcx,
|
||||
state_disc.into(),
|
||||
|
@ -710,6 +711,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
cond: Operand::Constant(box Constant {
|
||||
span: mir.span,
|
||||
ty: tcx.types.bool,
|
||||
user_ty: None,
|
||||
literal: ty::Const::from_bool(tcx, false),
|
||||
}),
|
||||
expected: true,
|
||||
|
|
|
@ -103,7 +103,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
|
|||
if let TyKind::Array(_, len) = place_ty.sty {
|
||||
let span = self.mir.source_info(location).span;
|
||||
let ty = self.tcx.types.usize;
|
||||
let constant = Constant { span, ty, literal: len };
|
||||
let constant = Constant { span, ty, literal: len, user_ty: None };
|
||||
self.optimizations.arrays_lengths.insert(location, constant);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -969,6 +969,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
Operand::Constant(box Constant {
|
||||
span: self.source_info.span,
|
||||
ty: self.tcx().types.usize,
|
||||
user_ty: None,
|
||||
literal: ty::Const::from_usize(self.tcx(), val.into()),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -397,10 +397,13 @@ impl<'cx, 'gcx, 'tcx> ExtraComments<'cx, 'gcx, 'tcx> {
|
|||
impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> {
|
||||
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
|
||||
self.super_constant(constant, location);
|
||||
let Constant { span, ty, literal } = constant;
|
||||
let Constant { span, ty, user_ty, literal } = constant;
|
||||
self.push("mir::Constant");
|
||||
self.push(&format!("+ span: {:?}", span));
|
||||
self.push(&format!("+ ty: {:?}", ty));
|
||||
if let Some(user_ty) = user_ty {
|
||||
self.push(&format!("+ user_ty: {:?}", user_ty));
|
||||
}
|
||||
self.push(&format!("+ literal: {:?}", literal));
|
||||
}
|
||||
|
||||
|
@ -429,6 +432,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> {
|
|||
self.push(&format!("+ movability: {:?}", movability));
|
||||
}
|
||||
|
||||
AggregateKind::Adt(_, _, _, Some(user_ty), _) => {
|
||||
self.push("adt");
|
||||
self.push(&format!("+ user_ty: {:?}", user_ty));
|
||||
}
|
||||
|
||||
_ => {}
|
||||
},
|
||||
|
||||
|
|
|
@ -1367,7 +1367,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
|
|||
-> Ty<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
debug!("base_def_to_ty(def={:?}, opt_self_ty={:?}, path_segments={:?})",
|
||||
debug!("def_to_ty(def={:?}, opt_self_ty={:?}, path_segments={:?})",
|
||||
path.def, opt_self_ty, path.segments);
|
||||
|
||||
let span = path.span;
|
||||
|
|
|
@ -95,7 +95,7 @@ use rustc::infer::anon_types::AnonTypeDecl;
|
|||
use rustc::infer::type_variable::{TypeVariableOrigin};
|
||||
use rustc::middle::region;
|
||||
use rustc::mir::interpret::{GlobalId};
|
||||
use rustc::ty::subst::{UnpackedKind, Subst, Substs};
|
||||
use rustc::ty::subst::{CanonicalSubsts, UnpackedKind, Subst, Substs};
|
||||
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
|
||||
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
|
||||
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
|
||||
|
@ -122,6 +122,7 @@ use std::ops::{self, Deref};
|
|||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::source_map::DUMMY_SP;
|
||||
use syntax::source_map::original_sp;
|
||||
use syntax::feature_gate::{GateIssue, emit_feature_err};
|
||||
use syntax::ptr::P;
|
||||
|
@ -2058,11 +2059,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
pub fn write_method_call(&self,
|
||||
hir_id: hir::HirId,
|
||||
method: MethodCallee<'tcx>) {
|
||||
debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method);
|
||||
self.tables
|
||||
.borrow_mut()
|
||||
.type_dependent_defs_mut()
|
||||
.insert(hir_id, Def::Method(method.def_id));
|
||||
|
||||
self.write_substs(hir_id, method.substs);
|
||||
|
||||
// When the method is confirmed, the `method.substs` includes
|
||||
// parameters from not just the method, but also the impl of
|
||||
// the method -- in particular, the `Self` type will be fully
|
||||
// resolved. However, those are not something that the "user
|
||||
// specified" -- i.e., those types come from the inferred type
|
||||
// of the receiver, not something the user wrote. So when we
|
||||
// create the user-substs, we want to replace those earlier
|
||||
// types with just the types that the user actually wrote --
|
||||
// that is, those that appear on the *method itself*.
|
||||
//
|
||||
// As an example, if the user wrote something like
|
||||
// `foo.bar::<u32>(...)` -- the `Self` type here will be the
|
||||
// type of `foo` (possibly adjusted), but we don't want to
|
||||
// include that. We want just the `[_, u32]` part.
|
||||
if !method.substs.is_noop() {
|
||||
let method_generics = self.tcx.generics_of(method.def_id);
|
||||
if !method_generics.params.is_empty() {
|
||||
let user_substs = self.infcx.probe(|_| {
|
||||
let just_method_substs = Substs::for_item(self.tcx, method.def_id, |param, _| {
|
||||
let i = param.index as usize;
|
||||
if i < method_generics.parent_count {
|
||||
self.infcx.var_for_def(DUMMY_SP, param)
|
||||
} else {
|
||||
method.substs[i]
|
||||
}
|
||||
});
|
||||
self.infcx.canonicalize_response(&just_method_substs)
|
||||
});
|
||||
|
||||
debug!("write_method_call: user_substs = {:?}", user_substs);
|
||||
self.write_user_substs(hir_id, user_substs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_substs(&self, node_id: hir::HirId, substs: &'tcx Substs<'tcx>) {
|
||||
|
@ -2076,6 +2113,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given the substs that we just converted from the HIR, try to
|
||||
/// canonicalize them and store them as user-given substitutions
|
||||
/// (i.e., substitutions that must be respected by the NLL check).
|
||||
///
|
||||
/// This should be invoked **before any unifications have
|
||||
/// occurred**, so that annotations like `Vec<_>` are preserved
|
||||
/// properly.
|
||||
pub fn write_user_substs_from_substs(&self, hir_id: hir::HirId, substs: &'tcx Substs<'tcx>) {
|
||||
if !substs.is_noop() {
|
||||
let user_substs = self.infcx.canonicalize_response(&substs);
|
||||
debug!("instantiate_value_path: user_substs = {:?}", user_substs);
|
||||
self.write_user_substs(hir_id, user_substs);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalSubsts<'tcx>) {
|
||||
debug!(
|
||||
"write_user_substs({:?}, {:?}) in fcx {}",
|
||||
hir_id,
|
||||
substs,
|
||||
self.tag(),
|
||||
);
|
||||
|
||||
if !substs.is_identity() {
|
||||
self.tables.borrow_mut().user_substs_mut().insert(hir_id, substs);
|
||||
} else {
|
||||
debug!("write_user_substs: skipping identity substs");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_adjustments(&self, expr: &hir::Expr, adj: Vec<Adjustment<'tcx>>) {
|
||||
debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
|
||||
|
||||
|
@ -3544,6 +3611,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
};
|
||||
|
||||
if let Some((variant, did, substs)) = variant {
|
||||
debug!("check_struct_path: did={:?} substs={:?}", did, substs);
|
||||
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
|
||||
self.write_user_substs_from_substs(hir_id, substs);
|
||||
|
||||
// Check bounds on type arguments used in the path.
|
||||
let bounds = self.instantiate_bounds(path_span, did, substs);
|
||||
let cause = traits::ObligationCause::new(path_span, self.body_id,
|
||||
|
@ -5083,7 +5154,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
debug!("instantiate_value_path: type of {:?} is {:?}",
|
||||
node_id,
|
||||
ty_substituted);
|
||||
self.write_substs(self.tcx.hir.node_to_hir_id(node_id), substs);
|
||||
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
|
||||
self.write_substs(hir_id, substs);
|
||||
|
||||
self.write_user_substs_from_substs(hir_id, substs);
|
||||
|
||||
ty_substituted
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
let item_id = self.tcx.hir.body_owner(body.id());
|
||||
let item_def_id = self.tcx.hir.local_def_id(item_id);
|
||||
|
||||
let mut wbcx = WritebackCx::new(self, body);
|
||||
// This attribute causes us to dump some writeback information
|
||||
// in the form of errors, which is used for unit tests.
|
||||
let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, "rustc_dump_user_substs");
|
||||
|
||||
let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs);
|
||||
for arg in &body.arguments {
|
||||
wbcx.visit_node_id(arg.pat.span, arg.hir_id);
|
||||
}
|
||||
|
@ -84,12 +88,15 @@ struct WritebackCx<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> {
|
|||
tables: ty::TypeckTables<'gcx>,
|
||||
|
||||
body: &'gcx hir::Body,
|
||||
|
||||
rustc_dump_user_substs: bool,
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
fn new(
|
||||
fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>,
|
||||
body: &'gcx hir::Body,
|
||||
rustc_dump_user_substs: bool,
|
||||
) -> WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
let owner = fcx.tcx.hir.definitions().node_to_hir_id(body.id().node_id);
|
||||
|
||||
|
@ -97,6 +104,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
fcx,
|
||||
tables: ty::TypeckTables::empty(Some(DefId::local(owner.owner))),
|
||||
body,
|
||||
rustc_dump_user_substs,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,6 +566,22 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
assert!(!substs.needs_infer() && !substs.has_skol());
|
||||
self.tables.node_substs_mut().insert(hir_id, substs);
|
||||
}
|
||||
|
||||
// Copy over any user-substs
|
||||
if let Some(user_substs) = self.fcx.tables.borrow().user_substs(hir_id) {
|
||||
let user_substs = self.tcx().lift_to_global(&user_substs).unwrap();
|
||||
self.tables.user_substs_mut().insert(hir_id, user_substs);
|
||||
|
||||
// Unit-testing mechanism:
|
||||
if self.rustc_dump_user_substs {
|
||||
let node_id = self.tcx().hir.hir_to_node_id(hir_id);
|
||||
let span = self.tcx().hir.span(node_id);
|
||||
self.tcx().sess.span_err(
|
||||
span,
|
||||
&format!("user substs: {:?}", user_substs),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
|
||||
|
|
|
@ -865,6 +865,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
|
|||
is just used for rustc unit tests \
|
||||
and will never be stable",
|
||||
cfg_fn!(rustc_attrs))),
|
||||
("rustc_dump_user_substs", Whitelisted, Gated(Stability::Unstable,
|
||||
"rustc_attrs",
|
||||
"this attribute \
|
||||
is just used for rustc unit tests \
|
||||
and will never be stable",
|
||||
cfg_fn!(rustc_attrs))),
|
||||
("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
|
||||
"rustc_attrs",
|
||||
"the `#[rustc_if_this_changed]` attribute \
|
||||
|
|
|
@ -18,17 +18,33 @@ LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
|
|||
LL | | fn(Inv<'y>)) }
|
||||
| |__________________________________________________- in this macro invocation
|
||||
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:110:1
|
||||
error: unsatisfied lifetime constraints
|
||||
--> $DIR/hr-subtype.rs:43:13
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
|
||||
LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
LL | fn subtype<'x,'y:'x,'z:'y>() {
|
||||
| -- -- lifetime `'y` defined here
|
||||
| |
|
||||
| lifetime `'x` defined here
|
||||
LL | gimme::<$t2>(None::<$t1>);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
|
||||
...
|
||||
LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
|
||||
LL | | fn(Inv<'y>)) }
|
||||
| |__________________________________________________- in this macro invocation
|
||||
|
||||
error: aborting due to previous error
|
||||
error: unsatisfied lifetime constraints
|
||||
--> $DIR/hr-subtype.rs:49:13
|
||||
|
|
||||
LL | fn supertype<'x,'y:'x,'z:'y>() {
|
||||
| -- -- lifetime `'y` defined here
|
||||
| |
|
||||
| lifetime `'x` defined here
|
||||
LL | gimme::<$t1>(None::<$t2>);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
|
||||
...
|
||||
LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
|
||||
LL | | fn(Inv<'y>)) }
|
||||
| |__________________________________________________- in this macro invocation
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -8,17 +8,19 @@ LL | / check! { free_x_vs_free_y: (fn(&'x u32),
|
|||
LL | | fn(&'y u32)) }
|
||||
| |__________________________________________- in this macro invocation
|
||||
|
||||
error: compilation successful
|
||||
--> $DIR/hr-subtype.rs:110:1
|
||||
error: unsatisfied lifetime constraints
|
||||
--> $DIR/hr-subtype.rs:49:13
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
|
||||
LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
|
||||
LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
|
||||
LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
|
||||
LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
|
||||
LL | | }
|
||||
| |_^
|
||||
LL | fn supertype<'x,'y:'x,'z:'y>() {
|
||||
| -- -- lifetime `'y` defined here
|
||||
| |
|
||||
| lifetime `'x` defined here
|
||||
LL | gimme::<$t1>(None::<$t2>);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
|
||||
...
|
||||
LL | / check! { free_x_vs_free_y: (fn(&'x u32),
|
||||
LL | | fn(&'y u32)) }
|
||||
| |__________________________________________- in this macro invocation
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
enum SomeEnum<T> {
|
||||
SomeVariant { t: T }
|
||||
}
|
||||
|
||||
fn no_annot() {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant { t: &c };
|
||||
}
|
||||
|
||||
fn annot_underscore() {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant::<_> { t: &c };
|
||||
}
|
||||
|
||||
fn annot_reference_any_lifetime() {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant::<&u32> { t: &c };
|
||||
}
|
||||
|
||||
fn annot_reference_static_lifetime() {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant::<&'static u32> { t: &c }; //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
|
||||
SomeEnum::SomeVariant::<&'a u32> { t: c };
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
let _closure = || {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR
|
||||
};
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
|
||||
let _closure = || {
|
||||
SomeEnum::SomeVariant::<&'a u32> { t: c };
|
||||
};
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,41 @@
|
|||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-brace-enums.rs:37:48
|
||||
|
|
||||
LL | SomeEnum::SomeVariant::<&'static u32> { t: &c }; //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-brace-enums.rs:42:43
|
||||
|
|
||||
LL | SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 40:35...
|
||||
--> $DIR/adt-brace-enums.rs:40:35
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-brace-enums.rs:52:47
|
||||
|
|
||||
LL | SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | };
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 49:46...
|
||||
--> $DIR/adt-brace-enums.rs:49:46
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
|
@ -0,0 +1,60 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
struct SomeStruct<T> { t: T }
|
||||
|
||||
fn no_annot() {
|
||||
let c = 66;
|
||||
SomeStruct { t: &c };
|
||||
}
|
||||
|
||||
fn annot_underscore() {
|
||||
let c = 66;
|
||||
SomeStruct::<_> { t: &c };
|
||||
}
|
||||
|
||||
fn annot_reference_any_lifetime() {
|
||||
let c = 66;
|
||||
SomeStruct::<&u32> { t: &c };
|
||||
}
|
||||
|
||||
fn annot_reference_static_lifetime() {
|
||||
let c = 66;
|
||||
SomeStruct::<&'static u32> { t: &c }; //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
let c = 66;
|
||||
SomeStruct::<&'a u32> { t: &c }; //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
|
||||
SomeStruct::<&'a u32> { t: c };
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
let _closure = || {
|
||||
let c = 66;
|
||||
SomeStruct::<&'a u32> { t: &c }; //~ ERROR
|
||||
};
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
|
||||
let _closure = || {
|
||||
SomeStruct::<&'a u32> { t: c };
|
||||
};
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,41 @@
|
|||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-brace-structs.rs:35:37
|
||||
|
|
||||
LL | SomeStruct::<&'static u32> { t: &c }; //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-brace-structs.rs:40:32
|
||||
|
|
||||
LL | SomeStruct::<&'a u32> { t: &c }; //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 38:35...
|
||||
--> $DIR/adt-brace-structs.rs:38:35
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-brace-structs.rs:50:36
|
||||
|
|
||||
LL | SomeStruct::<&'a u32> { t: &c }; //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | };
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 47:46...
|
||||
--> $DIR/adt-brace-structs.rs:47:46
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
|
@ -0,0 +1,80 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
#![feature(nll)]
|
||||
#![allow(warnings)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
enum SomeEnum<T> {
|
||||
SomeVariant(T),
|
||||
SomeOtherVariant,
|
||||
}
|
||||
|
||||
fn combine<T>(_: T, _: T) { }
|
||||
|
||||
fn no_annot() {
|
||||
let c = 66;
|
||||
combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant);
|
||||
}
|
||||
|
||||
fn annot_underscore() {
|
||||
let c = 66;
|
||||
combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant::<Cell<_>>);
|
||||
}
|
||||
|
||||
fn annot_reference_any_lifetime() {
|
||||
let c = 66;
|
||||
combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant::<Cell<&u32>>);
|
||||
}
|
||||
|
||||
fn annot_reference_static_lifetime() {
|
||||
let c = 66;
|
||||
combine(
|
||||
SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
|
||||
SomeEnum::SomeOtherVariant::<Cell<&'static u32>>,
|
||||
);
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
let c = 66;
|
||||
combine(
|
||||
SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
|
||||
SomeEnum::SomeOtherVariant::<Cell<&'a u32>>,
|
||||
);
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
|
||||
combine(SomeEnum::SomeVariant(Cell::new(c)), SomeEnum::SomeOtherVariant::<Cell<&'a u32>>);
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
let _closure = || {
|
||||
let c = 66;
|
||||
combine(
|
||||
SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
|
||||
SomeEnum::SomeOtherVariant::<Cell<&'a u32>>,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
|
||||
let _closure = || {
|
||||
combine(
|
||||
SomeEnum::SomeVariant(Cell::new(c)),
|
||||
SomeEnum::SomeOtherVariant::<Cell<&'a u32>>,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,44 @@
|
|||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-nullary-enums.rs:44:41
|
||||
|
|
||||
LL | SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
...
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-nullary-enums.rs:52:41
|
||||
|
|
||||
LL | SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
...
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 49:35...
|
||||
--> $DIR/adt-nullary-enums.rs:49:35
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-nullary-enums.rs:65:45
|
||||
|
|
||||
LL | SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
...
|
||||
LL | };
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 61:46...
|
||||
--> $DIR/adt-nullary-enums.rs:61:46
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
|
@ -0,0 +1,64 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
#![feature(nll)]
|
||||
#![allow(warnings)]
|
||||
|
||||
enum SomeEnum<T> {
|
||||
SomeVariant(T),
|
||||
SomeOtherVariant,
|
||||
}
|
||||
|
||||
fn no_annot() {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant(&c);
|
||||
}
|
||||
|
||||
fn annot_underscore() {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant::<_>(&c);
|
||||
}
|
||||
|
||||
fn annot_reference_any_lifetime() {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant::<&u32>(&c);
|
||||
}
|
||||
|
||||
fn annot_reference_static_lifetime() {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant::<&'static u32>(&c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
|
||||
SomeEnum::SomeVariant::<&'a u32>(c);
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
let _closure = || {
|
||||
let c = 66;
|
||||
SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR
|
||||
};
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
|
||||
let _closure = || {
|
||||
SomeEnum::SomeVariant::<&'a u32>(c);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,41 @@
|
|||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-tuple-enums.rs:39:43
|
||||
|
|
||||
LL | SomeEnum::SomeVariant::<&'static u32>(&c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-tuple-enums.rs:44:38
|
||||
|
|
||||
LL | SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 42:35...
|
||||
--> $DIR/adt-tuple-enums.rs:42:35
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-tuple-enums.rs:54:42
|
||||
|
|
||||
LL | SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | };
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 51:46...
|
||||
--> $DIR/adt-tuple-enums.rs:51:46
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
|
@ -0,0 +1,60 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
struct SomeStruct<T>(T);
|
||||
|
||||
fn no_annot() {
|
||||
let c = 66;
|
||||
SomeStruct(&c);
|
||||
}
|
||||
|
||||
fn annot_underscore() {
|
||||
let c = 66;
|
||||
SomeStruct::<_>(&c);
|
||||
}
|
||||
|
||||
fn annot_reference_any_lifetime() {
|
||||
let c = 66;
|
||||
SomeStruct::<&u32>(&c);
|
||||
}
|
||||
|
||||
fn annot_reference_static_lifetime() {
|
||||
let c = 66;
|
||||
SomeStruct::<&'static u32>(&c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
let c = 66;
|
||||
SomeStruct::<&'a u32>(&c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
|
||||
SomeStruct::<&'a u32>(c);
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
let _closure = || {
|
||||
let c = 66;
|
||||
SomeStruct::<&'a u32>(&c); //~ ERROR
|
||||
};
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
|
||||
let _closure = || {
|
||||
SomeStruct::<&'a u32>(c);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,41 @@
|
|||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-tuple-struct.rs:35:32
|
||||
|
|
||||
LL | SomeStruct::<&'static u32>(&c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-tuple-struct.rs:40:27
|
||||
|
|
||||
LL | SomeStruct::<&'a u32>(&c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 38:35...
|
||||
--> $DIR/adt-tuple-struct.rs:38:35
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/adt-tuple-struct.rs:50:31
|
||||
|
|
||||
LL | SomeStruct::<&'a u32>(&c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | };
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 47:46...
|
||||
--> $DIR/adt-tuple-struct.rs:47:46
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
|
@ -0,0 +1,29 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
// compile-flags:-Zverbose
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(nll)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
struct SomeStruct<T> { t: T }
|
||||
|
||||
#[rustc_dump_user_substs]
|
||||
fn main() {
|
||||
SomeStruct { t: 22 }; // Nothing given, no annotation.
|
||||
|
||||
SomeStruct::<_> { t: 22 }; // Nothing interesting given, no annotation.
|
||||
|
||||
SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
error: user substs: Canonical { variables: [], value: [u32] }
|
||||
--> $DIR/dump-adt-brace-struct.rs:28:5
|
||||
|
|
||||
LL | SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
// compile-flags:-Zverbose
|
||||
|
||||
#![feature(nll)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
// Note: we reference the names T and U in the comments below.
|
||||
trait Bazoom<T> {
|
||||
fn method<U>(&self, arg: T, arg2: U) { }
|
||||
}
|
||||
|
||||
impl<T, U> Bazoom<U> for T {
|
||||
}
|
||||
|
||||
fn foo<'a, T>(_: T) { }
|
||||
|
||||
#[rustc_dump_user_substs]
|
||||
fn main() {
|
||||
// Here: nothing is given, so we don't have any annotation.
|
||||
let x = foo;
|
||||
x(22);
|
||||
|
||||
// Here: `u32` is given.
|
||||
let x = foo::<u32>; //~ ERROR [u32]
|
||||
x(22);
|
||||
|
||||
// Here: we only want the `T` to be given, the rest should be variables.
|
||||
//
|
||||
// (`T` refers to the declaration of `Bazoom`)
|
||||
let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [?0, u32, ?1]
|
||||
x(&22, 44, 66);
|
||||
|
||||
// Here: all are given
|
||||
let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
|
||||
x(&22, 44, 66);
|
||||
|
||||
// Here: we want in particular that *only* the method `U`
|
||||
// annotation is given, the rest are variables.
|
||||
//
|
||||
// (`U` refers to the declaration of `Bazoom`)
|
||||
let y = 22_u32;
|
||||
y.method::<u32>(44, 66); //~ ERROR [?0, ?1, u32]
|
||||
|
||||
// Here: nothing is given, so we don't have any annotation.
|
||||
let y = 22_u32;
|
||||
y.method(44, 66);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
error: user substs: Canonical { variables: [], value: [u32] }
|
||||
--> $DIR/dump-fn-method.rs:36:13
|
||||
|
|
||||
LL | let x = foo::<u32>; //~ ERROR [u32]
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, u32, ?1] }
|
||||
--> $DIR/dump-fn-method.rs:42:13
|
||||
|
|
||||
LL | let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [?0, u32, ?1]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: user substs: Canonical { variables: [], value: [u8, u16, u32] }
|
||||
--> $DIR/dump-fn-method.rs:46:13
|
||||
|
|
||||
LL | let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, ?1, u32] }
|
||||
--> $DIR/dump-fn-method.rs:54:5
|
||||
|
|
||||
LL | y.method::<u32>(44, 66); //~ ERROR [?0, ?1, u32]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
fn some_fn<T>(arg: T) { }
|
||||
|
||||
fn no_annot() {
|
||||
let c = 66;
|
||||
some_fn(&c); // OK
|
||||
}
|
||||
|
||||
fn annot_underscore() {
|
||||
let c = 66;
|
||||
some_fn::<_>(&c); // OK
|
||||
}
|
||||
|
||||
fn annot_reference_any_lifetime() {
|
||||
let c = 66;
|
||||
some_fn::<&u32>(&c); // OK
|
||||
}
|
||||
|
||||
fn annot_reference_static_lifetime() {
|
||||
let c = 66;
|
||||
some_fn::<&'static u32>(&c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
let c = 66;
|
||||
some_fn::<&'a u32>(&c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
|
||||
some_fn::<&'a u32>(c);
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
let _closure = || {
|
||||
let c = 66;
|
||||
some_fn::<&'a u32>(&c); //~ ERROR
|
||||
};
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
|
||||
let _closure = || {
|
||||
some_fn::<&'a u32>(c);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,41 @@
|
|||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/fns.rs:35:29
|
||||
|
|
||||
LL | some_fn::<&'static u32>(&c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/fns.rs:40:24
|
||||
|
|
||||
LL | some_fn::<&'a u32>(&c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 38:35...
|
||||
--> $DIR/fns.rs:38:35
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/fns.rs:50:28
|
||||
|
|
||||
LL | some_fn::<&'a u32>(&c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | };
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 47:46...
|
||||
--> $DIR/fns.rs:47:46
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
|
@ -0,0 +1,81 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
trait Bazoom<T> {
|
||||
fn method<U>(&self, arg: T, arg2: U) { }
|
||||
}
|
||||
|
||||
impl<T, U> Bazoom<U> for T {
|
||||
}
|
||||
|
||||
fn no_annot() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
a.method(b, &c); // OK
|
||||
}
|
||||
|
||||
fn annot_underscore() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
a.method::<_>(b, &c); // OK
|
||||
}
|
||||
|
||||
fn annot_reference_any_lifetime() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
a.method::<&u32>(b, &c); // OK
|
||||
}
|
||||
|
||||
fn annot_reference_static_lifetime() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
a.method::<&'static u32>(b, &c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
a.method::<&'a u32>(b, &c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
a.method::<&'a u32>(b, c);
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let _closure = || {
|
||||
let c = 66;
|
||||
a.method::<&'a u32>(b, &c); //~ ERROR
|
||||
};
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let _closure = || {
|
||||
a.method::<&'a u32>(b, c);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,41 @@
|
|||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/method-call.rs:48:34
|
||||
|
|
||||
LL | a.method::<&'static u32>(b, &c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/method-call.rs:55:29
|
||||
|
|
||||
LL | a.method::<&'a u32>(b, &c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 51:35...
|
||||
--> $DIR/method-call.rs:51:35
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/method-call.rs:69:33
|
||||
|
|
||||
LL | a.method::<&'a u32>(b, &c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | };
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 64:46...
|
||||
--> $DIR/method-call.rs:64:46
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
|
@ -0,0 +1,75 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
trait Bazoom<T>: Sized {
|
||||
fn method<U>(self, arg: T, arg2: U) { }
|
||||
}
|
||||
|
||||
impl<T, U> Bazoom<U> for T {
|
||||
}
|
||||
|
||||
fn annot_underscore() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<_ as Bazoom<_>>::method::<_>(&a, b, c); // OK
|
||||
}
|
||||
|
||||
fn annot_reference_any_lifetime() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<&u32 as Bazoom<_>>::method(&a, b, c); // OK
|
||||
}
|
||||
|
||||
fn annot_reference_static_lifetime() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
let x = <&'static u32 as Bazoom<_>>::method;
|
||||
x(&a, b, c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_ok<'a>(a: &'a u32) {
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<&'a u32 as Bazoom<_>>::method(&a, b, c);
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let _closure = || {
|
||||
let c = 66;
|
||||
<&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR
|
||||
};
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure_ok<'a>(a: &'a u32) {
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
let _closure = || {
|
||||
<&'a u32 as Bazoom<_>>::method(&a, b, c);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,45 @@
|
|||
error[E0597]: `a` does not live long enough
|
||||
--> $DIR/method-ufcs-1.rs:42:7
|
||||
|
|
||||
LL | x(&a, b, c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `a` dropped here while still borrowed
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error[E0597]: `a` does not live long enough
|
||||
--> $DIR/method-ufcs-1.rs:49:36
|
||||
|
|
||||
LL | <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `a` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 45:35...
|
||||
--> $DIR/method-ufcs-1.rs:45:35
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error[E0597]: `a` does not live long enough
|
||||
--> $DIR/method-ufcs-1.rs:63:41
|
||||
|
|
||||
LL | let _closure = || {
|
||||
| -- value captured here
|
||||
LL | let c = 66;
|
||||
LL | <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR
|
||||
| ^ borrowed value does not live long enough
|
||||
LL | };
|
||||
LL | }
|
||||
| - `a` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 58:46...
|
||||
--> $DIR/method-ufcs-1.rs:58:46
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
|
@ -0,0 +1,75 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
trait Bazoom<T>: Sized {
|
||||
fn method<U>(self, arg: T, arg2: U) { }
|
||||
}
|
||||
|
||||
impl<T, U> Bazoom<U> for T {
|
||||
}
|
||||
|
||||
fn annot_underscore() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<_ as Bazoom<_>>::method(a, &b, c); // OK
|
||||
}
|
||||
|
||||
fn annot_reference_any_lifetime() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<_ as Bazoom<&u32>>::method(a, &b, c); // OK
|
||||
}
|
||||
|
||||
fn annot_reference_static_lifetime() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
let x = <&'static u32 as Bazoom<_>>::method;
|
||||
x(&a, b, c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_ok<'a>(b: &'a u32) {
|
||||
let a = 44;
|
||||
let c = 66;
|
||||
<_ as Bazoom<&'a u32>>::method(a, &b, c);
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let _closure = || {
|
||||
let c = 66;
|
||||
<_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR
|
||||
};
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure_ok<'a>(b: &'a u32) {
|
||||
let a = 44;
|
||||
let c = 66;
|
||||
let _closure = || {
|
||||
<_ as Bazoom<&'a u32>>::method(a, &b, c);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,45 @@
|
|||
error[E0597]: `a` does not live long enough
|
||||
--> $DIR/method-ufcs-2.rs:42:7
|
||||
|
|
||||
LL | x(&a, b, c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `a` dropped here while still borrowed
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error[E0597]: `b` does not live long enough
|
||||
--> $DIR/method-ufcs-2.rs:49:39
|
||||
|
|
||||
LL | <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `b` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 45:35...
|
||||
--> $DIR/method-ufcs-2.rs:45:35
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error[E0597]: `b` does not live long enough
|
||||
--> $DIR/method-ufcs-2.rs:63:44
|
||||
|
|
||||
LL | let _closure = || {
|
||||
| -- value captured here
|
||||
LL | let c = 66;
|
||||
LL | <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR
|
||||
| ^ borrowed value does not live long enough
|
||||
LL | };
|
||||
LL | }
|
||||
| - `b` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 58:46...
|
||||
--> $DIR/method-ufcs-2.rs:58:46
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
|
@ -0,0 +1,81 @@
|
|||
// 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.
|
||||
|
||||
// Unit test for the "user substitutions" that are annotated on each
|
||||
// node.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
trait Bazoom<T> {
|
||||
fn method<U>(&self, arg: T, arg2: U) { }
|
||||
}
|
||||
|
||||
impl<T, U> Bazoom<U> for T {
|
||||
}
|
||||
|
||||
fn no_annot() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<_ as Bazoom<_>>::method(&a, b, &c); // OK
|
||||
}
|
||||
|
||||
fn annot_underscore() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<_ as Bazoom<_>>::method::<_>(&a, b, &c); // OK
|
||||
}
|
||||
|
||||
fn annot_reference_any_lifetime() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<_ as Bazoom<_>>::method::<&u32>(&a, b, &c); // OK
|
||||
}
|
||||
|
||||
fn annot_reference_static_lifetime() {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let c = 66;
|
||||
<_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
<_ as Bazoom<_>>::method::<&'a u32>(&a, b, c);
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let _closure = || {
|
||||
let c = 66;
|
||||
<_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR
|
||||
};
|
||||
}
|
||||
|
||||
fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
|
||||
let a = 22;
|
||||
let b = 44;
|
||||
let _closure = || {
|
||||
<_ as Bazoom<_>>::method::<&'a u32>(&a, b, c);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,41 @@
|
|||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/method-ufcs-3.rs:48:53
|
||||
|
|
||||
LL | <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/method-ufcs-3.rs:55:48
|
||||
|
|
||||
LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 51:35...
|
||||
--> $DIR/method-ufcs-3.rs:51:35
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error[E0597]: `c` does not live long enough
|
||||
--> $DIR/method-ufcs-3.rs:69:52
|
||||
|
|
||||
LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR
|
||||
| ^^ borrowed value does not live long enough
|
||||
LL | };
|
||||
| - `c` dropped here while still borrowed
|
||||
|
|
||||
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 64:46...
|
||||
--> $DIR/method-ufcs-3.rs:64:46
|
||||
|
|
||||
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
Loading…
Reference in New Issue