提交 e87bf30f 编写于 作者: N Niko Matsakis

propagate user-ascribes types down onto resulting bindings

But only in very simple cases.
上级 a8710539
......@@ -24,6 +24,7 @@
impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
mutability,
ty,
user_ty,
name,
source_info,
visibility_scope,
......
......@@ -640,6 +640,12 @@ pub struct LocalDecl<'tcx> {
/// 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(_)`
......@@ -802,6 +808,7 @@ fn new_local(
LocalDecl {
mutability,
ty,
user_ty: None,
name: None,
source_info: SourceInfo {
span,
......@@ -821,6 +828,7 @@ pub fn new_return_place(return_ty: Ty, span: Span) -> LocalDecl {
LocalDecl {
mutability: Mutability::Mut,
ty: return_ty,
user_ty: None,
source_info: SourceInfo {
span,
scope: OUTERMOST_SOURCE_SCOPE,
......@@ -2613,6 +2621,7 @@ impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> {
is_user_variable,
internal,
ty,
user_ty,
name,
source_info,
visibility_scope,
......
......@@ -721,6 +721,7 @@ fn super_local_decl(&mut self,
let LocalDecl {
mutability: _,
ref $($mutability)* ty,
ref $($mutability)* user_ty,
name: _,
ref $($mutability)* source_info,
ref $($mutability)* visibility_scope,
......@@ -732,6 +733,9 @@ fn super_local_decl(&mut self,
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);
}
......
......@@ -275,6 +275,25 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
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>) {
......
......@@ -143,7 +143,7 @@ fn ast_block_stmts(&mut self,
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);
})
......
......@@ -296,6 +296,7 @@ pub fn into_expr(
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,
......
......@@ -399,7 +399,8 @@ pub fn declare_bindings(
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));
......@@ -421,6 +422,7 @@ pub fn declare_bindings(
num_patterns,
var,
ty,
user_ty,
has_guard,
opt_match_place.map(|(x, y)| (x.cloned(), y)),
patterns[0].span,
......@@ -470,10 +472,21 @@ pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span, for_guard:
);
}
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,
......@@ -484,9 +497,9 @@ pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, f: &mut F)
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 {
......@@ -499,21 +512,34 @@ pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, f: &mut F)
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);
}
}
}
......@@ -1375,6 +1401,7 @@ fn declare_binding(
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,
......@@ -1392,7 +1419,8 @@ fn declare_binding(
};
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty.clone(),
ty: var_ty,
user_ty: user_var_ty,
name: Some(name),
source_info,
visibility_scope,
......@@ -1424,6 +1452,7 @@ fn declare_binding(
// 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,
......
......@@ -730,6 +730,7 @@ fn args_and_body(&mut self,
self.local_decls.push(LocalDecl {
mutability: Mutability::Mut,
ty,
user_ty: None,
source_info,
visibility_scope: source_info.scope,
name,
......
......@@ -39,6 +39,7 @@
#![feature(if_while_or_patterns)]
#![feature(try_from)]
#![feature(reverse_bits)]
#![feature(underscore_imports)]
#![recursion_limit="256"]
......
......@@ -140,7 +140,9 @@ enum CallKind {
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,
......
......@@ -303,6 +303,7 @@ fn replace_result_variable<'tcx>(
let new_ret = LocalDecl {
mutability: Mutability::Mut,
ty: ret_ty,
user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,
......@@ -656,6 +657,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
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,
......@@ -672,6 +674,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
ty: gen_ty,
mutbl: hir::Mutability::MutMutable,
}),
user_ty: None,
name: None,
source_info,
visibility_scope: source_info.scope,
......
......@@ -17,6 +17,7 @@
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};
......@@ -493,14 +494,18 @@ fn write_scope_tree(
};
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}",
......
......@@ -3,10 +3,41 @@
#![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;
}
......@@ -39,8 +70,6 @@ fn pair_variable_with_initializer() {
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
......@@ -73,7 +102,7 @@ fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
}
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
......@@ -9,7 +41,7 @@ LL | }
= 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
......@@ -20,7 +52,7 @@ LL | }
= 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
......@@ -30,7 +62,7 @@ LL | let _: Vec<&'static String> = vec![&String::new()];
= 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
......@@ -40,7 +72,7 @@ LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
= 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
......@@ -50,7 +82,7 @@ LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
= 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
......@@ -60,7 +92,7 @@ LL | }
= 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
......@@ -70,7 +102,7 @@ LL | }
= 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
......@@ -80,7 +112,7 @@ LL | }
= 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
......@@ -90,7 +122,7 @@ LL | }
= 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
......@@ -101,7 +133,7 @@ LL | }
= 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
......@@ -110,13 +142,13 @@ LL | y //~ ERROR
| ^ 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`.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册