1
Fork 0

Auto merge of #55274 - pnkfelix:issue-54570-proj-path-into-pats-with-type-take-2, r=nikomatsakis

Handle bindings in substructure of patterns with type ascriptions

This attempts to follow the outline described by @nikomatsakis [here](https://github.com/rust-lang/rust/issues/47184#issuecomment-420041056). Its a bit more complicated than expected for two reasons:

 1. In general it handles sets of type ascriptions, because such ascriptions can be nested within patterns
 2.  It has a separate types in the HAIR, `PatternTypeProjections` and `PatternTypeProjection`, which are analogues to the corresponding types in the MIR.

The main reason I added the new HAIR types was because I am worried that the current implementation is inefficent, and asymptotically so: It makes copies of vectors as it descends the patterns, even when those accumulated vectors are never used.

Longer term, I would like to used a linked tree structure for the `PatternTypeProjections` and `PatternTypeProjection`, and save the construction of standalone vectors for the MIR types. I didn't want to block landing this on that hypoethetical revision; but I figured I could at least make the future change easier by differentiating between the two types now.

Oh, one more thing: This doesn't attempt to handle `ref x` (in terms of ensuring that any necessary types are ascribed to `x` in that scenario as well). We should open an issue to investigate supporting that as well. But I didn't want to block this PR on that future work.

Fix #54570
This commit is contained in:
bors 2018-10-27 00:39:11 +00:00
commit 10f42cbde0
29 changed files with 622 additions and 127 deletions

View file

@ -606,3 +606,6 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::UserTypeAnnotation<
}
}
}
impl_stable_hash_for!(struct mir::UserTypeProjection<'tcx> { base, projs });
impl_stable_hash_for!(struct mir::UserTypeProjections<'tcx> { contents });

View file

@ -710,7 +710,7 @@ pub struct LocalDecl<'tcx> {
/// e.g. via `let x: T`, then we carry that type here. The MIR
/// borrow checker needs this information since it can affect
/// region inference.
pub user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
pub user_ty: UserTypeProjections<'tcx>,
/// Name of the local, used in debuginfo and pretty-printing.
///
@ -882,7 +882,7 @@ impl<'tcx> LocalDecl<'tcx> {
LocalDecl {
mutability,
ty,
user_ty: None,
user_ty: UserTypeProjections::none(),
name: None,
source_info: SourceInfo {
span,
@ -903,7 +903,7 @@ impl<'tcx> LocalDecl<'tcx> {
LocalDecl {
mutability: Mutability::Mut,
ty: return_ty,
user_ty: None,
user_ty: UserTypeProjections::none(),
source_info: SourceInfo {
span,
scope: OUTERMOST_SOURCE_SCOPE,
@ -1741,7 +1741,7 @@ pub enum StatementKind<'tcx> {
/// - `Contravariant` -- requires that `T_y :> T`
/// - `Invariant` -- requires that `T_y == T`
/// - `Bivariant` -- no effect
AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeAnnotation<'tcx>>),
AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeProjection<'tcx>>),
/// No-op. Useful for deleting instructions without affecting statement indices.
Nop,
@ -1944,6 +1944,10 @@ pub type PlaceProjection<'tcx> = Projection<'tcx, Place<'tcx>, Local, Ty<'tcx>>;
/// and the index is a local.
pub type PlaceElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>;
/// Alias for projections as they appear in `UserTypeProjection`, where we
/// need neither the `V` parameter for `Index` nor the `T` for `Field`.
pub type ProjectionKind<'tcx> = ProjectionElem<'tcx, (), ()>;
newtype_index! {
pub struct Field {
DEBUG_FORMAT = "field[{}]"
@ -2449,6 +2453,117 @@ EnumLiftImpl! {
}
}
/// A collection of projections into user types.
///
/// They are projections because a binding can occur a part of a
/// parent pattern that has been ascribed a type.
///
/// Its a collection because there can be multiple type ascriptions on
/// the path from the root of the pattern down to the binding itself.
///
/// An example:
///
/// ```rust
/// struct S<'a>((i32, &'a str), String);
/// let S((_, w): (i32, &'static str), _): S = ...;
/// // ------ ^^^^^^^^^^^^^^^^^^^ (1)
/// // --------------------------------- ^ (2)
/// ```
///
/// The highlights labelled `(1)` show the subpattern `(_, w)` being
/// ascribed the type `(i32, &'static str)`.
///
/// The highlights labelled `(2)` show the whole pattern being
/// ascribed the type `S`.
///
/// In this example, when we descend to `w`, we will have built up the
/// following two projected types:
///
/// * base: `S`, projection: `(base.0).1`
/// * base: `(i32, &'static str)`, projection: `base.1`
///
/// The first will lead to the constraint `w: &'1 str` (for some
/// inferred region `'1`). The second will lead to the constraint `w:
/// &'static str`.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct UserTypeProjections<'tcx> {
pub(crate) contents: Vec<(UserTypeProjection<'tcx>, Span)>,
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjections<'tcx> {
contents
}
}
impl<'tcx> UserTypeProjections<'tcx> {
pub fn none() -> Self {
UserTypeProjections { contents: vec![] }
}
pub fn from_projections(projs: impl Iterator<Item=(UserTypeProjection<'tcx>, Span)>) -> Self {
UserTypeProjections { contents: projs.collect() }
}
pub fn projections_and_spans(&self) -> impl Iterator<Item=&(UserTypeProjection<'tcx>, Span)> {
self.contents.iter()
}
pub fn projections(&self) -> impl Iterator<Item=&UserTypeProjection<'tcx>> {
self.contents.iter().map(|&(ref user_type, _span)| user_type)
}
}
/// Encodes the effect of a user-supplied type annotation on the
/// subcomponents of a pattern. The effect is determined by applying the
/// given list of proejctions to some underlying base type. Often,
/// the projection element list `projs` is empty, in which case this
/// directly encodes a type in `base`. But in the case of complex patterns with
/// subpatterns and bindings, we want to apply only a *part* of the type to a variable,
/// in which case the `projs` vector is used.
///
/// Examples:
///
/// * `let x: T = ...` -- here, the `projs` vector is empty.
///
/// * `let (x, _): T = ...` -- here, the `projs` vector would contain
/// `field[0]` (aka `.0`), indicating that the type of `s` is
/// 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 projs: Vec<ProjectionElem<'tcx, (), ()>>,
}
impl<'tcx> Copy for ProjectionKind<'tcx> { }
CloneTypeFoldableAndLiftImpls! { ProjectionKind<'tcx>, }
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
use mir::ProjectionElem::*;
let base = self.base.fold_with(folder);
let projs: Vec<_> = self.projs
.iter()
.map(|elem| {
match elem {
Deref => Deref,
Field(f, ()) => Field(f.clone(), ()),
Index(()) => Index(()),
elem => elem.clone(),
}})
.collect();
UserTypeProjection { base, projs }
}
fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
self.base.visit_with(visitor)
// Note: there's nothing in `self.proj` to visit.
}
}
newtype_index! {
pub struct Promoted {
DEBUG_FORMAT = "promoted[{}]"

View file

@ -44,11 +44,59 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
}
}
/// `place_ty.field_ty(tcx, f)` computes the type at a given field
/// of a record or enum-variant. (Most clients of `PlaceTy` can
/// instead just extract the relevant type directly from their
/// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do
/// not carry a `Ty` for `T`.)
///
/// Note that the resulting type has not been normalized.
pub fn field_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, f: &Field) -> Ty<'tcx>
{
// Pass `0` here so it can be used as a "default" variant_index in first arm below
let answer = match (self, 0) {
(PlaceTy::Ty {
ty: &ty::TyS { sty: ty::TyKind::Adt(adt_def, substs), .. } }, variant_index) |
(PlaceTy::Downcast { adt_def, substs, variant_index }, _) => {
let variant_def = &adt_def.variants[variant_index];
let field_def = &variant_def.fields[f.index()];
field_def.ty(tcx, substs)
}
(PlaceTy::Ty { ty }, _) => {
match ty.sty {
ty::Tuple(ref tys) => tys[f.index()],
_ => bug!("extracting field of non-tuple non-adt: {:?}", self),
}
}
};
debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);
answer
}
/// Convenience wrapper around `projection_ty_core` for
/// `PlaceElem`, where we can just use the `Ty` that is already
/// stored inline on field projection elems.
pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
elem: &PlaceElem<'tcx>)
-> PlaceTy<'tcx>
{
match *elem {
self.projection_ty_core(tcx, elem, |_, _, ty| ty)
}
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
/// projects `place_ty` onto `elem`, returning the appropriate
/// `Ty` or downcast variant corresponding to that projection.
/// The `handle_field` callback must map a `Field` to its `Ty`,
/// (which should be trivial when `T` = `Ty`).
pub fn projection_ty_core<V, T>(self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
elem: &ProjectionElem<'tcx, V, T>,
mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>)
-> PlaceTy<'tcx>
where
V: ::std::fmt::Debug, T: ::std::fmt::Debug
{
let answer = match *elem {
ProjectionElem::Deref => {
let ty = self.to_ty(tcx)
.builtin_deref(true)
@ -94,8 +142,10 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
bug!("cannot downcast non-ADT type: `{:?}`", self)
}
},
ProjectionElem::Field(_, fty) => PlaceTy::Ty { ty: fty }
}
ProjectionElem::Field(ref f, ref fty) => PlaceTy::Ty { ty: handle_field(&self, f, fty) }
};
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
answer
}
}

View file

@ -147,7 +147,7 @@ macro_rules! make_mir_visitor {
fn visit_ascribe_user_ty(&mut self,
place: & $($mutability)* Place<'tcx>,
variance: & $($mutability)* ty::Variance,
user_ty: & $($mutability)* UserTypeAnnotation<'tcx>,
user_ty: & $($mutability)* UserTypeProjection<'tcx>,
location: Location) {
self.super_ascribe_user_ty(place, variance, user_ty, location);
}
@ -175,9 +175,8 @@ macro_rules! make_mir_visitor {
fn visit_projection_elem(&mut self,
place: & $($mutability)* PlaceElem<'tcx>,
context: PlaceContext<'tcx>,
location: Location) {
self.super_projection_elem(place, context, location);
self.super_projection_elem(place, location);
}
fn visit_branch(&mut self,
@ -214,6 +213,13 @@ macro_rules! make_mir_visitor {
self.super_ty(ty);
}
fn visit_user_type_projection(
&mut self,
ty: & $($mutability)* UserTypeProjection<'tcx>,
) {
self.super_user_type_projection(ty);
}
fn visit_user_type_annotation(
&mut self,
ty: & $($mutability)* UserTypeAnnotation<'tcx>,
@ -640,10 +646,10 @@ macro_rules! make_mir_visitor {
fn super_ascribe_user_ty(&mut self,
place: & $($mutability)* Place<'tcx>,
_variance: & $($mutability)* ty::Variance,
user_ty: & $($mutability)* UserTypeAnnotation<'tcx>,
user_ty: & $($mutability)* UserTypeProjection<'tcx>,
location: Location) {
self.visit_place(place, PlaceContext::Validate, location);
self.visit_user_type_annotation(user_ty);
self.visit_user_type_projection(user_ty);
}
fn super_place(&mut self,
@ -692,12 +698,11 @@ macro_rules! make_mir_visitor {
PlaceContext::Projection(Mutability::Not)
};
self.visit_place(base, context, location);
self.visit_projection_elem(elem, context, location);
self.visit_projection_elem(elem, location);
}
fn super_projection_elem(&mut self,
proj: & $($mutability)* PlaceElem<'tcx>,
_context: PlaceContext<'tcx>,
location: Location) {
match *proj {
ProjectionElem::Deref => {
@ -738,8 +743,8 @@ macro_rules! make_mir_visitor {
local,
source_info: *source_info,
});
if let Some((user_ty, _)) = user_ty {
self.visit_user_type_annotation(user_ty);
for (user_ty, _) in & $($mutability)* user_ty.contents {
self.visit_user_type_projection(user_ty);
}
self.visit_source_info(source_info);
self.visit_source_scope(visibility_scope);
@ -786,6 +791,17 @@ macro_rules! make_mir_visitor {
self.visit_source_scope(scope);
}
fn super_user_type_projection(
&mut self,
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>,

View file

@ -11,6 +11,7 @@
use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
use traits::query::Fallible;
use hir::def_id::DefId;
use mir::ProjectionKind;
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
use ty::subst::UserSubsts;
@ -20,6 +21,7 @@ pub struct AscribeUserType<'tcx> {
pub variance: ty::Variance,
pub def_id: DefId,
pub user_substs: UserSubsts<'tcx>,
pub projs: &'tcx ty::List<ProjectionKind<'tcx>>,
}
impl<'tcx> AscribeUserType<'tcx> {
@ -28,8 +30,9 @@ impl<'tcx> AscribeUserType<'tcx> {
variance: ty::Variance,
def_id: DefId,
user_substs: UserSubsts<'tcx>,
projs: &'tcx ty::List<ProjectionKind<'tcx>>,
) -> Self {
AscribeUserType { mir_ty, variance, def_id, user_substs }
AscribeUserType { mir_ty, variance, def_id, user_substs, projs }
}
}
@ -59,19 +62,19 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserType<'tcx>
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for AscribeUserType<'tcx> {
mir_ty, variance, def_id, user_substs
mir_ty, variance, def_id, user_substs, projs
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> {
type Lifted = AscribeUserType<'tcx>;
mir_ty, variance, def_id, user_substs
mir_ty, variance, def_id, user_substs, projs
}
}
impl_stable_hash_for! {
struct AscribeUserType<'tcx> {
mir_ty, variance, def_id, user_substs
mir_ty, variance, def_id, user_substs, projs
}
}

View file

@ -31,7 +31,7 @@ use middle::cstore::EncodedMetadata;
use middle::lang_items;
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use middle::stability;
use mir::{self, Mir, interpret};
use mir::{self, Mir, interpret, ProjectionKind};
use mir::interpret::Allocation;
use ty::subst::{CanonicalUserSubsts, Kind, Substs, Subst};
use ty::ReprOptions;
@ -132,6 +132,7 @@ pub struct CtxtInterners<'tcx> {
clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
goal: InternedSet<'tcx, GoalKind<'tcx>>,
goal_list: InternedSet<'tcx, List<Goal<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind<'tcx>>>,
}
impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
@ -149,6 +150,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
clauses: Default::default(),
goal: Default::default(),
goal_list: Default::default(),
projs: Default::default(),
}
}
@ -1886,6 +1888,24 @@ impl<'a, 'tcx> Lift<'tcx> for &'a List<CanonicalVarInfo> {
}
}
impl<'a, 'tcx> Lift<'tcx> for &'a List<ProjectionKind<'a>> {
type Lifted = &'tcx List<ProjectionKind<'tcx>>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
if self.len() == 0 {
return Some(List::empty());
}
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
}
// Also try in the global tcx if we're not that.
if !tcx.is_global() {
self.lift_to_tcx(tcx.global_tcx())
} else {
None
}
}
}
pub mod tls {
use super::{GlobalCtxt, TyCtxt};
@ -2294,6 +2314,13 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> {
}
}
impl<'tcx: 'lcx, 'lcx> Borrow<[ProjectionKind<'lcx>]>
for Interned<'tcx, List<ProjectionKind<'tcx>>> {
fn borrow<'a>(&'a self) -> &'a [ProjectionKind<'lcx>] {
&self.0[..]
}
}
impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
fn borrow<'a>(&'a self) -> &'a RegionKind {
&self.0
@ -2441,7 +2468,8 @@ slice_interners!(
type_list: _intern_type_list(Ty),
substs: _intern_substs(Kind),
clauses: _intern_clauses(Clause),
goal_list: _intern_goals(Goal)
goal_list: _intern_goals(Goal),
projs: _intern_projs(ProjectionKind)
);
// This isn't a perfect fit: CanonicalVarInfo slices are always
@ -2743,6 +2771,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
}
pub fn intern_projs(self, ps: &[ProjectionKind<'tcx>]) -> &'tcx List<ProjectionKind<'tcx>> {
if ps.len() == 0 {
List::empty()
} else {
self._intern_projs(ps)
}
}
pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'gcx> {
if ts.len() == 0 {
List::empty()

View file

@ -13,6 +13,7 @@
//! hand, though we've recently added some macros (e.g.,
//! `BraceStructLiftImpl!`) to help with the tedium.
use mir::ProjectionKind;
use mir::interpret::ConstValue;
use ty::{self, Lift, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
@ -628,6 +629,17 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind<'tcx>> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
folder.tcx().intern_projs(&v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.iter().any(|t| t.visit_with(visitor))
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
use ty::InstanceDef::*;

View file

@ -168,7 +168,9 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
let base_ty = self.fx.monomorphize(&base_ty);
// ZSTs don't require any actual memory access.
let elem_ty = base_ty.projection_ty(cx.tcx, &proj.elem).to_ty(cx.tcx);
let elem_ty = base_ty
.projection_ty(cx.tcx, &proj.elem)
.to_ty(cx.tcx);
let elem_ty = self.fx.monomorphize(&elem_ty);
if cx.layout_of(elem_ty).is_zst() {
return;

View file

@ -517,7 +517,8 @@ impl FunctionCx<'a, 'll, 'tcx> {
let mut subslice = cg_base.project_index(bx,
C_usize(bx.cx, from as u64));
let projected_ty = PlaceTy::Ty { ty: cg_base.layout.ty }
.projection_ty(tcx, &projection.elem).to_ty(bx.tcx());
.projection_ty(tcx, &projection.elem)
.to_ty(bx.tcx());
subslice.layout = bx.cx.layout_of(self.monomorphize(&projected_ty));
if subslice.layout.is_unsized() {

View file

@ -18,7 +18,7 @@ use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor;
use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
use rustc::mir::{Statement, Terminator};
use rustc::mir::UserTypeAnnotation;
use rustc::mir::UserTypeProjection;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::Substs;
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid};
@ -183,7 +183,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
&mut self,
_place: &Place<'tcx>,
_variance: &ty::Variance,
_user_ty: &UserTypeAnnotation<'tcx>,
_user_ty: &UserTypeProjection<'tcx>,
_location: Location,
) {
}

View file

@ -284,7 +284,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
if let Err(terr) = self.cx.relate_type_and_user_type(
constant.ty,
ty::Variance::Invariant,
user_ty,
&UserTypeProjection { base: user_ty, projs: vec![], },
location.to_locations(),
ConstraintCategory::Boring,
) {
@ -310,12 +310,12 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
self.super_local_decl(local, local_decl);
self.sanitize_type(local_decl, local_decl.ty);
if let Some((user_ty, span)) = local_decl.user_ty {
for (user_ty, span) in local_decl.user_ty.projections_and_spans() {
if let Err(terr) = self.cx.relate_type_and_user_type(
local_decl.ty,
ty::Variance::Invariant,
user_ty,
Locations::All(span),
Locations::All(*span),
ConstraintCategory::TypeAnnotation,
) {
span_mirbug!(
@ -971,7 +971,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
user_ty: UserTypeAnnotation<'tcx>,
user_ty: &UserTypeProjection<'tcx>,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
@ -980,7 +980,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
a, v, user_ty, locations,
);
match user_ty {
match user_ty.base {
UserTypeAnnotation::Ty(canonical_ty) => {
let (ty, _) = self.infcx
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
@ -990,6 +990,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
// ambient variance to get the right relationship.
let v1 = ty::Contravariant.xform(v);
let tcx = self.infcx.tcx;
let mut projected_ty = PlaceTy::from_ty(ty);
for proj in &user_ty.projs {
projected_ty = projected_ty.projection_ty_core(
tcx, proj, |this, field, &()| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
});
}
debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
user_ty.base, ty, user_ty.projs, projected_ty);
let ty = projected_ty.to_ty(tcx);
self.relate_types(ty, v1, a, locations, category)?;
}
UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
@ -999,11 +1013,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
) = self.infcx
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
let projs = self.infcx.tcx.intern_projs(&user_ty.projs);
self.fully_perform_op(
locations,
category,
self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
a, v, def_id, user_substs,
a, v, def_id, user_substs, projs,
)),
)?;
}
@ -1172,7 +1187,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
if let Err(terr) = self.relate_type_and_user_type(
rv_ty,
ty::Variance::Invariant,
user_ty,
&UserTypeProjection { base: user_ty, projs: vec![], },
location.to_locations(),
ConstraintCategory::Boring,
) {
@ -1225,7 +1240,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
);
};
}
StatementKind::AscribeUserType(ref place, variance, box c_ty) => {
StatementKind::AscribeUserType(ref place, variance, box ref c_ty) => {
let place_ty = place.ty(mir, tcx).to_ty(tcx);
if let Err(terr) = self.relate_type_and_user_type(
place_ty,

View file

@ -151,10 +151,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
None, remainder_span, lint_level, slice::from_ref(&pattern),
ArmHasGuard(false), None);
this.visit_bindings(&pattern, None, &mut |this, _, _, _, node, span, _, _| {
this.storage_live_binding(block, node, span, OutsideGuard);
this.schedule_drop_for_binding(node, span, OutsideGuard);
})
this.visit_bindings(
&pattern,
&PatternTypeProjections::none(),
&mut |this, _, _, _, node, span, _, _| {
this.storage_live_binding(block, node, span, OutsideGuard);
this.schedule_drop_for_binding(node, span, OutsideGuard);
})
}
// Enter the source scope, after evaluating the initializer.

View file

@ -147,7 +147,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
kind: StatementKind::AscribeUserType(
place.clone(),
Variance::Invariant,
box user_ty,
box UserTypeProjection { base: user_ty, projs: vec![], },
),
},
);
@ -167,7 +167,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
kind: StatementKind::AscribeUserType(
Place::Local(temp.clone()),
Variance::Invariant,
box user_ty,
box UserTypeProjection { base: user_ty, projs: vec![], },
),
},
);

