diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 8b97a87f214b8..8cbbcff0878e8 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -104,7 +104,9 @@ impl FlagComputation { self.add_ty(substs.return_ty()); self.add_ty(substs.witness()); self.add_ty(substs.yield_ty()); - self.add_ty(substs.tupled_upvars_ty()); + if let Ok(tupled_ty) = substs.tupled_upvars_ty() { + self.add_ty(tupled_ty); + } } &ty::GeneratorWitness(ts) => { @@ -122,7 +124,9 @@ impl FlagComputation { self.add_ty(substs.sig_as_fn_ptr_ty()); self.add_ty(substs.kind_ty()); - self.add_ty(substs.tupled_upvars_ty()); + if let Ok(tupled_ty) = substs.tupled_upvars_ty() { + self.add_ty(tupled_ty); + } } &ty::Bound(debruijn, _) => { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 8b3fb87507061..f63ec095da29c 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -506,9 +506,9 @@ fn polymorphize<'tcx>( // the unpolymorphized upvar closure would result in a polymorphized closure producing // multiple mono items (and eventually symbol clashes). let upvars_ty = if tcx.is_closure(def_id) { - Some(substs.as_closure().tupled_upvars_ty()) + substs.as_closure().tupled_upvars_ty().ok() } else if tcx.type_of(def_id).is_generator() { - Some(substs.as_generator().tupled_upvars_ty()) + substs.as_generator().tupled_upvars_ty().ok() } else { None }; diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 91c3dcbfa81cf..9b808f1525b63 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -609,12 +609,23 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { ty::Generator(def_id, substs, _) => self.generator_layout(ty, def_id, substs)?, ty::Closure(_, ref substs) => { - let tys = substs.as_closure().upvar_tys(); - univariant( - &tys.map(|ty| self.layout_of(ty)).collect::, _>>()?, - &ReprOptions::default(), - StructKind::AlwaysSized, - )? + let substs = substs.as_closure(); + if substs.tupled_upvars_ty().is_ok() { + let tys = substs.upvar_tys(); + univariant( + &tys.map(|ty| self.layout_of(ty)).collect::, _>>()?, + &ReprOptions::default(), + StructKind::AlwaysSized, + )? + } else { + univariant( + &std::iter::empty() + .map(|ty| self.layout_of(ty)) + .collect::, _>>()?, + &ReprOptions::default(), + StructKind::AlwaysSized, + )? + } } ty::Tuple(tys) => { @@ -1396,10 +1407,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let info = tcx.generator_layout(def_id); let (ineligible_locals, assignments) = self.generator_saved_local_eligibility(&info); + let substs = substs.as_generator(); + // Build a prefix layout, including "promoting" all ineligible // locals as part of the prefix. We compute the layout of all of // these fields at once to get optimal packing. - let tag_index = substs.as_generator().prefix_tys().count(); + let tag_index = + if substs.tupled_upvars_ty().is_ok() { substs.prefix_tys().count() } else { 0 }; // `info.variant_fields` already accounts for the reserved variants, so no need to add them. let max_discr = (info.variant_fields.len() - 1) as u128; @@ -1415,7 +1429,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .map(|ty| tcx.mk_maybe_uninit(ty)) .map(|ty| self.layout_of(ty)); let prefix_layouts = substs - .as_generator() .prefix_tys() .map(|ty| self.layout_of(ty)) .chain(iter::once(Ok(tag_layout))) diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs index 86750d5c08111..ff0da04ebfd60 100644 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -96,14 +96,16 @@ fn compute_components( } ty::Closure(_, ref substs) => { - let tupled_ty = substs.as_closure().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); + if let Ok(tupled_ty) = substs.as_closure().tupled_upvars_ty() { + compute_components(tcx, tupled_ty, out, visited); + } } ty::Generator(_, ref substs, _) => { // Same as the closure case - let tupled_ty = substs.as_generator().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); + if let Ok(tupled_ty) = substs.as_generator().tupled_upvars_ty() { + compute_components(tcx, tupled_ty, out, visited); + } // We ignore regions in the generator interior as we don't // want these to affect region inference diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index de24322e07de2..728147a1e94b8 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -664,7 +664,11 @@ pub trait PrettyPrinter<'tcx>: p!(print_def_path(did, substs)); p!(" upvar_tys=("); if !substs.as_generator().is_valid() { - p!("unavailable"); + if substs.as_generator().tupled_upvars_ty().is_err() { + p!("err"); + } else { + p!("unavailable"); + } } else { self = self.comma_sep(substs.as_generator().upvar_tys())?; } @@ -699,7 +703,13 @@ pub trait PrettyPrinter<'tcx>: } else { p!(print_def_path(did, substs)); if !substs.as_closure().is_valid() { - p!(" closure_substs=(unavailable)"); + p!(" closure_substs=("); + if substs.as_closure().tupled_upvars_ty().is_err() { + p!("err"); + } else { + p!("unavailable"); + } + p!(")"); } else { p!(" closure_kind_ty=", print(substs.as_closure().kind_ty())); p!( diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 0fd48d0928257..21e6b6eb52edb 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -14,6 +14,7 @@ use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS}; use polonius_engine::Atom; use rustc_ast as ast; use rustc_data_structures::captures::Captures; +use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; @@ -388,15 +389,23 @@ impl<'tcx> ClosureSubsts<'tcx> { self.split().parent_substs } + /// Returns an iterator that iterates the types of paths captured by a closure. + /// Note it's possible that there was a type error that prevented us from figuring out + /// the types of the upvars captured by the closure. + /// + /// This function can be safely called if `self.tupled_upvars_ty().is_ok()` is true. #[inline] pub fn upvar_tys(self) -> impl Iterator> + 'tcx { - self.tupled_upvars_ty().tuple_fields() + self.split().tupled_upvars_ty.expect_ty().tuple_fields() } - /// Returns the tuple type representing the upvars for this closure. + /// Returns a tuple type containing the types of paths captured by the closure. + /// Returns Err(ErrorReported) if a type error prevented us from figuring out + /// the types of the upvars for this closure. #[inline] - pub fn tupled_upvars_ty(self) -> Ty<'tcx> { - self.split().tupled_upvars_ty.expect_ty() + pub fn tupled_upvars_ty(self) -> Result, ErrorReported> { + let tupled_ty = self.split().tupled_upvars_ty.expect_ty(); + if let TyKind::Error(_) = tupled_ty.kind() { Err(ErrorReported) } else { Ok(tupled_ty) } } /// Returns the closure kind for this closure; may return a type @@ -515,15 +524,23 @@ impl<'tcx> GeneratorSubsts<'tcx> { self.split().witness.expect_ty() } + /// Returns an iterator that iterates the types of paths captured by a generator. + /// Note it's possible that there was a type error that prevented us from figuring out + /// the types of the upvars captured by the generator. + /// + /// This function can be safely called if `self.tupled_upvars_ty().is_ok()` is true. #[inline] pub fn upvar_tys(self) -> impl Iterator> + 'tcx { - self.tupled_upvars_ty().tuple_fields() + self.split().tupled_upvars_ty.expect_ty().tuple_fields() } - /// Returns the tuple type representing the upvars for this generator. + /// Returns a tuple type containing the types of paths captured by the generator. + /// Returns Err(ErrorReported) if a type error prevented us from figuring out + /// the types of the upvars for this generator. #[inline] - pub fn tupled_upvars_ty(self) -> Ty<'tcx> { - self.split().tupled_upvars_ty.expect_ty() + pub fn tupled_upvars_ty(self) -> Result, ErrorReported> { + let tupled_ty = self.split().tupled_upvars_ty.expect_ty(); + if let TyKind::Error(_) = tupled_ty.kind() { Err(ErrorReported) } else { Ok(tupled_ty) } } /// Returns the type representing the resume type of the generator. @@ -660,6 +677,11 @@ pub enum UpvarSubsts<'tcx> { } impl<'tcx> UpvarSubsts<'tcx> { + /// Returns an iterator that iterates the types of paths captured by a closure/generator. + /// Note it's possible that there was a type error that prevented us from figuring out + /// the types of the upvars captured by the closure/generator. + /// + /// This function can be safely called if `self.tupled_upvars_ty().is_ok()` is true. #[inline] pub fn upvar_tys(self) -> impl Iterator> + 'tcx { let tupled_upvars_ty = match self { @@ -669,8 +691,11 @@ impl<'tcx> UpvarSubsts<'tcx> { tupled_upvars_ty.expect_ty().tuple_fields() } + /// Returns a tuple type containing the types of paths captured by a closure/generator. + /// Returns Err(ErrorReported) if a type error prevented us from figuring out + /// the types of the upvars for this closure/generator. #[inline] - pub fn tupled_upvars_ty(self) -> Ty<'tcx> { + pub fn tupled_upvars_ty(self) -> Result, ErrorReported> { match self { UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(), UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(), diff --git a/compiler/rustc_mir/src/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs index 0e2d8e5495b72..c38f4f34c2be5 100644 --- a/compiler/rustc_mir/src/util/elaborate_drops.rs +++ b/compiler/rustc_mir/src/util/elaborate_drops.rs @@ -850,7 +850,12 @@ where let ty = self.place_ty(self.place); match ty.kind() { ty::Closure(_, substs) => { - let tys: Vec<_> = substs.as_closure().upvar_tys().collect(); + let substs = substs.as_closure(); + let tys: Vec<_> = if substs.tupled_upvars_ty().is_ok() { + substs.upvar_tys().collect() + } else { + vec![] + }; self.open_drop_for_tuple(&tys) } // Note that `elaborate_drops` only drops the upvars of a generator, @@ -860,7 +865,12 @@ where // It effetively only contains upvars until the generator transformation runs. // See librustc_body/transform/generator.rs for more details. ty::Generator(_, substs, _) => { - let tys: Vec<_> = substs.as_generator().upvar_tys().collect(); + let substs = substs.as_generator(); + let tys: Vec<_> = if substs.tupled_upvars_ty().is_ok() { + substs.upvar_tys().collect() + } else { + vec![] + }; self.open_drop_for_tuple(&tys) } ty::Tuple(..) => { diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index ecaafee77e29f..dc9a144e3f459 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -717,10 +717,12 @@ where ty::Closure(_, ref substs) => { // Skip lifetime parameters of the enclosing item(s) - substs.as_closure().tupled_upvars_ty().visit_with(self); + if let Ok(tupled_ty) = substs.as_closure().tupled_upvars_ty() { + tupled_ty.visit_with(self); - for upvar_ty in substs.as_closure().upvar_tys() { - upvar_ty.visit_with(self); + for upvar_ty in substs.as_closure().upvar_tys() { + upvar_ty.visit_with(self); + } } substs.as_closure().sig_as_fn_ptr_ty().visit_with(self); @@ -730,10 +732,12 @@ where // Skip lifetime parameters of the enclosing item(s) // Also skip the witness type, because that has no free regions. - substs.as_generator().tupled_upvars_ty().visit_with(self); + if let Ok(tupled_ty) = substs.as_generator().tupled_upvars_ty() { + tupled_ty.visit_with(self); - for upvar_ty in substs.as_generator().upvar_tys() { - upvar_ty.visit_with(self); + for upvar_ty in substs.as_closure().upvar_tys() { + upvar_ty.visit_with(self); + } } substs.as_generator().return_ty().visit_with(self); diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 8212823a6dbc7..344d13ba53978 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -110,7 +110,12 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { // check if *any* of those are trivial. ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), ty::Closure(_, ref substs) => { - trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty()) + if let Ok(tupled_tys) = substs.as_closure().tupled_upvars_ty() { + trivial_dropck_outlives(tcx, tupled_tys) + } else { + // Same as the error case above + true + } } ty::Adt(def, _) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4cc4bc0acdab6..40818a0c36384 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1601,12 +1601,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Closure(_, substs) => { // (*) binder moved here - let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); - if let ty::Infer(ty::TyVar(_)) = ty.kind() { - // Not yet resolved. - Ambiguous + + if let Ok(tupled_tys) = substs.as_closure().tupled_upvars_ty() { + let ty = self.infcx.shallow_resolve(tupled_tys); + if let ty::Infer(ty::TyVar(_)) = ty.kind() { + // Not yet resolved. + Ambiguous + } else { + Where( + obligation.predicate.rebind(substs.as_closure().upvar_tys().collect()), + ) + } } else { - Where(obligation.predicate.rebind(substs.as_closure().upvar_tys().collect())) + Where(ty::Binder::dummy(Vec::new())) } } @@ -1677,14 +1684,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::Closure(_, ref substs) => { - let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); - vec![ty] + if let Ok(tupled_tys) = substs.as_closure().tupled_upvars_ty() { + let ty = self.infcx.shallow_resolve(tupled_tys); + vec![ty] + } else { + vec![] + } } ty::Generator(_, ref substs, _) => { - let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); + let tys_vec = if let Ok(tupled_tys) = substs.as_closure().tupled_upvars_ty() { + let ty = self.infcx.shallow_resolve(tupled_tys); + vec![ty] + } else { + vec![] + }; let witness = substs.as_generator().witness(); - vec![ty].into_iter().chain(iter::once(witness)).collect() + tys_vec.into_iter().chain(iter::once(witness)).collect() } ty::GeneratorWitness(types) => { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 496dff6c5b2cf..e789a11e0eea2 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -593,7 +593,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // only inspects the upvar types). walker.skip_current_subtree(); // subtree handled below // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(substs.as_closure().tupled_upvars_ty().into()); + if let Ok(tupled_tys) = substs.as_closure().tupled_upvars_ty() { + self.compute(tupled_tys.into()); + } } ty::FnPtr(_) => { diff --git a/compiler/rustc_ty/src/needs_drop.rs b/compiler/rustc_ty/src/needs_drop.rs index 0356bcec5498b..5bbf8225a4f0e 100644 --- a/compiler/rustc_ty/src/needs_drop.rs +++ b/compiler/rustc_ty/src/needs_drop.rs @@ -94,15 +94,20 @@ where _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (), ty::Closure(_, substs) => { - for upvar_ty in substs.as_closure().upvar_tys() { - queue_type(self, upvar_ty); + let substs = substs.as_closure(); + if substs.tupled_upvars_ty().is_ok() { + for upvar_ty in substs.upvar_tys() { + queue_type(self, upvar_ty); + } } } ty::Generator(def_id, substs, _) => { let substs = substs.as_generator(); - for upvar_ty in substs.upvar_tys() { - queue_type(self, upvar_ty); + if substs.tupled_upvars_ty().is_ok() { + for upvar_ty in substs.upvar_tys() { + queue_type(self, upvar_ty); + } } let witness = substs.witness(); diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 1e97bd65a79f4..0cf75851ccf25 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -206,7 +206,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Build a tuple (U0..Un) of the final upvar types U0..Un // and unify the upvar tupe type in the closure with it: let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter()); - self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type); + if let Ok(tupled_upvars) = substs.tupled_upvars_ty() { + self.demand_suptype(span, tupled_upvars, final_tupled_upvars_type); + } // If we are also inferred the closure kind here, // process any deferred resolutions. diff --git a/src/test/ui/issues/issue-77993-1.rs b/src/test/ui/issues/issue-77993-1.rs new file mode 100644 index 0000000000000..515b3bc09f076 --- /dev/null +++ b/src/test/ui/issues/issue-77993-1.rs @@ -0,0 +1,12 @@ +#[derive(Clone)] +struct InGroup { + it: It, + //~^ ERROR cannot find type `It` in this scope + f: F, +} +fn dates_in_year() -> impl Clone { + InGroup { f: |d| d } + //~^ ERROR missing field `it` in initializer of `InGroup<_>` +} + +fn main() {} diff --git a/src/test/ui/issues/issue-77993-1.stderr b/src/test/ui/issues/issue-77993-1.stderr new file mode 100644 index 0000000000000..3dc78ba6f8563 --- /dev/null +++ b/src/test/ui/issues/issue-77993-1.stderr @@ -0,0 +1,16 @@ +error[E0412]: cannot find type `It` in this scope + --> $DIR/issue-77993-1.rs:3:9 + | +LL | it: It, + | ^^ not found in this scope + +error[E0063]: missing field `it` in initializer of `InGroup<_>` + --> $DIR/issue-77993-1.rs:8:5 + | +LL | InGroup { f: |d| d } + | ^^^^^^^ missing `it` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0063, E0412. +For more information about an error, try `rustc --explain E0063`. diff --git a/src/test/ui/issues/issue-77993-2.rs b/src/test/ui/issues/issue-77993-2.rs new file mode 100644 index 0000000000000..4d554a0a1d0e1 --- /dev/null +++ b/src/test/ui/issues/issue-77993-2.rs @@ -0,0 +1,9 @@ +// edition:2018 + +async fn test() -> Result<(), Box> { + macro!(); + //~^ ERROR expected identifier, found `!` + Ok(()) +} + +fn main() {} diff --git a/src/test/ui/issues/issue-77993-2.stderr b/src/test/ui/issues/issue-77993-2.stderr new file mode 100644 index 0000000000000..64b378f83fc03 --- /dev/null +++ b/src/test/ui/issues/issue-77993-2.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `!` + --> $DIR/issue-77993-2.rs:4:10 + | +LL | macro!(); + | ^ expected identifier + +error: aborting due to previous error +