From 40ab41fd1898e44328108295df3f17074a253dcf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 8 Oct 2018 19:03:24 -0400 Subject: [PATCH] add pattern type ascriptions for tuple/brace structs/enums --- src/librustc_mir/build/matches/mod.rs | 8 ++++ src/librustc_mir/hair/pattern/mod.rs | 47 +++++++++++++++---- src/librustc_typeck/check/mod.rs | 7 +++ .../pattern_substs_on_brace_enum_variant.rs | 24 ++++++++++ ...attern_substs_on_brace_enum_variant.stderr | 25 ++++++++++ .../pattern_substs_on_brace_struct.rs | 22 +++++++++ .../pattern_substs_on_brace_struct.stderr | 25 ++++++++++ .../pattern_substs_on_tuple_enum_variant.rs | 24 ++++++++++ ...attern_substs_on_tuple_enum_variant.stderr | 25 ++++++++++ .../pattern_substs_on_tuple_struct.rs | 22 +++++++++ .../pattern_substs_on_tuple_struct.stderr | 25 ++++++++++ 11 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs create mode 100644 src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr create mode 100644 src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs create mode 100644 src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr create mode 100644 src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs create mode 100644 src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr create mode 100644 src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs create mode 100644 src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 656c78a46ed7..c2a7172d54cc 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -1307,6 +1307,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ) { for ascription in ascriptions { let source_info = self.source_info(ascription.span); + + debug!( + "adding user ascription at span {:?} of place {:?} and {:?}", + source_info.span, + ascription.source, + ascription.user_ty, + ); + self.cfg.push( block, Statement { diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index b22cc4a1a42b..04090e5087ff 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -18,6 +18,8 @@ pub(crate) use self::check_match::check_match; use const_eval::{const_field, const_variant_index}; +use hair::util::UserAnnotatedTyHelpers; + use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region}; @@ -529,8 +531,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { field: Field::new(i), pattern: self.lower_pattern(field), }) - .collect(); - self.lower_variant_or_leaf(def, pat.span, ty, subpatterns) + .collect(); + + self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns) } PatKind::Struct(ref qpath, ref fields, _) => { @@ -546,7 +549,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }) .collect(); - self.lower_variant_or_leaf(def, pat.span, ty, subpatterns) + self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns) } }; @@ -637,12 +640,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn lower_variant_or_leaf( &mut self, def: Def, + hir_id: hir::HirId, span: Span, ty: Ty<'tcx>, - subpatterns: Vec>) - -> PatternKind<'tcx> - { - match def { + subpatterns: Vec>, + ) -> PatternKind<'tcx> { + let mut kind = match def { Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { let enum_id = self.tcx.parent_def_id(variant_id).unwrap(); let adt_def = self.tcx.adt_def(enum_id); @@ -675,7 +678,24 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { self.errors.push(PatternError::NonConstPath(span)); PatternKind::Wild } + }; + + if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) { + let subpattern = Pattern { + span, + ty, + kind: Box::new(kind), + }; + + debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span); + + kind = PatternKind::AscribeUserType { + subpattern, + user_ty, + }; } + + kind } /// Takes a HIR Path. If the path is a constant, evaluates it and feeds @@ -729,7 +749,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }, } } - _ => self.lower_variant_or_leaf(def, span, ty, vec![]), + _ => self.lower_variant_or_leaf(def, id, span, ty, vec![]), }; Pattern { @@ -894,6 +914,17 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } +impl UserAnnotatedTyHelpers<'tcx, 'tcx> for PatternContext<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'_, 'tcx, 'tcx> { + self.tcx + } + + fn tables(&self) -> &ty::TypeckTables<'tcx> { + self.tables + } +} + + pub trait PatternFoldable<'tcx> : Sized { fn fold_with>(&self, folder: &mut F) -> Self { self.super_fold_with(folder) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 529f1e6161be..52ed279b8539 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2164,6 +2164,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// occurred**, so that annotations like `Vec<_>` are preserved /// properly. pub fn write_user_substs_from_substs(&self, hir_id: hir::HirId, substs: &'tcx Substs<'tcx>) { + debug!( + "write_user_substs_from_substs({:?}, {:?}) in fcx {}", + hir_id, + substs, + self.tag(), + ); + if !substs.is_noop() { let user_substs = self.infcx.canonicalize_response(&substs); debug!("instantiate_value_path: user_substs = {:?}", user_substs); diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs new file mode 100644 index 000000000000..526134b6e4b3 --- /dev/null +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs @@ -0,0 +1,24 @@ +#![feature(nll)] + +enum Foo<'a> { + Bar { field: &'a u32 } +} + +fn in_let() { + let y = 22; + let foo = Foo::Bar { field: &y }; + //~^ ERROR `y` does not live long enough + let Foo::Bar::<'static> { field: _z } = foo; +} + +fn in_match() { + let y = 22; + let foo = Foo::Bar { field: &y }; + //~^ ERROR `y` does not live long enough + match foo { + Foo::Bar::<'static> { field: _z } => { + } + } +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr new file mode 100644 index 000000000000..5dbbf7c5b481 --- /dev/null +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr @@ -0,0 +1,25 @@ +error[E0597]: `y` does not live long enough + --> $DIR/pattern_substs_on_brace_enum_variant.rs:9:33 + | +LL | let foo = Foo::Bar { field: &y }; + | ^^ borrowed value does not live long enough +... +LL | } + | - `y` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `y` does not live long enough + --> $DIR/pattern_substs_on_brace_enum_variant.rs:16:33 + | +LL | let foo = Foo::Bar { field: &y }; + | ^^ borrowed value does not live long enough +... +LL | } + | - `y` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs new file mode 100644 index 000000000000..1c92858eb3a0 --- /dev/null +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs @@ -0,0 +1,22 @@ +#![feature(nll)] + +struct Foo<'a> { field: &'a u32 } + +fn in_let() { + let y = 22; + let foo = Foo { field: &y }; + //~^ ERROR `y` does not live long enough + let Foo::<'static> { field: _z } = foo; +} + +fn in_main() { + let y = 22; + let foo = Foo { field: &y }; + //~^ ERROR `y` does not live long enough + match foo { + Foo::<'static> { field: _z } => { + } + } +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr new file mode 100644 index 000000000000..0108a185b1f3 --- /dev/null +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr @@ -0,0 +1,25 @@ +error[E0597]: `y` does not live long enough + --> $DIR/pattern_substs_on_brace_struct.rs:7:28 + | +LL | let foo = Foo { field: &y }; + | ^^ borrowed value does not live long enough +... +LL | } + | - `y` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `y` does not live long enough + --> $DIR/pattern_substs_on_brace_struct.rs:14:28 + | +LL | let foo = Foo { field: &y }; + | ^^ borrowed value does not live long enough +... +LL | } + | - `y` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs new file mode 100644 index 000000000000..d6c364f8e3f0 --- /dev/null +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs @@ -0,0 +1,24 @@ +#![feature(nll)] + +enum Foo<'a> { + Bar(&'a u32) +} + +fn in_let() { + let y = 22; + let foo = Foo::Bar(&y); + //~^ ERROR `y` does not live long enough + let Foo::Bar::<'static>(_z) = foo; +} + +fn in_match() { + let y = 22; + let foo = Foo::Bar(&y); + //~^ ERROR `y` does not live long enough + match foo { + Foo::Bar::<'static>(_z) => { + } + } +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr new file mode 100644 index 000000000000..b18fdc30ac2d --- /dev/null +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr @@ -0,0 +1,25 @@ +error[E0597]: `y` does not live long enough + --> $DIR/pattern_substs_on_tuple_enum_variant.rs:9:24 + | +LL | let foo = Foo::Bar(&y); + | ^^ borrowed value does not live long enough +... +LL | } + | - `y` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `y` does not live long enough + --> $DIR/pattern_substs_on_tuple_enum_variant.rs:16:24 + | +LL | let foo = Foo::Bar(&y); + | ^^ borrowed value does not live long enough +... +LL | } + | - `y` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs new file mode 100644 index 000000000000..626ca9087978 --- /dev/null +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs @@ -0,0 +1,22 @@ +#![feature(nll)] + +struct Foo<'a>(&'a u32); + +fn in_let() { + let y = 22; + let foo = Foo(&y); + //~^ ERROR `y` does not live long enough + let Foo::<'static>(_z) = foo; +} + +fn in_match() { + let y = 22; + let foo = Foo(&y); + //~^ ERROR `y` does not live long enough + match foo { + Foo::<'static>(_z) => { + } + } +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr new file mode 100644 index 000000000000..b72fda955801 --- /dev/null +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr @@ -0,0 +1,25 @@ +error[E0597]: `y` does not live long enough + --> $DIR/pattern_substs_on_tuple_struct.rs:7:19 + | +LL | let foo = Foo(&y); + | ^^ borrowed value does not live long enough +... +LL | } + | - `y` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `y` does not live long enough + --> $DIR/pattern_substs_on_tuple_struct.rs:14:19 + | +LL | let foo = Foo(&y); + | ^^ borrowed value does not live long enough +... +LL | } + | - `y` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`.