View file

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

View file

@ -18,6 +18,7 @@ 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::hir;
use rustc::mir::*;
use rustc::ty::{self, Ty};
@ -31,6 +32,8 @@ mod simplify;
mod test;
mod util;
use std::convert::TryFrom;
/// ArmHasGuard is isomorphic to a boolean flag. It indicates whether
/// a match arm has a guard expression attached to it.
#[derive(Copy, Clone, Debug)]
@ -240,7 +243,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
end_block.unit()
}
pub fn expr_into_pattern(
pub(super) fn expr_into_pattern(
&mut self,
mut block: BasicBlock,
irrefutable_pat: Pattern<'tcx>,
@ -291,7 +294,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
},
..
},
user_ty: ascription_user_ty,
user_ty: pat_ascription_ty,
user_ty_span,
} => {
let place =
@ -316,7 +319,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
kind: StatementKind::AscribeUserType(
place,
ty::Variance::Invariant,
box ascription_user_ty,
box pat_ascription_ty.user_ty(),
),
},
);
@ -415,7 +418,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let num_patterns = patterns.len();
self.visit_bindings(
&patterns[0],
None,
&PatternTypeProjections::none(),
&mut |this, mutability, name, mode, var, span, ty, user_ty| {
if visibility_scope.is_none() {
visibility_scope =
@ -488,10 +491,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
);
}
pub fn visit_bindings(
pub(super) fn visit_bindings(
&mut self,
pattern: &Pattern<'tcx>,
mut pattern_user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
pattern_user_ty: &PatternTypeProjections<'tcx>,
f: &mut impl FnMut(
&mut Self,
Mutability,
@ -500,7 +503,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
NodeId,
Span,
Ty<'tcx>,
Option<(UserTypeAnnotation<'tcx>, Span)>,
&PatternTypeProjections<'tcx>,
),
) {
match *pattern.kind {
@ -513,20 +516,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ref subpattern,
..
} => {
match mode {
BindingMode::ByValue => { }
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`, so ignore
// `pattern_user_ty` for now.
//
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
pattern_user_ty = None;
// `T` but rather `&T`.
pattern_ref_binding = pattern_user_ty.ref_binding();
&pattern_ref_binding
}
}
};
f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty);
f(self, mutability, name, mode, var, pattern.span, ty, binding_user_ty);
if let Some(subpattern) = subpattern.as_ref() {
self.visit_bindings(subpattern, pattern_user_ty, f);
}
@ -541,33 +543,44 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ref slice,
ref suffix,
} => {
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
for subpattern in prefix.iter().chain(slice).chain(suffix) {
self.visit_bindings(subpattern, None, f);
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);
}
for subpattern in slice {
self.visit_bindings(subpattern, &pattern_user_ty.subslice(from, to), f);
}
for subpattern in suffix {
self.visit_bindings(subpattern, &pattern_user_ty.index(), f);
}
}
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
PatternKind::Deref { ref subpattern } => {
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
self.visit_bindings(subpattern, None, f);
self.visit_bindings(subpattern, &pattern_user_ty.deref(), f);
}
PatternKind::AscribeUserType { ref subpattern, user_ty, user_ty_span } => {
PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => {
// This corresponds to something like
//
// ```
// let A::<'a>(_): A<'static> = ...;
// ```
//
// FIXME(#47184): handle `pattern_user_ty` somehow
self.visit_bindings(subpattern, Some((user_ty, user_ty_span)), f)
let subpattern_user_ty = pattern_user_ty.add_user_type(user_ty, user_ty_span);
self.visit_bindings(subpattern, &subpattern_user_ty, f)
}
PatternKind::Leaf { ref subpatterns }
| PatternKind::Variant {
ref subpatterns, ..
} => {
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
PatternKind::Leaf { ref subpatterns } => {
for subpattern in subpatterns {
self.visit_bindings(&subpattern.pattern, None, f);
let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field);
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(
adt_def, variant_index, subpattern.field);
self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
}
}
}
@ -626,7 +639,7 @@ struct Binding<'tcx> {
struct Ascription<'tcx> {
span: Span,
source: Place<'tcx>,
user_ty: UserTypeAnnotation<'tcx>,
user_ty: PatternTypeProjection<'tcx>,
}
#[derive(Clone, Debug)]
@ -1323,7 +1336,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
kind: StatementKind::AscribeUserType(
ascription.source.clone(),
ty::Variance::Covariant,
box ascription.user_ty,
box ascription.user_ty.clone().user_ty(),
),
},
);
@ -1470,7 +1483,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
num_patterns: usize,
var_id: NodeId,
var_ty: Ty<'tcx>,
user_var_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
user_var_ty: &PatternTypeProjections<'tcx>,
has_guard: ArmHasGuard,
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
pat_span: Span,
@ -1489,7 +1502,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty,
user_ty: user_var_ty,
user_ty: user_var_ty.clone().user_ty(),
name: Some(name),
source_info,
visibility_scope,
@ -1522,7 +1535,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// See previous comment.
mutability: Mutability::Not,
ty: tcx.mk_imm_ref(tcx.types.re_empty, var_ty),
user_ty: None,
user_ty: UserTypeProjections::none(),
name: Some(name),
source_info,
visibility_scope,

View file

@ -63,10 +63,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
candidate: &mut Candidate<'pat, 'tcx>)
-> Result<(), MatchPair<'pat, 'tcx>> {
match *match_pair.pattern.kind {
PatternKind::AscribeUserType { ref subpattern, user_ty, user_ty_span } => {
PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => {
candidate.ascriptions.push(Ascription {
span: user_ty_span,
user_ty,
user_ty: user_ty.clone(),
source: match_pair.place.clone(),
});

View file

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

View file

@ -91,7 +91,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
ty: pattern.ty,
span: pattern.span,
kind: Box::new(PatternKind::AscribeUserType {
user_ty: UserTypeAnnotation::Ty(user_ty),
user_ty: PatternTypeProjection::from_canonical_ty(user_ty),
user_ty_span: ty.span,
subpattern: pattern
})

View file

@ -28,6 +28,7 @@ pub mod cx;
pub mod pattern;
pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
pub(crate) use self::pattern::{PatternTypeProjection, PatternTypeProjections};
mod util;

View file

@ -20,7 +20,8 @@ use const_eval::{const_field, const_variant_index};
use hair::util::UserAnnotatedTyHelpers;
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability, UserTypeAnnotation};
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::{ProjectionElem, UserTypeAnnotation, UserTypeProjection, UserTypeProjections};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty};
use rustc::ty::subst::{Substs, Kind};
@ -64,12 +65,123 @@ pub struct Pattern<'tcx> {
pub kind: Box<PatternKind<'tcx>>,
}
#[derive(Clone, Debug)]
pub(crate) struct PatternTypeProjections<'tcx> {
contents: Vec<(PatternTypeProjection<'tcx>, Span)>,
}
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(#47184): 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: usize,
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 subslice(&self, from: u32, to: u32) -> Self {
let mut new = self.clone();
new.0.projs.push(ProjectionElem::Subslice { from, to });
new
}
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: usize,
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)]
pub enum PatternKind<'tcx> {
Wild,
AscribeUserType {
user_ty: UserTypeAnnotation<'tcx>,
user_ty: PatternTypeProjection<'tcx>,
subpattern: Pattern<'tcx>,
user_ty_span: Span,
},
@ -690,9 +802,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span);
let pat_ty = PatternTypeProjection::from_user_type(user_ty);
kind = PatternKind::AscribeUserType {
subpattern,
user_ty,
user_ty: pat_ty,
user_ty_span: span,
};
}
@ -980,7 +1093,8 @@ macro_rules! CloneImpls {
CloneImpls!{ <'tcx>
Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>,
UserTypeProjection<'tcx>, PatternTypeProjection<'tcx>
}
impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
@ -1016,7 +1130,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
PatternKind::Wild => PatternKind::Wild,
PatternKind::AscribeUserType {
ref subpattern,
user_ty,
ref user_ty,
user_ty_span,
} => PatternKind::AscribeUserType {
subpattern: subpattern.fold_with(folder),

View file

@ -142,7 +142,7 @@ fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
LocalDecl {
mutability,
ty,
user_ty: None,
user_ty: UserTypeProjections::none(),
name: None,
source_info,
visibility_scope: source_info.scope,

View file

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

View file

@ -502,7 +502,7 @@ fn write_scope_tree(
local,
var.ty
);
if let Some(user_ty) = var.user_ty {
for user_ty in var.user_ty.projections() {
write!(indented_var, " as {:?}", user_ty).unwrap();
}
indented_var.push_str(";");

View file

@ -211,7 +211,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
fn visit_projection_elem(&mut self,
place: &PlaceElem<'tcx>,
context: mir_visit::PlaceContext<'tcx>,
location: Location) {
self.record("PlaceElem", place);
self.record(match *place {
@ -222,7 +221,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
ProjectionElem::ConstantIndex { .. } => "PlaceElem::ConstantIndex",
ProjectionElem::Downcast(..) => "PlaceElem::Downcast",
}, place);
self.super_projection_elem(place, context, location);
self.super_projection_elem(place, location);
}
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {

View file

@ -12,6 +12,8 @@ use rustc::infer::at::ToTrace;
use rustc::infer::canonical::{Canonical, QueryResponse};
use rustc::infer::InferCtxt;
use rustc::hir::def_id::DefId;
use rustc::mir::ProjectionKind;
use rustc::mir::tcx::PlaceTy;
use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType;
use rustc::traits::query::type_op::eq::Eq;
use rustc::traits::query::type_op::normalize::Normalize;
@ -58,14 +60,15 @@ fn type_op_ascribe_user_type<'tcx>(
variance,
def_id,
user_substs,
projs,
},
) = key.into_parts();
debug!(
"type_op_ascribe_user_type(\
mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}\
mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}, projs={:?}\
)",
mir_ty, variance, def_id, user_substs,
mir_ty, variance, def_id, user_substs, projs,
);
let mut cx = AscribeUserTypeCx {
@ -73,7 +76,7 @@ fn type_op_ascribe_user_type<'tcx>(
param_env,
fulfill_cx,
};
cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs)?;
cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs, projs)?;
Ok(())
})
@ -134,17 +137,30 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
variance: Variance,
def_id: DefId,
user_substs: UserSubsts<'tcx>,
projs: &[ProjectionKind<'tcx>],
) -> Result<(), NoSolution> {
let UserSubsts {
substs,
user_self_ty,
} = user_substs;
let ty = self.tcx().type_of(def_id);
let tcx = self.tcx();
let ty = tcx.type_of(def_id);
let ty = self.subst(ty, substs);
debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
let ty = self.normalize(ty);
let mut projected_ty = PlaceTy::from_ty(ty);
for proj in projs {
projected_ty = projected_ty.projection_ty_core(
tcx, proj, |this, field, &()| {
let ty = this.field_ty(tcx, field);
self.normalize(ty)
});
}
let ty = projected_ty.to_ty(tcx);
self.relate(mir_ty, variance, ty)?;
if let Some(UserSelfTy {

View file

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

View file

@ -0,0 +1,31 @@
// compile-pass
#![feature(nll)]
// This test is reduced from a scenario pnkfelix encountered while
// bootstrapping the compiler.
#[derive(Copy, Clone)]
pub struct Spanned<T> {
pub node: T,
pub span: Span,
}
pub type Variant = Spanned<VariantKind>;
// #[derive(Clone)] pub struct Variant { pub node: VariantKind, pub span: Span, }
#[derive(Clone)]
pub struct VariantKind { }
#[derive(Copy, Clone)]
pub struct Span;
pub fn variant_to_span(variant: Variant) {
match variant {
Variant {
span: _span,
..
} => { }
};
}
fn main() { }

View file

@ -9,11 +9,11 @@ fn variable_no_initializer() {
}
fn tuple_no_initializer() {
// FIXME(#47187): We are not propagating ascribed type through tuples.
let x = 22;
let (y, z): (&'static u32, &'static u32);
y = &x;
y = &x; //~ ERROR
}
fn ref_with_ascribed_static_type() -> u32 {
@ -34,11 +34,23 @@ fn ref_with_ascribed_any_type() -> u32 {
struct Single<T> { value: T }
fn struct_no_initializer() {
// FIXME(#47187): We are not propagating ascribed type through patterns.
let x = 22;
let Single { value: y }: Single<&'static u32>;
y = &x;
y = &x; //~ ERROR
}
fn struct_no_initializer_must_normalize() {
trait Indirect { type Assoc; }
struct StaticU32;
impl Indirect for StaticU32 { type Assoc = &'static u32; }
struct Single2<T: Indirect> { value: <T as Indirect>::Assoc }
let x = 22;
let Single2 { value: mut _y }: Single2<StaticU32>;
_y = &x; //~ ERROR
}
fn variable_with_initializer() {
@ -91,26 +103,31 @@ fn struct_double_field_underscore_with_initializer() {
}
fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
// The error in this test is inconsistency with
// `static_to_a_to_static_through_tuple`, but "feels right" to
// me. It occurs because we special case the single binding case
// and force the type of `y` to be `&'a u32`, even though the
// right-hand side has type `&'static u32`.
let y: &'a u32 = &22;
y //~ ERROR
}
fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 {
// FIXME(#47187): The fact that this type-checks is perhaps surprising.
// What happens is that the right-hand side is constrained to have
// type `&'a u32`, which is possible, because it has type
// `&'static u32`. The variable `y` is then forced to have type
// `&'static u32`, but it is constrained only by the right-hand
// side, not the ascribed type, and hence it passes.
let (y, _z): (&'a u32, u32) = (&22, 44);
y
y //~ ERROR
}
fn static_to_a_to_static_through_struct<'a>(_x: &'a u32) -> &'static u32 {
let Single { value: y }: Single<&'a u32> = Single { value: &22 };
y //~ ERROR
}
fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 {

View file

@ -8,6 +8,16 @@ LL | y = &x; //~ ERROR
LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:16:9
|
LL | let (y, z): (&'static u32, &'static u32);
| ---------------------------- type annotation requires that `x` is borrowed for `'static`
LL | y = &x; //~ ERROR
| ^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:22:13
|
@ -20,7 +30,27 @@ LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:46:27
--> $DIR/patterns.rs:41:9
|
LL | let Single { value: y }: Single<&'static u32>;
| -------------------- type annotation requires that `x` is borrowed for `'static`
LL | y = &x; //~ ERROR
| ^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:53:10
|
LL | let Single2 { value: mut _y }: Single2<StaticU32>;
| ------------------ type annotation requires that `x` is borrowed for `'static`
LL | _y = &x; //~ ERROR
| ^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:58:27
|
LL | let y: &'static u32 = &x; //~ ERROR
| ------------ ^^ borrowed value does not live long enough
@ -30,7 +60,7 @@ LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:51:27
--> $DIR/patterns.rs:63:27
|
LL | let _: &'static u32 = &x; //~ ERROR
| ------------ ^^ borrowed value does not live long enough
@ -41,7 +71,7 @@ LL | }
| - `x` dropped here while still borrowed
error[E0716]: temporary value dropped while borrowed
--> $DIR/patterns.rs:53:41
--> $DIR/patterns.rs:65:41
|
LL | let _: Vec<&'static String> = vec![&String::new()];
| -------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
@ -50,7 +80,7 @@ LL | let _: Vec<&'static String> = vec![&String::new()];
| type annotation requires that borrow lasts for `'static`
error[E0716]: temporary value dropped while borrowed
--> $DIR/patterns.rs:56:52
--> $DIR/patterns.rs:68:52
|
LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
| ------------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
@ -59,7 +89,7 @@ LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
| type annotation requires that borrow lasts for `'static`
error[E0716]: temporary value dropped while borrowed
--> $DIR/patterns.rs:59:53
--> $DIR/patterns.rs:71:53
|
LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
| ------------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
@ -68,7 +98,7 @@ LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
| type annotation requires that borrow lasts for `'static`
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:65:40
--> $DIR/patterns.rs:77:40
|
LL | let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR
| ------------------- ^^ borrowed value does not live long enough
@ -78,7 +108,7 @@ LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:70:40
--> $DIR/patterns.rs:82:40
|
LL | let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR
| ------------------- ^^ borrowed value does not live long enough
@ -88,7 +118,7 @@ LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:75:69
--> $DIR/patterns.rs:87:69
|
LL | let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR
| -------------------- ^^ borrowed value does not live long enough
@ -98,7 +128,7 @@ LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:80:69
--> $DIR/patterns.rs:92:69
|
LL | let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR
| -------------------- ^^ borrowed value does not live long enough
@ -108,7 +138,7 @@ LL | }
| - `x` dropped here while still borrowed
error[E0597]: `x` does not live long enough
--> $DIR/patterns.rs:88:17
--> $DIR/patterns.rs:100:17
|
LL | let Double { value1: _, value2: _ }: Double<&'static u32> = Double {
| -------------------- type annotation requires that `x` is borrowed for `'static`
@ -119,7 +149,7 @@ LL | }
| - `x` dropped here while still borrowed
error: unsatisfied lifetime constraints
--> $DIR/patterns.rs:101:5
--> $DIR/patterns.rs:113:5
|
LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
@ -128,14 +158,32 @@ LL | y //~ ERROR
| ^ returning this value requires that `'a` must outlive `'static`
error: unsatisfied lifetime constraints
--> $DIR/patterns.rs:117:18
--> $DIR/patterns.rs:125:5
|
LL | fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
...
LL | y //~ ERROR
| ^ returning this value requires that `'a` must outlive `'static`
error: unsatisfied lifetime constraints
--> $DIR/patterns.rs:130:5
|
LL | fn static_to_a_to_static_through_struct<'a>(_x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
LL | let Single { value: y }: Single<&'a u32> = Single { value: &22 };
LL | y //~ ERROR
| ^ returning this value requires that `'a` must outlive `'static`
error: unsatisfied lifetime constraints
--> $DIR/patterns.rs:134:18
|
LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
LL | let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR
| ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
error: aborting due to 14 previous errors
error: aborting due to 19 previous errors
Some errors occurred: E0597, E0716.
For more information about an error, try `rustc --explain E0597`.