Skip to content

Commit

Permalink
Use tuple inference
Browse files Browse the repository at this point in the history
Use shallow_resolve and is_valid to check if tuple has been resolved
Check upvars_mentioned instead of substs to coerce closure to fnptr

Co-authored-by: Aman Arora <[email protected]>
  • Loading branch information
roxelo and arora-aman committed Jul 22, 2020
1 parent 3cf82b5 commit 3c19b06
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 39 deletions.
19 changes: 19 additions & 0 deletions src/librustc_middle/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,11 @@ impl<'tcx> ClosureSubsts<'tcx> {
self.split().tupled_upvars_ty.expect_ty().tuple_fields()
}

#[inline]
pub fn upvar_tuple_ty(self) -> Ty<'tcx> {
self.split().tupled_upvars_ty.expect_ty()
}

/// Returns the closure kind for this closure; may return a type
/// variable during inference. To get the closure kind during
/// inference, use `infcx.closure_kind(substs)`.
Expand Down Expand Up @@ -492,6 +497,11 @@ impl<'tcx> GeneratorSubsts<'tcx> {
self.split().tupled_upvars_ty.expect_ty().tuple_fields()
}

#[inline]
pub fn upvar_tuple_ty(self) -> Ty<'tcx> {
self.split().tupled_upvars_ty.expect_ty()
}

/// Returns the type representing the resume type of the generator.
pub fn resume_ty(self) -> Ty<'tcx> {
self.split().resume_ty.expect_ty()
Expand Down Expand Up @@ -634,6 +644,15 @@ impl<'tcx> UpvarSubsts<'tcx> {
};
tupled_upvars_ty.expect_ty().tuple_fields()
}

#[inline]
pub fn upvar_tuple_ty(self) -> Ty<'tcx> {
let tupled_upvars_ty = match self {
UpvarSubsts::Closure(substs) => substs.as_closure().split().tupled_upvars_ty,
UpvarSubsts::Generator(substs) => substs.as_generator().split().tupled_upvars_ty,
};
tupled_upvars_ty.expect_ty()
}
}

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, RustcEncodable, RustcDecodable)]
Expand Down
30 changes: 20 additions & 10 deletions src/librustc_trait_selection/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -716,24 +716,34 @@ where
ty::Closure(_, ref substs) => {
// Skip lifetime parameters of the enclosing item(s)

for upvar_ty in substs.as_closure().upvar_tys() {
upvar_ty.visit_with(self);
}
if !substs.as_closure().is_valid() {
// Not yet resolved.
ty.super_visit_with(self);
} else {
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);
substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
}
}

ty::Generator(_, ref substs, _) => {
// Skip lifetime parameters of the enclosing item(s)
// Also skip the witness type, because that has no free regions.

for upvar_ty in substs.as_generator().upvar_tys() {
upvar_ty.visit_with(self);
}
if !substs.as_generator().is_valid() {
// Not yet resolved.
ty.super_visit_with(self);
} else {
for upvar_ty in substs.as_generator().upvar_tys() {
upvar_ty.visit_with(self);
}

substs.as_generator().return_ty().visit_with(self);
substs.as_generator().yield_ty().visit_with(self);
substs.as_generator().resume_ty().visit_with(self);
substs.as_generator().return_ty().visit_with(self);
substs.as_generator().yield_ty().visit_with(self);
substs.as_generator().resume_ty().visit_with(self);
}
}
_ => {
ty.super_visit_with(self);
Expand Down
7 changes: 6 additions & 1 deletion src/librustc_trait_selection/traits/query/dropck_outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t))
if !substs.as_closure().is_valid() {
// Not yet resolved.
false
} else {
substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t))
}
}

ty::Adt(def, _) => {
Expand Down
30 changes: 26 additions & 4 deletions src/librustc_trait_selection/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1632,7 +1632,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

ty::Closure(_, substs) => {
// (*) binder moved here
Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
let ty = self.infcx.shallow_resolve(substs.as_closure().upvar_tuple_ty());
if let ty::Infer(ty::TyVar(_)) = ty.kind {
// Not yet resolved.
Ambiguous
} else {
Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
}
}

ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
Expand Down Expand Up @@ -1701,11 +1707,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
tys.iter().map(|k| k.expect_ty()).collect()
}

ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().collect(),
ty::Closure(_, ref substs) => {
let ty = self.infcx.shallow_resolve(substs.as_closure().upvar_tuple_ty());
if let ty::Infer(ty::TyVar(_)) = ty.kind {
// Not yet resolved.
warn!("asked to assemble constituent types of unexpected type: {:?}", t);
Vec::new()
} else {
substs.as_closure().upvar_tys().collect()
}
}

