Auto merge of #55937 - davidtwco:issue-54943, r=pnkfelix

NLL: User type annotations refactor, associated constant patterns and ref bindings.

Fixes #55511 and Fixes #55401. Contributes to #54943.

This PR performs a large refactoring on user type annotations, checks user type annotations for associated constants in patterns and that user type annotations for `ref` bindings are respected.

r? @nikomatsakis
This commit is contained in:
bors 2019-01-01 15:26:12 +00:00
commit cae164753f
47 changed files with 804 additions and 500 deletions

View File

@ -494,22 +494,5 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::ClosureOutlivesSubj
impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted });
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::UserTypeAnnotation<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
mir::UserTypeAnnotation::Ty(ref ty) => {
ty.hash_stable(hcx, hasher);
}
mir::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => {
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
}
}
}
}
impl_stable_hash_for!(struct mir::UserTypeProjection<'tcx> { base, projs });
impl_stable_hash_for!(struct mir::UserTypeProjections<'tcx> { contents });

View File

@ -1251,3 +1251,29 @@ impl_stable_hash_for!(
goal,
}
);
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::UserTypeAnnotation<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
ty::UserTypeAnnotation::Ty(ref ty) => {
ty.hash_stable(hcx, hasher);
}
ty::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => {
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
}
}
}
}
impl<'a> HashStable<StableHashingContext<'a>> for ty::UserTypeAnnotationIndex {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
self.index().hash_stable(hcx, hasher);
}
}

View File

