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.
|
|
|
|
|
2014-07-22 07:46:36 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// # Type combining
|
2012-08-13 15:06:13 -07:00
|
|
|
//
|
2014-07-22 07:46:36 -04:00
|
|
|
// There are four type combiners: equate, sub, lub, and glb. Each
|
|
|
|
// implements the trait `Combine` and contains methods for combining
|
|
|
|
// two instances of various things and yielding a new instance. These
|
|
|
|
// combiner methods always yield a `Result<T>`. There is a lot of
|
|
|
|
// common code for these operations, implemented as default methods on
|
|
|
|
// the `Combine` trait.
|
2012-08-13 15:06:13 -07:00
|
|
|
//
|
2014-07-22 07:46:36 -04:00
|
|
|
// Each operation may have side-effects on the inference context,
|
|
|
|
// though these can be unrolled using snapshots. On success, the
|
|
|
|
// LUB/GLB operations return the appropriate bound. The Eq and Sub
|
|
|
|
// operations generally return the first operand.
|
2012-08-13 15:06:13 -07:00
|
|
|
//
|
2014-07-22 07:46:36 -04:00
|
|
|
// ## Contravariance
|
2012-08-13 15:06:13 -07:00
|
|
|
//
|
|
|
|
// When you are relating two things which have a contravariant
|
|
|
|
// relationship, you should use `contratys()` or `contraregions()`,
|
|
|
|
// rather than inversing the order of arguments! This is necessary
|
|
|
|
// because the order of arguments is not relevant for LUB and GLB. It
|
|
|
|
// is also useful to track which value is the "expected" value in
|
2014-07-22 07:46:36 -04:00
|
|
|
// terms of error reporting.
|
2012-08-13 15:06:13 -07:00
|
|
|
|
2014-11-25 16:59:02 -05:00
|
|
|
use super::equate::Equate;
|
|
|
|
use super::glb::Glb;
|
|
|
|
use super::lub::Lub;
|
|
|
|
use super::sub::Sub;
|
|
|
|
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
|
|
|
|
use super::{InferCtxt, cres};
|
|
|
|
use super::{MiscVariable, TypeTrace};
|
|
|
|
use super::type_variable::{RelationDir, EqTo, SubtypeOf, SupertypeOf};
|
2013-05-17 15:28:44 -07:00
|
|
|
|
2014-05-13 11:35:42 -04:00
|
|
|
use middle::subst;
|
2014-09-12 11:42:58 -04:00
|
|
|
use middle::subst::{ErasedRegions, NonerasedRegions, Substs};
|
2013-01-31 17:12:29 -08:00
|
|
|
use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
|
2014-05-13 11:35:42 -04:00
|
|
|
use middle::ty::{IntType, UintType};
|
2013-05-10 15:57:27 -04:00
|
|
|
use middle::ty::{BuiltinBounds};
|
2015-01-03 22:42:21 -05:00
|
|
|
use middle::ty::{self, Ty};
|
2014-09-09 17:45:51 -04:00
|
|
|
use middle::ty_fold;
|
|
|
|
use middle::ty_fold::{TypeFoldable};
|
2014-01-06 19:05:53 -08:00
|
|
|
use util::ppaux::Repr;
|
2012-12-13 13:05:22 -08:00
|
|
|
|
2014-12-17 14:16:28 -05:00
|
|
|
use std::rc::Rc;
|
2014-12-09 10:36:46 -05:00
|
|
|
use syntax::ast::{Onceness, Unsafety};
|
2012-12-23 17:41:37 -05:00
|
|
|
use syntax::ast;
|
2014-04-02 01:19:41 -07:00
|
|
|
use syntax::abi;
|
2014-09-09 17:45:51 -04:00
|
|
|
use syntax::codemap::Span;
|
2012-08-13 15:06:13 -07:00
|
|
|
|
2014-12-18 15:27:41 -05:00
|
|
|
pub trait Combine<'tcx> : Sized {
|
2014-04-22 15:56:37 +03:00
|
|
|
fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx>;
|
2014-11-15 17:09:51 -05:00
|
|
|
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx }
|
2014-05-22 16:57:53 -07:00
|
|
|
fn tag(&self) -> String;
|
2013-02-22 01:41:37 -05:00
|
|
|
fn a_is_expected(&self) -> bool;
|
2014-09-29 22:11:30 +03:00
|
|
|
fn trace(&self) -> TypeTrace<'tcx>;
|
2012-08-13 15:06:13 -07:00
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
fn equate<'a>(&'a self) -> Equate<'a, 'tcx>;
|
|
|
|
fn sub<'a>(&'a self) -> Sub<'a, 'tcx>;
|
|
|
|
fn lub<'a>(&'a self) -> Lub<'a, 'tcx>;
|
|
|
|
fn glb<'a>(&'a self) -> Glb<'a, 'tcx>;
|
2012-08-13 15:06:13 -07:00
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>>;
|
|
|
|
fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>;
|
|
|
|
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>;
|
2013-08-21 03:10:16 -04:00
|
|
|
|
2014-05-31 18:53:13 -04:00
|
|
|
fn tps(&self,
|
2014-06-25 18:18:13 -07:00
|
|
|
_: subst::ParamSpace,
|
2014-09-29 22:11:30 +03:00
|
|
|
as_: &[Ty<'tcx>],
|
|
|
|
bs: &[Ty<'tcx>])
|
|
|
|
-> cres<'tcx, Vec<Ty<'tcx>>> {
|
2014-06-25 18:18:13 -07:00
|
|
|
// FIXME -- In general, we treat variance a bit wrong
|
|
|
|
// here. For historical reasons, we treat tps and Self
|
|
|
|
// as invariant. This is overly conservative.
|
2014-05-31 18:53:13 -04:00
|
|
|
|
|
|
|
if as_.len() != bs.len() {
|
|
|
|
return Err(ty::terr_ty_param_size(expected_found(self,
|
|
|
|
as_.len(),
|
|
|
|
bs.len())));
|
2013-08-21 03:10:16 -04:00
|
|
|
}
|
|
|
|
|
2014-10-14 23:05:01 -07:00
|
|
|
try!(as_.iter().zip(bs.iter())
|
|
|
|
.map(|(a, b)| self.equate().tys(*a, *b))
|
2014-09-13 21:09:25 +03:00
|
|
|
.collect::<cres<Vec<Ty>>>());
|
2014-10-14 23:05:01 -07:00
|
|
|
Ok(as_.to_vec())
|
2013-08-21 03:10:16 -04:00
|
|
|
}
|
|
|
|
|
2013-10-29 06:08:34 -04:00
|
|
|
fn substs(&self,
|
|
|
|
item_def_id: ast::DefId,
|
2014-09-29 22:11:30 +03:00
|
|
|
a_subst: &subst::Substs<'tcx>,
|
|
|
|
b_subst: &subst::Substs<'tcx>)
|
|
|
|
-> cres<'tcx, subst::Substs<'tcx>>
|
2014-05-13 11:35:42 -04:00
|
|
|
{
|
2014-05-06 16:37:32 -07:00
|
|
|
let variances = if self.infcx().tcx.variance_computed.get() {
|
|
|
|
Some(ty::item_variances(self.infcx().tcx, item_def_id))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2014-10-18 10:46:57 -07:00
|
|
|
self.substs_variances(variances.as_ref().map(|v| &**v), a_subst, b_subst)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn substs_variances(&self,
|
|
|
|
variances: Option<&ty::ItemVariances>,
|
2014-09-29 22:11:30 +03:00
|
|
|
a_subst: &subst::Substs<'tcx>,
|
|
|
|
b_subst: &subst::Substs<'tcx>)
|
|
|
|
-> cres<'tcx, subst::Substs<'tcx>>
|
2014-10-18 10:46:57 -07:00
|
|
|
{
|
2014-05-31 18:53:13 -04:00
|
|
|
let mut substs = subst::Substs::empty();
|
|
|
|
|
|
|
|
for &space in subst::ParamSpace::all().iter() {
|
2014-07-04 16:39:28 +02:00
|
|
|
let a_tps = a_subst.types.get_slice(space);
|
|
|
|
let b_tps = b_subst.types.get_slice(space);
|
2014-07-22 07:15:43 -04:00
|
|
|
let tps = try!(self.tps(space, a_tps, b_tps));
|
2014-09-12 11:42:58 -04:00
|
|
|
substs.types.replace(space, tps);
|
|
|
|
}
|
2014-07-04 16:39:28 +02:00
|
|
|
|
2014-09-12 11:42:58 -04:00
|
|
|
match (&a_subst.regions, &b_subst.regions) {
|
|
|
|
(&ErasedRegions, _) | (_, &ErasedRegions) => {
|
|
|
|
substs.regions = ErasedRegions;
|
|
|
|
}
|
|
|
|
|
|
|
|
(&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => {
|
|
|
|
for &space in subst::ParamSpace::all().iter() {
|
|
|
|
let a_regions = a.get_slice(space);
|
|
|
|
let b_regions = b.get_slice(space);
|
|
|
|
|
|
|
|
let mut invariance = Vec::new();
|
|
|
|
let r_variances = match variances {
|
2014-10-18 10:46:57 -07:00
|
|
|
Some(variances) => {
|
2014-09-12 11:42:58 -04:00
|
|
|
variances.regions.get_slice(space)
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
for _ in a_regions.iter() {
|
|
|
|
invariance.push(ty::Invariant);
|
|
|
|
}
|
2014-12-10 19:46:38 -08:00
|
|
|
invariance[]
|
2014-09-12 11:42:58 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let regions = try!(relate_region_params(self,
|
|
|
|
r_variances,
|
|
|
|
a_regions,
|
|
|
|
b_regions));
|
|
|
|
substs.mut_regions().replace(space, regions);
|
2014-05-06 16:37:32 -07:00
|
|
|
}
|
2014-09-12 11:42:58 -04:00
|
|
|
}
|
2014-05-31 18:53:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return Ok(substs);
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C,
|
|
|
|
variances: &[ty::Variance],
|
|
|
|
a_rs: &[ty::Region],
|
|
|
|
b_rs: &[ty::Region])
|
2014-09-29 22:11:30 +03:00
|
|
|
-> cres<'tcx, Vec<ty::Region>> {
|
2013-10-29 06:08:34 -04:00
|
|
|
let tcx = this.infcx().tcx;
|
2014-05-31 18:53:13 -04:00
|
|
|
let num_region_params = variances.len();
|
|
|
|
|
|
|
|
debug!("relate_region_params(\
|
|
|
|
a_rs={}, \
|
|
|
|
b_rs={},
|
|
|
|
variances={})",
|
|
|
|
a_rs.repr(tcx),
|
|
|
|
b_rs.repr(tcx),
|
|
|
|
variances.repr(tcx));
|
|
|
|
|
|
|
|
assert_eq!(num_region_params, a_rs.len());
|
|
|
|
assert_eq!(num_region_params, b_rs.len());
|
|
|
|
let mut rs = vec!();
|
|
|
|
for i in range(0, num_region_params) {
|
2014-07-04 16:39:28 +02:00
|
|
|
let a_r = a_rs[i];
|
|
|
|
let b_r = b_rs[i];
|
|
|
|
let variance = variances[i];
|
2014-05-31 18:53:13 -04:00
|
|
|
let r = match variance {
|
2014-07-22 07:46:36 -04:00
|
|
|
ty::Invariant => this.equate().regions(a_r, b_r),
|
2014-05-31 18:53:13 -04:00
|
|
|
ty::Covariant => this.regions(a_r, b_r),
|
|
|
|
ty::Contravariant => this.contraregions(a_r, b_r),
|
|
|
|
ty::Bivariant => Ok(a_r),
|
|
|
|
};
|
2014-07-22 07:15:43 -04:00
|
|
|
rs.push(try!(r));
|
2013-08-21 03:10:16 -04:00
|
|
|
}
|
2014-05-31 18:53:13 -04:00
|
|
|
Ok(rs)
|
2013-08-21 03:10:16 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn bare_fn_tys(&self, a: &ty::BareFnTy<'tcx>,
|
|
|
|
b: &ty::BareFnTy<'tcx>) -> cres<'tcx, ty::BareFnTy<'tcx>> {
|
2014-12-09 10:36:46 -05:00
|
|
|
let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety));
|
2014-07-22 07:15:43 -04:00
|
|
|
let abi = try!(self.abi(a.abi, b.abi));
|
2014-12-12 11:28:35 -05:00
|
|
|
let sig = try!(self.binders(&a.sig, &b.sig));
|
2014-12-09 10:36:46 -05:00
|
|
|
Ok(ty::BareFnTy {unsafety: unsafety,
|
|
|
|
abi: abi,
|
|
|
|
sig: sig})
|
2013-08-21 03:10:16 -04:00
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn closure_tys(&self, a: &ty::ClosureTy<'tcx>,
|
|
|
|
b: &ty::ClosureTy<'tcx>) -> cres<'tcx, ty::ClosureTy<'tcx>> {
|
2013-08-21 03:10:16 -04:00
|
|
|
|
2014-04-11 18:03:10 +03:00
|
|
|
let store = match (a.store, b.store) {
|
|
|
|
(ty::RegionTraitStore(a_r, a_m),
|
|
|
|
ty::RegionTraitStore(b_r, b_m)) if a_m == b_m => {
|
2014-07-22 07:15:43 -04:00
|
|
|
let r = try!(self.contraregions(a_r, b_r));
|
2014-04-11 18:03:10 +03:00
|
|
|
ty::RegionTraitStore(r, a_m)
|
|
|
|
}
|
|
|
|
|
|
|
|
_ if a.store == b.store => {
|
|
|
|
a.store
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => {
|
|
|
|
return Err(ty::terr_sigil_mismatch(expected_found(self, a.store, b.store)))
|
|
|
|
}
|
|
|
|
};
|
2014-12-09 10:36:46 -05:00
|
|
|
let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety));
|
2014-07-22 07:15:43 -04:00
|
|
|
let onceness = try!(self.oncenesses(a.onceness, b.onceness));
|
2014-12-26 04:36:04 -05:00
|
|
|
let bounds = try!(self.existential_bounds(&a.bounds, &b.bounds));
|
2014-12-12 11:28:35 -05:00
|
|
|
let sig = try!(self.binders(&a.sig, &b.sig));
|
2014-07-22 07:15:43 -04:00
|
|
|
let abi = try!(self.abi(a.abi, b.abi));
|
2014-04-11 18:03:10 +03:00
|
|
|
Ok(ty::ClosureTy {
|
2014-12-09 10:36:46 -05:00
|
|
|
unsafety: unsafety,
|
2014-04-11 18:03:10 +03:00
|
|
|
onceness: onceness,
|
|
|
|
store: store,
|
|
|
|
bounds: bounds,
|
2014-05-28 22:26:56 -07:00
|
|
|
sig: sig,
|
|
|
|
abi: abi,
|
2014-04-11 18:03:10 +03:00
|
|
|
})
|
2013-08-21 03:10:16 -04:00
|
|
|
}
|
|
|
|
|
2014-12-12 11:28:35 -05:00
|
|
|
fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> cres<'tcx, ty::FnSig<'tcx>> {
|
|
|
|
if a.variadic != b.variadic {
|
|
|
|
return Err(ty::terr_variadic_mismatch(expected_found(self, a.variadic, b.variadic)));
|
|
|
|
}
|
|
|
|
|
|
|
|
let inputs = try!(argvecs(self,
|
|
|
|
a.inputs.as_slice(),
|
|
|
|
b.inputs.as_slice()));
|
|
|
|
|
|
|
|
let output = try!(match (a.output, b.output) {
|
|
|
|
(ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
|
|
|
|
Ok(ty::FnConverging(try!(self.tys(a_ty, b_ty)))),
|
|
|
|
(ty::FnDiverging, ty::FnDiverging) =>
|
|
|
|
Ok(ty::FnDiverging),
|
|
|
|
(a, b) =>
|
|
|
|
Err(ty::terr_convergence_mismatch(
|
|
|
|
expected_found(self, a != ty::FnDiverging, b != ty::FnDiverging))),
|
|
|
|
});
|
|
|
|
|
|
|
|
return Ok(ty::FnSig {inputs: inputs,
|
|
|
|
output: output,
|
|
|
|
variadic: a.variadic});
|
|
|
|
|
|
|
|
|
|
|
|
fn argvecs<'tcx, C: Combine<'tcx>>(combiner: &C,
|
|
|
|
a_args: &[Ty<'tcx>],
|
|
|
|
b_args: &[Ty<'tcx>])
|
|
|
|
-> cres<'tcx, Vec<Ty<'tcx>>>
|
|
|
|
{
|
|
|
|
if a_args.len() == b_args.len() {
|
|
|
|
a_args.iter().zip(b_args.iter())
|
|
|
|
.map(|(a, b)| combiner.args(*a, *b)).collect()
|
|
|
|
} else {
|
|
|
|
Err(ty::terr_arg_count)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-21 03:10:16 -04:00
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
|
2013-11-21 15:42:55 -08:00
|
|
|
self.contratys(a, b).and_then(|t| Ok(t))
|
2013-08-21 03:10:16 -04:00
|
|
|
}
|
|
|
|
|
2014-12-09 10:36:46 -05:00
|
|
|
fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety>;
|
2013-08-21 03:10:16 -04:00
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn abi(&self, a: abi::Abi, b: abi::Abi) -> cres<'tcx, abi::Abi> {
|
2013-08-21 03:10:16 -04:00
|
|
|
if a == b {
|
|
|
|
Ok(a)
|
|
|
|
} else {
|
|
|
|
Err(ty::terr_abi_mismatch(expected_found(self, a, b)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<'tcx, Onceness>;
|
2014-08-27 21:46:52 -04:00
|
|
|
|
2014-12-26 04:36:04 -05:00
|
|
|
fn projection_tys(&self,
|
|
|
|
a: &ty::ProjectionTy<'tcx>,
|
|
|
|
b: &ty::ProjectionTy<'tcx>)
|
|
|
|
-> cres<'tcx, ty::ProjectionTy<'tcx>>
|
|
|
|
{
|
|
|
|
if a.item_name != b.item_name {
|
|
|
|
Err(ty::terr_projection_name_mismatched(
|
|
|
|
expected_found(self, a.item_name, b.item_name)))
|
|
|
|
} else {
|
|
|
|
let trait_ref = try!(self.trait_refs(&*a.trait_ref, &*b.trait_ref));
|
|
|
|
Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn projection_predicates(&self,
|
|
|
|
a: &ty::ProjectionPredicate<'tcx>,
|
|
|
|
b: &ty::ProjectionPredicate<'tcx>)
|
|
|
|
-> cres<'tcx, ty::ProjectionPredicate<'tcx>>
|
|
|
|
{
|
|
|
|
let projection_ty = try!(self.projection_tys(&a.projection_ty, &b.projection_ty));
|
|
|
|
let ty = try!(self.tys(a.ty, b.ty));
|
|
|
|
Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty })
|
|
|
|
}
|
|
|
|
|
|
|
|
fn projection_bounds(&self,
|
|
|
|
a: &Vec<ty::PolyProjectionPredicate<'tcx>>,
|
|
|
|
b: &Vec<ty::PolyProjectionPredicate<'tcx>>)
|
|
|
|
-> cres<'tcx, Vec<ty::PolyProjectionPredicate<'tcx>>>
|
|
|
|
{
|
|
|
|
// To be compatible, `a` and `b` must be for precisely the
|
|
|
|
// same set of traits and item names. We always require that
|
|
|
|
// projection bounds lists are sorted by trait-def-id and item-name,
|
|
|
|
// so we can just iterate through the lists pairwise, so long as they are the
|
|
|
|
// same length.
|
|
|
|
if a.len() != b.len() {
|
|
|
|
Err(ty::terr_projection_bounds_length(expected_found(self, a.len(), b.len())))
|
|
|
|
} else {
|
|
|
|
a.iter()
|
|
|
|
.zip(b.iter())
|
|
|
|
.map(|(a, b)| self.binders(a, b))
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-27 21:46:52 -04:00
|
|
|
fn existential_bounds(&self,
|
2014-12-26 04:36:04 -05:00
|
|
|
a: &ty::ExistentialBounds<'tcx>,
|
|
|
|
b: &ty::ExistentialBounds<'tcx>)
|
|
|
|
-> cres<'tcx, ty::ExistentialBounds<'tcx>>
|
2014-08-27 21:46:52 -04:00
|
|
|
{
|
|
|
|
let r = try!(self.contraregions(a.region_bound, b.region_bound));
|
|
|
|
let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds));
|
2014-12-26 04:36:04 -05:00
|
|
|
let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds));
|
2014-08-27 21:46:52 -04:00
|
|
|
Ok(ty::ExistentialBounds { region_bound: r,
|
2014-12-26 04:36:04 -05:00
|
|
|
builtin_bounds: nb,
|
|
|
|
projection_bounds: pb })
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn builtin_bounds(&self,
|
|
|
|
a: ty::BuiltinBounds,
|
|
|
|
b: ty::BuiltinBounds)
|
2014-09-29 22:11:30 +03:00
|
|
|
-> cres<'tcx, ty::BuiltinBounds>;
|
2014-08-27 21:46:52 -04:00
|
|
|
|
2013-03-08 21:16:09 -08:00
|
|
|
fn contraregions(&self, a: ty::Region, b: ty::Region)
|
2014-09-29 22:11:30 +03:00
|
|
|
-> cres<'tcx, ty::Region>;
|
2014-08-27 21:46:52 -04:00
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>;
|
2013-08-21 03:10:16 -04:00
|
|
|
|
2013-03-08 21:16:09 -08:00
|
|
|
fn trait_stores(&self,
|
|
|
|
vk: ty::terr_vstore_kind,
|
|
|
|
a: ty::TraitStore,
|
|
|
|
b: ty::TraitStore)
|
2014-09-29 22:11:30 +03:00
|
|
|
-> cres<'tcx, ty::TraitStore> {
|
2014-06-20 06:35:06 -04:00
|
|
|
debug!("{}.trait_stores(a={}, b={})", self.tag(), a, b);
|
2013-08-21 03:10:16 -04:00
|
|
|
|
|
|
|
match (a, b) {
|
2014-04-11 09:01:31 +03:00
|
|
|
(ty::RegionTraitStore(a_r, a_m),
|
|
|
|
ty::RegionTraitStore(b_r, b_m)) if a_m == b_m => {
|
2013-11-21 15:42:55 -08:00
|
|
|
self.contraregions(a_r, b_r).and_then(|r| {
|
2014-04-11 09:01:31 +03:00
|
|
|
Ok(ty::RegionTraitStore(r, a_m))
|
2013-11-21 15:42:55 -08:00
|
|
|
})
|
2013-08-21 03:10:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
_ if a == b => {
|
|
|
|
Ok(a)
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => {
|
|
|
|
Err(ty::terr_trait_stores_differ(vk, expected_found(self, a, b)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trait_refs(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
a: &ty::TraitRef<'tcx>,
|
|
|
|
b: &ty::TraitRef<'tcx>)
|
2014-12-11 13:37:37 -05:00
|
|
|
-> cres<'tcx, ty::TraitRef<'tcx>>
|
|
|
|
{
|
|
|
|
// Different traits cannot be related
|
|
|
|
if a.def_id != b.def_id {
|
|
|
|
Err(ty::terr_traits(expected_found(self, a.def_id, b.def_id)))
|
|
|
|
} else {
|
2014-12-26 22:33:56 +11:00
|
|
|
let substs = try!(self.substs(a.def_id, a.substs, b.substs));
|
|
|
|
Ok(ty::TraitRef { def_id: a.def_id, substs: self.tcx().mk_substs(substs) })
|
2014-12-11 13:37:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 11:28:35 -05:00
|
|
|
fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
|
|
|
|
where T : Combineable<'tcx>;
|
2014-11-15 17:09:51 -05:00
|
|
|
// this must be overridden to do correctly, so as to account for higher-ranked
|
|
|
|
// behavior
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-12-12 11:28:35 -05:00
|
|
|
pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> {
|
|
|
|
fn combine<C:Combine<'tcx>>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>;
|
|
|
|
}
|
|
|
|
|
2014-12-17 14:16:28 -05:00
|
|
|
impl<'tcx,T> Combineable<'tcx> for Rc<T>
|
|
|
|
where T : Combineable<'tcx>
|
|
|
|
{
|
|
|
|
fn combine<C:Combine<'tcx>>(combiner: &C,
|
|
|
|
a: &Rc<T>,
|
|
|
|
b: &Rc<T>)
|
|
|
|
-> cres<'tcx, Rc<T>>
|
|
|
|
{
|
|
|
|
Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b))))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 11:28:35 -05:00
|
|
|
impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> {
|
|
|
|
fn combine<C:Combine<'tcx>>(combiner: &C,
|
|
|
|
a: &ty::TraitRef<'tcx>,
|
|
|
|
b: &ty::TraitRef<'tcx>)
|
|
|
|
-> cres<'tcx, ty::TraitRef<'tcx>>
|
|
|
|
{
|
|
|
|
combiner.trait_refs(a, b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-26 04:36:04 -05:00
|
|
|
impl<'tcx> Combineable<'tcx> for ty::ProjectionPredicate<'tcx> {
|
|
|
|
fn combine<C:Combine<'tcx>>(combiner: &C,
|
|
|
|
a: &ty::ProjectionPredicate<'tcx>,
|
|
|
|
b: &ty::ProjectionPredicate<'tcx>)
|
|
|
|
-> cres<'tcx, ty::ProjectionPredicate<'tcx>>
|
|
|
|
{
|
|
|
|
combiner.projection_predicates(a, b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 11:28:35 -05:00
|
|
|
impl<'tcx> Combineable<'tcx> for ty::FnSig<'tcx> {
|
|
|
|
fn combine<C:Combine<'tcx>>(combiner: &C,
|
|
|
|
a: &ty::FnSig<'tcx>,
|
|
|
|
b: &ty::FnSig<'tcx>)
|
|
|
|
-> cres<'tcx, ty::FnSig<'tcx>>
|
|
|
|
{
|
|
|
|
combiner.fn_sigs(a, b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 02:21:52 +03:00
|
|
|
#[deriving(Clone)]
|
2014-04-22 15:56:37 +03:00
|
|
|
pub struct CombineFields<'a, 'tcx: 'a> {
|
|
|
|
pub infcx: &'a InferCtxt<'a, 'tcx>,
|
2014-03-28 10:05:27 -07:00
|
|
|
pub a_is_expected: bool,
|
2014-09-29 22:11:30 +03:00
|
|
|
pub trace: TypeTrace<'tcx>,
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
pub fn expected_found<'tcx, C: Combine<'tcx>, T>(
|
2013-05-10 15:15:06 -07:00
|
|
|
this: &C, a: T, b: T) -> ty::expected_found<T> {
|
|
|
|
if this.a_is_expected() {
|
2013-02-15 04:14:34 -05:00
|
|
|
ty::expected_found {expected: a, found: b}
|
2012-08-13 15:06:13 -07:00
|
|
|
} else {
|
2013-02-15 04:14:34 -05:00
|
|
|
ty::expected_found {expected: b, found: a}
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
|
|
|
|
a: Ty<'tcx>,
|
|
|
|
b: Ty<'tcx>)
|
2014-12-25 07:20:48 -05:00
|
|
|
-> cres<'tcx, Ty<'tcx>>
|
|
|
|
{
|
2013-05-10 15:15:06 -07:00
|
|
|
let tcx = this.infcx().tcx;
|
2014-10-31 10:51:16 +02:00
|
|
|
let a_sty = &a.sty;
|
|
|
|
let b_sty = &b.sty;
|
2014-10-15 02:25:34 -04:00
|
|
|
debug!("super_tys: a_sty={} b_sty={}", a_sty, b_sty);
|
2013-10-29 06:03:32 -04:00
|
|
|
return match (a_sty, b_sty) {
|
2014-10-24 21:14:37 +02:00
|
|
|
// The "subtype" ought to be handling cases involving var:
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_infer(TyVar(_)), _) |
|
|
|
|
(_, &ty::ty_infer(TyVar(_))) => {
|
2012-08-13 15:06:13 -07:00
|
|
|
tcx.sess.bug(
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("{}: bot and var types should have been handled ({},{})",
|
2014-05-16 10:45:16 -07:00
|
|
|
this.tag(),
|
2014-06-20 06:35:06 -04:00
|
|
|
a.repr(this.infcx().tcx),
|
2014-12-10 19:46:38 -08:00
|
|
|
b.repr(this.infcx().tcx))[]);
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 08:54:31 -04:00
|
|
|
(&ty::ty_err, _) | (_, &ty::ty_err) => {
|
2014-12-25 07:20:48 -05:00
|
|
|
Ok(tcx.types.err)
|
2014-10-17 08:54:31 -04:00
|
|
|
}
|
|
|
|
|
2013-01-22 07:02:40 -08:00
|
|
|
// Relate integral variables to other types
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => {
|
2014-07-22 07:15:43 -04:00
|
|
|
try!(this.infcx().simple_vars(this.a_is_expected(),
|
2013-01-22 07:02:40 -08:00
|
|
|
a_id, b_id));
|
|
|
|
Ok(a)
|
|
|
|
}
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_infer(IntVar(v_id)), &ty::ty_int(v)) => {
|
2013-05-10 15:15:06 -07:00
|
|
|
unify_integral_variable(this, this.a_is_expected(),
|
2013-01-22 07:02:40 -08:00
|
|
|
v_id, IntType(v))
|
|
|
|
}
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_int(v), &ty::ty_infer(IntVar(v_id))) => {
|
2013-05-10 15:15:06 -07:00
|
|
|
unify_integral_variable(this, !this.a_is_expected(),
|
2013-01-22 07:02:40 -08:00
|
|
|
v_id, IntType(v))
|
|
|
|
}
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_infer(IntVar(v_id)), &ty::ty_uint(v)) => {
|
2013-05-10 15:15:06 -07:00
|
|
|
unify_integral_variable(this, this.a_is_expected(),
|
2013-01-22 07:02:40 -08:00
|
|
|
v_id, UintType(v))
|
|
|
|
}
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_uint(v), &ty::ty_infer(IntVar(v_id))) => {
|
2013-05-10 15:15:06 -07:00
|
|
|
unify_integral_variable(this, !this.a_is_expected(),
|
2013-01-22 07:02:40 -08:00
|
|
|
v_id, UintType(v))
|
2013-01-08 14:00:45 -08:00
|
|
|
}
|
2012-08-13 15:06:13 -07:00
|
|
|
|
2013-01-22 07:02:40 -08:00
|
|
|
// Relate floating-point variables to other types
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => {
|
2014-07-22 07:46:36 -04:00
|
|
|
try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id));
|
2013-01-22 07:02:40 -08:00
|
|
|
Ok(a)
|
|
|
|
}
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => {
|
2013-05-10 15:15:06 -07:00
|
|
|
unify_float_variable(this, this.a_is_expected(), v_id, v)
|
2013-01-22 07:02:40 -08:00
|
|
|
}
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_float(v), &ty::ty_infer(FloatVar(v_id))) => {
|
2013-05-10 15:15:06 -07:00
|
|
|
unify_float_variable(this, !this.a_is_expected(), v_id, v)
|
2013-01-22 07:02:40 -08:00
|
|
|
}
|
2012-11-07 18:40:34 -08:00
|
|
|
|
2013-10-29 06:03:32 -04:00
|
|
|
(&ty::ty_char, _) |
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_bool, _) |
|
|
|
|
(&ty::ty_int(_), _) |
|
|
|
|
(&ty::ty_uint(_), _) |
|
2014-10-17 08:54:31 -04:00
|
|
|
(&ty::ty_float(_), _) => {
|
2014-10-31 10:51:16 +02:00
|
|
|
if a == b {
|
2012-08-26 16:54:31 -07:00
|
|
|
Ok(a)
|
2012-08-13 15:06:13 -07:00
|
|
|
} else {
|
2013-05-10 15:15:06 -07:00
|
|
|
Err(ty::terr_sorts(expected_found(this, a, b)))
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-02 15:38:20 -07:00
|
|
|
(&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) if
|
|
|
|
a_p.idx == b_p.idx && a_p.space == b_p.space => {
|
2012-08-26 16:54:31 -07:00
|
|
|
Ok(a)
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-12-03 16:01:29 -08:00
|
|
|
(&ty::ty_enum(a_id, a_substs),
|
|
|
|
&ty::ty_enum(b_id, b_substs))
|
2012-08-13 15:06:13 -07:00
|
|
|
if a_id == b_id => {
|
2014-07-22 07:15:43 -04:00
|
|
|
let substs = try!(this.substs(a_id,
|
2013-10-29 06:08:34 -04:00
|
|
|
a_substs,
|
|
|
|
b_substs));
|
2014-12-03 16:01:29 -08:00
|
|
|
Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs)))
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-03-19 22:01:30 +11:00
|
|
|
(&ty::ty_trait(ref a_),
|
2014-11-07 06:16:57 -05:00
|
|
|
&ty::ty_trait(ref b_)) => {
|
2014-10-15 02:25:34 -04:00
|
|
|
debug!("Trying to match traits {} and {}", a, b);
|
2014-12-12 11:28:35 -05:00
|
|
|
let principal = try!(this.binders(&a_.principal, &b_.principal));
|
2014-12-26 04:36:04 -05:00
|
|
|
let bounds = try!(this.existential_bounds(&a_.bounds, &b_.bounds));
|
2014-11-07 06:16:57 -05:00
|
|
|
Ok(ty::mk_trait(tcx, principal, bounds))
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-12-03 16:01:29 -08:00
|
|
|
(&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs))
|
2012-08-13 15:06:13 -07:00
|
|
|
if a_id == b_id => {
|
2014-07-22 07:15:43 -04:00
|
|
|
let substs = try!(this.substs(a_id, a_substs, b_substs));
|
2014-12-03 16:01:29 -08:00
|
|
|
Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs)))
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-12-03 16:01:29 -08:00
|
|
|
(&ty::ty_unboxed_closure(a_id, a_region, a_substs),
|
|
|
|
&ty::ty_unboxed_closure(b_id, b_region, b_substs))
|
2014-05-28 22:26:56 -07:00
|
|
|
if a_id == b_id => {
|
2014-07-22 07:46:36 -04:00
|
|
|
// All ty_unboxed_closure types with the same id represent
|
|
|
|
// the (anonymous) type of the same closure expression. So
|
|
|
|
// all of their regions should be equated.
|
2014-12-04 16:52:57 -08:00
|
|
|
let region = try!(this.equate().regions(*a_region, *b_region));
|
2014-10-18 10:46:57 -07:00
|
|
|
let substs = try!(this.substs_variances(None, a_substs, b_substs));
|
2014-12-04 16:52:57 -08:00
|
|
|
Ok(ty::mk_unboxed_closure(tcx, a_id, tcx.mk_region(region), tcx.mk_substs(substs)))
|
2014-05-28 22:26:56 -07:00
|
|
|
}
|
|
|
|
|
2014-01-12 02:25:51 +02:00
|
|
|
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
|
2014-10-17 08:54:31 -04:00
|
|
|
let typ = try!(this.tys(a_inner, b_inner));
|
|
|
|
Ok(ty::mk_uniq(tcx, typ))
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
|
2014-10-17 08:54:31 -04:00
|
|
|
let mt = try!(this.mts(a_mt, b_mt));
|
|
|
|
Ok(ty::mk_ptr(tcx, mt))
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
|
2014-12-04 16:52:57 -08:00
|
|
|
let r = try!(this.contraregions(*a_r, *b_r));
|
2014-06-11 17:18:57 +12:00
|
|
|
// FIXME(14985) If we have mutable references to trait objects, we
|
|
|
|
// used to use covariant subtyping. I have preserved this behaviour,
|
|
|
|
// even though it is probably incorrect. So don't go down the usual
|
|
|
|
// path which would require invariance.
|
2014-10-31 10:51:16 +02:00
|
|
|
let mt = match (&a_mt.ty.sty, &b_mt.ty.sty) {
|
2014-06-11 17:18:57 +12:00
|
|
|
(&ty::ty_trait(..), &ty::ty_trait(..)) if a_mt.mutbl == b_mt.mutbl => {
|
2014-07-22 07:15:43 -04:00
|
|
|
let ty = try!(this.tys(a_mt.ty, b_mt.ty));
|
2014-06-11 17:18:57 +12:00
|
|
|
ty::mt { ty: ty, mutbl: a_mt.mutbl }
|
|
|
|
}
|
2014-07-22 07:15:43 -04:00
|
|
|
_ => try!(this.mts(a_mt, b_mt))
|
2014-06-11 17:18:57 +12:00
|
|
|
};
|
2014-12-04 16:52:57 -08:00
|
|
|
Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt))
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
Improve the readability of diagnostics that involve unresolved type variables
Diagnostics such as the following
```
mismatched types: expected `core::result::Result<uint,()>`, found `core::option::Option<<generic #1>>`
<anon>:6 let a: Result<uint, ()> = None;
^~~~
mismatched types: expected `&mut <generic #2>`, found `uint`
<anon>:7 f(42u);
^~~
```
tend to be fairly unappealing to new users. While specific type var IDs are valuable in
diagnostics that deal with more than one such variable, in practice many messages
only mention one. In those cases, leaving out the specific number makes the messages
slightly less terrifying.
In addition, type variables have been changed to use the type hole syntax `_` in diagnostics.
With a variable ID, they're printed as `_#id` (e.g. `_#1`). In cases where the ID is left out,
it's simply `_`. Integer and float variables have an additional suffix after the number, e.g.
`_#1i` or `_#3f`.
2014-10-23 22:35:19 +02:00
|
|
|
(&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) => {
|
|
|
|
this.tys(a_t, b_t).and_then(|t| {
|
|
|
|
if sz_a == sz_b {
|
|
|
|
Ok(ty::mk_vec(tcx, t, Some(sz_a)))
|
|
|
|
} else {
|
|
|
|
Err(ty::terr_fixed_array_size(expected_found(this, sz_a, sz_b)))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
DST coercions and DST structs
[breaking-change]
1. The internal layout for traits has changed from (vtable, data) to (data, vtable). If you were relying on this in unsafe transmutes, you might get some very weird and apparently unrelated errors. You should not be doing this! Prefer not to do this at all, but if you must, you should use raw::TraitObject rather than hardcoding rustc's internal representation into your code.
2. The minimal type of reference-to-vec-literals (e.g., `&[1, 2, 3]`) is now a fixed size vec (e.g., `&[int, ..3]`) where it used to be an unsized vec (e.g., `&[int]`). If you want the unszied type, you must explicitly give the type (e.g., `let x: &[_] = &[1, 2, 3]`). Note in particular where multiple blocks must have the same type (e.g., if and else clauses, vec elements), the compiler will not coerce to the unsized type without a hint. E.g., `[&[1], &[1, 2]]` used to be a valid expression of type '[&[int]]'. It no longer type checks since the first element now has type `&[int, ..1]` and the second has type &[int, ..2]` which are incompatible.
3. The type of blocks (including functions) must be coercible to the expected type (used to be a subtype). Mostly this makes things more flexible and not less (in particular, in the case of coercing function bodies to the return type). However, in some rare cases, this is less flexible. TBH, I'm not exactly sure of the exact effects. I think the change causes us to resolve inferred type variables slightly earlier which might make us slightly more restrictive. Possibly it only affects blocks with unreachable code. E.g., `if ... { fail!(); "Hello" }` used to type check, it no longer does. The fix is to add a semicolon after the string.
2014-08-04 14:20:11 +02:00
|
|
|
(&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => {
|
|
|
|
this.tys(a_t, b_t).and_then(|t| {
|
2014-04-09 19:15:31 +12:00
|
|
|
if sz_a == sz_b {
|
DST coercions and DST structs
[breaking-change]
1. The internal layout for traits has changed from (vtable, data) to (data, vtable). If you were relying on this in unsafe transmutes, you might get some very weird and apparently unrelated errors. You should not be doing this! Prefer not to do this at all, but if you must, you should use raw::TraitObject rather than hardcoding rustc's internal representation into your code.
2. The minimal type of reference-to-vec-literals (e.g., `&[1, 2, 3]`) is now a fixed size vec (e.g., `&[int, ..3]`) where it used to be an unsized vec (e.g., `&[int]`). If you want the unszied type, you must explicitly give the type (e.g., `let x: &[_] = &[1, 2, 3]`). Note in particular where multiple blocks must have the same type (e.g., if and else clauses, vec elements), the compiler will not coerce to the unsized type without a hint. E.g., `[&[1], &[1, 2]]` used to be a valid expression of type '[&[int]]'. It no longer type checks since the first element now has type `&[int, ..1]` and the second has type &[int, ..2]` which are incompatible.
3. The type of blocks (including functions) must be coercible to the expected type (used to be a subtype). Mostly this makes things more flexible and not less (in particular, in the case of coercing function bodies to the return type). However, in some rare cases, this is less flexible. TBH, I'm not exactly sure of the exact effects. I think the change causes us to resolve inferred type variables slightly earlier which might make us slightly more restrictive. Possibly it only affects blocks with unreachable code. E.g., `if ... { fail!(); "Hello" }` used to type check, it no longer does. The fix is to add a semicolon after the string.
2014-08-04 14:20:11 +02:00
|
|
|
Ok(ty::mk_vec(tcx, t, sz_a))
|
2014-04-09 19:15:31 +12:00
|
|
|
} else {
|
|
|
|
Err(ty::terr_sorts(expected_found(this, a, b)))
|
|
|
|
}
|
2013-11-21 15:42:55 -08:00
|
|
|
})
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-04-29 13:10:23 +12:00
|
|
|
(&ty::ty_str, &ty::ty_str) => {
|
|
|
|
Ok(ty::mk_str(tcx))
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => {
|
2013-03-20 01:17:42 -04:00
|
|
|
if as_.len() == bs.len() {
|
2014-10-14 23:05:01 -07:00
|
|
|
as_.iter().zip(bs.iter())
|
|
|
|
.map(|(a, b)| this.tys(*a, *b))
|
|
|
|
.collect::<Result<_, _>>()
|
|
|
|
.map(|ts| ty::mk_tup(tcx, ts))
|
2014-11-09 16:14:15 +01:00
|
|
|
} else if as_.len() != 0 && bs.len() != 0 {
|
2012-09-09 17:23:29 -07:00
|
|
|
Err(ty::terr_tuple_size(
|
2013-05-10 15:15:06 -07:00
|
|
|
expected_found(this, as_.len(), bs.len())))
|
2014-11-09 16:14:15 +01:00
|
|
|
} else {
|
|
|
|
Err(ty::terr_sorts(expected_found(this, a, b)))
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-04 14:52:20 -08:00
|
|
|
(&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty))
|
2014-11-26 06:36:09 -05:00
|
|
|
if a_opt_def_id == b_opt_def_id =>
|
|
|
|
{
|
|
|
|
let fty = try!(this.bare_fn_tys(a_fty, b_fty));
|
2014-12-26 22:33:56 +11:00
|
|
|
Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty)))
|
2014-11-26 06:36:09 -05:00
|
|
|
}
|
2013-01-31 17:12:29 -08:00
|
|
|
|
2013-06-08 02:28:06 +02:00
|
|
|
(&ty::ty_closure(ref a_fty), &ty::ty_closure(ref b_fty)) => {
|
2014-07-07 16:35:15 -07:00
|
|
|
this.closure_tys(&**a_fty, &**b_fty).and_then(|fty| {
|
2013-01-31 17:12:29 -08:00
|
|
|
Ok(ty::mk_closure(tcx, fty))
|
2013-11-21 15:42:55 -08:00
|
|
|
})
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
|
|
|
|
2014-12-17 14:16:28 -05:00
|
|
|
(&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => {
|
2014-12-26 04:36:04 -05:00
|
|
|
let projection_ty = try!(this.projection_tys(a_data, b_data));
|
|
|
|
Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name))
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
|
2013-05-10 15:15:06 -07:00
|
|
|
_ => Err(ty::terr_sorts(expected_found(this, a, b)))
|
2013-01-22 07:02:40 -08:00
|
|
|
};
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
fn unify_integral_variable<'tcx, C: Combine<'tcx>>(
|
2013-05-10 15:15:06 -07:00
|
|
|
this: &C,
|
2013-01-22 07:02:40 -08:00
|
|
|
vid_is_expected: bool,
|
|
|
|
vid: ty::IntVid,
|
2014-09-29 22:11:30 +03:00
|
|
|
val: ty::IntVarValue) -> cres<'tcx, Ty<'tcx>>
|
2013-01-22 07:02:40 -08:00
|
|
|
{
|
2014-07-22 07:15:43 -04:00
|
|
|
try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
|
2013-09-03 19:24:12 -04:00
|
|
|
match val {
|
2014-12-25 07:20:48 -05:00
|
|
|
IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)),
|
|
|
|
UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v))
|
2013-01-22 07:02:40 -08:00
|
|
|
}
|
2012-08-13 15:06:13 -07:00
|
|
|
}
|
2013-01-22 07:02:40 -08:00
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
fn unify_float_variable<'tcx, C: Combine<'tcx>>(
|
2013-05-10 15:15:06 -07:00
|
|
|
this: &C,
|
2013-01-22 07:02:40 -08:00
|
|
|
vid_is_expected: bool,
|
|
|
|
vid: ty::FloatVid,
|
2014-09-29 22:11:30 +03:00
|
|
|
val: ast::FloatTy) -> cres<'tcx, Ty<'tcx>>
|
2013-01-22 07:02:40 -08:00
|
|
|
{
|
2014-07-22 07:15:43 -04:00
|
|
|
try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
|
2014-12-25 07:20:48 -05:00
|
|
|
Ok(ty::mk_mach_float(this.tcx(), val))
|
2013-01-22 07:02:40 -08:00
|
|
|
}
|
2013-01-25 16:57:39 -08:00
|
|
|
}
|
2014-07-22 07:46:36 -04:00
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'f, 'tcx> CombineFields<'f, 'tcx> {
|
|
|
|
pub fn switch_expected(&self) -> CombineFields<'f, 'tcx> {
|
2014-07-22 07:46:36 -04:00
|
|
|
CombineFields {
|
|
|
|
a_is_expected: !self.a_is_expected,
|
|
|
|
..(*self).clone()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
fn equate(&self) -> Equate<'f, 'tcx> {
|
2014-07-22 07:46:36 -04:00
|
|
|
Equate((*self).clone())
|
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
fn sub(&self) -> Sub<'f, 'tcx> {
|
2014-07-22 07:46:36 -04:00
|
|
|
Sub((*self).clone())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn instantiate(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
a_ty: Ty<'tcx>,
|
2014-07-22 07:46:36 -04:00
|
|
|
dir: RelationDir,
|
|
|
|
b_vid: ty::TyVid)
|
2014-09-29 22:11:30 +03:00
|
|
|
-> cres<'tcx, ()>
|
2014-07-22 07:46:36 -04:00
|
|
|
{
|
|
|
|
let tcx = self.infcx.tcx;
|
|
|
|
let mut stack = Vec::new();
|
|
|
|
stack.push((a_ty, dir, b_vid));
|
|
|
|
loop {
|
|
|
|
// For each turn of the loop, we extract a tuple
|
|
|
|
//
|
|
|
|
// (a_ty, dir, b_vid)
|
|
|
|
//
|
|
|
|
// to relate. Here dir is either SubtypeOf or
|
|
|
|
// SupertypeOf. The idea is that we should ensure that
|
|
|
|
// the type `a_ty` is a subtype or supertype (respectively) of the
|
|
|
|
// type to which `b_vid` is bound.
|
|
|
|
//
|
|
|
|
// If `b_vid` has not yet been instantiated with a type
|
|
|
|
// (which is always true on the first iteration, but not
|
|
|
|
// necessarily true on later iterations), we will first
|
|
|
|
// instantiate `b_vid` with a *generalized* version of
|
|
|
|
// `a_ty`. Generalization introduces other inference
|
|
|
|
// variables wherever subtyping could occur (at time of
|
|
|
|
// this writing, this means replacing free regions with
|
|
|
|
// region variables).
|
|
|
|
let (a_ty, dir, b_vid) = match stack.pop() {
|
|
|
|
None => break,
|
|
|
|
Some(e) => e,
|
|
|
|
};
|
|
|
|
|
|
|
|
debug!("instantiate(a_ty={} dir={} b_vid={})",
|
|
|
|
a_ty.repr(tcx),
|
|
|
|
dir,
|
|
|
|
b_vid.repr(tcx));
|
|
|
|
|
|
|
|
// Check whether `vid` has been instantiated yet. If not,
|
|
|
|
// make a generalized form of `ty` and instantiate with
|
|
|
|
// that.
|
|
|
|
let b_ty = self.infcx.type_variables.borrow().probe(b_vid);
|
|
|
|
let b_ty = match b_ty {
|
|
|
|
Some(t) => t, // ...already instantiated.
|
|
|
|
None => { // ...not yet instantiated:
|
|
|
|
// Generalize type if necessary.
|
2014-09-09 17:45:51 -04:00
|
|
|
let generalized_ty = try!(match dir {
|
|
|
|
EqTo => {
|
|
|
|
self.generalize(a_ty, b_vid, false)
|
|
|
|
}
|
|
|
|
SupertypeOf | SubtypeOf => {
|
|
|
|
self.generalize(a_ty, b_vid, true)
|
|
|
|
}
|
|
|
|
});
|
2014-07-22 07:46:36 -04:00
|
|
|
debug!("instantiate(a_ty={}, dir={}, \
|
|
|
|
b_vid={}, generalized_ty={})",
|
|
|
|
a_ty.repr(tcx), dir, b_vid.repr(tcx),
|
|
|
|
generalized_ty.repr(tcx));
|
|
|
|
self.infcx.type_variables
|
|
|
|
.borrow_mut()
|
|
|
|
.instantiate_and_push(
|
|
|
|
b_vid, generalized_ty, &mut stack);
|
|
|
|
generalized_ty
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// The original triple was `(a_ty, dir, b_vid)` -- now we have
|
|
|
|
// resolved `b_vid` to `b_ty`, so apply `(a_ty, dir, b_ty)`:
|
|
|
|
//
|
2014-08-29 07:46:43 -04:00
|
|
|
// FIXME(#16847): This code is non-ideal because all these subtype
|
2014-07-22 07:46:36 -04:00
|
|
|
// relations wind up attributed to the same spans. We need
|
|
|
|
// to associate causes/spans with each of the relations in
|
|
|
|
// the stack to get this right.
|
|
|
|
match dir {
|
|
|
|
EqTo => {
|
|
|
|
try!(self.equate().tys(a_ty, b_ty));
|
|
|
|
}
|
|
|
|
|
|
|
|
SubtypeOf => {
|
|
|
|
try!(self.sub().tys(a_ty, b_ty));
|
|
|
|
}
|
|
|
|
|
|
|
|
SupertypeOf => {
|
|
|
|
try!(self.sub().contratys(a_ty, b_ty));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2014-11-25 21:17:11 -05:00
|
|
|
/// Attempts to generalize `ty` for the type variable `for_vid`. This checks for cycle -- that
|
|
|
|
/// is, whether the type `ty` references `for_vid`. If `make_region_vars` is true, it will also
|
|
|
|
/// replace all regions with fresh variables. Returns `ty_err` in the case of a cycle, `Ok`
|
|
|
|
/// otherwise.
|
2014-09-09 17:45:51 -04:00
|
|
|
fn generalize(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
ty: Ty<'tcx>,
|
2014-09-09 17:45:51 -04:00
|
|
|
for_vid: ty::TyVid,
|
|
|
|
make_region_vars: bool)
|
2014-09-29 22:11:30 +03:00
|
|
|
-> cres<'tcx, Ty<'tcx>>
|
2014-09-09 17:45:51 -04:00
|
|
|
{
|
|
|
|
let mut generalize = Generalizer { infcx: self.infcx,
|
|
|
|
span: self.trace.origin.span(),
|
|
|
|
for_vid: for_vid,
|
|
|
|
make_region_vars: make_region_vars,
|
|
|
|
cycle_detected: false };
|
|
|
|
let u = ty.fold_with(&mut generalize);
|
|
|
|
if generalize.cycle_detected {
|
|
|
|
Err(ty::terr_cyclic_ty)
|
|
|
|
} else {
|
|
|
|
Ok(u)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-22 07:46:36 -04:00
|
|
|
|
2014-09-09 17:45:51 -04:00
|
|
|
struct Generalizer<'cx, 'tcx:'cx> {
|
|
|
|
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
|
|
|
span: Span,
|
|
|
|
for_vid: ty::TyVid,
|
|
|
|
make_region_vars: bool,
|
|
|
|
cycle_detected: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
|
|
|
|
fn tcx(&self) -> &ty::ctxt<'tcx> {
|
|
|
|
self.infcx.tcx
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
2014-09-09 17:45:51 -04:00
|
|
|
// Check to see whether the type we are genealizing references
|
|
|
|
// `vid`. At the same time, also update any type variables to
|
|
|
|
// the values that they are bound to. This is needed to truly
|
|
|
|
// check for cycles, but also just makes things readable.
|
|
|
|
//
|
|
|
|
// (In particular, you could have something like `$0 = Box<$1>`
|
|
|
|
// where `$1` has already been instantiated with `Box<$0>`)
|
2014-10-31 10:51:16 +02:00
|
|
|
match t.sty {
|
2014-09-09 17:45:51 -04:00
|
|
|
ty::ty_infer(ty::TyVar(vid)) => {
|
|
|
|
if vid == self.for_vid {
|
|
|
|
self.cycle_detected = true;
|
2014-12-25 07:20:48 -05:00
|
|
|
self.tcx().types.err
|
2014-09-09 17:45:51 -04:00
|
|
|
} else {
|
|
|
|
match self.infcx.type_variables.borrow().probe(vid) {
|
|
|
|
Some(u) => self.fold_ty(u),
|
|
|
|
None => t,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
ty_fold::super_fold_ty(self, t)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
|
|
|
|
match r {
|
2014-12-01 10:11:59 -05:00
|
|
|
// Never make variables for regions bound within the type itself.
|
|
|
|
ty::ReLateBound(..) => { return r; }
|
|
|
|
|
|
|
|
// Early-bound regions should really have been substituted away before
|
|
|
|
// we get to this point.
|
|
|
|
ty::ReEarlyBound(..) => {
|
|
|
|
self.tcx().sess.span_bug(
|
|
|
|
self.span,
|
|
|
|
format!("Encountered early bound region when generalizing: {}",
|
|
|
|
r.repr(self.tcx()))[]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Always make a fresh region variable for skolemized regions;
|
|
|
|
// the higher-ranked decision procedures rely on this.
|
|
|
|
ty::ReInfer(ty::ReSkolemized(..)) => { }
|
|
|
|
|
|
|
|
// For anything else, we make a region variable, unless we
|
|
|
|
// are *equating*, in which case it's just wasteful.
|
|
|
|
ty::ReEmpty |
|
|
|
|
ty::ReStatic |
|
|
|
|
ty::ReScope(..) |
|
|
|
|
ty::ReInfer(ty::ReVar(..)) |
|
|
|
|
ty::ReFree(..) => {
|
|
|
|
if !self.make_region_vars {
|
|
|
|
return r;
|
|
|
|
}
|
2014-09-09 17:45:51 -04:00
|
|
|
}
|
|
|
|
}
|
2014-12-01 10:11:59 -05:00
|
|
|
|
|
|
|
// FIXME: This is non-ideal because we don't give a
|
|
|
|
// very descriptive origin for this region variable.
|
|
|
|
self.infcx.next_region_var(MiscVariable(self.span))
|
2014-07-22 07:46:36 -04:00
|
|
|
}
|
|
|
|
}
|