ty::Generator(_, ref substs, _) => {
let witness = substs.as_generator().witness();
substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
let ty = self.infcx.shallow_resolve(substs.as_generator().upvar_tuple_ty());
if let ty::Infer(ty::TyVar(_)) = ty.kind {
// Not yet resolved.
warn!("asked to assemble constituent types of unexpected type: {:?}", t);
Vec::new()
} else {
let witness = substs.as_generator().witness();
substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
}
}

ty::GeneratorWitness(types) => {
Expand Down
15 changes: 11 additions & 4 deletions src/librustc_trait_selection/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,10 +521,17 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
// are not directly inspecting closure types
// anyway, except via auto trait matching (which
// only inspects the upvar types).
walker.skip_current_subtree(); // subtree handled below
for upvar_ty in substs.as_closure().upvar_tys() {
// FIXME(eddyb) add the type to `walker` instead of recursing.
self.compute(upvar_ty.into());
let ty = self.infcx.shallow_resolve(substs.as_closure().upvar_tuple_ty());
if let ty::Infer(ty::TyVar(_)) = ty.kind {
// Not yet resolved.
walker.skip_current_subtree();
self.compute(ty.into());
} else {
walker.skip_current_subtree(); // subtree handled below
for upvar_ty in substs.as_closure().upvar_tys() {
// FIXME(eddyb) add the type to `walker` instead of recursing.
self.compute(upvar_ty.into());
}
}
}

Expand Down
18 changes: 5 additions & 13 deletions src/librustc_typeck/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
);

let tupled_upvars_ty =
self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(|upvars| {
upvars.iter().map(|(&var_hir_id, _)| {
// Create type variables (for now) to represent the transformed
// types of upvars. These will be unified during the upvar
// inference phase (`upvar.rs`).
self.infcx.next_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish upvar inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: self.tcx.hir().span(var_hir_id),
})
})
}));
let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish upvar inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: self.tcx.hir().span(expr.hir_id),
});

if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
{
Expand Down
23 changes: 19 additions & 4 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use crate::astconv::AstConv;
use crate::check::FnCtxt;
use rustc_errors::{struct_span_err, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
use rustc_middle::ty::adjustment::{
Expand Down Expand Up @@ -221,11 +222,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// unsafe qualifier.
self.coerce_from_fn_pointer(a, a_f, b)
}
ty::Closure(_, substs_a) => {
ty::Closure(closure_def_id_a, substs_a) => {
// Non-capturing closures are coercible to
// function pointers or unsafe function pointers.
// It cannot convert closures that require unsafe.
self.coerce_closure_to_fn(a, substs_a, b)
self.coerce_closure_to_fn(a, closure_def_id_a, substs_a, b)
}
_ => {
// Otherwise, just use unification rules.
Expand Down Expand Up @@ -762,6 +763,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn coerce_closure_to_fn(
&self,
a: Ty<'tcx>,
closure_def_id_a: DefId,
substs_a: SubstsRef<'tcx>,
b: Ty<'tcx>,
) -> CoerceResult<'tcx> {
Expand All @@ -772,7 +774,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let b = self.shallow_resolve(b);

match b.kind {
ty::FnPtr(fn_ty) if substs_a.as_closure().upvar_tys().next().is_none() => {
// At this point we haven't done capture analysis, which means
// that the ClosureSubsts just contains an inference variable instead
// of tuple of captured types.
//
// All we care here is if any variable is being captured and not the exact paths,
// so we check `upvars_mentioned` for root variables being captured.
ty::FnPtr(fn_ty)
if self.tcx.upvars_mentioned(closure_def_id_a.expect_local()).is_none() =>
{
// We coerce the closure, which has fn type
// `extern "rust-call" fn((arg0,arg1,...)) -> _`
// to
Expand Down Expand Up @@ -907,7 +917,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (a_sig, b_sig) = {
let is_capturing_closure = |ty| {
if let &ty::Closure(_, substs) = ty {
substs.as_closure().upvar_tys().next().is_some()
let ty = self.infcx.shallow_resolve(substs.as_closure().upvar_tuple_ty());
if let ty::Infer(ty::TyVar(_)) = ty.kind {
substs.as_closure().upvar_tys().next().is_some()
} else {
false
}
} else {
false
}
Expand Down
8 changes: 5 additions & 3 deletions src/librustc_typeck/check/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}",
closure_hir_id, substs, final_upvar_tys
);
for (upvar_ty, final_upvar_ty) in substs.upvar_tys().zip(final_upvar_tys) {
self.demand_suptype(span, upvar_ty, final_upvar_ty);
}

// 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_upvar_tuple_type = self.tcx.mk_tup(final_upvar_tys.iter());
self.demand_suptype(span, substs.upvar_tuple_ty(), final_upvar_tuple_type);

// If we are also inferred the closure kind here,
// process any deferred resolutions.
Expand Down

0 comments on commit 3c19b06

Please sign in to comment.