提交 d92e594c 编写于 作者: E Eduard Burtescu

typeck: record `impl Trait` concrete resolutions.

上级 1ef7ddfd
......@@ -194,6 +194,14 @@ fn visit_stmt(&mut self, stmt: &'ast Stmt) {
});
}
fn visit_ty(&mut self, ty: &'ast Ty) {
self.insert(ty.id, NodeTy(ty));
self.with_parent(ty.id, |this| {
intravisit::walk_ty(this, ty);
});
}
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
b: &'ast Block, s: Span, id: NodeId) {
assert_eq!(self.parent_node, id);
......
......@@ -50,6 +50,7 @@ pub enum Node<'ast> {
NodeVariant(&'ast Variant),
NodeExpr(&'ast Expr),
NodeStmt(&'ast Stmt),
NodeTy(&'ast Ty),
NodeLocal(&'ast Pat),
NodePat(&'ast Pat),
NodeBlock(&'ast Block),
......@@ -76,6 +77,7 @@ pub enum MapEntry<'ast> {
EntryVariant(NodeId, &'ast Variant),
EntryExpr(NodeId, &'ast Expr),
EntryStmt(NodeId, &'ast Stmt),
EntryTy(NodeId, &'ast Ty),
EntryLocal(NodeId, &'ast Pat),
EntryPat(NodeId, &'ast Pat),
EntryBlock(NodeId, &'ast Block),
......@@ -104,6 +106,7 @@ fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
NodeVariant(n) => EntryVariant(p, n),
NodeExpr(n) => EntryExpr(p, n),
NodeStmt(n) => EntryStmt(p, n),
NodeTy(n) => EntryTy(p, n),
NodeLocal(n) => EntryLocal(p, n),
NodePat(n) => EntryPat(p, n),
NodeBlock(n) => EntryBlock(p, n),
......@@ -122,6 +125,7 @@ fn parent_node(self) -> Option<NodeId> {
EntryVariant(id, _) => id,
EntryExpr(id, _) => id,
EntryStmt(id, _) => id,
EntryTy(id, _) => id,
EntryLocal(id, _) => id,
EntryPat(id, _) => id,
EntryBlock(id, _) => id,
......@@ -144,6 +148,7 @@ fn to_node(self) -> Option<Node<'ast>> {
EntryVariant(_, n) => NodeVariant(n),
EntryExpr(_, n) => NodeExpr(n),
EntryStmt(_, n) => NodeStmt(n),
EntryTy(_, n) => NodeTy(n),
EntryLocal(_, n) => NodeLocal(n),
EntryPat(_, n) => NodePat(n),
EntryBlock(_, n) => NodeBlock(n),
......@@ -257,6 +262,7 @@ fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
EntryVariant(p, _) |
EntryExpr(p, _) |
EntryStmt(p, _) |
EntryTy(p, _) |
EntryLocal(p, _) |
EntryPat(p, _) |
EntryBlock(p, _) |
......@@ -297,6 +303,7 @@ fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
EntryVariant(p, _) |
EntryExpr(p, _) |
EntryStmt(p, _) |
EntryTy(p, _) |
EntryLocal(p, _) |
EntryPat(p, _) |
EntryBlock(p, _) |
......@@ -680,6 +687,7 @@ pub fn opt_span(&self, id: NodeId) -> Option<Span> {
Some(NodeVariant(variant)) => variant.span,
Some(NodeExpr(expr)) => expr.span,
Some(NodeStmt(stmt)) => stmt.span,
Some(NodeTy(ty)) => ty.span,
Some(NodeLocal(pat)) => pat.span,
Some(NodePat(pat)) => pat.span,
Some(NodeBlock(block)) => block.span,
......@@ -971,6 +979,7 @@ fn print_node(&mut self, node: &Node) -> io::Result<()> {
NodeVariant(a) => self.print_variant(&a),
NodeExpr(a) => self.print_expr(&a),
NodeStmt(a) => self.print_stmt(&a),
NodeTy(a) => self.print_type(&a),
NodePat(a) => self.print_pat(&a),
NodeBlock(a) => self.print_block(&a),
NodeLifetime(a) => self.print_lifetime(&a),
......@@ -1059,6 +1068,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
Some(NodeStmt(ref stmt)) => {
format!("stmt {}{}", pprust::stmt_to_string(&stmt), id_str)
}
Some(NodeTy(ref ty)) => {
format!("type {}{}", pprust::ty_to_string(&ty), id_str)
}
Some(NodeLocal(ref pat)) => {
format!("local {}{}", pprust::pat_to_string(&pat), id_str)
}
......
......@@ -1390,6 +1390,20 @@ fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) {
intravisit::walk_foreign_item(self, ni);
encode_info_for_foreign_item(self.ecx, self.rbml_w_for_visit_item, ni, self.index);
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
intravisit::walk_ty(self, ty);
if let hir::TyImplTrait(_) = ty.node {
let rbml_w = &mut *self.rbml_w_for_visit_item;
let def_id = self.ecx.tcx.map.local_def_id(ty.id);
let _task = self.index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(self.ecx, rbml_w, def_id);
encode_family(rbml_w, 'y');
encode_bounds_and_type_for_item(rbml_w, self.ecx, self.index, ty.id);
rbml_w.end_tag();
}
}
}
fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
......
......@@ -1763,25 +1763,28 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
// Create the anonymized type.
let def_id = tcx.map.local_def_id(ast_ty.id);
let substs = if let Some(anon_scope) = rscope.anon_type_scope() {
anon_scope.fresh_substs(tcx)
if let Some(anon_scope) = rscope.anon_type_scope() {
let substs = anon_scope.fresh_substs(tcx);
let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs);
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
let bounds = compute_bounds(self, ty, bounds,
SizedByDefault::Yes,
Some(anon_scope),
ast_ty.span);
let predicates = bounds.predicates(tcx, ty);
let predicates = tcx.lift_to_global(&predicates).unwrap();
tcx.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
predicates: VecPerParamSpace::new(vec![], vec![], predicates)
});
ty
} else {
span_err!(tcx.sess, ast_ty.span, E0562,
"`impl Trait` not allowed outside of function \
and inherent method return types");
tcx.mk_substs(Substs::empty())
};
let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs);
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
let bounds = compute_bounds(self, ty, bounds, SizedByDefault::Yes, ast_ty.span);
let predicates = tcx.lift_to_global(&bounds.predicates(tcx, ty)).unwrap();
let predicates = ty::GenericPredicates {
predicates: VecPerParamSpace::new(vec![], vec![], predicates)
};
tcx.predicates.borrow_mut().insert(def_id, predicates);
ty
tcx.types.err
}
}
hir::TyPath(ref maybe_qself, ref path) => {
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
......
......@@ -96,7 +96,7 @@
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
use rustc::ty::{MethodCall, MethodCallee};
use rustc::ty::adjustment;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
use rustc::ty::util::{Representability, IntTypeExt};
use require_c_abi_if_variadic;
use rscope::{ElisionFailureInfo, RegionScope};
......@@ -172,6 +172,12 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'gcx, 'tcx>>>>,
deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
// Anonymized types found in explicit return types and their
// associated fresh inference variable. Writeback resolves these
// variables to get the concrete type, which can be used to
// deanonymize TyAnon, after typeck is done with all functions.
anon_types: RefCell<DefIdMap<Ty<'tcx>>>,
}
impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
......@@ -408,6 +414,7 @@ fn enter<F, R>(&'tcx mut self, f: F) -> R
locals: RefCell::new(NodeMap()),
deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()),
anon_types: RefCell::new(DefIdMap()),
})
})
}
......@@ -631,32 +638,29 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
body: &'gcx hir::Block)
-> FnCtxt<'a, 'gcx, 'tcx>
{
let arg_tys = &fn_sig.inputs;
let ret_ty = fn_sig.output;
let mut fn_sig = fn_sig.clone();
debug!("check_fn(arg_tys={:?}, ret_ty={:?}, fn_id={})",
arg_tys,
ret_ty,
fn_id);
debug!("check_fn(sig={:?}, fn_id={})", fn_sig, fn_id);
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
let fcx = FnCtxt::new(inherited, ret_ty, body.id);
let mut fcx = FnCtxt::new(inherited, fn_sig.output, body.id);
*fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
if let ty::FnConverging(ret_ty) = ret_ty {
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
}
debug!("fn-sig-map: fn_id={} fn_sig={:?}", fn_id, fn_sig);
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig.clone());
fn_sig.output = match fcx.ret_ty {
ty::FnConverging(orig_ret_ty) => {
fcx.require_type_is_sized(orig_ret_ty, decl.output.span(), traits::ReturnType);
ty::FnConverging(fcx.instantiate_anon_types(&orig_ret_ty))
}
ty::FnDiverging => ty::FnDiverging
};
fcx.ret_ty = fn_sig.output;
{
let mut visit = GatherLocalsVisitor { fcx: &fcx, };
// Add formal parameters.
for (arg_ty, input) in arg_tys.iter().zip(&decl.inputs) {
for (arg_ty, input) in fn_sig.inputs.iter().zip(&decl.inputs) {
// The type of the argument must be well-formed.
//
// NB -- this is now checked in wfcheck, but that
......@@ -672,21 +676,20 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
});
// Check the pattern.
fcx.check_pat(&input.pat, *arg_ty);
fcx.check_pat(&input.pat, arg_ty);
fcx.write_ty(input.id, arg_ty);
}
visit.visit_block(body);
}
fcx.check_block_with_expected(body, match ret_ty {
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
fcx.check_block_with_expected(body, match fcx.ret_ty {
ty::FnConverging(result_type) => ExpectHasType(result_type),
ty::FnDiverging => NoExpectation
});
for (input, arg) in decl.inputs.iter().zip(arg_tys) {
fcx.write_ty(input.id, arg);
}
fcx
}
......@@ -1623,6 +1626,41 @@ fn instantiate_bounds(&self,
}
}
/// Replace all anonymized types with fresh inference variables
/// and record them for writeback.
fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
value.fold_with(&mut BottomUpFolder { tcx: self.tcx, fldop: |ty| {
if let ty::TyAnon(def_id, substs) = ty.sty {
// Use the same type variable if the exact same TyAnon appears more
// than once in the return type (e.g. if it's pased to a type alias).
if let Some(ty_var) = self.anon_types.borrow().get(&def_id) {
return ty_var;
}
let ty_var = self.next_ty_var();
self.anon_types.borrow_mut().insert(def_id, ty_var);
let item_predicates = self.tcx.lookup_predicates(def_id);
let bounds = item_predicates.instantiate(self.tcx, substs);
let span = self.tcx.map.def_id_span(def_id, codemap::DUMMY_SP);
for predicate in bounds.predicates {
// Change the predicate to refer to the type variable,
// which will be the concrete type, instead of the TyAnon.
// This also instantiates nested `impl Trait`.
let predicate = self.instantiate_anon_types(&predicate);
// Require that the predicate holds for the concrete type.
let cause = traits::ObligationCause::new(span, self.body_id,
traits::ReturnType);
self.register_predicate(traits::Obligation::new(cause, predicate));
}
ty_var
} else {
ty
}
}})
}
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
where T : TypeFoldable<'tcx>
......
......@@ -18,7 +18,9 @@
use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
use rustc::ty::adjustment;
use rustc::ty::fold::{TypeFolder,TypeFoldable};
use rustc::ty::subst::ParamSpace;
use rustc::infer::{InferCtxt, FixupError};
use rustc::util::nodemap::DefIdMap;
use write_substs_to_tcx;
use write_ty_to_tcx;
......@@ -62,6 +64,7 @@ pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, blk: &hir::Block) {
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types();
wbcx.visit_anon_types();
}
}
......@@ -75,11 +78,48 @@ pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, blk: &hir::Block) {
struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>,
// Mapping from free regions of the function to the
// early-bound versions of them, visible from the
// outside of the function. This is needed by, and
// only populated if there are any `impl Trait`.
free_to_bound_regions: DefIdMap<ty::Region>
}
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>) -> WritebackCx<'cx, 'gcx, 'tcx> {
WritebackCx { fcx: fcx }
let mut wbcx = WritebackCx {
fcx: fcx,
free_to_bound_regions: DefIdMap()
};
// Only build the reverse mapping if `impl Trait` is used.
if fcx.anon_types.borrow().is_empty() {
return wbcx;
}
let free_substs = fcx.parameter_environment.free_substs;
for &space in &ParamSpace::all() {
for (i, r) in free_substs.regions.get_slice(space).iter().enumerate() {
match *r {
ty::ReFree(ty::FreeRegion {
bound_region: ty::BoundRegion::BrNamed(def_id, name, _), ..
}) => {
let bound_region = ty::ReEarlyBound(ty::EarlyBoundRegion {
space: space,
index: i as u32,
name: name,
});
wbcx.free_to_bound_regions.insert(def_id, bound_region);
}
_ => {
bug!("{:?} is not a free region for an early-bound lifetime", r);
}
}
}
}
wbcx
}
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
......@@ -255,6 +295,58 @@ fn visit_closures(&self) {
}
}
fn visit_anon_types(&self) {
if self.fcx.writeback_errors.get() {
return
}
let gcx = self.tcx().global_tcx();
for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
let reason = ResolvingAnonTy(def_id);
let inside_ty = self.resolve(&concrete_ty, reason);
// Convert the type from the function into a type valid outside
// the function, by replacing free regions with early-bound ones.
let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
match r {
// 'static is valid everywhere.
ty::ReStatic => ty::ReStatic,
// Free regions that come from early-bound regions are valid.
ty::ReFree(ty::FreeRegion {
bound_region: ty::BoundRegion::BrNamed(def_id, _, _), ..
}) if self.free_to_bound_regions.contains_key(&def_id) => {
self.free_to_bound_regions[&def_id]
}
ty::ReFree(_) |
ty::ReEarlyBound(_) |
ty::ReLateBound(..) |
ty::ReScope(_) |
ty::ReSkolemized(..) => {
let span = reason.span(self.tcx());
span_err!(self.tcx().sess, span, E0564,
"only named lifetimes are allowed in `impl Trait`, \
but `{}` was found in the type `{}`", r, inside_ty);
ty::ReStatic
}
ty::ReVar(_) |
ty::ReEmpty |
ty::ReErased => {
let span = reason.span(self.tcx());
span_bug!(span, "invalid region in impl Trait: {:?}", r);
}
}
});
gcx.tcache.borrow_mut().insert(def_id, ty::TypeScheme {
ty: outside_ty,
generics: ty::Generics::empty()
});
}
}
fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
// Resolve any borrowings for the node with id `id`
self.visit_adjustments(reason, id);
......@@ -377,7 +469,8 @@ enum ResolveReason {
ResolvingUpvar(ty::UpvarId),
ResolvingClosure(DefId),
ResolvingFnSig(ast::NodeId),
ResolvingFieldTypes(ast::NodeId)
ResolvingFieldTypes(ast::NodeId),
ResolvingAnonTy(DefId),
}
impl<'a, 'gcx, 'tcx> ResolveReason {
......@@ -395,12 +488,9 @@ fn span(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Span {
ResolvingFieldTypes(id) => {
tcx.map.span(id)
}
ResolvingClosure(did) => {
if let Some(node_id) = tcx.map.as_local_node_id(did) {
tcx.expr_span(node_id)
} else {
DUMMY_SP
}
ResolvingClosure(did) |
ResolvingAnonTy(did) => {
tcx.map.def_id_span(did, DUMMY_SP)
}
}
}
......@@ -483,6 +573,12 @@ fn report_error(&self, e: FixupError) {
span,
&format!("cannot resolve some aspect of data for {:?}", id));
}
ResolvingAnonTy(_) => {
let span = self.reason.span(self.tcx);
span_err!(self.tcx.sess, span, E0563,
"cannot determine a type for this `impl Trait`: {}", e)
}
}
}
}
......
......@@ -1194,10 +1194,11 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt,
// Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
let self_param_ty = tcx.mk_self_type();
let superbounds1 = compute_bounds(&ccx.icx(scope),
self_param_ty,
bounds,
SizedByDefault::No,
item.span);
self_param_ty,
bounds,
SizedByDefault::No,
None,
item.span);
let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
......@@ -1407,6 +1408,7 @@ fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
assoc_ty,
bounds,
SizedByDefault::Yes,
None,
trait_item.span);
bounds.predicates(ccx.tcx, assoc_ty).into_iter()
......@@ -1780,6 +1782,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
param_ty,
&param.bounds,
SizedByDefault::Yes,
None,
param.span);
let predicates = bounds.predicates(ccx.tcx, param_ty);
result.predicates.extend(space, predicates.into_iter());
......@@ -2052,25 +2055,43 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
param_ty: ty::Ty<'tcx>,
ast_bounds: &[hir::TyParamBound],
sized_by_default: SizedByDefault,
anon_scope: Option<AnonTypeScope>,
span: Span)
-> Bounds<'tcx>
{
let mut bounds =
conv_param_bounds(astconv,
span,
param_ty,
ast_bounds);
let tcx = astconv.tcx();
let PartitionedBounds {
mut builtin_bounds,
trait_bounds,
region_bounds
} = partition_bounds(tcx, span, &ast_bounds);
if let SizedByDefault::Yes = sized_by_default {
add_unsized_bound(astconv,
&mut bounds.builtin_bounds,
ast_bounds,
span);
add_unsized_bound(astconv, &mut builtin_bounds, ast_bounds, span);
}
bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
let mut projection_bounds = vec![];
let rscope = MaybeWithAnonTypes::new(ExplicitRscope, anon_scope);
let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| {
astconv.instantiate_poly_trait_ref(&rscope,
bound,
Some(param_ty),
&mut projection_bounds)
}).collect();
let region_bounds = region_bounds.into_iter().map(|r| {
ast_region_to_region(tcx, r)
}).collect();
trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
bounds
Bounds {
region_bounds: region_bounds,
builtin_bounds: builtin_bounds,
trait_bounds: trait_bounds,
projection_bounds: projection_bounds,
}
}
/// Converts a specific TyParamBound from the AST into a set of
......@@ -2116,42 +2137,6 @@ fn conv_poly_trait_ref<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
projections)
}
fn conv_param_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
span: Span,
param_ty: ty::Ty<'tcx>,
ast_bounds: &[hir::TyParamBound])
-> Bounds<'tcx>
{
let tcx = astconv.tcx();
let PartitionedBounds {
builtin_bounds,
trait_bounds,
region_bounds
} = partition_bounds(tcx, span, &ast_bounds);
let mut projection_bounds = Vec::new();
let trait_bounds: Vec<ty::PolyTraitRef> =
trait_bounds.iter()
.map(|bound| conv_poly_trait_ref(astconv,
param_ty,
*bound,
&mut projection_bounds))
.collect();
let region_bounds: Vec<ty::Region> =
region_bounds.into_iter()
.map(|r| ast_region_to_region(tcx, r))
.collect();
Bounds {
region_bounds: region_bounds,
builtin_bounds: builtin_bounds,
trait_bounds: trait_bounds,
projection_bounds: projection_bounds,
}
}
fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
ccx: &CrateCtxt<'a, 'tcx>,
id: DefId,
......
......@@ -4086,4 +4086,7 @@ struct Simba {
E0533, // `{}` does not name a unit variant, unit struct or a constant
E0562, // `impl Trait` not allowed outside of function
// and inherent method return types
E0563, // cannot determine a type for this `impl Trait`: {}
E0564, // only named lifetimes are allowed in `impl Trait`,
// but `{}` was found in the type `{}`
}
此差异已折叠。
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(conservative_impl_trait, question_mark)]
struct State;
type Error = ();
trait Bind<F> {
type Output;
fn bind(self, f: F) -> Self::Output;
}
fn bind<T, U, A, B, F>(mut a: A, mut f: F)
-> impl FnMut(&mut State) -> Result<U, Error>
where F: FnMut(T) -> B,
A: FnMut(&mut State) -> Result<T, Error>,
B: FnMut(&mut State) -> Result<U, Error>
{
move |state | {
let r = a(state)?;
f(r)(state)
}
}
fn atom<T>(x: T) -> impl FnMut(&mut State) -> Result<T, Error> {
let mut x = Some(x);
move |_| x.take().map_or(Err(()), Ok)
}
fn main() {
assert_eq!(bind(atom(5), |x| atom(x > 4))(&mut State), Ok(true));
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册