@ -27,9 +27,12 @@ use syntax::ast::{self, Name};
use syntax::symbol::InternedString;
use syntax_pos::{Span, DUMMY_SP};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::subst::{CanonicalUserSubsts, Subst, Substs};
use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt};
use ty::subst::{Subst, Substs};
use ty::layout::VariantIdx;
use ty::{
self, AdtDef, CanonicalUserTypeAnnotations, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt,
UserTypeAnnotationIndex, UserTypeAnnotation,
};
use util::ppaux;
pub use mir::interpret::AssertMessage;
@ -121,6 +124,9 @@ pub struct Mir<'tcx> {
/// variables and temporaries.
pub local_decls: LocalDecls<'tcx>,
/// User type annotations
pub user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
/// Number of arguments this function takes.
///
/// Starting at local 1, `arg_count` locals will be provided by the caller
@ -161,7 +167,8 @@ impl<'tcx> Mir<'tcx> {
source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
promoted: IndexVec<Promoted, Mir<'tcx>>,
yield_ty: Option<Ty<'tcx>>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
local_decls: LocalDecls<'tcx>,
user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
arg_count: usize,
upvar_decls: Vec<UpvarDecl>,
span: Span,
@ -185,6 +192,7 @@ impl<'tcx> Mir<'tcx> {
generator_drop: None,
generator_layout: None,
local_decls,
user_type_annotations,
arg_count,
upvar_decls,
spread_arg: None,
@ -418,6 +426,7 @@ impl_stable_hash_for!(struct Mir<'tcx> {
generator_drop,
generator_layout,
local_decls,
user_type_annotations,
arg_count,
upvar_decls,
spread_arg,
@ -2232,7 +2241,7 @@ pub enum AggregateKind<'tcx> {
&'tcx AdtDef,
VariantIdx,
&'tcx Substs<'tcx>,
Option<UserTypeAnnotation<'tcx>>,
Option<UserTypeAnnotationIndex>,
Option<usize>,
),
@ -2446,38 +2455,11 @@ pub struct Constant<'tcx> {
/// indicate that `Vec<_>` was explicitly specified.
///
/// Needed for NLL to impose user-given type constraints.
pub user_ty: Option<UserTypeAnnotation<'tcx>>,
pub user_ty: Option<UserTypeAnnotationIndex>,
pub literal: &'tcx ty::Const<'tcx>,
}
/// A user-given type annotation attached to a constant. These arise
/// from constants that are named via paths, like `Foo::<A>::new` and
/// so forth.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum UserTypeAnnotation<'tcx> {
Ty(CanonicalTy<'tcx>),
/// The canonical type is the result of `type_of(def_id)` with the
/// given substitutions applied.
TypeOf(DefId, CanonicalUserSubsts<'tcx>),
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> {
(UserTypeAnnotation::Ty)(ty),
(UserTypeAnnotation::TypeOf)(def, substs),
}
}
EnumLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> {
type Lifted = UserTypeAnnotation<'tcx>;
(UserTypeAnnotation::Ty)(ty),
(UserTypeAnnotation::TypeOf)(def, substs),
}
}
/// A collection of projections into user types.
///
/// They are projections because a binding can occur a part of a
@ -2537,6 +2519,48 @@ impl<'tcx> UserTypeProjections<'tcx> {
pub fn projections(&self) -> impl Iterator<Item=&UserTypeProjection<'tcx>> {
self.contents.iter().map(|&(ref user_type, _span)| user_type)
}
pub fn push_projection(
mut self,
user_ty: &UserTypeProjection<'tcx>,
span: Span,
) -> Self {
self.contents.push((user_ty.clone(), span));
self
}
fn map_projections(
mut self,
mut f: impl FnMut(UserTypeProjection<'tcx>) -> UserTypeProjection<'tcx>
) -> Self {
self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect();
self
}
pub fn index(self) -> Self {
self.map_projections(|pat_ty_proj| pat_ty_proj.index())
}
pub fn subslice(self, from: u32, to: u32) -> Self {
self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to))
}
pub fn deref(self) -> Self {
self.map_projections(|pat_ty_proj| pat_ty_proj.deref())
}
pub fn leaf(self, field: Field) -> Self {
self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field))
}
pub fn variant(
self,
adt_def: &'tcx AdtDef,
variant_index: VariantIdx,
field: Field,
) -> Self {
self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field))
}
}
/// Encodes the effect of a user-supplied type annotation on the
@ -2556,12 +2580,45 @@ impl<'tcx> UserTypeProjections<'tcx> {
/// determined by finding the type of the `.0` field from `T`.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct UserTypeProjection<'tcx> {
pub base: UserTypeAnnotation<'tcx>,
pub base: UserTypeAnnotationIndex,
pub projs: Vec<ProjectionElem<'tcx, (), ()>>,
}
impl<'tcx> Copy for ProjectionKind<'tcx> { }
impl<'tcx> UserTypeProjection<'tcx> {
pub(crate) fn index(mut self) -> Self {
self.projs.push(ProjectionElem::Index(()));
self
}
pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self {
self.projs.push(ProjectionElem::Subslice { from, to });
self
}
pub(crate) fn deref(mut self) -> Self {
self.projs.push(ProjectionElem::Deref);
self
}
pub(crate) fn leaf(mut self, field: Field) -> Self {
self.projs.push(ProjectionElem::Field(field, ()));
self
}
pub(crate) fn variant(
mut self,
adt_def: &'tcx AdtDef,
variant_index: VariantIdx,
field: Field,
) -> Self {
self.projs.push(ProjectionElem::Downcast(adt_def, variant_index));
self.projs.push(ProjectionElem::Field(field, ()));
self
}
}
CloneTypeFoldableAndLiftImpls! { ProjectionKind<'tcx>, }
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection<'tcx> {
@ -2970,6 +3027,7 @@ CloneTypeFoldableAndLiftImpls! {
SourceScope,
SourceScopeData,
SourceScopeLocalData,
UserTypeAnnotationIndex,
}
BraceStructTypeFoldableImpl! {
@ -2983,6 +3041,7 @@ BraceStructTypeFoldableImpl! {
generator_drop,
generator_layout,
local_decls,
user_type_annotations,
arg_count,
upvar_decls,
spread_arg,

View File

@ -1,4 +1,5 @@
use hir::def_id::DefId;
use infer::canonical::Canonical;
use ty::subst::Substs;
use ty::{ClosureSubsts, GeneratorSubsts, Region, Ty};
use mir::*;
@ -219,9 +220,10 @@ macro_rules! make_mir_visitor {
fn visit_user_type_annotation(
&mut self,
ty: & $($mutability)* UserTypeAnnotation<'tcx>,
index: UserTypeAnnotationIndex,
ty: & $($mutability)* Canonical<'tcx, UserTypeAnnotation<'tcx>>,
) {
self.super_user_type_annotation(ty);
self.super_user_type_annotation(index, ty);
}
fn visit_region(&mut self,
@ -307,6 +309,14 @@ macro_rules! make_mir_visitor {
self.visit_local_decl(local, & $($mutability)* mir.local_decls[local]);
}
for index in mir.user_type_annotations.indices() {
let (span, annotation) = & $($mutability)* mir.user_type_annotations[index];
self.visit_user_type_annotation(
index, annotation
);
self.visit_span(span);
}
self.visit_span(&$($mutability)* mir.span);
}
@ -865,18 +875,14 @@ macro_rules! make_mir_visitor {
fn super_user_type_projection(
&mut self,
ty: & $($mutability)* UserTypeProjection<'tcx>,
_ty: & $($mutability)* UserTypeProjection<'tcx>,
) {
let UserTypeProjection {
ref $($mutability)* base,
projs: _, // Note: Does not visit projection elems!
} = *ty;
self.visit_user_type_annotation(base);
}
fn super_user_type_annotation(
&mut self,
_ty: & $($mutability)* UserTypeAnnotation<'tcx>,
_index: UserTypeAnnotationIndex,
_ty: & $($mutability)* Canonical<'tcx, UserTypeAnnotation<'tcx>>,
) {
}

View File

@ -22,7 +22,7 @@ impl<'tcx> AscribeUserType<'tcx> {
user_substs: UserSubsts<'tcx>,
projs: &'tcx ty::List<ProjectionKind<'tcx>>,
) -> Self {
AscribeUserType { mir_ty, variance, def_id, user_substs, projs }
Self { mir_ty, variance, def_id, user_substs, projs }
}
}

View File

@ -14,7 +14,7 @@ use hir::map as hir_map;
use hir::map::DefPathHash;
use lint::{self, Lint};
use ich::{StableHashingContext, NodeIdHashingMode};
use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use infer::outlives::free_region_map::FreeRegionMap;
use middle::cstore::CrateStoreDyn;
use middle::cstore::EncodedMetadata;
@ -23,7 +23,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use middle::stability;
use mir::{self, Mir, interpret, ProjectionKind};
use mir::interpret::Allocation;
use ty::subst::{CanonicalUserSubsts, Kind, Substs, Subst};
use ty::subst::{Kind, Substs, Subst};
use ty::ReprOptions;
use traits;
use traits::{Clause, Clauses, GoalKind, Goal, Goals};
@ -38,8 +38,8 @@ use ty::GenericParamDefKind;
use ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx};
use ty::query;
use ty::steal::Steal;
use ty::BindingMode;
use ty::CanonicalTy;
use ty::subst::{UserSubsts, UnpackedKind};
use ty::{BoundVar, BindingMode};
use ty::CanonicalPolyFnSig;
use util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap};
use util::nodemap::{FxHashMap, FxHashSet};
@ -49,7 +49,7 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
StableHasher, StableHasherResult,
StableVec};
use arena::{TypedArena, SyncDroplessArena};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::sync::{self, Lrc, Lock, WorkerLocal};
use std::any::Any;
use std::borrow::Borrow;
@ -342,26 +342,21 @@ pub struct TypeckTables<'tcx> {
/// other items.
node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,
/// Stores the canonicalized types provided by the user. See also
/// `AscribeUserType` statement in MIR.
user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
/// This will either store the canonicalized types provided by the user
/// or 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.
///
/// For example, if the user wrote `foo.collect::<Vec<_>>()`, then the
/// canonical substitutions would include only `for<X> { Vec<X> }`.
///
/// See also `AscribeUserType` statement in MIR.
user_provided_types: ItemLocalMap<CanonicalUserTypeAnnotation<'tcx>>,
/// Stores the canonicalized types provided by the user. See also
/// `AscribeUserType` statement in MIR.
pub user_provided_sigs: DefIdMap<CanonicalPolyFnSig<'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<CanonicalUserSubsts<'tcx>>,
adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
/// Stores the actual binding mode for all instances of hir::BindingAnnotation.
@ -432,11 +427,10 @@ impl<'tcx> TypeckTables<'tcx> {
local_id_root,
type_dependent_defs: Default::default(),
field_indices: Default::default(),
user_provided_tys: Default::default(),
user_provided_types: Default::default(),
user_provided_sigs: Default::default(),
node_types: Default::default(),
node_substs: Default::default(),
user_substs: Default::default(),
adjustments: Default::default(),
pat_binding_modes: Default::default(),
pat_adjustments: Default::default(),
@ -491,17 +485,21 @@ impl<'tcx> TypeckTables<'tcx> {
}
}
pub fn user_provided_tys(&self) -> LocalTableInContext<'_, CanonicalTy<'tcx>> {
pub fn user_provided_types(
&self
) -> LocalTableInContext<'_, CanonicalUserTypeAnnotation<'tcx>> {
LocalTableInContext {
local_id_root: self.local_id_root,
data: &self.user_provided_tys
data: &self.user_provided_types
}
}
pub fn user_provided_tys_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalTy<'tcx>> {
pub fn user_provided_types_mut(
&mut self
) -> LocalTableInContextMut<'_, CanonicalUserTypeAnnotation<'tcx>> {
LocalTableInContextMut {
local_id_root: self.local_id_root,
data: &mut self.user_provided_tys
data: &mut self.user_provided_types
}
}
@ -551,18 +549,6 @@ impl<'tcx> TypeckTables<'tcx> {
self.node_substs.get(&id.local_id).cloned()
}
pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalUserSubsts<'tcx>> {
LocalTableInContextMut {
local_id_root: self.local_id_root,
data: &mut self.user_substs
}
}
pub fn user_substs(&self, id: hir::HirId) -> Option<CanonicalUserSubsts<'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> {
@ -739,11 +725,10 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
local_id_root,
ref type_dependent_defs,
ref field_indices,
ref user_provided_tys,
ref user_provided_types,
ref user_provided_sigs,
ref node_types,
ref node_substs,
ref user_substs,
ref adjustments,
ref pat_binding_modes,
ref pat_adjustments,
@ -763,11 +748,10 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
type_dependent_defs.hash_stable(hcx, hasher);
field_indices.hash_stable(hcx, hasher);
user_provided_tys.hash_stable(hcx, hasher);
user_provided_types.hash_stable(hcx, hasher);
user_provided_sigs.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);
@ -805,6 +789,84 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
}
}
newtype_index! {
pub struct UserTypeAnnotationIndex {
DEBUG_FORMAT = "UserTypeAnnotation({})",
const START_INDEX = 0,
}
}
/// Mapping of type annotation indices to canonical user type annotations.
pub type CanonicalUserTypeAnnotations<'tcx> =
IndexVec<UserTypeAnnotationIndex, (Span, CanonicalUserTypeAnnotation<'tcx>)>;
/// Canonicalized user type annotation.
pub type CanonicalUserTypeAnnotation<'gcx> = Canonical<'gcx, UserTypeAnnotation<'gcx>>;
impl CanonicalUserTypeAnnotation<'gcx> {
/// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
/// i.e. each thing is mapped to a canonical variable with the same index.
pub fn is_identity(&self) -> bool {
match self.value {
UserTypeAnnotation::Ty(_) => false,
UserTypeAnnotation::TypeOf(_, user_substs) => {
if user_substs.user_self_ty.is_some() {
return false;
}
user_substs.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| {
match kind.unpack() {
UnpackedKind::Type(ty) => match ty.sty {
ty::Bound(debruijn, b) => {
// We only allow a `ty::INNERMOST` index in substitutions.
assert_eq!(debruijn, ty::INNERMOST);
cvar == b.var
}
_ => false,
},
UnpackedKind::Lifetime(r) => match r {
ty::ReLateBound(debruijn, br) => {
// We only allow a `ty::INNERMOST` index in substitutions.
assert_eq!(*debruijn, ty::INNERMOST);
cvar == br.assert_bound_var()
}
_ => false,
},
}
})
},
}
}
}
/// A user-given type annotation attached to a constant. These arise
/// from constants that are named via paths, like `Foo::<A>::new` and
/// so forth.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum UserTypeAnnotation<'tcx> {
Ty(Ty<'tcx>),
/// The canonical type is the result of `type_of(def_id)` with the
/// given substitutions applied.
TypeOf(DefId, UserSubsts<'tcx>),
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> {
(UserTypeAnnotation::Ty)(ty),
(UserTypeAnnotation::TypeOf)(def, substs),
}
}
EnumLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> {
type Lifted = UserTypeAnnotation<'tcx>;
(UserTypeAnnotation::Ty)(ty),
(UserTypeAnnotation::TypeOf)(def, substs),
}
}
impl<'tcx> CommonTypes<'tcx> {
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);

View File

@ -73,6 +73,10 @@ pub use self::binding::BindingMode::*;
pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, keep_local};
pub use self::context::{Lift, TypeckTables, CtxtInterners};
pub use self::context::{
UserTypeAnnotationIndex, UserTypeAnnotation, CanonicalUserTypeAnnotation,
CanonicalUserTypeAnnotations,
};
pub use self::instance::{Instance, InstanceDef};

View File

@ -26,8 +26,8 @@ use session::config::OutputFilenames;
use traits::{self, Vtable};
use traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal,
CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal,
CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
CanonicalTypeOpNormalizeGoal, NoSolution,
};
use traits::query::method_autoderef::MethodAutoderefStepsResult;

View File

