2012-12-03 16:48:01 -08:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2012-08-13 15:06:13 -07:00
|
|
|
// 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>`.
|
|
|
|
//
|
2012-11-07 18:40:34 -08:00
|
|
|
// 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.
|
2012-08-13 15:06:13 -07:00
|
|
|
//
|
|
|
|
// # 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
|
2014-04-21 00:49:39 -04:00
|
|
|
// resolution to fail in this case instead, except for the case of
|
2012-08-13 15:06:13 -07:00
|
|
|
// 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`.
|
|
|
|
|
2014-10-27 15:37:07 -07:00
|
|
|
#![allow(non_upper_case_globals)]
|
2014-09-13 13:55:37 +12:00
|
|
|
|
2014-11-25 16:59:02 -05:00
|
|
|
use super::{fixup_err, fres, InferCtxt};
|
|
|
|
use super::{unresolved_int_ty,unresolved_float_ty,unresolved_ty};
|
|
|
|
|
2013-01-08 19:37:25 -08:00
|
|
|
use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid};
|
2014-07-22 07:46:36 -04:00
|
|
|
use middle::ty::{IntType, UintType};
|
2014-09-13 21:09:25 +03:00
|
|
|
use middle::ty::{mod, Ty};
|
2013-10-29 06:03:32 -04:00
|
|
|
use middle::ty_fold;
|
2014-04-21 17:58:52 -04:00
|
|
|
use syntax::codemap::Span;
|
2014-06-21 03:39:03 -07:00
|
|
|
use util::ppaux::{Repr, ty_to_string};
|
2012-08-13 15:06:13 -07:00
|
|
|
|
2014-10-06 17:30:54 -07:00
|
|
|
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;
|
2012-08-13 15:06:13 -07:00
|
|
|
|
2014-10-06 17:30:54 -07:00
|
|
|
pub const not_regions: uint = !(force_rvar | resolve_rvar);
|
2012-08-13 15:06:13 -07:00
|
|
|
|
2014-10-06 17:30:54 -07:00
|
|
|
pub const try_resolve_tvar_shallow: uint = 0;
|
|
|
|
pub const resolve_and_force_all_but_regions: uint =
|
2012-08-13 15:06:13 -07:00
|
|
|
(resolve_all | force_all) & not_regions;
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
pub struct ResolveState<'a, 'tcx: 'a> {
|
|
|
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
2012-08-13 15:06:13 -07:00
|
|
|
modes: uint,
|
2013-02-04 14:02:01 -08:00
|
|
|
err: Option<fixup_err>,
|
2014-04-21 17:58:52 -04:00
|
|
|
type_depth: uint,
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>,
|
|
|
|
modes: uint,
|
|
|
|
_: Option<Span>)
|
|
|
|
-> ResolveState<'a, 'tcx> {
|
2013-01-08 14:00:45 -08:00
|
|
|
ResolveState {
|
|
|
|
infcx: infcx,
|
|
|
|
modes: modes,
|
|
|
|
err: None,
|
2014-04-21 17:58:52 -04:00
|
|
|
type_depth: 0,
|
2013-01-08 14:00:45 -08:00
|
|
|
}
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for ResolveState<'a, 'tcx> {
|
2014-09-12 10:53:35 -04:00
|
|
|
fn tcx(&self) -> &ty::ctxt<'tcx> {
|
2013-10-29 06:03:32 -04:00
|
|
|
self.infcx.tcx
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
2013-10-29 06:03:32 -04:00
|
|
|
self.resolve_type(t)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
|
|
|
|
self.resolve_region(r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'a, 'tcx> ResolveState<'a, 'tcx> {
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn should(&mut self, mode: uint) -> bool {
|
2012-08-13 15:06:13 -07:00
|
|
|
(self.modes & mode) == mode
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
pub fn resolve_type_chk(&mut self, typ: Ty<'tcx>) -> fres<Ty<'tcx>> {
|
2012-08-20 12:23:37 -07:00
|
|
|
self.err = None;
|
2012-08-13 15:06:13 -07:00
|
|
|
|
2013-10-21 13:08:31 -07:00
|
|
|
debug!("Resolving {} (modes={:x})",
|
2014-06-21 03:39:03 -07:00
|
|
|
ty_to_string(self.infcx.tcx, typ),
|
2012-08-22 17:24:52 -07:00
|
|
|
self.modes);
|
2012-08-13 15:06:13 -07:00
|
|
|
|
|
|
|
// n.b. This is a hokey mess because the current fold doesn't
|
|
|
|
// allow us to pass back errors in any useful way.
|
|
|
|
|
2014-09-09 17:45:51 -04:00
|
|
|
let rty = self.resolve_type(typ);
|
2012-08-13 15:06:13 -07:00
|
|
|
match self.err {
|
2014-09-12 10:53:35 -04:00
|
|
|
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);
|
|
|
|
}
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-21 17:58:52 -04:00
|
|
|
pub fn resolve_region_chk(&mut self,
|
|
|
|
orig: ty::Region)
|
2013-05-31 15:17:22 -07:00
|
|
|
-> fres<ty::Region> {
|
2012-08-20 12:23:37 -07:00
|
|
|
self.err = None;
|
2014-09-12 10:53:35 -04:00
|
|
|
let resolved = self.resolve_region(orig);
|
2012-08-13 15:06:13 -07:00
|
|
|
match self.err {
|
2012-08-26 16:54:31 -07:00
|
|
|
None => Ok(resolved),
|
|
|
|
Some(e) => Err(e)
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
pub fn resolve_type(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> {
|
2014-06-20 06:35:06 -04:00
|
|
|
debug!("resolve_type({})", typ.repr(self.infcx.tcx));
|
2013-01-08 14:00:45 -08:00
|
|
|
|
|
|
|
if !ty::type_needs_infer(typ) {
|
|
|
|
return typ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.type_depth > 0 && !self.should(resolve_nested_tvar) {
|
|
|
|
return typ;
|
|
|
|
}
|
2012-08-13 15:06:13 -07:00
|
|
|
|
2014-10-31 10:51:16 +02:00
|
|
|
match typ.sty {
|
2013-01-08 14:00:45 -08:00
|
|
|
ty::ty_infer(TyVar(vid)) => {
|
2012-08-13 15:06:13 -07:00
|
|
|
self.resolve_ty_var(vid)
|
2013-01-08 14:00:45 -08:00
|
|
|
}
|
|
|
|
ty::ty_infer(IntVar(vid)) => {
|
2012-09-06 12:30:15 -07:00
|
|
|
self.resolve_int_var(vid)
|
2013-01-08 14:00:45 -08:00
|
|
|
}
|
|
|
|
ty::ty_infer(FloatVar(vid)) => {
|
2012-11-07 18:40:34 -08:00
|
|
|
self.resolve_float_var(vid)
|
2013-01-08 14:00:45 -08:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
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
|
2012-08-13 15:06:13 -07:00
|
|
|
typ
|
|
|
|
} else {
|
2013-01-08 14:00:45 -08:00
|
|
|
self.type_depth += 1;
|
2013-10-29 06:03:32 -04:00
|
|
|
let result = ty_fold::super_fold_ty(self, typ);
|
2013-01-08 14:00:45 -08:00
|
|
|
self.type_depth -= 1;
|
|
|
|
result
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region {
|
2014-06-20 06:35:06 -04:00
|
|
|
debug!("Resolve_region({})", orig.repr(self.infcx.tcx));
|
2012-08-13 15:06:13 -07:00
|
|
|
match orig {
|
2013-10-29 10:34:11 -04:00
|
|
|
ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid),
|
2012-08-13 15:06:13 -07:00
|
|
|
_ => orig
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region {
|
2012-08-13 15:06:13 -07:00
|
|
|
if !self.should(resolve_rvar) {
|
2013-10-29 10:34:11 -04:00
|
|
|
return ty::ReInfer(ty::ReVar(rid));
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
self.infcx.region_vars.resolve_var(rid)
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
pub fn resolve_ty_var(&mut self, vid: TyVid) -> Ty<'tcx> {
|
2014-09-09 17:45:51 -04:00
|
|
|
let tcx = self.infcx.tcx;
|
2014-10-24 21:14:37 +02:00
|
|
|
let tv = self.infcx.type_variables.borrow();
|
|
|
|
match tv.probe(vid) {
|
2014-09-09 17:45:51 -04:00
|
|
|
Some(t) => {
|
|
|
|
self.resolve_type(t)
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
if self.should(force_tvar) {
|
|
|
|
self.err = Some(unresolved_ty(vid));
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
2014-09-09 17:45:51 -04:00
|
|
|
ty::mk_var(tcx, vid)
|
|
|
|
}
|
2014-10-24 21:14:37 +02:00
|
|
|
}
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
pub fn resolve_int_var(&mut self, vid: IntVid) -> Ty<'tcx> {
|
2012-08-13 15:06:13 -07:00
|
|
|
if !self.should(resolve_ivar) {
|
2012-09-06 12:30:15 -07:00
|
|
|
return ty::mk_int_var(self.infcx.tcx, vid);
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-06-20 06:35:06 -04:00
|
|
|
let tcx = self.infcx.tcx;
|
|
|
|
let table = &self.infcx.int_unification_table;
|
|
|
|
let node = table.borrow_mut().get(tcx, vid);
|
|
|
|
match node.value {
|
2013-04-22 20:19:05 -07:00
|
|
|
Some(IntType(t)) => ty::mk_mach_int(t),
|
|
|
|
Some(UintType(t)) => ty::mk_mach_uint(t),
|
2012-08-20 12:23:37 -07:00
|
|
|
None => {
|
2012-08-13 15:06:13 -07:00
|
|
|
if self.should(force_ivar) {
|
2014-06-27 12:30:25 -07:00
|
|
|
// As a last resort, emit an error.
|
|
|
|
self.err = Some(unresolved_int_ty(vid));
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
2014-06-27 12:30:25 -07:00
|
|
|
ty::mk_int_var(self.infcx.tcx, vid)
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-07 18:40:34 -08:00
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
pub fn resolve_float_var(&mut self, vid: FloatVid) -> Ty<'tcx> {
|
2012-11-07 18:40:34 -08:00
|
|
|
if !self.should(resolve_fvar) {
|
|
|
|
return ty::mk_float_var(self.infcx.tcx, vid);
|
|
|
|
}
|
|
|
|
|
2014-06-20 06:35:06 -04:00
|
|
|
let tcx = self.infcx.tcx;
|
|
|
|
let table = &self.infcx.float_unification_table;
|
|
|
|
let node = table.borrow_mut().get(tcx, vid);
|
|
|
|
match node.value {
|
2013-04-22 20:19:05 -07:00
|
|
|
Some(t) => ty::mk_mach_float(t),
|
2012-11-07 18:40:34 -08:00
|
|
|
None => {
|
|
|
|
if self.should(force_fvar) {
|
2014-06-27 12:30:25 -07:00
|
|
|
// As a last resort, emit an error.
|
|
|
|
self.err = Some(unresolved_float_ty(vid));
|
2012-11-07 18:40:34 -08:00
|
|
|
}
|
2014-06-27 12:30:25 -07:00
|
|
|
ty::mk_float_var(self.infcx.tcx, vid)
|
2012-11-07 18:40:34 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
2014-12-01 10:11:59 -05:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
/// DEEP TYPE RESOLVER
|
|
|
|
///
|
|
|
|
/// This kind of 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> {
|
|
|
|
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> ty_fold::TypeFolder<'tcx> for DeepTypeResolver<'a, 'tcx> {
|
|
|
|
fn tcx(&self) -> &ty::ctxt<'tcx> {
|
|
|
|
self.infcx.tcx
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|