From 62108124946582e7536d84adedc1507e5c35e8fd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 23 Nov 2022 19:38:22 +0000 Subject: [PATCH] Do not record unresolved const vars in generator interior --- .../src/generator_interior/mod.rs | 14 +-- .../infer/error_reporting/need_type_info.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 13 ++- compiler/rustc_infer/src/infer/resolve.rs | 86 +++++++++++++------ compiler/rustc_middle/src/ty/subst.rs | 9 ++ src/test/ui/generator/unresolved-ct-var.rs | 14 +++ .../ui/generator/unresolved-ct-var.stderr | 78 +++++++++++++++++ 7 files changed, 173 insertions(+), 43 deletions(-) create mode 100644 src/test/ui/generator/unresolved-ct-var.rs create mode 100644 src/test/ui/generator/unresolved-ct-var.stderr diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 30d2c63fd849a..50722c42a6c61 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -98,8 +98,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { expr, scope, ty, self.expr_count, yield_data.span ); - if let Some((unresolved_type, unresolved_type_span)) = - self.fcx.unresolved_type_vars(&ty) + if let Some((unresolved_term, unresolved_type_span)) = + self.fcx.first_unresolved_const_or_ty_var(&ty) { // If unresolved type isn't a ty_var then unresolved_type_span is None let span = self @@ -108,13 +108,13 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { // If we encounter an int/float variable, then inference fallback didn't // finish due to some other error. Don't emit spurious additional errors. - if let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = - unresolved_type.kind() + if let Some(unresolved_ty) = unresolved_term.ty() + && let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = unresolved_ty.kind() { self.fcx .tcx .sess - .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_type)); + .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_term)); } else { let note = format!( "the type is part of the {} because of this {}", @@ -122,7 +122,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { ); self.fcx - .need_type_info_err_in_generator(self.kind, span, unresolved_type) + .need_type_info_err_in_generator(self.kind, span, unresolved_term) .span_note(yield_data.span, &*note) .emit(); } @@ -162,7 +162,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { expr.map(|e| e.span) ); if let Some((unresolved_type, unresolved_type_span)) = - self.fcx.unresolved_type_vars(&ty) + self.fcx.first_unresolved_const_or_ty_var(&ty) { debug!( "remained unresolved_type = {:?}, unresolved_type_span: {:?}", diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 7b3178e610fe4..8c63f55314187 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -571,7 +571,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, kind: hir::GeneratorKind, span: Span, - ty: Ty<'tcx>, + ty: ty::Term<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let ty = self.resolve_vars_if_possible(ty); let data = self.extract_inference_diagnostics_data(ty.into(), None); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 67feb83faace6..cda9299dcb6e7 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1421,16 +1421,15 @@ impl<'tcx> InferCtxt<'tcx> { value.fold_with(&mut r) } - /// Returns the first unresolved variable contained in `T`. In the - /// process of visiting `T`, this will resolve (where possible) - /// type variables in `T`, but it never constructs the final, - /// resolved type, so it's more efficient than - /// `resolve_vars_if_possible()`. - pub fn unresolved_type_vars(&self, value: &T) -> Option<(Ty<'tcx>, Option)> + /// Returns the first unresolved type or const variable contained in `T`. + pub fn first_unresolved_const_or_ty_var( + &self, + value: &T, + ) -> Option<(ty::Term<'tcx>, Option)> where T: TypeVisitable<'tcx>, { - value.visit_with(&mut resolve::UnresolvedTypeFinder::new(self)).break_value() + value.visit_with(&mut resolve::UnresolvedTypeOrConstFinder::new(self)).break_value() } pub fn probe_const_var( diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 4db4ff2388d77..8671f8d45a917 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -1,5 +1,6 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::{FixupError, FixupResult, InferCtxt, Span}; +use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor}; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable}; @@ -110,48 +111,77 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { /// type variables that don't yet have a value. The first unresolved type is stored. /// It does not construct the fully resolved type (which might /// involve some hashing and so forth). -pub struct UnresolvedTypeFinder<'a, 'tcx> { +pub struct UnresolvedTypeOrConstFinder<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, } -impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { +impl<'a, 'tcx> UnresolvedTypeOrConstFinder<'a, 'tcx> { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - UnresolvedTypeFinder { infcx } + UnresolvedTypeOrConstFinder { infcx } } } -impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { - type BreakTy = (Ty<'tcx>, Option); +impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> { + type BreakTy = (ty::Term<'tcx>, Option); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let t = self.infcx.shallow_resolve(t); - if t.has_infer_types() { - if let ty::Infer(infer_ty) = *t.kind() { - // Since we called `shallow_resolve` above, this must - // be an (as yet...) unresolved inference variable. - let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty { - let mut inner = self.infcx.inner.borrow_mut(); - let ty_vars = &inner.type_variables(); - if let TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(_, _), - span, - } = *ty_vars.var_origin(ty_vid) - { - Some(span) - } else { - None - } + if let ty::Infer(infer_ty) = *t.kind() { + // Since we called `shallow_resolve` above, this must + // be an (as yet...) unresolved inference variable. + let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty { + let mut inner = self.infcx.inner.borrow_mut(); + let ty_vars = &inner.type_variables(); + if let TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeParameterDefinition(_, _), + span, + } = *ty_vars.var_origin(ty_vid) + { + Some(span) } else { None - }; - ControlFlow::Break((t, ty_var_span)) + } } else { - // Otherwise, visit its contents. - t.super_visit_with(self) - } + None + }; + ControlFlow::Break((t.into(), ty_var_span)) + } else if !t.has_non_region_infer() { + // All const/type variables in inference types must already be resolved, + // no need to visit the contents. + ControlFlow::CONTINUE } else { - // All type variables in inference types must already be resolved, - // - no need to visit the contents, continue visiting. + // Otherwise, keep visiting. + t.super_visit_with(self) + } + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { + let ct = self.infcx.shallow_resolve(ct); + if let ty::ConstKind::Infer(i) = ct.kind() { + // Since we called `shallow_resolve` above, this must + // be an (as yet...) unresolved inference variable. + let ct_var_span = if let ty::InferConst::Var(vid) = i { + let mut inner = self.infcx.inner.borrow_mut(); + let ct_vars = &mut inner.const_unification_table(); + if let ConstVariableOrigin { + span, + kind: ConstVariableOriginKind::ConstParameterDefinition(_, _), + } = ct_vars.probe_value(vid).origin + { + Some(span) + } else { + None + } + } else { + None + }; + ControlFlow::Break((ct.into(), ct_var_span)) + } else if !ct.has_non_region_infer() { + // All const/type variables in inference types must already be resolved, + // no need to visit the contents. ControlFlow::CONTINUE + } else { + // Otherwise, keep visiting. + ct.super_visit_with(self) } } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index c1cf7896db59a..239b67bd22674 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -140,6 +140,15 @@ impl<'tcx> From> for GenericArg<'tcx> { } } +impl<'tcx> From> for GenericArg<'tcx> { + fn from(value: ty::Term<'tcx>) -> Self { + match value.unpack() { + ty::TermKind::Ty(t) => t.into(), + ty::TermKind::Const(c) => c.into(), + } + } +} + impl<'tcx> GenericArg<'tcx> { #[inline] pub fn unpack(self) -> GenericArgKind<'tcx> { diff --git a/src/test/ui/generator/unresolved-ct-var.rs b/src/test/ui/generator/unresolved-ct-var.rs new file mode 100644 index 0000000000000..0a1570fc2395e --- /dev/null +++ b/src/test/ui/generator/unresolved-ct-var.rs @@ -0,0 +1,14 @@ +// incremental +// edition:2021 + +fn main() { + let _ = async { + let s = std::array::from_fn(|_| ()).await; + //~^ ERROR `[(); _]` is not a future + //~| ERROR type inside `async` block must be known in this context + //~| ERROR type inside `async` block must be known in this context + //~| ERROR type inside `async` block must be known in this context + //~| ERROR type inside `async` block must be known in this context + //~| ERROR type inside `async` block must be known in this context + }; +} diff --git a/src/test/ui/generator/unresolved-ct-var.stderr b/src/test/ui/generator/unresolved-ct-var.stderr new file mode 100644 index 0000000000000..fdf00dfad7ab7 --- /dev/null +++ b/src/test/ui/generator/unresolved-ct-var.stderr @@ -0,0 +1,78 @@ +error[E0277]: `[(); _]` is not a future + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ---------------------------^^^^^^ + | | | + | | `[(); _]` is not a future + | | help: remove the `.await` + | this call returns `[(); _]` + | + = help: the trait `Future` is not implemented for `[(); _]` + = note: [(); _] must be a future or must implement `IntoFuture` to be awaited + = note: required for `[(); _]` to implement `IntoFuture` + +error[E0698]: type inside `async` block must be known in this context + --> $DIR/unresolved-ct-var.rs:6:17 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn` + | +note: the type is part of the `async` block because of this `await` + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^ + +error[E0698]: type inside `async` block must be known in this context + --> $DIR/unresolved-ct-var.rs:6:17 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn` + | +note: the type is part of the `async` block because of this `await` + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^ + +error[E0698]: type inside `async` block must be known in this context + --> $DIR/unresolved-ct-var.rs:6:17 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn` + | +note: the type is part of the `async` block because of this `await` + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^ + +error[E0698]: type inside `async` block must be known in this context + --> $DIR/unresolved-ct-var.rs:6:17 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn` + | +note: the type is part of the `async` block because of this `await` + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^ + +error[E0698]: type inside `async` block must be known in this context + --> $DIR/unresolved-ct-var.rs:6:17 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn` + | +note: the type is part of the `async` block because of this `await` + --> $DIR/unresolved-ct-var.rs:6:44 + | +LL | let s = std::array::from_fn(|_| ()).await; + | ^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0277, E0698. +For more information about an error, try `rustc --explain E0277`.