Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,7 @@ impl_stable_hash_for!(

impl_stable_hash_for!(
struct ty::CanonicalUserTypeAnnotation<'tcx> {
user_ty, span
user_ty, span, inferred_ty
}
);

Expand Down
13 changes: 6 additions & 7 deletions src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,20 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
elem: &PlaceElem<'tcx>)
-> PlaceTy<'tcx>
{
self.projection_ty_core(tcx, elem, |_, _, ty| -> Result<Ty<'tcx>, ()> { Ok(ty) })
.unwrap()
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, E>(
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) -> Result<Ty<'tcx>, E>)
-> Result<PlaceTy<'tcx>, E>
mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>)
-> PlaceTy<'tcx>
where
V: ::std::fmt::Debug, T: ::std::fmt::Debug
{
Expand Down Expand Up @@ -140,10 +139,10 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
}
},
ProjectionElem::Field(ref f, ref fty) =>
PlaceTy::Ty { ty: handle_field(&self, f, fty)? },
PlaceTy::Ty { ty: handle_field(&self, f, fty) },
};
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
Ok(answer)
answer
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,7 @@ macro_rules! make_mir_visitor {
ty: & $($mutability)* CanonicalUserTypeAnnotation<'tcx>,
) {
self.visit_span(& $($mutability)* ty.span);
self.visit_ty(& $($mutability)* ty.inferred_ty, TyContext::UserTy(ty.span));
}

fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
Expand Down Expand Up @@ -967,6 +968,9 @@ pub enum TyContext {
source_info: SourceInfo,
},

/// The inferred type of a user type annotation.
UserTy(Span),

/// The return type of the function.
ReturnTy(SourceInfo),

Expand Down
15 changes: 5 additions & 10 deletions src/librustc/traits/query/type_op/ascribe_user_type.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
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::{ParamEnvAnd, Ty, TyCtxt};
use ty::subst::UserSubsts;

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct AscribeUserType<'tcx> {
pub mir_ty: Ty<'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> {
pub fn new(
mir_ty: Ty<'tcx>,
variance: ty::Variance,
def_id: DefId,
user_substs: UserSubsts<'tcx>,
projs: &'tcx ty::List<ProjectionKind<'tcx>>,
) -> Self {
Self { mir_ty, variance, def_id, user_substs, projs }
Self { mir_ty, def_id, user_substs }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm interesting that you have found a way to get rid of carrying the projections around as part of the AscribeUserType.

}
}

Expand Down Expand Up @@ -52,19 +47,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, projs
mir_ty, def_id, user_substs
}
}

BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> {
type Lifted = AscribeUserType<'tcx>;
mir_ty, variance, def_id, user_substs, projs
mir_ty, def_id, user_substs
}
}

impl_stable_hash_for! {
struct AscribeUserType<'tcx> {
mir_ty, variance, def_id, user_substs, projs
mir_ty, def_id, user_substs
}
}
5 changes: 3 additions & 2 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,18 +813,19 @@ pub type CanonicalUserTypeAnnotations<'tcx> =
pub struct CanonicalUserTypeAnnotation<'tcx> {
pub user_ty: CanonicalUserType<'tcx>,
pub span: Span,
pub inferred_ty: Ty<'tcx>,
}

BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for CanonicalUserTypeAnnotation<'tcx> {
user_ty, span
user_ty, span, inferred_ty
}
}

BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for CanonicalUserTypeAnnotation<'a> {
type Lifted = CanonicalUserTypeAnnotation<'tcx>;
user_ty, span
user_ty, span, inferred_ty
}
}

