Skip to content

Commit e87bf30

Browse files
committed
propagate user-ascribes types down onto resulting bindings
But only in very simple cases.
1 parent a871053 commit e87bf30

File tree

14 files changed

+171
-35
lines changed

14 files changed

+171
-35
lines changed

src/librustc/ich/impls_mir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
2424
impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
2525
mutability,
2626
ty,
27+
user_ty,
2728
name,
2829
source_info,
2930
visibility_scope,

src/librustc/mir/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,12 @@ pub struct LocalDecl<'tcx> {
640640
/// Type of this local.
641641
pub ty: Ty<'tcx>,
642642

643+
/// If the user manually ascribed a type to this variable,
644+
/// e.g. via `let x: T`, then we carry that type here. The MIR
645+
/// borrow checker needs this information since it can affect
646+
/// region inference.
647+
pub user_ty: Option<CanonicalTy<'tcx>>,
648+
643649
/// Name of the local, used in debuginfo and pretty-printing.
644650
///
645651
/// Note that function arguments can also have this set to `Some(_)`
@@ -802,6 +808,7 @@ impl<'tcx> LocalDecl<'tcx> {
802808
LocalDecl {
803809
mutability,
804810
ty,
811+
user_ty: None,
805812
name: None,
806813
source_info: SourceInfo {
807814
span,
@@ -821,6 +828,7 @@ impl<'tcx> LocalDecl<'tcx> {
821828
LocalDecl {
822829
mutability: Mutability::Mut,
823830
ty: return_ty,
831+
user_ty: None,
824832
source_info: SourceInfo {
825833
span,
826834
scope: OUTERMOST_SOURCE_SCOPE,
@@ -2613,6 +2621,7 @@ BraceStructTypeFoldableImpl! {
26132621
is_user_variable,
26142622
internal,
26152623
ty,
2624+
user_ty,
26162625
name,
26172626
source_info,
26182627
visibility_scope,

src/librustc/mir/visit.rs

+4
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,7 @@ macro_rules! make_mir_visitor {
721721
let LocalDecl {
722722
mutability: _,
723723
ref $($mutability)* ty,
724+
ref $($mutability)* user_ty,
724725
name: _,
725726
ref $($mutability)* source_info,
726727
ref $($mutability)* visibility_scope,
@@ -732,6 +733,9 @@ macro_rules! make_mir_visitor {
732733
local,
733734
source_info: *source_info,
734735
});
736+
if let Some(user_ty) = user_ty {
737+
self.visit_canonical_ty(user_ty);
738+
}
735739
self.visit_source_info(source_info);
736740
self.visit_source_scope(visibility_scope);
737741
}

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

+19
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,25 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
275275
fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
276276
self.super_local_decl(local, local_decl);
277277
self.sanitize_type(local_decl, local_decl.ty);
278+
279+
if let Some(user_ty) = local_decl.user_ty {
280+
if let Err(terr) = self.cx.relate_type_and_user_type(
281+
local_decl.ty,
282+
ty::Variance::Invariant,
283+
user_ty,
284+
Locations::All,
285+
) {
286+
span_mirbug!(
287+
self,
288+
local,
289+
"bad user type on variable {:?}: {:?} != {:?} ({:?})",
290+
local,
291+
local_decl.ty,
292+
local_decl.user_ty,
293+
terr,
294+
);
295+
}
296+
}
278297
}
279298

280299
fn visit_mir(&mut self, mir: &Mir<'tcx>) {

src/librustc_mir/build/block.rs

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

146-
this.visit_bindings(&pattern, &mut |this, _, _, _, node, span, _| {
146+
this.visit_bindings(&pattern, None, &mut |this, _, _, _, node, span, _, _| {
147147
this.storage_live_binding(block, node, span, OutsideGuard);
148148
this.schedule_drop_for_binding(node, span, OutsideGuard);
149149
})

src/librustc_mir/build/expr/into.rs

+1
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
296296
let ptr_temp = this.local_decls.push(LocalDecl {
297297
mutability: Mutability::Mut,
298298
ty: ptr_ty,
299+
user_ty: None,
299300
name: None,
300301
source_info,
301302
visibility_scope: source_info.scope,

src/librustc_mir/build/matches/mod.rs

+42-13
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
399399
let num_patterns = patterns.len();
400400
self.visit_bindings(
401401
&patterns[0],
402-
&mut |this, mutability, name, mode, var, span, ty| {
402+
None,
403+
&mut |this, mutability, name, mode, var, span, ty, user_ty| {
403404
if visibility_scope.is_none() {
404405
visibility_scope =
405406
Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
@@ -421,6 +422,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
421422
num_patterns,
422423
var,
423424
ty,
425+
user_ty,
424426
has_guard,
425427
opt_match_place.map(|(x, y)| (x.cloned(), y)),
426428
patterns[0].span,
@@ -470,10 +472,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
470472
);
471473
}
472474

473-
pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, f: &mut F)
474-
where
475-
F: FnMut(&mut Self, Mutability, Name, BindingMode, NodeId, Span, Ty<'tcx>),
476-
{
475+
pub fn visit_bindings(
476+
&mut self,
477+
pattern: &Pattern<'tcx>,
478+
pattern_user_ty: Option<CanonicalTy<'tcx>>,
479+
f: &mut impl FnMut(
480+
&mut Self,
481+
Mutability,
482+
Name,
483+
BindingMode,
484+
NodeId,
485+
Span,
486+
Ty<'tcx>,
487+
Option<CanonicalTy<'tcx>>,
488+
),
489+
) {
477490
match *pattern.kind {
478491
PatternKind::Binding {
479492
mutability,
@@ -484,9 +497,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
484497
ref subpattern,
485498
..
486499
} => {
487-
f(self, mutability, name, mode, var, pattern.span, ty);
500+
f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty);
488501
if let Some(subpattern) = subpattern.as_ref() {
489-
self.visit_bindings(subpattern, f);
502+
self.visit_bindings(subpattern, pattern_user_ty, f);
490503
}
491504
}
492505
PatternKind::Array {
@@ -499,21 +512,34 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
499512
ref slice,
500513
ref suffix,
501514
} => {
515+
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
502516
for subpattern in prefix.iter().chain(slice).chain(suffix) {
503-
self.visit_bindings(subpattern, f);
517+
self.visit_bindings(subpattern, None, f);
504518
}
505519
}
506520
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
507-
PatternKind::AscribeUserType { ref subpattern, .. }
508-
| PatternKind::Deref { ref subpattern } => {
509-
self.visit_bindings(subpattern, f);
521+
PatternKind::Deref { ref subpattern } => {
522+
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
523+
self.visit_bindings(subpattern, None, f);
524+
}
525+
PatternKind::AscribeUserType { ref subpattern, user_ty } => {
526+
// This corresponds to something like
527+
//
528+
// ```
529+
// let (p1: T1): T2 = ...;
530+
// ```
531+
//
532+
// Not presently possible, though maybe someday.
533+
assert!(pattern_user_ty.is_none());
534+
self.visit_bindings(subpattern, Some(user_ty), f)
510535
}
511536
PatternKind::Leaf { ref subpatterns }
512537
| PatternKind::Variant {
513538
ref subpatterns, ..
514539
} => {
540+
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
515541
for subpattern in subpatterns {
516-
self.visit_bindings(&subpattern.pattern, f);
542+
self.visit_bindings(&subpattern.pattern, None, f);
517543
}
518544
}
519545
}
@@ -1375,6 +1401,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
13751401
num_patterns: usize,
13761402
var_id: NodeId,
13771403
var_ty: Ty<'tcx>,
1404+
user_var_ty: Option<CanonicalTy<'tcx>>,
13781405
has_guard: ArmHasGuard,
13791406
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
13801407
pat_span: Span,
@@ -1392,7 +1419,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
13921419
};
13931420
let local = LocalDecl::<'tcx> {
13941421
mutability,
1395-
ty: var_ty.clone(),
1422+
ty: var_ty,
1423+
user_ty: user_var_ty,
13961424
name: Some(name),
13971425
source_info,
13981426
visibility_scope,
@@ -1424,6 +1452,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
14241452
// See previous comment.
14251453
mutability: Mutability::Not,
14261454
ty: tcx.mk_imm_ref(tcx.types.re_empty, var_ty),
1455+
user_ty: None,
14271456
name: Some(name),
14281457
source_info,
14291458
visibility_scope,

src/librustc_mir/build/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
730730
self.local_decls.push(LocalDecl {
731731
mutability: Mutability::Mut,
732732
ty,
733+
user_ty: None,
733734
source_info,
734735
visibility_scope: source_info.scope,
735736
name,

src/librustc_mir/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
3939
#![feature(if_while_or_patterns)]
4040
#![feature(try_from)]
4141
#![feature(reverse_bits)]
42+
#![feature(underscore_imports)]
4243

4344
#![recursion_limit="256"]
4445

src/librustc_mir/shim.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ enum CallKind {
140140
fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
141141
let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span };
142142
LocalDecl {
143-
mutability, ty, name: None,
143+
mutability, ty,
144+
user_ty: None,
145+
name: None,
144146
source_info,
145147
visibility_scope: source_info.scope,
146148
internal: false,

src/librustc_mir/transform/generator.rs

+3
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ fn replace_result_variable<'tcx>(
303303
let new_ret = LocalDecl {
304304
mutability: Mutability::Mut,
305305
ty: ret_ty,
306+
user_ty: None,
306307
name: None,
307308
source_info,
308309
visibility_scope: source_info.scope,
@@ -656,6 +657,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
656657
mir.local_decls[RETURN_PLACE] = LocalDecl {
657658
mutability: Mutability::Mut,
658659
ty: tcx.mk_nil(),
660+
user_ty: None,
659661
name: None,
660662
source_info,
661663
visibility_scope: source_info.scope,
@@ -672,6 +674,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
672674
ty: gen_ty,
673675
mutbl: hir::Mutability::MutMutable,
674676
}),
677+
user_ty: None,
675678
name: None,
676679
source_info,
677680
visibility_scope: source_info.scope,

src/librustc_mir/util/pretty.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rustc::ty::item_path;
1717
use rustc_data_structures::fx::FxHashMap;
1818
use rustc_data_structures::indexed_vec::Idx;
1919
use std::fmt::Display;
20+
use std::fmt::Write as _;
2021
use std::fs;
2122
use std::io::{self, Write};
2223
use std::path::{Path, PathBuf};
@@ -493,14 +494,18 @@ fn write_scope_tree(
493494
};
494495

495496
let indent = indent + INDENT.len();
496-
let indented_var = format!(
497-
"{0:1$}let {2}{3:?}: {4:?};",
497+
let mut indented_var = format!(
498+
"{0:1$}let {2}{3:?}: {4:?}",
498499
INDENT,
499500
indent,
500501
mut_str,
501502
local,
502503
var.ty
503504
);
505+
if let Some(user_ty) = var.user_ty {
506+
write!(indented_var, " as {:?}", user_ty).unwrap();
507+
}
508+
indented_var.push_str(";");
504509
writeln!(
505510
w,
506511
"{0:1$} // \"{2}\" in {3}",

src/test/ui/nll/user-annotations/patterns.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,41 @@
33
#![feature(nll)]
44

55
fn variable_no_initializer() {
6-
// FIXME: It is unclear to me whether this should be an error or not.
7-
86
let x = 22;
97
let y: &'static u32;
8+
y = &x; //~ ERROR
9+
}
10+
11+
fn tuple_no_initializer() {
12+
// FIXME(#47187): We are not propagating ascribed type through tuples.
13+
14+
let x = 22;
15+
let (y, z): (&'static u32, &'static u32);
16+
y = &x;
17+
}
18+
19+
fn ref_with_ascribed_static_type() -> u32 {
20+
// Check the behavior in some wacky cases.
21+
let x = 22;
22+
let y = &x; //~ ERROR
23+
let ref z: &'static u32 = y; //~ ERROR
24+
**z
25+
}
26+
27+
fn ref_with_ascribed_any_type() -> u32 {
28+
let x = 22;
29+
let y = &x;
30+
let ref z: &u32 = y;
31+
**z
32+
}
33+
34+
struct Single<T> { value: T }
35+
36+
fn struct_no_initializer() {
37+
// FIXME(#47187): We are not propagating ascribed type through patterns.
38+
39+
let x = 22;
40+
let Single { value: y }: Single<&'static u32>;
1041
y = &x;
1142
}
1243

@@ -39,8 +70,6 @@ fn pair_variable_with_initializer() {
3970
let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR
4071
}
4172

42-
struct Single<T> { value: T }
43-
4473
fn struct_single_field_variable_with_initializer() {
4574
let x = 22;
4675
let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR
@@ -73,7 +102,7 @@ fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
73102
}
74103

75104
fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 {
76-
// FIXME: The fact that this type-checks is perhaps surprising.
105+
// FIXME(#47187): The fact that this type-checks is perhaps surprising.
77106
// What happens is that the right-hand side is constrained to have
78107
// type `&'a u32`, which is possible, because it has type
79108
// `&'static u32`. The variable `y` is then forced to have type

0 commit comments

Comments
 (0)