@ -2,12 +2,11 @@
use hir::def_id::DefId;
use infer::canonical::Canonical;
use ty::{self, BoundVar, Lift, List, Ty, TyCtxt};
use ty::{self, 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::indexed_vec::Idx;
use smallvec::SmallVec;
use core::intrinsics;
@ -559,43 +558,6 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>;
impl CanonicalUserSubsts<'tcx> {
/// 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 {
if self.value.user_self_ty.is_some() {
return false;
}
self.value.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| {
match kind.unpack() {
UnpackedKind::Type(ty) => match ty.sty {
ty::Bound(debruijn, b) => {
// We only allow a `ty::INNERMOST` index in substitutions.
assert_eq!(debruijn, ty::INNERMOST);
cvar == b.var
}
_ => false,
},
UnpackedKind::Lifetime(r) => match r {
ty::ReLateBound(debruijn, br) => {
// We only allow a `ty::INNERMOST` index in substitutions.
assert_eq!(*debruijn, ty::INNERMOST);
cvar == br.assert_bound_var()
}
_ => false,
},
}
})
}
}
/// Stores the user-given substs to reach some fully qualified path
/// (e.g., `<T>::Item` or `<T as Trait>::Item`).
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]

View File

@ -289,6 +289,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
self.out.extend(obligations);
}
ty::FnDef(did, substs) => {
let obligations = self.nominal_obligations(did, substs);
self.out.extend(obligations);
}
ty::Ref(r, rty, _) => {
// WfReference
if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
@ -349,7 +354,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
}
}
ty::FnDef(..) | ty::FnPtr(_) => {
ty::FnPtr(_) => {
// let the loop iterate into the argument/return
// types appearing in the fn signature
}

View File

@ -230,13 +230,14 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
// Before the CFG, dump out the values for each region variable.
PassWhere::BeforeCFG => {
regioncx.dump_mir(out)?;
writeln!(out, "|")?;
if let Some(closure_region_requirements) = closure_region_requirements {
writeln!(out, "|")?;
writeln!(out, "| Free Region Constraints")?;
for_each_region_constraint(closure_region_requirements, &mut |msg| {
writeln!(out, "| {}", msg)
})?;
writeln!(out, "|")?;
}
}

View File

@ -1,6 +1,10 @@
use rustc::infer::canonical::Canonical;
use rustc::ty::subst::Substs;
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
use rustc::mir::{Location, Mir, UserTypeAnnotation};
use rustc::ty::{
self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable, UserTypeAnnotation,
UserTypeAnnotationIndex,
};
use rustc::mir::{Location, Mir};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
@ -55,7 +59,11 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
debug!("visit_ty: ty={:?}", ty);
}
fn visit_user_type_annotation(&mut self, _ty: &mut UserTypeAnnotation<'tcx>) {
fn visit_user_type_annotation(
&mut self,
_index: UserTypeAnnotationIndex,
_ty: &mut Canonical<'tcx, UserTypeAnnotation<'tcx>>,
) {
// User type annotations represent the types that the user
// wrote in the progarm. We don't want to erase the regions
// from these types: rather, we want to add them as

View File

@ -36,7 +36,10 @@ use rustc::traits::query::{Fallible, NoSolution};
use rustc::traits::{ObligationCause, PredicateObligations};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::{Subst, Substs, UnpackedKind};
use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
use rustc::ty::{
self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserTypeAnnotation,
UserTypeAnnotationIndex,
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc::ty::layout::VariantIdx;
@ -272,19 +275,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
self.sanitize_constant(constant, location);
self.sanitize_type(constant, constant.ty);
if let Some(user_ty) = constant.user_ty {
if let Some(annotation_index) = constant.user_ty {
if let Err(terr) = self.cx.relate_type_and_user_type(
constant.ty,
ty::Variance::Invariant,
&UserTypeProjection { base: user_ty, projs: vec![], },
&UserTypeProjection { base: annotation_index, projs: vec![], },
location.to_locations(),
ConstraintCategory::Boring,
) {
let annotation = self.cx.instantiated_type_annotations[&annotation_index];
span_mirbug!(
self,
constant,
"bad constant user type {:?} vs {:?}: {:?}",
user_ty,
annotation,
constant.ty,
terr,
);
@ -303,8 +307,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
self.sanitize_type(local_decl, local_decl.ty);
for (user_ty, span) in local_decl.user_ty.projections_and_spans() {
let ty = if !local_decl.is_nonref_binding() {
// If we have a binding of the form `let ref x: T = ..` then remove the outermost
// reference so we can check the type annotation for the remaining type.
if let ty::Ref(_, rty, _) = local_decl.ty.sty {
rty
} else {
bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty);
}
} else {
local_decl.ty
};
if let Err(terr) = self.cx.relate_type_and_user_type(
local_decl.ty,
ty,
ty::Variance::Invariant,
user_ty,
Locations::All(*span),
@ -715,6 +731,15 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
/// For each user-type annotation (identified by a UserTypeAnnotationIndex), we create
/// an "instantiated" version at the beginning of type check, which replaces each
/// canonical variable with a fresh inference variable. These instantiated versions are
/// stored either in this field or in user_substs, depending on the kind of user-type
/// annotation. They are then referenced by the code which has the job of enforcing these
/// annotations. Part of the reason for this setup is that it allows us to enforce basic
/// WF criteria on the types even if the code that referenced them is dead
/// code (see #54943).
instantiated_type_annotations: FxHashMap<UserTypeAnnotationIndex, UserTypeAnnotation<'tcx>>,
}
struct BorrowCheckContext<'a, 'tcx: 'a> {
@ -860,7 +885,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
) -> Self {
TypeChecker {
let mut checker = Self {
infcx,
last_span: DUMMY_SP,
mir,
@ -871,7 +896,36 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
borrowck_context,
reported_errors: Default::default(),
universal_region_relations,
instantiated_type_annotations: Default::default(),
};
checker.instantiate_user_type_annotations();
checker
}
/// Instantiate canonical types from user type annotations in the `Mir` into the
/// `TypeChecker`. Used when relating user type annotations and when checking if
/// annotations are well-formed.
fn instantiate_user_type_annotations(&mut self) {
debug!(
"instantiate_user_type_annotations: user_type_annotations={:?}",
self.mir.user_type_annotations
);
for annotation_index in self.mir.user_type_annotations.indices() {
let (span, canonical_annotation) = &self.mir.user_type_annotations[annotation_index];
let (mut annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
*span, &canonical_annotation
);
match annotation {
UserTypeAnnotation::Ty(ref mut ty) =>
*ty = self.normalize(ty, Locations::All(*span)),
_ => {},
}
self.instantiated_type_annotations.insert(annotation_index, annotation);
}
debug!(
"instantiate_user_type_annotations: instantiated_type_annotations={:?}",
self.instantiated_type_annotations,
);
}
/// Given some operation `op` that manipulates types, proves
@ -1003,18 +1057,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
a, v, user_ty, locations,
);
match user_ty.base {
UserTypeAnnotation::Ty(canonical_ty) => {
let (ty, _) = self.infcx
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
let type_annotation = self.instantiated_type_annotations[&user_ty.base];
match type_annotation {
UserTypeAnnotation::Ty(ty) => {
// The `TypeRelating` code assumes that "unresolved inference
// variables" appear in the "a" side, so flip `Contravariant`
// ambient variance to get the right relationship.
let v1 = ty::Contravariant.xform(v);
let tcx = self.infcx.tcx;
let ty = self.normalize(ty, locations);
// We need to follow any provided projetions into the type.
//
@ -1048,13 +1098,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
self.relate_types(ty, v1, a, locations, category)?;
}
}
UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
let (
user_substs,
_,
) = self.infcx
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
UserTypeAnnotation::TypeOf(def_id, user_substs) => {
let projs = self.infcx.tcx.intern_projs(&user_ty.projs);
self.fully_perform_op(
locations,
@ -1225,19 +1269,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
);
}
if let Some(user_ty) = self.rvalue_user_ty(rv) {
if let Some(annotation_index) = self.rvalue_user_ty(rv) {
if let Err(terr) = self.relate_type_and_user_type(
rv_ty,
ty::Variance::Invariant,
&UserTypeProjection { base: user_ty, projs: vec![], },
&UserTypeProjection { base: annotation_index, projs: vec![], },
location.to_locations(),
ConstraintCategory::Boring,
) {
let annotation = self.instantiated_type_annotations[&annotation_index];
span_mirbug!(
self,
stmt,
"bad user type on rvalue ({:?} = {:?}): {:?}",
user_ty,
annotation,
rv_ty,
terr
);
@ -1282,21 +1327,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
);
};
}
StatementKind::AscribeUserType(ref place, variance, box ref c_ty) => {
StatementKind::AscribeUserType(ref place, variance, box ref projection) => {
let place_ty = place.ty(mir, tcx).to_ty(tcx);
if let Err(terr) = self.relate_type_and_user_type(
place_ty,
variance,
c_ty,
projection,
Locations::All(stmt.source_info.span),
ConstraintCategory::TypeAnnotation,
) {
let annotation = self.instantiated_type_annotations[&projection.base];
span_mirbug!(
self,
stmt,
"bad type assert ({:?} <: {:?}): {:?}",
"bad type assert ({:?} <: {:?} with projections {:?}): {:?}",
place_ty,
c_ty,
annotation,
projection.projs,
terr
);
}
@ -1955,7 +2002,7 @@ 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<UserTypeAnnotation<'tcx>> {
fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<UserTypeAnnotationIndex> {
match rvalue {
Rvalue::Use(_)
| Rvalue::Repeat(..)

View File

@ -141,9 +141,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
None, remainder_span, lint_level, slice::from_ref(&pattern),
ArmHasGuard(false), None);
debug!("ast_block_stmts: pattern={:?}", pattern);
this.visit_bindings(
&pattern,
&PatternTypeProjections::none(),
UserTypeProjections::none(),
&mut |this, _, _, _, node, span, _, _| {
this.storage_live_binding(block, node, span, OutsideGuard);
this.schedule_drop_for_binding(node, span, OutsideGuard);

View File

@ -29,11 +29,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
lint_level: _,
value,
} => this.as_constant(value),
ExprKind::Literal { literal, user_ty } => Constant {
span,
ty,
user_ty,
literal,
ExprKind::Literal { literal, user_ty } => {
let user_ty = user_ty.map(|ty| {
this.canonical_user_type_annotations.push((span, ty))
});
Constant {
span,
ty,
user_ty,
literal,
}
},
_ => span_bug!(span, "expression is not a valid constant {:?}", kind),
}

View File

@ -133,6 +133,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ExprKind::PlaceTypeAscription { source, user_ty } => {
let place = unpack!(block = this.as_place(block, source));
if let Some(user_ty) = user_ty {
let annotation_index = this.canonical_user_type_annotations.push(
(source_info.span, user_ty)
);
this.cfg.push(
block,
Statement {
@ -140,7 +143,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
kind: StatementKind::AscribeUserType(
place.clone(),
Variance::Invariant,
box UserTypeProjection { base: user_ty, projs: vec![], },
box UserTypeProjection { base: annotation_index, projs: vec![], },
),
},
);
@ -153,6 +156,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
block = this.as_temp(block, source.temp_lifetime, source, mutability)
);
if let Some(user_ty) = user_ty {
let annotation_index = this.canonical_user_type_annotations.push(
(source_info.span, user_ty)
);
this.cfg.push(
block,
Statement {
@ -160,7 +166,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
kind: StatementKind::AscribeUserType(
Place::Local(temp.clone()),
Variance::Invariant,
box UserTypeProjection { base: user_ty, projs: vec![], },
box UserTypeProjection { base: annotation_index, projs: vec![], },
),
},
);

View File

@ -331,6 +331,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
.collect()
};
let user_ty = user_ty.map(|ty| {
this.canonical_user_type_annotations.push((expr_span, ty))
});
let adt = box AggregateKind::Adt(
adt_def,
variant_index,

View File

@ -8,7 +8,6 @@ use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard};
use build::{BlockAnd, BlockAndExtension, Builder};
use build::{GuardFrame, GuardFrameLocal, LocalsForNode};
use hair::*;
use hair::pattern::PatternTypeProjections;
use rustc::mir::*;
use rustc::ty::{self, Ty};
use rustc::ty::layout::VariantIdx;
@ -302,6 +301,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
);
let ty_source_info = self.source_info(user_ty_span);
let user_ty = box pat_ascription_ty.user_ty(
&mut self.canonical_user_type_annotations, ty_source_info.span
);
self.cfg.push(
block,
Statement {
@ -309,7 +311,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
kind: StatementKind::AscribeUserType(
place,
ty::Variance::Invariant,
box pat_ascription_ty.user_ty(),
user_ty,
),
},
);
@ -406,9 +408,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
);
let mut scope = self.source_scope;
let num_patterns = patterns.len();
debug!("declare_bindings: patterns={:?}", patterns);
self.visit_bindings(
&patterns[0],
&PatternTypeProjections::none(),
UserTypeProjections::none(),
&mut |this, mutability, name, mode, var, span, ty, user_ty| {
if visibility_scope.is_none() {
visibility_scope =
@ -484,7 +487,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pub(super) fn visit_bindings(
&mut self,
pattern: &Pattern<'tcx>,
pattern_user_ty: &PatternTypeProjections<'tcx>,
pattern_user_ty: UserTypeProjections<'tcx>,
f: &mut impl FnMut(
&mut Self,
Mutability,
@ -493,9 +496,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
NodeId,
Span,
Ty<'tcx>,
&PatternTypeProjections<'tcx>,
UserTypeProjections<'tcx>,
),
) {
debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty);
match *pattern.kind {
PatternKind::Binding {
mutability,
@ -506,19 +510,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ref subpattern,
..
} => {
let pattern_ref_binding; // sidestep temp lifetime limitations.
let binding_user_ty = match mode {
BindingMode::ByValue => { pattern_user_ty }
BindingMode::ByRef(..) => {
// If this is a `ref` binding (e.g., `let ref
// x: T = ..`), then the type of `x` is not
// `T` but rather `&T`.
pattern_ref_binding = pattern_user_ty.ref_binding();
&pattern_ref_binding
}
};
f(self, mutability, name, mode, var, pattern.span, ty, binding_user_ty);
f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
if let Some(subpattern) = subpattern.as_ref() {
self.visit_bindings(subpattern, pattern_user_ty, f);
}
@ -536,18 +528,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let from = u32::try_from(prefix.len()).unwrap();
let to = u32::try_from(suffix.len()).unwrap();
for subpattern in prefix {
self.visit_bindings(subpattern, &pattern_user_ty.index(), f);
self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f);
}
for subpattern in slice {
self.visit_bindings(subpattern, &pattern_user_ty.subslice(from, to), f);
self.visit_bindings(subpattern, pattern_user_ty.clone().subslice(from, to), f);
}
for subpattern in suffix {
self.visit_bindings(subpattern, &pattern_user_ty.index(), f);
self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f);
}
}
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
PatternKind::Deref { ref subpattern } => {
self.visit_bindings(subpattern, &pattern_user_ty.deref(), f);
self.visit_bindings(subpattern, pattern_user_ty.deref(), f);
}
PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => {
// This corresponds to something like
@ -555,22 +547,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// ```
// let A::<'a>(_): A<'static> = ...;
// ```
let subpattern_user_ty = pattern_user_ty.add_user_type(user_ty, user_ty_span);
self.visit_bindings(subpattern, &subpattern_user_ty, f)
let annotation = (user_ty_span, user_ty.base);
let projection = UserTypeProjection {
base: self.canonical_user_type_annotations.push(annotation),
projs: user_ty.projs.clone(),
};
let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span);
self.visit_bindings(subpattern, subpattern_user_ty, f)
}
PatternKind::Leaf { ref subpatterns } => {
for subpattern in subpatterns {
let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field);
self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
}
}
PatternKind::Variant { adt_def, substs: _, variant_index, ref subpatterns } => {
for subpattern in subpatterns {
let subpattern_user_ty = pattern_user_ty.variant(
let subpattern_user_ty = pattern_user_ty.clone().variant(
adt_def, variant_index, subpattern.field);
self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
}
}
}
@ -1314,6 +1312,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ascription.user_ty,
);
let user_ty = box ascription.user_ty.clone().user_ty(
&mut self.canonical_user_type_annotations, source_info.span
);
self.cfg.push(
block,
Statement {
@ -1321,7 +1322,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
kind: StatementKind::AscribeUserType(
ascription.source.clone(),
ty::Variance::Covariant,
box ascription.user_ty.clone().user_ty(),
user_ty,
),
},
);
@ -1468,7 +1469,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
num_patterns: usize,
var_id: NodeId,
var_ty: Ty<'tcx>,
user_var_ty: &PatternTypeProjections<'tcx>,
user_ty: UserTypeProjections<'tcx>,
has_guard: ArmHasGuard,
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
pat_span: Span,
@ -1484,10 +1485,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()),
BindingMode::ByRef { .. } => ty::BindingMode::BindByReference(mutability.into()),
};
debug!("declare_binding: user_ty={:?}", user_ty);
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty,
user_ty: user_var_ty.clone().user_ty(),
user_ty,
name: Some(name),
source_info,
visibility_scope,

View File

@ -379,6 +379,7 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
/// (A match binding can have two locals; the 2nd is for the arm's guard.)
var_indices: NodeMap<LocalsForNode>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
upvar_decls: Vec<UpvarDecl>,
unit_temp: Option<Place<'tcx>>,
@ -812,6 +813,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
LocalDecl::new_return_place(return_ty, return_span),
1,
),
canonical_user_type_annotations: IndexVec::new(),
upvar_decls,
var_indices: Default::default(),
unit_temp: None,
@ -845,6 +847,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
IndexVec::new(),
yield_ty,
self.local_decls,
self.canonical_user_type_annotations,
self.arg_count,
self.upvar_decls,
self.fn_span,

View File

@ -78,12 +78,13 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let mut pattern = cx.pattern_from_hir(&local.pat);
if let Some(ty) = &local.ty {
if let Some(&user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) {
if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) {
debug!("mirror_stmts: user_ty={:?}", user_ty);
pattern = Pattern {
ty: pattern.ty,
span: pattern.span,
kind: Box::new(PatternKind::AscribeUserType {
user_ty: PatternTypeProjection::from_canonical_ty(user_ty),
user_ty: PatternTypeProjection::from_user_type(user_ty),
user_ty_span: ty.span,
subpattern: pattern
})

View File

@ -11,7 +11,7 @@ use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability
use rustc::ty::cast::CastKind as TyCastKind;
use rustc::hir;
use rustc::hir::def_id::LocalDefId;
use rustc::mir::{BorrowKind};
use rustc::mir::BorrowKind;
use syntax_pos::Span;
impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
@ -283,9 +283,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| UserTypeAnnotation::TypeOf(adt_def.did, user_substs));
let user_provided_types = cx.tables().user_provided_types();
let user_ty = user_provided_types.get(fun.hir_id)
.map(|u_ty| *u_ty)
.map(|mut u_ty| {
if let UserTypeAnnotation::TypeOf(ref mut did, _) = &mut u_ty.value {
*did = adt_def.did;
}
u_ty
});
debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
let field_refs = args.iter()
.enumerate()
@ -464,11 +471,14 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
ty::Adt(adt, substs) => {
match adt.adt_kind() {
AdtKind::Struct | AdtKind::Union => {
let user_provided_types = cx.tables().user_provided_types();
let user_ty = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
ExprKind::Adt {
adt_def: adt,
variant_index: VariantIdx::new(0),
substs,
user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
user_ty,
fields: field_refs(cx, fields),
base: base.as_ref().map(|base| {
FruInfo {
@ -487,11 +497,18 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
assert!(base.is_none());
let index = adt.variant_index_with_id(variant_id);
let user_provided_types = cx.tables().user_provided_types();
let user_ty = user_provided_types.get(expr.hir_id)
.map(|u_ty| *u_ty);
debug!(
"make_mirror_unadjusted: (variant) user_ty={:?}",
user_ty
);
ExprKind::Adt {
adt_def: adt,
variant_index: index,
substs,
user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
user_ty,
fields: field_refs(cx, fields),
base: None,
}
@ -635,8 +652,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
}
hir::ExprKind::Cast(ref source, ref cast_ty) => {
// Check for a user-given type annotation on this `cast`
let user_ty = cx.tables.user_provided_tys().get(cast_ty.hir_id)
.map(|&t| UserTypeAnnotation::Ty(t));
let user_provided_types = cx.tables.user_provided_types();
let user_ty = user_provided_types.get(cast_ty.hir_id);
debug!(
"cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
@ -742,20 +759,20 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
span: expr.span,
kind: cast,
};
debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty);
ExprKind::ValueTypeAscription {
source: cast_expr.to_ref(),
user_ty: Some(user_ty),
user_ty: Some(*user_ty),
}
} else {
cast
}
}
hir::ExprKind::Type(ref source, ref ty) => {
let user_provided_tys = cx.tables.user_provided_tys();
let user_ty = user_provided_tys
.get(ty.hir_id)
.map(|&c_ty| UserTypeAnnotation::Ty(c_ty));
let user_provided_types = cx.tables.user_provided_types();
let user_ty = user_provided_types.get(ty.hir_id).map(|u_ty| *u_ty);
debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
if source.is_place_expr() {
ExprKind::PlaceTypeAscription {
source: source.to_ref(),
@ -792,8 +809,9 @@ fn user_substs_applied_to_def(
cx: &mut Cx<'a, 'gcx, 'tcx>,
hir_id: hir::HirId,
def: &Def,
) -> Option<UserTypeAnnotation<'tcx>> {
match def {
) -> Option<ty::CanonicalUserTypeAnnotation<'tcx>> {
debug!("user_substs_applied_to_def: def={:?}", def);
let user_provided_type = 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.
@ -802,8 +820,7 @@ fn user_substs_applied_to_def(
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) |
Def::Const(_) |
Def::AssociatedConst(_) =>
Some(UserTypeAnnotation::TypeOf(def.def_id(), cx.tables().user_substs(hir_id)?)),
Def::AssociatedConst(_) => cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty),
// A unit struct/variant which is used as a value (e.g.,
// `None`). This has the type of the enum/struct that defines
@ -819,7 +836,9 @@ fn user_substs_applied_to_def(
_ =>
bug!("user_substs_applied_to_def: unexpected def {:?} at {:?}", def, hir_id)
}
};
debug!("user_substs_applied_to_def: user_provided_type={:?}", user_provided_type);
user_provided_type
}
fn method_callee<'a, 'gcx, 'tcx>(
@ -839,6 +858,7 @@ fn method_callee<'a, 'gcx, 'tcx>(
span_bug!(expr.span, "no type-dependent def for method callee")
});
let user_ty = user_substs_applied_to_def(cx, expr.hir_id, def);
debug!("method_callee: user_ty={:?}", user_ty);
(def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty)
}
};
@ -906,6 +926,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
Def::VariantCtor(_, CtorKind::Fn) |
Def::SelfCtor(..) => {
let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
debug!("convert_path_expr: user_ty={:?}", user_ty);
ExprKind::Literal {
literal: ty::Const::zero_sized(
cx.tcx,
@ -918,6 +939,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
Def::Const(def_id) |
Def::AssociatedConst(def_id) => {
let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
ExprKind::Literal {
literal: ty::Const::unevaluated(
cx.tcx,
@ -931,6 +953,9 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
Def::StructCtor(def_id, CtorKind::Const) |
Def::VariantCtor(def_id, CtorKind::Const) => {
let user_provided_types = cx.tables.user_provided_types();
let user_provided_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
debug!("convert_path_expr: user_provided_type={:?}", user_provided_type);
match cx.tables().node_id_to_type(expr.hir_id).sty {
// A unit struct/variant which is used as a value.
// We return a completely different ExprKind here to account for this special case.
@ -939,7 +964,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: cx.user_substs_applied_to_adt(expr.hir_id, adt_def),
user_ty: user_provided_type,
fields: vec![],
base: None,
}

View File

@ -4,11 +4,12 @@
//! unit-tested and separated from the Rust source and compiler data
//! structures.
use rustc::mir::{BinOp, BorrowKind, UserTypeAnnotation, Field, UnOp};
use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
use rustc::hir::def_id::DefId;
use rustc::infer::canonical::Canonical;
use rustc::middle::region;
use rustc::ty::subst::Substs;
use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const};
use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const, UserTypeAnnotation};
use rustc::ty::layout::VariantIdx;
use rustc::hir;
use syntax::ast;
@ -20,7 +21,7 @@ mod constant;
pub mod pattern;
pub use self::pattern::{BindingMode, Pattern, PatternKind, PatternRange, FieldPattern};
pub(crate) use self::pattern::{PatternTypeProjection, PatternTypeProjections};
pub(crate) use self::pattern::PatternTypeProjection;
mod util;
@ -265,7 +266,7 @@ pub enum ExprKind<'tcx> {
/// Optional user-given substs: for something like `let x =
/// Bar::<T> { ... }`.
user_ty: Option<UserTypeAnnotation<'tcx>>,
user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
fields: Vec<FieldExprRef<'tcx>>,
base: Option<FruInfo<'tcx>>
@ -273,12 +274,12 @@ pub enum ExprKind<'tcx> {
PlaceTypeAscription {
source: ExprRef<'tcx>,
/// Type that the user gave to this expression
user_ty: Option<UserTypeAnnotation<'tcx>>,
user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
},
ValueTypeAscription {
source: ExprRef<'tcx>,
/// Type that the user gave to this expression
user_ty: Option<UserTypeAnnotation<'tcx>>,
user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
},
Closure {
closure_id: DefId,
@ -288,7 +289,7 @@ pub enum ExprKind<'tcx> {
},
Literal {
literal: &'tcx Const<'tcx>,
user_ty: Option<UserTypeAnnotation<'tcx>>,
user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
},
InlineAsm {
asm: &'tcx hir::InlineAsm,

View File

@ -12,9 +12,10 @@ use hair::util::UserAnnotatedTyHelpers;
use hair::constant::*;
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::{ProjectionElem, UserTypeAnnotation, UserTypeProjection, UserTypeProjections};
use rustc::mir::{ProjectionElem, UserTypeProjection};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, Lift};
use rustc::ty::{CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, UserTypeAnnotation};
use rustc::ty::subst::{Substs, Kind};
use rustc::ty::layout::VariantIdx;
use rustc::hir::{self, PatKind, RangeEnd};
@ -58,113 +59,29 @@ pub struct Pattern<'tcx> {
#[derive(Clone, Debug)]
pub(crate) struct PatternTypeProjections<'tcx> {
contents: Vec<(PatternTypeProjection<'tcx>, Span)>,
pub struct PatternTypeProjection<'tcx> {
pub base: CanonicalUserTypeAnnotation<'tcx>,
pub projs: Vec<ProjectionElem<'tcx, (), ()>>,
}
impl<'tcx> PatternTypeProjections<'tcx> {
pub(crate) fn user_ty(self) -> UserTypeProjections<'tcx> {
UserTypeProjections::from_projections(
self.contents.into_iter().map(|(pat_ty_proj, span)| (pat_ty_proj.user_ty(), span)))
}
pub(crate) fn none() -> Self {
PatternTypeProjections { contents: vec![] }
}
pub(crate) fn ref_binding(&self) -> Self {
// FIXME(#55401): ignore for now
PatternTypeProjections { contents: vec![] }
}
fn map_projs(&self,
mut f: impl FnMut(&PatternTypeProjection<'tcx>) -> PatternTypeProjection<'tcx>)
-> Self
{
PatternTypeProjections {
contents: self.contents
.iter()
.map(|(proj, span)| (f(proj), *span))
.collect(), }
}
pub(crate) fn index(&self) -> Self { self.map_projs(|pat_ty_proj| pat_ty_proj.index()) }
pub(crate) fn subslice(&self, from: u32, to: u32) -> Self {
self.map_projs(|pat_ty_proj| pat_ty_proj.subslice(from, to))
}
pub(crate) fn deref(&self) -> Self { self.map_projs(|pat_ty_proj| pat_ty_proj.deref()) }
pub(crate) fn leaf(&self, field: Field) -> Self {
self.map_projs(|pat_ty_proj| pat_ty_proj.leaf(field))
}
pub(crate) fn variant(&self,
adt_def: &'tcx AdtDef,
variant_index: VariantIdx,
field: Field) -> Self {
self.map_projs(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field))
}
pub(crate) fn add_user_type(&self, user_ty: &PatternTypeProjection<'tcx>, sp: Span) -> Self {
let mut new = self.clone();
new.contents.push((user_ty.clone(), sp));
new
}
}
#[derive(Clone, Debug)]
pub struct PatternTypeProjection<'tcx>(UserTypeProjection<'tcx>);
impl<'tcx> PatternTypeProjection<'tcx> {
pub(crate) fn index(&self) -> Self {
let mut new = self.clone();
new.0.projs.push(ProjectionElem::Index(()));
new
pub(crate) fn from_user_type(user_annotation: CanonicalUserTypeAnnotation<'tcx>) -> Self {
Self {
base: user_annotation,
projs: Vec::new(),
}
}
pub(crate) fn subslice(&self, from: u32, to: u32) -> Self {
let mut new = self.clone();
new.0.projs.push(ProjectionElem::Subslice { from, to });
new
pub(crate) fn user_ty(
self,
annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
span: Span,
) -> UserTypeProjection<'tcx> {
UserTypeProjection {
base: annotations.push((span, self.base)),
projs: self.projs
}
}
pub(crate) fn deref(&self) -> Self {
let mut new = self.clone();
new.0.projs.push(ProjectionElem::Deref);
new
}
pub(crate) fn leaf(&self, field: Field) -> Self {
let mut new = self.clone();
new.0.projs.push(ProjectionElem::Field(field, ()));
new
}
pub(crate) fn variant(&self,
adt_def: &'tcx AdtDef,
variant_index: VariantIdx,
field: Field) -> Self {
let mut new = self.clone();
new.0.projs.push(ProjectionElem::Downcast(adt_def, variant_index));
new.0.projs.push(ProjectionElem::Field(field, ()));
new
}
pub(crate) fn from_canonical_ty(c_ty: ty::CanonicalTy<'tcx>) -> Self {
Self::from_user_type(UserTypeAnnotation::Ty(c_ty))
}
pub(crate) fn from_user_type(u_ty: UserTypeAnnotation<'tcx>) -> Self {
Self::from_user_type_proj(UserTypeProjection { base: u_ty, projs: vec![], })
}
pub(crate) fn from_user_type_proj(u_ty: UserTypeProjection<'tcx>) -> Self {
PatternTypeProjection(u_ty)
}
pub(crate) fn user_ty(self) -> UserTypeProjection<'tcx> { self.0 }
}
#[derive(Clone, Debug)]
@ -788,18 +705,14 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
};
if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
let subpattern = Pattern {
span,
ty,
kind: Box::new(kind),
};
debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span);
let pat_ty = PatternTypeProjection::from_user_type(user_ty);
debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
kind = PatternKind::AscribeUserType {
subpattern,
user_ty: pat_ty,
subpattern: Pattern {
span,
ty,
kind: Box::new(kind),
},
user_ty: PatternTypeProjection::from_user_type(user_ty),
user_ty_span: span,
};
}
@ -837,7 +750,28 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
};
match self.tcx.at(span).const_eval(self.param_env.and(cid)) {
Ok(value) => {
return self.const_to_pat(instance, value, id, span)
let pattern = self.const_to_pat(instance, value, id, span);
if !is_associated_const {
return pattern;
}
let user_provided_types = self.tables().user_provided_types();
return if let Some(u_ty) = user_provided_types.get(id) {
let user_ty = PatternTypeProjection::from_user_type(*u_ty);
Pattern {
span,
kind: Box::new(
PatternKind::AscribeUserType {
subpattern: pattern,
user_ty,
user_ty_span: span,
}
),
ty: value.ty,
}
} else {
pattern
}
},
Err(_) => {
self.tcx.sess.span_err(
@ -927,7 +861,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
id: hir::HirId,
span: Span,
) -> Pattern<'tcx> {
debug!("const_to_pat: cv={:#?}", cv);
debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
let adt_subpattern = |i, variant_opt| {
let field = Field::new(i);
let val = const_field(
@ -945,6 +879,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}
}).collect::<Vec<_>>()
};
debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span);
let kind = match cv.ty.sty {
ty::Float(_) => {
let id = self.tcx.hir().hir_to_node_id(id);

View File

@ -1,37 +1,31 @@
use rustc::hir;
use rustc::mir::UserTypeAnnotation;
use rustc::ty::{self, AdtDef, TyCtxt};
use rustc::ty::{self, CanonicalUserTypeAnnotation, TyCtxt, UserTypeAnnotation};
crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>;
fn tables(&self) -> &ty::TypeckTables<'tcx>;
fn user_substs_applied_to_adt(
&self,
hir_id: hir::HirId,
adt_def: &'tcx AdtDef,
) -> Option<UserTypeAnnotation<'tcx>> {
let user_substs = self.tables().user_substs(hir_id)?;
Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs))
}
/// Looks up the type associated with this hir-id and applies the
/// user-given substitutions; the hir-id must map to a suitable
/// type.
fn user_substs_applied_to_ty_of_hir_id(
&self,
hir_id: hir::HirId,
) -> Option<UserTypeAnnotation<'tcx>> {
let user_substs = self.tables().user_substs(hir_id)?;
) -> Option<CanonicalUserTypeAnnotation<'tcx>> {
let user_provided_types = self.tables().user_provided_types();
let mut user_ty = *user_provided_types.get(hir_id)?;
debug!("user_subts_applied_to_ty_of_hir_id: user_ty={:?}", user_ty);
match &self.tables().node_id_to_type(hir_id).sty {
ty::Adt(adt_def, _) => Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs)),
ty::FnDef(def_id, _) => Some(UserTypeAnnotation::TypeOf(*def_id, user_substs)),
sty => bug!(
"sty: {:?} should not have user-substs {:?} recorded ",
sty,
user_substs
),
ty::Adt(adt_def, ..) => {
if let UserTypeAnnotation::TypeOf(ref mut did, _) = &mut user_ty.value {
*did = adt_def.did;
}
Some(user_ty)
}
ty::FnDef(..) => Some(user_ty),
sty =>
bug!("sty: {:?} should not have user provided type {:?} recorded ", sty, user_ty),
}
}
}

View File

@ -207,6 +207,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
IndexVec::new(),
None,
local_decls_for_sig(&sig, span),
IndexVec::new(),
sig.inputs().len(),
vec![],
span,
@ -376,6 +377,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
IndexVec::new(),
None,
self.local_decls,
IndexVec::new(),
self.sig.inputs().len(),
vec![],
self.span,
@ -825,6 +827,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
IndexVec::new(),
None,
local_decls,
IndexVec::new(),
sig.inputs().len(),
vec![],
span,
@ -903,6 +906,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
IndexVec::new(),
None,
local_decls,
IndexVec::new(),
sig.inputs().len(),
vec![],
span,

View File

@ -400,6 +400,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
IndexVec::new(),
None,
initial_locals,
IndexVec::new(),
0,
vec![],
mir.span,

View File

@ -142,6 +142,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
}
writeln!(file, "")?;
extra_data(PassWhere::BeforeCFG, &mut file)?;
write_user_type_annotations(mir, &mut file)?;
write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?;
extra_data(PassWhere::AfterCFG, &mut file)?;
};
@ -618,6 +619,19 @@ fn write_temp_decls(mir: &Mir, w: &mut dyn Write) -> io::Result<()> {
Ok(())
}
fn write_user_type_annotations(mir: &Mir, w: &mut dyn Write) -> io::Result<()> {
if !mir.user_type_annotations.is_empty() {
writeln!(w, "| User Type Annotations")?;
}
for (index, (span, annotation)) in mir.user_type_annotations.iter_enumerated() {
writeln!(w, "| {:?}: {:?} at {:?}", index.index(), annotation, span)?;
}
if !mir.user_type_annotations.is_empty() {
writeln!(w, "|")?;
}
Ok(())
}
pub fn dump_mir_def_ids(tcx: TyCtxt, single: Option<DefId>) -> Vec<DefId> {
if let Some(i) = single {
vec![i]

View File

@ -14,7 +14,7 @@ use rustc::traits::{
Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt,
};
use rustc::ty::query::Providers;
use rustc::ty::subst::{Kind, Subst, UserSelfTy, UserSubsts};
use rustc::ty::subst::{Kind, Subst, UserSubsts, UserSelfTy};
use rustc::ty::{
FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance,
};
@ -44,28 +44,16 @@ fn type_op_ascribe_user_type<'tcx>(
tcx.infer_ctxt()
.enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
let (
param_env,
AscribeUserType {
mir_ty,
variance,
def_id,
user_substs,
projs,
},
param_env, AscribeUserType { mir_ty, variance, def_id, user_substs, projs }
) = key.into_parts();
debug!(
"type_op_ascribe_user_type(\
mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}, projs={:?}\
)",
mir_ty, variance, def_id, user_substs, projs,
"type_op_ascribe_user_type: mir_ty={:?} variance={:?} def_id={:?} \
user_substs={:?} projs={:?}",
mir_ty, variance, def_id, user_substs, projs
);
let mut cx = AscribeUserTypeCx {
infcx,
param_env,
fulfill_cx,
};
let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs, projs)?;
Ok(())
@ -130,10 +118,9 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
projs: &[ProjectionKind<'tcx>],
) -> Result<(), NoSolution> {
let UserSubsts {
substs,
user_self_ty,
substs,
} = user_substs;
let tcx = self.tcx();
let ty = tcx.type_of(def_id);
@ -171,20 +158,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
self.relate(mir_ty, variance, ty)?;
}
if let Some(UserSelfTy {
impl_def_id,
self_ty,
}) = user_self_ty
{
let impl_self_ty = self.tcx().type_of(impl_def_id);
let impl_self_ty = self.subst(impl_self_ty, &substs);
let impl_self_ty = self.normalize(impl_self_ty);
self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
self.prove_predicate(Predicate::WellFormed(impl_self_ty));
}
// Prove the predicates coming along with `def_id`.
//
// Also, normalize the `instantiated_predicates`
@ -198,6 +171,19 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
self.prove_predicate(instantiated_predicate);
}
if let Some(UserSelfTy {
impl_def_id,
self_ty,
}) = user_self_ty {
let impl_self_ty = self.tcx().type_of(impl_def_id);
let impl_self_ty = self.subst(impl_self_ty, &substs);
let impl_self_ty = self.normalize(impl_self_ty);
self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
self.prove_predicate(Predicate::WellFormed(impl_self_ty));
}
// In addition to proving the predicates, we have to
// prove that `ty` is well-formed -- this is because
// the WF of `ty` is predicated on the substs being
@ -210,7 +196,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
// type were ill-formed but did not appear in `ty`,
// which...could happen with normalization...
self.prove_predicate(Predicate::WellFormed(ty));
Ok(())
}
}

