Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not record unresolved const vars in generator interior #104788

Merged
merged 1 commit into from
Nov 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions compiler/rustc_hir_typeck/src/generator_interior/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -108,21 +108,21 @@ 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 {}",
self.kind, yield_data.source
);

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();
}
Expand Down Expand Up @@ -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: {:?}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 6 additions & 7 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Span>)>
/// Returns the first unresolved type or const variable contained in `T`.
pub fn first_unresolved_const_or_ty_var<T>(
&self,
value: &T,
) -> Option<(ty::Term<'tcx>, Option<Span>)>
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(
Expand Down
86 changes: 58 additions & 28 deletions compiler/rustc_infer/src/infer/resolve.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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<Span>);
impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
type BreakTy = (ty::Term<'tcx>, Option<Span>);
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
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<Self::BreakTy> {
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)
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_middle/src/ty/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,15 @@ impl<'tcx> From<ty::Const<'tcx>> for GenericArg<'tcx> {
}
}

impl<'tcx> From<ty::Term<'tcx>> 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> {
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/generator/unresolved-ct-var.rs
Original file line number Diff line number Diff line change
@@ -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
};
}
78 changes: 78 additions & 0 deletions src/test/ui/generator/unresolved-ct-var.stderr
Original file line number Diff line number Diff line change
@@ -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`.