Support user type annotations in ref bindings.

This commit adds support for user type annotations in variables declared
using `ref` bindings. When a variable declared using a `ref` binding,
then the `LocalDecl` has the type `&T` where the `&` was introduced by
the `ref` binding but the canonicalized type annotation has only a
`T` since the reference is implicit with the `ref` binding.

Therefore, to support type annotations, the canonicalized type
annotation either needs wrapped in a reference, or the `LocalDecl` type
must have a wrapped reference removed for comparison. It is easier to
remove the outer reference from the `LocalDecl` for the purpose of
comparison, so that is the approach this commit takes.
This commit is contained in:
David Wood 2018-11-25 15:14:39 +01:00
parent 162dcdc16f
commit dc41606ff4
No known key found for this signature in database
GPG key ID: 01760B4F9F53F154
7 changed files with 40 additions and 20 deletions

View file

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

View file

@ -141,6 +141,7 @@ 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(),

View file

@ -409,6 +409,7 @@ 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(),
@ -499,6 +500,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
&PatternTypeProjections<'tcx>,
),
) {
debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty);
match *pattern.kind {
PatternKind::Binding {
mutability,
@ -509,19 +511,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);
if let Some(subpattern) = subpattern.as_ref() {
self.visit_bindings(subpattern, pattern_user_ty, f);
}
@ -565,6 +555,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
PatternKind::Leaf { ref subpatterns } => {
for subpattern in subpatterns {
let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field);
debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
}
}

View file

@ -79,11 +79,6 @@ impl<'tcx> PatternTypeProjections<'tcx> {
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
@ -803,7 +798,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
};
if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
debug!("lower_variant_or_leaf: user_ty={:?} span={:?}", user_ty, span);
debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
kind = PatternKind::AscribeUserType {
subpattern: Pattern {
span,

View file

@ -2388,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
@ -2398,6 +2399,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// already sufficiently enforced with erased regions. =)
if ty.has_free_regions() || ty.has_projections() {
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);
}

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