-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Ensure no type errors when calling Closure/Generator upvars_ty #78392
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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<Item = Ty<'tcx>> + '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<Ty<'tcx>, 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<Item = Ty<'tcx>> + '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<Ty<'tcx>, 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<Item = Ty<'tcx>> + '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<Ty<'tcx>, ErrorReported> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pre-existing to some extent, but I think this function merits a comment. Something like: Returns a tuple type whose elements are the types of the upvars captured by this closure/generator. Returns |
||
match self { | ||
UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(), | ||
UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: it feels like we may want a helper for this pattern of shallow resolving the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see too much benefit here, especially since each case Tuple/Infer/Error will need to be handled at each call site. Also, we only do this in 3 spots. |
||
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) => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think this function merits a comment too. Something like
That said, this will still ICE in the event of a
Ty::Err
, right? I'm not sure if that's a great idea, as it means that every use of this function has to be guarded by a call totupled_upvars_ty
. Why not make this function return aResult
as well (or perhaps an empty vector)?