diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 08dcbffc9287b..e946001a3148b 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -779,6 +779,17 @@ impl<'a, 'tcx> RegionFolder<'a, 'tcx> { } } +pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec + where T : TypeFoldable<'tcx> +{ + let mut vec = Vec::new(); + { + let mut folder = RegionFolder::new(tcx, |r, _| { vec.push(r); r }); + value.fold_with(&mut folder); + } + vec +} + impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index cdfd607d06710..5790d3b3f5ec3 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -14,7 +14,7 @@ use middle::subst::{Subst, Substs}; use middle::ty::{mod, Ty}; use middle::typeck::check::{check_expr, check_expr_has_type, demand, FnCtxt}; use middle::typeck::check::{instantiate_path, structurally_resolved_type, valid_range_bounds}; -use middle::typeck::infer::{mod, resolve}; +use middle::typeck::infer; use middle::typeck::require_same_types; use util::nodemap::FnvHashMap; @@ -142,11 +142,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ast::PatRegion(ref inner) => { let inner_ty = fcx.infcx().next_ty_var(); - let mutbl = infer::resolve_type( - fcx.infcx(), Some(pat.span), - expected, resolve::try_resolve_tvar_shallow) - .ok() - .and_then(|t| ty::deref(t, true)) + let mutbl = + ty::deref(fcx.infcx().shallow_resolve(expected), true) .map_or(ast::MutImmutable, |mt| mt.mutbl); let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; @@ -213,23 +210,21 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, inner: &ast::Pat) -> bool { let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; - match infer::resolve_type( - fcx.infcx(), Some(span), - expected, resolve::try_resolve_tvar_shallow) { - Ok(t) if pat_is_binding(&tcx.def_map, inner) => { - ty::deref(t, true).map_or(true, |mt| match mt.ty.sty { - ty::ty_trait(_) => { - // This is "x = SomeTrait" being reduced from - // "let &x = &SomeTrait" or "let box x = Box", an error. - span_err!(tcx.sess, span, E0033, - "type `{}` cannot be dereferenced", - fcx.infcx().ty_to_string(t)); - false - } - _ => true - }) - } - _ => true + if pat_is_binding(&tcx.def_map, inner) { + let expected = fcx.infcx().shallow_resolve(expected); + ty::deref(expected, true).map_or(true, |mt| match mt.ty.sty { + ty::ty_trait(_) => { + // This is "x = SomeTrait" being reduced from + // "let &x = &SomeTrait" or "let box x = Box", an error. + span_err!(tcx.sess, span, E0033, + "type `{}` cannot be dereferenced", + fcx.infcx().ty_to_string(expected)); + false + } + _ => true + }) + } else { + true } } diff --git a/src/librustc/middle/typeck/check/closure.rs b/src/librustc/middle/typeck/check/closure.rs index 0a93b3a5ec7dc..f3b64d958dd42 100644 --- a/src/librustc/middle/typeck/check/closure.rs +++ b/src/librustc/middle/typeck/check/closure.rs @@ -199,7 +199,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( debug!("found object type {}", kind); let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0); - let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(arg_param_ty); + let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty); debug!("arg_param_ty {}", arg_param_ty.repr(tcx)); let input_tys = match arg_param_ty.sty { @@ -209,7 +209,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( debug!("input_tys {}", input_tys.repr(tcx)); let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1); - let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(ret_param_ty); + let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty); debug!("ret_param_ty {}", ret_param_ty.repr(tcx)); let fn_sig = ty::FnSig { diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc/middle/typeck/check/demand.rs index 1e45d059b849b..f9d5ee5ff99e0 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc/middle/typeck/check/demand.rs @@ -12,8 +12,6 @@ use middle::ty::{mod, Ty}; use middle::typeck::check::FnCtxt; use middle::typeck::infer; -use middle::typeck::infer::resolve_type; -use middle::typeck::infer::resolve::try_resolve_tvar_shallow; use std::result::{Err, Ok}; use std::result; @@ -68,12 +66,7 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, debug!("demand::coerce(expected = {}, expr_ty = {})", expected.repr(fcx.ccx.tcx), expr_ty.repr(fcx.ccx.tcx)); - let expected = if ty::type_needs_infer(expected) { - resolve_type(fcx.infcx(), - None, - expected, - try_resolve_tvar_shallow).unwrap_or(expected) - } else { expected }; + let expected = fcx.infcx().resolve_type_vars_if_possible(&expected); match fcx.mk_assignty(expr, expr_ty, expected) { result::Ok(()) => { /* ok */ } result::Err(ref err) => { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 40a38d45fa078..dbe6ab1732511 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1382,13 +1382,7 @@ fn check_cast(fcx: &FnCtxt, let t_1 = fcx.to_ty(t); let t_1 = structurally_resolved_type(fcx, span, t_1); - if ty::type_is_scalar(t_1) { - // Supply the type as a hint so as to influence integer - // literals and other things that might care. - check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1)) - } else { - check_expr(fcx, e) - } + check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1)); let t_e = fcx.expr_ty(e); @@ -1626,7 +1620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn default_diverging_type_variables_to_nil(&self) { for (_, &ref ty) in self.inh.node_types.borrow_mut().iter_mut() { - if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(*ty)) { + if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(ty)) { demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx())); } } @@ -2563,7 +2557,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let method_type = match method { Some(ref method) => method.ty, None => { - let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(expr_type); + let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(&expr_type); if !ty::type_is_error(true_expr_type) { let ty_string = fcx.infcx().ty_to_string(true_expr_type); @@ -4468,11 +4462,11 @@ impl<'tcx> Expectation<'tcx> { } ExpectCastableToType(t) => { ExpectCastableToType( - fcx.infcx().resolve_type_vars_if_possible(t)) + fcx.infcx().resolve_type_vars_if_possible(&t)) } ExpectHasType(t) => { ExpectHasType( - fcx.infcx().resolve_type_vars_if_possible(t)) + fcx.infcx().resolve_type_vars_if_possible(&t)) } } } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index bc6e7d9d87ffe..9e721d500bab0 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -124,8 +124,6 @@ use middle::typeck::astconv::AstConv; use middle::typeck::check::FnCtxt; use middle::typeck::check::regionmanip; use middle::typeck::check::vtable; -use middle::typeck::infer::resolve_and_force_all_but_regions; -use middle::typeck::infer::resolve_type; use middle::typeck::infer; use middle::typeck::MethodCall; use middle::pat_util; @@ -295,11 +293,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { /// of b will be `&.int` and then `*b` will require that `` be bigger than the let and /// the `*b` expression, so we will effectively resolve `` to be the block B. pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self.fcx.infcx(), None, unresolved_ty, - resolve_and_force_all_but_regions) { - Ok(t) => t, - Err(_) => ty::mk_err() - } + self.fcx.infcx().resolve_type_vars_if_possible(&unresolved_ty) } /// Try to resolve the type for the given node. diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 51978a01f7124..c40cf2068017a 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -316,8 +316,7 @@ fn resolve_trait_ref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, obligation: &Obligation<' -> (Rc>, Ty<'tcx>) { let trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( - &*obligation.trait_ref); + fcx.infcx().resolve_type_vars_if_possible(&*obligation.trait_ref); let self_ty = trait_ref.substs.self_ty().unwrap(); (Rc::new(trait_ref), self_ty) @@ -371,8 +370,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => { let expected_trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( - &**expected_trait_ref); + fcx.infcx().resolve_type_vars_if_possible(&**expected_trait_ref); let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); if !ty::type_is_error(self_ty) { fcx.tcx().sess.span_err( diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 23af30b44d935..9735f1514ab30 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -19,8 +19,6 @@ use middle::ty::{mod, Ty}; use middle::ty_fold::{TypeFolder,TypeFoldable}; use middle::typeck::astconv::AstConv; use middle::typeck::check::FnCtxt; -use middle::typeck::infer::{force_all, resolve_all, resolve_region}; -use middle::typeck::infer::resolve_type; use middle::typeck::infer; use middle::typeck::{MethodCall, MethodCallee}; use middle::typeck::write_substs_to_tcx; @@ -339,8 +337,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn resolve>(&self, t: &T, reason: ResolveReason) -> T { - t.resolve_in(&mut Resolver::new(self.fcx, reason)) + fn resolve>(&self, t: &T, reason: ResolveReason) -> T { + t.fold_with(&mut Resolver::new(self.fcx, reason)) } } @@ -375,19 +373,6 @@ impl ResolveReason { } } -/////////////////////////////////////////////////////////////////////////// -// Convenience methods for resolving different kinds of things. - -trait ResolveIn<'tcx> { - fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> Self; -} - -impl<'tcx, T: TypeFoldable<'tcx>> ResolveIn<'tcx> for T { - fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> T { - self.fold_with(resolver) - } -} - /////////////////////////////////////////////////////////////////////////// // The Resolver. This is the type folding engine that detects // unresolved types and so forth. @@ -465,13 +450,11 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_needs_infer(t) { - return t; - } - - match resolve_type(self.infcx, None, t, resolve_all | force_all) { + match self.infcx.fully_resolve(&t) { Ok(t) => t, Err(e) => { + debug!("Resolver::fold_ty: input type `{}` not fully resolvable", + t.repr(self.tcx)); self.report_error(e); ty::mk_err() } @@ -479,7 +462,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match resolve_region(self.infcx, r, resolve_all | force_all) { + match self.infcx.fully_resolve(&r) { Ok(r) => r, Err(e) => { self.report_error(e); diff --git a/src/librustc/middle/typeck/coherence/mod.rs b/src/librustc/middle/typeck/coherence/mod.rs index 758608b79c2cb..5bc2a46f69b37 100644 --- a/src/librustc/middle/typeck/coherence/mod.rs +++ b/src/librustc/middle/typeck/coherence/mod.rs @@ -28,13 +28,12 @@ use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn}; use middle::ty::{ty_closure}; -use middle::ty::type_is_ty_var; use middle::subst::Subst; use middle::ty; use middle::typeck::CrateCtxt; use middle::typeck::infer::combine::Combine; use middle::typeck::infer::InferCtxt; -use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type}; +use middle::typeck::infer::new_infer_ctxt; use std::collections::{HashSet}; use std::cell::RefCell; use std::rc::Rc; @@ -54,80 +53,35 @@ use util::ppaux::Repr; mod orphan; mod overlap; -fn get_base_type<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, - span: Span, - original_type: Ty<'tcx>) - -> Option> { - let resolved_type = match resolve_type(inference_context, - Some(span), - original_type, - resolve_ivar) { - Ok(resulting_type) if !type_is_ty_var(resulting_type) => resulting_type, - _ => { - inference_context.tcx.sess.span_fatal(span, - "the type of this value must be known in order \ - to determine the base type"); - } - }; - - match resolved_type.sty { - ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => { - debug!("(getting base type) found base type"); - Some(resolved_type) +// Returns the def ID of the base type, if there is one. +fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, + span: Span, + ty: Ty<'tcx>) + -> Option { + match ty.sty { + ty_enum(def_id, _) | + ty_struct(def_id, _) => { + Some(def_id) } - _ if ty::type_is_trait(resolved_type) => { - debug!("(getting base type) found base type (trait)"); - Some(resolved_type) + ty_trait(ref t) => { + Some(t.principal.def_id) } ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) | - ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) | + ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => { - debug!("(getting base type) no base type; found {}", - original_type.sty); None } - ty_trait(..) => panic!("should have been caught") - } -} -// Returns the def ID of the base type, if there is one. -fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, - span: Span, - original_type: Ty<'tcx>) - -> Option { - match get_base_type(inference_context, span, original_type) { - None => None, - Some(base_type) => { - match base_type.sty { - ty_enum(def_id, _) | - ty_struct(def_id, _) | - ty_unboxed_closure(def_id, _, _) => { - Some(def_id) - } - ty_ptr(ty::mt {ty, ..}) | - ty_rptr(_, ty::mt {ty, ..}) | - ty_uniq(ty) => { - match ty.sty { - ty_trait(box ty::TyTrait { ref principal, .. }) => { - Some(principal.def_id) - } - _ => { - panic!("get_base_type() returned a type that wasn't an \ - enum, struct, or trait"); - } - } - } - ty_trait(box ty::TyTrait { ref principal, .. }) => { - Some(principal.def_id) - } - _ => { - panic!("get_base_type() returned a type that wasn't an \ - enum, struct, or trait"); - } - } + ty_infer(..) | ty_unboxed_closure(..) => { + // `ty` comes from a user declaration so we should only expect types + // that the user can type + inference_context.tcx.sess.span_bug( + span, + format!("coherence encountered unexpected type searching for base type: {}", + ty.repr(inference_context.tcx))[]); } } } diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 51f8668692ea7..e339c1ca0337d 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -64,10 +64,9 @@ use middle::subst; use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; use middle::ty::{mt}; use middle::ty::{mod, Ty}; -use middle::typeck::infer::{CoerceResult, resolve_type, Coercion}; +use middle::typeck::infer::{CoerceResult, Coercion}; use middle::typeck::infer::combine::{CombineFields, Combine}; use middle::typeck::infer::sub::Sub; -use middle::typeck::infer::resolve::try_resolve_tvar_shallow; use util::ppaux; use util::ppaux::Repr; @@ -194,19 +193,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } pub fn unpack_actual_value(&self, a: Ty<'tcx>, f: |&ty::sty<'tcx>| -> T) - -> T { - match resolve_type(self.get_ref().infcx, None, - a, try_resolve_tvar_shallow) { - Ok(t) => { - f(&t.sty) - } - Err(e) => { - self.get_ref().infcx.tcx.sess.span_bug( - self.get_ref().trace.origin.span(), - format!("failed to resolve even without \ - any force options: {}", e).as_slice()); - } - } + -> T + { + f(&self.get_ref().infcx.shallow_resolve(a).sty) } // ~T -> &T or &mut T -> &T (including where T = [U] or str) @@ -284,7 +273,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_rptr(self.get_ref().infcx.tcx, r_borrow, ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -307,7 +296,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_ptr(self.get_ref().infcx.tcx, ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -325,7 +314,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match self.unsize_ty(t_a, sty_a, t_b) { Some((ty, kind)) => { let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty); - try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoUnsizeUniq({}))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -382,7 +371,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut result = None; let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); for (i, (tp_a, tp_b)) in tps { - if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() { + if self.get_ref().infcx.try(|_| sub.tys(*tp_a, *tp_b)).is_ok() { continue; } match @@ -395,7 +384,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut new_substs = substs_a.clone(); new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; let ty = ty::mk_struct(tcx, did_a, new_substs); - if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() { + if self.get_ref().infcx.try(|_| sub.tys(ty, ty_b)).is_err() { debug!("Unsized type parameter '{}', but still \ could not match types {} and {}", ppaux::ty_to_string(tcx, *tp_a), diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index ba6ae00b6671f..4e6fd578f3506 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -707,14 +707,38 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { fn fold_region(&mut self, r: ty::Region) -> ty::Region { match r { - ty::ReLateBound(..) | ty::ReEarlyBound(..) => r, - _ if self.make_region_vars => { - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - self.infcx.next_region_var(MiscVariable(self.span)) + // Never make variables for regions bound within the type itself. + ty::ReLateBound(..) => { return r; } + + // Early-bound regions should really have been substituted away before + // we get to this point. + ty::ReEarlyBound(..) => { + self.tcx().sess.span_bug( + self.span, + format!("Encountered early bound region when generalizing: {}", + r.repr(self.tcx()))[]); + } + + // Always make a fresh region variable for skolemized regions; + // the higher-ranked decision procedures rely on this. + ty::ReInfer(ty::ReSkolemized(..)) => { } + + // For anything else, we make a region variable, unless we + // are *equating*, in which case it's just wasteful. + ty::ReEmpty | + ty::ReStatic | + ty::ReScope(..) | + ty::ReInfer(ty::ReVar(..)) | + ty::ReFree(..) => { + if !self.make_region_vars { + return r; + } } - _ => r, } + + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + self.infcx.next_region_var(MiscVariable(self.span)) } } diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 0607ccdc595a2..9651a2860d8a2 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -1676,7 +1676,7 @@ pub trait Resolvable<'tcx> { impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> { - infcx.resolve_type_vars_if_possible(*self) + infcx.resolve_type_vars_if_possible(self) } fn contains_error(&self) -> bool { ty::type_is_error(*self) @@ -1686,7 +1686,7 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { impl<'tcx> Resolvable<'tcx> for Rc> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Rc> { - Rc::new(infcx.resolve_type_vars_in_trait_ref_if_possible(&**self)) + Rc::new(infcx.resolve_type_vars_if_possible(&**self)) } fn contains_error(&self) -> bool { ty::trait_ref_contains_error(&**self) diff --git a/src/librustc/middle/typeck/infer/higher_ranked/doc.rs b/src/librustc/middle/typeck/infer/higher_ranked/doc.rs index 2bad3616a05d1..f6f254c0e8dfc 100644 --- a/src/librustc/middle/typeck/infer/higher_ranked/doc.rs +++ b/src/librustc/middle/typeck/infer/higher_ranked/doc.rs @@ -249,19 +249,21 @@ //! in T and try to, in some cases, replace them with bound regions to //! yield the final result. //! -//! To decide whether to replace a region `R` that appears in `T` with a -//! bound region, the algorithms make use of two bits of information. -//! First is a set `V` that contains all region variables created as part -//! of the LUB/GLB computation. `V` will contain the region variables -//! created to replace the bound regions in the input types, but it also -//! contains 'intermediate' variables created to represent the LUB/GLB of -//! individual regions. Basically, when asked to compute the LUB/GLB of a -//! region variable with another region, the inferencer cannot oblige -//! immediately since the values of that variables are not known. -//! Therefore, it creates a new variable that is related to the two -//! regions. For example, the LUB of two variables `$x` and `$y` is a -//! fresh variable `$z` that is constrained such that `$x <= $z` and `$y -//! <= $z`. So `V` will contain these intermediate variables as well. +//! To decide whether to replace a region `R` that appears in `T` with +//! a bound region, the algorithms make use of two bits of +//! information. First is a set `V` that contains all region +//! variables created as part of the LUB/GLB computation (roughly; see +//! `region_vars_confined_to_snapshot()` for full details). `V` will +//! contain the region variables created to replace the bound regions +//! in the input types, but it also contains 'intermediate' variables +//! created to represent the LUB/GLB of individual regions. +//! Basically, when asked to compute the LUB/GLB of a region variable +//! with another region, the inferencer cannot oblige immediately +//! since the values of that variables are not known. Therefore, it +//! creates a new variable that is related to the two regions. For +//! example, the LUB of two variables `$x` and `$y` is a fresh +//! variable `$z` that is constrained such that `$x <= $z` and `$y <= +//! $z`. So `V` will contain these intermediate variables as well. //! //! The other important factor in deciding how to replace a region in T is //! the function `Tainted($r)` which, for a region variable, identifies diff --git a/src/librustc/middle/typeck/infer/higher_ranked/mod.rs b/src/librustc/middle/typeck/infer/higher_ranked/mod.rs index 2f80a574bb18b..fcfb9101b4e87 100644 --- a/src/librustc/middle/typeck/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/typeck/infer/higher_ranked/mod.rs @@ -11,13 +11,14 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. +use super::{combine, CombinedSnapshot, cres, InferCtxt, HigherRankedType}; +use super::combine::Combine; + use middle::ty::{mod, Ty, replace_late_bound_regions}; -use middle::typeck::infer::{mod, combine, cres, InferCtxt}; -use middle::typeck::infer::combine::Combine; -use middle::typeck::infer::region_inference::{RegionMark}; +use middle::ty::RegionVid; use middle::ty_fold::{mod, HigherRankedFoldable, TypeFoldable}; use syntax::codemap::Span; -use util::nodemap::FnvHashMap; +use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux::{bound_region_to_string, Repr}; pub trait HigherRankedCombineable<'tcx>: HigherRankedFoldable<'tcx> + @@ -36,6 +37,14 @@ pub trait HigherRankedRelations<'tcx> { where T : HigherRankedCombineable<'tcx>; } +trait InferCtxtExt<'tcx> { + fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec; + + fn region_vars_confined_to_snapshot(&self, + snapshot: &CombinedSnapshot) + -> Vec; +} + impl<'tcx,C> HigherRankedRelations<'tcx> for C where C : Combine<'tcx> { @@ -53,114 +62,115 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // please see the large comment at the end of the file in the (inlined) module // `doc`. - // Make a mark so we can examine "all bindings that were + // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // First, we instantiate each bound region in the subtype with a fresh - // region variable. - let (a_prime, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), - infer::HigherRankedType, - a); - - // Second, we instantiate each bound region in the supertype with a - // fresh concrete region. - let (b_prime, skol_map) = { - replace_late_bound_regions(self.tcx(), b, |br, _| { - let skol = self.infcx().region_vars.new_skolemized(br); - debug!("Bound region {} skolemized to {}", - bound_region_to_string(self.tcx(), "", false, br), - skol); - skol - }) - }; - - debug!("a_prime={}", a_prime.repr(self.tcx())); - debug!("b_prime={}", b_prime.repr(self.tcx())); - - // Compare types now that bound regions have been replaced. - let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime)); - - // Presuming type comparison succeeds, we need to check - // that the skolemized regions do not "leak". - let new_vars = - self.infcx().region_vars.vars_created_since_mark(mark); - for (&skol_br, &skol) in skol_map.iter() { - let tainted = self.infcx().region_vars.tainted(mark, skol); - for tainted_region in tainted.iter() { - // Each skolemized should only be relatable to itself - // or new variables: - match *tainted_region { - ty::ReInfer(ty::ReVar(ref vid)) => { - if new_vars.iter().any(|x| x == vid) { continue; } - } - _ => { - if *tainted_region == skol { continue; } + return self.infcx().try(|snapshot| { + // First, we instantiate each bound region in the subtype with a fresh + // region variable. + let (a_prime, _) = + self.infcx().replace_late_bound_regions_with_fresh_var( + self.trace().origin.span(), + HigherRankedType, + a); + + // Second, we instantiate each bound region in the supertype with a + // fresh concrete region. + let (b_prime, skol_map) = { + replace_late_bound_regions(self.tcx(), b, |br, _| { + let skol = self.infcx().region_vars.new_skolemized(br); + debug!("Bound region {} skolemized to {}", + bound_region_to_string(self.tcx(), "", false, br), + skol); + skol + }) + }; + + debug!("a_prime={}", a_prime.repr(self.tcx())); + debug!("b_prime={}", b_prime.repr(self.tcx())); + + // Compare types now that bound regions have been replaced. + let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime)); + + // Presuming type comparison succeeds, we need to check + // that the skolemized regions do not "leak". + let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); + for (&skol_br, &skol) in skol_map.iter() { + let tainted = self.infcx().tainted_regions(snapshot, skol); + for tainted_region in tainted.iter() { + // Each skolemized should only be relatable to itself + // or new variables: + match *tainted_region { + ty::ReInfer(ty::ReVar(ref vid)) => { + if new_vars.iter().any(|x| x == vid) { continue; } + } + _ => { + if *tainted_region == skol { continue; } + } + }; + + // A is not as polymorphic as B: + if self.a_is_expected() { + debug!("Not as polymorphic!"); + return Err(ty::terr_regions_insufficiently_polymorphic(skol_br, + *tainted_region)); + } else { + debug!("Overly polymorphic!"); + return Err(ty::terr_regions_overly_polymorphic(skol_br, + *tainted_region)); } - }; - - // A is not as polymorphic as B: - if self.a_is_expected() { - debug!("Not as polymorphic!"); - return Err(ty::terr_regions_insufficiently_polymorphic( - skol_br, *tainted_region)); - } else { - debug!("Overly polymorphic!"); - return Err(ty::terr_regions_overly_polymorphic( - skol_br, *tainted_region)); } } - } - debug!("higher_ranked_sub: OK result={}", - result.repr(self.tcx())); + debug!("higher_ranked_sub: OK result={}", + result.repr(self.tcx())); - return Ok(result); + Ok(result) + }); } fn higher_ranked_lub(&self, a: &T, b: &T) -> cres<'tcx, T> where T : HigherRankedCombineable<'tcx> { - // Make a mark so we can examine "all bindings that were + // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // Instantiate each bound region with a fresh region variable. - let span = self.trace().origin.span(); - let (a_with_fresh, a_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - span, infer::HigherRankedType, a); - let (b_with_fresh, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( - span, infer::HigherRankedType, b); - - // Collect constraints. - let result0 = - try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); - debug!("lub result0 = {}", result0.repr(self.tcx())); - - // Generalize the regions appearing in result0 if possible - let new_vars = self.infcx().region_vars.vars_created_since_mark(mark); - let span = self.trace().origin.span(); - let result1 = - fold_regions_in( - self.tcx(), - &result0, - |r, debruijn| generalize_region(self.infcx(), span, mark, debruijn, - new_vars.as_slice(), &a_map, r)); - - debug!("lub({},{}) = {}", - a.repr(self.tcx()), - b.repr(self.tcx()), - result1.repr(self.tcx())); - - return Ok(result1); + return self.infcx().try(|snapshot| { + // Instantiate each bound region with a fresh region variable. + let span = self.trace().origin.span(); + let (a_with_fresh, a_map) = + self.infcx().replace_late_bound_regions_with_fresh_var( + span, HigherRankedType, a); + let (b_with_fresh, _) = + self.infcx().replace_late_bound_regions_with_fresh_var( + span, HigherRankedType, b); + + // Collect constraints. + let result0 = + try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); + let result0 = + self.infcx().resolve_type_vars_if_possible(&result0); + debug!("lub result0 = {}", result0.repr(self.tcx())); + + // Generalize the regions appearing in result0 if possible + let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); + let span = self.trace().origin.span(); + let result1 = + fold_regions_in( + self.tcx(), + &result0, + |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + new_vars.as_slice(), &a_map, r)); + + debug!("lub({},{}) = {}", + a.repr(self.tcx()), + b.repr(self.tcx()), + result1.repr(self.tcx())); + + Ok(result1) + }); fn generalize_region(infcx: &InferCtxt, span: Span, - mark: RegionMark, + snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], a_map: &FnvHashMap, @@ -173,7 +183,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C return r0; } - let tainted = infcx.region_vars.tainted(mark, r0); + let tainted = infcx.tainted_regions(snapshot, r0); // Variables created during LUB computation which are // *related* to regions that pre-date the LUB computation @@ -214,47 +224,49 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C debug!("{}.higher_ranked_glb({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); - // Make a mark so we can examine "all bindings that were + // Make a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // Instantiate each bound region with a fresh region variable. - let (a_with_fresh, a_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), infer::HigherRankedType, a); - let (b_with_fresh, b_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), infer::HigherRankedType, b); - let a_vars = var_ids(self, &a_map); - let b_vars = var_ids(self, &b_map); - - // Collect constraints. - let result0 = - try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); - debug!("glb result0 = {}", result0.repr(self.tcx())); - - // Generalize the regions appearing in fn_ty0 if possible - let new_vars = self.infcx().region_vars.vars_created_since_mark(mark); - let span = self.trace().origin.span(); - let result1 = - fold_regions_in( - self.tcx(), - &result0, - |r, debruijn| generalize_region(self.infcx(), span, mark, debruijn, - new_vars.as_slice(), - &a_map, a_vars.as_slice(), b_vars.as_slice(), - r)); - - debug!("glb({},{}) = {}", - a.repr(self.tcx()), - b.repr(self.tcx()), - result1.repr(self.tcx())); - - return Ok(result1); + return self.infcx().try(|snapshot| { + // Instantiate each bound region with a fresh region variable. + let (a_with_fresh, a_map) = + self.infcx().replace_late_bound_regions_with_fresh_var( + self.trace().origin.span(), HigherRankedType, a); + let (b_with_fresh, b_map) = + self.infcx().replace_late_bound_regions_with_fresh_var( + self.trace().origin.span(), HigherRankedType, b); + let a_vars = var_ids(self, &a_map); + let b_vars = var_ids(self, &b_map); + + // Collect constraints. + let result0 = + try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); + let result0 = + self.infcx().resolve_type_vars_if_possible(&result0); + debug!("glb result0 = {}", result0.repr(self.tcx())); + + // Generalize the regions appearing in fn_ty0 if possible + let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); + let span = self.trace().origin.span(); + let result1 = + fold_regions_in( + self.tcx(), + &result0, + |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + new_vars.as_slice(), + &a_map, a_vars.as_slice(), b_vars.as_slice(), + r)); + + debug!("glb({},{}) = {}", + a.repr(self.tcx()), + b.repr(self.tcx()), + result1.repr(self.tcx())); + + Ok(result1) + }); fn generalize_region(infcx: &InferCtxt, span: Span, - mark: RegionMark, + snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], a_map: &FnvHashMap, @@ -266,7 +278,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C return r0; } - let tainted = infcx.region_vars.tainted(mark, r0); + let tainted = infcx.tainted_regions(snapshot, r0); let mut a_r = None; let mut b_r = None; @@ -444,3 +456,86 @@ fn fold_regions_in<'tcx, T>(tcx: &ty::ctxt<'tcx>, })) } +impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> { + fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec { + self.region_vars.tainted(&snapshot.region_vars_snapshot, r) + } + + fn region_vars_confined_to_snapshot(&self, + snapshot: &CombinedSnapshot) + -> Vec + { + /*! + * Returns the set of region variables that do not affect any + * types/regions which existed before `snapshot` was + * started. This is used in the sub/lub/glb computations. The + * idea here is that when we are computing lub/glb of two + * regions, we sometimes create intermediate region variables. + * Those region variables may touch some of the skolemized or + * other "forbidden" regions we created to replace bound + * regions, but they don't really represent an "external" + * constraint. + * + * However, sometimes fresh variables are created for other + * purposes too, and those *may* represent an external + * constraint. In particular, when a type variable is + * instantiated, we create region variables for all the + * regions that appear within, and if that type variable + * pre-existed the snapshot, then those region variables + * represent external constraints. + * + * An example appears in the unit test + * `sub_free_bound_false_infer`. In this test, we want to + * know whether + * + * ```rust + * fn(_#0t) <: for<'a> fn(&'a int) + * ``` + * + * Note that the subtype has a type variable. Because the type + * variable can't be instantiated with a region that is bound + * in the fn signature, this comparison ought to fail. But if + * we're not careful, it will succeed. + * + * The reason is that when we walk through the subtyping + * algorith, we begin by replacing `'a` with a skolemized + * variable `'0`. We then have `fn(_#0t) <: fn(&'0 int)`. This + * can be made true by unifying `_#0t` with `&'0 int`. In the + * process, we create a fresh variable for the skolemized + * region, `'$0`, and hence we have that `_#0t == &'$0 + * int`. However, because `'$0` was created during the sub + * computation, if we're not careful we will erroneously + * assume it is one of the transient region variables + * representing a lub/glb internally. Not good. + * + * To prevent this, we check for type variables which were + * unified during the snapshot, and say that any region + * variable created during the snapshot but which finds its + * way into a type variable is considered to "escape" the + * snapshot. + */ + + let mut region_vars = + self.region_vars.vars_created_since_snapshot(&snapshot.region_vars_snapshot); + + let escaping_types = + self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot); + + let escaping_region_vars: FnvHashSet<_> = + escaping_types + .iter() + .flat_map(|&t| ty_fold::collect_regions(self.tcx, &t).into_iter()) + .collect(); + + region_vars.retain(|®ion_vid| { + let r = ty::ReInfer(ty::ReVar(region_vid)); + !escaping_region_vars.contains(&r) + }); + + debug!("region_vars_confined_to_snapshot: region_vars={} escaping_types={}", + region_vars.repr(self.tcx), + escaping_types.repr(self.tcx)); + + region_vars + } +} diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index c5845b143af89..cc194aefd7251 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -19,13 +19,6 @@ pub use self::TypeOrigin::*; pub use self::ValuePairs::*; pub use self::fixup_err::*; pub use middle::ty::IntVarValue; -pub use self::resolve::resolve_and_force_all_but_regions; -pub use self::resolve::{force_all, not_regions}; -pub use self::resolve::{force_ivar}; -pub use self::resolve::{force_tvar, force_rvar}; -pub use self::resolve::{resolve_ivar, resolve_all}; -pub use self::resolve::{resolve_nested_tvar}; -pub use self::resolve::{resolve_rvar}; pub use self::skolemize::TypeSkolemizer; use middle::subst; @@ -47,7 +40,6 @@ use util::ppaux::{trait_ref_to_string, Repr}; use self::coercion::Coerce; use self::combine::{Combine, CombineFields}; use self::region_inference::{RegionVarBindings, RegionSnapshot}; -use self::resolve::{resolver}; use self::equate::Equate; use self::sub::Sub; use self::lub::Lub; @@ -451,22 +443,6 @@ pub fn mk_coercety<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, }) } -// See comment on the type `resolve_state` below -pub fn resolve_type<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - span: Option, - a: Ty<'tcx>, - modes: uint) - -> fres> { - let mut resolver = resolver(cx, modes, span); - cx.commit_unconditionally(|| resolver.resolve_type_chk(a)) -} - -pub fn resolve_region(cx: &InferCtxt, r: ty::Region, modes: uint) - -> fres { - let mut resolver = resolver(cx, modes, None); - resolver.resolve_region_chk(r) -} - trait then<'tcx> { fn then(&self, f: || -> Result>) -> Result>; @@ -512,6 +488,7 @@ pub fn uok<'tcx>() -> ures<'tcx> { Ok(()) } +#[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot { type_snapshot: type_variable::Snapshot, int_snapshot: unify::Snapshot, @@ -617,14 +594,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Execute `f` and commit the bindings if successful pub fn commit_if_ok(&self, f: || -> Result) -> Result { - self.commit_unconditionally(|| self.try(|| f())) + self.commit_unconditionally(|| self.try(|_| f())) } /// Execute `f`, unroll bindings on panic - pub fn try(&self, f: || -> Result) -> Result { + pub fn try(&self, f: |&CombinedSnapshot| -> Result) -> Result { debug!("try()"); let snapshot = self.start_snapshot(); - let r = f(); + let r = f(&snapshot); debug!("try() -- r.is_ok() = {}", r.is_ok()); match r { Ok(_) => { @@ -805,7 +782,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { ty_to_string(self.tcx, - self.resolve_type_vars_if_possible(t)) + self.resolve_type_vars_if_possible(&t)) } pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { @@ -814,24 +791,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn trait_ref_to_string(&self, t: &Rc>) -> String { - let t = self.resolve_type_vars_in_trait_ref_if_possible(&**t); + let t = self.resolve_type_vars_if_possible(&**t); trait_ref_to_string(self.tcx, &t) } - pub fn contains_unbound_type_variables(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self, - None, - typ, resolve_nested_tvar | resolve_ivar) { - Ok(new_type) => new_type, - Err(_) => typ - } - } - pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { match typ.sty { ty::ty_infer(ty::TyVar(v)) => { + // Not entirely obvious: if `typ` is a type variable, + // it can be resolved to an int/float variable, which + // can then be recursively resolved, hence the + // recursion. Note though that we prevent type + // variables from unifying to other type variables + // directly (though they may be embedded + // structurally), and we prevent cycles in any case, + // so this recursion should always be of very limited + // depth. self.type_variables.borrow() .probe(v) + .map(|t| self.shallow_resolve(t)) .unwrap_or(typ) } @@ -851,35 +829,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn resolve_type_vars_if_possible(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self, - None, - typ, resolve_nested_tvar | resolve_ivar) { - Ok(new_type) => new_type, - Err(_) => typ - } + pub fn resolve_type_vars_if_possible>(&self, value: &T) -> T { + /*! + * Where possible, replaces type/int/float variables in + * `value` with their final value. Note that region variables + * are unaffected. If a type variable has not been unified, it + * is left as is. This is an idempotent operation that does + * not affect inference state in any way and so you can do it + * at will. + */ + + let mut r = resolve::OpportunisticTypeResolver::new(self); + value.fold_with(&mut r) } - pub fn resolve_type_vars_in_trait_ref_if_possible(&self, - trait_ref: &ty::TraitRef<'tcx>) - -> ty::TraitRef<'tcx> { - // make up a dummy type just to reuse/abuse the resolve machinery - let dummy0 = ty::mk_trait(self.tcx, - (*trait_ref).clone(), - ty::region_existential_bound(ty::ReStatic)); - let dummy1 = self.resolve_type_vars_if_possible(dummy0); - match dummy1.sty { - ty::ty_trait(box ty::TyTrait { ref principal, .. }) => { - (*principal).clone() - } - _ => { - self.tcx.sess.bug( - format!("resolve_type_vars_if_possible() yielded {} \ - when supplied with {}", - self.ty_to_string(dummy0), - self.ty_to_string(dummy1)).as_slice()); - } - } + pub fn fully_resolve>(&self, value: &T) -> fres { + /*! + * Attempts to resolve all type/region variables in + * `value`. Region inference must have been run already (e.g., + * by calling `resolve_regions_and_report_errors`). If some + * variable was never unified, an `Err` results. + * + * This method is idempotent, but it not typically not invoked + * except during the writeback phase. + */ + + resolve::fully_resolve(self, value) } // [Note-Type-error-reporting] @@ -911,9 +886,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: Option<&ty::type_err<'tcx>>) { debug!("hi! expected_ty = {}, actual_ty = {}", expected_ty, actual_ty); - let resolved_expected = expected_ty.map(|e_ty| { - self.resolve_type_vars_if_possible(e_ty) - }); + let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty)); match resolved_expected { Some(t) if ty::type_is_error(t) => (), @@ -938,7 +911,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { mk_msg: |String| -> String, actual_ty: Ty<'tcx>, err: Option<&ty::type_err<'tcx>>) { - let actual_ty = self.resolve_type_vars_if_possible(actual_ty); + let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); // Don't report an error if actual type is ty_err. if ty::type_is_error(actual_ty) { diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index e39fbe105dcfc..cdc0a9b89675d 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -76,7 +76,6 @@ pub struct TwoRegions { pub enum UndoLogEntry { OpenSnapshot, CommitedSnapshot, - Mark, AddVar(RegionVid), AddConstraint(Constraint), AddVerify(uint), @@ -220,11 +219,6 @@ pub struct RegionSnapshot { length: uint } -#[deriving(Show)] -pub struct RegionMark { - length: uint -} - impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { pub fn new(tcx: &'a ty::ctxt<'tcx>) -> RegionVarBindings<'a, 'tcx> { RegionVarBindings { @@ -253,13 +247,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { RegionSnapshot { length: length } } - pub fn mark(&self) -> RegionMark { - let length = self.undo_log.borrow().len(); - debug!("RegionVarBindings: mark({})", length); - self.undo_log.borrow_mut().push(Mark); - RegionMark { length: length } - } - pub fn commit(&self, snapshot: RegionSnapshot) { debug!("RegionVarBindings: commit({})", snapshot.length); assert!(self.undo_log.borrow().len() > snapshot.length); @@ -283,7 +270,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { OpenSnapshot => { panic!("Failure to observe stack discipline"); } - Mark | CommitedSnapshot => { } + CommitedSnapshot => { } AddVar(vid) => { let mut var_origins = self.var_origins.borrow_mut(); var_origins.pop().unwrap(); @@ -584,8 +571,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { ReInfer(ReVar(c)) } - pub fn vars_created_since_mark(&self, mark: RegionMark) - -> Vec + pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) + -> Vec { self.undo_log.borrow() .slice_from(mark.length) @@ -600,7 +587,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { /// Computes all regions that have been related to `r0` in any way since the mark `mark` was /// made---`r0` itself will be the first entry. This is used when checking whether skolemized /// regions are being improperly related to other regions. - pub fn tainted(&self, mark: RegionMark, r0: Region) -> Vec { + pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec { debug!("tainted(mark={}, r0={})", mark, r0.repr(self.tcx)); let _indenter = indenter(); @@ -655,7 +642,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } } &AddCombination(..) | - &Mark | &AddVar(..) | &OpenSnapshot | &CommitedSnapshot => { diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index cf5efd188ed96..12400de31ed9e 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -8,252 +8,108 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Resolution is the process of removing type variables and replacing -// them with their inferred values. Unfortunately our inference has -// become fairly complex and so there are a number of options to -// control *just how much* you want to resolve and how you want to do -// it. -// -// # Controlling the scope of resolution -// -// The options resolve_* determine what kinds of variables get -// resolved. Generally resolution starts with a top-level type -// variable; we will always resolve this. However, once we have -// resolved that variable, we may end up with a type that still -// contains type variables. For example, if we resolve `` we may -// end up with something like `[]`. If the option -// `resolve_nested_tvar` is passed, we will then go and recursively -// resolve ``. -// -// The options `resolve_rvar` controls whether we resolve region -// variables. The options `resolve_fvar` and `resolve_ivar` control -// whether we resolve floating point and integral variables, -// respectively. -// -// # What do if things are unconstrained -// -// Sometimes we will encounter a variable that has no constraints, and -// therefore cannot sensibly be mapped to any particular result. By -// default, we will leave such variables as is (so you will get back a -// variable in your result). The options force_* will cause the -// resolution to fail in this case instead, except for the case of -// integral variables, which resolve to `int` if forced. -// -// # resolve_all and force_all -// -// The options are a bit set, so you can use the *_all to resolve or -// force all kinds of variables (including those we may add in the -// future). If you want to resolve everything but one type, you are -// probably better off writing `resolve_all - resolve_ivar`. - -#![allow(non_upper_case_globals)] - -use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; -use middle::ty::{IntType, UintType}; +use super::{InferCtxt, fixup_err, fres, unresolved_ty, unresolved_int_ty, unresolved_float_ty}; use middle::ty::{mod, Ty}; -use middle::ty_fold; -use middle::typeck::infer::{fixup_err, fres, InferCtxt}; -use middle::typeck::infer::{unresolved_int_ty,unresolved_float_ty,unresolved_ty}; -use syntax::codemap::Span; -use util::ppaux::{Repr, ty_to_string}; - -pub const resolve_nested_tvar: uint = 0b0000000001; -pub const resolve_rvar: uint = 0b0000000010; -pub const resolve_ivar: uint = 0b0000000100; -pub const resolve_fvar: uint = 0b0000001000; -pub const resolve_all: uint = 0b0000001111; -pub const force_tvar: uint = 0b0000100000; -pub const force_rvar: uint = 0b0001000000; -pub const force_ivar: uint = 0b0010000000; -pub const force_fvar: uint = 0b0100000000; -pub const force_all: uint = 0b0111100000; - -pub const not_regions: uint = !(force_rvar | resolve_rvar); - -pub const try_resolve_tvar_shallow: uint = 0; -pub const resolve_and_force_all_but_regions: uint = - (resolve_all | force_all) & not_regions; - -pub struct ResolveState<'a, 'tcx: 'a> { +use middle::ty_fold::{mod, TypeFoldable}; +use util::ppaux::Repr; + +/////////////////////////////////////////////////////////////////////////// +// OPPORTUNISTIC TYPE RESOLVER + +/// The opportunistic type resolver can be used at any time. It simply replaces +/// type variables that have been unified with the things they have +/// been unified with (similar to `shallow_resolve`, but deep). This is +/// useful for printing messages etc but also required at various +/// points for correctness. +pub struct OpportunisticTypeResolver<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, - modes: uint, - err: Option, - type_depth: uint, } -pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>, - modes: uint, - _: Option) - -> ResolveState<'a, 'tcx> { - ResolveState { - infcx: infcx, - modes: modes, - err: None, - type_depth: 0, +impl<'a, 'tcx> OpportunisticTypeResolver<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> OpportunisticTypeResolver<'a, 'tcx> { + OpportunisticTypeResolver { infcx: infcx } } } -impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for ResolveState<'a, 'tcx> { +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - self.resolve_type(t) - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - self.resolve_region(r) - } -} - -impl<'a, 'tcx> ResolveState<'a, 'tcx> { - pub fn should(&mut self, mode: uint) -> bool { - (self.modes & mode) == mode - } - - pub fn resolve_type_chk(&mut self, typ: Ty<'tcx>) -> fres> { - self.err = None; - - debug!("Resolving {} (modes={:x})", - ty_to_string(self.infcx.tcx, typ), - self.modes); - - // n.b. This is a hokey mess because the current fold doesn't - // allow us to pass back errors in any useful way. - - let rty = self.resolve_type(typ); - match self.err { - None => { - debug!("Resolved {} to {} (modes={:x})", - ty_to_string(self.infcx.tcx, typ), - ty_to_string(self.infcx.tcx, rty), - self.modes); - return Ok(rty); - } - Some(e) => { - return Err(e); - } - } - } - - pub fn resolve_region_chk(&mut self, - orig: ty::Region) - -> fres { - self.err = None; - let resolved = self.resolve_region(orig); - match self.err { - None => Ok(resolved), - Some(e) => Err(e) + if !ty::type_has_ty_infer(t) { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t0 = self.infcx.shallow_resolve(t); + ty_fold::super_fold_ty(self, t0) } } +} - pub fn resolve_type(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { - debug!("resolve_type({})", typ.repr(self.infcx.tcx)); - - if !ty::type_needs_infer(typ) { - return typ; - } - - if self.type_depth > 0 && !self.should(resolve_nested_tvar) { - return typ; - } - - match typ.sty { - ty::ty_infer(TyVar(vid)) => { - self.resolve_ty_var(vid) - } - ty::ty_infer(IntVar(vid)) => { - self.resolve_int_var(vid) - } - ty::ty_infer(FloatVar(vid)) => { - self.resolve_float_var(vid) - } - _ => { - if self.modes & resolve_all == 0 { - // if we are only resolving top-level type - // variables, and this is not a top-level type - // variable, then shortcircuit for efficiency - typ - } else { - self.type_depth += 1; - let result = ty_fold::super_fold_ty(self, typ); - self.type_depth -= 1; - result - } - } - } +/////////////////////////////////////////////////////////////////////////// +// FULL TYPE RESOLUTION + +/// Full type resolution replaces all type and region variables with +/// their concrete results. If any variable cannot be replaced (never unified, etc) +/// then an `Err` result is returned. +pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a,'tcx>, value: &T) -> fres + where T : TypeFoldable<'tcx> +{ + let mut full_resolver = FullTypeResolver { infcx: infcx, err: None }; + let result = value.fold_with(&mut full_resolver); + match full_resolver.err { + None => Ok(result), + Some(e) => Err(e), } +} - pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region { - debug!("Resolve_region({})", orig.repr(self.infcx.tcx)); - match orig { - ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid), - _ => orig - } - } +// N.B. This type is not public because the protocol around checking the +// `err` field is not enforcable otherwise. +struct FullTypeResolver<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + err: Option, +} - pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region { - if !self.should(resolve_rvar) { - return ty::ReInfer(ty::ReVar(rid)); - } - self.infcx.region_vars.resolve_var(rid) +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.infcx.tcx } - pub fn resolve_ty_var(&mut self, vid: TyVid) -> Ty<'tcx> { - let tcx = self.infcx.tcx; - let tv = self.infcx.type_variables.borrow(); - match tv.probe(vid) { - Some(t) => { - self.resolve_type(t) - } - None => { - if self.should(force_tvar) { + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !ty::type_needs_infer(t) { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t = self.infcx.shallow_resolve(t); + match t.sty { + ty::ty_infer(ty::TyVar(vid)) => { self.err = Some(unresolved_ty(vid)); + ty::mk_err() + } + ty::ty_infer(ty::IntVar(vid)) => { + self.err = Some(unresolved_int_ty(vid)); + ty::mk_err() + } + ty::ty_infer(ty::FloatVar(vid)) => { + self.err = Some(unresolved_float_ty(vid)); + ty::mk_err() + } + ty::ty_infer(_) => { + self.infcx.tcx.sess.bug( + format!("Unexpected type in full type resolver: {}", + t.repr(self.infcx.tcx))[]); + } + _ => { + ty_fold::super_fold_ty(self, t) } - ty::mk_var(tcx, vid) - } - } - } - - pub fn resolve_int_var(&mut self, vid: IntVid) -> Ty<'tcx> { - if !self.should(resolve_ivar) { - return ty::mk_int_var(self.infcx.tcx, vid); - } - - let tcx = self.infcx.tcx; - let table = &self.infcx.int_unification_table; - let node = table.borrow_mut().get(tcx, vid); - match node.value { - Some(IntType(t)) => ty::mk_mach_int(t), - Some(UintType(t)) => ty::mk_mach_uint(t), - None => { - if self.should(force_ivar) { - // As a last resort, emit an error. - self.err = Some(unresolved_int_ty(vid)); } - ty::mk_int_var(self.infcx.tcx, vid) - } } } - pub fn resolve_float_var(&mut self, vid: FloatVid) -> Ty<'tcx> { - if !self.should(resolve_fvar) { - return ty::mk_float_var(self.infcx.tcx, vid); - } - - let tcx = self.infcx.tcx; - let table = &self.infcx.float_unification_table; - let node = table.borrow_mut().get(tcx, vid); - match node.value { - Some(t) => ty::mk_mach_float(t), - None => { - if self.should(force_fvar) { - // As a last resort, emit an error. - self.err = Some(unresolved_float_ty(vid)); - } - ty::mk_float_var(self.infcx.tcx, vid) - } + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReInfer(ty::ReVar(rid)) => self.infcx.region_vars.resolve_var(rid), + _ => r, } } } + diff --git a/src/librustc/middle/typeck/infer/type_variable.rs b/src/librustc/middle/typeck/infer/type_variable.rs index 3058f09a83a85..e5bf573cf586b 100644 --- a/src/librustc/middle/typeck/infer/type_variable.rs +++ b/src/librustc/middle/typeck/infer/type_variable.rs @@ -13,7 +13,9 @@ use self::TypeVariableValue::*; use self::UndoEntry::*; use middle::ty::{mod, Ty}; +use std::cmp::min; use std::mem; +use std::uint; use util::snapshot_vec as sv; pub struct TypeVariableTable<'tcx> { @@ -76,7 +78,6 @@ impl<'tcx> TypeVariableTable<'tcx> { /// /// Precondition: neither `a` nor `b` are known. pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) { - if a != b { self.relations(a).push((dir, b)); self.relations(b).push((dir.opposite(), a)); @@ -149,6 +150,49 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn commit(&mut self, s: Snapshot) { self.values.commit(s.snapshot); } + + pub fn types_escaping_snapshot(&self, s: &Snapshot) -> Vec> { + /*! + * Find the set of type variables that existed *before* `s` + * but which have only been unified since `s` started, and + * return the types with which they were unified. So if we had + * a type variable `V0`, then we started the snapshot, then we + * created a type variable `V1`, unifed `V0` with `T0`, and + * unified `V1` with `T1`, this function would return `{T0}`. + */ + + let mut new_elem_threshold = uint::MAX; + let mut escaping_types = Vec::new(); + let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); + for action in actions_since_snapshot.iter() { + match *action { + sv::UndoLog::NewElem(index) => { + // if any new variables were created during the + // snapshot, remember the lower index (which will + // always be the first one we see). Note that this + // action must precede those variables being + // specified. + new_elem_threshold = min(new_elem_threshold, index); + debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); + } + + sv::UndoLog::Other(SpecifyVar(vid, _)) => { + if vid.index < new_elem_threshold { + // quick check to see if this variable was + // created since the snapshot started or not. + let escaping_type = self.probe(vid).unwrap(); + escaping_types.push(escaping_type); + } + debug!("SpecifyVar({}) new_elem_threshold={}", vid, new_elem_threshold); + } + + _ => { } + } + } + + escaping_types + } } impl<'tcx> sv::SnapshotVecDelegate,UndoEntry> for Delegate { diff --git a/src/librustc/util/snapshot_vec.rs b/src/librustc/util/snapshot_vec.rs index 519cd6b167502..e287a5e7c6b3c 100644 --- a/src/librustc/util/snapshot_vec.rs +++ b/src/librustc/util/snapshot_vec.rs @@ -24,7 +24,7 @@ use std::kinds::marker; use std::mem; #[deriving(PartialEq)] -enum UndoLog { +pub enum UndoLog { /// Indicates where a snapshot started. OpenSnapshot, @@ -116,6 +116,12 @@ impl> SnapshotVec { marker: marker::NoCopy } } + pub fn actions_since_snapshot(&self, + snapshot: &Snapshot) + -> &[UndoLog] { + self.undo_log[snapshot.length..] + } + fn assert_open_snapshot(&self, snapshot: &Snapshot) { // Or else there was a failure to follow a stack discipline: assert!(self.undo_log.len() > snapshot.length); diff --git a/src/librustc_trans/test.rs b/src/librustc_trans/test.rs index 41fbe85576933..fdb4d36518fd7 100644 --- a/src/librustc_trans/test.rs +++ b/src/librustc_trans/test.rs @@ -23,6 +23,7 @@ use middle::subst::Subst; use middle::ty::{mod, Ty}; use middle::typeck::infer::combine::Combine; use middle::typeck::infer; +use middle::typeck::infer::sub::Sub; use middle::typeck::infer::lub::Lub; use middle::typeck::infer::glb::Glb; use session::{mod,config}; @@ -339,6 +340,11 @@ impl<'a, 'tcx> Env<'a, 'tcx> { infer::TypeTrace::dummy() } + pub fn sub(&self) -> Sub<'a, 'tcx> { + let trace = self.dummy_type_trace(); + Sub(self.infcx.combine_fields(true, trace)) + } + pub fn lub(&self) -> Lub<'a, 'tcx> { let trace = self.dummy_type_trace(); Lub(self.infcx.combine_fields(true, trace)) @@ -357,6 +363,33 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } } + /// Checks that `t1 <: t2` is true (this may register additional + /// region checks). + pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { + match self.sub().tys(t1, t2) { + Ok(_) => { } + Err(ref e) => { + panic!("unexpected error computing sub({},{}): {}", + t1.repr(self.infcx.tcx), + t2.repr(self.infcx.tcx), + ty::type_err_to_str(self.infcx.tcx, e)); + } + } + } + + /// Checks that `t1 <: t2` is false (this may register additional + /// region checks). + pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { + match self.sub().tys(t1, t2) { + Err(_) => { } + Ok(_) => { + panic!("unexpected success computing sub({},{})", + t1.repr(self.infcx.tcx), + t2.repr(self.infcx.tcx)); + } + } + } + /// Checks that `LUB(t1,t2) == t_lub` pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { match self.lub().tys(t1, t2) { @@ -419,6 +452,74 @@ fn contravariant_region_ptr_err() { }) } +#[test] +fn sub_free_bound_false() { + //! Test that: + //! + //! fn(&'a int) <: for<'b> fn(&'b int) + //! + //! does NOT hold. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_free1 = env.t_rptr_free(0, 1); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + env.check_not_sub(env.t_fn(&[t_rptr_free1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + }) +} + +#[test] +fn sub_bound_free_true() { + //! Test that: + //! + //! for<'a> fn(&'a int) <: fn(&'b int) + //! + //! DOES hold. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_rptr_free1 = env.t_rptr_free(0, 1); + env.check_sub(env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_rptr_free1], ty::mk_int())); + }) +} + +#[test] +fn sub_free_bound_false_infer() { + //! Test that: + //! + //! fn(_#1) <: for<'b> fn(&'b int) + //! + //! does NOT hold for any instantiation of `_#1`. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_infer1 = env.infcx.next_ty_var(); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + env.check_not_sub(env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + }) +} + +#[test] +fn lub_free_bound_infer() { + //! Test result of: + //! + //! LUB(fn(_#1), for<'b> fn(&'b int)) + //! + //! This should yield `fn(&'_ int)`. We check + //! that it yields `fn(&'x int)` for some free `'x`, + //! anyhow. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_infer1 = env.infcx.next_ty_var(); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_rptr_free1 = env.t_rptr_free(0, 1); + env.check_lub(env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_rptr_free1], ty::mk_int())); + }); +} + #[test] fn lub_bound_bound() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { @@ -522,6 +623,28 @@ fn glb_bound_free() { }) } +#[test] +fn glb_bound_free_infer() { + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_infer1 = env.infcx.next_ty_var(); + + // compute GLB(fn(_) -> int, for<'b> fn(&'b int) -> int), + // which should yield for<'b> fn(&'b int) -> int + env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + + // as a side-effect, computing GLB should unify `_` with + // `&'_ int` + let t_resolve1 = env.infcx.shallow_resolve(t_infer1); + match t_resolve1.sty { + ty::ty_rptr(..) => { } + _ => { panic!("t_resolve1={}", t_resolve1.repr(env.infcx.tcx)); } + } + }) +} + #[test] fn glb_bound_static() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { diff --git a/src/test/run-pass/issue-10501.rs b/src/test/run-pass/issue-10501.rs deleted file mode 100644 index 78f125398edcb..0000000000000 --- a/src/test/run-pass/issue-10501.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub type Foo = fn(&int) -> (); -#[deriving(Clone)] -enum Baz { Bar(Foo) } -fn main() {} diff --git a/src/test/run-pass/issue-12741.rs b/src/test/run-pass/issue-12741.rs deleted file mode 100644 index e41613b4ae305..0000000000000 --- a/src/test/run-pass/issue-12741.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[deriving(Clone)] -pub struct Foo { - f: fn(char, |char| -> char) -> char -} - -impl Foo { - fn bar(&self) -> char { - ((*self).f)('a', |c: char| c) - } -} - -fn bla(c: char, cb: |char| -> char) -> char { - cb(c) -} - -pub fn make_foo() -> Foo { - Foo { - f: bla - } -} - -fn main() { - let a = make_foo(); - assert_eq!(a.bar(), 'a'); -} diff --git a/src/test/run-pass/issue-14039.rs b/src/test/run-pass/issue-14039.rs index c017a9dad6446..9f60c2cd49875 100644 --- a/src/test/run-pass/issue-14039.rs +++ b/src/test/run-pass/issue-14039.rs @@ -8,10 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main() { +#![feature(unboxed_closures)] + +fn foo<'a>() { if true { - proc(_) {} + // in this branch, the lifetime is bound + (box move|_| {}) as Box } else { - proc(_: &mut ()) {} + // in this branch, the lifetime is free + (box move|_| {}) as Box }; } + +fn main() { +}