diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index 43d99ecb427..edb544aca6d 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -60,10 +60,9 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use super::{CoerceResult, resolve_type, Coercion}; +use super::{CoerceResult, Coercion}; use super::combine::{CombineFields, Combine}; use super::sub::Sub; -use super::resolve::try_resolve_tvar_shallow; use middle::subst; use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; @@ -197,18 +196,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { pub fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where F: FnOnce(&ty::sty<'tcx>) -> 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()); - } - } + f(&self.get_ref().infcx.shallow_resolve(a).sty) } // ~T -> &T or &mut T -> &T (including where T = [U] or str) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 4ad7af713bd..0c70d208119 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/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; @@ -453,22 +445,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<Span>, - a: Ty<'tcx>, - modes: uint) - -> fres<Ty<'tcx>> { - 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<ty::Region> { - let mut resolver = resolver(cx, modes, None); - resolver.resolve_region_chk(r) -} - trait then<'tcx> { fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where T: Clone, @@ -835,20 +811,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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) } @@ -869,10 +846,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn resolve_type_vars_if_possible<T:TypeFoldable<'tcx>>(&self, value: &T) -> T { - let mut r = resolve::DeepTypeResolver::new(self); + /*! + * 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 fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> fres<T> { + /*! + * 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] // An invariant is that anytime the expected or actual type is ty_err (the special // error type, meaning that an error occurred when typechecking this expression), diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index 5edf78a474b..12400de31ed 100644 --- a/src/librustc/middle/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -8,276 +8,30 @@ // 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 `<T0>` we may -// end up with something like `[<T1>]`. If the option -// `resolve_nested_tvar` is passed, we will then go and recursively -// resolve `<T1>`. -// -// 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 super::{fixup_err, fres, InferCtxt}; -use super::{unresolved_int_ty,unresolved_float_ty,unresolved_ty}; - -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 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> { - infcx: &'a InferCtxt<'a, 'tcx>, - modes: uint, - err: Option<fixup_err>, - type_depth: uint, -} - -pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>, - modes: uint, - _: Option<Span>) - -> ResolveState<'a, 'tcx> { - ResolveState { - infcx: infcx, - modes: modes, - err: None, - type_depth: 0, - } -} - -impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for ResolveState<'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<Ty<'tcx>> { - 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<ty::Region> { - self.err = None; - let resolved = self.resolve_region(orig); - match self.err { - None => Ok(resolved), - Some(e) => Err(e) - } - } - - 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 - } - } - } - } - - 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 - } - } - - 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) - } - - 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) { - self.err = Some(unresolved_ty(vid)); - } - 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) - } - } - } -} +use middle::ty_fold::{mod, TypeFoldable}; +use util::ppaux::Repr; /////////////////////////////////////////////////////////////////////////// -/// DEEP TYPE RESOLVER -/// -/// This kind of resolver can be used at any time. It simply replaces +// 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 DeepTypeResolver<'a, 'tcx:'a> { +pub struct OpportunisticTypeResolver<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, } -impl<'a, 'tcx> DeepTypeResolver<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> DeepTypeResolver<'a, 'tcx> { - DeepTypeResolver { infcx: infcx } +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 DeepTypeResolver<'a, 'tcx> { +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } @@ -292,4 +46,70 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for DeepTypeResolver<'a, 'tcx> { } } +/////////////////////////////////////////////////////////////////////////// +// 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<T> + 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), + } +} + +// 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<fixup_err>, +} + +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.infcx.tcx + } + + 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) + } + } + } + } + + 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_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index b88da5d9387..b31683219f1 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::def; -use middle::infer::{mod, resolve}; +use middle::infer; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const}; use middle::subst::{Subst, Substs}; use middle::ty::{mod, Ty}; @@ -143,11 +143,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 }; @@ -214,23 +211,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<SomeTrait>", 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<SomeTrait>", 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_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 980097eaead..9af9eaf75f5 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -12,8 +12,6 @@ use check::FnCtxt; use middle::ty::{mod, Ty}; use middle::infer; -use middle::infer::resolve_type; -use middle::infer::resolve::try_resolve_tvar_shallow; use std::result::Result::{Err, Ok}; use syntax::ast; @@ -63,12 +61,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) { Ok(()) => { /* ok */ } Err(ref err) => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index bfa3c384da7..ad6ba0a1d55 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -124,8 +124,6 @@ use middle::region::CodeExtent; use middle::traits; use middle::ty::{ReScope}; use middle::ty::{mod, Ty, MethodCall}; -use middle::infer::resolve_and_force_all_but_regions; -use middle::infer::resolve_type; use middle::infer; use middle::pat_util; use util::nodemap::{DefIdMap, NodeMap, FnvHashMap}; @@ -307,11 +305,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { /// of b will be `&<R0>.int` and then `*b` will require that `<R0>` be bigger than the let and /// the `*b` expression, so we will effectively resolve `<R0>` 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_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 8d94cf5dd5e..b73381966e8 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -19,8 +19,6 @@ use middle::def; use middle::pat_util; use middle::ty::{mod, Ty, MethodCall, MethodCallee}; use middle::ty_fold::{TypeFolder,TypeFoldable}; -use middle::infer::{force_all, resolve_all, resolve_region}; -use middle::infer::resolve_type; use middle::infer; use write_substs_to_tcx; use write_ty_to_tcx; @@ -337,8 +335,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn resolve<T:ResolveIn<'tcx>>(&self, t: &T, reason: ResolveReason) -> T { - t.resolve_in(&mut Resolver::new(self.fcx, reason)) + fn resolve<T:TypeFoldable<'tcx>>(&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_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index a55f3c61919..8ed0ac98e1e 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -26,12 +26,13 @@ use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open}; use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn}; -use middle::ty::{type_is_ty_var}; +use middle::ty::{ty_closure}; +use middle::subst::Subst; use middle::ty; use CrateCtxt; use middle::infer::combine::Combine; use middle::infer::InferCtxt; -use middle::infer::{new_infer_ctxt, resolve_ivar, resolve_type}; +use middle::infer::{new_infer_ctxt}; use std::collections::{HashSet}; use std::cell::RefCell; use std::rc::Rc; @@ -52,80 +53,35 @@ mod orphan; mod overlap; mod unsafety; -fn get_base_type<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, - span: Span, - original_type: Ty<'tcx>) - -> Option<Ty<'tcx>> { - 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<DefId> { + 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<DefId> { - 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))[]); } } }