move the signature into the closure type
This commit is contained in:
parent
54f4f396d9
commit
d0bda669ea
9 changed files with 66 additions and 26 deletions
|
@ -125,9 +125,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
// ```
|
// ```
|
||||||
labels.clear();
|
labels.clear();
|
||||||
labels.push((pattern.span, format!("consider giving this closure parameter a type")));
|
labels.push((pattern.span, format!("consider giving this closure parameter a type")));
|
||||||
}
|
} else if let Some(pattern) = local_visitor.found_local_pattern {
|
||||||
|
|
||||||
if let Some(pattern) = local_visitor.found_local_pattern {
|
|
||||||
if let Some(simple_name) = pattern.simple_name() {
|
if let Some(simple_name) = pattern.simple_name() {
|
||||||
labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
|
labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -174,7 +174,7 @@ pub enum TypeVariants<'tcx> {
|
||||||
|
|
||||||
/// A closure can be modeled as a struct that looks like:
|
/// A closure can be modeled as a struct that looks like:
|
||||||
///
|
///
|
||||||
/// struct Closure<'l0...'li, T0...Tj, CK, U0...Uk> {
|
/// struct Closure<'l0...'li, T0...Tj, CK, CS, U0...Uk> {
|
||||||
/// upvar0: U0,
|
/// upvar0: U0,
|
||||||
/// ...
|
/// ...
|
||||||
/// upvark: Uk
|
/// upvark: Uk
|
||||||
|
@ -187,6 +187,10 @@ pub enum TypeVariants<'tcx> {
|
||||||
/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This
|
/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This
|
||||||
/// is rather hackily encoded via a scalar type. See
|
/// is rather hackily encoded via a scalar type. See
|
||||||
/// `TyS::to_opt_closure_kind` for details.
|
/// `TyS::to_opt_closure_kind` for details.
|
||||||
|
/// - CS represents the *closure signature*, representing as a `fn()`
|
||||||
|
/// type. For example, `fn(u32, u32) -> u32` would mean that the closure
|
||||||
|
/// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait
|
||||||
|
/// specified above.
|
||||||
/// - U0...Uk are type parameters representing the types of its upvars
|
/// - U0...Uk are type parameters representing the types of its upvars
|
||||||
/// (borrowed, if appropriate; that is, if Ui represents a by-ref upvar,
|
/// (borrowed, if appropriate; that is, if Ui represents a by-ref upvar,
|
||||||
/// and the up-var has the type `Foo`, then `Ui = &Foo`).
|
/// and the up-var has the type `Foo`, then `Ui = &Foo`).
|
||||||
|
@ -266,6 +270,7 @@ pub struct ClosureSubsts<'tcx> {
|
||||||
/// parent slice and not canonical substs themselves.
|
/// parent slice and not canonical substs themselves.
|
||||||
struct SplitClosureSubsts<'tcx> {
|
struct SplitClosureSubsts<'tcx> {
|
||||||
closure_kind_ty: Ty<'tcx>,
|
closure_kind_ty: Ty<'tcx>,
|
||||||
|
closure_sig_ty: Ty<'tcx>,
|
||||||
upvar_kinds: &'tcx [Kind<'tcx>],
|
upvar_kinds: &'tcx [Kind<'tcx>],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,8 +282,9 @@ impl<'tcx> ClosureSubsts<'tcx> {
|
||||||
let generics = tcx.generics_of(def_id);
|
let generics = tcx.generics_of(def_id);
|
||||||
let parent_len = generics.parent_count();
|
let parent_len = generics.parent_count();
|
||||||
SplitClosureSubsts {
|
SplitClosureSubsts {
|
||||||
closure_kind_ty: self.substs[parent_len].as_type().expect("closure-kind should be type"),
|
closure_kind_ty: self.substs[parent_len].as_type().expect("CK should be a type"),
|
||||||
upvar_kinds: &self.substs[parent_len + 1..],
|
closure_sig_ty: self.substs[parent_len + 1].as_type().expect("CS should be a type"),
|
||||||
|
upvar_kinds: &self.substs[parent_len + 2..],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,6 +301,20 @@ impl<'tcx> ClosureSubsts<'tcx> {
|
||||||
pub fn closure_kind_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
|
pub fn closure_kind_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
|
||||||
self.split(def_id, tcx).closure_kind_ty
|
self.split(def_id, tcx).closure_kind_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the type representing the closure signature for this
|
||||||
|
/// closure; may contain type variables during inference.
|
||||||
|
pub fn closure_sig_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
|
||||||
|
self.split(def_id, tcx).closure_sig_ty
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the signature from the closure.
|
||||||
|
pub fn closure_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> ty::PolyFnSig<'tcx> {
|
||||||
|
match &self.split(def_id, tcx).closure_sig_ty.sty {
|
||||||
|
ty::TyFnPtr(sig) => *sig,
|
||||||
|
t => bug!("closure_sig_ty is not a fn-ptr: {:?}", t),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ClosureSubsts<'tcx> {
|
impl<'tcx> ClosureSubsts<'tcx> {
|
||||||
|
|
|
@ -336,7 +336,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyGenerator(..) | ty::TyClosure(..) => {
|
ty::TyGenerator(..) => {
|
||||||
// the types in a closure or generator are always the types of
|
// the types in a closure or generator are always the types of
|
||||||
// local variables (or possibly references to local
|
// local variables (or possibly references to local
|
||||||
// variables), we'll walk those.
|
// variables), we'll walk those.
|
||||||
|
@ -346,6 +346,21 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
|
||||||
// WFedness.)
|
// WFedness.)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty::TyClosure(def_id, substs) => {
|
||||||
|
// Just check the upvar types for WF. This is
|
||||||
|
// needed because we capture the signature and it
|
||||||
|
// may not be WF without the implied
|
||||||
|
// bounds. Consider a closure like `|x: &'a T|` --
|
||||||
|
// it may be that `T: 'a` is not known to hold in
|
||||||
|
// the creator's context (and indeed the closure
|
||||||
|
// may not be invoked by its creator, but rather
|
||||||
|
// turned to someone who *can* verify that).
|
||||||
|
subtys.skip_current_subtree(); // subtree handled by compute_projection
|
||||||
|
for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) {
|
||||||
|
self.compute(upvar_ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ty::TyFnDef(..) | ty::TyFnPtr(_) => {
|
ty::TyFnDef(..) | ty::TyFnPtr(_) => {
|
||||||
// let the loop iterate into the argument/return
|
// let the loop iterate into the argument/return
|
||||||
// types appearing in the fn signature
|
// types appearing in the fn signature
|
||||||
|
|
|
@ -110,6 +110,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
self.demand_eqtype(expr.span,
|
self.demand_eqtype(expr.span,
|
||||||
ty::ClosureKind::FnOnce.to_ty(self.tcx),
|
ty::ClosureKind::FnOnce.to_ty(self.tcx),
|
||||||
substs.closure_kind_ty(expr_def_id, self.tcx));
|
substs.closure_kind_ty(expr_def_id, self.tcx));
|
||||||
|
self.demand_eqtype(expr.span,
|
||||||
|
self.tcx.types.char, // for generator, use some bogus type
|
||||||
|
substs.closure_sig_ty(expr_def_id, self.tcx));
|
||||||
return self.tcx.mk_generator(expr_def_id, substs, interior);
|
return self.tcx.mk_generator(expr_def_id, substs, interior);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +141,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
opt_kind
|
opt_kind
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let sig_fn_ptr_ty = self.tcx.mk_fn_ptr(sig);
|
||||||
|
self.demand_eqtype(expr.span,
|
||||||
|
sig_fn_ptr_ty,
|
||||||
|
substs.closure_sig_ty(expr_def_id, self.tcx));
|
||||||
|
|
||||||
self.tables.borrow_mut().closure_tys_mut().insert(expr.hir_id, sig);
|
self.tables.borrow_mut().closure_tys_mut().insert(expr.hir_id, sig);
|
||||||
if let Some(kind) = opt_kind {
|
if let Some(kind) = opt_kind {
|
||||||
self.demand_eqtype(expr.span,
|
self.demand_eqtype(expr.span,
|
||||||
|
|
|
@ -1017,7 +1017,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node {
|
if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node {
|
||||||
// add a dummy parameter for the closure kind
|
// add a dummy parameter for the closure kind
|
||||||
types.push(ty::TypeParameterDef {
|
types.push(ty::TypeParameterDef {
|
||||||
index: type_start as u32,
|
index: type_start,
|
||||||
name: Symbol::intern("<closure_kind>"),
|
name: Symbol::intern("<closure_kind>"),
|
||||||
def_id,
|
def_id,
|
||||||
has_default: false,
|
has_default: false,
|
||||||
|
@ -1026,9 +1026,20 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
synthetic: None,
|
synthetic: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// add a dummy parameter for the closure signature
|
||||||
|
types.push(ty::TypeParameterDef {
|
||||||
|
index: type_start + 1,
|
||||||
|
name: Symbol::intern("<closure_signature>"),
|
||||||
|
def_id,
|
||||||
|
has_default: false,
|
||||||
|
object_lifetime_default: rl::Set1::Empty,
|
||||||
|
pure_wrt_drop: false,
|
||||||
|
synthetic: None,
|
||||||
|
});
|
||||||
|
|
||||||
tcx.with_freevars(node_id, |fv| {
|
tcx.with_freevars(node_id, |fv| {
|
||||||
types.extend(fv.iter().zip(1..).map(|(_, i)| ty::TypeParameterDef {
|
types.extend(fv.iter().zip(2..).map(|(_, i)| ty::TypeParameterDef {
|
||||||
index: type_start + i as u32,
|
index: type_start + i,
|
||||||
name: Symbol::intern("<upvar>"),
|
name: Symbol::intern("<upvar>"),
|
||||||
def_id,
|
def_id,
|
||||||
has_default: false,
|
has_default: false,
|
||||||
|
|
|
@ -13,8 +13,7 @@ fn bar<F>(blk: F) where F: FnOnce() + 'static {
|
||||||
|
|
||||||
fn foo(x: &()) {
|
fn foo(x: &()) {
|
||||||
bar(|| {
|
bar(|| {
|
||||||
//~^ ERROR cannot infer
|
//~^ ERROR does not fulfill
|
||||||
//~| ERROR does not fulfill
|
|
||||||
let _ = x;
|
let _ = x;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,5 @@
|
||||||
fn g<F>(_: F) where F: FnOnce(Option<F>) {}
|
fn g<F>(_: F) where F: FnOnce(Option<F>) {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
g(|_| { });
|
g(|_| { }); //~ ERROR mismatched types
|
||||||
}
|
}
|
|
@ -15,5 +15,5 @@ fn fix<F>(f: F) -> i32 where F: Fn(Helper<F>, i32) -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
fix(|_, x| x);
|
fix(|_, x| x); //~ ERROR mismatched types
|
||||||
}
|
}
|
|
@ -6,16 +6,5 @@ error[E0599]: no method named `b` found for type `&Self` in the current scope
|
||||||
|
|
|
|
||||||
= help: did you mean `a`?
|
= help: did you mean `a`?
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error: aborting due to previous error
|
||||||
--> $DIR/issue-3563.rs:13:9
|
|
||||||
|
|
|
||||||
12 | fn a(&self) {
|
|
||||||
| - possibly return type missing here?
|
|
||||||
13 | || self.b()
|
|
||||||
| ^^^^^^^^^^^ expected (), found closure
|
|
||||||
|
|
|
||||||
= note: expected type `()`
|
|
||||||
found type `[closure@$DIR/issue-3563.rs:13:9: 13:20 self:_]`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue