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

1646 lines
58 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 the Book for more information.
2012-11-29 16:41:39 -08:00
pub use self::LateBoundRegionConversionTime::*;
pub use self::RegionVariableOrigin::*;
pub use self::SubregionOrigin::*;
pub use self::ValuePairs::*;
pub use ty::IntVarValue;
pub use self::freshen::TypeFreshener;
pub use self::region_inference::{GenericKind, VerifyBound};
2015-08-16 06:32:28 -04:00
use middle::def_id::DefId;
2015-07-31 00:04:06 -07:00
use rustc_front::hir;
use middle::free_region::FreeRegionMap;
use middle::mem_categorization as mc;
use middle::mem_categorization::McResult;
2015-06-25 17:11:02 -07:00
use middle::region::CodeExtent;
use ty::subst;
use ty::subst::Substs;
use ty::subst::Subst;
use traits::{self, ProjectionMode};
use ty::adjustment;
use ty::{TyVid, IntVid, FloatVid};
use ty::{self, Ty, TyCtxt};
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use ty::fold::{TypeFolder, TypeFoldable};
use ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_data_structures::unify::{self, UnificationTable};
use std::cell::{RefCell, Ref};
use std::fmt;
use syntax::ast;
2013-01-30 09:56:33 -08:00
use syntax::codemap;
2015-06-27 22:04:15 -07:00
use syntax::codemap::{Span, DUMMY_SP};
2015-12-21 10:00:43 +13:00
use syntax::errors::DiagnosticBuilder;
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
2012-11-29 16:41:39 -08:00
use self::combine::CombineFields;
use self::region_inference::{RegionVarBindings, RegionSnapshot};
use self::error_reporting::ErrorReporting;
use self::unify_key::ToType;
pub mod bivariate;
pub mod combine;
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_key;
pub type Bound<T> = Option<T>;
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
2015-07-10 19:16:35 -07:00
pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
pub struct InferCtxt<'a, 'tcx: 'a> {
2016-02-29 23:36:51 +00:00
pub tcx: &'a TyCtxt<'tcx>,
2012-11-29 16:41:39 -08:00
pub tables: &'a RefCell<ty::Tables<'tcx>>,
// 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.
2015-07-12 21:43:13 -07:00
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>>,
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>>,
2012-11-29 16:41:39 -08:00
// For region variables.
region_vars: RegionVarBindings<'a, 'tcx>,
pub parameter_environment: ty::ParameterEnvironment<'a, 'tcx>,
// the set of predicates on which errors have been reported, to
// avoid reporting the same error twice.
pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>,
2015-06-26 12:23:41 -07:00
// This is a temporary field used for toggling on normalization in the inference context,
// as we move towards the approach described here:
// https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
// At a point sometime in the future normalization will be done by the typing context
// directly.
normalize: bool,
// Sadly, the behavior of projection varies a bit depending on the
// stage of compilation. The specifics are given in the
// documentation for `ProjectionMode`.
projection_mode: ProjectionMode,
err_count_on_creation: usize,
}
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
2015-01-28 08:34:18 -05:00
#[derive(Clone, Copy, Debug)]
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, hir::MatchSource),
// 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),
}
2015-03-24 20:55:02 -07:00
impl TypeOrigin {
fn as_str(&self) -> &'static str {
match self {
&TypeOrigin::Misc(_) |
&TypeOrigin::RelateSelfType(_) |
&TypeOrigin::RelateOutputImplTypes(_) |
&TypeOrigin::ExprAssignable(_) => "mismatched types",
&TypeOrigin::RelateTraitRefs(_) => "mismatched traits",
2015-03-24 20:55:02 -07:00
&TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
&TypeOrigin::MatchExpressionArm(_, _, source) => match source {
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
_ => "match arms have incompatible types",
},
&TypeOrigin::IfExpression(_) => "if and else have incompatible types",
&TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause",
&TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types",
&TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied",
2015-03-24 20:55:02 -07:00
}
}
}
impl fmt::Display for TypeOrigin {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> {
fmt::Display::fmt(self.as_str(), f)
}
}
/// See `error_reporting.rs` for more details
2015-01-28 08:34:18 -05:00
#[derive(Clone, Debug)]
pub enum ValuePairs<'tcx> {
2015-09-06 21:51:58 +03:00
Types(ExpectedFound<Ty<'tcx>>),
TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
PolyTraitRefs(ExpectedFound<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)]
pub struct TypeTrace<'tcx> {
origin: TypeOrigin,
values: ValuePairs<'tcx>,
}
/// The origin of a `r1 <= r2` constraint.
///
/// See `error_reporting.rs` for more details
2015-01-28 08:34:18 -05:00
#[derive(Clone, Debug)]
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),
// Data with type `Ty<'tcx>` was borrowed
DataBorrowed(Ty<'tcx>, Span),
// (&'a &'b T) where a >= b
ReferenceOutlivesReferent(Ty<'tcx>, Span),
// Type or region parameters must be in scope.
ParameterInScope(ParameterOrigin, 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),
// Operands must be in scope
Operand(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),
// Region constraint arriving from destructor safety
SafeDestructor(Span),
}
/// Places that type/region parameters can appear.
#[derive(Clone, Copy, Debug)]
pub enum ParameterOrigin {
Path, // foo::bar
MethodCall, // foo.bar() <-- parameters on impl providing bar()
OverloadedOperator, // a + b when overloaded
OverloadedDeref, // *a when overloaded
}
/// Times when we replace late-bound regions with variables:
2015-01-28 08:34:18 -05:00
#[derive(Clone, Copy, Debug)]
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
2015-01-28 08:34:18 -05:00
#[derive(Clone, Debug)]
pub enum RegionVariableOrigin {
// 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 as part of an autoref of a method receiver
Autoref(Span),
// Regions created as part of an automatic coercion
Coercion(Span),
// 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),
}
2015-03-30 09:38:44 -04:00
#[derive(Copy, Clone, Debug)]
2015-07-10 19:16:35 -07:00
pub enum FixupError {
UnresolvedIntTy(IntVid),
UnresolvedFloatTy(FloatVid),
UnresolvedTy(TyVid)
2012-11-29 16:41:39 -08:00
}
2015-07-10 19:16:35 -07:00
pub fn fixup_err_to_string(f: FixupError) -> String {
use self::FixupError::*;
2012-11-29 16:41:39 -08:00
match f {
2015-07-10 19:16:35 -07:00
UnresolvedIntTy(_) => {
"cannot determine the type of this integer; add a suffix to \
specify the type explicitly".to_string()
}
2015-07-10 19:16:35 -07:00
UnresolvedFloatTy(_) => {
"cannot determine the type of this number; add a suffix to specify \
the type explicitly".to_string()
}
2015-07-10 19:16:35 -07:00
UnresolvedTy(_) => "unconstrained type".to_string(),
2012-11-29 16:41:39 -08:00
}
}
2016-02-29 23:36:51 +00:00
pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>,
tables: &'a RefCell<ty::Tables<'tcx>>,
param_env: Option<ty::ParameterEnvironment<'a, 'tcx>>,
projection_mode: ProjectionMode)
-> InferCtxt<'a, 'tcx> {
2014-02-07 00:38:33 +02:00
InferCtxt {
tcx: tcx,
tables: tables,
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),
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
reported_trait_errors: RefCell::new(FnvHashSet()),
2015-06-26 12:23:41 -07:00
normalize: false,
projection_mode: projection_mode,
err_count_on_creation: tcx.sess.err_count()
}
}
2016-02-29 23:36:51 +00:00
pub fn normalizing_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>,
tables: &'a RefCell<ty::Tables<'tcx>>,
projection_mode: ProjectionMode)
2015-06-27 22:04:15 -07:00
-> InferCtxt<'a, 'tcx> {
let mut infcx = new_infer_ctxt(tcx, tables, None, projection_mode);
2015-06-27 22:04:15 -07:00
infcx.normalize = true;
infcx
}
pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> UnitResult<'tcx>
{
2015-06-18 20:25:05 +03:00
debug!("mk_subty({:?} <: {:?})", a, b);
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>)
-> UnitResult<'tcx> {
2015-06-18 20:25:05 +03:00
debug!("can_mk_subty({:?} <: {:?})", a, b);
cx.probe(|_| {
let trace = TypeTrace {
2015-11-25 12:41:09 +01:00
origin: TypeOrigin::Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, a, b))
};
cx.sub(true, trace, &a, &b).map(|_| ())
})
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>)
-> UnitResult<'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) {
2015-06-18 20:25:05 +03:00
debug!("mk_subr({:?} <: {:?})", a, b);
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>)
-> UnitResult<'tcx>
{
2015-06-18 20:25:05 +03:00
debug!("mk_eqty({:?} <: {:?})", a, b);
cx.eq_types(a_is_expected, origin, a, b)
2012-11-29 16:41:39 -08:00
}
pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
a: ty::TraitRef<'tcx>,
b: ty::TraitRef<'tcx>)
-> UnitResult<'tcx>
{
debug!("mk_eq_trait_refs({:?} = {:?})", a, b);
cx.eq_trait_refs(a_is_expected, origin, a, b)
}
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>)
-> UnitResult<'tcx>
{
debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b);
cx.sub_poly_trait_refs(a_is_expected, origin, a, b)
}
pub fn mk_eq_impl_headers<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
a: &ty::ImplHeader<'tcx>,
b: &ty::ImplHeader<'tcx>)
-> UnitResult<'tcx>
{
debug!("mk_eq_impl_header({:?} = {:?})", a, b);
match (a.trait_ref, b.trait_ref) {
(Some(a_ref), Some(b_ref)) => mk_eq_trait_refs(cx, a_is_expected, origin, a_ref, b_ref),
(None, None) => mk_eqty(cx, a_is_expected, origin, a.self_ty, b.self_ty),
_ => cx.tcx.sess.bug("mk_eq_impl_headers given mismatched impl kinds"),
}
}
fn expected_found<T>(a_is_expected: bool,
a: T,
b: T)
2015-09-06 21:51:58 +03:00
-> ExpectedFound<T>
{
if a_is_expected {
2015-09-06 21:51:58 +03:00
ExpectedFound {expected: a, found: b}
} else {
2015-09-06 21:51:58 +03:00
ExpectedFound {expected: b, found: a}
}
}
#[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
}
// NOTE: Callable from trans only!
2016-02-29 23:36:51 +00:00
pub fn normalize_associated_type<'tcx,T>(tcx: &TyCtxt<'tcx>, value: &T) -> T
where T : TypeFoldable<'tcx>
2015-06-27 22:04:15 -07:00
{
debug!("normalize_associated_type(t={:?})", value);
let value = tcx.erase_regions(value);
2015-06-27 22:04:15 -07:00
if !value.has_projection_types() {
return value;
}
let infcx = new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Any);
let mut selcx = traits::SelectionContext::new(&infcx);
2015-06-27 22:04:15 -07:00
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &value);
debug!("normalize_associated_type: result={:?} obligations={:?}",
result,
obligations);
let mut fulfill_cx = traits::FulfillmentContext::new();
2015-06-27 22:04:15 -07:00
for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result)
2015-06-27 22:04:15 -07:00
}
pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
infcx: &InferCtxt<'a,'tcx>,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> T
where T : TypeFoldable<'tcx>
2015-06-27 22:04:15 -07:00
{
match drain_fulfillment_cx(infcx, fulfill_cx, result) {
Ok(v) => v,
Err(errors) => {
infcx.tcx.sess.span_bug(
span,
&format!("Encountered errors `{:?}` fulfilling during trans",
errors));
}
}
}
/// Finishes processes any obligations that remain in the fulfillment
/// context, and then "freshens" and returns `result`. This is
/// primarily used during normalization and other cases where
/// processing the obligations in `fulfill_cx` may cause type
/// inference variables that appear in `result` to be unified, and
/// hence we need to process those obligations to get the complete
/// picture of the type.
pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> Result<T,Vec<traits::FulfillmentError<'tcx>>>
where T : TypeFoldable<'tcx>
2015-06-27 22:04:15 -07:00
{
debug!("drain_fulfillment_cx(result={:?})",
result);
2015-06-27 22:04:15 -07:00
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
match fulfill_cx.select_all_or_error(infcx) {
2015-06-27 22:04:15 -07:00
Ok(()) => { }
Err(errors) => {
return Err(errors);
}
}
let result = infcx.resolve_type_vars_if_possible(result);
Ok(infcx.tcx.erase_regions(&result))
2015-06-27 22:04:15 -07:00
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn projection_mode(&self) -> ProjectionMode {
self.projection_mode
}
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::TyInfer(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 ty::error::UnconstrainedNumeric::Neither;
use ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
match ty.sty {
ty::TyInfer(ty::IntVar(vid)) => {
if self.int_unification_table.borrow_mut().has_value(vid) {
Neither
} else {
UnconstrainedInt
}
},
ty::TyInfer(ty::FloatVar(vid)) => {
if self.float_unification_table.borrow_mut().has_value(vid) {
Neither
} else {
UnconstrainedFloat
}
},
_ => Neither,
}
}
/// Returns a type variable's default fallback if any exists. A default
/// must be attached to the variable when created, if it is created
/// without a default, this will return None.
///
2015-07-16 11:26:02 -07:00
/// This code does not apply to integral or floating point variables,
/// only to use declared defaults.
///
/// See `new_ty_var_with_default` to create a type variable with a default.
/// See `type_variable::Default` for details about what a default entails.
pub fn default(&self, ty: Ty<'tcx>) -> Option<type_variable::Default<'tcx>> {
match ty.sty {
ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid),
_ => None
}
}
pub fn unsolved_variables(&self) -> Vec<ty::Ty<'tcx>> {
let mut variables = Vec::new();
let unbound_ty_vars = self.type_variables
.borrow_mut()
.unsolved_variables()
.into_iter()
.map(|t| self.tcx.mk_var(t));
let unbound_int_vars = self.int_unification_table
.borrow_mut()
.unsolved_variables()
.into_iter()
.map(|v| self.tcx.mk_int_var(v));
let unbound_float_vars = self.float_unification_table
.borrow_mut()
.unsolved_variables()
.into_iter()
.map(|v| self.tcx.mk_float_var(v));
variables.extend(unbound_ty_vars);
variables.extend(unbound_int_vars);
variables.extend(unbound_float_vars);
return variables;
}
fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-> CombineFields<'a, 'tcx> {
CombineFields {infcx: self,
a_is_expected: a_is_expected,
trace: trace,
cause: None}
2012-11-29 16:41:39 -08:00
}
pub fn equate<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> RelateResult<'tcx, T>
where T: Relate<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).equate().relate(a, b)
}
pub fn sub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> RelateResult<'tcx, T>
where T: Relate<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).sub().relate(a, b)
2012-11-29 16:41:39 -08:00
}
pub fn lub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> RelateResult<'tcx, T>
where T: Relate<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).lub().relate(a, b)
}
pub fn glb<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> RelateResult<'tcx, T>
where T: Relate<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).glb().relate(a, b)
}
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, cause: &str, snapshot: CombinedSnapshot) {
debug!("rollback_to(cause={})", cause);
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 closure `f` returns `Ok(_)`
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(&CombinedSnapshot) -> Result<T, E>
2014-12-08 20:26:43 -05:00
{
debug!("commit_if_ok()");
let snapshot = self.start_snapshot();
let r = f(&snapshot);
debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok());
match r {
Ok(_) => { self.commit_from(snapshot); }
Err(_) => { self.rollback_to("commit_if_ok -- error", snapshot); }
}
r
2012-11-29 16:41:39 -08:00
}
/// Execute `f` and commit only the region bindings if successful.
/// The function f must be very careful not to leak any non-region
/// variables that get created.
pub fn commit_regions_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
F: FnOnce() -> Result<T, E>
{
debug!("commit_regions_if_ok()");
let CombinedSnapshot { type_snapshot,
int_snapshot,
float_snapshot,
region_vars_snapshot } = self.start_snapshot();
let r = self.commit_if_ok(|_| f());
debug!("commit_regions_if_ok: rolling back everything but regions");
// Roll back any non-region bindings - they should be resolved
// inside `f`, with, e.g. `resolve_type_vars_if_possible`.
self.type_variables
.borrow_mut()
.rollback_to(type_snapshot);
self.int_unification_table
.borrow_mut()
.rollback_to(int_snapshot);
self.float_unification_table
.borrow_mut()
.rollback_to(float_snapshot);
// Commit region vars that may escape through resolved types.
self.region_vars
.commit(region_vars_snapshot);
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("probe", 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>)
-> UnitResult<'tcx>
{
2015-06-18 20:25:05 +03:00
debug!("sub_types({:?} <: {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
self.sub(a_is_expected, trace, &a, &b).map(|_| ())
})
}
pub fn eq_types(&self,
a_is_expected: bool,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> UnitResult<'tcx>
{
self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
self.equate(a_is_expected, trace, &a, &b).map(|_| ())
})
}
pub fn eq_trait_refs(&self,
a_is_expected: bool,
origin: TypeOrigin,
a: ty::TraitRef<'tcx>,
b: ty::TraitRef<'tcx>)
-> UnitResult<'tcx>
{
debug!("eq_trait_refs({:?} <: {:?})",
2015-06-18 20:25:05 +03:00
a,
b);
self.commit_if_ok(|_| {
let trace = TypeTrace {
origin: origin,
values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
};
self.equate(a_is_expected, trace, &a, &b).map(|_| ())
})
}
pub fn sub_poly_trait_refs(&self,
a_is_expected: bool,
origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
-> UnitResult<'tcx>
{
2015-06-18 20:25:05 +03:00
debug!("sub_poly_trait_refs({:?} <: {:?})",
a,
b);
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, &a, &b).map(|_| ())
})
}
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>
{
/*! 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)
-> UnitResult<'tcx>
{
/*! See `higher_ranked::leak_check` */
match higher_ranked::leak_check(self, skol_map, snapshot) {
Ok(()) => Ok(()),
2015-07-10 15:40:04 -07:00
Err((br, r)) => Err(TypeError::RegionsInsufficientlyPolymorphic(br, r))
}
}
pub fn plug_leaks<T>(&self,
skol_map: SkolemizationMap,
snapshot: &CombinedSnapshot,
value: &T)
-> T
where T : TypeFoldable<'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>)
-> UnitResult<'tcx> {
self.commit_if_ok(|snapshot| {
let (ty::EquatePredicate(a, b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
2015-11-25 12:41:09 +01:00
let origin = TypeOrigin::EquatePredicate(span);
let () = mk_eqty(self, false, origin, a, b)?;
self.leak_check(&skol_map, snapshot)
})
}
pub fn region_outlives_predicate(&self,
span: Span,
predicate: &ty::PolyRegionOutlivesPredicate)
-> UnitResult<'tcx> {
self.commit_if_ok(|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, None)
2012-11-29 16:41:39 -08:00
}
pub fn next_ty_var(&self) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(false))
}
pub fn next_ty_var_with_default(&self,
default: Option<type_variable::Default<'tcx>>) -> Ty<'tcx> {
let ty_var_id = self.type_variables
.borrow_mut()
.new_var(false, default);
self.tcx.mk_var(ty_var_id)
}
pub fn next_diverging_ty_var(&self) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(true))
2012-11-29 16:41:39 -08:00
}
pub fn next_ty_vars(&self, n: usize) -> Vec<Ty<'tcx>> {
(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) -> ty::Region {
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()
}
// We have to take `&mut Substs` in order to provide the correct substitutions for defaults
// along the way, for this reason we don't return them.
pub fn type_vars_for_defs(&self,
span: Span,
space: subst::ParamSpace,
substs: &mut Substs<'tcx>,
defs: &[ty::TypeParameterDef<'tcx>]) {
for def in defs.iter() {
2015-07-16 11:26:02 -07:00
let default = def.default.map(|default| {
type_variable::Default {
2015-07-16 11:26:02 -07:00
ty: default.subst_spanned(self.tcx, substs, Some(span)),
origin_span: span,
2015-07-20 12:39:34 -07:00
def_id: def.default_def_id
}
});
let ty_var = self.next_ty_var_with_default(default);
substs.types.push(space, ty_var);
}
}
/// 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 = subst::VecPerParamSpace::empty();
let region_params =
generics.regions.map(
|d| self.next_region_var(EarlyBoundRegion(span, d.name)));
let mut substs = subst::Substs::new(type_params, region_params);
for space in subst::ParamSpace::all().iter() {
self.type_vars_for_defs(
span,
*space,
&mut substs,
generics.types.get_slice(*space));
}
return substs;
}
/// 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_params = Vec::new();
let region_param_defs = generics.regions.get_slice(subst::TypeSpace);
let regions = self.region_vars_for_defs(span, region_param_defs);
let mut substs = subst::Substs::new_trait(type_params, regions, self_ty);
let type_parameter_defs = generics.types.get_slice(subst::TypeSpace);
self.type_vars_for_defs(span, subst::TypeSpace, &mut substs, type_parameter_defs);
return substs;
}
pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {
self.region_vars.new_bound(debruijn)
}
/// Apply `adjustment` to the type of `expr`
pub fn adjust_expr_ty(&self,
2015-07-31 00:04:06 -07:00
expr: &hir::Expr,
2015-09-14 14:55:56 +03:00
adjustment: Option<&adjustment::AutoAdjustment<'tcx>>)
-> Ty<'tcx>
{
let raw_ty = self.expr_ty(expr);
let raw_ty = self.shallow_resolve(raw_ty);
let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty);
raw_ty.adjust(self.tcx,
expr.span,
expr.id,
adjustment,
|method_call| self.tables
.borrow()
.method_map
.get(&method_call)
.map(|method| resolve_ty(method.ty)))
}
pub fn errors_since_creation(&self) -> bool {
self.tcx.sess.err_count() - self.err_count_on_creation != 0
}
pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> {
match self.tables.borrow().node_types.get(&id) {
Some(&t) => t,
// FIXME
None if self.errors_since_creation() =>
2015-06-26 12:23:41 -07:00
self.tcx.types.err,
None => {
self.tcx.sess.bug(
&format!("no type for node {}: {} in fcx",
id, self.tcx.map.node_to_string(id)));
}
}
}
2015-07-31 00:04:06 -07:00
pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> {
match self.tables.borrow().node_types.get(&ex.id) {
Some(&t) => t,
None => {
self.tcx.sess.bug("no type for expr in fcx");
}
}
}
pub fn resolve_regions_and_report_errors(&self,
free_regions: &FreeRegionMap,
subject_node_id: ast::NodeId) {
let errors = self.region_vars.resolve_regions(free_regions, subject_node_id);
if !self.errors_since_creation() {
// As a heuristic, just skip reporting region errors
// altogether if other errors have been reported while
// this infcx was in use. This is totally hokey but
// otherwise we have a hard time separating legit region
// errors from silly ones.
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 {
2015-06-18 20:25:05 +03:00
self.resolve_type_vars_if_possible(&t).to_string()
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.join(", "))
}
pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String {
2015-06-18 20:25:05 +03:00
self.resolve_type_vars_if_possible(t).to_string()
}
pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
match typ.sty {
ty::TyInfer(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_mut()
.probe(v)
.map(|t| self.shallow_resolve(t))
.unwrap_or(typ)
}
ty::TyInfer(ty::IntVar(v)) => {
self.int_unification_table
.borrow_mut()
.probe(v)
.map(|v| v.to_type(self.tcx))
.unwrap_or(typ)
}
ty::TyInfer(ty::FloatVar(v)) => {
self.float_unification_table
.borrow_mut()
.probe(v)
.map(|v| v.to_type(self.tcx))
.unwrap_or(typ)
}
_ => {
typ
}
}
}
pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
where T: TypeFoldable<'tcx>
{
/*!
* 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.
*/
if !value.needs_infer() {
return value.clone(); // avoid duplicated subst-folding
}
let mut r = resolve::OpportunisticTypeResolver::new(self);
value.fold_with(&mut r)
}
pub fn resolve_type_and_region_vars_if_possible<T>(&self, value: &T) -> T
where T: TypeFoldable<'tcx>
{
let mut r = resolve::OpportunisticTypeAndRegionResolver::new(self);
value.fold_with(&mut r)
}
2015-06-25 17:11:02 -07:00
/// Resolves all type variables in `t` and then, if any were left
/// unresolved, substitutes an error type. This is used after the
/// main checking when doing a second pass before writeback. The
/// justification is that writeback will produce an error for
/// these unconstrained type variables.
fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult<Ty<'tcx>> {
let ty = self.resolve_type_vars_if_possible(t);
2015-07-23 21:08:29 -04:00
if ty.references_error() || ty.is_ty_var() {
debug!("resolve_type_vars_or_error: error from {:?}", ty);
Err(())
} else {
Ok(ty)
}
}
2015-07-10 19:16:35 -07:00
pub fn fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<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 TyError (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 TyError, 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,
2015-12-21 10:00:43 +13:00
err: Option<&TypeError<'tcx>>)
where M: FnOnce(Option<String>, String) -> String,
2014-12-08 20:26:43 -05:00
{
self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err)
}
2015-12-21 10:00:43 +13:00
pub fn type_error_struct_str<M>(&self,
sp: Span,
mk_msg: M,
actual_ty: String,
err: Option<&TypeError<'tcx>>)
2015-12-23 19:27:20 +13:00
-> DiagnosticBuilder<'tcx>
2015-12-21 10:00:43 +13:00
where M: FnOnce(Option<String>, String) -> String,
{
self.type_error_struct_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,
2015-12-21 10:00:43 +13:00
err: Option<&TypeError<'tcx>>)
where M: FnOnce(Option<String>, String) -> String,
{
self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err)
2015-12-23 19:27:20 +13:00
.emit();
2015-12-21 10:00:43 +13:00
}
pub fn type_error_struct_str_with_expected<M>(&self,
sp: Span,
mk_msg: M,
expected_ty: Option<Ty<'tcx>>,
actual_ty: String,
err: Option<&TypeError<'tcx>>)
2015-12-23 19:27:20 +13:00
-> DiagnosticBuilder<'tcx>
2015-12-21 10:00:43 +13:00
where M: FnOnce(Option<String>, String) -> String,
2014-12-08 20:26:43 -05:00
{
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));
if !resolved_expected.references_error() {
let error_str = err.map_or("".to_string(), |t_err| {
format!(" ({})", t_err)
});
2015-12-21 10:00:43 +13:00
let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}",
mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty),
error_str));
if let Some(err) = err {
2015-12-21 10:00:43 +13:00
self.tcx.note_and_explain_type_err(&mut db, err, sp);
}
2015-12-23 19:27:20 +13:00
db
2015-12-21 10:00:43 +13:00
} else {
2015-12-23 19:27:20 +13:00
self.tcx.sess.diagnostic().struct_dummy()
}
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>,
2015-12-21 10:00:43 +13:00
err: Option<&TypeError<'tcx>>)
where M: FnOnce(String) -> String,
{
2015-12-23 19:27:20 +13:00
self.type_error_struct(sp, mk_msg, actual_ty, err).emit();
2015-12-21 10:00:43 +13:00
}
pub fn type_error_struct<M>(&self,
sp: Span,
mk_msg: M,
actual_ty: Ty<'tcx>,
err: Option<&TypeError<'tcx>>)
2015-12-23 19:27:20 +13:00
-> DiagnosticBuilder<'tcx>
2015-12-21 10:00:43 +13:00
where M: FnOnce(String) -> String,
2014-12-08 20:26:43 -05:00
{
let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
// Don't report an error if actual type is TyError.
if actual_ty.references_error() {
2015-12-23 19:27:20 +13:00
return self.tcx.sess.diagnostic().struct_dummy();
}
2015-12-21 10:00:43 +13:00
self.type_error_struct_str(sp,
2014-12-08 20:26:43 -05:00
move |_e, a| { mk_msg(a) },
2015-12-21 10:00:43 +13:00
self.ty_to_string(actual_ty), err)
}
2014-02-07 00:38:33 +02:00
pub fn report_mismatched_types(&self,
origin: TypeOrigin,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
err: TypeError<'tcx>) {
let trace = TypeTrace {
origin: origin,
2015-09-06 21:51:58 +03:00
values: Types(ExpectedFound {
expected: expected,
found: actual
})
2012-11-29 16:41:39 -08:00
};
self.report_and_explain_type_error(trace, &err).emit();
2012-11-29 16:41:39 -08:00
}
pub fn report_conflicting_default_types(&self,
2015-07-12 21:43:13 -07:00
span: Span,
expected: type_variable::Default<'tcx>,
actual: type_variable::Default<'tcx>) {
let trace = TypeTrace {
2015-11-25 12:41:09 +01:00
origin: TypeOrigin::Misc(span),
2015-09-06 21:51:58 +03:00
values: Types(ExpectedFound {
expected: expected.ty,
found: actual.ty
})
};
self.report_and_explain_type_error(
trace,
2015-09-06 21:51:58 +03:00
&TypeError::TyParamDefaultMismatch(ExpectedFound {
2015-07-07 16:06:35 -07:00
expected: expected,
found: actual
}))
.emit();
}
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>
{
2015-09-06 21:51:58 +03:00
self.tcx.replace_late_bound_regions(
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,
bound: VerifyBound) {
2015-06-18 20:25:05 +03:00
debug!("verify_generic_bound({:?}, {:?} <: {:?})",
kind,
a,
bound);
self.region_vars.verify_generic_bound(origin, kind, a, bound);
}
pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx>
2015-06-18 20:25:05 +03:00
where T: Relate<'b,'tcx> + fmt::Debug
{
2015-06-18 20:25:05 +03:00
debug!("can_equate({:?}, {:?})", a, b);
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;
2015-11-25 12:41:09 +01:00
let trace = TypeTrace {
origin: TypeOrigin::Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, e, e))
};
self.equate(true, trace, a, b)
}).map(|_| ())
}
pub fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
let ty = self.node_type(id);
self.resolve_type_vars_or_error(&ty)
}
2015-07-31 00:04:06 -07:00
pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id));
self.resolve_type_vars_or_error(&ty)
}
pub fn tables_are_tcx_tables(&self) -> bool {
let tables: &RefCell<ty::Tables> = &self.tables;
let tcx_tables: &RefCell<ty::Tables> = &self.tcx.tables;
tables as *const _ == tcx_tables as *const _
}
pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
let ty = self.resolve_type_vars_if_possible(&ty);
if ty.needs_infer() ||
(ty.has_closure_types() && !self.tables_are_tcx_tables()) {
// this can get called from typeck (by euv), and moves_by_default
// rightly refuses to work with inference variables, but
// moves_by_default has a cache, which we want to use in other
// cases.
!traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundCopy, span)
} else {
ty.moves_by_default(&self.parameter_environment, span)
}
}
pub fn node_method_ty(&self, method_call: ty::MethodCall)
-> Option<Ty<'tcx>> {
self.tables
.borrow()
.method_map
.get(&method_call)
.map(|method| method.ty)
.map(|ty| self.resolve_type_vars_if_possible(&ty))
}
pub fn node_method_id(&self, method_call: ty::MethodCall)
2015-08-16 06:32:28 -04:00
-> Option<DefId> {
self.tables
.borrow()
.method_map
.get(&method_call)
.map(|method| method.def_id)
}
2015-09-14 14:55:56 +03:00
pub fn adjustments(&self) -> Ref<NodeMap<adjustment::AutoAdjustment<'tcx>>> {
fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
2015-09-14 14:55:56 +03:00
-> &'a NodeMap<adjustment::AutoAdjustment<'tcx>> {
&tables.adjustments
}
Ref::map(self.tables.borrow(), project_adjustments)
}
pub fn is_method_call(&self, id: ast::NodeId) -> bool {
self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id))
}
pub fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
self.tcx.region_maps.temporary_scope(rvalue_id)
}
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
}
pub fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
&self.parameter_environment
}
pub fn closure_kind(&self,
2015-08-16 06:32:28 -04:00
def_id: DefId)
-> Option<ty::ClosureKind>
{
if def_id.is_local() {
self.tables.borrow().closure_kinds.get(&def_id).cloned()
} else {
// During typeck, ALL closures are local. But afterwards,
// during trans, we see closure ids from other traits.
// That may require loading the closure data out of the
// cstore.
Some(ty::Tables::closure_kind(&self.tables, self.tcx, def_id))
}
}
pub fn closure_type(&self,
2015-08-16 06:32:28 -04:00
def_id: DefId,
substs: &ty::ClosureSubsts<'tcx>)
-> ty::ClosureTy<'tcx>
{
let closure_ty =
ty::Tables::closure_type(self.tables,
self.tcx,
def_id,
substs);
if self.normalize {
normalize_associated_type(&self.tcx, &closure_ty)
} else {
closure_ty
}
}
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 types(origin: TypeOrigin,
a_is_expected: bool,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> TypeTrace<'tcx> {
TypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
}
}
2016-02-29 23:36:51 +00:00
pub fn dummy(tcx: &TyCtxt<'tcx>) -> TypeTrace<'tcx> {
TypeTrace {
2015-11-25 12:41:09 +01:00
origin: TypeOrigin::Misc(codemap::DUMMY_SP),
2015-09-06 21:51:58 +03:00
values: Types(ExpectedFound {
expected: tcx.types.err,
found: tcx.types.err,
})
}
}
}
impl<'tcx> fmt::Debug for TypeTrace<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TypeTrace({:?})", self.origin)
}
}
impl TypeOrigin {
pub fn span(&self) -> Span {
match *self {
2015-11-25 12:41:09 +01:00
TypeOrigin::MethodCompatCheck(span) => span,
TypeOrigin::ExprAssignable(span) => span,
TypeOrigin::Misc(span) => span,
TypeOrigin::RelateTraitRefs(span) => span,
TypeOrigin::RelateSelfType(span) => span,
TypeOrigin::RelateOutputImplTypes(span) => span,
TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span,
TypeOrigin::IfExpression(span) => span,
TypeOrigin::IfExpressionWithNoElse(span) => span,
TypeOrigin::RangeExpression(span) => span,
TypeOrigin::EquatePredicate(span) => span,
}
}
}
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,
DataBorrowed(_, a) => a,
ReferenceOutlivesReferent(_, a) => a,
ParameterInScope(_, a) => a,
ExprTypeIsNotInScope(_, a) => a,
BindingTypeIsNotValidAtDecl(a) => a,
CallRcvr(a) => a,
CallArg(a) => a,
CallReturn(a) => a,
Operand(a) => a,
AddrOf(a) => a,
AutoBorrow(a) => a,
SafeDestructor(a) => a,
}
}
}
impl RegionVariableOrigin {
pub fn span(&self) -> Span {
match *self {
MiscVariable(a) => a,
PatternRegion(a) => a,
AddrOfRegion(a) => a,
Autoref(a) => a,
Coercion(a) => a,
EarlyBoundRegion(a, _) => a,
LateBoundRegion(a, _, _) => a,
BoundRegionInCoherence(_) => codemap::DUMMY_SP,
UpvarRegion(_, a) => a
}
}
}