Expand Down
11 changes: 6 additions & 5 deletions src/librustc_mir/borrow_check/nll/constraint_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc::infer::InferCtxt;
use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor;
use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
use rustc::mir::{Statement, Terminator};
use rustc::mir::{SourceInfo, Statement, Terminator};
use rustc::mir::UserTypeProjection;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::Substs;
Expand Down Expand Up @@ -66,11 +66,12 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
/// call. Make them live at the location where they appear.
fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) {
match ty_context {
TyContext::ReturnTy(source_info)
| TyContext::YieldTy(source_info)
| TyContext::LocalDecl { source_info, .. } => {
TyContext::ReturnTy(SourceInfo { span, .. })
| TyContext::YieldTy(SourceInfo { span, .. })
| TyContext::UserTy(span)
| TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
span_bug!(
source_info.span,
span,
"should not be visiting outside of the CFG: {:?}",
ty_context
);
Expand Down
17 changes: 1 addition & 16 deletions src/librustc_mir/borrow_check/nll/renumber.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use rustc::ty::subst::Substs;
use rustc::ty::{
self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable,
UserTypeAnnotationIndex, CanonicalUserTypeAnnotation
};
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
use rustc::mir::{Location, Mir};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
Expand Down Expand Up @@ -58,18 +55,6 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
debug!("visit_ty: ty={:?}", ty);
}

fn visit_user_type_annotation(
&mut self,
_index: UserTypeAnnotationIndex,
_ty: &mut CanonicalUserTypeAnnotation,
) {
// 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
// constraints at type-check time.
debug!("visit_user_type_annotation: skipping renumber");
}

fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
debug!("visit_substs(substs={:?}, location={:?})", substs, location);

Expand Down
118 changes: 62 additions & 56 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
/// 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, UserType<'tcx>>,
instantiated_type_annotations: FxHashMap<UserTypeAnnotationIndex, Ty<'tcx>>,
}

struct BorrowCheckContext<'a, 'tcx: 'a> {
Expand Down Expand Up @@ -920,17 +920,58 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
self.mir.user_type_annotations
);
for annotation_index in self.mir.user_type_annotations.indices() {
let CanonicalUserTypeAnnotation { span, ref user_ty } =
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } =
self.mir.user_type_annotations[annotation_index];
let (mut annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
let (annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
span, user_ty
);
match annotation {
UserType::Ty(ref mut ty) =>
*ty = self.normalize(ty, Locations::All(span)),
_ => {},
UserType::Ty(mut ty) => {
ty = self.normalize(ty, Locations::All(span));

if let Err(terr) = self.eq_types(
ty,
inferred_ty,
Locations::All(span),
ConstraintCategory::BoringNoLocation,
) {
span_mirbug!(
self,
self.mir.user_type_annotations[annotation_index],
"bad user type ({:?} = {:?}): {:?}",
ty,
inferred_ty,
terr
);
}

self.prove_predicate(
ty::Predicate::WellFormed(inferred_ty),
Locations::All(span),
ConstraintCategory::TypeAnnotation,
);
},
UserType::TypeOf(def_id, user_substs) => {
if let Err(terr) = self.fully_perform_op(
Locations::All(span),
ConstraintCategory::BoringNoLocation,
self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
inferred_ty, def_id, user_substs,
)),
) {
span_mirbug!(
self,
self.mir.user_type_annotations[annotation_index],
"bad user type AscribeUserType({:?}, {:?} {:?}): {:?}",
inferred_ty,
def_id,
user_substs,
terr
);
}
},
}
self.instantiated_type_annotations.insert(annotation_index, annotation);
self.instantiated_type_annotations.insert(annotation_index, inferred_ty);
}
debug!(
"instantiate_user_type_annotations: instantiated_type_annotations={:?}",
Expand Down Expand Up @@ -1067,58 +1108,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
a, v, user_ty, locations,
);

let type_annotation = self.instantiated_type_annotations[&user_ty.base];
match type_annotation {
UserType::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 annotated_type = self.instantiated_type_annotations[&user_ty.base];
let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);

// We need to follow any provided projetions into the type.
//
// if we hit a ty var as we descend, then just skip the
// attempt to relate the mir local with any type.
#[derive(Debug)] struct HitTyVar;
let mut curr_projected_ty: Result<PlaceTy, HitTyVar>;

curr_projected_ty = Ok(PlaceTy::from_ty(ty));
for proj in &user_ty.projs {
let projected_ty = if let Ok(projected_ty) = curr_projected_ty {
projected_ty
} else {
break;
};
curr_projected_ty = projected_ty.projection_ty_core(
tcx, proj, |this, field, &()| {
if this.to_ty(tcx).is_ty_var() {
Err(HitTyVar)
} else {
let ty = this.field_ty(tcx, field);
Ok(self.normalize(ty, locations))
}
});
}
debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
user_ty.base, ty, user_ty.projs, curr_projected_ty);
let tcx = self.infcx.tcx;

if let Ok(projected_ty) = curr_projected_ty {
let ty = projected_ty.to_ty(tcx);
self.relate_types(ty, v1, a, locations, category)?;
}
}
UserType::TypeOf(def_id, user_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, projs,
)),
)?;
}
for proj in &user_ty.projs {
let projected_ty = curr_projected_ty.projection_ty_core(tcx, proj, |this, field, &()| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
});
curr_projected_ty = projected_ty;
}
debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
user_ty.base, annotated_type, user_ty.projs, curr_projected_ty);

let ty = curr_projected_ty.to_ty(tcx);
self.relate_types(a, v, ty, locations, category)?;

Ok(())
}
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_mir/build/expr/as_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
value,
} => this.as_constant(value),
ExprKind::Literal { literal, user_ty } => {
let user_ty = user_ty.map(|ty| {
let user_ty = user_ty.map(|user_ty| {
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span,
user_ty: ty,
user_ty,
inferred_ty: ty,
})
});
Constant {
Expand Down
12 changes: 10 additions & 2 deletions src/librustc_mir/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
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(
CanonicalUserTypeAnnotation { span: source_info.span, user_ty }
CanonicalUserTypeAnnotation {
span: source_info.span,
user_ty,
inferred_ty: expr.ty,
}
);
this.cfg.push(
block,
Expand All @@ -157,7 +161,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
);
if let Some(user_ty) = user_ty {
let annotation_index = this.canonical_user_type_annotations.push(
CanonicalUserTypeAnnotation { span: source_info.span, user_ty }
CanonicalUserTypeAnnotation {
span: source_info.span,
user_ty,
inferred_ty: expr.ty,
}
);
this.cfg.push(
block,
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
.collect()
};

let inferred_ty = expr.ty;
let user_ty = user_ty.map(|ty| {
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span: source_info.span,
user_ty: ty,
inferred_ty,
})
});
let adt = box AggregateKind::Adt(
Expand Down
Loading