View File

@ -357,16 +357,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
})
}
pub fn resolve_ufcs(&self,
span: Span,
method_name: ast::Ident,
self_ty: Ty<'tcx>,
expr_id: ast::NodeId)
-> Result<Def, MethodError<'tcx>> {
debug!("resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}",
method_name,
self_ty,
expr_id
pub fn resolve_ufcs(
&self,
span: Span,
method_name: ast::Ident,
self_ty: Ty<'tcx>,
expr_id: ast::NodeId
) -> Result<Def, MethodError<'tcx>> {
debug!(
"resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}",
method_name, self_ty, expr_id,
);
let tcx = self.tcx;
@ -375,6 +375,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
match self.probe_for_name(span, mode, method_name, IsSuggestion(false),
self_ty, expr_id, ProbeScope::TraitsInScope) {
Ok(pick) => {
debug!("resolve_ufcs: pick={:?}", pick);
if let Some(import_id) = pick.import_id {
let import_def_id = tcx.hir().local_def_id(import_id);
debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id);
@ -383,6 +384,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
let def = pick.item.def();
debug!("resolve_ufcs: def={:?}", def);
tcx.check_stability(def.def_id(), Some(expr_id), span);
Ok(def)

View File

@ -102,13 +102,14 @@ use rustc::infer::type_variable::{TypeVariableOrigin};
use rustc::middle::region;
use rustc::mir::interpret::{ConstValue, GlobalId};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, RegionKind, Visibility,
ToPolyTraitRef, ToPredicate};
use rustc::ty::{
self, AdtKind, CanonicalUserTypeAnnotation, Ty, TyCtxt, GenericParamDefKind, Visibility,
ToPolyTraitRef, ToPredicate, RegionKind, UserTypeAnnotation
};
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::query::Providers;
use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
UserSelfTy, UserSubsts};
use rustc::ty::subst::{UnpackedKind, Subst, Substs, UserSelfTy, UserSubsts};
use rustc::ty::util::{Representability, IntTypeExt, Discr};
use rustc::ty::layout::VariantIdx;
use syntax_pos::{self, BytePos, Span, MultiSpan};
@ -974,10 +975,12 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
o_ty
};
let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(&revealed_ty);
let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(
&UserTypeAnnotation::Ty(revealed_ty)
);
debug!("visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
ty.hir_id, o_ty, revealed_ty, c_ty);
self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty);
self.fcx.tables.borrow_mut().user_provided_types_mut().insert(ty.hir_id, c_ty);
Some(LocalTy { decl_ty: o_ty, revealed_ty })
},
@ -2108,8 +2111,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.tables.borrow_mut().field_indices_mut().insert(hir_id, index);
}
// The NodeId and the ItemLocalId must identify the same item. We just pass
// both of them for consistency checking.
pub fn write_method_call(&self,
hir_id: hir::HirId,
method: MethodCallee<'tcx>) {
@ -2138,23 +2139,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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_user_type_annotation(&UserSubsts {
substs: just_method_substs,
let user_type_annotation = self.infcx.probe(|_| {
let user_substs = UserSubsts {
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]
}
}),
user_self_ty: None, // not relevant here
})
};
self.infcx.canonicalize_user_type_annotation(&UserTypeAnnotation::TypeOf(
method.def_id,
user_substs,
))
});
debug!("write_method_call: user_substs = {:?}", user_substs);
self.write_user_substs(hir_id, user_substs);
debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
self.write_user_type_annotation(hir_id, user_type_annotation);
}
}
}
@ -2177,41 +2182,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// This should be invoked **before any unifications have
/// occurred**, so that annotations like `Vec<_>` are preserved
/// properly.
pub fn write_user_substs_from_substs(
pub fn write_user_type_annotation_from_substs(
&self,
hir_id: hir::HirId,
def_id: DefId,
substs: &'tcx Substs<'tcx>,
user_self_ty: Option<UserSelfTy<'tcx>>,
) {
debug!(
"write_user_substs_from_substs({:?}, {:?}) in fcx {}",
hir_id,
substs,
self.tag(),
"write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \
user_self_ty={:?} in fcx {}",
hir_id, def_id, substs, user_self_ty, self.tag(),
);
if !substs.is_noop() {
let user_substs = self.infcx.canonicalize_user_type_annotation(&UserSubsts {
substs,
user_self_ty,
});
debug!("instantiate_value_path: user_substs = {:?}", user_substs);
self.write_user_substs(hir_id, user_substs);
let canonicalized = self.infcx.canonicalize_user_type_annotation(
&UserTypeAnnotation::TypeOf(def_id, UserSubsts {
substs,
user_self_ty,
})
);
debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized);
self.write_user_type_annotation(hir_id, canonicalized);
}
}
pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalUserSubsts<'tcx>) {
pub fn write_user_type_annotation(
&self,
hir_id: hir::HirId,
canonical_user_type_annotation: CanonicalUserTypeAnnotation<'tcx>,
) {
debug!(
"write_user_substs({:?}, {:?}) in fcx {}",
hir_id,
substs,
self.tag(),
"write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
hir_id, canonical_user_type_annotation, self.tag(),
);
if !substs.is_identity() {
self.tables.borrow_mut().user_substs_mut().insert(hir_id, substs);
if !canonical_user_type_annotation.is_identity() {
self.tables.borrow_mut().user_provided_types_mut().insert(
hir_id, canonical_user_type_annotation
);
} else {
debug!("write_user_substs: skipping identity substs");
debug!("write_user_type_annotation: skipping identity substs");
}
}
@ -2377,6 +2388,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
let ty = self.to_ty(ast_ty);
debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
// If the type given by the user has free regions, save it for
// later, since NLL would like to enforce those. Also pass in
@ -2386,8 +2398,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// although I have my doubts). Other sorts of things are
// already sufficiently enforced with erased regions. =)
if ty.has_free_regions() || ty.has_projections() {
let c_ty = self.infcx.canonicalize_response(&ty);
self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty);
let c_ty = self.infcx.canonicalize_response(&UserTypeAnnotation::Ty(ty));
debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
}
ty
@ -3742,7 +3755,7 @@ 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, None);
self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
// Check bounds on type arguments used in the path.
let bounds = self.instantiate_bounds(path_span, did, substs);
@ -4581,6 +4594,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
span: Span)
-> (Def, Option<Ty<'tcx>>, &'b [hir::PathSegment])
{
debug!("resolve_ty_and_def_ufcs: qpath={:?} node_id={:?} span={:?}", qpath, node_id, span);
let (ty, qself, item_segment) = match *qpath {
QPath::Resolved(ref opt_qself, ref path) => {
return (path.def,
@ -5101,6 +5115,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
Def::Method(def_id) |
Def::AssociatedConst(def_id) => {
let container = tcx.associated_item(def_id).container;
debug!("instantiate_value_path: def={:?} container={:?}", def, container);
match container {
ty::TraitContainer(trait_did) => {
callee::check_legal_trait_for_method_call(tcx, span, trait_did)
@ -5300,7 +5315,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// First, store the "user substs" for later.
let hir_id = tcx.hir().node_to_hir_id(node_id);
self.write_user_substs_from_substs(hir_id, substs, user_self_ty);
self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
// Add all the obligations that are required, substituting and
// normalized appropriately.

View File

@ -3,6 +3,7 @@
// substitutions.
use check::FnCtxt;
use errors::DiagnosticBuilder;
use rustc::hir;
use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
@ -357,7 +358,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
let common_local_id_root = fcx_tables.local_id_root.unwrap();
for (&local_id, c_ty) in fcx_tables.user_provided_tys().iter() {
let mut errors_buffer = Vec::new();
for (&local_id, c_ty) in fcx_tables.user_provided_types().iter() {
let hir_id = hir::HirId {
owner: common_local_id_root.index,
local_id,
@ -374,8 +376,30 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
};
self.tables
.user_provided_tys_mut()
.user_provided_types_mut()
.insert(hir_id, c_ty.clone());
if let ty::UserTypeAnnotation::TypeOf(_, user_substs) = c_ty.value {
if self.rustc_dump_user_substs {
// This is a unit-testing mechanism.
let node_id = self.tcx().hir().hir_to_node_id(hir_id);
let span = self.tcx().hir().span(node_id);
// We need to buffer the errors in order to guarantee a consistent
// order when emitting them.
let err = self.tcx().sess.struct_span_err(
span,
&format!("user substs: {:?}", user_substs)
);
err.buffer(&mut errors_buffer);
}
}
}
if !errors_buffer.is_empty() {
errors_buffer.sort_by_key(|diag| diag.span.primary_span());
for diag in errors_buffer.drain(..) {
DiagnosticBuilder::new_diagnostic(self.tcx().sess.diagnostic(), diag).emit();
}
}
}
@ -573,22 +597,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
assert!(!substs.needs_infer() && !substs.has_placeholders());
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

@ -70,7 +70,7 @@ pub fn change_mutability_of_reference_type() {
#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,TypeckTables,MirValidated")]
except="HirBody,TypeckTables,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
pub fn change_mutability_of_reference_type() {
let _x: &mut u64;

View File

@ -37,7 +37,7 @@ fn main() {
// StorageLive(_4);
// _4 = std::option::Option<std::boxed::Box<u32>>::None;
// FakeRead(ForLet, _4);
// AscribeUserType(_4, o, UserTypeProjection { base: Ty(Canonical { max_universe: U0, variables: [], value: std::option::Option<std::boxed::Box<u32>> }), projs: [] });
// AscribeUserType(_4, o, UserTypeProjection { base: UserTypeAnnotation(1), projs: [] });
// StorageLive(_5);
// StorageLive(_6);
// _6 = move _4;

View File

@ -1,5 +1,5 @@
// run-pass
#![allow(dead_code)]
#![allow(dead_code, unreachable_patterns)]
struct Foo;

View File

@ -0,0 +1,15 @@
#![feature(nll)]
// This test is a minimal version of an ICE in the dropck-eyepatch tests
// found in the fix for #54943.
// compile-pass
fn foo<T>(_t: T) {
}
fn main() {
struct A<'a, B: 'a>(&'a B);
let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
foo((a1, a2));
}

View File

@ -0,0 +1,18 @@
#![feature(nll)]
// This test is a minimal version of an ICE in the dropck-eyepatch tests
// found in the fix for #54943. In particular, this test is in unreachable
// code as the initial fix for this ICE only worked if the code was reachable.
// compile-pass
fn foo<T>(_t: T) {
}
fn main() {
return;
struct A<'a, B: 'a>(&'a B);
let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
foo((a1, a2));
}

View File

@ -0,0 +1,21 @@
// compile-pass
// FIXME(#54943) This test targets the scenario where proving the WF requirements requires
// knowing the value of the `_` type present in the user type annotation - unfortunately, figuring
// out the value of that `_` requires type-checking the surrounding code, but that code is dead,
// so our NLL region checker doesn't have access to it. This test should actually fail to compile.
#![feature(nll)]
#![allow(warnings)]
use std::fmt::Debug;
fn foo<T: 'static + Debug>(_: T) { }
fn bar<'a>() {
return;
let _x = foo::<Vec<_>>(Vec::<&'a u32>::new());
//~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477]
}
fn main() {}

View File

@ -0,0 +1,17 @@
// compile-pass
// FIXME(#54943) This test targets the scenario where proving the WF requirements of a user
// type annotation requires checking dead code. This test should actually fail to compile.
#![feature(nll)]
#![allow(warnings)]
fn foo<T: 'static>() { }
fn boo<'a>() {
return;
let x = foo::<&'a u32>();
//~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477]
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0597]: `a` does not live long enough
--> $DIR/issue-55511.rs:13:28
|
LL | let b = Some(Cell::new(&a));
| ^^ borrowed value does not live long enough
...
LL | <() as Foo<'static>>::C => { }
| ----------------------- type annotation requires that `a` is borrowed for `'static`
...
LL | }
| - `a` dropped here while still borrowed
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.

View File

@ -0,0 +1,19 @@
use std::cell::Cell;
trait Foo<'a> {
const C: Option<Cell<&'a u32>>;
}
impl<'a, T> Foo<'a> for T {
const C: Option<Cell<&'a u32>> = None;
}
fn main() {
let a = 22;
let b = Some(Cell::new(&a));
//~^ ERROR `a` does not live long enough [E0597]
match b {
<() as Foo<'static>>::C => { }
_ => { }
}
}

View File

@ -0,0 +1,14 @@
error[E0597]: `a` does not live long enough
--> $DIR/issue-55511.rs:13:29
|
LL | let b = Some(Cell::new(&a));
| ^ borrowed value does not live long enough
...
LL | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.

View File

@ -0,0 +1,8 @@
#![feature(nll)]
fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
let (ref y, _z): (&'a u32, u32) = (&22, 44);
*y //~ ERROR
}
fn main() {}

View File

@ -0,0 +1,11 @@
error: unsatisfied lifetime constraints
--> $DIR/issue-55401.rs:5:5
|
LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
LL | let (ref y, _z): (&'a u32, u32) = (&22, 44);
LL | *y //~ ERROR
| ^^ returning this value requires that `'a` must outlive `'static`
error: aborting due to previous error

View File

@ -1,4 +1,4 @@
error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
error: user substs: UserSubsts { substs: [u32], user_self_ty: None }
--> $DIR/dump-adt-brace-struct.rs:18:5
|
LL | SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]

View File

@ -1,22 +1,22 @@
error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
error: user substs: UserSubsts { substs: [u32], user_self_ty: None }
--> $DIR/dump-fn-method.rs:26:13
|
LL | let x = foo::<u32>; //~ ERROR [u32]
| ^^^^^^^^^^
error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }], value: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } }
error: user substs: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None }
--> $DIR/dump-fn-method.rs:32:13
|
LL | let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [^0, u32, ^1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } }
error: user substs: UserSubsts { substs: [u8, u16, u32], user_self_ty: None }
--> $DIR/dump-fn-method.rs:36:13
|
LL | let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }], value: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } }
error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None }
--> $DIR/dump-fn-method.rs:44:5
|
LL | y.method::<u32>(44, 66); //~ ERROR [^0, ^1, u32]

View File

@ -31,9 +31,7 @@ fn with_assoc<'a,'b>() {
// outlive 'a. In this case, that means TheType<'b>::TheAssocType,
// which is &'b (), must outlive 'a.
// FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
// `_x` is changed to `_`
let _x: &'a WithAssoc<TheType<'b>> = loop { };
let _: &'a WithAssoc<TheType<'b>> = loop { };
//~^ ERROR reference has a longer lifetime
}

View File

@ -1,8 +1,8 @@
error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
--> $DIR/regions-outlives-projection-container-wc.rs:36:13
--> $DIR/regions-outlives-projection-container-wc.rs:34:12
|
LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime 'a as defined on the function body at 28:15
--> $DIR/regions-outlives-projection-container-wc.rs:28:15