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:
bors 2018-08-24 22:42:00 +00:00
commit d95f078f0a
55 changed files with 1757 additions and 79 deletions

View File

@ -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),

View File

@ -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 });

View File

@ -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> {

View File

@ -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),
}
}

View File

@ -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) => {

View File

@ -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>) {
}

View File

@ -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);

View File

@ -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> {}
///////////////////////////////////////////////////////////////////////////

View File

@ -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)

View File

@ -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)
}

View File

@ -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,

View File

@ -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 { .. } |

View File

@ -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(),
});

View File

@ -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)),

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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)

View File

@ -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()

View File

@ -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 {

View File

@ -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),
})))
}

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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()),
})
}

View File

@ -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));
}
_ => {}
},

View File

@ -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;

View File

@ -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
}

View File

@ -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) {

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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() { }

View File

@ -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`.

View File

@ -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() { }

View File

@ -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`.

View File

@ -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() { }

View File

@ -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`.

View File

@ -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() { }

View File

@ -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`.

View File

@ -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() { }

View File

@ -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`.

View File

@ -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]
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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() { }

View File

@ -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`.

View File

@ -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() { }

View File

@ -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`.

View File

@ -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() { }

View File

@ -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`.

View File

@ -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() { }

View File

@ -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`.

View File

@ -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() { }

View File

@ -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`.