But only in very simple cases.
impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
mutability,
ty,
+ user_ty,
name,
source_info,
visibility_scope,
/// Type of this local.
pub ty: Ty<'tcx>,
+ /// If the user manually ascribed a type to this variable,
+ /// 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<CanonicalTy<'tcx>>,
+
/// Name of the local, used in debuginfo and pretty-printing.
///
/// Note that function arguments can also have this set to `Some(_)`
LocalDecl {
mutability,
ty,
+ user_ty: None,
name: None,
source_info: SourceInfo {
span,
LocalDecl {
mutability: Mutability::Mut,
ty: return_ty,
+ user_ty: None,
source_info: SourceInfo {
span,
scope: OUTERMOST_SOURCE_SCOPE,
is_user_variable,
internal,
ty,
+ user_ty,
name,
source_info,
visibility_scope,
let LocalDecl {
mutability: _,
ref $($mutability)* ty,
+ ref $($mutability)* user_ty,
name: _,
ref $($mutability)* source_info,
ref $($mutability)* visibility_scope,
local,
source_info: *source_info,
});
+ if let Some(user_ty) = user_ty {
+ self.visit_canonical_ty(user_ty);
+ }
self.visit_source_info(source_info);
self.visit_source_scope(visibility_scope);
}
fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
self.super_local_decl(local, local_decl);
self.sanitize_type(local_decl, local_decl.ty);
+
+ if let Some(user_ty) = local_decl.user_ty {
+ if let Err(terr) = self.cx.relate_type_and_user_type(
+ local_decl.ty,
+ ty::Variance::Invariant,
+ user_ty,
+ Locations::All,
+ ) {
+ span_mirbug!(
+ self,
+ local,
+ "bad user type on variable {:?}: {:?} != {:?} ({:?})",
+ local,
+ local_decl.ty,
+ local_decl.user_ty,
+ terr,
+ );
+ }
+ }
}
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
None, remainder_span, lint_level, slice::from_ref(&pattern),
ArmHasGuard(false), None);
- this.visit_bindings(&pattern, &mut |this, _, _, _, node, span, _| {
+ 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);
})
let ptr_temp = this.local_decls.push(LocalDecl {
mutability: Mutability::Mut,
ty: ptr_ty,
+ user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,
let num_patterns = patterns.len();
self.visit_bindings(
&patterns[0],
- &mut |this, mutability, name, mode, var, span, ty| {
+ None,
+ &mut |this, mutability, name, mode, var, span, ty, user_ty| {
if visibility_scope.is_none() {
visibility_scope =
Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
num_patterns,
var,
ty,
+ user_ty,
has_guard,
opt_match_place.map(|(x, y)| (x.cloned(), y)),
patterns[0].span,
);
}
- pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, f: &mut F)
- where
- F: FnMut(&mut Self, Mutability, Name, BindingMode, NodeId, Span, Ty<'tcx>),
- {
+ pub fn visit_bindings(
+ &mut self,
+ pattern: &Pattern<'tcx>,
+ pattern_user_ty: Option<CanonicalTy<'tcx>>,
+ f: &mut impl FnMut(
+ &mut Self,
+ Mutability,
+ Name,
+ BindingMode,
+ NodeId,
+ Span,
+ Ty<'tcx>,
+ Option<CanonicalTy<'tcx>>,
+ ),
+ ) {
match *pattern.kind {
PatternKind::Binding {
mutability,
ref subpattern,
..
} => {
- f(self, mutability, name, mode, var, pattern.span, ty);
+ f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty);
if let Some(subpattern) = subpattern.as_ref() {
- self.visit_bindings(subpattern, f);
+ self.visit_bindings(subpattern, pattern_user_ty, f);
}
}
PatternKind::Array {
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, f);
+ self.visit_bindings(subpattern, None, f);
}
}
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
- PatternKind::AscribeUserType { ref subpattern, .. }
- | PatternKind::Deref { ref subpattern } => {
- self.visit_bindings(subpattern, f);
+ PatternKind::Deref { ref subpattern } => {
+ // FIXME(#47184): extract or handle `pattern_user_ty` somehow
+ self.visit_bindings(subpattern, None, f);
+ }
+ PatternKind::AscribeUserType { ref subpattern, user_ty } => {
+ // This corresponds to something like
+ //
+ // ```
+ // let (p1: T1): T2 = ...;
+ // ```
+ //
+ // Not presently possible, though maybe someday.
+ assert!(pattern_user_ty.is_none());
+ self.visit_bindings(subpattern, Some(user_ty), f)
}
PatternKind::Leaf { ref subpatterns }
| PatternKind::Variant {
ref subpatterns, ..
} => {
+ // FIXME(#47184): extract or handle `pattern_user_ty` somehow
for subpattern in subpatterns {
- self.visit_bindings(&subpattern.pattern, f);
+ self.visit_bindings(&subpattern.pattern, None, f);
}
}
}
num_patterns: usize,
var_id: NodeId,
var_ty: Ty<'tcx>,
+ user_var_ty: Option<CanonicalTy<'tcx>>,
has_guard: ArmHasGuard,
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
pat_span: Span,
};
let local = LocalDecl::<'tcx> {
mutability,
- ty: var_ty.clone(),
+ ty: var_ty,
+ user_ty: user_var_ty,
name: Some(name),
source_info,
visibility_scope,
// See previous comment.
mutability: Mutability::Not,
ty: tcx.mk_imm_ref(tcx.types.re_empty, var_ty),
+ user_ty: None,
name: Some(name),
source_info,
visibility_scope,
self.local_decls.push(LocalDecl {
mutability: Mutability::Mut,
ty,
+ user_ty: None,
source_info,
visibility_scope: source_info.scope,
name,
#![feature(if_while_or_patterns)]
#![feature(try_from)]
#![feature(reverse_bits)]
+#![feature(underscore_imports)]
#![recursion_limit="256"]
fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span };
LocalDecl {
- mutability, ty, name: None,
+ mutability, ty,
+ user_ty: None,
+ name: None,
source_info,
visibility_scope: source_info.scope,
internal: false,
let new_ret = LocalDecl {
mutability: Mutability::Mut,
ty: ret_ty,
+ user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,
mir.local_decls[RETURN_PLACE] = LocalDecl {
mutability: Mutability::Mut,
ty: tcx.mk_nil(),
+ user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,
ty: gen_ty,
mutbl: hir::Mutability::MutMutable,
}),
+ user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
use std::fmt::Display;
+use std::fmt::Write as _;
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
};
let indent = indent + INDENT.len();
- let indented_var = format!(
- "{0:1$}let {2}{3:?}: {4:?};",
+ let mut indented_var = format!(
+ "{0:1$}let {2}{3:?}: {4:?}",
INDENT,
indent,
mut_str,
local,
var.ty
);
+ if let Some(user_ty) = var.user_ty {
+ write!(indented_var, " as {:?}", user_ty).unwrap();
+ }
+ indented_var.push_str(";");
writeln!(
w,
"{0:1$} // \"{2}\" in {3}",
#![feature(nll)]
fn variable_no_initializer() {
- // FIXME: It is unclear to me whether this should be an error or not.
-
let x = 22;
let y: &'static u32;
+ y = &x; //~ ERROR
+}
+
+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;
+}
+
+fn ref_with_ascribed_static_type() -> u32 {
+ // Check the behavior in some wacky cases.
+ let x = 22;
+ let y = &x; //~ ERROR
+ let ref z: &'static u32 = y; //~ ERROR
+ **z
+}
+
+fn ref_with_ascribed_any_type() -> u32 {
+ let x = 22;
+ let y = &x;
+ let ref z: &u32 = y;
+ **z
+}
+
+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;
}
let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR
}
-struct Single<T> { value: T }
-
fn struct_single_field_variable_with_initializer() {
let x = 22;
let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR
}
fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 {
- // FIXME: The fact that this type-checks is perhaps surprising.
+ // 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
error[E0597]: `x` does not live long enough
- --> $DIR/patterns.rs:15:27
+ --> $DIR/patterns.rs:8:9
+ |
+LL | y = &x; //~ ERROR
+ | ^^ borrowed value does not live long enough
+LL | }
+ | - `x` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:22:13
+ |
+LL | let y = &x; //~ ERROR
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `x` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/patterns.rs:23:9
+ |
+LL | let ref z: &'static u32 = y; //~ ERROR
+ | ^^^^^ borrowed value does not live long enough
+LL | **z
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:46:27
|
LL | let y: &'static u32 = &x; //~ ERROR
| ^^ borrowed value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
- --> $DIR/patterns.rs:20:27
+ --> $DIR/patterns.rs:51:27
|
LL | let _: &'static u32 = &x; //~ ERROR
| ^^ borrowed value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
- --> $DIR/patterns.rs:22:41
+ --> $DIR/patterns.rs:53:41
|
LL | let _: Vec<&'static String> = vec![&String::new()];
| ^^^^^^^^^^^^^ - temporary value only lives until here
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
- --> $DIR/patterns.rs:25:52
+ --> $DIR/patterns.rs:56:52
|
LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
| ^^^^^^^^^^^^^ - temporary value only lives until here
= note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
- --> $DIR/patterns.rs:28:53
+ --> $DIR/patterns.rs:59:53
|
LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
| ^^^^^^^^^^^^^ - temporary value only lives until here
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
- --> $DIR/patterns.rs:34:40
+ --> $DIR/patterns.rs:65:40
|
LL | let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR
| ^^ borrowed value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
- --> $DIR/patterns.rs:39:40
+ --> $DIR/patterns.rs:70:40
|
LL | let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR
| ^^ borrowed value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
- --> $DIR/patterns.rs:46:69
+ --> $DIR/patterns.rs:75:69
|
LL | let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR
| ^^ borrowed value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
- --> $DIR/patterns.rs:51:69
+ --> $DIR/patterns.rs:80:69
|
LL | let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR
| ^^ borrowed value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough
- --> $DIR/patterns.rs:59:17
+ --> $DIR/patterns.rs:88:17
|
LL | value1: &x, //~ ERROR
| ^^ borrowed value does not live long enough
= note: borrowed value must be valid for the static lifetime...
error: unsatisfied lifetime constraints
- --> $DIR/patterns.rs:72:5
+ --> $DIR/patterns.rs:101:5
|
LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
| ^ returning this value requires that `'a` must outlive `'static`
error: unsatisfied lifetime constraints
- --> $DIR/patterns.rs:88:40
+ --> $DIR/patterns.rs:117:40
|
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
| ^^^^^^^ requires that `'a` must outlive `'static`
-error: aborting due to 12 previous errors
+error: aborting due to 15 previous errors
For more information about this error, try `rustc --explain E0597`.