From 033bd8c7af79d362b4e861543b63991e7300948f Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 26 Dec 2019 21:13:51 +0000 Subject: [PATCH 01/25] Explain a test --- .../impl-trait/multiple-lifetimes/error-handling.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs index b226cf058aa75..8fb4794e89132 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs @@ -12,10 +12,17 @@ type E<'a, 'b> = impl Sized; fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { //~^ ERROR lifetime may not live long enough - let v = CopyIfEq::<*mut _, *mut _>(&mut {x}, &mut y); + let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y); + + // This assignment requires that `x` and `y` have the same type due to the + // `Copy` impl. The reason why we are using a copy to create a constraint + // is that only borrow checking (not regionck in type checking) enforces + // this bound. let u = v; let _: *mut &'a i32 = u.1; - unsafe { let _: &'b i32 = *u.0; } + unsafe { + let _: &'b i32 = *u.0; + } u.0 } From 7f41cf4cef551d887de539842d11945b6bfaa8b6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 26 Dec 2019 23:41:32 +0000 Subject: [PATCH 02/25] Check associated opaque types don't use unconstrained lifetimes --- src/librustc_typeck/impl_wf_check.rs | 18 ++++++++++--- .../type-alias-impl-trait/assoc-type-const.rs | 12 ++++----- .../assoc-type-lifetime-unconstrained.rs | 26 +++++++++++++++++++ .../assoc-type-lifetime-unconstrained.stderr | 9 +++++++ .../assoc-type-lifetime.rs | 6 ++--- 5 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs create mode 100644 src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.stderr diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index e9c18b59da982..0b4b8a49054fa 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -120,11 +120,23 @@ fn enforce_impl_params_are_constrained( let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs .iter() .map(|item_ref| tcx.hir().local_def_id(item_ref.id.hir_id)) - .filter(|&def_id| { + .flat_map(|def_id| { let item = tcx.associated_item(def_id); - item.kind == ty::AssocKind::Type && item.defaultness.has_value() + match item.kind { + ty::AssocKind::Type => { + if item.defaultness.has_value() { + cgp::parameters_for(&tcx.type_of(def_id), true) + } else { + Vec::new() + } + } + ty::AssocKind::OpaqueTy => { + let predicates = tcx.predicates_of(def_id).instantiate_identity(tcx); + cgp::parameters_for(&predicates, true) + } + ty::AssocKind::Method | ty::AssocKind::Const => Vec::new(), + } }) - .flat_map(|def_id| cgp::parameters_for(&tcx.type_of(def_id), true)) .collect(); for param in &impl_generics.params { diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-const.rs b/src/test/ui/type-alias-impl-trait/assoc-type-const.rs index 5db677d82e266..2907c21c6203c 100644 --- a/src/test/ui/type-alias-impl-trait/assoc-type-const.rs +++ b/src/test/ui/type-alias-impl-trait/assoc-type-const.rs @@ -6,7 +6,7 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -trait UnwrapItemsExt { +trait UnwrapItemsExt<'a, const C: usize> { type Iter; fn unwrap_items(self) -> Self::Iter; } @@ -18,18 +18,16 @@ trait MyTrait<'a, const C: usize> { const MY_CONST: usize; } -impl<'a, const C: usize> MyTrait<'a, {C}> for MyStruct<{C}> { +impl<'a, const C: usize> MyTrait<'a, { C }> for MyStruct<{ C }> { type MyItem = u8; const MY_CONST: usize = C; } -impl<'a, I, const C: usize> UnwrapItemsExt<{C}> for I -where -{ - type Iter = impl MyTrait<'a, {C}>; +impl<'a, I, const C: usize> UnwrapItemsExt<'a, { C }> for I { + type Iter = impl MyTrait<'a, { C }>; fn unwrap_items(self) -> Self::Iter { - MyStruct::<{C}> {} + MyStruct::<{ C }> {} } } diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs new file mode 100644 index 0000000000000..3f34b00ec77e1 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs @@ -0,0 +1,26 @@ +// Tests that we don't allow unconstrained lifetime parameters in impls when +// the lifetime is used in an associated opaque type. + +#![feature(type_alias_impl_trait)] + +trait UnwrapItemsExt { + type Iter; + fn unwrap_items(self) -> Self::Iter; +} + +struct MyStruct {} + +trait MyTrait<'a> {} + +impl<'a> MyTrait<'a> for MyStruct {} + +impl<'a, I> UnwrapItemsExt for I { + //~^ ERROR the lifetime parameter `'a` is not constrained + type Iter = impl MyTrait<'a>; + + fn unwrap_items(self) -> Self::Iter { + MyStruct {} + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.stderr b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.stderr new file mode 100644 index 0000000000000..e594dc577b1cd --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.stderr @@ -0,0 +1,9 @@ +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/assoc-type-lifetime-unconstrained.rs:17:6 + | +LL | impl<'a, I> UnwrapItemsExt for I { + | ^^ unconstrained lifetime parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-lifetime.rs b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime.rs index cff1d24494e83..39f785d8cc55d 100644 --- a/src/test/ui/type-alias-impl-trait/assoc-type-lifetime.rs +++ b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime.rs @@ -4,7 +4,7 @@ #![feature(type_alias_impl_trait)] -trait UnwrapItemsExt { +trait UnwrapItemsExt<'a> { type Iter; fn unwrap_items(self) -> Self::Iter; } @@ -15,9 +15,7 @@ trait MyTrait<'a> {} impl<'a> MyTrait<'a> for MyStruct {} -impl<'a, I> UnwrapItemsExt for I -where -{ +impl<'a, I> UnwrapItemsExt<'a> for I { type Iter = impl MyTrait<'a>; fn unwrap_items(self) -> Self::Iter { From 4af0952961520d44088107d000b78eb3a698edba Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 28 Dec 2019 15:51:44 +0000 Subject: [PATCH 03/25] Call `is_freeze` less in unsafety-checking This is to avoid cycles when calling `is_freeze` on an opaque type. --- src/librustc_mir/transform/check_unsafety.rs | 45 +++++++++++-------- .../ui/impl-trait/unsafety-checking-cycle.rs | 32 +++++++++++++ 2 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/impl-trait/unsafety-checking-cycle.rs diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 6e80338c975ed..fab55018d3099 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -178,6 +178,16 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { + // prevent + // * `&mut x.field` + // * `x.field = y;` + // * `&x.field` if `field`'s type has interior mutability + // because either of these would allow modifying the layout constrained field and + // insert values that violate the layout constraints. + if context.is_mutating_use() || context.is_borrow() { + self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use()); + } + for (i, elem) in place.projection.iter().enumerate() { let proj_base = &place.projection[..i]; @@ -198,24 +208,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { ); } } - let is_borrow_of_interior_mut = context.is_borrow() - && !Place::ty_from(place.local, proj_base, self.body, self.tcx).ty.is_freeze( - self.tcx, - self.param_env, - self.source_info.span, - ); - // prevent - // * `&mut x.field` - // * `x.field = y;` - // * `&x.field` if `field`'s type has interior mutability - // because either of these would allow modifying the layout constrained field and - // insert values that violate the layout constraints. - if context.is_mutating_use() || is_borrow_of_interior_mut { - self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use()); - } let old_source_info = self.source_info; - if let (local, []) = (&place.local, proj_base) { - let decl = &self.body.local_decls[*local]; + if let [] = proj_base { + let decl = &self.body.local_decls[place.local]; if decl.internal { if let LocalInfo::StaticRef { def_id, .. } = decl.local_info { if self.tcx.is_mutable_static(def_id) { @@ -240,7 +235,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { // Internal locals are used in the `move_val_init` desugaring. // We want to check unsafety against the source info of the // desugaring, rather than the source info of the RHS. - self.source_info = self.body.local_decls[*local].source_info; + self.source_info = self.body.local_decls[place.local].source_info; } } } @@ -396,6 +391,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { cursor = proj_base; match elem { + // Modifications behind a dereference don't affect the value of + // the pointer. + ProjectionElem::Deref => return, ProjectionElem::Field(..) => { let ty = Place::ty_from(place.local, proj_base, &self.body.local_decls, self.tcx).ty; @@ -409,7 +407,14 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { "mutating layout constrained fields cannot statically be \ checked for valid values", ) - } else { + + // Check `is_freeze` as late as possible to avoid cycle errors + // with opaque types. + } else if !place.ty(self.body, self.tcx).ty.is_freeze( + self.tcx, + self.param_env, + self.source_info.span, + ) { ( "borrow of layout constrained field with interior \ mutability", @@ -417,6 +422,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { lose the constraints. Coupled with interior mutability, \ the field can be changed to invalid values", ) + } else { + continue; }; self.require_unsafe( description, diff --git a/src/test/ui/impl-trait/unsafety-checking-cycle.rs b/src/test/ui/impl-trait/unsafety-checking-cycle.rs new file mode 100644 index 0000000000000..4a5831c5b73df --- /dev/null +++ b/src/test/ui/impl-trait/unsafety-checking-cycle.rs @@ -0,0 +1,32 @@ +// Ensure that we don't get a cycle error from trying to determine whether an +// opaque type implements `Freeze` in safety checking, when it doesn't matter. + +// check-pass + +#![feature(rustc_attrs)] + +struct AnyValue(T); + +// No need to check for `Freeze` here, there's no +// `rustc_layout_scalar_valid_range_start` involved. +fn not_restricted(c: bool) -> impl Sized { + if c { + let x = AnyValue(not_restricted(false)); + &x.0; + } + 2u32 +} + +#[rustc_layout_scalar_valid_range_start(1)] +struct NonZero(T); + +// No need to check for `Freeze` here, we're not borrowing the field. +fn not_field(c: bool) -> impl Sized { + if c { + let x = unsafe { NonZero(not_field(false)) }; + &x; + } + 5u32 +} + +fn main() {} From 60970be1fd67b19cfcdbbc53f5e87ebcbf0b61bf Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 28 Dec 2019 15:39:52 +0000 Subject: [PATCH 04/25] Distinguish RPIT from other impl trait --- src/librustc/infer/opaque_types/mod.rs | 1 + src/librustc_ast_lowering/item.rs | 14 ++++++--- src/librustc_ast_lowering/lib.rs | 42 ++++++++++++++++---------- src/librustc_hir/hir.rs | 2 ++ 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 7fef9d27c4d4a..7a45782cd45b1 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -502,6 +502,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Otherwise, generate the label we'll use in the error message. hir::OpaqueTyOrigin::TypeAlias => "impl Trait", hir::OpaqueTyOrigin::FnReturn => "impl Trait", + hir::OpaqueTyOrigin::Misc => "impl Trait", }; let msg = format!("ambiguous lifetime bound in `{}`", context_name); let mut err = self.tcx.sess.struct_span_err(span, &msg); diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 73a25620b5a04..426659fd92452 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -272,7 +272,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty( t, if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(None) + ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc) } else { ImplTraitContext::Disallowed(ImplTraitPosition::Binding) }, @@ -283,7 +283,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty( t, if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(None) + ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc) } else { ImplTraitContext::Disallowed(ImplTraitPosition::Binding) }, @@ -327,8 +327,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } Some(bounds) => { let ty = hir::OpaqueTy { - generics: self.lower_generics(generics, ImplTraitContext::OpaqueTy(None)), - bounds: self.lower_param_bounds(bounds, ImplTraitContext::OpaqueTy(None)), + generics: self.lower_generics( + generics, + ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc), + ), + bounds: self.lower_param_bounds( + bounds, + ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc), + ), impl_trait_fn: None, origin: hir::OpaqueTyOrigin::TypeAlias, }; diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 618b1e7964b95..b600869fdf626 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -222,7 +222,7 @@ enum ImplTraitContext<'b, 'a> { /// We optionally store a `DefId` for the parent item here so we can look up necessary /// information later. It is `None` when no information about the context should be stored /// (e.g., for consts and statics). - OpaqueTy(Option /* fn def-ID */), + OpaqueTy(Option /* fn def-ID */, hir::OpaqueTyOrigin), /// `impl Trait` is not accepted in this position. Disallowed(ImplTraitPosition), @@ -248,7 +248,7 @@ impl<'a> ImplTraitContext<'_, 'a> { use self::ImplTraitContext::*; match self { Universal(params) => Universal(params), - OpaqueTy(fn_def_id) => OpaqueTy(*fn_def_id), + OpaqueTy(fn_def_id, origin) => OpaqueTy(*fn_def_id, *origin), Disallowed(pos) => Disallowed(*pos), } } @@ -1010,7 +1010,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so desugar to // // fn foo() -> impl Iterator - ImplTraitContext::OpaqueTy(_) => (true, itctx), + ImplTraitContext::OpaqueTy(..) => (true, itctx), // We are in the argument position, but within a dyn type: // @@ -1019,7 +1019,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so desugar to // // fn foo(x: dyn Iterator) - ImplTraitContext::Universal(_) if self.is_in_dyn_type => (true, itctx), + ImplTraitContext::Universal(..) if self.is_in_dyn_type => (true, itctx), // In `type Foo = dyn Iterator` we desugar to // `type Foo = dyn Iterator` but we have to override the @@ -1028,7 +1028,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // FIXME: this is only needed until `impl Trait` is allowed in type aliases. ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => { - (true, ImplTraitContext::OpaqueTy(None)) + (true, ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)) } // We are in the parameter position, but not within a dyn type: @@ -1269,8 +1269,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::ImplTrait(def_node_id, ref bounds) => { let span = t.span; match itctx { - ImplTraitContext::OpaqueTy(fn_def_id) => { - self.lower_opaque_impl_trait(span, fn_def_id, def_node_id, |this| { + ImplTraitContext::OpaqueTy(fn_def_id, origin) => { + self.lower_opaque_impl_trait(span, fn_def_id, origin, def_node_id, |this| { this.lower_param_bounds(bounds, itctx) }) } @@ -1349,6 +1349,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, span: Span, fn_def_id: Option, + origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>, ) -> hir::TyKind<'hir> { @@ -1390,7 +1391,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }, bounds: hir_bounds, impl_trait_fn: fn_def_id, - origin: hir::OpaqueTyOrigin::FnReturn, + origin, }; trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_index); @@ -1622,7 +1623,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_ty( t, if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(Some(parent_def_id)) + ImplTraitContext::OpaqueTy(Some(parent_def_id), hir::OpaqueTyOrigin::Misc) } else { ImplTraitContext::Disallowed(ImplTraitPosition::Binding) }, @@ -1723,9 +1724,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { match decl.output { FunctionRetTy::Ty(ref ty) => match in_band_ty_params { - Some((def_id, _)) if impl_trait_return_allow => hir::FunctionRetTy::Return( - self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(def_id))), - ), + Some((def_id, _)) if impl_trait_return_allow => { + hir::FunctionRetTy::Return(self.lower_ty( + ty, + ImplTraitContext::OpaqueTy(Some(def_id), hir::OpaqueTyOrigin::FnReturn), + )) + } _ => hir::FunctionRetTy::Return( self.lower_ty(ty, ImplTraitContext::disallowed()), ), @@ -1957,7 +1961,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::GenericBound<'hir> { // Compute the `T` in `Future` from the return type. let output_ty = match output { - FunctionRetTy::Ty(ty) => self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(fn_def_id))), + FunctionRetTy::Ty(ty) => self.lower_ty( + ty, + ImplTraitContext::OpaqueTy(Some(fn_def_id), hir::OpaqueTyOrigin::FnReturn), + ), FunctionRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), }; @@ -2102,9 +2109,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let kind = hir::GenericParamKind::Type { - default: default - .as_ref() - .map(|x| self.lower_ty(x, ImplTraitContext::OpaqueTy(None))), + default: default.as_ref().map(|x| { + self.lower_ty( + x, + ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc), + ) + }), synthetic: param .attrs .iter() diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 80b379218a5d5..07a2c48225349 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -1990,6 +1990,8 @@ pub enum OpaqueTyOrigin { FnReturn, /// `async fn` AsyncFn, + /// Impl trait in bindings, consts, statics, bounds. + Misc, } /// The various kinds of types recognized by the compiler. From 43dae91821afd70eeea46bfe0a793321b7e77526 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 28 Dec 2019 11:24:26 +0000 Subject: [PATCH 05/25] Give some more queries descriptions --- src/librustc/query/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 11b079806af2d..1cc7c7a1c69a8 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -125,7 +125,9 @@ rustc_queries! { /// Fetch the MIR for a given `DefId` right after it's built - this includes /// unreachable code. - query mir_built(_: DefId) -> &'tcx Steal> {} + query mir_built(_: DefId) -> &'tcx Steal> { + desc { "building MIR for" } + } /// Fetch the MIR for a given `DefId` up till the point where it is /// ready for const evaluation. @@ -345,6 +347,7 @@ rustc_queries! { TypeChecking { /// The result of unsafety-checking this `DefId`. query unsafety_check_result(key: DefId) -> mir::UnsafetyCheckResult { + desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } } @@ -414,6 +417,7 @@ rustc_queries! { } query typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> { + desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } load_cached(tcx, id) { let typeck_tables: Option> = tcx @@ -453,6 +457,7 @@ rustc_queries! { /// Borrow-checks the function body. If this is a closure, returns /// additional requirements that the closure's creator must verify. query mir_borrowck(key: DefId) -> mir::BorrowCheckResult<'tcx> { + desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if(tcx, _) { key.is_local() && tcx.is_closure(key) } } } From 9664122b1ff04dd8a853de602cd64d86a6473248 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 26 Dec 2019 20:46:38 +0000 Subject: [PATCH 06/25] Simplify function signature in opaque_types --- src/librustc/infer/opaque_types/mod.rs | 12 ++++-------- src/librustc_typeck/check/writeback.rs | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 7a45782cd45b1..1d69f598256f2 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -550,13 +550,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// # Parameters /// /// - `def_id`, the `impl Trait` type - /// - `opaque_defn`, the opaque definition created in `instantiate_opaque_types` + /// - `substs`, the substs used to instantiate this opaque type /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of /// `opaque_defn.concrete_ty` pub fn infer_opaque_definition_from_instantiation( &self, def_id: DefId, - opaque_defn: &OpaqueTypeDecl<'tcx>, + substs: SubstsRef<'tcx>, instantiated_ty: Ty<'tcx>, span: Span, ) -> Ty<'tcx> { @@ -572,12 +572,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // `impl Trait` return type, resulting in the parameters // shifting. let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); - let map: FxHashMap, GenericArg<'tcx>> = opaque_defn - .substs - .iter() - .enumerate() - .map(|(index, subst)| (*subst, id_substs[index])) - .collect(); + let map: FxHashMap, GenericArg<'tcx>> = + substs.iter().enumerate().map(|(index, subst)| (*subst, id_substs[index])).collect(); // Convert the type from the function into a type valid outside // the function, by replacing invalid regions with 'static, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index b4798fb67f80f..758ce6b5222f8 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -444,7 +444,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // figures out the concrete type with `U`, but the stored type is with `T`. let definition_ty = self.fcx.infer_opaque_definition_from_instantiation( def_id, - opaque_defn, + opaque_defn.substs, instantiated_ty, span, ); From 378b5b4ca06d027d9dfff807fe0fff4bc5e62806 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 26 Dec 2019 17:51:39 +0000 Subject: [PATCH 07/25] Generate more accurate MIR in `construct_error` --- src/librustc_mir_build/build/mod.rs | 47 ++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index 32b1f2b6e1368..5f8c0b027e96a 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -670,14 +670,51 @@ fn construct_const<'a, 'tcx>( builder.finish() } +/// Construct MIR for a item that has had errors in type checking. +/// +/// This is required because we may still want to run MIR passes on an item +/// with type errors, but normal MIR construction can't handle that in general. fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'tcx> { - let owner_id = hir.tcx().hir().body_owner(body_id); - let span = hir.tcx().hir().span(owner_id); - let ty = hir.tcx().types.err; - let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, None); + let tcx = hir.tcx(); + let owner_id = tcx.hir().body_owner(body_id); + let span = tcx.hir().span(owner_id); + let ty = tcx.types.err; + let num_params = match hir.body_owner_kind { + hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len(), + hir::BodyOwnerKind::Closure => { + if tcx.hir().body(body_id).generator_kind().is_some() { + // Generators have an implicit `self` parameter *and* a possibly + // implicit resume parameter. + 2 + } else { + // The implicit self parameter adds another local in MIR. + 1 + tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len() + } + } + hir::BodyOwnerKind::Const => 0, + hir::BodyOwnerKind::Static(_) => 0, + }; + let mut builder = Builder::new(hir, span, num_params, Safety::Safe, ty, span, None); let source_info = builder.source_info(span); + // Some MIR passes will expect the number of parameters to match the + // function declaration. + for _ in 0..num_params { + builder.local_decls.push(LocalDecl { + mutability: Mutability::Mut, + ty, + user_ty: UserTypeProjections::none(), + source_info, + internal: false, + local_info: LocalInfo::Other, + is_block_tail: None, + }); + } builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); - builder.finish() + let mut body = builder.finish(); + if tcx.hir().body(body_id).generator_kind.is_some() { + body.yield_ty = Some(ty); + } + body } impl<'a, 'tcx> Builder<'a, 'tcx> { From 43a3348fd94568b78db7755bb5196fc73fa65214 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 26 Dec 2019 17:26:53 +0000 Subject: [PATCH 08/25] Arena allocate the result of mir_borrowck --- src/librustc/arena.rs | 3 ++- src/librustc/query/mod.rs | 15 ++++++--------- src/librustc_mir/borrow_check/mod.rs | 4 ++-- src/librustc_mir/borrow_check/type_check/mod.rs | 3 ++- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index dd242686d26f2..33cbf6ede0a01 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -35,7 +35,8 @@ macro_rules! arena_types { rustc::mir::Promoted, rustc::mir::BodyAndCache<$tcx> >, - [] tables: rustc::ty::TypeckTables<$tcx>, + [decode] tables: rustc::ty::TypeckTables<$tcx>, + [decode] borrowck_result: rustc::mir::BorrowCheckResult<$tcx>, [] const_allocs: rustc::mir::interpret::Allocation, [] vtable_method: Option<( rustc_hir::def_id::DefId, diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 1cc7c7a1c69a8..5e279975d152d 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -419,13 +419,6 @@ rustc_queries! { query typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> { desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } - load_cached(tcx, id) { - let typeck_tables: Option> = tcx - .queries.on_disk_cache - .try_load_query_result(tcx, id); - - typeck_tables.map(|tables| &*tcx.arena.alloc(tables)) - } } query diagnostic_only_typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> { cache_on_disk_if { key.is_local() } @@ -456,9 +449,13 @@ rustc_queries! { BorrowChecking { /// Borrow-checks the function body. If this is a closure, returns /// additional requirements that the closure's creator must verify. - query mir_borrowck(key: DefId) -> mir::BorrowCheckResult<'tcx> { + query mir_borrowck(key: DefId) -> &'tcx mir::BorrowCheckResult<'tcx> { desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if(tcx, _) { key.is_local() && tcx.is_closure(key) } + cache_on_disk_if(tcx, opt_result) { + key.is_local() + && (tcx.is_closure(key) + || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())) + } } } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 941534e68fcad..07d3a12fb20d8 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -90,7 +90,7 @@ pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { mir_borrowck, ..*providers }; } -fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> { +fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> &BorrowCheckResult<'_> { let (input_body, promoted) = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id)); @@ -101,7 +101,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> { }); debug!("mir_borrowck done"); - opt_closure_req + tcx.arena.alloc(opt_closure_req) } fn do_mir_borrowck<'a, 'tcx>( diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 5dab064c7b7fc..67dbf8a2b6d24 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -2512,7 +2512,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { substs: SubstsRef<'tcx>, location: Location, ) -> ty::InstantiatedPredicates<'tcx> { - if let Some(closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements { + if let Some(ref closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements + { let closure_constraints = QueryRegionConstraints { outlives: closure_region_requirements.apply_requirements(tcx, def_id, substs), From 75ac0cca3678d5d309c737f1bd8ef237628a278b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 25 Dec 2019 09:50:07 +0000 Subject: [PATCH 09/25] Prepare to use borrowck to resolve opaque types --- src/librustc/mir/query.rs | 8 +- src/librustc_mir/borrow_check/mod.rs | 32 +++--- src/librustc_mir/borrow_check/nll.rs | 32 +++--- .../borrow_check/type_check/mod.rs | 101 +++++++++++------- src/librustc_typeck/collect.rs | 23 +++- 5 files changed, 128 insertions(+), 68 deletions(-) diff --git a/src/librustc/mir/query.rs b/src/librustc/mir/query.rs index 34f58ab89b107..824cdfe55bfb6 100644 --- a/src/librustc/mir/query.rs +++ b/src/librustc/mir/query.rs @@ -1,8 +1,10 @@ //! Values computed by queries that use MIR. use crate::ty::{self, Ty}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; +use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitMatrix; use rustc_index::vec::IndexVec; use rustc_span::{Span, Symbol}; @@ -59,8 +61,12 @@ pub struct GeneratorLayout<'tcx> { pub storage_conflicts: BitMatrix, } -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct BorrowCheckResult<'tcx> { + /// All the opaque types that are restricted to concrete types + /// by this function. Unlike the value in `TypeckTables`, this has + /// unerased regions. + pub concrete_opaque_types: FxHashMap>, pub closure_requirements: Option>, pub used_mut_upvars: SmallVec<[Field; 8]>, } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 07d3a12fb20d8..1843d4bf72dc6 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -195,19 +195,24 @@ fn do_mir_borrowck<'a, 'tcx>( Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); // Compute non-lexical lifetimes. - let nll::NllOutput { regioncx, polonius_output, opt_closure_req, nll_errors } = - nll::compute_regions( - infcx, - def_id, - free_regions, - body, - &promoted, - location_table, - param_env, - &mut flow_inits, - &mdpe.move_data, - &borrow_set, - ); + let nll::NllOutput { + regioncx, + opaque_type_values, + polonius_output, + opt_closure_req, + nll_errors, + } = nll::compute_regions( + infcx, + def_id, + free_regions, + body, + &promoted, + location_table, + param_env, + &mut flow_inits, + &mdpe.move_data, + &borrow_set, + ); // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. @@ -389,6 +394,7 @@ fn do_mir_borrowck<'a, 'tcx>( } let result = BorrowCheckResult { + concrete_opaque_types: opaque_type_values, closure_requirements: opt_closure_req, used_mut_upvars: mbcx.used_mut_upvars, }; diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index a71dfc9a7780f..4acf1cf7c2b9a 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -6,6 +6,7 @@ use rustc::mir::{ Location, Promoted, ReadOnlyBodyAndCache, }; use rustc::ty::{self, RegionKind, RegionVid}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::Diagnostic; use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; @@ -46,6 +47,7 @@ crate type PoloniusOutput = Output; /// closure requirements to propagate, and any generated errors. crate struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, + pub opaque_type_values: FxHashMap>, pub polonius_output: Option>, pub opt_closure_req: Option>, pub nll_errors: RegionErrors<'tcx>, @@ -160,20 +162,21 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( let elements = &Rc::new(RegionValueElements::new(&body)); // Run the MIR type-checker. - let MirTypeckResults { constraints, universal_region_relations } = type_check::type_check( - infcx, - param_env, - body, - promoted, - def_id, - &universal_regions, - location_table, - borrow_set, - &mut all_facts, - flow_inits, - move_data, - elements, - ); + let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = + type_check::type_check( + infcx, + param_env, + body, + promoted, + def_id, + &universal_regions, + location_table, + borrow_set, + &mut all_facts, + flow_inits, + move_data, + elements, + ); if let Some(all_facts) = &mut all_facts { let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation"); @@ -281,6 +284,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( NllOutput { regioncx, + opaque_type_values, polonius_output, opt_closure_req: closure_region_requirements, nll_errors, diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 67dbf8a2b6d24..c6809f9e37e86 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -158,7 +158,7 @@ pub(crate) fn type_check<'mir, 'tcx>( constraints: &mut constraints, }; - type_check_internal( + let opaque_type_values = type_check_internal( infcx, mir_def_id, param_env, @@ -173,10 +173,11 @@ pub(crate) fn type_check<'mir, 'tcx>( liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); translate_outlives_facts(&mut cx); + cx.opaque_type_values }, ); - MirTypeckResults { constraints, universal_region_relations } + MirTypeckResults { constraints, universal_region_relations, opaque_type_values } } fn type_check_internal<'a, 'tcx, R>( @@ -189,7 +190,7 @@ fn type_check_internal<'a, 'tcx, R>( implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, universal_region_relations: &'a UniversalRegionRelations<'tcx>, - mut extra: impl FnMut(&mut TypeChecker<'a, 'tcx>) -> R, + extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R, ) -> R { let mut checker = TypeChecker::new( infcx, @@ -212,7 +213,7 @@ fn type_check_internal<'a, 'tcx, R>( checker.typeck_mir(body); } - extra(&mut checker) + extra(checker) } fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { @@ -799,6 +800,7 @@ struct TypeChecker<'a, 'tcx> { reported_errors: FxHashSet<(Ty<'tcx>, Span)>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, universal_region_relations: &'a UniversalRegionRelations<'tcx>, + opaque_type_values: FxHashMap>, } struct BorrowCheckContext<'a, 'tcx> { @@ -812,6 +814,7 @@ struct BorrowCheckContext<'a, 'tcx> { crate struct MirTypeckResults<'tcx> { crate constraints: MirTypeckRegionConstraints<'tcx>, crate universal_region_relations: Rc>, + crate opaque_type_values: FxHashMap>, } /// A collection of region constraints that must be satisfied for the @@ -958,6 +961,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { borrowck_context, reported_errors: Default::default(), universal_region_relations, + opaque_type_values: FxHashMap::default(), }; checker.check_user_type_annotations(); checker @@ -1195,6 +1199,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let tcx = infcx.tcx; let param_env = self.param_env; let body = self.body; + let concrete_opaque_types = &tcx.typeck_tables_of(anon_owner_def_id).concrete_opaque_types; + let mut opaque_type_values = Vec::new(); + debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id); let opaque_type_map = self.fully_perform_op( locations, @@ -1226,47 +1233,65 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); for (&opaque_def_id, opaque_decl) in &opaque_type_map { - let opaque_defn_ty = tcx.type_of(opaque_def_id); - let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs); - let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty); - let concrete_is_opaque = infcx - .resolve_vars_if_possible(&opaque_decl.concrete_ty) - .is_impl_trait(); + let resolved_ty = infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty); + let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind { + def_id == opaque_def_id + } else { + false + }; + let opaque_defn_ty = match concrete_opaque_types.get(&opaque_def_id) { + None => { + assert!( + concrete_is_opaque, + "Non-defining use of {:?} with revealed type", + opaque_def_id, + ); + continue; + } + Some(opaque_defn_ty) => opaque_defn_ty, + }; + debug!("opaque_defn_ty = {:?}", opaque_defn_ty); + let subst_opaque_defn_ty = + opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs); + let renumbered_opaque_defn_ty = + renumber::renumber_regions(infcx, &subst_opaque_defn_ty); debug!( - "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?} \ - concrete_is_opaque={}", - opaque_decl.concrete_ty, - infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty), - opaque_defn_ty, - concrete_is_opaque + "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}", + opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty, ); - // concrete_is_opaque is `true` when we're using an opaque `impl Trait` - // type without 'revealing' it. For example, code like this: - // - // type Foo = impl Debug; - // fn foo1() -> Foo { ... } - // fn foo2() -> Foo { foo1() } - // - // In `foo2`, we're not revealing the type of `Foo` - we're - // just treating it as the opaque type. - // - // When this occurs, we do *not* want to try to equate - // the concrete type with the underlying defining type - // of the opaque type - this will always fail, since - // the defining type of an opaque type is always - // some other type (e.g. not itself) - // Essentially, none of the normal obligations apply here - - // we're just passing around some unknown opaque type, - // without actually looking at the underlying type it - // gets 'revealed' into - if !concrete_is_opaque { obligations.add( infcx .at(&ObligationCause::dummy(), param_env) - .eq(opaque_decl.concrete_ty, opaque_defn_ty)?, + .eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?, + ); + opaque_type_values + .push((opaque_def_id, ty::ResolvedOpaqueTy { ..*opaque_defn_ty })); + } else { + // We're using an opaque `impl Trait` type without + // 'revealing' it. For example, code like this: + // + // type Foo = impl Debug; + // fn foo1() -> Foo { ... } + // fn foo2() -> Foo { foo1() } + // + // In `foo2`, we're not revealing the type of `Foo` - we're + // just treating it as the opaque type. + // + // When this occurs, we do *not* want to try to equate + // the concrete type with the underlying defining type + // of the opaque type - this will always fail, since + // the defining type of an opaque type is always + // some other type (e.g. not itself) + // Essentially, none of the normal obligations apply here - + // we're just passing around some unknown opaque type, + // without actually looking at the underlying type it + // gets 'revealed' into + debug!( + "eq_opaque_type_and_type: non-defining use of {:?}", + opaque_def_id, ); } } @@ -1282,6 +1307,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ), )?; + self.opaque_type_values.extend(opaque_type_values); + let universal_region_relations = self.universal_region_relations; // Finally, if we instantiated the anon types successfully, we diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 5349c324ad8a7..cf82789482bc3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1464,7 +1464,7 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } // Opaque types desugared from `impl Trait`. ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(owner), .. }) => { - tcx.typeck_tables_of(owner) + tcx.mir_borrowck(owner) .concrete_opaque_types .get(&def_id) .map(|opaque| opaque.concrete_type) @@ -1687,7 +1687,7 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { - use rustc_hir::{ImplItem, Item, TraitItem}; + use rustc_hir::{Expr, ImplItem, Item, TraitItem}; debug!("find_opaque_ty_constraints({:?})", def_id); @@ -1713,7 +1713,17 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { ); return; } - let ty = self.tcx.typeck_tables_of(def_id).concrete_opaque_types.get(&self.def_id); + // Calling `mir_borrowck` can lead to cycle errors through + // const-checking, avoid calling it if we don't have to. + if !self.tcx.typeck_tables_of(def_id).concrete_opaque_types.contains_key(&self.def_id) { + debug!( + "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", + self.def_id, def_id, + ); + return; + } + // Use borrowck to get the type with unerased regions. + let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id); if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty { debug!( "find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}", @@ -1856,6 +1866,13 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> { intravisit::NestedVisitorMap::All(&self.tcx.hir()) } + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + if let hir::ExprKind::Closure(..) = ex.kind { + let def_id = self.tcx.hir().local_def_id(ex.hir_id); + self.check(def_id); + } + intravisit::walk_expr(self, ex); + } fn visit_item(&mut self, it: &'tcx Item<'tcx>) { debug!("find_existential_constraints: visiting {:?}", it); let def_id = self.tcx.hir().local_def_id(it.hir_id); From d9b9f00109aefcaf565c9da3c6fdf9e446f4876c Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 26 Dec 2019 21:16:28 +0000 Subject: [PATCH 10/25] Infer opaque type regions in borrow checking We want type checking for function bodies to ignore/erase regions. As such, we need to infer the regions in opaque types in borrow check instead. --- src/librustc_mir/borrow_check/nll.rs | 4 +- .../borrow_check/region_infer/mod.rs | 1 + .../borrow_check/region_infer/opaque_types.rs | 72 +++++++++++++++++++ .../borrow_check/type_check/mod.rs | 9 ++- 4 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 src/librustc_mir/borrow_check/region_infer/opaque_types.rs diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index 4acf1cf7c2b9a..e4e5fe35d7f92 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -282,9 +282,11 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( let (closure_region_requirements, nll_errors) = regioncx.solve(infcx, &body, def_id, polonius_output.clone()); + let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values, body.span); + NllOutput { regioncx, - opaque_type_values, + opaque_type_values: remapped_opaque_tys, polonius_output, opt_closure_req: closure_region_requirements, nll_errors, diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 6abca481eac9c..4a2f398c6d508 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -36,6 +36,7 @@ use crate::borrow_check::{ mod dump_mir; mod graphviz; +mod opaque_types; pub mod values; diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs new file mode 100644 index 0000000000000..e16a2c838ebe9 --- /dev/null +++ b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs @@ -0,0 +1,72 @@ +use rustc::hir::def_id::DefId; +use rustc::infer::InferCtxt; +use rustc::ty; +use rustc_data_structures::fx::FxHashMap; +use rustc_span::Span; + +use super::RegionInferenceContext; + +impl<'tcx> RegionInferenceContext<'tcx> { + /// Resolve any opaque types that were encountered while borrow checking + /// this item. This is then used to get the type in the `type_of` query. + pub(in crate::borrow_check) fn infer_opaque_types( + &self, + infcx: &InferCtxt<'_, 'tcx>, + opaque_ty_decls: FxHashMap>, + span: Span, + ) -> FxHashMap> { + opaque_ty_decls + .into_iter() + .map(|(opaque_def_id, ty::ResolvedOpaqueTy { concrete_type, substs })| { + debug!( + "infer_opaque_types(concrete_type = {:?}, substs = {:?})", + concrete_type, substs + ); + + // Map back to "concrete" regions so that errors in + // `infer_opaque_definition_from_instantiation` can show + // sensible region names. + let universal_concrete_type = + infcx.tcx.fold_regions(&concrete_type, &mut false, |region, _| match region { + &ty::ReVar(vid) => { + let universal_bound = self.universal_upper_bound(vid); + self.definitions[universal_bound] + .external_name + .filter(|_| self.eval_equal(universal_bound, vid)) + .unwrap_or(infcx.tcx.lifetimes.re_empty) + } + concrete => concrete, + }); + let universal_substs = + infcx.tcx.fold_regions(&substs, &mut false, |region, _| match region { + ty::ReVar(vid) => { + self.definitions[*vid].external_name.unwrap_or_else(|| { + infcx.tcx.sess.delay_span_bug( + span, + "opaque type with non-universal region substs", + ); + infcx.tcx.lifetimes.re_static + }) + } + concrete => concrete, + }); + + debug!( + "infer_opaque_types(universal_concrete_type = {:?}, universal_substs = {:?})", + universal_concrete_type, universal_substs + ); + + let remapped_type = infcx.infer_opaque_definition_from_instantiation( + opaque_def_id, + universal_substs, + universal_concrete_type, + span, + ); + ( + opaque_def_id, + ty::ResolvedOpaqueTy { concrete_type: remapped_type, substs: universal_substs }, + ) + }) + .collect() + } +} diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index c6809f9e37e86..5c6f3a0ffa975 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1267,8 +1267,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .at(&ObligationCause::dummy(), param_env) .eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?, ); - opaque_type_values - .push((opaque_def_id, ty::ResolvedOpaqueTy { ..*opaque_defn_ty })); + opaque_type_values.push(( + opaque_def_id, + ty::ResolvedOpaqueTy { + concrete_type: renumbered_opaque_defn_ty, + substs: opaque_decl.substs, + }, + )); } else { // We're using an opaque `impl Trait` type without // 'revealing' it. For example, code like this: From edee23ee25d813547587fdd6bcd3677606839fad Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 28 Dec 2019 15:50:06 +0000 Subject: [PATCH 11/25] Avoid unnecessary opaque type errors in borrowck --- src/librustc_mir/borrow_check/mod.rs | 3 +++ src/librustc_mir/borrow_check/nll.rs | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 1843d4bf72dc6..da9bdc8b4b015 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -136,6 +136,9 @@ fn do_mir_borrowck<'a, 'tcx>( // Gather the upvars of a closure, if any. let tables = tcx.typeck_tables_of(def_id); + if tables.tainted_by_errors { + infcx.set_tainted_by_errors(); + } let upvars: Vec<_> = tables .upvar_list .get(&def_id) diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index e4e5fe35d7f92..4c1ee9582c1f2 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -282,6 +282,11 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( let (closure_region_requirements, nll_errors) = regioncx.solve(infcx, &body, def_id, polonius_output.clone()); + if !nll_errors.is_empty() { + // Suppress unhelpful extra errors in `infer_opaque_types`. + infcx.set_tainted_by_errors(); + } + let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values, body.span); NllOutput { From 2fb02549b85258a039cc8cb6006c028ab437f85a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 28 Dec 2019 15:50:39 +0000 Subject: [PATCH 12/25] Ensure RPIT types get recorded in borrowck --- .../borrow_check/type_check/input_output.rs | 2 ++ .../borrow_check/type_check/mod.rs | 32 +++++++++++++++---- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs index 3d3b1e5cbf6a9..1f1106f054555 100644 --- a/src/librustc_mir/borrow_check/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/type_check/input_output.rs @@ -120,6 +120,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.mir_def_id, Locations::All(output_span), ConstraintCategory::BoringNoLocation, + true, ) { span_mirbug!( self, @@ -143,6 +144,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.mir_def_id, Locations::All(output_span), ConstraintCategory::BoringNoLocation, + false, ) { span_mirbug!( self, diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 5c6f3a0ffa975..e7b4471586503 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1122,7 +1122,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // the resulting inferend values are stored with the // def-id of the base function. let parent_def_id = self.tcx().closure_base_def_id(self.mir_def_id); - return self.eq_opaque_type_and_type(sub, sup, parent_def_id, locations, category); + return self.eq_opaque_type_and_type( + sub, + sup, + parent_def_id, + locations, + category, + false, + ); } else { return Err(terr); } @@ -1188,6 +1195,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { anon_owner_def_id: DefId, locations: Locations, category: ConstraintCategory, + is_function_return: bool, ) -> Fallible<()> { debug!( "eq_opaque_type_and_type( \ @@ -1241,11 +1249,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }; let opaque_defn_ty = match concrete_opaque_types.get(&opaque_def_id) { None => { - assert!( - concrete_is_opaque, - "Non-defining use of {:?} with revealed type", - opaque_def_id, - ); + if !concrete_is_opaque { + tcx.sess.delay_span_bug( + body.span, + &format!( + "Non-defining use of {:?} with revealed type", + opaque_def_id, + ), + ); + } continue; } Some(opaque_defn_ty) => opaque_defn_ty, @@ -1261,7 +1273,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty, ); - if !concrete_is_opaque { + if !concrete_is_opaque + || (is_function_return + && matches!(opaque_decl.origin, hir::OpaqueTyOrigin::FnReturn)) + { + // For return position impl Trait, the function + // return is the only possible definition site, so + // always record it. obligations.add( infcx .at(&ObligationCause::dummy(), param_env) From bb8c9911f591b2f72d5d473acab3c27ef9ae1a46 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 28 Dec 2019 15:52:51 +0000 Subject: [PATCH 13/25] Erase regions in opaque types in typeck --- src/librustc/infer/opaque_types/mod.rs | 37 +++++++++++++++----------- src/librustc/ty/fold.rs | 4 +++ src/librustc/ty/mod.rs | 10 ++++--- src/librustc/ty/sty.rs | 4 ++- src/librustc_typeck/check/writeback.rs | 3 ++- src/librustc_typeck/collect.rs | 34 ++++++++++++++++++----- 6 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 1d69f598256f2..088e57f91a7a5 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -814,32 +814,37 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r { - // ignore bound regions that appear in the type (e.g., this - // would ignore `'r` in a type like `for<'r> fn(&'r u32)`. - ty::ReLateBound(..) | + // Ignore bound regions that appear in the type, they don't need to + // be remapped (e.g., this would ignore `'r` in a type like + // `for<'r> fn(&'r u32)`. + ty::ReLateBound(..) + + // If regions have been erased, don't try to unerase them. + | ty::ReErased // ignore `'static`, as that can appear anywhere - ty::ReStatic => return r, + | ty::ReStatic => return r, - _ => { } + _ => {} } let generics = self.tcx().generics_of(self.opaque_type_def_id); match self.map.get(&r.into()).map(|k| k.unpack()) { Some(GenericArgKind::Lifetime(r1)) => r1, Some(u) => panic!("region mapped to unexpected kind: {:?}", u), + None if self.map_missing_regions_to_empty || self.tainted_by_errors => { + self.tcx.lifetimes.re_empty + } None if generics.parent.is_some() => { - if !self.map_missing_regions_to_empty && !self.tainted_by_errors { - if let Some(hidden_ty) = self.hidden_ty.take() { - unexpected_hidden_region_diagnostic( - self.tcx, - None, - self.opaque_type_def_id, - hidden_ty, - r, - ) - .emit(); - } + if let Some(hidden_ty) = self.hidden_ty.take() { + unexpected_hidden_region_diagnostic( + self.tcx, + None, + self.opaque_type_def_id, + hidden_ty, + r, + ) + .emit(); } self.tcx.lifetimes.re_root_empty } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 1f007b970b0ca..5ff0d04c1ed24 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -120,6 +120,10 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) } + fn has_erased_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_ERASED) + } + /// True if there are any un-erased free regions. fn has_erasable_regions(&self) -> bool { self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b67cab65207ec..6d36116d782e6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -474,10 +474,13 @@ bitflags! { /// if a global bound is safe to evaluate. const HAS_RE_LATE_BOUND = 1 << 11; - const HAS_TY_PLACEHOLDER = 1 << 12; + /// Does this have any `ReErased` regions? + const HAS_RE_ERASED = 1 << 12; - const HAS_CT_INFER = 1 << 13; - const HAS_CT_PLACEHOLDER = 1 << 14; + const HAS_TY_PLACEHOLDER = 1 << 13; + + const HAS_CT_INFER = 1 << 14; + const HAS_CT_PLACEHOLDER = 1 << 15; const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits; @@ -497,6 +500,7 @@ bitflags! { TypeFlags::HAS_FREE_LOCAL_NAMES.bits | TypeFlags::KEEP_IN_LOCAL_TCX.bits | TypeFlags::HAS_RE_LATE_BOUND.bits | + TypeFlags::HAS_RE_ERASED.bits | TypeFlags::HAS_TY_PLACEHOLDER.bits | TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_CT_PLACEHOLDER.bits; diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0718853b1df59..02abac975ac84 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1777,7 +1777,9 @@ impl RegionKind { ty::ReEmpty(_) | ty::ReStatic | ty::ReFree { .. } | ty::ReScope { .. } => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } - ty::ReErased => {} + ty::ReErased => { + flags = flags | TypeFlags::HAS_RE_ERASED; + } ty::ReClosureBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 758ce6b5222f8..3a1622f1649e5 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -426,7 +426,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_opaque_types(&mut self, span: Span) { for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() { let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap(); - let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id); + let instantiated_ty = + self.tcx().erase_regions(&self.resolve(&opaque_defn.concrete_ty, &hir_id)); debug_assert!(!instantiated_ty.has_escaping_bound_vars()); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index cf82789482bc3..4448c067d348b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -33,8 +33,8 @@ use rustc::ty::subst::GenericArgKind; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::util::Discr; use rustc::ty::util::IntTypeExt; -use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, WithConstness}; -use rustc::ty::{ReprOptions, ToPredicate}; +use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{ReprOptions, ToPredicate, WithConstness}; use rustc_attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; @@ -1463,9 +1463,22 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { find_opaque_ty_constraints(tcx, def_id) } // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(owner), .. }) => { - tcx.mir_borrowck(owner) - .concrete_opaque_types + ItemKind::OpaqueTy(hir::OpaqueTy { + impl_trait_fn: Some(owner), origin, .. + }) => { + let concrete_types = match origin { + hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => { + &tcx.mir_borrowck(owner).concrete_opaque_types + } + hir::OpaqueTyOrigin::Misc => { + // We shouldn't leak borrowck results through impl Trait in bindings. + &tcx.typeck_tables_of(owner).concrete_opaque_types + } + hir::OpaqueTyOrigin::TypeAlias => { + span_bug!(item.span, "Type alias impl trait shouldn't have an owner") + } + }; + let concrete_ty = concrete_types .get(&def_id) .map(|opaque| opaque.concrete_type) .unwrap_or_else(|| { @@ -1480,7 +1493,16 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { ), ); tcx.types.err - }) + }); + debug!("concrete_ty = {:?}", concrete_ty); + if concrete_ty.has_erased_regions() { + // FIXME(impl_trait_in_bindings) Handle this case. + tcx.sess.span_fatal( + item.span, + "lifetimes in impl Trait types in bindings are not currently supported", + ); + } + concrete_ty } ItemKind::Trait(..) | ItemKind::TraitAlias(..) From 93ac5bc7de2b47f8848275254a0e327269ee5f06 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 28 Dec 2019 15:54:27 +0000 Subject: [PATCH 14/25] Update tests --- .../ui/consts/min_const_fn/min_const_fn.rs | 3 - .../consts/min_const_fn/min_const_fn.stderr | 34 ++---- .../min_const_fn/min_const_fn_impl_trait.rs | 9 ++ .../min_const_fn_impl_trait.stderr | 21 ++++ .../feature-gate-member-constraints.rs | 5 +- .../feature-gate-member-constraints.stderr | 10 +- src/test/ui/impl-trait/auto-trait-leak.stderr | 100 ++++++++++++++++++ .../recursive-impl-trait-type-direct.rs | 5 +- .../recursive-impl-trait-type-direct.stderr | 2 +- .../recursive-impl-trait-type-indirect.rs | 65 ++++++++---- .../recursive-impl-trait-type-indirect.stderr | 42 ++++---- src/test/ui/lint/lint-unused-mut-variables.rs | 52 ++++----- .../ui/lint/lint-unused-mut-variables.stderr | 68 ++++++------ .../generic_duplicate_param_use6.rs | 6 +- .../generic_duplicate_param_use6.stderr | 4 +- .../issue-52843-closure-constrain.rs | 2 +- .../issue-52843-closure-constrain.stderr | 18 ++-- .../ui/type-alias-impl-trait/issue-60564.rs | 2 +- 18 files changed, 291 insertions(+), 157 deletions(-) create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index c3436d4840ac7..557439f394953 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -123,12 +123,9 @@ impl Foo { } struct AlanTuring(T); -const fn no_rpit2() -> AlanTuring { AlanTuring(0) } -//~^ ERROR `impl Trait` in const fn is unstable const fn no_apit2(_x: AlanTuring) {} //~^ ERROR trait bounds other than `Sized` const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` -const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~^ ERROR trait bounds other than `Sized` diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index 927cdfae189d7..512b343011b40 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -214,17 +214,8 @@ LL | impl Foo { = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: `impl Trait` in const fn is unstable - --> $DIR/min_const_fn.rs:126:24 - | -LL | const fn no_rpit2() -> AlanTuring { AlanTuring(0) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:128:34 + --> $DIR/min_const_fn.rs:126:34 | LL | const fn no_apit2(_x: AlanTuring) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +224,7 @@ LL | const fn no_apit2(_x: AlanTuring) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:130:22 + --> $DIR/min_const_fn.rs:128:22 | LL | const fn no_apit(_x: impl std::fmt::Debug) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -241,17 +232,8 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {} = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: `impl Trait` in const fn is unstable - --> $DIR/min_const_fn.rs:131:23 - | -LL | const fn no_rpit() -> impl std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:132:23 + --> $DIR/min_const_fn.rs:129:23 | LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} | ^^ @@ -260,7 +242,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:133:32 + --> $DIR/min_const_fn.rs:130:32 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -269,7 +251,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:138:41 + --> $DIR/min_const_fn.rs:135:41 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -278,7 +260,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:141:21 + --> $DIR/min_const_fn.rs:138:21 | LL | const fn no_fn_ptrs(_x: fn()) {} | ^^ @@ -287,7 +269,7 @@ LL | const fn no_fn_ptrs(_x: fn()) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:143:27 + --> $DIR/min_const_fn.rs:140:27 | LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } | ^^^^ @@ -295,7 +277,7 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error: aborting due to 34 previous errors +error: aborting due to 32 previous errors Some errors have detailed explanations: E0493, E0723. For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs new file mode 100644 index 0000000000000..9cc9b69ac0b6c --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs @@ -0,0 +1,9 @@ +struct AlanTuring(T); +const fn no_rpit2() -> AlanTuring { + //~^ ERROR `impl Trait` in const fn is unstable + AlanTuring(0) +} + +const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr new file mode 100644 index 0000000000000..a62a340332db2 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr @@ -0,0 +1,21 @@ +error[E0723]: `impl Trait` in const fn is unstable + --> $DIR/min_const_fn_impl_trait.rs:2:24 + | +LL | const fn no_rpit2() -> AlanTuring { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0723]: `impl Trait` in const fn is unstable + --> $DIR/min_const_fn_impl_trait.rs:7:23 + | +LL | const fn no_rpit() -> impl std::fmt::Debug {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.rs b/src/test/ui/feature-gates/feature-gate-member-constraints.rs index 293a93352e641..f6a92b0d0bfb5 100644 --- a/src/test/ui/feature-gates/feature-gate-member-constraints.rs +++ b/src/test/ui/feature-gates/feature-gate-member-constraints.rs @@ -1,9 +1,10 @@ -trait Trait<'a, 'b> { } +trait Trait<'a, 'b> {} impl Trait<'_, '_> for T {} fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { //~^ ERROR ambiguous lifetime bound + //~| ERROR ambiguous lifetime bound (x, y) } -fn main() { } +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr index 3745d5e1c59d6..c2ec7ae16a3a6 100644 --- a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr +++ b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr @@ -6,5 +6,13 @@ LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { | = help: add #![feature(member_constraints)] to the crate attributes to enable -error: aborting due to previous error +error: ambiguous lifetime bound in `impl Trait` + --> $DIR/feature-gate-member-constraints.rs:4:43 + | +LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { + | ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another + | + = help: add #![feature(member_constraints)] to the crate attributes to enable + +error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 0ebaac8945050..981fad57b0fff 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -4,9 +4,34 @@ error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ | +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... @@ -15,9 +40,34 @@ note: ...which requires processing `cycle2::{{opaque}}#0`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... @@ -40,9 +90,34 @@ error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ | +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... @@ -51,6 +126,11 @@ note: ...which requires processing `cycle2::{{opaque}}#0`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | @@ -89,6 +169,26 @@ LL | fn cycle2() -> impl Clone { note: ...which requires processing `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs index 2b4f5e0975ac3..3cc537440977c 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs @@ -1,6 +1,9 @@ // Test that an `impl Trait` type that expands to itself is an error. -fn test() -> impl Sized { //~ ERROR E0720 +#![allow(unconditional_recursion)] + +fn test() -> impl Sized { + //~^ ERROR E0720 test() } diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr index 1b5dbd814a481..5a95e2969d1b0 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr @@ -1,5 +1,5 @@ error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-direct.rs:3:14 + --> $DIR/recursive-impl-trait-type-direct.rs:5:14 | LL | fn test() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs index 2428b560b7001..e3c621f0c5742 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -2,59 +2,75 @@ // otherwise forbidden. #![feature(generators)] +#![allow(unconditional_recursion)] -fn option(i: i32) -> impl Sized { //~ ERROR - if i < 0 { - None - } else { - Some((option(i - 1), i)) - } +fn option(i: i32) -> impl Sized { + //~^ ERROR + if i < 0 { None } else { Some((option(i - 1), i)) } } -fn tuple() -> impl Sized { //~ ERROR +fn tuple() -> impl Sized { + //~^ ERROR (tuple(),) } -fn array() -> impl Sized { //~ ERROR +fn array() -> impl Sized { + //~^ ERROR [array()] } -fn ptr() -> impl Sized { //~ ERROR +fn ptr() -> impl Sized { + //~^ ERROR &ptr() as *const _ } -fn fn_ptr() -> impl Sized { //~ ERROR +fn fn_ptr() -> impl Sized { + //~^ ERROR fn_ptr as fn() -> _ } -fn closure_capture() -> impl Sized { //~ ERROR +fn closure_capture() -> impl Sized { + //~^ ERROR let x = closure_capture(); - move || { x; } + move || { + x; + } } -fn closure_ref_capture() -> impl Sized { //~ ERROR +fn closure_ref_capture() -> impl Sized { + //~^ ERROR let x = closure_ref_capture(); - move || { &x; } + move || { + &x; + } } -fn closure_sig() -> impl Sized { //~ ERROR +fn closure_sig() -> impl Sized { + //~^ ERROR || closure_sig() } -fn generator_sig() -> impl Sized { //~ ERROR +fn generator_sig() -> impl Sized { + //~^ ERROR || generator_sig() } -fn generator_capture() -> impl Sized { //~ ERROR +fn generator_capture() -> impl Sized { + //~^ ERROR let x = generator_capture(); - move || { yield; x; } + move || { + yield; + x; + } } -fn substs_change() -> impl Sized { //~ ERROR +fn substs_change() -> impl Sized { + //~^ ERROR (substs_change::<&T>(),) } -fn generator_hold() -> impl Sized { //~ ERROR +fn generator_hold() -> impl Sized { + //~^ ERROR move || { let x = generator_hold(); yield; @@ -62,15 +78,18 @@ fn generator_hold() -> impl Sized { //~ ERROR } } -fn use_fn_ptr() -> impl Sized { // OK, error already reported +fn use_fn_ptr() -> impl Sized { + // OK, error already reported fn_ptr() } -fn mutual_recursion() -> impl Sync { //~ ERROR +fn mutual_recursion() -> impl Sync { + //~^ ERROR mutual_recursion_b() } -fn mutual_recursion_b() -> impl Sized { //~ ERROR +fn mutual_recursion_b() -> impl Sized { + //~^ ERROR mutual_recursion() } diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index b7ba0d6ab177c..6573b00870c5b 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -1,5 +1,5 @@ error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:6:22 + --> $DIR/recursive-impl-trait-type-indirect.rs:7:22 | LL | fn option(i: i32) -> impl Sized { | ^^^^^^^^^^ expands to a recursive type @@ -7,7 +7,7 @@ LL | fn option(i: i32) -> impl Sized { = note: expanded type is `std::option::Option<(impl Sized, i32)>` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:14:15 + --> $DIR/recursive-impl-trait-type-indirect.rs:12:15 | LL | fn tuple() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type @@ -15,7 +15,7 @@ LL | fn tuple() -> impl Sized { = note: expanded type is `(impl Sized,)` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:18:15 + --> $DIR/recursive-impl-trait-type-indirect.rs:17:15 | LL | fn array() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type @@ -31,7 +31,7 @@ LL | fn ptr() -> impl Sized { = note: expanded type is `*const impl Sized` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:26:16 + --> $DIR/recursive-impl-trait-type-indirect.rs:27:16 | LL | fn fn_ptr() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type @@ -39,63 +39,63 @@ LL | fn fn_ptr() -> impl Sized { = note: expanded type is `fn() -> impl Sized` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:30:25 + --> $DIR/recursive-impl-trait-type-indirect.rs:32:25 | LL | fn closure_capture() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:32:5: 32:19 x:impl Sized]` + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:35:29 + --> $DIR/recursive-impl-trait-type-indirect.rs:40:29 | LL | fn closure_ref_capture() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:37:5: 37:20 x:impl Sized]` + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:40:21 + --> $DIR/recursive-impl-trait-type-indirect.rs:48:21 | LL | fn closure_sig() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:41:5: 41:21]` + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:44:23 + --> $DIR/recursive-impl-trait-type-indirect.rs:53:23 | LL | fn generator_sig() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:45:5: 45:23]` + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:48:27 + --> $DIR/recursive-impl-trait-type-indirect.rs:58:27 | LL | fn generator_capture() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:26 x:impl Sized {()}]` + = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:53:26 + --> $DIR/recursive-impl-trait-type-indirect.rs:67:35 | -LL | fn substs_change() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type +LL | fn substs_change() -> impl Sized { + | ^^^^^^^^^^ expands to a recursive type | = note: expanded type is `(impl Sized,)` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:57:24 + --> $DIR/recursive-impl-trait-type-indirect.rs:72:24 | LL | fn generator_hold() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:58:5: 62:6 {impl Sized, ()}]` + = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:69:26 + --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 | LL | fn mutual_recursion() -> impl Sync { | ^^^^^^^^^ expands to a recursive type @@ -103,7 +103,7 @@ LL | fn mutual_recursion() -> impl Sync { = note: type resolves to itself error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:73:28 + --> $DIR/recursive-impl-trait-type-indirect.rs:91:28 | LL | fn mutual_recursion_b() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type diff --git a/src/test/ui/lint/lint-unused-mut-variables.rs b/src/test/ui/lint/lint-unused-mut-variables.rs index dd8dbda6d4303..5c7ed9d521940 100644 --- a/src/test/ui/lint/lint-unused-mut-variables.rs +++ b/src/test/ui/lint/lint-unused-mut-variables.rs @@ -2,17 +2,17 @@ // Exercise the unused_mut attribute in some positive and negative cases -#![deny(unused_mut)] +#![warn(unused_mut)] #![feature(async_closure, raw_ref_op)] async fn baz_async( mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, ) {} fn baz( mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, #[allow(unused_mut)] (mut c, d): (i32, i32) ) {} @@ -21,13 +21,13 @@ struct RefStruct {} impl RefStruct { async fn baz_async( mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, ) {} fn baz( &self, mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, #[allow(unused_mut)] (mut c, d): (i32, i32) ) {} @@ -37,7 +37,7 @@ trait RefTrait { fn baz( &self, mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, #[allow(unused_mut)] (mut c, d): (i32, i32) ) {} @@ -46,7 +46,7 @@ impl RefTrait for () { fn baz( &self, mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, #[allow(unused_mut)] (mut c, d): (i32, i32) ) {} @@ -55,32 +55,32 @@ impl RefTrait for () { fn main() { let _ = async move | mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, | {}; let _ = | mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, #[allow(unused_mut)] (mut c, d): (i32, i32) | {}; // negative cases - let mut a = 3; //~ ERROR: variable does not need to be mutable + let mut a = 3; //~ WARN: variable does not need to be mutable - let mut a = 2; //~ ERROR: variable does not need to be mutable + let mut a = 2; //~ WARN: variable does not need to be mutable - let mut b = 3; //~ ERROR: variable does not need to be mutable + let mut b = 3; //~ WARN: variable does not need to be mutable - let mut a = vec![3]; //~ ERROR: variable does not need to be mutable + let mut a = vec![3]; //~ WARN: variable does not need to be mutable - let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable + let (mut a, b) = (1, 2); //~ WARN: variable does not need to be mutable - let mut a; //~ ERROR: variable does not need to be mutable + let mut a; //~ WARN: variable does not need to be mutable a = 3; - let mut b; //~ ERROR: variable does not need to be mutable + let mut b; //~ WARN: variable does not need to be mutable if true { b = 3; @@ -89,11 +89,11 @@ fn main() { } match 30 { - mut x => {} //~ ERROR: variable does not need to be mutable + mut x => {} //~ WARN: variable does not need to be mutable } match (30, 2) { - (mut x, 1) | //~ ERROR: variable does not need to be mutable + (mut x, 1) | //~ WARN: variable does not need to be mutable (mut x, 2) | (mut x, 3) => { @@ -101,20 +101,20 @@ fn main() { _ => {} } - let x = |mut y: isize| 10; //~ ERROR: variable does not need to be mutable + let x = |mut y: isize| 10; //~ WARN: variable does not need to be mutable - fn what(mut foo: isize) {} //~ ERROR: variable does not need to be mutable + fn what(mut foo: isize) {} //~ WARN: variable does not need to be mutable - let mut a = &mut 5; //~ ERROR: variable does not need to be mutable + let mut a = &mut 5; //~ WARN: variable does not need to be mutable *a = 4; let mut a = 5; - let mut b = (&mut a,); //~ ERROR: variable does not need to be mutable + let mut b = (&mut a,); //~ WARN: variable does not need to be mutable *b.0 = 4; - let mut x = &mut 1; //~ ERROR: variable does not need to be mutable + let mut x = &mut 1; //~ WARN: variable does not need to be mutable let mut f = || { *x += 1; @@ -122,11 +122,11 @@ fn main() { f(); fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] { - &mut arg[..] //~^ ERROR: variable does not need to be mutable + &mut arg[..] //~^ WARN: variable does not need to be mutable } - let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not need to be mutable + let mut v : &mut Vec<()> = &mut vec![]; //~ WARN: variable does not need to be mutable v.push(()); @@ -181,7 +181,7 @@ fn main() { let mut raw_address_of_mut = 1; // OK let mut_ptr = &raw mut raw_address_of_mut; - let mut raw_address_of_const = 1; //~ ERROR: variable does not need to be mutable + let mut raw_address_of_const = 1; //~ WARN: variable does not need to be mutable let const_ptr = &raw const raw_address_of_const; } diff --git a/src/test/ui/lint/lint-unused-mut-variables.stderr b/src/test/ui/lint/lint-unused-mut-variables.stderr index eda078da9a0ea..b56b3c7569f71 100644 --- a/src/test/ui/lint/lint-unused-mut-variables.stderr +++ b/src/test/ui/lint/lint-unused-mut-variables.stderr @@ -1,4 +1,4 @@ -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:9:5 | LL | mut a: i32, @@ -9,18 +9,10 @@ LL | mut a: i32, note: the lint level is defined here --> $DIR/lint-unused-mut-variables.rs:5:9 | -LL | #![deny(unused_mut)] +LL | #![warn(unused_mut)] | ^^^^^^^^^^ -error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:14:5 - | -LL | mut a: i32, - | ----^ - | | - | help: remove this `mut` - -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:23:9 | LL | mut a: i32, @@ -28,7 +20,15 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable + --> $DIR/lint-unused-mut-variables.rs:14:5 + | +LL | mut a: i32, + | ----^ + | | + | help: remove this `mut` + +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:29:9 | LL | mut a: i32, @@ -36,7 +36,7 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:39:9 | LL | mut a: i32, @@ -44,7 +44,7 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:48:9 | LL | mut a: i32, @@ -52,7 +52,7 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:57:9 | LL | mut a: i32, @@ -60,7 +60,7 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:62:9 | LL | mut a: i32, @@ -68,7 +68,7 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:104:14 | LL | let x = |mut y: isize| 10; @@ -76,7 +76,7 @@ LL | let x = |mut y: isize| 10; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:69:9 | LL | let mut a = 3; @@ -84,7 +84,7 @@ LL | let mut a = 3; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:71:9 | LL | let mut a = 2; @@ -92,7 +92,7 @@ LL | let mut a = 2; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:73:9 | LL | let mut b = 3; @@ -100,7 +100,7 @@ LL | let mut b = 3; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:75:9 | LL | let mut a = vec![3]; @@ -108,7 +108,7 @@ LL | let mut a = vec![3]; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:77:10 | LL | let (mut a, b) = (1, 2); @@ -116,7 +116,7 @@ LL | let (mut a, b) = (1, 2); | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:79:9 | LL | let mut a; @@ -124,7 +124,7 @@ LL | let mut a; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:83:9 | LL | let mut b; @@ -132,7 +132,7 @@ LL | let mut b; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:92:9 | LL | mut x => {} @@ -140,7 +140,7 @@ LL | mut x => {} | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:96:8 | LL | (mut x, 1) | @@ -148,7 +148,7 @@ LL | (mut x, 1) | | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:109:9 | LL | let mut a = &mut 5; @@ -156,7 +156,7 @@ LL | let mut a = &mut 5; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:114:9 | LL | let mut b = (&mut a,); @@ -164,7 +164,7 @@ LL | let mut b = (&mut a,); | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:117:9 | LL | let mut x = &mut 1; @@ -172,7 +172,7 @@ LL | let mut x = &mut 1; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:129:9 | LL | let mut v : &mut Vec<()> = &mut vec![]; @@ -180,7 +180,7 @@ LL | let mut v : &mut Vec<()> = &mut vec![]; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:184:9 | LL | let mut raw_address_of_const = 1; @@ -188,7 +188,7 @@ LL | let mut raw_address_of_const = 1; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:106:13 | LL | fn what(mut foo: isize) {} @@ -196,7 +196,7 @@ LL | fn what(mut foo: isize) {} | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:124:20 | LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] { @@ -218,5 +218,5 @@ note: the lint level is defined here LL | #[deny(unused_mut)] | ^^^^^^^^^^ -error: aborting due to 26 previous errors +error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs index 59e7de413a2c6..6cbb3069ecd4b 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs @@ -7,11 +7,11 @@ fn main() {} // test that unused generic parameters are ok type Two = impl Debug; -fn two(t: T, u: U) -> Two { +fn two(t: T, u: U) -> Two { (t, t) } -fn three(t: T, u: U) -> Two { -//~^ concrete type differs from previous +fn three(t: T, u: U) -> Two { + //~^ concrete type differs from previous (u, t) } diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr index 66649413d382b..7e81d362661bc 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr @@ -1,7 +1,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/generic_duplicate_param_use6.rs:14:1 | -LL | / fn three(t: T, u: U) -> Two { +LL | / fn three(t: T, u: U) -> Two { LL | | LL | | (u, t) LL | | } @@ -10,7 +10,7 @@ LL | | } note: previous use here --> $DIR/generic_duplicate_param_use6.rs:10:1 | -LL | / fn two(t: T, u: U) -> Two { +LL | / fn two(t: T, u: U) -> Two { LL | | (t, t) LL | | } | |_^ diff --git a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.rs b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.rs index a102d16078bed..50eeff0b18fd4 100644 --- a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.rs +++ b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.rs @@ -7,7 +7,7 @@ use std::fmt::Debug; fn main() { type Opaque = impl Debug; fn _unused() -> Opaque { String::new() } - //~^ ERROR: concrete type differs from previous defining opaque type use let null = || -> Opaque { 0 }; + //~^ ERROR: concrete type differs from previous defining opaque type use println!("{:?}", null()); } diff --git a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr index c994eb5986cb2..1333b4c63d18c 100644 --- a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr @@ -1,20 +1,14 @@ error: concrete type differs from previous defining opaque type use - --> $DIR/issue-52843-closure-constrain.rs:9:5 + --> $DIR/issue-52843-closure-constrain.rs:10:16 | -LL | fn _unused() -> Opaque { String::new() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, got `std::string::String` +LL | let null = || -> Opaque { 0 }; + | ^^^^^^^^^^^^^^^^^^ expected `std::string::String`, got `i32` | note: previous use here - --> $DIR/issue-52843-closure-constrain.rs:7:1 + --> $DIR/issue-52843-closure-constrain.rs:9:5 | -LL | / fn main() { -LL | | type Opaque = impl Debug; -LL | | fn _unused() -> Opaque { String::new() } -LL | | -LL | | let null = || -> Opaque { 0 }; -LL | | println!("{:?}", null()); -LL | | } - | |_^ +LL | fn _unused() -> Opaque { String::new() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs index 8686100205ffb..73acc92172bad 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs @@ -8,7 +8,7 @@ trait IterBits { type IterBitsIter = impl std::iter::Iterator; //~^ ERROR could not find defining uses -impl IterBits for T +impl IterBits for T where T: std::ops::Shr + std::ops::BitAnd From f23bca79d44642b7a6af11f288216a4828a7b530 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 29 Dec 2019 14:23:20 +0000 Subject: [PATCH 15/25] Address review comments --- src/librustc/infer/opaque_types/mod.rs | 45 ++++++++++++------- src/librustc_ast_lowering/lib.rs | 32 ++++++------- .../borrow_check/type_check/input_output.rs | 2 - .../borrow_check/type_check/mod.rs | 18 +------- src/librustc_typeck/collect.rs | 22 ++++++--- src/librustc_typeck/impl_wf_check.rs | 3 ++ 6 files changed, 67 insertions(+), 55 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 088e57f91a7a5..4abc3ef437ed9 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -500,9 +500,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { hir::OpaqueTyOrigin::AsyncFn => return false, // Otherwise, generate the label we'll use in the error message. - hir::OpaqueTyOrigin::TypeAlias => "impl Trait", - hir::OpaqueTyOrigin::FnReturn => "impl Trait", - hir::OpaqueTyOrigin::Misc => "impl Trait", + hir::OpaqueTyOrigin::TypeAlias + | hir::OpaqueTyOrigin::FnReturn + | hir::OpaqueTyOrigin::Misc => "impl Trait", }; let msg = format!("ambiguous lifetime bound in `{}`", context_name); let mut err = self.tcx.sess.struct_span_err(span, &msg); @@ -814,18 +814,29 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r { - // Ignore bound regions that appear in the type, they don't need to - // be remapped (e.g., this would ignore `'r` in a type like - // `for<'r> fn(&'r u32)`. - ty::ReLateBound(..) - - // If regions have been erased, don't try to unerase them. - | ty::ReErased - - // ignore `'static`, as that can appear anywhere - | ty::ReStatic => return r, - - _ => {} + // Ignore bound regions and `'static` regions that appear in the + // type, we only need to remap regions that reference lifetimes + // from the function declaraion. + // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`. + ty::ReLateBound(..) | ty::ReStatic => return r, + + // If regions have been erased (by writeback), don't try to unerase + // them. + ty::ReErased => return r, + + // The regions that we expect from borrow checking. + ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} + + ty::ReEmpty(_) + | ty::RePlaceholder(_) + | ty::ReVar(_) + | ty::ReScope(_) + | ty::ReClosureBound(_) => { + // All of the regions in the type should either have been + // erased by writeback, or mapped back to named regions by + // borrow checking. + bug!("unexpected region kind in opaque type: {:?}", r); + } } let generics = self.tcx().generics_of(self.opaque_type_def_id); @@ -833,7 +844,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { Some(GenericArgKind::Lifetime(r1)) => r1, Some(u) => panic!("region mapped to unexpected kind: {:?}", u), None if self.map_missing_regions_to_empty || self.tainted_by_errors => { - self.tcx.lifetimes.re_empty + self.tcx.lifetimes.re_root_empty } None if generics.parent.is_some() => { if let Some(hidden_ty) = self.hidden_ty.take() { @@ -862,7 +873,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { ) .emit(); - self.tcx().mk_region(ty::ReStatic) + self.tcx().lifetimes.re_static } } } diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index b600869fdf626..99de4b88fd3c4 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1723,17 +1723,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } else { match decl.output { - FunctionRetTy::Ty(ref ty) => match in_band_ty_params { - Some((def_id, _)) if impl_trait_return_allow => { - hir::FunctionRetTy::Return(self.lower_ty( - ty, - ImplTraitContext::OpaqueTy(Some(def_id), hir::OpaqueTyOrigin::FnReturn), - )) - } - _ => hir::FunctionRetTy::Return( - self.lower_ty(ty, ImplTraitContext::disallowed()), - ), - }, + FunctionRetTy::Ty(ref ty) => { + let context = match in_band_ty_params { + Some((def_id, _)) if impl_trait_return_allow => { + ImplTraitContext::OpaqueTy(Some(def_id), hir::OpaqueTyOrigin::FnReturn) + } + _ => ImplTraitContext::disallowed(), + }; + hir::FunctionRetTy::Return(self.lower_ty(ty, context)) + } FunctionRetTy::Default(span) => hir::FunctionRetTy::DefaultReturn(span), } }; @@ -1961,10 +1959,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::GenericBound<'hir> { // Compute the `T` in `Future` from the return type. let output_ty = match output { - FunctionRetTy::Ty(ty) => self.lower_ty( - ty, - ImplTraitContext::OpaqueTy(Some(fn_def_id), hir::OpaqueTyOrigin::FnReturn), - ), + FunctionRetTy::Ty(ty) => { + // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the + // `impl Future` opaque type that `async fn` implicitly + // generates. + let context = + ImplTraitContext::OpaqueTy(Some(fn_def_id), hir::OpaqueTyOrigin::FnReturn); + self.lower_ty(ty, context) + } FunctionRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), }; diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs index 1f1106f054555..3d3b1e5cbf6a9 100644 --- a/src/librustc_mir/borrow_check/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/type_check/input_output.rs @@ -120,7 +120,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.mir_def_id, Locations::All(output_span), ConstraintCategory::BoringNoLocation, - true, ) { span_mirbug!( self, @@ -144,7 +143,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.mir_def_id, Locations::All(output_span), ConstraintCategory::BoringNoLocation, - false, ) { span_mirbug!( self, diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index e7b4471586503..b2e8cf9df7c61 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1122,14 +1122,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // the resulting inferend values are stored with the // def-id of the base function. let parent_def_id = self.tcx().closure_base_def_id(self.mir_def_id); - return self.eq_opaque_type_and_type( - sub, - sup, - parent_def_id, - locations, - category, - false, - ); + return self.eq_opaque_type_and_type(sub, sup, parent_def_id, locations, category); } else { return Err(terr); } @@ -1195,7 +1188,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { anon_owner_def_id: DefId, locations: Locations, category: ConstraintCategory, - is_function_return: bool, ) -> Fallible<()> { debug!( "eq_opaque_type_and_type( \ @@ -1273,13 +1265,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty, ); - if !concrete_is_opaque - || (is_function_return - && matches!(opaque_decl.origin, hir::OpaqueTyOrigin::FnReturn)) - { - // For return position impl Trait, the function - // return is the only possible definition site, so - // always record it. + if !concrete_is_opaque { obligations.add( infcx .at(&ObligationCause::dummy(), param_env) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4448c067d348b..899527ebb9568 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1471,7 +1471,9 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { &tcx.mir_borrowck(owner).concrete_opaque_types } hir::OpaqueTyOrigin::Misc => { - // We shouldn't leak borrowck results through impl Trait in bindings. + // We shouldn't leak borrowck results through impl trait in bindings. + // For example, we shouldn't be able to tell if `x` in + // `let x: impl Sized + 'a = &()` has type `&'static ()` or `&'a ()`. &tcx.typeck_tables_of(owner).concrete_opaque_types } hir::OpaqueTyOrigin::TypeAlias => { @@ -1482,9 +1484,6 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { .get(&def_id) .map(|opaque| opaque.concrete_type) .unwrap_or_else(|| { - // This can occur if some error in the - // owner fn prevented us from populating - // the `concrete_opaque_types` table. tcx.sess.delay_span_bug( DUMMY_SP, &format!( @@ -1492,7 +1491,20 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { owner, def_id, ), ); - tcx.types.err + if tcx.typeck_tables_of(owner).tainted_by_errors { + // Some error in the + // owner fn prevented us from populating + // the `concrete_opaque_types` table. + tcx.types.err + } else { + // We failed to resolve the opaque type or it + // resolves to itself. Return the non-revealed + // type, which should result in E0720. + tcx.mk_opaque( + def_id, + InternalSubsts::identity_for_item(tcx, def_id), + ) + } }); debug!("concrete_ty = {:?}", concrete_ty); if concrete_ty.has_erased_regions() { diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index 0b4b8a49054fa..0a765a1f9c93c 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -131,6 +131,9 @@ fn enforce_impl_params_are_constrained( } } ty::AssocKind::OpaqueTy => { + // We don't know which lifetimes appear in the actual + // opaque type, so use all of the lifetimes that appear + // in the type's predicates. let predicates = tcx.predicates_of(def_id).instantiate_identity(tcx); cgp::parameters_for(&predicates, true) } From 728224d1e08f4d28fdc8d9c94b8a553750534435 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 5 Jan 2020 18:27:51 +0000 Subject: [PATCH 16/25] Show inferred opaque types with `#[rustc_regions]` --- src/librustc_mir/borrow_check/mod.rs | 12 ++++++++++-- src/librustc_mir/borrow_check/nll.rs | 13 ++++++++++--- src/librustc_mir/borrow_check/type_check/mod.rs | 9 +++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index da9bdc8b4b015..f9db62e0a3a42 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -221,9 +221,17 @@ fn do_mir_borrowck<'a, 'tcx>( // write unit-tests, as well as helping with debugging. nll::dump_mir_results(infcx, MirSource::item(def_id), &body, ®ioncx, &opt_closure_req); - // We also have a `#[rustc_nll]` annotation that causes us to dump + // We also have a `#[rustc_regions]` annotation that causes us to dump // information. - nll::dump_annotation(infcx, &body, def_id, ®ioncx, &opt_closure_req, &mut errors_buffer); + nll::dump_annotation( + infcx, + &body, + def_id, + ®ioncx, + &opt_closure_req, + &opaque_type_values, + &mut errors_buffer, + ); // The various `flow_*` structures can be large. We drop `flow_inits` here // so it doesn't overlap with the others below. This reduces peak memory diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index 4c1ee9582c1f2..101d1856c38f2 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -355,6 +355,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( mir_def_id: DefId, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, + opaque_type_values: &FxHashMap>, errors_buffer: &mut Vec, ) { let tcx = infcx.tcx; @@ -370,7 +371,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( // viewing the intraprocedural state, the -Zdump-mir output is // better. - if let Some(closure_region_requirements) = closure_region_requirements { + let mut err = if let Some(closure_region_requirements) = closure_region_requirements { let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "external requirements"); regioncx.annotate(tcx, &mut err); @@ -388,13 +389,19 @@ pub(super) fn dump_annotation<'a, 'tcx>( }) .unwrap(); - err.buffer(errors_buffer); + err } else { let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "no external requirements"); regioncx.annotate(tcx, &mut err); - err.buffer(errors_buffer); + err + }; + + if !opaque_type_values.is_empty() { + err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values)); } + + err.buffer(errors_buffer); } fn for_each_region_constraint( diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index b2e8cf9df7c61..6c073b3d2c8dc 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1226,6 +1226,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { revealed_ty={:?}", output_ty, opaque_type_map, revealed_ty ); + // Make sure that the inferred types are well-formed. I'm + // not entirely sure this is needed (the HIR type check + // didn't do this) but it seems sensible to prevent opaque + // types hiding ill-formed types. + obligations.obligations.push(traits::Obligation::new( + ObligationCause::dummy(), + param_env, + ty::Predicate::WellFormed(revealed_ty), + )); obligations.add( infcx .at(&ObligationCause::dummy(), param_env) From 5cfa7d1dfb8a83c24ba3220d6740388546c664b9 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 8 Jan 2020 21:20:38 +0000 Subject: [PATCH 17/25] Handle equal regions in opaque type inference --- .../borrow_check/region_infer/opaque_types.rs | 86 +++++++++++++++---- .../borrow_check/type_check/mod.rs | 2 + .../ui/impl-trait/equal-hidden-lifetimes.rs | 49 +++++++++++ .../impl-trait/equal-hidden-lifetimes.stderr | 8 ++ 4 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/impl-trait/equal-hidden-lifetimes.rs create mode 100644 src/test/ui/impl-trait/equal-hidden-lifetimes.stderr diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs index e16a2c838ebe9..f3f392683f68f 100644 --- a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs +++ b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs @@ -1,7 +1,7 @@ -use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::ty; use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::DefId; use rustc_span::Span; use super::RegionInferenceContext; @@ -9,6 +9,42 @@ use super::RegionInferenceContext; impl<'tcx> RegionInferenceContext<'tcx> { /// Resolve any opaque types that were encountered while borrow checking /// this item. This is then used to get the type in the `type_of` query. + /// + /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`. + /// This is lowered to give HIR something like + /// + /// type _Return<'_a> = impl Sized + '_a; + /// fn f<'a>(x: &'a i32) -> _Return<'a> { x } + /// + /// When checking the return type record the type from the return and the + /// type used in the return value. In this case they might be `_Return<'1>` + /// and `&'2 i32` respectively. + /// + /// Once we to this method, we have completed region inference and want to + /// call `infer_opaque_definition_from_instantiation` to get the inferred + /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation` + /// compares lifetimes directly, so we need to map the inference variables + /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`. + /// + /// First we map all the lifetimes in the concrete type to an equal + /// universal region that occurs in the concrete type's substs, in this case + /// this would result in `&'1 i32`. We only consider regions in the substs + /// in case there is an equal region that does not. For example, this should + /// be allowed: + /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }` + /// + /// Then we map the regions in both the type and the subst to their + /// `external_name` giving `concrete_type = &'a i32, substs = ['a]`. This + /// will then allow `infer_opaque_definition_from_instantiation` to + /// determine that `_Return<'_a> = &'_a i32`. + /// + /// There's a slight complication around closures. Given + /// `fn f<'a: 'a>() { || {} }` the closure's type is something like + /// `f::<'a>::{{closure}}`. The region parameter from f is essentially + /// ignored by type checking so ends up being inferred to an empty region. + /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, + /// which has no `external_name` in which case we use `'empty` as the + /// region to pass to `infer_opaque_definition_from_instantiation`. pub(in crate::borrow_check) fn infer_opaque_types( &self, infcx: &InferCtxt<'_, 'tcx>, @@ -23,24 +59,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { concrete_type, substs ); - // Map back to "concrete" regions so that errors in - // `infer_opaque_definition_from_instantiation` can show - // sensible region names. - let universal_concrete_type = - infcx.tcx.fold_regions(&concrete_type, &mut false, |region, _| match region { - &ty::ReVar(vid) => { - let universal_bound = self.universal_upper_bound(vid); - self.definitions[universal_bound] - .external_name - .filter(|_| self.eval_equal(universal_bound, vid)) - .unwrap_or(infcx.tcx.lifetimes.re_empty) - } - concrete => concrete, - }); + let mut subst_regions = vec![self.universal_regions.fr_static]; let universal_substs = - infcx.tcx.fold_regions(&substs, &mut false, |region, _| match region { + infcx.tcx.fold_regions(&substs, &mut false, |region, _| match *region { ty::ReVar(vid) => { - self.definitions[*vid].external_name.unwrap_or_else(|| { + subst_regions.push(vid); + self.definitions[vid].external_name.unwrap_or_else(|| { infcx.tcx.sess.delay_span_bug( span, "opaque type with non-universal region substs", @@ -48,7 +72,33 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx.tcx.lifetimes.re_static }) } - concrete => concrete, + _ => { + infcx.tcx.sess.delay_span_bug( + span, + &format!("unexpected concrete region in borrowck: {:?}", region), + ); + region + } + }); + + subst_regions.sort(); + subst_regions.dedup(); + + let universal_concrete_type = + infcx.tcx.fold_regions(&concrete_type, &mut false, |region, _| match *region { + ty::ReVar(vid) => subst_regions + .iter() + .find(|ur_vid| self.eval_equal(vid, **ur_vid)) + .and_then(|ur_vid| self.definitions[*ur_vid].external_name) + .unwrap_or(infcx.tcx.lifetimes.re_root_empty), + ty::ReLateBound(..) => region, + _ => { + infcx.tcx.sess.delay_span_bug( + span, + &format!("unexpected concrete region in borrowck: {:?}", region), + ); + region + } }); debug!( diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 6c073b3d2c8dc..85bc032606f2a 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1275,6 +1275,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); if !concrete_is_opaque { + // Equate concrete_ty (an inference variable) with + // the renumbered type from typeck. obligations.add( infcx .at(&ObligationCause::dummy(), param_env) diff --git a/src/test/ui/impl-trait/equal-hidden-lifetimes.rs b/src/test/ui/impl-trait/equal-hidden-lifetimes.rs new file mode 100644 index 0000000000000..79db88828b9af --- /dev/null +++ b/src/test/ui/impl-trait/equal-hidden-lifetimes.rs @@ -0,0 +1,49 @@ +// Test that we consider equal regions when checking for hidden regions in +// opaque types + +// check-pass + +// `'a == 'static` so `&'a i32` is fine as the return type +fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized { + //~^ WARNING unnecessary lifetime parameter `'a` + x +} + +// `'a == 'b` so `&'b i32` is fine as the return type +fn equal_regions<'a: 'b, 'b: 'a>(x: &'b i32) -> impl Sized + 'a { + let y: &'a i32 = x; + let z: &'b i32 = y; + x +} + +// `'a == 'b` so `&'a i32` is fine as the return type +fn equal_regions_rev<'a: 'b, 'b: 'a>(x: &'a i32) -> impl Sized + 'b { + let y: &'a i32 = x; + let z: &'b i32 = y; + x +} + +// `'a == 'b` so `*mut &'b i32` is fine as the return type +fn equal_regions_inv<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { + let y: *mut &'a i32 = x; + let z: *mut &'b i32 = y; + x +} + +// `'a == 'b` so `*mut &'a i32` is fine as the return type +fn equal_regions_inv_rev<'a: 'b, 'b: 'a>(x: *mut &'a i32) -> impl Sized + 'b { + let y: *mut &'a i32 = x; + let z: *mut &'b i32 = y; + x +} + +// Should be able to infer `fn(&'static ())` as the return type. +fn contravariant_lub<'a, 'b: 'a, 'c: 'a, 'd: 'b + 'c>( + x: fn(&'b ()), + y: fn(&'c ()), + c: bool, +) -> impl Sized + 'a { + if c { x } else { y } +} + +fn main() {} diff --git a/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr b/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr new file mode 100644 index 0000000000000..eb064b4e14a5e --- /dev/null +++ b/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr @@ -0,0 +1,8 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/equal-hidden-lifetimes.rs:7:25 + | +LL | fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized { + | ^^^^^^^^^^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + From 2bd16f3c81af80718403e2e202fd0d59e8f94c60 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 11 Jan 2020 14:12:39 +0000 Subject: [PATCH 18/25] Improve opaque type lifetime errors * Use better span for member constraint errors * Avoid a bad suggestion * Don't report member constraint errors if we have other universal region errors. --- src/librustc/infer/error_reporting/mod.rs | 6 ++--- .../infer/lexical_region_resolve/mod.rs | 11 +-------- src/librustc/infer/opaque_types/mod.rs | 5 ++-- .../borrow_check/diagnostics/region_errors.rs | 23 ++++++++++--------- .../borrow_check/region_infer/mod.rs | 6 +++-- .../borrow_check/region_infer/opaque_types.rs | 21 ++++++++++++++++- 6 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 01390f2c7195b..327e1da64c4cd 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -405,17 +405,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } RegionResolutionError::MemberConstraintFailure { - opaque_type_def_id, hidden_ty, member_region, - span: _, - choice_regions: _, + span, } => { let hidden_ty = self.resolve_vars_if_possible(&hidden_ty); opaque_types::unexpected_hidden_region_diagnostic( self.tcx, Some(region_scope_tree), - opaque_type_def_id, + span, hidden_ty, member_region, ) diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index e0a8c3b4e654a..1b204e5ba6cb3 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -18,7 +18,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{ Direction, Graph, NodeIndex, INCOMING, OUTGOING, }; -use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_span::Span; use std::fmt; @@ -95,13 +94,7 @@ pub enum RegionResolutionError<'tcx> { /// Indicates a failure of a `MemberConstraint`. These arise during /// impl trait processing explicitly -- basically, the impl trait's hidden type /// included some region that it was not supposed to. - MemberConstraintFailure { - span: Span, - opaque_type_def_id: DefId, - hidden_ty: Ty<'tcx>, - member_region: Region<'tcx>, - choice_regions: Vec>, - }, + MemberConstraintFailure { span: Span, hidden_ty: Ty<'tcx>, member_region: Region<'tcx> }, } struct RegionAndOrigin<'tcx> { @@ -656,10 +649,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let span = self.tcx().def_span(member_constraint.opaque_type_def_id); errors.push(RegionResolutionError::MemberConstraintFailure { span, - opaque_type_def_id: member_constraint.opaque_type_def_id, hidden_ty: member_constraint.hidden_ty, member_region, - choice_regions: choice_regions.collect(), }); } } diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 4abc3ef437ed9..4edacd4731c48 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -595,11 +595,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn unexpected_hidden_region_diagnostic( tcx: TyCtxt<'tcx>, region_scope_tree: Option<®ion::ScopeTree>, - opaque_type_def_id: DefId, + span: Span, hidden_ty: Ty<'tcx>, hidden_region: ty::Region<'tcx>, ) -> DiagnosticBuilder<'tcx> { - let span = tcx.def_span(opaque_type_def_id); let mut err = struct_span_err!( tcx.sess, span, @@ -851,7 +850,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { unexpected_hidden_region_diagnostic( self.tcx, None, - self.opaque_type_def_id, + self.tcx.def_span(self.opaque_type_def_id), hidden_ty, r, ) diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 0e040ec7827e1..b393d4bc2a5b3 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -6,7 +6,6 @@ use rustc::infer::{ use rustc::mir::ConstraintCategory; use rustc::ty::{self, RegionVid, Ty}; use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_hir::def_id::DefId; use rustc_span::symbol::kw; use rustc_span::Span; @@ -58,8 +57,8 @@ crate enum RegionErrorKind<'tcx> { /// An unexpected hidden region for an opaque type. UnexpectedHiddenRegion { - /// The def id of the opaque type. - opaque_type_def_id: DefId, + /// The span for the member constraint. + span: Span, /// The hidden type. hidden_ty: Ty<'tcx>, /// The unexpected region. @@ -194,18 +193,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - RegionErrorKind::UnexpectedHiddenRegion { - opaque_type_def_id, - hidden_ty, - member_region, - } => { + RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => { let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); + let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); + let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); opaque_types::unexpected_hidden_region_diagnostic( self.infcx.tcx, Some(region_scope_tree), - opaque_type_def_id, - hidden_ty, - member_region, + span, + named_ty, + named_region, ) .buffer(&mut self.errors_buffer); } @@ -588,6 +585,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { found = true; break; + } else { + // If there's already a lifetime bound, don't + // suggest anything. + return; } } } diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 4a2f398c6d508..8435e6bc885ba 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -511,7 +511,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_universal_regions(body, outlives_requirements.as_mut(), &mut errors_buffer); } - self.check_member_constraints(infcx, &mut errors_buffer); + if errors_buffer.is_empty() { + self.check_member_constraints(infcx, &mut errors_buffer); + } let outlives_requirements = outlives_requirements.unwrap_or(vec![]); @@ -1604,7 +1606,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // If not, report an error. let member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid)); errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { - opaque_type_def_id: m_c.opaque_type_def_id, + span: m_c.definition_span, hidden_ty: m_c.hidden_ty, member_region, }); diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs index f3f392683f68f..71702eb84e784 100644 --- a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs +++ b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs @@ -1,5 +1,5 @@ use rustc::infer::InferCtxt; -use rustc::ty; +use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_span::Span; @@ -119,4 +119,23 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) .collect() } + + /// Map the regions in the type to named regions. This is similar to what + /// `infer_opaque_types` does, but can infer any universal region, not only + /// ones from the substs for the opaque type. It also doesn't double check + /// that the regions produced are in fact equal to the named region they are + /// replaced with. This is fine because this function is only to improve the + /// region names in error messages. + pub(in crate::borrow_check) fn name_regions(&self, tcx: TyCtxt<'tcx>, ty: T) -> T + where + T: TypeFoldable<'tcx>, + { + tcx.fold_regions(&ty, &mut false, |region, _| match *region { + ty::ReVar(vid) => { + let upper_bound = self.universal_upper_bound(vid); + self.definitions[upper_bound].external_name.unwrap_or(region) + } + _ => region, + }) + } } From dd1687ef416f9a5856872c7ed40c4a1a3d8788ea Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 11 Jan 2020 16:58:50 +0000 Subject: [PATCH 19/25] Always check upper bounds when choosing member regions Also correctly calculate what the upper bounds are. --- .../borrow_check/region_infer/mod.rs | 53 ++++----------- .../borrow_check/region_infer/reverse_sccs.rs | 68 +++++++++++++++++++ 2 files changed, 81 insertions(+), 40 deletions(-) create mode 100644 src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 8435e6bc885ba..192e4700b91f6 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -12,8 +12,6 @@ use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::binary_search_util; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; -use rustc_data_structures::graph::vec_graph::VecGraph; -use rustc_data_structures::graph::WithSuccessors; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; @@ -26,6 +24,7 @@ use crate::borrow_check::{ diagnostics::{RegionErrorKind, RegionErrors}, member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}, nll::{PoloniusOutput, ToRegionVid}, + region_infer::reverse_sccs::ReverseSccGraph, region_infer::values::{ LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues, ToElementIndex, @@ -37,6 +36,7 @@ use crate::borrow_check::{ mod dump_mir; mod graphviz; mod opaque_types; +mod reverse_sccs; pub mod values; @@ -66,9 +66,10 @@ pub struct RegionInferenceContext<'tcx> { /// compute the values of each region. constraint_sccs: Rc>, - /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` - /// exists if `B: A`. Computed lazilly. - rev_constraint_graph: Option>>, + /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if + /// `B: A`. This is used to compute the universal regions that are required + /// to outlive a given SCC. Computed lazily. + rev_scc_graph: Option>, /// The "R0 member of [R1..Rn]" constraints, indexed by SCC. member_constraints: Rc>, @@ -288,7 +289,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraints, constraint_graph, constraint_sccs, - rev_constraint_graph: None, + rev_scc_graph: None, member_constraints, member_constraints_applied: Vec::new(), closure_bounds_mapping, @@ -680,15 +681,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { // free region that must outlive the member region `R0` (`UB: // R0`). Therefore, we need only keep an option `O` if `UB: O` // for all UB. - if choice_regions.len() > 1 { - let universal_region_relations = self.universal_region_relations.clone(); - let rev_constraint_graph = self.rev_constraint_graph(); - for ub in self.upper_bounds(scc, &rev_constraint_graph) { - debug!("apply_member_constraint: ub={:?}", ub); - choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r)); - } - debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions); + let rev_scc_graph = self.reverse_scc_graph(); + let universal_region_relations = &self.universal_region_relations; + for ub in rev_scc_graph.upper_bounds(scc) { + debug!("apply_member_constraint: ub={:?}", ub); + choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r)); } + debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions); // If we ruled everything out, we're done. if choice_regions.is_empty() { @@ -744,32 +743,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - /// Compute and return the reverse SCC-based constraint graph (lazilly). - fn upper_bounds( - &'a mut self, - scc0: ConstraintSccIndex, - rev_constraint_graph: &'a VecGraph, - ) -> impl Iterator + 'a { - let scc_values = &self.scc_values; - let mut duplicates = FxHashSet::default(); - rev_constraint_graph - .depth_first_search(scc0) - .skip(1) - .flat_map(move |scc1| scc_values.universal_regions_outlived_by(scc1)) - .filter(move |&r| duplicates.insert(r)) - } - - /// Compute and return the reverse SCC-based constraint graph (lazilly). - fn rev_constraint_graph(&mut self) -> Rc> { - if let Some(g) = &self.rev_constraint_graph { - return g.clone(); - } - - let rev_graph = Rc::new(self.constraint_sccs.reverse()); - self.rev_constraint_graph = Some(rev_graph.clone()); - rev_graph - } - /// Returns `true` if all the elements in the value of `scc_b` are nameable /// in `scc_a`. Used during constraint propagation, and only once /// the value of `scc_b` has been computed. diff --git a/src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs b/src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs new file mode 100644 index 0000000000000..4b8357bda0280 --- /dev/null +++ b/src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs @@ -0,0 +1,68 @@ +use crate::borrow_check::constraints::ConstraintSccIndex; +use crate::borrow_check::RegionInferenceContext; +use itertools::Itertools; +use rustc::ty::RegionVid; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::graph::vec_graph::VecGraph; +use rustc_data_structures::graph::WithSuccessors; +use std::ops::Range; +use std::rc::Rc; + +crate struct ReverseSccGraph { + graph: VecGraph, + /// For each SCC, the range of `universal_regions` that use that SCC as + /// their value. + scc_regions: FxHashMap>, + /// All of the universal regions, in grouped so that `scc_regions` can + /// index into here. + universal_regions: Vec, +} + +impl ReverseSccGraph { + /// Find all universal regions that are required to outlive the given SCC. + pub(super) fn upper_bounds<'a>( + &'a self, + scc0: ConstraintSccIndex, + ) -> impl Iterator + 'a { + let mut duplicates = FxHashSet::default(); + self.graph + .depth_first_search(scc0) + .flat_map(move |scc1| { + self.scc_regions + .get(&scc1) + .map_or(&[][..], |range| &self.universal_regions[range.clone()]) + }) + .copied() + .filter(move |r| duplicates.insert(*r)) + } +} + +impl RegionInferenceContext<'_> { + /// Compute and return the reverse SCC-based constraint graph (lazily). + pub(super) fn reverse_scc_graph(&mut self) -> Rc { + if let Some(g) = &self.rev_scc_graph { + return g.clone(); + } + + let graph = self.constraint_sccs.reverse(); + let mut paired_scc_regions = self + .universal_regions + .universal_regions() + .map(|region| (self.constraint_sccs.scc(region), region)) + .collect_vec(); + paired_scc_regions.sort(); + let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect(); + + let mut scc_regions = FxHashMap::default(); + let mut start = 0; + for (scc, group) in &paired_scc_regions.into_iter().group_by(|(scc, _)| *scc) { + let group_size = group.into_iter().count(); + scc_regions.insert(scc, start..start + group_size); + start += group_size; + } + + let rev_graph = Rc::new(ReverseSccGraph { graph, scc_regions, universal_regions }); + self.rev_scc_graph = Some(rev_graph.clone()); + rev_graph + } +} From e3e5d27f23f466f7a9e65950e6ce32169ad2a557 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 11 Jan 2020 17:18:52 +0000 Subject: [PATCH 20/25] Use member constraint for most opaque types in NLL This ensures that NLL will infer suitable values for regions in opaque types when it's possible. --- src/librustc/infer/opaque_types/mod.rs | 56 ++++++++++++++----- .../borrow_check/type_check/mod.rs | 2 + 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 4edacd4731c48..5ecd03e41234e 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -93,6 +93,18 @@ pub struct OpaqueTypeDecl<'tcx> { pub origin: hir::OpaqueTyOrigin, } +/// Whether member constraints should be generated for all opaque types +pub enum GenerateMemberConstraints { + /// The default, used by typeck + WhenRequired, + /// The borrow checker needs member constraints in any case where we don't + /// have a `'static` bound. This is because the borrow checker has more + /// flexibility in the values of regions. For example, given `f<'a, 'b>` + /// the borrow checker can have an inference variable outlive `'a` and `'b`, + /// but not be equal to `'static`. + IfNoStaticBound, +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Replaces all opaque types in `value` with fresh inference variables /// and creates appropriate obligations. For example, given the input: @@ -315,7 +327,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("constrain_opaque_types()"); for (&def_id, opaque_defn) in opaque_types { - self.constrain_opaque_type(def_id, opaque_defn, free_region_relations); + self.constrain_opaque_type( + def_id, + opaque_defn, + GenerateMemberConstraints::WhenRequired, + free_region_relations, + ); } } @@ -324,6 +341,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, def_id: DefId, opaque_defn: &OpaqueTypeDecl<'tcx>, + mode: GenerateMemberConstraints, free_region_relations: &FRR, ) { debug!("constrain_opaque_type()"); @@ -358,6 +376,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { op: |r| self.sub_regions(infer::CallReturn(span), required_region, r), }); } + if let GenerateMemberConstraints::IfNoStaticBound = mode { + self.generate_member_constraint( + concrete_ty, + opaque_type_generics, + opaque_defn, + def_id, + ); + } return; } @@ -398,13 +424,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // we will create a "in bound" like `'r in // ['a, 'b, 'c]`, where `'a..'c` are the // regions that appear in the impl trait. + + // For now, enforce a feature gate outside of async functions. + self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_arg); + return self.generate_member_constraint( concrete_ty, opaque_type_generics, opaque_defn, def_id, - lr, - subst_arg, ); } } @@ -414,6 +442,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let least_region = least_region.unwrap_or(tcx.lifetimes.re_static); debug!("constrain_opaque_types: least_region={:?}", least_region); + if let GenerateMemberConstraints::IfNoStaticBound = mode { + if least_region != tcx.lifetimes.re_static { + self.generate_member_constraint( + concrete_ty, + opaque_type_generics, + opaque_defn, + def_id, + ); + } + } concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { tcx: self.tcx, op: |r| self.sub_regions(infer::CallReturn(span), least_region, r), @@ -434,19 +472,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { opaque_type_generics: &ty::Generics, opaque_defn: &OpaqueTypeDecl<'tcx>, opaque_type_def_id: DefId, - conflict1: ty::Region<'tcx>, - conflict2: ty::Region<'tcx>, ) { - // For now, enforce a feature gate outside of async functions. - if self.member_constraint_feature_gate( - opaque_defn, - opaque_type_def_id, - conflict1, - conflict2, - ) { - return; - } - // Create the set of choice regions: each region in the hidden // type can be equal to any of the region parameters of the // opaque type definition. diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 85bc032606f2a..2a2d864276067 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -6,6 +6,7 @@ use std::{fmt, iter, mem}; use either::Either; use rustc::infer::canonical::QueryRegionConstraints; +use rustc::infer::opaque_types::GenerateMemberConstraints; use rustc::infer::outlives::env::RegionBoundPairs; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin}; @@ -1345,6 +1346,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { infcx.constrain_opaque_type( opaque_def_id, &opaque_decl, + GenerateMemberConstraints::IfNoStaticBound, universal_region_relations, ); Ok(InferOk { value: (), obligations: vec![] }) From 78e0ab53fb4ac444e7d62735f0b8dcc9a42004f6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 11 Jan 2020 17:18:58 +0000 Subject: [PATCH 21/25] Update tests --- .../issues/issue-63388-1.nll.stderr | 11 +-- src/test/ui/impl-trait/auto-trait-leak.stderr | 70 ++++++++++++++++--- .../multiple-lifetimes/error-handling-2.rs | 29 ++++++++ .../error-handling-2.stderr | 15 ++++ .../multiple-lifetimes/error-handling.rs | 2 +- .../multiple-lifetimes/error-handling.stderr | 17 ++--- .../ordinary-bounds-unrelated.nll.stderr | 2 + .../ordinary-bounds-unsuited.nll.stderr | 2 + ...pes_pin_lifetime_mismatch-async.nll.stderr | 19 +---- .../self/elision/lt-ref-self-async.nll.stderr | 51 +------------- .../elision/ref-mut-self-async.nll.stderr | 51 +------------- .../elision/ref-mut-struct-async.nll.stderr | 43 +----------- .../self/elision/ref-struct-async.nll.stderr | 43 +----------- 13 files changed, 124 insertions(+), 231 deletions(-) create mode 100644 src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs create mode 100644 src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr diff --git a/src/test/ui/async-await/issues/issue-63388-1.nll.stderr b/src/test/ui/async-await/issues/issue-63388-1.nll.stderr index 4ae3971e90eae..8e0e1ce3dc34d 100644 --- a/src/test/ui/async-await/issues/issue-63388-1.nll.stderr +++ b/src/test/ui/async-await/issues/issue-63388-1.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/issue-63388-1.rs:12:10 - | -LL | ) -> &dyn Foo - | ^^^^^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#22r - error: lifetime may not live long enough --> $DIR/issue-63388-1.rs:13:5 | @@ -19,6 +11,5 @@ LL | | foo LL | | } | |_____^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 981fad57b0fff..3d60cbff3203f 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -41,7 +41,7 @@ note: ...which requires processing `cycle2::{{opaque}}#0`... LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:21:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,22 +51,22 @@ note: ...which requires processing `cycle2`... LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:21:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:21:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires building MIR for... - --> $DIR/auto-trait-leak.rs:21:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:21:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,13 +127,33 @@ note: ...which requires processing `cycle2::{{opaque}}#0`... LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:21:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle @@ -155,9 +175,34 @@ error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ | +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... @@ -166,28 +211,33 @@ note: ...which requires processing `cycle2::{{opaque}}#0`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:21:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:21:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires building MIR for... - --> $DIR/auto-trait-leak.rs:21:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:21:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs new file mode 100644 index 0000000000000..96d891b2cf1d7 --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs @@ -0,0 +1,29 @@ +// compile-flags:-Zborrowck=mir + +#![feature(member_constraints)] +#![feature(type_alias_impl_trait)] + +#[derive(Clone)] +struct CopyIfEq(T, U); + +impl Copy for CopyIfEq {} + +type E<'a, 'b> = impl Sized; + +fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds + let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y); + + // This assignment requires that `x` and `y` have the same type due to the + // `Copy` impl. The reason why we are using a copy to create a constraint + // is that only borrow checking (not regionck in type checking) enforces + // this bound. + let u = v; + let _: *mut &'a i32 = u.1; + unsafe { + let _: &'b i32 = *u.0; + } + u.0 +} + +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr new file mode 100644 index 0000000000000..59105f11805cd --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr @@ -0,0 +1,15 @@ +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/error-handling-2.rs:13:60 + | +LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + | ^^^^^^^^^ + | +note: hidden type `*mut &'a i32` captures the lifetime `'a` as defined on the function body at 13:8 + --> $DIR/error-handling-2.rs:13:8 + | +LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs index 8fb4794e89132..8d02d635094be 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs @@ -11,7 +11,6 @@ impl Copy for CopyIfEq {} type E<'a, 'b> = impl Sized; fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { - //~^ ERROR lifetime may not live long enough let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y); // This assignment requires that `x` and `y` have the same type due to the @@ -22,6 +21,7 @@ fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { let _: *mut &'a i32 = u.1; unsafe { let _: &'b i32 = *u.0; + //~^ ERROR lifetime may not live long enough } u.0 } diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr index 5957ecbdc5faa..6ce3aaf49eb33 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr @@ -1,14 +1,15 @@ error: lifetime may not live long enough - --> $DIR/error-handling.rs:13:56 + --> $DIR/error-handling.rs:23:16 | LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { - | -- lifetime `'a` defined here ^^^^^^^^^ opaque type requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` -help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound - | -LL | type E<'a, 'b> = impl Sized + 'a; - | + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'b i32 = *u.0; + | ^^^^^^^ type annotation requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr index a255c48ec6ef1..5bfc446f6a573 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr @@ -3,6 +3,8 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea | LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> | ^^^^^^^^^^^^^^^^^^ + | + = note: hidden type `Ordinary<'_>` captures lifetime '_#8r error: aborting due to previous error diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr index af42ed1c5c15a..7291eee7b9e88 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr @@ -3,6 +3,8 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea | LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> | ^^^^^^^^^^^^^^^^^^ + | + = note: hidden type `Ordinary<'_>` captures lifetime '_#5r error: aborting due to previous error diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr index b05940fd273a1..61f6680d5a423 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:45 - | -LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52 | @@ -24,14 +16,6 @@ LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { ( | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:58 - | -LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - | ^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64 | @@ -41,6 +25,5 @@ LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } | | let's call the lifetime of this reference `'1` | lifetime `'a` defined here -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/self/elision/lt-ref-self-async.nll.stderr b/src/test/ui/self/elision/lt-ref-self-async.nll.stderr index 8dd823a220497..e66711076e893 100644 --- a/src/test/ui/self/elision/lt-ref-self-async.nll.stderr +++ b/src/test/ui/self/elision/lt-ref-self-async.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:12:42 - | -LL | async fn ref_self(&self, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r - error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:13:9 | @@ -16,14 +8,6 @@ LL | async fn ref_self(&self, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:18:48 - | -LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r - error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:19:9 | @@ -34,14 +18,6 @@ LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:22:57 - | -LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r - error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:23:9 | @@ -52,14 +28,6 @@ LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:26:57 - | -LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r - error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:27:9 | @@ -70,14 +38,6 @@ LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:30:66 - | -LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r - error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:31:9 | @@ -88,14 +48,6 @@ LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:34:62 - | -LL | async fn box_pin_Self(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r - error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:35:9 | @@ -106,6 +58,5 @@ LL | async fn box_pin_Self(self: Box>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error: aborting due to 12 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/self/elision/ref-mut-self-async.nll.stderr b/src/test/ui/self/elision/ref-mut-self-async.nll.stderr index 768f532c18317..82098cd4f077e 100644 --- a/src/test/ui/self/elision/ref-mut-self-async.nll.stderr +++ b/src/test/ui/self/elision/ref-mut-self-async.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:12:46 - | -LL | async fn ref_self(&mut self, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:13:9 | @@ -16,14 +8,6 @@ LL | async fn ref_self(&mut self, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:18:52 - | -LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:19:9 | @@ -34,14 +18,6 @@ LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:22:61 - | -LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:23:9 | @@ -52,14 +28,6 @@ LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:26:61 - | -LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:27:9 | @@ -70,14 +38,6 @@ LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:30:70 - | -LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:31:9 | @@ -88,14 +48,6 @@ LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:34:70 - | -LL | async fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:35:9 | @@ -106,6 +58,5 @@ LL | async fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error: aborting due to 12 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr b/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr index 9e26e411d30bd..736cebae4bccf 100644 --- a/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr +++ b/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-struct-async.rs:12:56 - | -LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:13:9 | @@ -16,14 +8,6 @@ LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-struct-async.rs:16:65 - | -LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:17:9 | @@ -34,14 +18,6 @@ LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-struct-async.rs:20:65 - | -LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:21:9 | @@ -52,14 +28,6 @@ LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-struct-async.rs:24:74 - | -LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:25:9 | @@ -70,14 +38,6 @@ LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-struct-async.rs:28:74 - | -LL | async fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:29:9 | @@ -88,6 +48,5 @@ LL | async fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error: aborting due to 10 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/self/elision/ref-struct-async.nll.stderr b/src/test/ui/self/elision/ref-struct-async.nll.stderr index cbf051205ed96..5d7dd76827a96 100644 --- a/src/test/ui/self/elision/ref-struct-async.nll.stderr +++ b/src/test/ui/self/elision/ref-struct-async.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-struct-async.rs:12:52 - | -LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:13:9 | @@ -16,14 +8,6 @@ LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-struct-async.rs:16:61 - | -LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:17:9 | @@ -34,14 +18,6 @@ LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-struct-async.rs:20:61 - | -LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:21:9 | @@ -52,14 +28,6 @@ LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-struct-async.rs:24:70 - | -LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:25:9 | @@ -70,14 +38,6 @@ LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-struct-async.rs:28:66 - | -LL | async fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:29:9 | @@ -88,6 +48,5 @@ LL | async fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { LL | f | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error: aborting due to 10 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0700`. From 6d9e270a4ddf517b008537f0d8b3768db20d5436 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 12 Jan 2020 10:19:19 +0000 Subject: [PATCH 22/25] Fix and test nested impl Trait --- .../borrow_check/region_infer/opaque_types.rs | 18 +++++++++++++----- src/test/ui/impl-trait/nested-return-type.rs | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/impl-trait/nested-return-type.rs diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs index 71702eb84e784..52d54f7b53c79 100644 --- a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs +++ b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs @@ -13,8 +13,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`. /// This is lowered to give HIR something like /// - /// type _Return<'_a> = impl Sized + '_a; - /// fn f<'a>(x: &'a i32) -> _Return<'a> { x } + /// type f<'a>::_Return<'_a> = impl Sized + '_a; + /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x } /// /// When checking the return type record the type from the return and the /// type used in the return value. In this case they might be `_Return<'1>` @@ -34,9 +34,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }` /// /// Then we map the regions in both the type and the subst to their - /// `external_name` giving `concrete_type = &'a i32, substs = ['a]`. This - /// will then allow `infer_opaque_definition_from_instantiation` to - /// determine that `_Return<'_a> = &'_a i32`. + /// `external_name` giving `concrete_type = &'a i32`, + /// `substs = ['static, 'a]`. This will then allow + /// `infer_opaque_definition_from_instantiation` to determine that + /// `_Return<'_a> = &'_a i32`. /// /// There's a slight complication around closures. Given /// `fn f<'a: 'a>() { || {} }` the closure's type is something like @@ -72,6 +73,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx.tcx.lifetimes.re_static }) } + // We don't fold regions in the predicates of opaque + // types to `ReVar`s. This means that in a case like + // + // fn f<'a: 'a>() -> impl Iterator + // + // The inner opaque type has `'static` in its substs. + ty::ReStatic => region, _ => { infcx.tcx.sess.delay_span_bug( span, diff --git a/src/test/ui/impl-trait/nested-return-type.rs b/src/test/ui/impl-trait/nested-return-type.rs new file mode 100644 index 0000000000000..7d7a084b89046 --- /dev/null +++ b/src/test/ui/impl-trait/nested-return-type.rs @@ -0,0 +1,16 @@ +// Check that nested impl Trait items work in functions with generic parameters. +// check-pass + +trait Captures<'a> {} + +impl Captures<'_> for T {} + +fn nested_assoc_type<'a: 'a, T>() -> impl Iterator { + [1].iter() +} + +fn nested_assoc_lifetime<'a: 'a, T>() -> impl Iterator> { + [1].iter() +} + +fn main() {} From 223a2ee3061a4bfe31df8aee70c682618ef28fe1 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 17 Jan 2020 20:11:51 +0000 Subject: [PATCH 23/25] Add fast path to eq_opaque_type_and_type --- src/librustc/ty/flags.rs | 2 +- src/librustc/ty/fold.rs | 3 +++ src/librustc/ty/mod.rs | 5 ++++- src/librustc/ty/util.rs | 2 +- src/librustc_mir/borrow_check/type_check/mod.rs | 16 ++++++++++++++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 4a4280ba7dc4d..4546eadc6e6e1 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -138,7 +138,7 @@ impl FlagComputation { } &ty::Opaque(_, substs) => { - self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_flags(TypeFlags::HAS_PROJECTION | TypeFlags::HAS_TY_OPAQUE); self.add_substs(substs); } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 5ff0d04c1ed24..3212bc7241783 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -78,6 +78,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_projections(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PROJECTION) } + fn has_opaque_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) + } fn references_error(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_ERR) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6d36116d782e6..45ea05efd4a84 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -481,6 +481,8 @@ bitflags! { const HAS_CT_INFER = 1 << 14; const HAS_CT_PLACEHOLDER = 1 << 15; + /// Does this have any [Opaque] types. + const HAS_TY_OPAQUE = 1 << 16; const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits; @@ -503,7 +505,8 @@ bitflags! { TypeFlags::HAS_RE_ERASED.bits | TypeFlags::HAS_TY_PLACEHOLDER.bits | TypeFlags::HAS_CT_INFER.bits | - TypeFlags::HAS_CT_PLACEHOLDER.bits; + TypeFlags::HAS_CT_PLACEHOLDER.bits | + TypeFlags::HAS_TY_OPAQUE.bits; } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index db7b8d8cfd9ed..f3c3d04931ac3 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -615,7 +615,7 @@ impl<'tcx> TyCtxt<'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if let ty::Opaque(def_id, substs) = t.kind { self.expand_opaque_ty(def_id, substs).unwrap_or(t) - } else if t.has_projections() { + } else if t.has_opaque_types() { t.super_fold_with(self) } else { t diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 2a2d864276067..88fe6d1a3a49d 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1196,6 +1196,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { anon_ty={:?})", revealed_ty, anon_ty ); + + // Fast path for the common case. + if !anon_ty.has_opaque_types() { + if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) { + span_mirbug!( + self, + locations, + "eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`", + revealed_ty, + anon_ty, + terr + ); + } + return Ok(()); + } + let infcx = self.infcx; let tcx = infcx.tcx; let param_env = self.param_env; From edddb62099056abae853aa1157919d3ec112eeb4 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 17 Jan 2020 21:15:03 +0000 Subject: [PATCH 24/25] Split `type_of` out of collect.rs --- src/librustc_typeck/collect.rs | 658 +----------------------- src/librustc_typeck/collect/type_of.rs | 661 +++++++++++++++++++++++++ 2 files changed, 666 insertions(+), 653 deletions(-) create mode 100644 src/librustc_typeck/collect/type_of.rs diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 899527ebb9568..1a505a39e4637 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! "Collection" is the process of determining the type and other external //! details of each item in Rust. Collection is specifically concerned //! with *inter-procedural* things -- for example, for a function @@ -27,18 +25,16 @@ use rustc::hir::map::Map; use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc::mir::mono::Linkage; use rustc::session::parse::feature_err; -use rustc::traits; use rustc::ty::query::Providers; -use rustc::ty::subst::GenericArgKind; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::util::Discr; use rustc::ty::util::IntTypeExt; -use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::{ReprOptions, ToPredicate, WithConstness}; use rustc_attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability, StashKey}; +use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -50,6 +46,8 @@ use rustc_target::spec::abi; use syntax::ast; use syntax::ast::{Ident, MetaItemKind}; +mod type_of; + struct OnlySelfBounds(bool); /////////////////////////////////////////////////////////////////////////// @@ -64,7 +62,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) { pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { - type_of, + type_of: type_of::type_of, generics_of, predicates_of, predicates_defined_on, @@ -1329,652 +1327,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { }) } -fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) { - struct_span_err!( - tcx.sess, - span, - E0202, - "associated types are not yet supported in inherent impls (see #8995)" - ) - .emit(); -} - -fn infer_placeholder_type( - tcx: TyCtxt<'_>, - def_id: DefId, - body_id: hir::BodyId, - span: Span, - item_ident: Ident, -) -> Ty<'_> { - let ty = tcx.diagnostic_only_typeck_tables_of(def_id).node_type(body_id.hir_id); - - // If this came from a free `const` or `static mut?` item, - // then the user may have written e.g. `const A = 42;`. - // In this case, the parser has stashed a diagnostic for - // us to improve in typeck so we do that now. - match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) { - Some(mut err) => { - // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. - // We are typeck and have the real type, so remove that and suggest the actual type. - err.suggestions.clear(); - err.span_suggestion( - span, - "provide a type for the item", - format!("{}: {}", item_ident, ty), - Applicability::MachineApplicable, - ) - .emit(); - } - None => { - let mut diag = bad_placeholder_type(tcx, vec![span]); - if ty != tcx.types.err { - diag.span_suggestion( - span, - "replace `_` with the correct type", - ty.to_string(), - Applicability::MaybeIncorrect, - ); - } - diag.emit(); - } - } - - ty -} - -fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { - use rustc_hir::*; - - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - - let icx = ItemCtxt::new(tcx, def_id); - - match tcx.hir().get(hir_id) { - Node::TraitItem(item) => match item.kind { - TraitItemKind::Method(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs) - } - TraitItemKind::Const(ref ty, body_id) => body_id - .and_then(|body_id| { - if is_suggestable_infer_ty(ty) { - Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)) - } else { - None - } - }) - .unwrap_or_else(|| icx.to_ty(ty)), - TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty), - TraitItemKind::Type(_, None) => { - span_bug!(item.span, "associated type missing default"); - } - }, - - Node::ImplItem(item) => match item.kind { - ImplItemKind::Method(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs) - } - ImplItemKind::Const(ref ty, body_id) => { - if is_suggestable_infer_ty(ty) { - infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) - } else { - icx.to_ty(ty) - } - } - ImplItemKind::OpaqueTy(_) => { - if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() { - report_assoc_ty_on_inherent_impl(tcx, item.span); - } - - find_opaque_ty_constraints(tcx, def_id) - } - ImplItemKind::TyAlias(ref ty) => { - if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() { - report_assoc_ty_on_inherent_impl(tcx, item.span); - } - - icx.to_ty(ty) - } - }, - - Node::Item(item) => { - match item.kind { - ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => { - if is_suggestable_infer_ty(ty) { - infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) - } else { - icx.to_ty(ty) - } - } - ItemKind::TyAlias(ref self_ty, _) | ItemKind::Impl { ref self_ty, .. } => { - icx.to_ty(self_ty) - } - ItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs) - } - ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { - let def = tcx.adt_def(def_id); - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_adt(def, substs) - } - ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => { - find_opaque_ty_constraints(tcx, def_id) - } - // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(hir::OpaqueTy { - impl_trait_fn: Some(owner), origin, .. - }) => { - let concrete_types = match origin { - hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => { - &tcx.mir_borrowck(owner).concrete_opaque_types - } - hir::OpaqueTyOrigin::Misc => { - // We shouldn't leak borrowck results through impl trait in bindings. - // For example, we shouldn't be able to tell if `x` in - // `let x: impl Sized + 'a = &()` has type `&'static ()` or `&'a ()`. - &tcx.typeck_tables_of(owner).concrete_opaque_types - } - hir::OpaqueTyOrigin::TypeAlias => { - span_bug!(item.span, "Type alias impl trait shouldn't have an owner") - } - }; - let concrete_ty = concrete_types - .get(&def_id) - .map(|opaque| opaque.concrete_type) - .unwrap_or_else(|| { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "owner {:?} has no opaque type for {:?} in its tables", - owner, def_id, - ), - ); - if tcx.typeck_tables_of(owner).tainted_by_errors { - // Some error in the - // owner fn prevented us from populating - // the `concrete_opaque_types` table. - tcx.types.err - } else { - // We failed to resolve the opaque type or it - // resolves to itself. Return the non-revealed - // type, which should result in E0720. - tcx.mk_opaque( - def_id, - InternalSubsts::identity_for_item(tcx, def_id), - ) - } - }); - debug!("concrete_ty = {:?}", concrete_ty); - if concrete_ty.has_erased_regions() { - // FIXME(impl_trait_in_bindings) Handle this case. - tcx.sess.span_fatal( - item.span, - "lifetimes in impl Trait types in bindings are not currently supported", - ); - } - concrete_ty - } - ItemKind::Trait(..) - | ItemKind::TraitAlias(..) - | ItemKind::Mod(..) - | ItemKind::ForeignMod(..) - | ItemKind::GlobalAsm(..) - | ItemKind::ExternCrate(..) - | ItemKind::Use(..) => { - span_bug!( - item.span, - "compute_type_of_item: unexpected item type: {:?}", - item.kind - ); - } - } - } - - Node::ForeignItem(foreign_item) => match foreign_item.kind { - ForeignItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs) - } - ForeignItemKind::Static(ref t, _) => icx.to_ty(t), - ForeignItemKind::Type => tcx.mk_foreign(def_id), - }, - - Node::Ctor(&ref def) | Node::Variant(hir::Variant { data: ref def, .. }) => match *def { - VariantData::Unit(..) | VariantData::Struct(..) => { - tcx.type_of(tcx.hir().get_parent_did(hir_id)) - } - VariantData::Tuple(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs) - } - }, - - Node::Field(field) => icx.to_ty(&field.ty), - - Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., gen), .. }) => { - if gen.is_some() { - return tcx.typeck_tables_of(def_id).node_type(hir_id); - } - - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_closure(def_id, substs) - } - - Node::AnonConst(_) => { - let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); - match parent_node { - Node::Ty(&hir::Ty { kind: hir::TyKind::Array(_, ref constant), .. }) - | Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref constant), .. }) - | Node::Expr(&hir::Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - if constant.hir_id == hir_id => - { - tcx.types.usize - } - - Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { - tcx.adt_def(tcx.hir().get_parent_did(hir_id)).repr.discr_type().to_ty(tcx) - } - - Node::Ty(&hir::Ty { kind: hir::TyKind::Path(_), .. }) - | Node::Expr(&hir::Expr { kind: ExprKind::Struct(..), .. }) - | Node::Expr(&hir::Expr { kind: ExprKind::Path(_), .. }) - | Node::TraitRef(..) => { - let path = match parent_node { - Node::Ty(&hir::Ty { - kind: hir::TyKind::Path(QPath::Resolved(_, ref path)), - .. - }) - | Node::Expr(&hir::Expr { - kind: ExprKind::Path(QPath::Resolved(_, ref path)), - .. - }) => Some(&**path), - Node::Expr(&hir::Expr { kind: ExprKind::Struct(ref path, ..), .. }) => { - if let QPath::Resolved(_, ref path) = **path { - Some(&**path) - } else { - None - } - } - Node::TraitRef(&hir::TraitRef { ref path, .. }) => Some(&**path), - _ => None, - }; - - if let Some(path) = path { - let arg_index = path - .segments - .iter() - .filter_map(|seg| seg.args.as_ref()) - .map(|generic_args| generic_args.args.as_ref()) - .find_map(|args| { - args.iter() - .filter(|arg| arg.is_const()) - .enumerate() - .filter(|(_, arg)| arg.id() == hir_id) - .map(|(index, _)| index) - .next() - }) - .unwrap_or_else(|| { - bug!("no arg matching AnonConst in path"); - }); - - // We've encountered an `AnonConst` in some path, so we need to - // figure out which generic parameter it corresponds to and return - // the relevant type. - let generics = match path.res { - Res::Def(DefKind::Ctor(..), def_id) => { - tcx.generics_of(tcx.parent(def_id).unwrap()) - } - Res::Def(_, def_id) => tcx.generics_of(def_id), - Res::Err => return tcx.types.err, - res => { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("unexpected const parent path def {:?}", res,), - ); - return tcx.types.err; - } - }; - - generics - .params - .iter() - .filter(|param| { - if let ty::GenericParamDefKind::Const = param.kind { - true - } else { - false - } - }) - .nth(arg_index) - .map(|param| tcx.type_of(param.def_id)) - // This is no generic parameter associated with the arg. This is - // probably from an extra arg where one is not needed. - .unwrap_or(tcx.types.err) - } else { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("unexpected const parent path {:?}", parent_node,), - ); - return tcx.types.err; - } - } - - x => { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("unexpected const parent in type_of_def_id(): {:?}", x), - ); - tcx.types.err - } - } - } - - Node::GenericParam(param) => match ¶m.kind { - hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty), - hir::GenericParamKind::Const { ty: ref hir_ty, .. } => { - let ty = icx.to_ty(hir_ty); - if !tcx.features().const_compare_raw_pointers { - let err = match ty.peel_refs().kind { - ty::FnPtr(_) => Some("function pointers"), - ty::RawPtr(_) => Some("raw pointers"), - _ => None, - }; - if let Some(unsupported_type) = err { - feature_err( - &tcx.sess.parse_sess, - sym::const_compare_raw_pointers, - hir_ty.span, - &format!( - "using {} as const generic parameters is unstable", - unsupported_type - ), - ) - .emit(); - }; - } - if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty) - .is_some() - { - struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "the types of const generic parameters must derive `PartialEq` and `Eq`", - ) - .span_label( - hir_ty.span, - format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty), - ) - .emit(); - } - ty - } - x => bug!("unexpected non-type Node::GenericParam: {:?}", x), - }, - - x => { - bug!("unexpected sort of node in type_of_def_id(): {:?}", x); - } - } -} - -fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { - use rustc_hir::{Expr, ImplItem, Item, TraitItem}; - - debug!("find_opaque_ty_constraints({:?})", def_id); - - struct ConstraintLocator<'tcx> { - tcx: TyCtxt<'tcx>, - def_id: DefId, - // (first found type span, actual type, mapping from the opaque type's generic - // parameters to the concrete type's generic parameters) - // - // The mapping is an index for each use site of a generic parameter in the concrete type - // - // The indices index into the generic parameters on the opaque type. - found: Option<(Span, Ty<'tcx>, Vec)>, - } - - impl ConstraintLocator<'tcx> { - fn check(&mut self, def_id: DefId) { - // Don't try to check items that cannot possibly constrain the type. - if !self.tcx.has_typeck_tables(def_id) { - debug!( - "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`: no tables", - self.def_id, def_id, - ); - return; - } - // Calling `mir_borrowck` can lead to cycle errors through - // const-checking, avoid calling it if we don't have to. - if !self.tcx.typeck_tables_of(def_id).concrete_opaque_types.contains_key(&self.def_id) { - debug!( - "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", - self.def_id, def_id, - ); - return; - } - // Use borrowck to get the type with unerased regions. - let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id); - if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty { - debug!( - "find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}", - self.def_id, def_id, ty, - ); - - // FIXME(oli-obk): trace the actual span from inference to improve errors. - let span = self.tcx.def_span(def_id); - // used to quickly look up the position of a generic parameter - let mut index_map: FxHashMap = FxHashMap::default(); - // Skipping binder is ok, since we only use this to find generic parameters and - // their positions. - for (idx, subst) in substs.iter().enumerate() { - if let GenericArgKind::Type(ty) = subst.unpack() { - if let ty::Param(p) = ty.kind { - if index_map.insert(p, idx).is_some() { - // There was already an entry for `p`, meaning a generic parameter - // was used twice. - self.tcx.sess.span_err( - span, - &format!( - "defining opaque type use restricts opaque \ - type by using the generic parameter `{}` twice", - p, - ), - ); - return; - } - } else { - self.tcx.sess.delay_span_bug( - span, - &format!( - "non-defining opaque ty use in defining scope: {:?}, {:?}", - concrete_type, substs, - ), - ); - } - } - } - // Compute the index within the opaque type for each generic parameter used in - // the concrete type. - let indices = concrete_type - .subst(self.tcx, substs) - .walk() - .filter_map(|t| match &t.kind { - ty::Param(p) => Some(*index_map.get(p).unwrap()), - _ => None, - }) - .collect(); - let is_param = |ty: Ty<'_>| match ty.kind { - ty::Param(_) => true, - _ => false, - }; - let bad_substs: Vec<_> = substs - .iter() - .enumerate() - .filter_map(|(i, k)| { - if let GenericArgKind::Type(ty) = k.unpack() { Some((i, ty)) } else { None } - }) - .filter(|(_, ty)| !is_param(ty)) - .collect(); - - if !bad_substs.is_empty() { - let identity_substs = InternalSubsts::identity_for_item(self.tcx, self.def_id); - for (i, bad_subst) in bad_substs { - self.tcx.sess.span_err( - span, - &format!( - "defining opaque type use does not fully define opaque type: \ - generic parameter `{}` is specified as concrete type `{}`", - identity_substs.type_at(i), - bad_subst - ), - ); - } - } else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found { - let mut ty = concrete_type.walk().fuse(); - let mut p_ty = prev_ty.walk().fuse(); - let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.kind, &p.kind) { - // Type parameters are equal to any other type parameter for the purpose of - // concrete type equality, as it is possible to obtain the same type just - // by passing matching parameters to a function. - (ty::Param(_), ty::Param(_)) => true, - _ => t == p, - }); - if !iter_eq || ty.next().is_some() || p_ty.next().is_some() { - debug!("find_opaque_ty_constraints: span={:?}", span); - // Found different concrete types for the opaque type. - let mut err = self.tcx.sess.struct_span_err( - span, - "concrete type differs from previous defining opaque type use", - ); - err.span_label( - span, - format!("expected `{}`, got `{}`", prev_ty, concrete_type), - ); - err.span_note(prev_span, "previous use here"); - err.emit(); - } else if indices != *prev_indices { - // Found "same" concrete types, but the generic parameter order differs. - let mut err = self.tcx.sess.struct_span_err( - span, - "concrete type's generic parameters differ from previous defining use", - ); - use std::fmt::Write; - let mut s = String::new(); - write!(s, "expected [").unwrap(); - let list = |s: &mut String, indices: &Vec| { - let mut indices = indices.iter().cloned(); - if let Some(first) = indices.next() { - write!(s, "`{}`", substs[first]).unwrap(); - for i in indices { - write!(s, ", `{}`", substs[i]).unwrap(); - } - } - }; - list(&mut s, prev_indices); - write!(s, "], got [").unwrap(); - list(&mut s, &indices); - write!(s, "]").unwrap(); - err.span_label(span, s); - err.span_note(prev_span, "previous use here"); - err.emit(); - } - } else { - self.found = Some((span, concrete_type, indices)); - } - } else { - debug!( - "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", - self.def_id, def_id, - ); - } - } - } - - impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> { - type Map = Map<'tcx>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> { - intravisit::NestedVisitorMap::All(&self.tcx.hir()) - } - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - if let hir::ExprKind::Closure(..) = ex.kind { - let def_id = self.tcx.hir().local_def_id(ex.hir_id); - self.check(def_id); - } - intravisit::walk_expr(self, ex); - } - fn visit_item(&mut self, it: &'tcx Item<'tcx>) { - debug!("find_existential_constraints: visiting {:?}", it); - let def_id = self.tcx.hir().local_def_id(it.hir_id); - // The opaque type itself or its children are not within its reveal scope. - if def_id != self.def_id { - self.check(def_id); - intravisit::walk_item(self, it); - } - } - fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { - debug!("find_existential_constraints: visiting {:?}", it); - let def_id = self.tcx.hir().local_def_id(it.hir_id); - // The opaque type itself or its children are not within its reveal scope. - if def_id != self.def_id { - self.check(def_id); - intravisit::walk_impl_item(self, it); - } - } - fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { - debug!("find_existential_constraints: visiting {:?}", it); - let def_id = self.tcx.hir().local_def_id(it.hir_id); - self.check(def_id); - intravisit::walk_trait_item(self, it); - } - } - - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let scope = tcx.hir().get_defining_scope(hir_id); - let mut locator = ConstraintLocator { def_id, tcx, found: None }; - - debug!("find_opaque_ty_constraints: scope={:?}", scope); - - if scope == hir::CRATE_HIR_ID { - intravisit::walk_crate(&mut locator, tcx.hir().krate()); - } else { - debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope)); - match tcx.hir().get(scope) { - // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods - // This allows our visitor to process the defining item itself, causing - // it to pick up any 'sibling' defining uses. - // - // For example, this code: - // ``` - // fn foo() { - // type Blah = impl Debug; - // let my_closure = || -> Blah { true }; - // } - // ``` - // - // requires us to explicitly process `foo()` in order - // to notice the defining usage of `Blah`. - Node::Item(ref it) => locator.visit_item(it), - Node::ImplItem(ref it) => locator.visit_impl_item(it), - Node::TraitItem(ref it) => locator.visit_trait_item(it), - other => bug!("{:?} is not a valid scope for an opaque type item", other), - } - } - - match locator.found { - Some((_, ty, _)) => ty, - None => { - let span = tcx.def_span(def_id); - tcx.sess.span_err(span, "could not find defining uses"); - tcx.types.err - } - } -} - fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool { generic_args .iter() diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs new file mode 100644 index 0000000000000..8b6dba749a6ef --- /dev/null +++ b/src/librustc_typeck/collect/type_of.rs @@ -0,0 +1,661 @@ +use rustc::hir::map::Map; +use rustc::session::parse::feature_err; +use rustc::traits; +use rustc::ty::subst::{GenericArgKind, InternalSubsts, Subst}; +use rustc::ty::util::IntTypeExt; +use rustc::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable}; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{struct_span_err, Applicability, StashKey}; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::intravisit; +use rustc_hir::intravisit::Visitor; +use rustc_hir::Node; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::{Span, DUMMY_SP}; + +use super::ItemCtxt; +use super::{bad_placeholder_type, is_suggestable_infer_ty}; + +pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { + use rustc_hir::*; + + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + + let icx = ItemCtxt::new(tcx, def_id); + + match tcx.hir().get(hir_id) { + Node::TraitItem(item) => match item.kind { + TraitItemKind::Method(..) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) + } + TraitItemKind::Const(ref ty, body_id) => body_id + .and_then(|body_id| { + if is_suggestable_infer_ty(ty) { + Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)) + } else { + None + } + }) + .unwrap_or_else(|| icx.to_ty(ty)), + TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty), + TraitItemKind::Type(_, None) => { + span_bug!(item.span, "associated type missing default"); + } + }, + + Node::ImplItem(item) => match item.kind { + ImplItemKind::Method(..) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) + } + ImplItemKind::Const(ref ty, body_id) => { + if is_suggestable_infer_ty(ty) { + infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) + } else { + icx.to_ty(ty) + } + } + ImplItemKind::OpaqueTy(_) => { + if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() { + report_assoc_ty_on_inherent_impl(tcx, item.span); + } + + find_opaque_ty_constraints(tcx, def_id) + } + ImplItemKind::TyAlias(ref ty) => { + if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() { + report_assoc_ty_on_inherent_impl(tcx, item.span); + } + + icx.to_ty(ty) + } + }, + + Node::Item(item) => { + match item.kind { + ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => { + if is_suggestable_infer_ty(ty) { + infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) + } else { + icx.to_ty(ty) + } + } + ItemKind::TyAlias(ref self_ty, _) | ItemKind::Impl { ref self_ty, .. } => { + icx.to_ty(self_ty) + } + ItemKind::Fn(..) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) + } + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { + let def = tcx.adt_def(def_id); + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_adt(def, substs) + } + ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }) => { + find_opaque_ty_constraints(tcx, def_id) + } + // Opaque types desugared from `impl Trait`. + ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), origin, .. }) => { + let concrete_types = match origin { + OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => { + &tcx.mir_borrowck(owner).concrete_opaque_types + } + OpaqueTyOrigin::Misc => { + // We shouldn't leak borrowck results through impl trait in bindings. + // For example, we shouldn't be able to tell if `x` in + // `let x: impl Sized + 'a = &()` has type `&'static ()` or `&'a ()`. + &tcx.typeck_tables_of(owner).concrete_opaque_types + } + OpaqueTyOrigin::TypeAlias => { + span_bug!(item.span, "Type alias impl trait shouldn't have an owner") + } + }; + let concrete_ty = concrete_types + .get(&def_id) + .map(|opaque| opaque.concrete_type) + .unwrap_or_else(|| { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "owner {:?} has no opaque type for {:?} in its tables", + owner, def_id, + ), + ); + if tcx.typeck_tables_of(owner).tainted_by_errors { + // Some error in the + // owner fn prevented us from populating + // the `concrete_opaque_types` table. + tcx.types.err + } else { + // We failed to resolve the opaque type or it + // resolves to itself. Return the non-revealed + // type, which should result in E0720. + tcx.mk_opaque( + def_id, + InternalSubsts::identity_for_item(tcx, def_id), + ) + } + }); + debug!("concrete_ty = {:?}", concrete_ty); + if concrete_ty.has_erased_regions() { + // FIXME(impl_trait_in_bindings) Handle this case. + tcx.sess.span_fatal( + item.span, + "lifetimes in impl Trait types in bindings are not currently supported", + ); + } + concrete_ty + } + ItemKind::Trait(..) + | ItemKind::TraitAlias(..) + | ItemKind::Mod(..) + | ItemKind::ForeignMod(..) + | ItemKind::GlobalAsm(..) + | ItemKind::ExternCrate(..) + | ItemKind::Use(..) => { + span_bug!( + item.span, + "compute_type_of_item: unexpected item type: {:?}", + item.kind + ); + } + } + } + + Node::ForeignItem(foreign_item) => match foreign_item.kind { + ForeignItemKind::Fn(..) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) + } + ForeignItemKind::Static(ref t, _) => icx.to_ty(t), + ForeignItemKind::Type => tcx.mk_foreign(def_id), + }, + + Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def { + VariantData::Unit(..) | VariantData::Struct(..) => { + tcx.type_of(tcx.hir().get_parent_did(hir_id)) + } + VariantData::Tuple(..) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) + } + }, + + Node::Field(field) => icx.to_ty(&field.ty), + + Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => { + if gen.is_some() { + return tcx.typeck_tables_of(def_id).node_type(hir_id); + } + + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_closure(def_id, substs) + } + + Node::AnonConst(_) => { + let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); + match parent_node { + Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. }) + | Node::Ty(&Ty { kind: TyKind::Typeof(ref constant), .. }) + | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) + if constant.hir_id == hir_id => + { + tcx.types.usize + } + + Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { + tcx.adt_def(tcx.hir().get_parent_did(hir_id)).repr.discr_type().to_ty(tcx) + } + + Node::Ty(&Ty { kind: TyKind::Path(_), .. }) + | Node::Expr(&Expr { kind: ExprKind::Struct(..), .. }) + | Node::Expr(&Expr { kind: ExprKind::Path(_), .. }) + | Node::TraitRef(..) => { + let path = match parent_node { + Node::Ty(&Ty { + kind: TyKind::Path(QPath::Resolved(_, ref path)), .. + }) + | Node::Expr(&Expr { + kind: ExprKind::Path(QPath::Resolved(_, ref path)), + .. + }) => Some(&**path), + Node::Expr(&Expr { kind: ExprKind::Struct(ref path, ..), .. }) => { + if let QPath::Resolved(_, ref path) = **path { + Some(&**path) + } else { + None + } + } + Node::TraitRef(&TraitRef { ref path, .. }) => Some(&**path), + _ => None, + }; + + if let Some(path) = path { + let arg_index = path + .segments + .iter() + .filter_map(|seg| seg.args.as_ref()) + .map(|generic_args| generic_args.args.as_ref()) + .find_map(|args| { + args.iter() + .filter(|arg| arg.is_const()) + .enumerate() + .filter(|(_, arg)| arg.id() == hir_id) + .map(|(index, _)| index) + .next() + }) + .unwrap_or_else(|| { + bug!("no arg matching AnonConst in path"); + }); + + // We've encountered an `AnonConst` in some path, so we need to + // figure out which generic parameter it corresponds to and return + // the relevant type. + let generics = match path.res { + Res::Def(DefKind::Ctor(..), def_id) => { + tcx.generics_of(tcx.parent(def_id).unwrap()) + } + Res::Def(_, def_id) => tcx.generics_of(def_id), + Res::Err => return tcx.types.err, + res => { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("unexpected const parent path def {:?}", res,), + ); + return tcx.types.err; + } + }; + + generics + .params + .iter() + .filter(|param| { + if let ty::GenericParamDefKind::Const = param.kind { + true + } else { + false + } + }) + .nth(arg_index) + .map(|param| tcx.type_of(param.def_id)) + // This is no generic parameter associated with the arg. This is + // probably from an extra arg where one is not needed. + .unwrap_or(tcx.types.err) + } else { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("unexpected const parent path {:?}", parent_node,), + ); + return tcx.types.err; + } + } + + x => { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("unexpected const parent in type_of_def_id(): {:?}", x), + ); + tcx.types.err + } + } + } + + Node::GenericParam(param) => match ¶m.kind { + GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty), + GenericParamKind::Const { ty: ref hir_ty, .. } => { + let ty = icx.to_ty(hir_ty); + if !tcx.features().const_compare_raw_pointers { + let err = match ty.peel_refs().kind { + ty::FnPtr(_) => Some("function pointers"), + ty::RawPtr(_) => Some("raw pointers"), + _ => None, + }; + if let Some(unsupported_type) = err { + feature_err( + &tcx.sess.parse_sess, + sym::const_compare_raw_pointers, + hir_ty.span, + &format!( + "using {} as const generic parameters is unstable", + unsupported_type + ), + ) + .emit(); + }; + } + if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty) + .is_some() + { + struct_span_err!( + tcx.sess, + hir_ty.span, + E0741, + "the types of const generic parameters must derive `PartialEq` and `Eq`", + ) + .span_label( + hir_ty.span, + format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty), + ) + .emit(); + } + ty + } + x => bug!("unexpected non-type Node::GenericParam: {:?}", x), + }, + + x => { + bug!("unexpected sort of node in type_of_def_id(): {:?}", x); + } + } +} + +fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { + use rustc_hir::{Expr, ImplItem, Item, TraitItem}; + + debug!("find_opaque_ty_constraints({:?})", def_id); + + struct ConstraintLocator<'tcx> { + tcx: TyCtxt<'tcx>, + def_id: DefId, + // (first found type span, actual type, mapping from the opaque type's generic + // parameters to the concrete type's generic parameters) + // + // The mapping is an index for each use site of a generic parameter in the concrete type + // + // The indices index into the generic parameters on the opaque type. + found: Option<(Span, Ty<'tcx>, Vec)>, + } + + impl ConstraintLocator<'_> { + fn check(&mut self, def_id: DefId) { + // Don't try to check items that cannot possibly constrain the type. + if !self.tcx.has_typeck_tables(def_id) { + debug!( + "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`: no tables", + self.def_id, def_id, + ); + return; + } + // Calling `mir_borrowck` can lead to cycle errors through + // const-checking, avoid calling it if we don't have to. + if !self.tcx.typeck_tables_of(def_id).concrete_opaque_types.contains_key(&self.def_id) { + debug!( + "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", + self.def_id, def_id, + ); + return; + } + // Use borrowck to get the type with unerased regions. + let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id); + if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty { + debug!( + "find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}", + self.def_id, def_id, ty, + ); + + // FIXME(oli-obk): trace the actual span from inference to improve errors. + let span = self.tcx.def_span(def_id); + // used to quickly look up the position of a generic parameter + let mut index_map: FxHashMap = FxHashMap::default(); + // Skipping binder is ok, since we only use this to find generic parameters and + // their positions. + for (idx, subst) in substs.iter().enumerate() { + if let GenericArgKind::Type(ty) = subst.unpack() { + if let ty::Param(p) = ty.kind { + if index_map.insert(p, idx).is_some() { + // There was already an entry for `p`, meaning a generic parameter + // was used twice. + self.tcx.sess.span_err( + span, + &format!( + "defining opaque type use restricts opaque \ + type by using the generic parameter `{}` twice", + p, + ), + ); + return; + } + } else { + self.tcx.sess.delay_span_bug( + span, + &format!( + "non-defining opaque ty use in defining scope: {:?}, {:?}", + concrete_type, substs, + ), + ); + } + } + } + // Compute the index within the opaque type for each generic parameter used in + // the concrete type. + let indices = concrete_type + .subst(self.tcx, substs) + .walk() + .filter_map(|t| match &t.kind { + ty::Param(p) => Some(*index_map.get(p).unwrap()), + _ => None, + }) + .collect(); + let is_param = |ty: Ty<'_>| match ty.kind { + ty::Param(_) => true, + _ => false, + }; + let bad_substs: Vec<_> = substs + .iter() + .enumerate() + .filter_map(|(i, k)| { + if let GenericArgKind::Type(ty) = k.unpack() { Some((i, ty)) } else { None } + }) + .filter(|(_, ty)| !is_param(ty)) + .collect(); + if !bad_substs.is_empty() { + let identity_substs = InternalSubsts::identity_for_item(self.tcx, self.def_id); + for (i, bad_subst) in bad_substs { + self.tcx.sess.span_err( + span, + &format!( + "defining opaque type use does not fully define opaque type: \ + generic parameter `{}` is specified as concrete type `{}`", + identity_substs.type_at(i), + bad_subst + ), + ); + } + } else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found { + let mut ty = concrete_type.walk().fuse(); + let mut p_ty = prev_ty.walk().fuse(); + let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.kind, &p.kind) { + // Type parameters are equal to any other type parameter for the purpose of + // concrete type equality, as it is possible to obtain the same type just + // by passing matching parameters to a function. + (ty::Param(_), ty::Param(_)) => true, + _ => t == p, + }); + if !iter_eq || ty.next().is_some() || p_ty.next().is_some() { + debug!("find_opaque_ty_constraints: span={:?}", span); + // Found different concrete types for the opaque type. + let mut err = self.tcx.sess.struct_span_err( + span, + "concrete type differs from previous defining opaque type use", + ); + err.span_label( + span, + format!("expected `{}`, got `{}`", prev_ty, concrete_type), + ); + err.span_note(prev_span, "previous use here"); + err.emit(); + } else if indices != *prev_indices { + // Found "same" concrete types, but the generic parameter order differs. + let mut err = self.tcx.sess.struct_span_err( + span, + "concrete type's generic parameters differ from previous defining use", + ); + use std::fmt::Write; + let mut s = String::new(); + write!(s, "expected [").unwrap(); + let list = |s: &mut String, indices: &Vec| { + let mut indices = indices.iter().cloned(); + if let Some(first) = indices.next() { + write!(s, "`{}`", substs[first]).unwrap(); + for i in indices { + write!(s, ", `{}`", substs[i]).unwrap(); + } + } + }; + list(&mut s, prev_indices); + write!(s, "], got [").unwrap(); + list(&mut s, &indices); + write!(s, "]").unwrap(); + err.span_label(span, s); + err.span_note(prev_span, "previous use here"); + err.emit(); + } + } else { + self.found = Some((span, concrete_type, indices)); + } + } else { + debug!( + "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", + self.def_id, def_id, + ); + } + } + } + + impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> { + intravisit::NestedVisitorMap::All(&self.tcx.hir()) + } + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + if let hir::ExprKind::Closure(..) = ex.kind { + let def_id = self.tcx.hir().local_def_id(ex.hir_id); + self.check(def_id); + } + intravisit::walk_expr(self, ex); + } + fn visit_item(&mut self, it: &'tcx Item<'tcx>) { + debug!("find_existential_constraints: visiting {:?}", it); + let def_id = self.tcx.hir().local_def_id(it.hir_id); + // The opaque type itself or its children are not within its reveal scope. + if def_id != self.def_id { + self.check(def_id); + intravisit::walk_item(self, it); + } + } + fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { + debug!("find_existential_constraints: visiting {:?}", it); + let def_id = self.tcx.hir().local_def_id(it.hir_id); + // The opaque type itself or its children are not within its reveal scope. + if def_id != self.def_id { + self.check(def_id); + intravisit::walk_impl_item(self, it); + } + } + fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { + debug!("find_existential_constraints: visiting {:?}", it); + let def_id = self.tcx.hir().local_def_id(it.hir_id); + self.check(def_id); + intravisit::walk_trait_item(self, it); + } + } + + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let scope = tcx.hir().get_defining_scope(hir_id); + let mut locator = ConstraintLocator { def_id, tcx, found: None }; + + debug!("find_opaque_ty_constraints: scope={:?}", scope); + + if scope == hir::CRATE_HIR_ID { + intravisit::walk_crate(&mut locator, tcx.hir().krate()); + } else { + debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope)); + match tcx.hir().get(scope) { + // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods + // This allows our visitor to process the defining item itself, causing + // it to pick up any 'sibling' defining uses. + // + // For example, this code: + // ``` + // fn foo() { + // type Blah = impl Debug; + // let my_closure = || -> Blah { true }; + // } + // ``` + // + // requires us to explicitly process `foo()` in order + // to notice the defining usage of `Blah`. + Node::Item(ref it) => locator.visit_item(it), + Node::ImplItem(ref it) => locator.visit_impl_item(it), + Node::TraitItem(ref it) => locator.visit_trait_item(it), + other => bug!("{:?} is not a valid scope for an opaque type item", other), + } + } + + match locator.found { + Some((_, ty, _)) => ty, + None => { + let span = tcx.def_span(def_id); + tcx.sess.span_err(span, "could not find defining uses"); + tcx.types.err + } + } +} + +fn infer_placeholder_type( + tcx: TyCtxt<'_>, + def_id: DefId, + body_id: hir::BodyId, + span: Span, + item_ident: Ident, +) -> Ty<'_> { + let ty = tcx.diagnostic_only_typeck_tables_of(def_id).node_type(body_id.hir_id); + + // If this came from a free `const` or `static mut?` item, + // then the user may have written e.g. `const A = 42;`. + // In this case, the parser has stashed a diagnostic for + // us to improve in typeck so we do that now. + match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) { + Some(mut err) => { + // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. + // We are typeck and have the real type, so remove that and suggest the actual type. + err.suggestions.clear(); + err.span_suggestion( + span, + "provide a type for the item", + format!("{}: {}", item_ident, ty), + Applicability::MachineApplicable, + ) + .emit(); + } + None => { + let mut diag = bad_placeholder_type(tcx, vec![span]); + if ty != tcx.types.err { + diag.span_suggestion( + span, + "replace `_` with the correct type", + ty.to_string(), + Applicability::MaybeIncorrect, + ); + } + diag.emit(); + } + } + + ty +} + +fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) { + struct_span_err!( + tcx.sess, + span, + E0202, + "associated types are not yet supported in inherent impls (see #8995)" + ) + .emit(); +} From d863978f89c74bd5cb90baa47331d421bbfd3936 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 14 Feb 2020 22:39:55 +0000 Subject: [PATCH 25/25] Fix tests after rebase --- src/libstd/future.rs | 3 +- src/test/ui/async-await/no-const-async.rs | 1 + src/test/ui/async-await/no-const-async.stderr | 12 +++- ...row-immutable-upvar-mutation-impl-trait.rs | 14 +++++ ...immutable-upvar-mutation-impl-trait.stderr | 16 +++++ .../borrow-immutable-upvar-mutation.rs | 26 ++++---- .../borrow-immutable-upvar-mutation.stderr | 61 ++++++++----------- 7 files changed, 82 insertions(+), 51 deletions(-) create mode 100644 src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs create mode 100644 src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr diff --git a/src/libstd/future.rs b/src/libstd/future.rs index f74c84e6dfd48..7b1beb1ecda80 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -16,9 +16,10 @@ pub use core::future::*; /// /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). +// This is `const` to avoid extra errors after we recover from `const async fn` #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] -pub fn from_generator>(x: T) -> impl Future { +pub const fn from_generator>(x: T) -> impl Future { GenFuture(x) } diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs index b3c59734e036f..57a9f175ca318 100644 --- a/src/test/ui/async-await/no-const-async.rs +++ b/src/test/ui/async-await/no-const-async.rs @@ -3,3 +3,4 @@ pub const async fn x() {} //~^ ERROR functions cannot be both `const` and `async` +//~| ERROR `impl Trait` in const fn is unstable diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr index f6ae0f1447ced..07559cd240bb6 100644 --- a/src/test/ui/async-await/no-const-async.stderr +++ b/src/test/ui/async-await/no-const-async.stderr @@ -7,5 +7,15 @@ LL | pub const async fn x() {} | | `async` because of this | `const` because of this -error: aborting due to previous error +error[E0723]: `impl Trait` in const fn is unstable + --> $DIR/no-const-async.rs:4:24 + | +LL | pub const async fn x() {} + | ^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs new file mode 100644 index 0000000000000..57198cb95e770 --- /dev/null +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs @@ -0,0 +1,14 @@ +#![feature(unboxed_closures)] + +// Tests that we can't assign to or mutably borrow upvars from `Fn` +// closures (issue #17780) + +fn main() {} + +fn bar() -> impl Fn() -> usize { + let mut x = 0; + move || { + x += 1; //~ ERROR cannot assign + x + } +} diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr new file mode 100644 index 0000000000000..003c40d27736d --- /dev/null +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr @@ -0,0 +1,16 @@ +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation-impl-trait.rs:11:9 + | +LL | fn bar() -> impl Fn() -> usize { + | --- ------------------ change this to return `FnMut` instead of `Fn` +LL | let mut x = 0; +LL | / move || { +LL | | x += 1; + | | ^^^^^^ cannot assign +LL | | x +LL | | } + | |_____- in this closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs index 62e27bcf1643f..e2f016614bf86 100644 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs @@ -3,10 +3,16 @@ // Tests that we can't assign to or mutably borrow upvars from `Fn` // closures (issue #17780) -fn set(x: &mut usize) { *x = 5; } +fn set(x: &mut usize) { + *x = 5; +} -fn to_fn>(f: F) -> F { f } -fn to_fn_mut>(f: F) -> F { f } +fn to_fn>(f: F) -> F { + f +} +fn to_fn_mut>(f: F) -> F { + f +} fn main() { // By-ref captures @@ -33,7 +39,11 @@ fn main() { let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow let mut z = 0; - let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign + let _h = to_fn_mut(move || { + set(&mut z); + to_fn(move || z = 42); + //~^ ERROR cannot assign + }); } } @@ -44,11 +54,3 @@ fn foo() -> Box usize> { x }) } - -fn bar() -> impl Fn() -> usize { - let mut x = 0; - move || { - x += 1; //~ ERROR cannot assign - x - } -} diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr index 3046b047d00f6..a28cb7431e6a9 100644 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr @@ -1,8 +1,8 @@ error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:15:27 + --> $DIR/borrow-immutable-upvar-mutation.rs:21:27 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... LL | let _f = to_fn(|| x = 42); | ----- ^^^^^^ cannot assign @@ -10,10 +10,10 @@ LL | let _f = to_fn(|| x = 42); | expects `Fn` instead of `FnMut` error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:18:31 + --> $DIR/borrow-immutable-upvar-mutation.rs:24:31 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... LL | let _g = to_fn(|| set(&mut y)); | ----- ^^^^^^ cannot borrow as mutable @@ -21,10 +21,10 @@ LL | let _g = to_fn(|| set(&mut y)); | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:23:22 + --> $DIR/borrow-immutable-upvar-mutation.rs:29:22 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... LL | to_fn(|| z = 42); | ----- ^^^^^^ cannot assign @@ -32,10 +32,10 @@ LL | to_fn(|| z = 42); | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:30:32 + --> $DIR/borrow-immutable-upvar-mutation.rs:36:32 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... LL | let _f = to_fn(move || x = 42); | ----- ^^^^^^ cannot assign @@ -43,10 +43,10 @@ LL | let _f = to_fn(move || x = 42); | expects `Fn` instead of `FnMut` error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:33:36 + --> $DIR/borrow-immutable-upvar-mutation.rs:39:36 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... LL | let _g = to_fn(move || set(&mut y)); | ----- ^^^^^^ cannot borrow as mutable @@ -54,18 +54,18 @@ LL | let _g = to_fn(move || set(&mut y)); | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:36:65 + --> $DIR/borrow-immutable-upvar-mutation.rs:44:27 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... -LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); - | ----- ^^^^^^ cannot assign - | | - | expects `Fn` instead of `FnMut` +LL | to_fn(move || z = 42); + | ----- ^^^^^^ cannot assign + | | + | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:43:9 + --> $DIR/borrow-immutable-upvar-mutation.rs:53:9 | LL | fn foo() -> Box usize> { | --- ---------------------- change this to return `FnMut` instead of `Fn` @@ -78,20 +78,7 @@ LL | | x LL | | }) | |_____- in this closure -error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:51:9 - | -LL | fn bar() -> impl Fn() -> usize { - | --- ------------------ change this to return `FnMut` instead of `Fn` -LL | let mut x = 0; -LL | / move || { -LL | | x += 1; - | | ^^^^^^ cannot assign -LL | | x -LL | | } - | |_____- in this closure - -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0594, E0596. For more information about an error, try `rustc --explain E0594`.