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

Use tuple inference for closures #23

Merged
merged 4 commits into from
Oct 15, 2020
Merged
Show file tree
Hide file tree
Changes from 3 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
18 changes: 14 additions & 4 deletions compiler/rustc_middle/src/ty/outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,25 @@ fn compute_components(
}

ty::Closure(_, ref substs) => {
for upvar_ty in substs.as_closure().upvar_tys() {
compute_components(tcx, upvar_ty, out, visited);
if substs.as_closure().is_valid() {
for upvar_ty in substs.as_closure().upvar_tys() {
compute_components(tcx, upvar_ty, out, visited);
}
} else {
let tupled_ty = substs.as_closure().tupled_upvars_ty();
compute_components(tcx, tupled_ty, out, visited);
}
}

ty::Generator(_, ref substs, _) => {
// Same as the closure case
for upvar_ty in substs.as_generator().upvar_tys() {
compute_components(tcx, upvar_ty, out, visited);
if substs.as_generator().is_valid() {
for upvar_ty in substs.as_generator().upvar_tys() {
compute_components(tcx, upvar_ty, out, visited);
}
} else {
let 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
Expand Down
46 changes: 17 additions & 29 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,18 +663,13 @@ pub trait PrettyPrinter<'tcx>:
}
} else {
p!(print_def_path(did, substs));
if substs.as_generator().is_valid() {
// Search for the first inference variable
p!(" upvar_tys=(");
let mut uninferred_ty =
substs.as_generator().upvar_tys().filter(|ty| ty.is_ty_infer());
if uninferred_ty.next().is_some() {
p!(write("unavailable"));
} else {
self = self.comma_sep(substs.as_generator().upvar_tys())?;
}
p!(")");
p!(" upvar_tys=(");
if !substs.as_generator().is_valid() {
p!("unavailable");
} else {
self = self.comma_sep(substs.as_generator().upvar_tys())?;
}
p!(")");
}

if substs.as_generator().is_valid() {
Expand Down Expand Up @@ -704,24 +699,17 @@ pub trait PrettyPrinter<'tcx>:
}
} else {
p!(print_def_path(did, substs));
if substs.as_closure().is_valid() {
// Search for the first inference variable
let mut uninferred_ty =
substs.as_closure().upvar_tys().filter(|ty| ty.is_ty_infer());
if uninferred_ty.next().is_some() {
// If the upvar substs contain an inference variable we haven't
// finished capture analysis.
p!(" closure_substs=(unavailable)");
} else {
p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
p!(
" closure_sig_as_fn_ptr_ty=",
print(substs.as_closure().sig_as_fn_ptr_ty())
);
p!(" upvar_tys=(");
self = self.comma_sep(substs.as_closure().upvar_tys())?;
p!(")");
}
if !substs.as_closure().is_valid() {
p!(" closure_substs=(unavailable)");
} else {
p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
p!(
" closure_sig_as_fn_ptr_ty=",
print(substs.as_closure().sig_as_fn_ptr_ty())
);
p!(" upvar_tys=(");
self = self.comma_sep(substs.as_closure().upvar_tys())?;
p!(")");
}
}
p!("]");
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,14 @@ impl<'tcx> UpvarSubsts<'tcx> {
};
tupled_upvars_ty.expect_ty().tuple_fields()
}

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

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
Expand Down
40 changes: 28 additions & 12 deletions compiler/rustc_trait_selection/src/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {

for required_region in required_region_bounds {
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
infcx: self,
op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
});
}
Expand Down Expand Up @@ -509,6 +510,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
}
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
infcx: self,
op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
});
}
Expand Down Expand Up @@ -543,6 +545,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
);

concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
infcx: self,
op: |r| {
self.member_constraint(
opaque_type_def_id,
Expand Down Expand Up @@ -683,11 +686,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
//
// We ignore any type parameters because impl trait values are assumed to
// capture all the in-scope type parameters.
struct ConstrainOpaqueTypeRegionVisitor<OP> {
struct ConstrainOpaqueTypeRegionVisitor<'cx, 'tcx, OP> {
infcx: &'cx InferCtxt<'cx, 'tcx>,
op: OP,
}

impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
impl<'cx, 'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'cx, 'tcx, OP>
where
OP: FnMut(ty::Region<'tcx>),
{
Expand Down Expand Up @@ -717,24 +721,36 @@ 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);
}
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
if let ty::Infer(ty::TyVar(_)) = ty.kind() {
// 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);
}
let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
if let ty::Infer(ty::TyVar(_)) = ty.kind() {
// 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
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let mut generator = None;
let mut outer_generator = None;
let mut next_code = Some(&obligation.cause.code);

let mut seen_upvar_tys_infer_tuple = false;

while let Some(code) = next_code {
debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
match code {
Expand All @@ -1327,6 +1330,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
outer_generator = Some(did);
}
ty::GeneratorWitness(..) => {}
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
// By introducing a tuple of upvar types into the chain of obligations
// of a generator, the first non-generator item is now the tuple itself,
// we shall ignore this.

seen_upvar_tys_infer_tuple = true;
}
_ if generator.is_none() => {
trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder());
target_ty = Some(ty);
Expand Down Expand Up @@ -1912,7 +1922,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
return;
}

err.note(&format!("required because it appears within the type `{}`", ty));
// If the obligation for a tuple is set directly by a Generator or Closure,
// then the tuple must be the one containing capture types.
let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) {
false
} else {
if let ObligationCauseCode::BuiltinDerivedObligation(ref data) =
*data.parent_code
{
let parent_trait_ref =
self.resolve_vars_if_possible(&data.parent_trait_ref);
let ty = parent_trait_ref.skip_binder().self_ty();
matches!(ty.kind(), ty::Generator(..))
|| matches!(ty.kind(), ty::Closure(..))
} else {
false
}
};

// Don't print the tuple of capture types
if !is_upvar_tys_infer_tuple {
err.note(&format!("required because it appears within the type `{}`", ty));
}

obligated_types.push(ty);

let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ 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))
trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty())
}

ty::Adt(def, _) => {
Expand Down
16 changes: 13 additions & 3 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1631,7 +1631,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().tupled_upvars_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 @@ -1700,11 +1706,15 @@ 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().tupled_upvars_ty());
vec![ty]
}

ty::Generator(_, ref substs, _) => {
let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
let witness = substs.as_generator().witness();
substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
vec![ty].into_iter().chain(iter::once(witness)).collect()
}

ty::GeneratorWitness(types) => {
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,10 +592,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
// 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());
}
// FIXME(eddyb) add the type to `walker` instead of recursing.
self.compute(substs.as_closure().tupled_upvars_ty().into());
}

ty::FnPtr(_) => {
Expand Down
24 changes: 19 additions & 5 deletions compiler/rustc_traits/src/dropck_outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,20 @@ fn dtorck_constraint_for_ty<'tcx>(
Ok::<_, NoSolution>(())
})?,

ty::Closure(_, substs) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
for ty in substs.as_closure().upvar_tys() {
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
ty::Closure(_, substs) => {
if !substs.as_closure().is_valid() {
// By the time this code runs, all type variables ought to
// be fully resolved.
return Err(NoSolution);
}
Ok::<_, NoSolution>(())
})?,

rustc_data_structures::stack::ensure_sufficient_stack(|| {
for ty in substs.as_closure().upvar_tys() {
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
}
Ok::<_, NoSolution>(())
})?
}

ty::Generator(_, substs, _movability) => {
// rust-lang/rust#49918: types can be constructed, stored
Expand All @@ -241,6 +249,12 @@ fn dtorck_constraint_for_ty<'tcx>(
// derived from lifetimes attached to the upvars and resume
// argument, and we *do* incorporate those here.

if !substs.as_generator().is_valid() {
// By the time this code runs, all type variables ought to
// be fully resolved.
return Err(NoSolution);
}

constraints.outlives.extend(
substs
.as_generator()
Expand Down
17 changes: 4 additions & 13 deletions compiler/rustc_typeck/src/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,10 @@ 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 {
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
Loading