1
Fork 0
rust/src/librustc/middle/infer/mod.rs

1300 lines
43 KiB
Rust
Raw Normal View History

// Copyright 2012-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 <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.
//! See doc.rs for documentation
2012-11-29 16:41:39 -08:00
#![allow(non_camel_case_types)]
pub use self::LateBoundRegionConversionTime::*;
pub use self::RegionVariableOrigin::*;
pub use self::SubregionOrigin::*;
pub use self::TypeOrigin::*;
pub use self::ValuePairs::*;
pub use self::fixup_err::*;
pub use middle::ty::IntVarValue;
pub use self::freshen::TypeFreshener;
pub use self::region_inference::GenericKind;
use middle::subst;
use middle::subst::Substs;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
use middle::ty::replace_late_bound_regions;
2015-01-03 22:42:21 -05:00
use middle::ty::{self, Ty};
use middle::ty_fold::{TypeFolder, TypeFoldable};
use std::cell::{RefCell};
2014-04-22 02:21:52 +03:00
use std::rc::Rc;
use syntax::ast;
2013-01-30 09:56:33 -08:00
use syntax::codemap;
use syntax::codemap::Span;
use util::common::indent;
use util::nodemap::FnvHashMap;
use util::ppaux::{ty_to_string};
use util::ppaux::{Repr, UserString};
2012-11-29 16:41:39 -08:00
use self::coercion::Coerce;
use self::combine::{Combine, Combineable, CombineFields};
use self::region_inference::{RegionVarBindings, RegionSnapshot};
use self::equate::Equate;
use self::sub::Sub;
use self::lub::Lub;
use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes};
use self::error_reporting::ErrorReporting;
pub mod coercion;
pub mod combine;
pub mod doc;
pub mod equate;
pub mod error_reporting;
pub mod glb;
mod higher_ranked;
pub mod lattice;
pub mod lub;
pub mod region_inference;
pub mod resolve;
mod freshen;
pub mod sub;
pub mod type_variable;
pub mod unify;
pub type Bound<T> = Option<T>;
2013-07-02 12:47:32 -07:00
pub type cres<'tcx, T> = Result<T,ty::type_err<'tcx>>; // "combine result"
pub type ures<'tcx> = cres<'tcx, ()>; // "unify result"
pub type fres<T> = Result<T, fixup_err>; // "fixup result"
pub type CoerceResult<'tcx> = cres<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
pub struct InferCtxt<'a, 'tcx: 'a> {
pub tcx: &'a ty::ctxt<'tcx>,
2012-11-29 16:41:39 -08:00
// We instantiate UnificationTable with bounds<Ty> because the
2012-11-29 16:41:39 -08:00
// types that might instantiate a general type variable have an
// order, represented by its upper and lower bounds.
type_variables: RefCell<type_variable::TypeVariableTable<'tcx>>,
2012-11-29 16:41:39 -08:00
// Map from integral variable to the kind of integer it represents
int_unification_table:
RefCell<UnificationTable<ty::IntVid, Option<IntVarValue>>>,
2012-11-29 16:41:39 -08:00
// Map from floating variable to the kind of float it represents
float_unification_table:
RefCell<UnificationTable<ty::FloatVid, Option<ast::FloatTy>>>,
2012-11-29 16:41:39 -08:00
// For region variables.
region_vars:
RegionVarBindings<'a, 'tcx>,
}
2012-11-29 16:41:39 -08:00
/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
/// region that each late-bound region was replaced with.
pub type SkolemizationMap = FnvHashMap<ty::BoundRegion,ty::Region>;
/// Why did we require that the two types be related?
///
/// See `error_reporting.rs` for more details
#[derive(Clone, Copy, Show)]
pub enum TypeOrigin {
// Not yet categorized in a better way
Misc(Span),
// Checking that method of impl is compatible with trait
MethodCompatCheck(Span),
// Checking that this expression can be assigned where it needs to be
2014-01-06 14:00:46 +02:00
// FIXME(eddyb) #11161 is the original Expr required?
ExprAssignable(Span),
// Relating trait refs when resolving vtables
RelateTraitRefs(Span),
// Relating self types when resolving vtables
RelateSelfType(Span),
// Relating trait type parameters to those found in impl etc
RelateOutputImplTypes(Span),
// Computing common supertype in the arms of a match expression
MatchExpressionArm(Span, Span),
// Computing common supertype in an if expression
IfExpression(Span),
// Computing common supertype of an if expression with no else counter-part
IfExpressionWithNoElse(Span),
2014-12-16 16:25:33 +13:00
// Computing common supertype in a range expression
RangeExpression(Span),
// `where a == b`
EquatePredicate(Span),
}
/// See `error_reporting.rs` for more details
#[derive(Clone, Show)]
pub enum ValuePairs<'tcx> {
Types(ty::expected_found<Ty<'tcx>>),
TraitRefs(ty::expected_found<Rc<ty::TraitRef<'tcx>>>),
PolyTraitRefs(ty::expected_found<ty::PolyTraitRef<'tcx>>),
}
/// The trace designates the path through inference that we took to
/// encounter an error or subtyping constraint.
///
/// See `error_reporting.rs` for more details.
#[derive(Clone, Show)]
pub struct TypeTrace<'tcx> {
origin: TypeOrigin,
values: ValuePairs<'tcx>,
}
/// The origin of a `r1 <= r2` constraint.
///
/// See `error_reporting.rs` for more details
#[derive(Clone, Show)]
pub enum SubregionOrigin<'tcx> {
// Arose from a subtyping relation
Subtype(TypeTrace<'tcx>),
// Stack-allocated closures cannot outlive innermost loop
// or function so as to ensure we only require finite stack
InfStackClosure(Span),
// Invocation of closure must be within its lifetime
InvokeClosure(Span),
2014-01-07 18:49:13 -08:00
// Dereference of reference must be within its lifetime
DerefPointer(Span),
// Closure bound must not outlive captured free variables
FreeVariable(Span, ast::NodeId),
// Index into slice must be within its lifetime
IndexSlice(Span),
// When casting `&'a T` to an `&'b Trait` object,
// relating `'a` to `'b`
RelateObjectBound(Span),
// Some type parameter was instantiated with the given type,
// and that type must outlive some region.
RelateParamBound(Span, Ty<'tcx>),
// The given region parameter was instantiated with a region
// that must outlive some other region.
RelateRegionParamBound(Span),
// A bound placed on type parameters that states that must outlive
// the moment of their instantiation.
RelateDefaultParamBound(Span, Ty<'tcx>),
2014-01-07 18:49:13 -08:00
// Creating a pointer `b` to contents of another reference
Reborrow(Span),
// Creating a pointer `b` to contents of an upvar
ReborrowUpvar(Span, ty::UpvarId),
// (&'a &'b T) where a >= b
ReferenceOutlivesReferent(Ty<'tcx>, Span),
// The type T of an expression E must outlive the lifetime for E.
ExprTypeIsNotInScope(Ty<'tcx>, Span),
// A `ref b` whose region does not enclose the decl site
BindingTypeIsNotValidAtDecl(Span),
// Regions appearing in a method receiver must outlive method call
CallRcvr(Span),
// Regions appearing in a function argument must outlive func call
CallArg(Span),
// Region in return type of invoked fn must enclose call
CallReturn(Span),
// Region resulting from a `&` expr must enclose the `&` expr
AddrOf(Span),
// An auto-borrow that does not enclose the expr where it occurs
AutoBorrow(Span),
}
/// Times when we replace late-bound regions with variables:
#[derive(Clone, Copy, Show)]
pub enum LateBoundRegionConversionTime {
/// when a fn is called
FnCall,
/// when two higher-ranked types are compared
HigherRankedType,
/// when projecting an associated type
AssocTypeProjection(ast::Name),
}
/// Reasons to create a region inference variable
///
/// See `error_reporting.rs` for more details
#[derive(Clone, Show)]
pub enum RegionVariableOrigin<'tcx> {
// Region variables created for ill-categorized reasons,
// mostly indicates places in need of refactoring
MiscVariable(Span),
// Regions created by a `&P` or `[...]` pattern
PatternRegion(Span),
// Regions created by `&` operator
AddrOfRegion(Span),
// Regions created by `&[...]` literal
AddrOfSlice(Span),
// Regions created as part of an autoref of a method receiver
Autoref(Span),
// Regions created as part of an automatic coercion
Coercion(TypeTrace<'tcx>),
// Region variables created as the values for early-bound regions
EarlyBoundRegion(Span, ast::Name),
// Region variables created for bound regions
// in a function or method that is called
LateBoundRegion(Span, ty::BoundRegion, LateBoundRegionConversionTime),
UpvarRegion(ty::UpvarId, Span),
BoundRegionInCoherence(ast::Name),
}
#[derive(Copy, Show)]
pub enum fixup_err {
2012-11-29 16:41:39 -08:00
unresolved_int_ty(IntVid),
unresolved_float_ty(FloatVid),
2014-09-20 15:37:14 +02:00
unresolved_ty(TyVid)
2012-11-29 16:41:39 -08:00
}
pub fn fixup_err_to_string(f: fixup_err) -> String {
2012-11-29 16:41:39 -08:00
match f {
unresolved_int_ty(_) => {
"cannot determine the type of this integer; add a suffix to \
specify the type explicitly".to_string()
}
unresolved_float_ty(_) => {
"cannot determine the type of this number; add a suffix to specify \
the type explicitly".to_string()
}
unresolved_ty(_) => "unconstrained type".to_string(),
2012-11-29 16:41:39 -08:00
}
}
pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>)
-> InferCtxt<'a, 'tcx> {
2014-02-07 00:38:33 +02:00
InferCtxt {
tcx: tcx,
type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
int_unification_table: RefCell::new(UnificationTable::new()),
float_unification_table: RefCell::new(UnificationTable::new()),
region_vars: RegionVarBindings::new(tcx),
}
}
/// Computes the least upper-bound of `a` and `b`. If this is not possible, reports an error and
/// returns ty::err.
pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin,
a_is_expected: bool,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> Ty<'tcx>
{
debug!("common_supertype({}, {})",
a.repr(cx.tcx), b.repr(cx.tcx));
let trace = TypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
let result =
cx.commit_if_ok(|| cx.lub(a_is_expected, trace.clone()).tys(a, b));
match result {
Ok(t) => t,
Err(ref err) => {
cx.report_and_explain_type_error(trace, err);
cx.tcx.types.err
}
}
}
pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> ures<'tcx>
{
debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
cx.commit_if_ok(|| {
cx.sub_types(a_is_expected, origin, a, b)
})
2012-11-29 16:41:39 -08:00
}
pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> ures<'tcx> {
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
cx.probe(|_| {
let trace = TypeTrace {
origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, a, b))
};
cx.sub(true, trace).tys(a, b).to_ures()
})
2012-11-29 16:41:39 -08:00
}
pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx>
{
cx.can_equate(&a, &b)
}
pub fn mk_subr<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: SubregionOrigin<'tcx>,
a: ty::Region,
b: ty::Region) {
debug!("mk_subr({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
let snapshot = cx.region_vars.start_snapshot();
cx.region_vars.make_subregion(origin, a, b);
cx.region_vars.commit(snapshot);
2012-11-29 16:41:39 -08:00
}
pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> ures<'tcx>
{
debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
cx.commit_if_ok(
|| cx.eq_types(a_is_expected, origin, a, b))
2012-11-29 16:41:39 -08:00
}
pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
-> ures<'tcx>
{
debug!("mk_sub_trait_refs({} <: {})",
a.repr(cx.tcx), b.repr(cx.tcx));
cx.commit_if_ok(
|| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
}
fn expected_found<T>(a_is_expected: bool,
a: T,
b: T)
-> ty::expected_found<T>
{
if a_is_expected {
ty::expected_found {expected: a, found: b}
} else {
ty::expected_found {expected: b, found: a}
}
}
pub fn mk_coercety<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
debug!("mk_coercety({} -> {})", a.repr(cx.tcx), b.repr(cx.tcx));
indent(|| {
cx.commit_if_ok(|| {
let trace = TypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
Coerce(cx.combine_fields(a_is_expected, trace)).tys(a, b)
})
})
2012-11-29 16:41:39 -08:00
}
trait then<'tcx> {
2014-12-08 20:26:43 -05:00
fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where
T: Clone,
F: FnOnce() -> Result<T, ty::type_err<'tcx>>;
2012-11-29 16:41:39 -08:00
}
impl<'tcx> then<'tcx> for ures<'tcx> {
2014-12-08 20:26:43 -05:00
fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where
T: Clone,
F: FnOnce() -> Result<T, ty::type_err<'tcx>>,
{
self.and_then(move |_| f())
2012-11-29 16:41:39 -08:00
}
}
trait ToUres<'tcx> {
fn to_ures(&self) -> ures<'tcx>;
2012-11-29 16:41:39 -08:00
}
impl<'tcx, T> ToUres<'tcx> for cres<'tcx, T> {
fn to_ures(&self) -> ures<'tcx> {
2013-02-22 01:41:37 -05:00
match *self {
Ok(ref _v) => Ok(()),
Err(ref e) => Err((*e))
2012-11-29 16:41:39 -08:00
}
}
}
trait CresCompare<'tcx, T> {
2014-12-08 20:26:43 -05:00
fn compare<F>(&self, t: T, f: F) -> cres<'tcx, T> where
F: FnOnce() -> ty::type_err<'tcx>;
2012-11-29 16:41:39 -08:00
}
impl<'tcx, T:Clone + PartialEq> CresCompare<'tcx, T> for cres<'tcx, T> {
2014-12-08 20:26:43 -05:00
fn compare<F>(&self, t: T, f: F) -> cres<'tcx, T> where
F: FnOnce() -> ty::type_err<'tcx>,
{
(*self).clone().and_then(move |s| {
2012-11-29 16:41:39 -08:00
if s == t {
2013-07-02 12:47:32 -07:00
(*self).clone()
2012-11-29 16:41:39 -08:00
} else {
Err(f())
}
})
2012-11-29 16:41:39 -08:00
}
}
pub fn uok<'tcx>() -> ures<'tcx> {
2012-11-29 16:41:39 -08:00
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<ty::IntVid>,
float_snapshot: unify::Snapshot<ty::FloatVid>,
region_vars_snapshot: RegionSnapshot,
2012-11-29 16:41:39 -08:00
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
t.fold_with(&mut self.freshener())
}
pub fn type_var_diverges(&'a self, ty: Ty) -> bool {
match ty.sty {
ty::ty_infer(ty::TyVar(vid)) => self.type_variables.borrow().var_diverges(vid),
_ => false
}
}
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
freshen::TypeFreshener::new(self)
}
pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric {
use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat};
match ty.sty {
ty::ty_infer(ty::IntVar(vid)) => {
match self.int_unification_table.borrow_mut().get(self.tcx, vid).value {
None => UnconstrainedInt,
_ => Neither,
}
},
ty::ty_infer(ty::FloatVar(vid)) => {
match self.float_unification_table.borrow_mut().get(self.tcx, vid).value {
None => return UnconstrainedFloat,
_ => Neither,
}
},
_ => Neither,
}
}
2014-12-12 11:09:32 -05:00
pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-> CombineFields<'b, 'tcx> {
CombineFields {infcx: self,
a_is_expected: a_is_expected,
trace: trace}
2012-11-29 16:41:39 -08:00
}
2014-12-12 11:09:32 -05:00
pub fn equate<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-> Equate<'b, 'tcx> {
Equate(self.combine_fields(a_is_expected, trace))
}
2014-12-12 11:09:32 -05:00
pub fn sub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-> Sub<'b, 'tcx> {
Sub(self.combine_fields(a_is_expected, trace))
2012-11-29 16:41:39 -08:00
}
2014-12-12 11:09:32 -05:00
pub fn lub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-> Lub<'b, 'tcx> {
Lub(self.combine_fields(a_is_expected, trace))
}
fn start_snapshot(&self) -> CombinedSnapshot {
CombinedSnapshot {
type_snapshot: self.type_variables.borrow_mut().snapshot(),
int_snapshot: self.int_unification_table.borrow_mut().snapshot(),
float_snapshot: self.float_unification_table.borrow_mut().snapshot(),
region_vars_snapshot: self.region_vars.start_snapshot(),
2012-11-29 16:41:39 -08:00
}
}
fn rollback_to(&self, snapshot: CombinedSnapshot) {
debug!("rollback!");
let CombinedSnapshot { type_snapshot,
int_snapshot,
float_snapshot,
region_vars_snapshot } = snapshot;
self.type_variables
.borrow_mut()
2014-07-22 07:40:51 -04:00
.rollback_to(type_snapshot);
self.int_unification_table
.borrow_mut()
2014-07-22 07:40:51 -04:00
.rollback_to(int_snapshot);
self.float_unification_table
.borrow_mut()
2014-07-22 07:40:51 -04:00
.rollback_to(float_snapshot);
self.region_vars
.rollback_to(region_vars_snapshot);
2012-11-29 16:41:39 -08:00
}
fn commit_from(&self, snapshot: CombinedSnapshot) {
debug!("commit_from!");
let CombinedSnapshot { type_snapshot,
int_snapshot,
float_snapshot,
region_vars_snapshot } = snapshot;
self.type_variables
.borrow_mut()
.commit(type_snapshot);
self.int_unification_table
.borrow_mut()
.commit(int_snapshot);
self.float_unification_table
.borrow_mut()
.commit(float_snapshot);
self.region_vars
.commit(region_vars_snapshot);
}
2012-11-29 16:41:39 -08:00
/// Execute `f` and commit the bindings
2014-12-08 20:26:43 -05:00
pub fn commit_unconditionally<R, F>(&self, f: F) -> R where
F: FnOnce() -> R,
{
debug!("commit()");
let snapshot = self.start_snapshot();
let r = f();
self.commit_from(snapshot);
r
}
2012-11-29 16:41:39 -08:00
/// Execute `f` and commit the bindings if successful
2014-12-08 20:26:43 -05:00
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
F: FnOnce() -> Result<T, E>
{
self.commit_unconditionally(move || self.try(move |_| f()))
2012-11-29 16:41:39 -08:00
}
/// Execute `f`, unroll bindings on panic
2014-12-08 20:26:43 -05:00
pub fn try<T, E, F>(&self, f: F) -> Result<T, E> where
F: FnOnce(&CombinedSnapshot) -> Result<T, E>
2014-12-08 20:26:43 -05:00
{
debug!("try()");
let snapshot = self.start_snapshot();
let r = f(&snapshot);
debug!("try() -- r.is_ok() = {}", r.is_ok());
match r {
Ok(_) => {
self.commit_from(snapshot);
}
Err(_) => {
self.rollback_to(snapshot);
2012-11-29 16:41:39 -08:00
}
}
r
2012-11-29 16:41:39 -08:00
}
/// Execute `f` then unroll any bindings it creates
2014-12-08 20:26:43 -05:00
pub fn probe<R, F>(&self, f: F) -> R where
F: FnOnce(&CombinedSnapshot) -> R,
2014-12-08 20:26:43 -05:00
{
debug!("probe()");
let snapshot = self.start_snapshot();
let r = f(&snapshot);
self.rollback_to(snapshot);
r
2012-11-29 16:41:39 -08:00
}
pub fn add_given(&self,
sub: ty::FreeRegion,
sup: ty::RegionVid)
{
self.region_vars.add_given(sub, sup);
}
pub fn sub_types(&self,
a_is_expected: bool,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> ures<'tcx>
{
debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx));
self.commit_if_ok(|| {
let trace = TypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
self.sub(a_is_expected, trace).tys(a, b).to_ures()
})
}
pub fn eq_types(&self,
a_is_expected: bool,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> ures<'tcx>
{
self.commit_if_ok(|| {
let trace = TypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
self.equate(a_is_expected, trace).tys(a, b).to_ures()
})
}
pub fn sub_trait_refs(&self,
a_is_expected: bool,
origin: TypeOrigin,
a: Rc<ty::TraitRef<'tcx>>,
b: Rc<ty::TraitRef<'tcx>>)
-> ures<'tcx>
{
debug!("sub_trait_refs({} <: {})",
a.repr(self.tcx),
b.repr(self.tcx));
self.commit_if_ok(|| {
let trace = TypeTrace {
origin: origin,
values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
};
self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures()
})
}
pub fn sub_poly_trait_refs(&self,
a_is_expected: bool,
origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
-> ures<'tcx>
{
debug!("sub_poly_trait_refs({} <: {})",
a.repr(self.tcx),
b.repr(self.tcx));
self.commit_if_ok(|| {
let trace = TypeTrace {
origin: origin,
values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
};
self.sub(a_is_expected, trace).binders(&a, &b).to_ures()
})
}
2012-11-29 16:41:39 -08:00
pub fn skolemize_late_bound_regions<T>(&self,
value: &ty::Binder<T>,
snapshot: &CombinedSnapshot)
-> (T, SkolemizationMap)
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
/*! See `higher_ranked::skolemize_late_bound_regions` */
higher_ranked::skolemize_late_bound_regions(self, value, snapshot)
}
pub fn leak_check(&self,
skol_map: &SkolemizationMap,
snapshot: &CombinedSnapshot)
-> ures<'tcx>
{
/*! See `higher_ranked::leak_check` */
match higher_ranked::leak_check(self, skol_map, snapshot) {
Ok(()) => Ok(()),
Err((br, r)) => Err(ty::terr_regions_insufficiently_polymorphic(br, r))
}
}
pub fn plug_leaks<T>(&self,
skol_map: SkolemizationMap,
snapshot: &CombinedSnapshot,
value: &T)
-> T
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
/*! See `higher_ranked::plug_leaks` */
higher_ranked::plug_leaks(self, skol_map, snapshot, value)
}
pub fn equality_predicate(&self,
span: Span,
predicate: &ty::PolyEquatePredicate<'tcx>)
-> ures<'tcx> {
self.try(|snapshot| {
let (ty::EquatePredicate(a, b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
let origin = EquatePredicate(span);
let () = try!(mk_eqty(self, false, origin, a, b));
self.leak_check(&skol_map, snapshot)
})
}
pub fn region_outlives_predicate(&self,
span: Span,
predicate: &ty::PolyRegionOutlivesPredicate)
-> ures<'tcx> {
self.try(|snapshot| {
let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
let origin = RelateRegionParamBound(span);
let () = mk_subr(self, origin, r_b, r_a); // `b : a` ==> `a <= b`
self.leak_check(&skol_map, snapshot)
})
}
pub fn next_ty_var_id(&self, diverging: bool) -> TyVid {
self.type_variables
.borrow_mut()
.new_var(diverging)
2012-11-29 16:41:39 -08:00
}
pub fn next_ty_var(&self) -> Ty<'tcx> {
ty::mk_var(self.tcx, self.next_ty_var_id(false))
}
pub fn next_diverging_ty_var(&self) -> Ty<'tcx> {
ty::mk_var(self.tcx, self.next_ty_var_id(true))
2012-11-29 16:41:39 -08:00
}
pub fn next_ty_vars(&self, n: uint) -> Vec<Ty<'tcx>> {
2014-12-30 10:51:18 -08:00
range(0, n).map(|_i| self.next_ty_var()).collect()
2012-11-29 16:41:39 -08:00
}
pub fn next_int_var_id(&self) -> IntVid {
self.int_unification_table
.borrow_mut()
.new_key(None)
2012-11-29 16:41:39 -08:00
}
pub fn next_float_var_id(&self) -> FloatVid {
self.float_unification_table
.borrow_mut()
.new_key(None)
2012-11-29 16:41:39 -08:00
}
pub fn next_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> ty::Region {
2013-10-29 10:34:11 -04:00
ty::ReInfer(ty::ReVar(self.region_vars.new_region_var(origin)))
2012-11-29 16:41:39 -08:00
}
pub fn region_vars_for_defs(&self,
span: Span,
defs: &[ty::RegionParameterDef])
-> Vec<ty::Region> {
defs.iter()
.map(|d| self.next_region_var(EarlyBoundRegion(span, d.name)))
.collect()
}
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
/// type/region parameter to a fresh inference variable.
pub fn fresh_substs_for_generics(&self,
span: Span,
generics: &ty::Generics<'tcx>)
-> subst::Substs<'tcx>
{
let type_params =
generics.types.map(
|_| self.next_ty_var());
let region_params =
generics.regions.map(
|d| self.next_region_var(EarlyBoundRegion(span, d.name)));
subst::Substs::new(type_params, region_params)
}
/// Given a set of generics defined on a trait, returns a substitution mapping each output
/// type/region parameter to a fresh inference variable, and mapping the self type to
/// `self_ty`.
pub fn fresh_substs_for_trait(&self,
span: Span,
generics: &ty::Generics<'tcx>,
self_ty: Ty<'tcx>)
-> subst::Substs<'tcx>
{
assert!(generics.types.len(subst::SelfSpace) == 1);
assert!(generics.types.len(subst::FnSpace) == 0);
assert!(generics.regions.len(subst::SelfSpace) == 0);
assert!(generics.regions.len(subst::FnSpace) == 0);
let type_parameter_count = generics.types.len(subst::TypeSpace);
let type_parameters = self.next_ty_vars(type_parameter_count);
let region_param_defs = generics.regions.get_slice(subst::TypeSpace);
let regions = self.region_vars_for_defs(span, region_param_defs);
2014-12-29 16:32:12 -05:00
subst::Substs::new_trait(type_parameters, regions, self_ty)
}
pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {
self.region_vars.new_bound(debruijn)
}
pub fn resolve_regions_and_report_errors(&self, subject_node_id: ast::NodeId) {
let errors = self.region_vars.resolve_regions(subject_node_id);
self.report_region_errors(&errors); // see error_reporting.rs
2012-11-29 16:41:39 -08:00
}
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
ty_to_string(self.tcx,
self.resolve_type_vars_if_possible(&t))
2012-11-29 16:41:39 -08:00
}
pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String {
let tstrs: Vec<String> = ts.iter().map(|t| self.ty_to_string(*t)).collect();
format!("({})", tstrs.connect(", "))
}
pub fn trait_ref_to_string(&self, t: &Rc<ty::TraitRef<'tcx>>) -> String {
let t = self.resolve_type_vars_if_possible(&**t);
t.user_string(self.tcx)
}
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)
}
ty::ty_infer(ty::IntVar(v)) => {
self.probe_var(v)
.unwrap_or(typ)
}
ty::ty_infer(ty::FloatVar(v)) => {
self.probe_var(v)
.unwrap_or(typ)
}
_ => {
typ
}
}
}
pub fn resolve_type_vars_if_possible<T:TypeFoldable<'tcx>>(&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 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),
// this is a derived error. The error cascaded from another error (that was already
// reported), so it's not useful to display it to the user.
// The following four methods -- type_error_message_str, type_error_message_str_with_expected,
// type_error_message, and report_mismatched_types -- implement this logic.
// They check if either the actual or expected type is ty_err, and don't print the error
// in this case. The typechecker should only ever report type errors involving mismatched
// types using one of these four methods, and should not call span_err directly for such
// errors.
2014-12-08 20:26:43 -05:00
pub fn type_error_message_str<M>(&self,
sp: Span,
mk_msg: M,
actual_ty: String,
err: Option<&ty::type_err<'tcx>>) where
M: FnOnce(Option<String>, String) -> String,
{
self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err)
}
2014-12-08 20:26:43 -05:00
pub fn type_error_message_str_with_expected<M>(&self,
sp: Span,
mk_msg: M,
expected_ty: Option<Ty<'tcx>>,
actual_ty: String,
err: Option<&ty::type_err<'tcx>>) where
M: FnOnce(Option<String>, String) -> String,
{
debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty);
2012-11-29 16:41:39 -08:00
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) => (),
_ => {
let error_str = err.map_or("".to_string(), |t_err| {
format!(" ({})", ty::type_err_to_str(self.tcx, t_err))
});
2015-01-07 11:58:31 -05:00
self.tcx.sess.span_err(sp, &format!("{}{}",
mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty),
2015-01-07 11:58:31 -05:00
error_str)[]);
for err in err.iter() {
ty::note_and_explain_type_err(self.tcx, *err)
}
}
}
2012-11-29 16:41:39 -08:00
}
2014-12-08 20:26:43 -05:00
pub fn type_error_message<M>(&self,
sp: Span,
mk_msg: M,
actual_ty: Ty<'tcx>,
err: Option<&ty::type_err<'tcx>>) where
M: FnOnce(String) -> String,
{
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) {
return;
}
2014-12-08 20:26:43 -05:00
self.type_error_message_str(sp,
move |_e, a| { mk_msg(a) },
self.ty_to_string(actual_ty), err);
}
2014-02-07 00:38:33 +02:00
pub fn report_mismatched_types(&self,
span: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
err: &ty::type_err<'tcx>) {
let trace = TypeTrace {
origin: Misc(span),
values: Types(ty::expected_found {
expected: expected,
found: actual
})
2012-11-29 16:41:39 -08:00
};
self.report_and_explain_type_error(trace, err);
2012-11-29 16:41:39 -08:00
}
2014-11-12 14:11:22 -05:00
pub fn replace_late_bound_regions_with_fresh_var<T>(
&self,
span: Span,
lbrct: LateBoundRegionConversionTime,
value: &ty::Binder<T>)
2014-11-12 14:11:22 -05:00
-> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
ty::replace_late_bound_regions(
self.tcx,
value,
|br| self.next_region_var(LateBoundRegion(span, br, lbrct)))
2012-11-29 16:41:39 -08:00
}
/// See `verify_generic_bound` method in `region_inference`
pub fn verify_generic_bound(&self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
a: ty::Region,
bs: Vec<ty::Region>) {
debug!("verify_generic_bound({}, {} <: {})",
kind.repr(self.tcx),
a.repr(self.tcx),
bs.repr(self.tcx));
self.region_vars.verify_generic_bound(origin, kind, a, bs);
}
pub fn can_equate<T>(&self, a: &T, b: &T) -> ures<'tcx>
where T : Combineable<'tcx> + Repr<'tcx>
{
debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx));
self.probe(|_| {
// Gin up a dummy trace, since this won't be committed
// anyhow. We should make this typetrace stuff more
// generic so we don't have to do anything quite this
// terrible.
let e = self.tcx.types.err;
let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, e, e)) };
let eq = self.equate(true, trace);
Combineable::combine(&eq, a, b)
}).to_ures()
}
2013-05-02 14:32:37 -04:00
}
2012-11-29 16:41:39 -08:00
impl<'tcx> TypeTrace<'tcx> {
pub fn span(&self) -> Span {
self.origin.span()
}
pub fn dummy(tcx: &ty::ctxt<'tcx>) -> TypeTrace<'tcx> {
TypeTrace {
origin: Misc(codemap::DUMMY_SP),
values: Types(ty::expected_found {
expected: tcx.types.err,
found: tcx.types.err,
})
}
}
}
impl<'tcx> Repr<'tcx> for TypeTrace<'tcx> {
fn repr(&self, tcx: &ty::ctxt) -> String {
format!("TypeTrace({})", self.origin.repr(tcx))
}
}
impl TypeOrigin {
pub fn span(&self) -> Span {
match *self {
MethodCompatCheck(span) => span,
2014-01-06 14:00:46 +02:00
ExprAssignable(span) => span,
Misc(span) => span,
RelateTraitRefs(span) => span,
RelateSelfType(span) => span,
RelateOutputImplTypes(span) => span,
MatchExpressionArm(match_span, _) => match_span,
IfExpression(span) => span,
IfExpressionWithNoElse(span) => span,
2014-12-16 16:25:33 +13:00
RangeExpression(span) => span,
EquatePredicate(span) => span,
}
}
}
impl<'tcx> Repr<'tcx> for TypeOrigin {
fn repr(&self, tcx: &ty::ctxt) -> String {
match *self {
MethodCompatCheck(a) => {
format!("MethodCompatCheck({})", a.repr(tcx))
}
ExprAssignable(a) => {
format!("ExprAssignable({})", a.repr(tcx))
}
Misc(a) => format!("Misc({})", a.repr(tcx)),
RelateTraitRefs(a) => {
format!("RelateTraitRefs({})", a.repr(tcx))
}
RelateSelfType(a) => {
format!("RelateSelfType({})", a.repr(tcx))
}
RelateOutputImplTypes(a) => {
format!("RelateOutputImplTypes({})", a.repr(tcx))
}
MatchExpressionArm(a, b) => {
format!("MatchExpressionArm({}, {})", a.repr(tcx), b.repr(tcx))
}
IfExpression(a) => {
format!("IfExpression({})", a.repr(tcx))
}
IfExpressionWithNoElse(a) => {
format!("IfExpressionWithNoElse({})", a.repr(tcx))
}
2014-12-16 16:25:33 +13:00
RangeExpression(a) => {
format!("RangeExpression({})", a.repr(tcx))
}
EquatePredicate(a) => {
format!("EquatePredicate({})", a.repr(tcx))
}
}
}
}
impl<'tcx> SubregionOrigin<'tcx> {
pub fn span(&self) -> Span {
match *self {
2014-04-22 02:21:52 +03:00
Subtype(ref a) => a.span(),
InfStackClosure(a) => a,
InvokeClosure(a) => a,
DerefPointer(a) => a,
FreeVariable(a, _) => a,
IndexSlice(a) => a,
RelateObjectBound(a) => a,
RelateParamBound(a, _) => a,
RelateRegionParamBound(a) => a,
RelateDefaultParamBound(a, _) => a,
Reborrow(a) => a,
ReborrowUpvar(a, _) => a,
ReferenceOutlivesReferent(_, a) => a,
ExprTypeIsNotInScope(_, a) => a,
BindingTypeIsNotValidAtDecl(a) => a,
CallRcvr(a) => a,
CallArg(a) => a,
CallReturn(a) => a,
AddrOf(a) => a,
AutoBorrow(a) => a,
}
}
}
impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
Subtype(ref a) => {
format!("Subtype({})", a.repr(tcx))
}
InfStackClosure(a) => {
format!("InfStackClosure({})", a.repr(tcx))
}
InvokeClosure(a) => {
format!("InvokeClosure({})", a.repr(tcx))
}
DerefPointer(a) => {
format!("DerefPointer({})", a.repr(tcx))
}
FreeVariable(a, b) => {
format!("FreeVariable({}, {})", a.repr(tcx), b)
}
IndexSlice(a) => {
format!("IndexSlice({})", a.repr(tcx))
}
RelateObjectBound(a) => {
format!("RelateObjectBound({})", a.repr(tcx))
}
RelateParamBound(a, b) => {
format!("RelateParamBound({},{})",
a.repr(tcx),
b.repr(tcx))
}
RelateRegionParamBound(a) => {
format!("RelateRegionParamBound({})",
a.repr(tcx))
}
RelateDefaultParamBound(a, b) => {
format!("RelateDefaultParamBound({},{})",
a.repr(tcx),
b.repr(tcx))
}
Reborrow(a) => format!("Reborrow({})", a.repr(tcx)),
ReborrowUpvar(a, b) => {
format!("ReborrowUpvar({},{:?})", a.repr(tcx), b)
}
ReferenceOutlivesReferent(_, a) => {
format!("ReferenceOutlivesReferent({})", a.repr(tcx))
}
ExprTypeIsNotInScope(a, b) => {
format!("ExprTypeIsNotInScope({}, {})",
a.repr(tcx),
b.repr(tcx))
}
BindingTypeIsNotValidAtDecl(a) => {
format!("BindingTypeIsNotValidAtDecl({})", a.repr(tcx))
}
CallRcvr(a) => format!("CallRcvr({})", a.repr(tcx)),
CallArg(a) => format!("CallArg({})", a.repr(tcx)),
CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
}
}
}
impl<'tcx> RegionVariableOrigin<'tcx> {
pub fn span(&self) -> Span {
match *self {
MiscVariable(a) => a,
PatternRegion(a) => a,
AddrOfRegion(a) => a,
AddrOfSlice(a) => a,
Autoref(a) => a,
2014-04-22 02:21:52 +03:00
Coercion(ref a) => a.span(),
EarlyBoundRegion(a, _) => a,
LateBoundRegion(a, _, _) => a,
BoundRegionInCoherence(_) => codemap::DUMMY_SP,
UpvarRegion(_, a) => a
}
}
}
impl<'tcx> Repr<'tcx> for RegionVariableOrigin<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
MiscVariable(a) => {
format!("MiscVariable({})", a.repr(tcx))
}
PatternRegion(a) => {
format!("PatternRegion({})", a.repr(tcx))
}
AddrOfRegion(a) => {
format!("AddrOfRegion({})", a.repr(tcx))
}
AddrOfSlice(a) => format!("AddrOfSlice({})", a.repr(tcx)),
Autoref(a) => format!("Autoref({})", a.repr(tcx)),
Coercion(ref a) => format!("Coercion({})", a.repr(tcx)),
EarlyBoundRegion(a, b) => {
format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx))
}
LateBoundRegion(a, b, c) => {
format!("LateBoundRegion({},{},{:?})", a.repr(tcx), b.repr(tcx), c)
}
BoundRegionInCoherence(a) => {
format!("bound_regionInCoherence({})", a.repr(tcx))
}
UpvarRegion(a, b) => {
format!("UpvarRegion({}, {})", a.repr(tcx), b.repr(tcx))
}
}
}
}