Skip to content

Commit dc41606

Browse files
committed
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.
1 parent 162dcdc commit dc41606

File tree

7 files changed

+40
-20
lines changed

7 files changed

+40
-20
lines changed

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
307307
self.sanitize_type(local_decl, local_decl.ty);
308308

309309
for (user_ty, span) in local_decl.user_ty.projections_and_spans() {
310+
let ty = if !local_decl.is_nonref_binding() {
311+
// If we have a binding of the form `let ref x: T = ..` then remove the outermost
312+
// reference so we can check the type annotation for the remaining type.
313+
if let ty::Ref(_, rty, _) = local_decl.ty.sty {
314+
rty
315+
} else {
316+
bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty);
317+
}
318+
} else {
319+
local_decl.ty
320+
};
321+
310322
if let Err(terr) = self.cx.relate_type_and_user_type(
311-
local_decl.ty,
323+
ty,
312324
ty::Variance::Invariant,
313325
user_ty,
314326
Locations::All(*span),

src/librustc_mir/build/block.rs

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
141141
None, remainder_span, lint_level, slice::from_ref(&pattern),
142142
ArmHasGuard(false), None);
143143

144+
debug!("ast_block_stmts: pattern={:?}", pattern);
144145
this.visit_bindings(
145146
&pattern,
146147
&PatternTypeProjections::none(),

src/librustc_mir/build/matches/mod.rs

+4-13
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
409409
);
410410
let mut scope = self.source_scope;
411411
let num_patterns = patterns.len();
412+
debug!("declare_bindings: patterns={:?}", patterns);
412413
self.visit_bindings(
413414
&patterns[0],
414415
&PatternTypeProjections::none(),
@@ -499,6 +500,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
499500
&PatternTypeProjections<'tcx>,
500501
),
501502
) {
503+
debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty);
502504
match *pattern.kind {
503505
PatternKind::Binding {
504506
mutability,
@@ -509,19 +511,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
509511
ref subpattern,
510512
..
511513
} => {
512-
let pattern_ref_binding; // sidestep temp lifetime limitations.
513-
let binding_user_ty = match mode {
514-
BindingMode::ByValue => { pattern_user_ty }
515-
BindingMode::ByRef(..) => {
516-
// If this is a `ref` binding (e.g., `let ref
517-
// x: T = ..`), then the type of `x` is not
518-
// `T` but rather `&T`.
519-
pattern_ref_binding = pattern_user_ty.ref_binding();
520-
&pattern_ref_binding
521-
}
522-
};
523-
524-
f(self, mutability, name, mode, var, pattern.span, ty, binding_user_ty);
514+
f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty);
525515
if let Some(subpattern) = subpattern.as_ref() {
526516
self.visit_bindings(subpattern, pattern_user_ty, f);
527517
}
@@ -565,6 +555,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
565555
PatternKind::Leaf { ref subpatterns } => {
566556
for subpattern in subpatterns {
567557
let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field);
558+
debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
568559
self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
569560
}
570561
}

src/librustc_mir/hair/pattern/mod.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,6 @@ impl<'tcx> PatternTypeProjections<'tcx> {
7979
PatternTypeProjections { contents: vec![] }
8080
}
8181

82-
pub(crate) fn ref_binding(&self) -> Self {
83-
// FIXME(#55401): ignore for now
84-
PatternTypeProjections { contents: vec![] }
85-
}
86-
8782
fn map_projs(&self,
8883
mut f: impl FnMut(&PatternTypeProjection<'tcx>) -> PatternTypeProjection<'tcx>)
8984
-> Self
@@ -803,7 +798,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
803798
};
804799

805800
if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
806-
debug!("lower_variant_or_leaf: user_ty={:?} span={:?}", user_ty, span);
801+
debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
807802
kind = PatternKind::AscribeUserType {
808803
subpattern: Pattern {
809804
span,

src/librustc_typeck/check/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2388,6 +2388,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
23882388

23892389
pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
23902390
let ty = self.to_ty(ast_ty);
2391+
debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
23912392

23922393
// If the type given by the user has free regions, save it for
23932394
// later, since NLL would like to enforce those. Also pass in
@@ -2398,6 +2399,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
23982399
// already sufficiently enforced with erased regions. =)
23992400
if ty.has_free_regions() || ty.has_projections() {
24002401
let c_ty = self.infcx.canonicalize_response(&UserTypeAnnotation::Ty(ty));
2402+
debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
24012403
self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
24022404
}
24032405

src/test/ui/nll/issue-55401.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(nll)]
2+
3+
fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
4+
let (ref y, _z): (&'a u32, u32) = (&22, 44);
5+
*y //~ ERROR
6+
}
7+
8+
fn main() {}

src/test/ui/nll/issue-55401.stderr

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

0 commit comments

Comments
 (0)